sk1502 commited on
Commit
3d242c8
·
1 Parent(s): 6105445

added updated files

Browse files
Files changed (4) hide show
  1. Dockerfile +8 -14
  2. aisearch_v1.py +302 -0
  3. app.py +46 -6
  4. requirements.txt +7 -1
Dockerfile CHANGED
@@ -1,17 +1,11 @@
1
- # Use an official Python runtime as a parent image
2
  FROM python:3.10
3
-
4
- # Set the working directory
5
- WORKDIR /app
6
-
7
- # Copy your app files into the container
 
 
 
8
  COPY . .
9
-
10
- # Install required packages
11
- RUN pip install --no-cache-dir chainlit
12
-
13
- # Expose the port Chainlit will run on
14
- EXPOSE 7860
15
-
16
- # Start the Chainlit app
17
  CMD ["chainlit", "run", "app.py", "--host", "0.0.0.0", "--port", "7860"]
 
 
1
  FROM python:3.10
2
+ RUN useradd -m -u 1000 user
3
+ USER user
4
+ ENV HOME=/home/user \
5
+ PATH=/home/user/.local/bin:$PATH
6
+ WORKDIR $HOME/app
7
+ COPY --chown=user . $HOME/app
8
+ COPY ./requirements.txt ~/app/requirements.txt
9
+ RUN pip install -r requirements.txt
10
  COPY . .
 
 
 
 
 
 
 
 
11
  CMD ["chainlit", "run", "app.py", "--host", "0.0.0.0", "--port", "7860"]
aisearch_v1.py ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ # from groq import Groq
3
+ from bs4 import BeautifulSoup
4
+ import os
5
+ import re
6
+ from dotenv import load_dotenv
7
+ # from ollama import chat
8
+ from google import genai
9
+ from google.genai import types
10
+ import asyncio
11
+ from openai import AsyncAzureOpenAI
12
+ import urllib3
13
+ # import bs4
14
+ import fitz
15
+ from pydantic import BaseModel
16
+ import json
17
+ from langchain_community.document_loaders import WebBaseLoader
18
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
19
+
20
+ # load_dotenv()
21
+ # GROQ_APIKEY = os.environ.get('GROQ_APIKEY')
22
+ GOOGS_APIKEY = "AIzaSyDwkt2Ha0Y2eWOH0XonhJvEg5gXUfedRf4"
23
+ SEARCH_ENGINE_ID = "f722438bf451a41a1"
24
+ # GEMINI_APIKEY = os.environ.get('GEMINI_APIKEY')
25
+
26
+ az_client = AsyncAzureOpenAI(
27
+ api_key='55b49aec1d734ba2a7e912bdef22af7a',
28
+ api_version="2024-12-01-preview", # Use the appropriate API version
29
+ azure_endpoint='https://docuswiftchat-aillm-zgpfobsurevrg.openai.azure.com/'
30
+ )
31
+
32
+ az_client_in = AsyncAzureOpenAI(
33
+ api_key='CvRegNn4vwFkcAs8LPkjqeAb0qdHO88AvVxsSrnshauwP9jDm9DsJQQJ99BCAC77bzfXJ3w3AAAAACOGdbvR',
34
+ api_version="2024-12-01-preview", # Use the appropriate API version
35
+ azure_endpoint='https://docus-ai-ind954042238035.openai.azure.com'
36
+ )
37
+
38
+ class ReportResponse(BaseModel):
39
+ title : str
40
+ justification : str
41
+ summary : str
42
+
43
+ # class ListReport(BaseModel)
44
+
45
+
46
+ # client = genai.Client(api_key=GEMINI_APIKEY)
47
+ gemini_client = genai.Client(api_key='AIzaSyBOtSrEcYlGuTZ-XZT5zJo3T_oPAWn3T2Y')
48
+ # gemini_client1 = genai.Client(api_key='AIzaSyBOtSrEcYlGuTZ-XZT5zJo3T_oPAWn3T2Y')
49
+
50
+ class aiSearch:
51
+ def __init__(self):
52
+ # self.query = query
53
+ # self.client = Groq(
54
+ # api_key=GROQ_APIKEY,
55
+ # )
56
+ self.research_prompt = """
57
+ <role>
58
+ You are AI agent, who is specialized in research and analysis of Indian Judgments.
59
+ </role>
60
+ <input format>
61
+ [
62
+ {
63
+ "title" : title of the url,
64
+ "link" : url link,
65
+ "snippet" : sinnept from link
66
+ "text" : text from url webpage
67
+ },
68
+ {
69
+ "title" : title of the url,
70
+ "link" : url link,
71
+ "snippet" : sinnept from link
72
+ "text" : text from url webpage
73
+ }
74
+ ]
75
+ </input format>
76
+ <instructions>
77
+ 1. Analyze each link and it's text to find relevant judgement to the user query .
78
+ 2. Once analyzed extract judgement names and text of the judgement
79
+ 3. In the response provide judgement name, one-two line justifications on why judgement is relevant to the query and text of the judgement in the webpage
80
+ 4. If there is no relevant judgement return empty output
81
+ 5. Think step by step before the response and only use the context for response.
82
+ </instructions>
83
+ <output format>
84
+ [
85
+ {
86
+ "title" : Judgement title,
87
+ "justification" : Justification on why judgement is relevant,
88
+ "summary" : Summary of the Judgement
89
+ },
90
+ {
91
+ "title" : Judgement title,
92
+ "justification" : Justification on why judgement is relevant,
93
+ "summary" : Summary of the Judgement
94
+ }
95
+ ]
96
+ </output format>
97
+ """
98
+ self.sp_final_report = """
99
+ <role>
100
+ You are AI agent, who is specialized in making formatted report.
101
+ </role>
102
+ <instructions>
103
+ 1. Input will be in json format.
104
+ 2. Do not include the report if it says no relevant judgement found and justifications says document not relevant
105
+ 2. Return the output on markdown format
106
+ </instructions>
107
+ <output format>
108
+ ##1. Judgement name (H2 heading)
109
+ Justification - reaosn to shortlist the judgement
110
+ Summary - Summary of the judgement
111
+
112
+ ##2. Judgement name (H2 heading)
113
+ Justification - reaosn to shortlist the judgement
114
+ Summary - Summary of the judgement
115
+ </output format>"""
116
+
117
+ async def gpt4omini(self,query):
118
+ chat_completion = await az_client_in.chat.completions.create(
119
+ messages=[
120
+ {
121
+ "role" : "system",
122
+ "content" : self.research_prompt
123
+ },
124
+ {
125
+ "role": "user",
126
+ "content": query,
127
+ }
128
+ ],
129
+ stream=True,
130
+ model="gpt4o-mini",
131
+ # temperature=0,
132
+ # reasoning_effort='low',
133
+ # response_format=ReportResponse
134
+ )
135
+
136
+ return chat_completion.choices[0].message.content
137
+
138
+ async def o3_mini(self,query):
139
+ chat_completion = await az_client.beta.chat.completions.parse(
140
+ messages=[
141
+ {
142
+ "role" : "system",
143
+ "content" : self.research_prompt
144
+ },
145
+ {
146
+ "role": "user",
147
+ "content": query,
148
+ }
149
+ ],
150
+ model="o3-mini",
151
+ # temperature=0,
152
+ # reasoning_effort='low',
153
+ response_format=ReportResponse
154
+ )
155
+
156
+ return chat_completion.choices[0].message.content
157
+
158
+ async def gemini(self,prompt):
159
+ # try:
160
+ response = await gemini_client.aio.models.generate_content_stream(
161
+ model='gemini-2.0-flash',
162
+ contents = self.sp_final_report,
163
+ config=types.GenerateContentConfig(
164
+ system_instruction=prompt,
165
+ max_output_tokens= 4096,
166
+ temperature= 0.1
167
+ )
168
+ )
169
+
170
+ return response
171
+
172
+ # except Exception as e:
173
+ # print(e)
174
+ # return ''
175
+
176
+ def google_custom_search(self,query):
177
+ """
178
+ Make a request to Google Custom Search API
179
+
180
+ Args:
181
+ query (str): Search query
182
+ api_key (str): Your Google API key
183
+ cx (str): Your Programmable Search Engine ID
184
+
185
+ Returns:
186
+ dict: JSON response from the API
187
+ """
188
+ base_url = "https://www.googleapis.com/customsearch/v1"
189
+ en_query = f"{query}, Indian Judgments"
190
+ params = {
191
+ 'q': en_query,
192
+ 'key': GOOGS_APIKEY,
193
+ 'cx': SEARCH_ENGINE_ID,
194
+ 'gl': 'in'
195
+ }
196
+
197
+ try:
198
+ response = requests.get(base_url, params=params,verify=False)
199
+ response.raise_for_status()
200
+ return response.json()
201
+ except requests.exceptions.RequestException as e:
202
+ print(f"An error occurred: {e}")
203
+ return None
204
+
205
+ def extract_text_from_html(self,url):
206
+ try:
207
+ headers = {
208
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
209
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
210
+ 'Accept-Language': 'en-US,en;q=0.5'
211
+ }
212
+ response = requests.get(url, headers=headers, verify=False)
213
+ soup = BeautifulSoup(response.text, 'html.parser')
214
+ for element in soup(['script', 'style']):
215
+ element.decompose()
216
+
217
+ text_chunks = []
218
+ content_tags = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'div']
219
+
220
+ for tag in soup.find_all(content_tags):
221
+ text = tag.get_text(strip=True)
222
+ if len(text) < 3:
223
+ continue
224
+ if tag.name in ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div']:
225
+ text = f"\n{text}\n"
226
+ elif tag.name == 'li':
227
+ text = f"• {text}\n"
228
+ text = re.sub(r'\s+', ' ', text).strip()
229
+ if text:
230
+ text_chunks.append(text)
231
+
232
+ text = ' '.join(text_chunks)
233
+ text = re.sub(r'\s+', ' ', text)
234
+ text = re.sub(r'\n\s*\n', '\n\n', text)
235
+ except Exception as e:
236
+ print(e)
237
+ text = ''
238
+ return text.strip()
239
+
240
+ async def langchain_extracter(self,url):
241
+ loader = WebBaseLoader(web_paths=[url],verify_ssl=False)
242
+ docs = []
243
+ async for doc in loader.alazy_load():
244
+ docs.append(doc)
245
+ return docs[0].page_content
246
+
247
+ def pdfreader(self,url):
248
+ ext_txt = ''
249
+ try:
250
+ response = requests.get(url)
251
+ # Open the PDF with PyMuPDF
252
+ with fitz.open(stream=response.content, filetype="pdf") as doc:
253
+ ext_txt = ''
254
+ for page_num, page in enumerate(doc, start=1):
255
+ text = page.get_text()
256
+ ext_txt+=text
257
+ # print(f"--- Page {page_num} ---\n{text}\n")
258
+ except:
259
+ print(url)
260
+ return ext_txt
261
+
262
+ async def run_search(self,query):
263
+ self.results = self.google_custom_search(query)
264
+
265
+ self.url_items = []
266
+ for item in self.results['items']:
267
+ if len(self.url_items) < 10:
268
+ temp = {
269
+ "title" : item["title"],
270
+ "link" : item["link"],
271
+ "snippet" : item["snippet"]
272
+ }
273
+ self.url_items.append(temp)
274
+
275
+ for item in self.url_items:
276
+ if item['link'].endswith(".pdf"):
277
+ item['text'] = self.pdfreader(item['link'])
278
+ else:
279
+ item['text'] = await self.langchain_extracter(item['link'])
280
+
281
+ batch_size = 3
282
+ batches = [self.url_items[i:i+batch_size] for i in range(0, len(self.url_items), batch_size)]
283
+
284
+ tasks = []
285
+ for batch in batches:
286
+ context_prompt = f"""
287
+ <context>
288
+ {batch}
289
+ </context>
290
+
291
+ <user query>
292
+ {query}
293
+ </user query>
294
+ """
295
+ tasks.append(self.o3_mini(context_prompt))
296
+
297
+ # response = await self.gemini(context_promt)
298
+ batch_responses = await asyncio.gather(*tasks)
299
+ reports = [resp for resp in batch_responses]
300
+
301
+ stream_responses = await self.gemini(str(reports))
302
+ return stream_responses
app.py CHANGED
@@ -1,11 +1,51 @@
1
  import chainlit as cl
 
 
2
 
 
 
3
 
4
- @cl.on_message
 
 
 
 
 
 
 
5
  async def main(message: cl.Message):
6
- # Your custom logic goes here...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- # Send a response back to the user
9
- await cl.Message(
10
- content=f"Received: {message.content}",
11
- ).send()
 
1
  import chainlit as cl
2
+ # from ollama import chat
3
+ from aisearch_v1 import aiSearch
4
 
5
+ @cl.step(type="tool")
6
+ async def tool(msg):
7
 
8
+ print(f"Message from user: {msg}")
9
+
10
+ inst = aiSearch()
11
+ stream = await inst.run_search(msg)
12
+ return stream
13
+
14
+
15
+ @cl.on_message # this function will be called every time a user inputs a message in the UI
16
  async def main(message: cl.Message):
17
+ """
18
+ This function is called every time a user inputs a message in the UI.
19
+ It sends back an intermediate response from the tool, followed by the final answer.
20
+
21
+ Args:
22
+ message: The user's message.
23
+
24
+ Returns:
25
+ None.
26
+ """
27
+
28
+ msg = cl.Message(content="")
29
+ # Call the tool
30
+ # streams,sources = await tool(message.content)
31
+
32
+ streams = await tool(message.content)
33
+
34
+ # await cl.Message(content=result).send()
35
+
36
+ # for stream in streams:
37
+ async for part in streams:
38
+ if token := part.text or "":
39
+ await msg.stream_token(token)
40
+
41
+ # # After streaming is complete, add citations if available
42
+ # if sources and len(sources) > 0:
43
+ # # Add a divider
44
+ # await msg.stream_token("\n\n---\n\n**Sources:**\n\n")
45
+
46
+ # # Add each source as a numbered citation
47
+ # for i, source in enumerate(sources, 1):
48
+ # citation = f"{i}. [{source['title']}]({source['link']})\n"
49
+ # await msg.stream_token(citation)
50
 
51
+ await msg.update()
 
 
 
requirements.txt CHANGED
@@ -1 +1,7 @@
1
- chainlit
 
 
 
 
 
 
 
1
+ chainlit
2
+ beautifulsoup4
3
+ python-dotenv
4
+ google-genai
5
+ openai
6
+ PyMuPDF
7
+ langchain-community