55from django .conf import settings
66
77import requests
8+ import typing
89
10+ from core .services import mime_types
911
1012class ConversionError (Exception ):
1113 """Base exception for conversion-related errors."""
@@ -19,8 +21,65 @@ class ServiceUnavailableError(ConversionError):
1921 """Raised when the conversion service is unavailable."""
2022
2123
24+ class ConverterProtocol (typing .Protocol ):
25+ def convert (self , text , content_type , accept ): ...
26+
27+
28+ class Converter :
29+ docspec : ConverterProtocol
30+ ydoc : ConverterProtocol
31+
32+ def __init__ (self ):
33+ self .docspec = DocSpecConverter ()
34+ self .ydoc = YdocConverter ()
35+
36+ def convert (self , input , content_type , accept ):
37+ """Convert input into other formats using external microservices."""
38+
39+ if content_type == mime_types .DOCX and accept == mime_types .YJS :
40+ return self .convert (
41+ self .docspec .convert (input , mime_types .DOCX , mime_types .BLOCKNOTE ),
42+ mime_types .BLOCKNOTE ,
43+ mime_types .YJS
44+ )
45+
46+ return self .ydoc .convert (input , content_type , accept )
47+
48+
49+ class DocSpecConverter :
50+ """Service class for DocSpec conversion-related operations."""
51+
52+ def _request (self , url , data , content_type ):
53+ """Make a request to the DocSpec API."""
54+
55+ response = requests .post (
56+ url ,
57+ headers = {"Accept" : mime_types .BLOCKNOTE },
58+ files = {"file" : ("document.docx" , data , content_type )},
59+ timeout = settings .CONVERSION_API_TIMEOUT ,
60+ verify = settings .CONVERSION_API_SECURE ,
61+ )
62+ response .raise_for_status ()
63+ return response
64+
65+ def convert (self , data , content_type , accept ):
66+ """Convert a Document to BlockNote."""
67+ if not data :
68+ raise ValidationError ("Input data cannot be empty" )
69+
70+ if content_type != mime_types .DOCX or accept != mime_types .BLOCKNOTE :
71+ raise ValidationError (f"Conversion from { content_type } to { accept } is not supported." )
72+
73+ try :
74+ return self ._request (settings .DOCSPEC_API_URL , data , content_type ).content
75+ except requests .RequestException as err :
76+ raise ServiceUnavailableError (
77+ "Failed to connect to DocSpec conversion service" ,
78+ ) from err
79+
80+
2281class YdocConverter :
23- """Service class for conversion-related operations."""
82+ """Service class for YDoc conversion-related operations."""
2483
2584 @property
2685 def auth_header (self ):
@@ -45,7 +104,7 @@ def _request(self, url, data, content_type, accept):
45104 return response
46105
47106 def convert (
48- self , text , content_type = "text/markdown" , accept = "application/vnd.yjs.doc"
107+ self , text , content_type = mime_types . MARKDOWN , accept = mime_types . YJS
49108 ):
50109 """Convert a Markdown text into our internal format using an external microservice."""
51110
@@ -59,14 +118,14 @@ def convert(
59118 content_type ,
60119 accept ,
61120 )
62- if accept == "application/vnd.yjs.doc" :
121+ if accept == mime_types . YJS :
63122 return b64encode (response .content ).decode ("utf-8" )
64- if accept in {"text/markdown" , "text/html" }:
123+ if accept in {mime_types . MARKDOWN , "text/html" }:
65124 return response .text
66- if accept == "application/json" :
125+ if accept == mime_types . JSON :
67126 return response .json ()
68127 raise ValidationError ("Unsupported format" )
69128 except requests .RequestException as err :
70129 raise ServiceUnavailableError (
71- "Failed to connect to conversion service" ,
130+ f "Failed to connect to YDoc conversion service { content_type } , { accept } " ,
72131 ) from err
0 commit comments