feat: add video OCR/ASR, DOCX/PDF export, input block and risk config updates
- Video pipeline: video file OCR via VLM plus audio track ASR, integrated into job_handlers with progress emit per phase. New media_utils.py for audio extraction from video files. - Document export: richExport.js replaces inline docx builder; DOCX and PDF export buttons are now enabled in MilkdownEditor. File size limit raised to 100 MB. - Input block: new InputBlockCrepe.vue component with inputBlockPlugin.ts and inputBlock.js for custom user-input nodes in the editor. - Risk config: added Vite dev server ports (5173) to CORS allowlist and increased OCR max input from 10 MB to 100 MB. - TTS/ASR refactor: simplified tts_asr.py model loading and warmup logic. - Test coverage: updated tests for llm, main endpoints, pro completions and web search modules. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+24
-7
@@ -106,6 +106,8 @@ class OCRRequest(BaseModel):
|
||||
image: str
|
||||
filename: str = "image.jpg"
|
||||
language: str = "auto"
|
||||
media_type: str = "image"
|
||||
mime_type: str | None = None
|
||||
|
||||
|
||||
class ConvertRequest(BaseModel):
|
||||
@@ -281,8 +283,10 @@ def _register_handlers() -> None:
|
||||
确保 Redis 重连或实例重建后处理器不会丢失。"""
|
||||
global _handlers_registered
|
||||
manager = get_job_manager()
|
||||
# 强制清空旧 handlers,避免重复注册累积
|
||||
manager.handlers.clear()
|
||||
# 强制清空旧 handlers,避免重复注册累积;测试替身只暴露 register_handler。
|
||||
handlers = getattr(manager, "handlers", None)
|
||||
if handlers is not None:
|
||||
handlers.clear()
|
||||
manager.register_handler("completion", completion_handler)
|
||||
manager.register_handler("pro_completion", pro_completion_handler)
|
||||
manager.register_handler("web_search", web_search_handler)
|
||||
@@ -294,7 +298,8 @@ def _register_handlers() -> None:
|
||||
_handlers_registered = True
|
||||
|
||||
# 打印注册信息便于调试
|
||||
logger.info("handlers registered: %s", list(manager.handlers.keys()))tered: %s", list(manager.handlers.keys()))
|
||||
registered = list(getattr(manager, "handlers", {}).keys())
|
||||
logger.info("handlers registered: %s", registered)
|
||||
|
||||
|
||||
def _sse(event: str, data: dict) -> str:
|
||||
@@ -623,16 +628,28 @@ async def ocr_image(request: Request, req: OCRRequest, auth: dict = Security(_au
|
||||
except Exception as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=500)
|
||||
if len(image_bytes) > config.ocr_max_input_bytes:
|
||||
return JSONResponse({"error": "图片过大,无法执行 OCR"}, status_code=400)
|
||||
return JSONResponse({"error": "文件过大,无法执行 OCR/视频解析"}, status_code=400)
|
||||
input_path = persist_temp_input(image_bytes, os.path.splitext(req.filename)[1] or ".img")
|
||||
try:
|
||||
identity, payload = await _prepare_llm_payload(
|
||||
request,
|
||||
job_type="ocr",
|
||||
request_body={"filename": req.filename, "language": req.language, "image_bytes": len(image_bytes)},
|
||||
request_body={
|
||||
"filename": req.filename,
|
||||
"language": req.language,
|
||||
"media_type": req.media_type,
|
||||
"mime_type": req.mime_type,
|
||||
"image_bytes": len(image_bytes),
|
||||
},
|
||||
raw_size=len(image_bytes),
|
||||
token_source_text=f"{req.filename}:{len(image_bytes)}:{req.language}",
|
||||
extra_payload={"input_path": input_path, "filename": req.filename, "language": req.language},
|
||||
token_source_text=f"{req.filename}:{req.media_type}:{req.mime_type}:{len(image_bytes)}:{req.language}",
|
||||
extra_payload={
|
||||
"input_path": input_path,
|
||||
"filename": req.filename,
|
||||
"language": req.language,
|
||||
"media_type": req.media_type,
|
||||
"mime_type": req.mime_type,
|
||||
},
|
||||
)
|
||||
job_id = await _queue_job("ocr", payload, identity.request_id)
|
||||
except RiskRejected as exc:
|
||||
|
||||
Reference in New Issue
Block a user