接收 image + audio,返回视频字节(video/mp4)。忙时返回 503。
(
image: UploadFile = File(...),
audio: UploadFile = File(...),
)
| 117 | |
| 118 | @app.post("/infer") |
| 119 | async def infer( |
| 120 | image: UploadFile = File(...), |
| 121 | audio: UploadFile = File(...), |
| 122 | ): |
| 123 | """接收 image + audio,返回视频字节(video/mp4)。忙时返回 503。""" |
| 124 | global _total_requests, _in_flight |
| 125 | lock = _get_lock() |
| 126 | if not lock.acquire(blocking=False): |
| 127 | raise HTTPException(status_code=503, detail="Instance busy, try another or retry later") |
| 128 | |
| 129 | _in_flight = 1 |
| 130 | try: |
| 131 | _total_requests += 1 |
| 132 | with tempfile.TemporaryDirectory(prefix="echomimic_api_") as tmpdir: |
| 133 | tmp = Path(tmpdir) |
| 134 | img_path = tmp / (image.filename or "image.png") |
| 135 | aud_path = tmp / (audio.filename or "audio.wav") |
| 136 | with open(img_path, "wb") as f: |
| 137 | f.write(await image.read()) |
| 138 | with open(aud_path, "wb") as f: |
| 139 | f.write(await audio.read()) |
| 140 | |
| 141 | loop = asyncio.get_event_loop() |
| 142 | out_mp4 = await loop.run_in_executor( |
| 143 | None, |
| 144 | lambda: _run_echomimic_subprocess(str(img_path), str(aud_path), str(tmp)), |
| 145 | ) |
| 146 | if not out_mp4 or not out_mp4.exists(): |
| 147 | raise HTTPException(status_code=500, detail="EchoMimic did not produce output mp4") |
| 148 | data = out_mp4.read_bytes() |
| 149 | return Response(content=data, media_type="video/mp4") |
| 150 | except HTTPException: |
| 151 | raise |
| 152 | except Exception as e: |
| 153 | import traceback |
| 154 | tb = traceback.format_exc() |
| 155 | raise HTTPException(status_code=500, detail=f"EchoMimic inference failed: {e}\n{tb}") |
| 156 | finally: |
| 157 | _in_flight = 0 |
| 158 | lock.release() |
| 159 | |
| 160 | |
| 161 | @app.get("/health") |
nothing calls this directly
no test coverage detected