Initial commit: VoIdeaAI - voice-first AI idea assistant
This commit is contained in:
+132
@@ -0,0 +1,132 @@
|
||||
import asyncio
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from slowapi import _rate_limit_exceeded_handler
|
||||
from slowapi.errors import RateLimitExceeded
|
||||
|
||||
from app.api.v1 import api_v1_router
|
||||
from app.core.config import get_settings
|
||||
from app.core.database import async_session_maker, engine
|
||||
from app.core.limiter import limiter
|
||||
from app.core.logging_middleware import DebugLoggingMiddleware
|
||||
from app.core.middleware import SecurityHeadersMiddleware
|
||||
from app.core.seed import seed_database
|
||||
from app.services.debug_service import DebugService
|
||||
|
||||
settings = get_settings()
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# Seed database on startup (idempotent — skips if data exists)
|
||||
try:
|
||||
async with async_session_maker() as db:
|
||||
await seed_database(db)
|
||||
except Exception:
|
||||
pass # DB may not be ready yet, seed will run on next restart
|
||||
|
||||
# Auto-cleanup logs on startup
|
||||
try:
|
||||
async with async_session_maker() as db:
|
||||
svc = DebugService(db)
|
||||
await svc.auto_cleanup_if_needed()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Sync bot commands on startup
|
||||
try:
|
||||
async with async_session_maker() as db:
|
||||
from app.integrations.telegram.sync_service import TelegramBotSyncService
|
||||
from app.integrations.telegram.client import TelegramBotClient
|
||||
bot_client = TelegramBotClient(token=settings.telegram_bot_token)
|
||||
svc = TelegramBotSyncService(db, bot_client)
|
||||
await svc.full_sync()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Auto-run QATesterAgent after fresh deploy (within 5 min)
|
||||
async def _auto_qa():
|
||||
try:
|
||||
deploy_stamp = "/opt/voidea/.last_deploy"
|
||||
if not os.path.exists(deploy_stamp):
|
||||
return
|
||||
with open(deploy_stamp) as f:
|
||||
ts = int(f.read().strip())
|
||||
if (datetime.now().timestamp() - ts) > 300:
|
||||
return # older than 5 min
|
||||
|
||||
await asyncio.sleep(3)
|
||||
async with async_session_maker() as db:
|
||||
from app.agents.qa_tester_agent import QATesterAgent
|
||||
agent = QATesterAgent(session=db)
|
||||
result = await agent.run({"action": "api", "test_count": 2})
|
||||
if not result.success:
|
||||
logger = __import__("logging").getLogger("voidea.qa_auto")
|
||||
logger.warning("Auto-QA after deploy: %s", result.message)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
asyncio.create_task(_auto_qa())
|
||||
|
||||
yield
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title=settings.project_name,
|
||||
description="VoIdeaAI — идеи рождаются вслух, решения приходят мгновенно!",
|
||||
version=settings.project_version,
|
||||
docs_url="/docs",
|
||||
redoc_url="/redoc",
|
||||
openapi_url="/openapi.json",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
app.state.limiter = limiter
|
||||
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
||||
|
||||
app.include_router(api_v1_router)
|
||||
|
||||
app.mount("/assets", StaticFiles(directory="webui/dist/assets"), name="assets")
|
||||
|
||||
app.mount("/icons", StaticFiles(directory="webui/dist/icons"), name="icons")
|
||||
|
||||
app.mount("/", StaticFiles(directory="webui/dist", html=True), name="static")
|
||||
|
||||
app.add_middleware(SecurityHeadersMiddleware)
|
||||
|
||||
app.add_middleware(DebugLoggingMiddleware)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=settings.cors_origins_list,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
@limiter.limit("30/minute")
|
||||
async def health_check(request: Request):
|
||||
return {
|
||||
"status": "healthy",
|
||||
"version": settings.project_version,
|
||||
"environment": settings.project_env,
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/v1/health")
|
||||
@limiter.limit("30/minute")
|
||||
async def api_health(request: Request):
|
||||
return {
|
||||
"status": "healthy",
|
||||
"api_version": "v1",
|
||||
"database": "connected",
|
||||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||||
}
|
||||
Reference in New Issue
Block a user