File size: 6,744 Bytes
1bc6e15 |
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 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
#!/usr/bin/env python3
"""
run.py - FastAPI backend + frontend server for GAKR AI
Features:
- Serves templates/chat.html at "/"
- /api/analyze:
- prompt: required (must not be empty)
- files: optional list[UploadFile] (0, 1, many; any type)
- api_key: required
- If files are present β file-analysis mode (different system prompt)
- If no files β general assistant mode
- Detailed exceptions and logs for easier debugging
"""
from typing import List, Optional
import json
import traceback
from fastapi import (
FastAPI,
HTTPException,
Form,
UploadFile,
File,
Request,
)
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates
import uvicorn
from load_model import init_model
from generate import generate_response
from file_pipeline import process_files
# ============================================================
# APP SETUP
# ============================================================
app = FastAPI(title="GAKR AI")
# Templates (chat.html lives in ./templates)
templates = Jinja2Templates(directory="templates")
# CORS (open for dev; restrict origins in production)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # change to specific origin in production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# API Key
API_KEY = "gakr-ai-2025-secret"
# Load model ONCE at startup
print("π Starting GAKR AI Backend...")
try:
model, tokenizer = init_model(".")
print("β
Model initialized successfully")
except Exception as e:
print("β Failed to load model at startup:")
traceback.print_exc()
raise e
# ============================================================
# ROUTES
# ============================================================
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
"""
Serve chat.html as homepage.
"""
try:
return templates.TemplateResponse("chat.html", {"request": request})
except Exception as e:
# If template not found or other template error
traceback.print_exc()
raise HTTPException(
status_code=500,
detail=f"Failed to render chat.html: {str(e)}",
)
@app.post("/api/analyze")
async def analyze_endpoint(
prompt: str = Form(...), # required
api_key: str = Form(...),
files: Optional[List[UploadFile]] = File(None), # optional
):
"""
Main analysis endpoint.
Cases:
- prompt only (no files) β general assistant mode
- prompt + one/many files β file-analysis mode (uses file context)
"""
try:
# ---------- Basic validation ----------
if api_key != API_KEY:
raise HTTPException(status_code=401, detail="Invalid API key")
if prompt is None:
raise HTTPException(status_code=400, detail="Prompt is missing")
if not prompt.strip():
raise HTTPException(status_code=400, detail="Prompt cannot be empty")
files = files or []
# ---------- Branch by presence of files ----------
if files:
# ----- CASE 1: prompt + files -----
try:
context = await process_files(files)
except Exception as extract_err:
traceback.print_exc()
raise HTTPException(
status_code=500,
detail=f"Error while processing uploaded files: {str(extract_err)}",
)
context_text = json.dumps(context, indent=2, ensure_ascii=False)
combined_user_prompt = f"""
User question:
{prompt}
Below is structured information extracted from the user's uploaded files.
The extraction was done by automated tools.
Your task:
1. Answer the user's question as accurately as possible.
2. Use the context when it is relevant.
3. Highlight important patterns, risks, or opportunities.
4. If some information is missing or uncertain, say so honestly.
Context:
{context_text}
"""
system_prompt = (
"You are GAKR AI, a careful and honest analysis assistant that works with "
"structured summaries of files (tables, PDFs, documents, images, audio, video, etc.). "
"You never assume file contents beyond what the provided context states."
)
else:
# ----- CASE 2: prompt only -----
context = {"files": []} # keep structure consistent
combined_user_prompt = prompt
system_prompt = (
"You are GAKR AI, a helpful and honest general-purpose assistant. "
"You answer questions, explain concepts, help with reasoning and coding, "
"using your knowledge up to 2024. Be clear, concise, and direct."
)
# ---------- Generate with Phiβ3 ----------
try:
response_text = generate_response(
user_prompt=combined_user_prompt,
system_prompt=system_prompt,
max_tokens=512,
temperature=0.2,
)
except Exception as gen_err:
traceback.print_exc()
raise HTTPException(
status_code=500,
detail=f"Error during model generation: {str(gen_err)}",
)
return JSONResponse(
{
"response": response_text,
"context": context,
"status": "success",
}
)
except HTTPException:
# Let FastAPI handle HTTPException as-is
raise
except Exception as e:
# Unexpected error: log full traceback and return 500
traceback.print_exc()
raise HTTPException(
status_code=500,
detail=f"Unexpected backend error: {str(e)}",
)
@app.get("/health")
async def health_check():
"""
Simple health check.
"""
return {"status": "healthy", "model_loaded": True}
# ============================================================
# ENTRY POINT
# ============================================================
if __name__ == "__main__":
print("\n" + "=" * 60)
print("π SERVER & CHAT LOCATION")
print("=" * 60)
print("π CHAT INTERFACE: http://localhost:8080")
print("π± ALTERNATIVE URL: http://127.0.0.1:8080")
print("π§ API DOCUMENTATION: http://localhost:8080/docs")
print("β
CHAT.HTML SERVED: templates/chat.html")
print("π TEMPLATES FOLDER: ./templates/")
print("=" * 60 + "\n")
uvicorn.run(app, host="0.0.0.0", port=8080)
|