File size: 5,732 Bytes
5df55ff 8fab536 5df55ff 8fab536 5df55ff 8fab536 5df55ff 8c81e76 8fab536 5df55ff 8fab536 5df55ff 8c81e76 5df55ff 8fab536 5df55ff 8fab536 5df55ff 8fab536 5df55ff 8fab536 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | """PitchFight AI — Gradio Server app with custom frontend."""
from __future__ import annotations
import os
from pathlib import Path
from typing import Any
from fastapi import Body
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from gradio import Server
from core.api_handlers import (
handle_chat_round,
handle_deck_critique_placeholder,
handle_end_battle,
handle_end_deal,
handle_deal_round,
handle_load_sample,
handle_reset_session,
handle_retry_weakest_start,
handle_retry_weakest_submit,
handle_start_deal_phase,
handle_start_session,
handle_structure_pitch,
handle_voice_pitch,
handle_voice_turn,
)
from core import model_router
APP_VERSION = "0.1.0"
PITCHFIGHT_PORT = int(os.getenv("PITCHFIGHT_PORT", "7860"))
FRONTEND_DIR = Path(__file__).parent / "frontend"
app = Server()
# ---------------------------------------------------------------------------
# PitchFight REST API (product endpoints — use these from the custom frontend)
# ---------------------------------------------------------------------------
@app.get("/health")
async def health() -> dict[str, str]:
"""Health check for app status."""
return {"status": "ok", "app": "PitchFight AI", "version": APP_VERSION}
@app.get("/api/model-health")
async def api_model_health() -> dict[str, Any]:
"""Model provider configuration status. Keys are never exposed."""
return model_router.get_model_health()
@app.post("/api/load-sample")
def api_load_sample() -> dict[str, Any]:
return handle_load_sample()
@app.post("/api/start-session")
def api_start_session(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_start_session(payload)
@app.post("/api/structure-pitch")
def api_structure_pitch(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_structure_pitch(payload)
@app.post("/api/chat-round")
def api_chat_round(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_chat_round(payload)
@app.post("/api/end-battle")
def api_end_battle(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_end_battle(payload)
@app.post("/api/retry-weakest-question/start")
def api_retry_weakest_start(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_retry_weakest_start(payload)
@app.post("/api/retry-weakest-question/submit")
def api_retry_weakest_submit(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_retry_weakest_submit(payload)
@app.post("/api/reset-session")
def api_reset_session(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_reset_session(payload)
@app.post("/api/voice-pitch")
def api_voice_pitch(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_voice_pitch(payload)
@app.post("/api/voice-turn")
def api_voice_turn(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_voice_turn(payload)
@app.post("/api/start-deal-phase")
def api_start_deal_phase(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_start_deal_phase(payload)
@app.post("/api/deal-round")
def api_deal_round(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_deal_round(payload)
@app.post("/api/end-deal")
def api_end_deal(payload: dict[str, Any] = Body(...)) -> dict[str, Any]:
return handle_end_deal(payload)
@app.post("/api/deck-critique")
def api_deck_critique(payload: dict[str, Any] = Body(default_factory=dict)) -> dict[str, str]:
return handle_deck_critique_placeholder(payload)
# ---------------------------------------------------------------------------
# Gradio @app.api compatibility (same handlers — for gradio_client / queue)
# ---------------------------------------------------------------------------
@app.api(name="load_sample")
def gradio_load_sample() -> dict[str, Any]:
return handle_load_sample()
@app.api(name="start_session")
def gradio_start_session(payload: dict[str, Any]) -> dict[str, Any]:
return handle_start_session(payload)
@app.api(name="chat_round")
def gradio_chat_round(payload: dict[str, Any]) -> dict[str, Any]:
return handle_chat_round(payload)
@app.api(name="end_battle")
def gradio_end_battle(payload: dict[str, Any]) -> dict[str, Any]:
return handle_end_battle(payload)
@app.api(name="reset_session")
def gradio_reset_session(payload: dict[str, Any]) -> dict[str, Any]:
return handle_reset_session(payload)
# ---------------------------------------------------------------------------
# Frontend
# ---------------------------------------------------------------------------
@app.get("/", response_class=HTMLResponse)
async def homepage() -> HTMLResponse:
"""Serve the custom PitchFight frontend."""
index_path = FRONTEND_DIR / "index.html"
return HTMLResponse(index_path.read_text(encoding="utf-8"))
app.mount("/frontend", StaticFiles(directory=str(FRONTEND_DIR)), name="frontend")
if __name__ == "__main__":
url = f"http://127.0.0.1:{PITCHFIGHT_PORT}"
print(f"Starting PitchFight AI on {url}")
try:
app.launch(show_error=True, server_port=PITCHFIGHT_PORT)
except OSError as exc:
if "empty port" in str(exc).lower() or str(PITCHFIGHT_PORT) in str(exc):
print(
f"\nERROR: Port {PITCHFIGHT_PORT} is already in use by another process.\n"
f"Stop the old server (Ctrl+C in its terminal), or free the port:\n"
f" netstat -ano | findstr \":{PITCHFIGHT_PORT}\"\n"
f" taskkill /PID <pid> /F\n"
f"Then run: python app.py\n"
)
raise SystemExit(1) from exc
|