MRP999 commited on
Commit
e313bf4
·
verified ·
1 Parent(s): bed2015

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -139
app.py CHANGED
@@ -1,140 +1,140 @@
1
- import os
2
- from fastapi import FastAPI, Request, HTTPException, status, BackgroundTasks
3
- from fastapi.responses import JSONResponse
4
- from fastapi.middleware.cors import CORSMiddleware
5
- from pydantic import BaseModel
6
- from typing import List
7
- from google import genai
8
- from semantic_aware import load_document
9
- import hashlib
10
- import httpx
11
- from datetime import datetime
12
- import re
13
- from pinecone import Pinecone
14
- from pinecone_embeddings import PineconeVectorStore
15
-
16
-
17
- # Configuration
18
- EMBEDDING_MODEL = "BAAI/bge-base-en-v1.5"
19
- PINECONE_INDEX = 'policy-documents'
20
- CACHE_DIR = "./document_cache"
21
- os.makedirs(CACHE_DIR, exist_ok=True)
22
- pinecone = Pinecone(
23
- api_key=os.getenv("PINECONE_API_KEY"),
24
- environment=os.getenv("PINECONE_ENV")
25
- )
26
-
27
- # Initialize Gemini
28
- # genai.configure(api_key=os.environ["GEMINI_API_KEY"])
29
- # model = genai.GenerativeModel('gemini-1.5-flash')
30
-
31
- app = FastAPI()
32
- app.add_middleware(
33
- CORSMiddleware,
34
- allow_origins=["*"],
35
- allow_methods=["*"],
36
- allow_headers=["*"],
37
- )
38
-
39
- class QueryRequest(BaseModel):
40
- documents: str
41
- questions: List[str]
42
-
43
- class QueryResponse(BaseModel):
44
- answers: List[str]
45
-
46
- def document_cache_key(url: str) -> str:
47
- return hashlib.md5(url.encode()).hexdigest()
48
-
49
- async def fetch_with_cache(url: str) -> str:
50
- """Download with caching"""
51
- cache_key = document_cache_key(url)
52
- cache_path = os.path.join(CACHE_DIR, f"{cache_key}.pdf")
53
-
54
- if os.path.exists(cache_path):
55
- return cache_path
56
-
57
- async with httpx.AsyncClient() as client:
58
- response = await client.get(url)
59
- response.raise_for_status()
60
- with open(cache_path, "wb") as f:
61
- f.write(response.content)
62
-
63
- return cache_path
64
-
65
- def build_gemini_prompt(question: str, clauses: List[dict]) -> str:
66
- """Strictly formatted prompt for Gemini"""
67
- context = "\n\n".join(
68
- f"CLAUSE {c.get('header', '')} (Page {c.get('page', 'N/A')}):\n{c['text']}"
69
- for c in clauses
70
- )
71
-
72
- return f"""You are a strict, accurate assistant that answers insurance or policy-related questions using only provided clauses.
73
-
74
- A user has asked the following question:
75
- "{question}"
76
-
77
- You must answer only based on the given text below, without guessing or skipping any information.
78
- If an answer is partially stated or implied, respond accordingly with brief clarification.
79
- If the information is not present at all, reply exactly: "Not mentioned in the provided clauses."
80
-
81
- Clauses:
82
- {context}
83
-
84
- Respond with 1 to 3 sentences max.
85
- Do not add explanations, formatting, bullet points, summaries, or any output other than the answer sentence.
86
-
87
- """
88
-
89
- # def extract_first_sentence(text: str) -> str:
90
- # """Ensure single-sentence output"""
91
- # sentences = re.split(r'(?<=[.!?])\s+', text.strip())
92
- # return sentences[0] if sentences else text
93
-
94
- @app.post("/query", response_model=QueryResponse)
95
- async def answer_questions(request: Request, body: QueryRequest):
96
- # Authentication
97
- if request.headers.get("Authorization") != f"Bearer {os.environ['API_KEY']}":
98
- raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
99
-
100
- try:
101
- # 1. Process document
102
- local_path = await fetch_with_cache(body.documents)
103
- doc = load_document(local_path)
104
-
105
- # 2. Initialize engine
106
- vector_store = PineconeVectorStore(index_name=PINECONE_INDEX, pinecone=pinecone)
107
- vector_store.overwrite_vectors(doc["chunks"], 'doc_a.pdf', pinecone)
108
-
109
- # 3. Process questions
110
- answers = []
111
- client = genai.Client(
112
- api_key=os.environ["GEMINI_API_KEY"]
113
- )
114
-
115
- for question in body.questions:
116
- # Retrieve relevant clauses
117
- clauses = vector_store.retrieve_chunks(question, pinecone, top_k=5)
118
-
119
- # print("\n\n")
120
- # print(clauses)
121
-
122
- # Generate answer with Gemini
123
- prompt = build_gemini_prompt(question, clauses)
124
- response = client.models.generate_content(
125
- model="gemini-2.5-flash",
126
- contents=prompt
127
- )
128
-
129
- # Strict formatting
130
- # answer = extract_first_sentence(response.text)
131
- # print(response.text)
132
- answers.append(response.text)
133
-
134
- return {"answers": answers}
135
-
136
- except Exception as e:
137
- raise HTTPException(
138
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
139
- detail=str(e)
140
  )
 
1
+ import os
2
+ from fastapi import FastAPI, Request, HTTPException, status, BackgroundTasks
3
+ from fastapi.responses import JSONResponse
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+ from pydantic import BaseModel
6
+ from typing import List
7
+ from google import genai
8
+ from semantic_aware import load_document
9
+ import hashlib
10
+ import httpx
11
+ from datetime import datetime
12
+ import re
13
+ from pinecone import Pinecone
14
+ from pinecone_embeddings import PineconeVectorStore
15
+
16
+
17
+ # Configuration
18
+ EMBEDDING_MODEL = "BAAI/bge-base-en-v1.5"
19
+ PINECONE_INDEX = 'policy-documents'
20
+ CACHE_DIR = "./document_cache"
21
+ os.makedirs(CACHE_DIR, exist_ok=True)
22
+ pinecone = Pinecone(
23
+ api_key=os.getenv("PINECONE_API_KEY"),
24
+ environment=os.getenv("PINECONE_ENV")
25
+ )
26
+
27
+ # Initialize Gemini
28
+ # genai.configure(api_key=os.environ["GEMINI_API_KEY"])
29
+ # model = genai.GenerativeModel('gemini-1.5-flash')
30
+
31
+ app = FastAPI()
32
+ app.add_middleware(
33
+ CORSMiddleware,
34
+ allow_origins=["*"],
35
+ allow_methods=["*"],
36
+ allow_headers=["*"],
37
+ )
38
+
39
+ class QueryRequest(BaseModel):
40
+ documents: str
41
+ questions: List[str]
42
+
43
+ class QueryResponse(BaseModel):
44
+ answers: List[str]
45
+
46
+ def document_cache_key(url: str) -> str:
47
+ return hashlib.md5(url.encode()).hexdigest()
48
+
49
+ async def fetch_with_cache(url: str) -> str:
50
+ """Download with caching"""
51
+ cache_key = document_cache_key(url)
52
+ cache_path = os.path.join(CACHE_DIR, f"{cache_key}.pdf")
53
+
54
+ if os.path.exists(cache_path):
55
+ return cache_path
56
+
57
+ async with httpx.AsyncClient() as client:
58
+ response = await client.get(url)
59
+ response.raise_for_status()
60
+ with open(cache_path, "wb") as f:
61
+ f.write(response.content)
62
+
63
+ return cache_path
64
+
65
+ def build_gemini_prompt(question: str, clauses: List[dict]) -> str:
66
+ """Strictly formatted prompt for Gemini"""
67
+ context = "\n\n".join(
68
+ f"CLAUSE {c.get('header', '')} (Page {c.get('page', 'N/A')}):\n{c['text']}"
69
+ for c in clauses
70
+ )
71
+
72
+ return f"""
73
+ You are a strict, accurate assistant that answers insurance or policy-related questions using only provided clauses.
74
+
75
+ A user has asked the following question:
76
+ '{question}'
77
+
78
+ You must answer only based on the given text below, without guessing or skipping any information.
79
+ If an answer is partially stated or implied, respond accordingly with brief clarification.
80
+ If the information is not present at all, reply exactly: 'Not mentioned in the provided clauses.'
81
+
82
+ Clauses:
83
+ {context}
84
+
85
+ Respond with 1 to 3 sentences max.
86
+ Do not add explanations, formatting, bullet points, summaries, or any output other than the answer sentence.
87
+ """
88
+
89
+ # def extract_first_sentence(text: str) -> str:
90
+ # """Ensure single-sentence output"""
91
+ # sentences = re.split(r'(?<=[.!?])\s+', text.strip())
92
+ # return sentences[0] if sentences else text
93
+
94
+ @app.post("/query", response_model=QueryResponse)
95
+ async def answer_questions(request: Request, body: QueryRequest):
96
+ # Authentication
97
+ if request.headers.get("Authorization") != f"Bearer {os.environ['API_KEY']}":
98
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
99
+
100
+ try:
101
+ # 1. Process document
102
+ local_path = await fetch_with_cache(body.documents)
103
+ doc = load_document(local_path)
104
+
105
+ # 2. Initialize engine
106
+ vector_store = PineconeVectorStore(index_name=PINECONE_INDEX, pinecone=pinecone)
107
+ vector_store.overwrite_vectors(doc["chunks"], 'doc_a.pdf', pinecone)
108
+
109
+ # 3. Process questions
110
+ answers = []
111
+ client = genai.Client(
112
+ api_key=os.environ["GEMINI_API_KEY"]
113
+ )
114
+
115
+ for question in body.questions:
116
+ # Retrieve relevant clauses
117
+ clauses = vector_store.retrieve_chunks(question, pinecone, top_k=5)
118
+
119
+ # print("\n\n")
120
+ # print(clauses)
121
+
122
+ # Generate answer with Gemini
123
+ prompt = build_gemini_prompt(question, clauses)
124
+ response = client.models.generate_content(
125
+ model="gemini-2.5-flash",
126
+ contents=prompt
127
+ )
128
+
129
+ # Strict formatting
130
+ # answer = extract_first_sentence(response.text)
131
+ # print(response.text)
132
+ answers.append(response.text)
133
+
134
+ return {"answers": answers}
135
+
136
+ except Exception as e:
137
+ raise HTTPException(
138
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
139
+ detail=str(e)
140
  )