File size: 3,241 Bytes
6e94f25
 
 
 
 
 
 
 
 
 
 
555a055
 
 
 
6e94f25
 
 
 
 
 
 
555a055
6e94f25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
555a055
 
 
 
6e94f25
 
 
 
 
 
 
b64d6a4
6e94f25
 
8eaaf5c
6e94f25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import logging
import uvicorn
import json
import hashlib

# Import our existing pipeline components
from app.utils.util import verify_api_key
from app.core.models import llm_response_generator
from app.schema.schema import QuestionRequest, AnswerResponse

from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, Depends, status
from fastapi.responses import FileResponse, RedirectResponse

logging.basicConfig(format='%(asctime)s - %(levelname)s - Line: %(lineno)d - %(message)s', 
                    datefmt='%Y-%m-%d %H:%M:%S', 
                    level=logging.INFO)


os.environ["TOKENIZERS_PARALLELISM"] = "false"


# Load config.json at startup
@asynccontextmanager
async def lifespan(app: FastAPI):
    import json
    config_path = os.path.join(os.path.dirname(__file__), "app", "config", "config.json")
    with open(config_path, "r") as f:
        app.state.config = json.load(f)
    logging.info("Config loaded successfully.")
    yield
    logging.info("Shutting down FastAPI app...")


# FastAPI app
app = FastAPI(title="HackRx PDF RAG API", version="1.0.0", lifespan=lifespan)

@app.get("/", include_in_schema=False)
async def docs_redirect():
    return RedirectResponse("/docs")

@app.post("/api/v1/hackrx/run", response_model=AnswerResponse)
async def process_questions(request: QuestionRequest, api_key: str = Depends(verify_api_key)):
    try:
        url = str(request.documents)
        config = app.state.config
        questions = request.questions

        logging.info(f"Received {(questions)} questions for processing. Documents URL: {url}")

        # Create cache directory if not exists
        cache_dir = "/tmp/cache"
        os.makedirs(cache_dir, exist_ok=True)
        # Create a cache key from url and questions
        cache_key = hashlib.sha256((url + json.dumps(questions, sort_keys=True)).encode()).hexdigest()
        cache_file = os.path.join(cache_dir, f"{cache_key}.json")

        # Try to load from cache
        if os.path.exists(cache_file):
            logging.info(f"Cache hit for key: {cache_key}")
            with open(cache_file, "r") as f:
                cached_response = json.load(f)
            return cached_response

        # Otherwise, call LLM and cache response
        response, status_code = await llm_response_generator(config=config, url=url, questions=questions)
        if status_code != status.HTTP_200_OK:
            raise HTTPException(status_code=status_code, detail="Error processing questions")
        
        else:
            with open(cache_file, "w") as f:
                json.dump(response, f)
            logging.info(f"Cache saved for key: {cache_key}")
            return response

    except Exception as e:
        logging.error(f"Error processing questions: {e}")
        raise HTTPException(status_code=500, detail="Internal Server Error")

@app.get("/health")
async def health_check():
    """
    Health check endpoint to verify API is running
    """
    return {"status": "Healthy", "message": "API is running smoothly.", "code": status.HTTP_200_OK}

if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        workers=1
    )