-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathapp.py
More file actions
145 lines (122 loc) · 4.51 KB
/
app.py
File metadata and controls
145 lines (122 loc) · 4.51 KB
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
import warnings
warnings.filterwarnings("ignore", message="resource_tracker: There appear to be.*")
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from pydantic import BaseModel
from typing import List, Optional
import os
from config import config
from rag_system import RAGSystem
# Initialize FastAPI app
app = FastAPI(title="Course Materials RAG System", root_path="")
# Add trusted host middleware for proxy
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=["*"]
)
# Enable CORS with proper settings for proxy
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
)
# Initialize RAG system
rag_system = RAGSystem(config)
# Pydantic models for request/response
class QueryRequest(BaseModel):
"""Request model for course queries"""
query: str
session_id: Optional[str] = None
class QueryResponse(BaseModel):
"""Response model for course queries"""
answer: str
sources: List[str]
session_id: str
class CourseStats(BaseModel):
"""Response model for course statistics"""
total_courses: int
course_titles: List[str]
class SessionClearRequest(BaseModel):
"""Request model for clearing session"""
session_id: Optional[str] = None
class SessionClearResponse(BaseModel):
"""Response model for session clear"""
success: bool
cleared_session_id: Optional[str] = None
# API Endpoints
@app.post("/api/session/clear", response_model=SessionClearResponse)
async def clear_session(request: SessionClearRequest):
"""Clear session history on the backend"""
try:
session_id = request.session_id
if session_id:
rag_system.session_manager.clear_session(session_id)
return SessionClearResponse(
success=True,
cleared_session_id=session_id
)
return SessionClearResponse(success=True, cleared_session_id=None)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/query", response_model=QueryResponse)
async def query_documents(request: QueryRequest):
"""Process a query and return response with sources"""
try:
# Create session if not provided
session_id = request.session_id
if not session_id:
session_id = rag_system.session_manager.create_session()
# Process query using RAG system
answer, sources = rag_system.query(request.query, session_id)
return QueryResponse(
answer=answer,
sources=sources,
session_id=session_id
)
except Exception as e:
import traceback
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/courses", response_model=CourseStats)
async def get_course_stats():
"""Get course analytics and statistics"""
try:
analytics = rag_system.get_course_analytics()
return CourseStats(
total_courses=analytics["total_courses"],
course_titles=analytics["course_titles"]
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.on_event("startup")
async def startup_event():
"""Load initial documents on startup"""
docs_path = "../docs"
if os.path.exists(docs_path):
print("Loading initial documents...")
try:
courses, chunks = rag_system.add_course_folder(docs_path, clear_existing=False)
print(f"Loaded {courses} courses with {chunks} chunks")
except Exception as e:
print(f"Error loading documents: {e}")
# Custom static file handler with no-cache headers for development
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
import os
from pathlib import Path
class DevStaticFiles(StaticFiles):
async def get_response(self, path: str, scope):
response = await super().get_response(path, scope)
if isinstance(response, FileResponse):
# Add no-cache headers for development
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
return response
# Serve static files for the frontend
app.mount("/", StaticFiles(directory="../frontend", html=True), name="static")