Spaces:
Running
Running
File size: 5,303 Bytes
85f900d | 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 | """
VoiceVault β FastAPI Server
============================
Custom web frontend entry point. Serves the HTML/CSS/JS SPA and REST API.
Run: python server.py
URL: http://localhost:7860
"""
from __future__ import annotations
# ββ Environment overrides (must be first, before any ML imports) ββββββββ
import os
# RTX 5070 (sm_120) incompatible with packaged PyTorch β force CPU
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
# Suppress Windows symlink warning from huggingface_hub cache
os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1"
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
import logging
import sys
from contextlib import asynccontextmanager
from pathlib import Path
import uvicorn
from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from config import cfg
from voicevault import __version__
# ------------------------------------------------------------------ #
# Logging #
# ------------------------------------------------------------------ #
logging.basicConfig(
level=logging.DEBUG if cfg.debug else logging.INFO,
format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[logging.StreamHandler(sys.stdout)],
)
logger = logging.getLogger(__name__)
# Suppress noisy third-party loggers that spam the console
for _noisy in ("httpx", "httpcore", "huggingface_hub", "sentence_transformers",
"transformers", "filelock", "urllib3"):
logging.getLogger(_noisy).setLevel(logging.WARNING)
_CENTRAL_DB_PATH = cfg.data_dir / "voicevault.db"
_STATIC_DIR = Path(__file__).parent / "static"
# ------------------------------------------------------------------ #
# Startup #
# ------------------------------------------------------------------ #
def _startup():
"""Initialize all pipeline components."""
cfg.ensure_directories()
logger.info("=" * 60)
logger.info("VoiceVault v%s β FastAPI Server Starting", __version__)
logger.info("Data directory : %s", cfg.data_dir.resolve())
logger.info("Central DB : %s", _CENTRAL_DB_PATH)
logger.info("Groq key : %s", "β configured" if cfg.has_groq_key() else "β not set")
logger.info("Gemini key : %s", "β configured" if cfg.has_gemini_key() else "β not set")
logger.info("Static dir : %s", _STATIC_DIR.resolve())
logger.info("=" * 60)
if not cfg.has_any_llm_key():
logger.warning("No LLM API key found β set GROQ_API_KEY or GEMINI_API_KEY in .env")
from voicevault.kb.kb_manager import KBManager
kb_manager = KBManager(db_path=_CENTRAL_DB_PATH)
logger.info("KBManager ready β %d KB(s) found", len(kb_manager.list_kbs()))
# Prefer Groq Whisper API (instant, ~200ms) over local model (slow CPU)
if cfg.has_groq_key():
from voicevault.asr.groq_transcriber import GroqTranscriber
transcriber = GroqTranscriber()
logger.info("Transcriber: Groq Whisper API (whisper-large-v3-turbo) β fast cloud mode")
else:
from voicevault.asr.whisper_transcriber import WhisperTranscriber
transcriber = WhisperTranscriber()
logger.info("Transcriber: local Whisper (CPU) β set GROQ_API_KEY for instant transcription")
from voicevault.generation.answer_chain import AnswerChain
answer_chain = AnswerChain()
logger.info("AnswerChain ready (Groq β Gemini fallback)")
return kb_manager, transcriber, answer_chain
# ------------------------------------------------------------------ #
# App Factory #
# ------------------------------------------------------------------ #
@asynccontextmanager
async def _lifespan(app: FastAPI):
"""Initialize pipeline singletons before the server starts accepting requests."""
kb_manager, transcriber, answer_chain = _startup()
from api.routes import init_routes
init_routes(kb_manager, transcriber, answer_chain, _CENTRAL_DB_PATH)
logger.info("All routes initialized. App is ready.")
yield
# (shutdown hooks go here if needed)
def create_app() -> FastAPI:
app = FastAPI(
title="VoiceVault",
version=__version__,
docs_url=None,
redoc_url=None,
lifespan=_lifespan,
)
# Serve static assets
app.mount("/static", StaticFiles(directory=str(_STATIC_DIR)), name="static")
from api.routes import router
app.include_router(router)
@app.get("/")
async def index():
return FileResponse(_STATIC_DIR / "index.html")
return app
# ------------------------------------------------------------------ #
# Entry Point #
# ------------------------------------------------------------------ #
app = create_app()
if __name__ == "__main__":
uvicorn.run(
"server:app",
host=cfg.host,
port=cfg.port,
reload=False,
log_level="info",
)
|