File size: 4,513 Bytes
25f9893
 
 
 
 
8ba01c3
b10856a
 
f6b1e89
12832d8
b10856a
 
cfdd7b3
ce181f4
e627b57
6fdf170
 
385aed6
25f9893
c3bf14b
 
d8f52d8
 
 
 
25f9893
d8f52d8
 
 
78be6d7
25f9893
 
 
d8f52d8
 
25f9893
 
 
 
 
 
 
 
d8f52d8
25f9893
d8f52d8
 
 
 
 
 
12832d8
34caeeb
 
 
 
6fdf170
 
25f9893
 
6fdf170
29f5dfb
f6b1e89
 
 
 
 
 
 
 
 
 
 
25f9893
385aed6
78be6d7
fb62834
25f9893
 
 
 
 
6fdf170
ee25b7a
12832d8
b10856a
 
 
ce181f4
 
 
 
 
b10856a
25f9893
 
 
a50f65d
25f9893
 
 
 
 
 
 
 
 
 
 
b10856a
25f9893
 
 
 
 
 
78be6d7
25f9893
 
 
 
b10856a
12832d8
78be6d7
b10856a
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
"""
Flare – Main Application (Refactored)
=====================================
"""

from fastapi import FastAPI, WebSocket
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import os
from pathlib import Path
import mimetypes
from websocket_handler import websocket_endpoint

from utils import log
from chat_handler import router as chat_router  # ← start_session & chat
from admin_routes import router as admin_router, start_cleanup_task
from llm_startup import run_in_thread  # Changed from spark_startup
from session import session_store, start_session_cleanup

from config_provider import ConfigProvider

# ===================== Environment Setup =====================
def setup_environment():
    """Setup environment based on deployment mode"""
    cfg = ConfigProvider.get()
    
    log("=" * 60)
    log(f"πŸš€ Flare Starting")
    log(f"πŸ”Œ LLM Provider: {cfg.global_config.llm_provider.name}")
    log(f"🎀 TTS Provider: {cfg.global_config.tts_provider.name}")
    log(f"🎧 STT Provider: {cfg.global_config.stt_provider.name}")
    log("=" * 60)
    
    if cfg.global_config.is_cloud_mode():
        log("☁️  Cloud Mode: Using HuggingFace Secrets")
        log("πŸ“Œ Required secrets: JWT_SECRET, FLARE_TOKEN_KEY")
        
        # Check for provider-specific tokens
        llm_config = cfg.global_config.get_provider_config("llm", cfg.global_config.llm_provider.name)
        if llm_config and llm_config.requires_repo_info:
            log("πŸ“Œ LLM requires SPARK_TOKEN for repository operations")
    else:
        log("🏒 On-Premise Mode: Using .env file")
        if not Path(".env").exists():
            log("⚠️  WARNING: .env file not found!")
            log("πŸ“Œ Copy .env.example to .env and configure it")

# Run setup
setup_environment()

# Fix MIME types for JavaScript files
mimetypes.add_type("application/javascript", ".js")
mimetypes.add_type("text/css", ".css")

app = FastAPI(
    title="Flare Orchestration Service",
    version="2.0.0",
    description="LLM-driven intent & API flow engine with multi-provider support",
)

# CORS for development
if os.getenv("ENVIRONMENT") == "development":
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["http://localhost:4200"],  # Angular dev server
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    log("πŸ”§ CORS enabled for development")
    
run_in_thread()  # Start LLM startup notifier if needed
start_cleanup_task()  # Activity log cleanup
start_session_cleanup()  # Session cleanup

# ---------------- Health probe (HF Spaces watchdog) -----------------
@app.get("/")
def health_check():
    return {"status": "ok", "version": "2.0.0"}

# ---------------- Core chat/session routes --------------------------
app.include_router(chat_router, prefix="/api")

# ---------------- Admin API routes ----------------------------------
app.include_router(admin_router)

# ---------------- WebSocket route for real-time STT ------------------
@app.websocket("/ws/conversation/{session_id}")
async def conversation_websocket(websocket: WebSocket, session_id: str):
    await websocket_endpoint(websocket, session_id)
    
# ---------------- Serve Angular UI if exists ------------------------
static_dir = Path(__file__).parent / "static"
if static_dir.exists():
    log("🎨 Serving Angular UI from /static directory")
    
    # Mount static files with custom handler for Angular routing
    @app.get("/{path:path}")
    async def serve_angular(path: str):
        # API routes should not be handled here
        if path.startswith("api/"):
            return {"error": "Not found"}, 404
            
        # Try to serve the exact file first
        file_path = static_dir / path
        if file_path.is_file():
            return FileResponse(file_path)
        
        # For Angular routes, always serve index.html
        index_path = static_dir / "index.html"
        if index_path.exists():
            return FileResponse(index_path)
        
        return {"error": "Not found"}, 404
    
    # Mount static files for assets
    app.mount("/", StaticFiles(directory=str(static_dir), html=True), name="static")
else:
    log("⚠️ No UI found. Run 'cd flare-ui && npm run build' to build the UI.")

if __name__ == "__main__":
    log("🌐 Starting Flare backend on port 7860...")
    uvicorn.run(app, host="0.0.0.0", port=7860)