xieli commited on
Commit
463162b
·
1 Parent(s): 501ca3e

feat: fix

Browse files
Files changed (1) hide show
  1. stepfun_api.py +129 -40
stepfun_api.py CHANGED
@@ -159,7 +159,16 @@ class StepFunAPIClient:
159
  Raises:
160
  Exception: 如果转录失败
161
  """
162
- url = f"{API_BASE_URL}/audio/asr/sse"
 
 
 
 
 
 
 
 
 
163
 
164
  # 读取音频文件并转换为base64
165
  try:
@@ -167,13 +176,9 @@ class StepFunAPIClient:
167
  audio_data = base64.b64encode(audio_file.read()).decode('utf-8')
168
  except Exception as e:
169
  logger.error(f"❌ Failed to read audio file: {e}")
170
- if streaming:
171
- yield f"[读取文件失败: {e}]"
172
- return
173
- else:
174
- raise Exception(f"Failed to read audio file: {e}")
175
 
176
- # 构建请求payload - 修正格式根据文档
177
  payload = {
178
  "audio": {
179
  "data": audio_data,
@@ -229,66 +234,150 @@ class StepFunAPIClient:
229
  accumulated_text += delta
230
  logger.debug(f"📝 ASR delta: {delta}")
231
 
232
- # 处理增量更新
233
- if streaming:
234
- yield accumulated_text
235
- elif progress_callback:
236
  progress_callback(accumulated_text)
237
 
238
  elif event_type == "transcript.text.done":
239
  final_text = event_data.get("text", accumulated_text)
240
  logger.info(f"✅ ASR transcription complete: {final_text}")
241
-
242
- if streaming:
243
- yield final_text
244
- return
245
- else:
246
- break
247
 
248
  elif event_type == "error":
249
  error_msg = event_data.get("message", "Unknown ASR error")
250
  logger.error(f"❌ ASR error: {error_msg}")
251
-
252
- if streaming:
253
- yield f"[ASR错误: {error_msg}]"
254
- return
255
- else:
256
- raise Exception(f"ASR API error: {error_msg}")
257
 
258
  except json.JSONDecodeError as e:
259
  logger.warning(f"⚠️ Failed to parse SSE line: {line}, error: {e}")
260
  continue
261
  except Exception as e:
262
  logger.error(f"❌ Error processing SSE event: {e}")
263
- if streaming:
264
- yield f"[处理错误: {str(e)}]"
265
- return
266
- else:
267
- raise
268
 
269
  # 如果没有获得final_text,使用accumulated_text
270
  if not final_text:
271
  final_text = accumulated_text
272
 
273
  if not final_text:
274
- error_msg = "No transcription result received"
275
- if streaming:
276
- yield f"[转录无结果]"
277
- return
278
- else:
279
- raise Exception(error_msg)
280
 
281
  logger.info(f"🎯 Final transcription: {final_text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
 
283
- if not streaming:
284
- return final_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
 
286
  except Exception as e:
287
  logger.error(f"❌ ASR transcription failed: {e}")
288
- if streaming:
289
- yield f"[转录失败: {str(e)}]"
290
- else:
291
- raise Exception(f"ASR transcription failed: {e}")
292
 
293
 
294
  # Global API client instance (singleton)
 
159
  Raises:
160
  Exception: 如果转录失败
161
  """
162
+ if streaming:
163
+ return self._transcribe_audio_sse_streaming(audio_path, progress_callback)
164
+ else:
165
+ return self._transcribe_audio_sse_sync(audio_path, progress_callback)
166
+
167
+ def _transcribe_audio_sse_sync(self, audio_path: str, progress_callback=None) -> str:
168
+ """
169
+ 同步ASR转录,返回最终文本
170
+ """
171
+ url = f"{API_BASE_URL}/audio/asr"
172
 
173
  # 读取音频文件并转换为base64
174
  try:
 
176
  audio_data = base64.b64encode(audio_file.read()).decode('utf-8')
177
  except Exception as e:
178
  logger.error(f"❌ Failed to read audio file: {e}")
179
+ raise Exception(f"Failed to read audio file: {e}")
 
 
 
 
180
 
181
+ # 构建请求payload
182
  payload = {
183
  "audio": {
184
  "data": audio_data,
 
234
  accumulated_text += delta
235
  logger.debug(f"📝 ASR delta: {delta}")
236
 
237
+ # 处理增量更新回调
238
+ if progress_callback:
 
 
239
  progress_callback(accumulated_text)
240
 
241
  elif event_type == "transcript.text.done":
242
  final_text = event_data.get("text", accumulated_text)
243
  logger.info(f"✅ ASR transcription complete: {final_text}")
244
+ break
 
 
 
 
 
245
 
246
  elif event_type == "error":
247
  error_msg = event_data.get("message", "Unknown ASR error")
248
  logger.error(f"❌ ASR error: {error_msg}")
249
+ raise Exception(f"ASR API error: {error_msg}")
 
 
 
 
 
250
 
251
  except json.JSONDecodeError as e:
252
  logger.warning(f"⚠️ Failed to parse SSE line: {line}, error: {e}")
253
  continue
254
  except Exception as e:
255
  logger.error(f"❌ Error processing SSE event: {e}")
256
+ raise
 
 
 
 
257
 
258
  # 如果没有获得final_text,使用accumulated_text
259
  if not final_text:
260
  final_text = accumulated_text
261
 
262
  if not final_text:
263
+ raise Exception("No transcription result received")
 
 
 
 
 
264
 
265
  logger.info(f"🎯 Final transcription: {final_text}")
266
+ return final_text
267
+
268
+ except Exception as e:
269
+ logger.error(f"❌ ASR transcription failed: {e}")
270
+ raise Exception(f"ASR transcription failed: {e}")
271
+
272
+ def _transcribe_audio_sse_streaming(self, audio_path: str, progress_callback=None):
273
+ """
274
+ 流式ASR转录,返回生成器
275
+ """
276
+ url = f"{API_BASE_URL}/audio/asr"
277
+
278
+ # 读取音频文件并转换为base64
279
+ try:
280
+ with open(audio_path, 'rb') as audio_file:
281
+ audio_data = base64.b64encode(audio_file.read()).decode('utf-8')
282
+ except Exception as e:
283
+ logger.error(f"❌ Failed to read audio file: {e}")
284
+ yield f"[读取文件失败: {e}]"
285
+ return
286
+
287
+ # 构建请求payload
288
+ payload = {
289
+ "audio": {
290
+ "data": audio_data,
291
+ "input": {
292
+ "transcription": {
293
+ "language": "zh",
294
+ "prompt": "请记录下你所听到的语音内容。",
295
+ "model": "step-asr",
296
+ "full_rerun_on_commit": True,
297
+ "enable_itn": True
298
+ },
299
+ "format": {
300
+ "type": "pcm",
301
+ "codec": "pcm_s16le",
302
+ "rate": 16000,
303
+ "bits": 16,
304
+ "channel": 1
305
+ }
306
+ }
307
+ }
308
+ }
309
+
310
+ headers = {
311
+ **self.base_headers,
312
+ "Content-Type": "application/json",
313
+ "Accept": "text/event-stream"
314
+ }
315
+
316
+ logger.info("🎙️ Starting ASR transcription...")
317
+
318
+ try:
319
+ response = requests.post(url, headers=headers, data=json.dumps(payload), stream=True, timeout=120)
320
+ response.raise_for_status()
321
+
322
+ final_text = ""
323
+ accumulated_text = ""
324
 
325
+ for line in response.iter_lines(decode_unicode=True):
326
+ if line:
327
+ line = line.strip()
328
+ if line.startswith("data: "):
329
+ try:
330
+ # 解析SSE数据
331
+ data_str = line[6:] # 去掉 "data: " 前缀
332
+ if data_str == "[DONE]":
333
+ break
334
+
335
+ event_data = json.loads(data_str)
336
+ event_type = event_data.get("type")
337
+
338
+ if event_type == "transcript.text.delta":
339
+ delta = event_data.get("delta", "")
340
+ accumulated_text += delta
341
+ logger.debug(f"📝 ASR delta: {delta}")
342
+
343
+ # 流式更新
344
+ yield accumulated_text
345
+ if progress_callback:
346
+ progress_callback(accumulated_text)
347
+
348
+ elif event_type == "transcript.text.done":
349
+ final_text = event_data.get("text", accumulated_text)
350
+ logger.info(f"✅ ASR transcription complete: {final_text}")
351
+ yield final_text
352
+ return
353
+
354
+ elif event_type == "error":
355
+ error_msg = event_data.get("message", "Unknown ASR error")
356
+ logger.error(f"❌ ASR error: {error_msg}")
357
+ yield f"[ASR错误: {error_msg}]"
358
+ return
359
+
360
+ except json.JSONDecodeError as e:
361
+ logger.warning(f"⚠️ Failed to parse SSE line: {line}, error: {e}")
362
+ continue
363
+ except Exception as e:
364
+ logger.error(f"❌ Error processing SSE event: {e}")
365
+ yield f"[处理错误: {str(e)}]"
366
+ return
367
+
368
+ # 如果没有获得final_text,使用accumulated_text
369
+ if not final_text:
370
+ final_text = accumulated_text
371
+
372
+ if not final_text:
373
+ yield f"[转录无结果]"
374
+ return
375
+
376
+ logger.info(f"🎯 Final transcription: {final_text}")
377
 
378
  except Exception as e:
379
  logger.error(f"❌ ASR transcription failed: {e}")
380
+ yield f"[转录失败: {str(e)}]"
 
 
 
381
 
382
 
383
  # Global API client instance (singleton)