Spaces:
Sleeping
Sleeping
return to faiz last commit
Browse files- app/main.py +9 -81
app/main.py
CHANGED
|
@@ -29,51 +29,14 @@ except ImportError:
|
|
| 29 |
API_KEY = os.getenv("GEMINI_API_KEY", "")
|
| 30 |
MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-pro")
|
| 31 |
GEMINI_SMALL_MODEL = os.getenv("GEMINI_SMALL_MODEL")
|
| 32 |
-
|
| 33 |
-
OPENAI_SMALL_MODEL = os.getenv("OPENAI_SMALL_MODEL") or DEFAULT_OPENAI_SMALL_MODEL
|
| 34 |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
| 35 |
USE_OPENAI = os.getenv("USE_OPENAI", "").lower() == "true"
|
| 36 |
PORT = int(os.getenv("PORT", "7860"))
|
| 37 |
|
| 38 |
-
_OPENAI_RESPONSES_MODELS_ENV = os.getenv("OPENAI_RESPONSES_MODELS", "")
|
| 39 |
-
RESPONSES_API_MODEL_NAMES = {"gpt-5-mini"}
|
| 40 |
-
if _OPENAI_RESPONSES_MODELS_ENV:
|
| 41 |
-
RESPONSES_API_MODEL_NAMES.update(
|
| 42 |
-
model.strip().lower()
|
| 43 |
-
for model in _OPENAI_RESPONSES_MODELS_ENV.split(",")
|
| 44 |
-
if model.strip()
|
| 45 |
-
)
|
| 46 |
-
|
| 47 |
-
_OPENAI_RESPONSES_PREFIXES_ENV = os.getenv("OPENAI_RESPONSES_PREFIXES", "")
|
| 48 |
-
_RESPONSES_API_MODEL_PREFIXES = ["gpt-5"]
|
| 49 |
-
if _OPENAI_RESPONSES_PREFIXES_ENV:
|
| 50 |
-
_RESPONSES_API_MODEL_PREFIXES.extend(
|
| 51 |
-
prefix.strip().lower()
|
| 52 |
-
for prefix in _OPENAI_RESPONSES_PREFIXES_ENV.split(",")
|
| 53 |
-
if prefix.strip()
|
| 54 |
-
)
|
| 55 |
-
RESPONSES_API_MODEL_PREFIXES = tuple(_RESPONSES_API_MODEL_PREFIXES)
|
| 56 |
-
RESPONSES_API_ERROR_HINTS = (
|
| 57 |
-
"only supported in v1/responses",
|
| 58 |
-
"use the responses api",
|
| 59 |
-
"use the responses endpoint",
|
| 60 |
-
"please call the responses api",
|
| 61 |
-
"please use the responses endpoint",
|
| 62 |
-
)
|
| 63 |
-
|
| 64 |
gemini_client = genai.Client(api_key=API_KEY) if API_KEY else None
|
| 65 |
gpt_client = OpenAI(api_key=OPENAI_API_KEY) if (OPENAI_API_KEY and OpenAI and USE_OPENAI) else None
|
| 66 |
|
| 67 |
-
def _active_storyboard_model() -> str:
|
| 68 |
-
"""
|
| 69 |
-
Return the identifier of the model used for storyboard chats.
|
| 70 |
-
Example: "openai:gpt-5-mini" or "gemini:gemini-2.5-pro".
|
| 71 |
-
"""
|
| 72 |
-
if gpt_client:
|
| 73 |
-
return f"openai:{OPENAI_SMALL_MODEL}"
|
| 74 |
-
fallback = GEMINI_SMALL_MODEL or MODEL or "gemini-unknown"
|
| 75 |
-
return f"gemini:{fallback}"
|
| 76 |
-
|
| 77 |
# -------- FastAPI app --------
|
| 78 |
app = FastAPI(title="Manim Render API (error + visual refine)")
|
| 79 |
app.add_middleware(
|
|
@@ -199,22 +162,6 @@ def _build_responses_input(system: str, contents: Any) -> List[Dict[str, Any]]:
|
|
| 199 |
{"role": "user", "content": _build_openai_content(contents, for_chat=False)},
|
| 200 |
]
|
| 201 |
|
| 202 |
-
def _requires_responses_api(model: str) -> bool:
|
| 203 |
-
lowered = (model or "").lower()
|
| 204 |
-
if not lowered:
|
| 205 |
-
return False
|
| 206 |
-
if lowered in RESPONSES_API_MODEL_NAMES:
|
| 207 |
-
return True
|
| 208 |
-
return any(
|
| 209 |
-
prefix and lowered.startswith(prefix)
|
| 210 |
-
for prefix in RESPONSES_API_MODEL_PREFIXES
|
| 211 |
-
)
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
def _should_use_responses_fallback(err: Exception) -> bool:
|
| 215 |
-
message = str(err).lower()
|
| 216 |
-
return any(hint in message for hint in RESPONSES_API_ERROR_HINTS)
|
| 217 |
-
|
| 218 |
|
| 219 |
def _extract_chat_content(resp: Any) -> str:
|
| 220 |
content = resp.choices[0].message.content
|
|
@@ -252,20 +199,17 @@ def _invoke_gpt_model(model: str, system: str, contents: Any) -> str:
|
|
| 252 |
if not gpt_client:
|
| 253 |
raise RuntimeError("GPT client is not configured")
|
| 254 |
messages = _build_chat_messages(system, contents)
|
| 255 |
-
responses_input: Optional[List[Dict[str, Any]]] = None
|
| 256 |
-
if _requires_responses_api(model):
|
| 257 |
-
responses_input = _build_responses_input(system, contents)
|
| 258 |
-
resp = gpt_client.responses.create(model=model, input=responses_input)
|
| 259 |
-
return _extract_responses_content(resp)
|
| 260 |
try:
|
| 261 |
resp = gpt_client.chat.completions.create(model=model, messages=messages)
|
| 262 |
return _extract_chat_content(resp)
|
| 263 |
except Exception as err:
|
| 264 |
-
|
|
|
|
| 265 |
raise
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
|
|
|
| 269 |
return _extract_responses_content(resp)
|
| 270 |
|
| 271 |
|
|
@@ -290,13 +234,7 @@ def gemini_small_call(*, system: str, contents: str) -> str:
|
|
| 290 |
return _invoke_gpt_model(target_model, system, contents)
|
| 291 |
if not gemini_client:
|
| 292 |
raise RuntimeError("Gemini client is not configured")
|
| 293 |
-
fallback_model =
|
| 294 |
-
if (
|
| 295 |
-
not fallback_model
|
| 296 |
-
or _requires_responses_api(fallback_model)
|
| 297 |
-
or str(fallback_model).lower().startswith("gpt-")
|
| 298 |
-
):
|
| 299 |
-
fallback_model = MODEL
|
| 300 |
resp = gemini_client.models.generate_content(
|
| 301 |
model=fallback_model,
|
| 302 |
config=types.GenerateContentConfig(system_instruction=system),
|
|
@@ -1236,7 +1174,6 @@ def storyboard_chat(inp: StoryboardChatIn):
|
|
| 1236 |
"plan": plan_model.dict(),
|
| 1237 |
"questions": questions,
|
| 1238 |
"settings": session.settings,
|
| 1239 |
-
"model": _active_storyboard_model(),
|
| 1240 |
}
|
| 1241 |
|
| 1242 |
|
|
@@ -1267,7 +1204,6 @@ def storyboard_confirm(inp: StoryboardConfirmIn):
|
|
| 1267 |
"render_prompt": render_prompt,
|
| 1268 |
"plan": final_plan.dict(),
|
| 1269 |
"settings": session.settings,
|
| 1270 |
-
"model": _active_storyboard_model(),
|
| 1271 |
}
|
| 1272 |
|
| 1273 |
|
|
@@ -1337,9 +1273,6 @@ def health():
|
|
| 1337 |
"model": MODEL,
|
| 1338 |
"has_gemini": bool(gemini_client),
|
| 1339 |
"has_gpt": bool(gpt_client),
|
| 1340 |
-
"use_openai": bool(gpt_client),
|
| 1341 |
-
"storyboard_model": _active_storyboard_model(),
|
| 1342 |
-
"openai_small_model": OPENAI_SMALL_MODEL if gpt_client else None,
|
| 1343 |
}
|
| 1344 |
|
| 1345 |
@app.post("/generate-code")
|
|
@@ -1418,12 +1351,7 @@ def render_code(inp: RenderCodeIn):
|
|
| 1418 |
detail_log = (final_log or log)[-6000:]
|
| 1419 |
raise HTTPException(
|
| 1420 |
status_code=400,
|
| 1421 |
-
detail={
|
| 1422 |
-
"error": "render_failed",
|
| 1423 |
-
"message": "Render failed after automatic fixes. Please review the log for details.",
|
| 1424 |
-
"log": detail_log,
|
| 1425 |
-
"code": inp.code,
|
| 1426 |
-
},
|
| 1427 |
)
|
| 1428 |
except RuntimeError:
|
| 1429 |
raise HTTPException(
|
|
|
|
| 29 |
API_KEY = os.getenv("GEMINI_API_KEY", "")
|
| 30 |
MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-pro")
|
| 31 |
GEMINI_SMALL_MODEL = os.getenv("GEMINI_SMALL_MODEL")
|
| 32 |
+
OPENAI_SMALL_MODEL = os.getenv("OPENAI_SMALL_MODEL") or "gpt-4o-mini"
|
|
|
|
| 33 |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
| 34 |
USE_OPENAI = os.getenv("USE_OPENAI", "").lower() == "true"
|
| 35 |
PORT = int(os.getenv("PORT", "7860"))
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
gemini_client = genai.Client(api_key=API_KEY) if API_KEY else None
|
| 38 |
gpt_client = OpenAI(api_key=OPENAI_API_KEY) if (OPENAI_API_KEY and OpenAI and USE_OPENAI) else None
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
# -------- FastAPI app --------
|
| 41 |
app = FastAPI(title="Manim Render API (error + visual refine)")
|
| 42 |
app.add_middleware(
|
|
|
|
| 162 |
{"role": "user", "content": _build_openai_content(contents, for_chat=False)},
|
| 163 |
]
|
| 164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
|
| 166 |
def _extract_chat_content(resp: Any) -> str:
|
| 167 |
content = resp.choices[0].message.content
|
|
|
|
| 199 |
if not gpt_client:
|
| 200 |
raise RuntimeError("GPT client is not configured")
|
| 201 |
messages = _build_chat_messages(system, contents)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
try:
|
| 203 |
resp = gpt_client.chat.completions.create(model=model, messages=messages)
|
| 204 |
return _extract_chat_content(resp)
|
| 205 |
except Exception as err:
|
| 206 |
+
message = str(err)
|
| 207 |
+
if "only supported in v1/responses" not in message:
|
| 208 |
raise
|
| 209 |
+
resp = gpt_client.responses.create(
|
| 210 |
+
model=model,
|
| 211 |
+
input=_build_responses_input(system, contents),
|
| 212 |
+
)
|
| 213 |
return _extract_responses_content(resp)
|
| 214 |
|
| 215 |
|
|
|
|
| 234 |
return _invoke_gpt_model(target_model, system, contents)
|
| 235 |
if not gemini_client:
|
| 236 |
raise RuntimeError("Gemini client is not configured")
|
| 237 |
+
fallback_model = GEMINI_SMALL_MODEL or MODEL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
resp = gemini_client.models.generate_content(
|
| 239 |
model=fallback_model,
|
| 240 |
config=types.GenerateContentConfig(system_instruction=system),
|
|
|
|
| 1174 |
"plan": plan_model.dict(),
|
| 1175 |
"questions": questions,
|
| 1176 |
"settings": session.settings,
|
|
|
|
| 1177 |
}
|
| 1178 |
|
| 1179 |
|
|
|
|
| 1204 |
"render_prompt": render_prompt,
|
| 1205 |
"plan": final_plan.dict(),
|
| 1206 |
"settings": session.settings,
|
|
|
|
| 1207 |
}
|
| 1208 |
|
| 1209 |
|
|
|
|
| 1273 |
"model": MODEL,
|
| 1274 |
"has_gemini": bool(gemini_client),
|
| 1275 |
"has_gpt": bool(gpt_client),
|
|
|
|
|
|
|
|
|
|
| 1276 |
}
|
| 1277 |
|
| 1278 |
@app.post("/generate-code")
|
|
|
|
| 1351 |
detail_log = (final_log or log)[-6000:]
|
| 1352 |
raise HTTPException(
|
| 1353 |
status_code=400,
|
| 1354 |
+
detail={"error": "Render failed", "log": detail_log, "code": inp.code},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1355 |
)
|
| 1356 |
except RuntimeError:
|
| 1357 |
raise HTTPException(
|