|
1 | | -import boto3 |
2 | | -import logging |
3 | | -from typing import Optional |
4 | | -from fastapi import FastAPI, HTTPException, Request |
5 | | -from fastapi.middleware.cors import CORSMiddleware |
6 | | -from pydantic import BaseModel, Field, ValidationError |
7 | | -from langchain_aws import BedrockEmbeddings |
8 | | -from fastapi.responses import JSONResponse |
9 | | -from contextlib import asynccontextmanager |
10 | | -from src.chatbot.config import DATA_DIRECTORY, FAISS_INDEX_PATH, TITAN_MODEL_ID, LLAMA_MODEL_ID, LOG_LEVEL |
11 | | -from src.chatbot.services import FAISSManager, PDFDocumentProcessor, LLMService |
| 1 | +import subprocess |
| 2 | +import os |
| 3 | +import time |
| 4 | +from threading import Thread |
12 | 5 |
|
13 | | -# Initialize FastAPI app |
14 | | -@asynccontextmanager |
15 | | -async def lifespan(app: FastAPI): |
| 6 | +# Function to run the FastAPI app |
| 7 | +def run_fastapi(): |
16 | 8 | try: |
17 | | - logger.info("Lifespan event triggered. Automatically running the /create_index endpoint...") |
18 | | - await create_index() # Automatically trigger create_index during startup |
| 9 | + # Assuming the FastAPI app is in app.py |
| 10 | + print("Starting FastAPI server...") |
| 11 | + subprocess.run(["uvicorn", "src.chatbot.main:app", "--host", "0.0.0.0", "--port", "8000"]) |
19 | 12 | except Exception as e: |
20 | | - logger.error(f"Error during lifespan event: {e}", exc_info=True) |
21 | | - yield # Continue with the application lifecycle |
| 13 | + print(f"Error running FastAPI: {e}") |
22 | 14 |
|
23 | | -app = FastAPI(lifespan=lifespan) |
24 | | - |
25 | | -# Add CORS middleware |
26 | | -app.add_middleware( |
27 | | - CORSMiddleware, |
28 | | - allow_origins=["*"], # Adjust this to your specific needs |
29 | | - allow_credentials=True, |
30 | | - allow_methods=["*"], |
31 | | - allow_headers=["*"], |
32 | | -) |
33 | | - |
34 | | -# Initialize logging |
35 | | -logging.basicConfig( |
36 | | - level=LOG_LEVEL, |
37 | | - format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", |
38 | | -) |
39 | | -logger = logging.getLogger(__name__) |
40 | | - |
41 | | -# Pydantic model for the question input |
42 | | -class QuestionRequest(BaseModel): |
43 | | - question: str = Field(..., json_schema_extra={"example": "What is the new tax laws??"}) |
44 | | - aws_access_key_id: Optional[str] = Field(None, json_schema_extra={"example": "your_access_key_id"}) |
45 | | - aws_secret_access_key: Optional[str] = Field(None, json_schema_extra={"example": "your_secret_access_key"}) |
46 | | - aws_default_region: Optional[str] = Field(None, json_schema_extra={"example": "your_region"}) |
47 | | - |
48 | | -# Middleware to log requests and responses |
49 | | -@app.middleware("http") |
50 | | -async def log_requests(request: Request, call_next): |
51 | | - logger.info(f"Incoming request: {request.method} {request.url}") |
52 | | - response = await call_next(request) |
53 | | - logger.info(f"Completed request: {request.method} {request.url} - Status code: {response.status_code}") |
54 | | - return response |
55 | | - |
56 | | -# Custom error handler for validation errors |
57 | | -@app.exception_handler(ValidationError) |
58 | | -async def validation_exception_handler(request: Request, exc: ValidationError): |
59 | | - logger.error(f"Validation error for request: {request.url} - {exc.errors()}") |
60 | | - return JSONResponse( |
61 | | - status_code=422, |
62 | | - content={ |
63 | | - "detail": exc.errors(), |
64 | | - "body": exc.body |
65 | | - }, |
66 | | - ) |
67 | | - |
68 | | -# General exception handler |
69 | | -@app.exception_handler(Exception) |
70 | | -async def general_exception_handler(request: Request, exc: Exception): |
71 | | - logger.error(f"An unexpected error occurred: {exc}", exc_info=True) |
72 | | - return JSONResponse(status_code=500, content={"detail": "An unexpected error occurred"}) |
73 | | - |
74 | | -# Endpoint to create FAISS index from PDF documents |
75 | | -@app.post("/create_index") |
76 | | -async def create_index(): |
| 15 | +# Function to update and run the React app |
| 16 | +def run_react(): |
77 | 17 | try: |
78 | | - logger.info("Creating FAISS index...") |
79 | | - |
80 | | - # Load and chunk PDF documents |
81 | | - processor = PDFDocumentProcessor(data_directory=DATA_DIRECTORY) |
82 | | - chunked_documents = processor.load_and_chunk_documents() |
83 | | - |
84 | | - # Load embeddings and create FAISS index |
85 | | - embeddings = BedrockEmbeddings(model_id=TITAN_MODEL_ID) |
86 | | - faiss_manager = FAISSManager(index_path=FAISS_INDEX_PATH, embeddings=embeddings) |
87 | | - faiss_manager.create_and_save_vector_store(chunked_documents) |
88 | | - |
89 | | - return {"message": "FAISS index created successfully."} |
90 | | - except HTTPException as http_exc: |
91 | | - raise http_exc |
92 | | - except Exception as e: |
93 | | - logger.error(f"Error creating FAISS index: {e}", exc_info=True) |
94 | | - raise HTTPException(status_code=500, detail="Error creating FAISS index") |
95 | | - |
96 | | -# Question answering endpoint |
97 | | -@app.post("/answer") |
98 | | -async def answer_question(request: QuestionRequest): |
99 | | - try: |
100 | | - logger.info(f"Received question: {request.question}") |
101 | | - |
102 | | - # Validate AWS credentials |
103 | | - if request.aws_access_key_id and request.aws_secret_access_key and request.aws_default_region: |
104 | | - logger.info("AWS credentials provided in the request.") |
105 | | - # Initialize Boto3 client using provided credentials |
106 | | - client = boto3.Session( |
107 | | - aws_access_key_id=request.aws_access_key_id, |
108 | | - aws_secret_access_key=request.aws_secret_access_key, |
109 | | - region_name=request.aws_default_region |
110 | | - ).client("bedrock-runtime") |
111 | | - else: |
112 | | - # Initialize Boto3 client using environment variables or credentials from AWS CLI |
113 | | - client = boto3.client("bedrock-runtime") |
114 | | - logger.info("Using AWS credentials from environment variables or AWS CLI configuration.") |
115 | | - |
116 | | - # Load FAISS index |
117 | | - embeddings = BedrockEmbeddings(model_id=TITAN_MODEL_ID) |
118 | | - faiss_manager = FAISSManager(index_path=FAISS_INDEX_PATH, embeddings=embeddings) |
119 | | - vectorstore_faiss = faiss_manager.load_vector_store() |
| 18 | + # Set working directory to the frontend React folder |
| 19 | + os.chdir('frontend-react') |
120 | 20 |
|
121 | | - # Initialize LLM |
122 | | - llm_service = LLMService(model_id=LLAMA_MODEL_ID, client=client) |
123 | | - llm = llm_service.initialize_llm() |
| 21 | + # Install dependencies if needed |
| 22 | + print("Installing npm dependencies...") |
| 23 | + subprocess.run(["npm", "install"]) |
124 | 24 |
|
125 | | - # Generate response |
126 | | - response = llm_service.generate_response(llm=llm, vectorstore_faiss=vectorstore_faiss, query=request.question) |
127 | | - return {"answer": response} |
| 25 | + # Fix vulnerabilities and update deprecated options |
| 26 | + print("Fixing vulnerabilities and updating dependencies...") |
| 27 | + #subprocess.run(["npm", "audit", "fix"]) |
| 28 | + #subprocess.run(["npm", "audit", "fix", "--force"]) |
128 | 29 |
|
129 | | - except HTTPException as http_exc: |
130 | | - raise http_exc |
| 30 | + # Start the React app using npm start |
| 31 | + print("Starting React app...") |
| 32 | + subprocess.run(["npm", "start"]) |
131 | 33 | except Exception as e: |
132 | | - logger.error(f"Error processing question: {e}", exc_info=True) |
133 | | - raise HTTPException(status_code=500, detail="Error processing question") |
| 34 | + print(f"Error running React app: {e}") |
| 35 | + finally: |
| 36 | + # Return to the original directory |
| 37 | + os.chdir('..') |
| 38 | + |
| 39 | +# Main function to run both FastAPI and React concurrently |
| 40 | +def main(): |
| 41 | + # Create threads to run both FastAPI and React |
| 42 | + fastapi_thread = Thread(target=run_fastapi) |
| 43 | + react_thread = Thread(target=run_react) |
| 44 | + |
| 45 | + # Start both threads |
| 46 | + fastapi_thread.start() |
| 47 | + time.sleep(5) # Give FastAPI a moment to start |
| 48 | + react_thread.start() |
| 49 | + |
| 50 | + # Wait for both threads to finish |
| 51 | + fastapi_thread.join() |
| 52 | + react_thread.join() |
| 53 | + |
| 54 | +if __name__ == "__main__": |
| 55 | + main() |
0 commit comments