| from fastapi import FastAPI, UploadFile, File, Form |
| from fastapi.responses import FileResponse, JSONResponse |
| from gradio_client import Client, handle_file |
| from gradio_client.exceptions import AppError |
| import tempfile |
| import os |
| import shutil |
|
|
| HF_TOKEN = os.getenv("HF_TOKEN") |
|
|
| app = FastAPI(title="ZHSAPI") |
|
|
|
|
| @app.get("/health") |
| def health(): |
| return {"status": "ok"} |
|
|
|
|
| @app.post("/timelapse") |
| async def generate_timelapse( |
| start_frame: UploadFile = File(...), |
| end_frame: UploadFile = File(...), |
| prompt: str = Form(default="a construction timelapse"), |
| ): |
| with tempfile.TemporaryDirectory() as tmpdir: |
| start_path = os.path.join(tmpdir, start_frame.filename) |
| end_path = os.path.join(tmpdir, end_frame.filename) |
|
|
| with open(start_path, "wb") as f: |
| shutil.copyfileobj(start_frame.file, f) |
| with open(end_path, "wb") as f: |
| shutil.copyfileobj(end_frame.file, f) |
|
|
| |
| try: |
| client = Client("linoyts/LTX-2-3-First-Last-Frame", token=HF_TOKEN) |
| result = client.predict( |
| first_image=handle_file(start_path), |
| last_image=handle_file(end_path), |
| input_audio=None, |
| prompt=prompt, |
| api_name="/generate_video", |
| ) |
| output_path = result[0] if isinstance(result, (list, tuple)) else result |
| except AppError as e: |
| if "GPU quota" not in str(e): |
| return JSONResponse(status_code=502, content={"error": str(e)}) |
|
|
| |
| film = Client("freealise/video_frame_interpolation") |
| loaded = film.predict( |
| f=[handle_file(start_path), handle_file(end_path)], |
| r_bg=False, |
| api_name="/loadf", |
| ) |
| frames = loaded[0] |
| result = film.predict( |
| f_in=frames, |
| interpolation=4, |
| fps_output=0, |
| api_name="/infer", |
| ) |
| output_path = result[0]["video"] if isinstance(result[0], dict) else result[0] |
|
|
| return FileResponse(output_path, media_type="video/mp4", filename="timelapse.mp4") |
|
|