@@ -49,8 +49,9 @@ class MistralTranscriptionGenerator(GeneratorBase):
4949 def __init__ (self , ** kwargs ):
5050 super ().__init__ (** kwargs )
5151
52- async def chat (self , chat , provider = None , context = None ):
53- headers = self .get_headers (provider , chat )
52+ async def transcribe (self , file_bytes , filename , model = None , headers = None , context = None ):
53+ model = model or "voxtral-mini-latest"
54+ headers = headers or self .get_headers ()
5455 # Remove Content-Type to allow aiohttp to set it for FormData
5556 if "Content-Type" in headers :
5657 del headers ["Content-Type" ]
@@ -60,6 +61,35 @@ async def chat(self, chat, provider=None, context=None):
6061 token = headers ["Authorization" ].replace ("Bearer " , "" )
6162 headers ["x-api-key" ] = token
6263
64+ # Prepare FormData
65+ data = aiohttp .FormData ()
66+ data .add_field ("model" , model )
67+ data .add_field (
68+ "file" , file_bytes , filename = filename , content_type = mimetypes .guess_type (filename )[0 ] or "audio/mpeg"
69+ )
70+
71+ ctx .log (f"POST { self .api_url } model={ model } file={ filename } ({ len (file_bytes )} bytes)" )
72+
73+ async with aiohttp .ClientSession () as session , session .post (
74+ self .api_url , headers = headers , data = data
75+ ) as response :
76+ text = await response .text ()
77+ if response .status != 200 :
78+ raise Exception (f"Mistral API Error { response .status } : { text } " )
79+
80+ if context :
81+ context ["providerResponse" ] = text
82+
83+ try :
84+ result = json .loads (text )
85+ except Exception :
86+ result = {"text" : text } # Fallback
87+
88+ return result
89+
90+ async def chat (self , chat , provider = None , context = None ):
91+ headers = self .get_headers (provider , chat )
92+
6393 model = provider .provider_model (chat ["model" ]) or chat ["model" ] or "voxtral-mini-latest"
6494 # Replace internal alias with actual model name
6595 if model == "voxtral-mini-transcription" :
@@ -110,50 +140,28 @@ async def chat(self, chat, provider=None, context=None):
110140 except Exception as e :
111141 raise Exception (f"Failed to decode audio data: { e } " ) from e
112142
113- # Prepare FormData
114- data = aiohttp .FormData ()
115- data .add_field ("model" , model )
116- data .add_field (
117- "file" , file_bytes , filename = filename , content_type = mimetypes .guess_type (filename )[0 ] or "audio/mpeg"
118- )
119-
120- ctx .log (f"POST { self .api_url } model={ model } file={ filename } ({ len (file_bytes )} bytes)" )
143+ result = await self .transcribe (file_bytes , filename , model = model , headers = headers , context = context )
144+ transcription = result .get ("text" , "" )
121145
122- async with aiohttp .ClientSession () as session , session .post (
123- self .api_url , headers = headers , data = data
124- ) as response :
125- text = await response .text ()
126- if response .status != 200 :
127- raise Exception (f"Mistral API Error { response .status } : { text } " )
128-
129- context ["providerResponse" ] = text
130-
131- try :
132- result = json .loads (text )
133- except Exception :
134- result = {"text" : text } # Fallback
135-
136- transcription = result .get ("text" , "" )
137-
138- ret = {
139- "choices" : [
140- {
141- "message" : {
142- "role" : "assistant" ,
143- "content" : transcription ,
144- }
146+ ret = {
147+ "choices" : [
148+ {
149+ "message" : {
150+ "role" : "assistant" ,
151+ "content" : transcription ,
145152 }
146- ],
147- "created" : result .get ("created" , int (time .time ())),
148- }
153+ }
154+ ],
155+ "created" : result .get ("created" , int (time .time ())),
156+ }
149157
150- if "model" in result :
151- ret ["model" ] = result ["model" ]
158+ if "model" in result :
159+ ret ["model" ] = result ["model" ]
152160
153- if "usage" in result :
154- ret ["usage" ] = result ["usage" ]
161+ if "usage" in result :
162+ ret ["usage" ] = result ["usage" ]
155163
156- return ret
164+ return ret
157165
158166 class MistralProvider (OpenAiCompatible ):
159167 sdk = "@ai-sdk/mistral"
0 commit comments