import requests # from groq import Groq from bs4 import BeautifulSoup import os import re from dotenv import load_dotenv # from ollama import chat from google import genai from google.genai import types import asyncio from openai import AsyncAzureOpenAI import urllib3 # import bs4 import fitz from pydantic import BaseModel import json from langchain_community.document_loaders import WebBaseLoader urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) load_dotenv() # GROQ_APIKEY = os.environ.get('GROQ_APIKEY') GOOGS_APIKEY = os.environ.get('GOOGS_APIKEY') SEARCH_ENGINE_ID = os.environ.get('SEARCH_ENGINE_ID') GEMINI_APIKEY = os.environ.get('GEMINI_APIKEY') az_client = AsyncAzureOpenAI( api_key=os.environ.get('AZURE_OPENAI_API_KEY'), api_version="2024-12-01-preview", # Use the appropriate API version azure_endpoint=os.environ.get('AZURE_OPENAI_ENDPOINT') ) az_client_in = AsyncAzureOpenAI( api_key=os.environ.get('AZURE_OPENAI_API_KEY_IN'), api_version="2024-12-01-preview", # Use the appropriate API version azure_endpoint=os.environ.get('AZURE_OPENAI_ENDPOINT_IN') ) class ReportResponse(BaseModel): title : str justification : str summary : str link : str # class ListReport(BaseModel) # client = genai.Client(api_key=GEMINI_APIKEY) gemini_client = genai.Client(api_key=GEMINI_APIKEY) class aiSearch: def __init__(self): # self.query = query # self.client = Groq( # api_key=GROQ_APIKEY, # ) self.research_prompt = """ You are AI agent, who is specialized in research and analysis of Indian Judgments. [ { "title" : title of the url, "link" : url link, "snippet" : sinnept from link "text" : text from url webpage }, { "title" : title of the url, "link" : url link, "snippet" : sinnept from link "text" : text from url webpage } ] 1. Analyze each link and it's text to find relevant judgement to the user query . 2. Once analyzed extract judgement names and text of the judgement 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 4. If there is no relevant judgement return empty output 5. Think step by step before the response and only use the context for response. 6. Only shortlist Indian court based judgements. 7. Return the url link of the webpage used as the source in the output. [ { "title" : Judgement title, "justification" : Justification on why judgement is relevant, "summary" : Summary of the Judgement, "link" : url link provided in input }, { "title" : Judgement title, "justification" : Justification on why judgement is relevant, "summary" : Summary of the Judgement, "link" : url link provided in input } ] """ self.sp_final_report = """ You are AI agent, who is specialized in making formatted report. [{ "title" : Judgement title, "justification" : Justification on why judgement is relevant, "summary" : Summary of the Judgement, "link" : url link of webpage }] 1. Convert the input provided into a report. 2. Do not include the report if it says no relevant judgement found and justifications says document not relevant 3. Return the clickable url links as well in the output from the input 4. Do not include any extra text on warnings about URL 5. Only shortlist Indian court based judgements 1. **Judgement name** Justification: reaosn to shortlist the judgement Summary: Summary of the judgement Source: (URL_link) 2. **Judgement name** Justification: reaosn to shortlist the judgement Summary: Summary of the judgement Source: (URL_link) """ async def gpt4omini(self,query): chat_completion = await az_client_in.chat.completions.create( messages=[ { "role" : "system", "content" : self.sp_final_report }, { "role": "user", "content": query, } ], stream=True, model="gpt-4o-mini", temperature=0, # reasoning_effort='low', # response_format=ReportResponse ) return chat_completion async def o3_mini(self,query): chat_completion = await az_client.beta.chat.completions.parse( messages=[ { "role" : "system", "content" : self.research_prompt }, { "role": "user", "content": query, } ], model="o3-mini", # temperature=0, # reasoning_effort='low', response_format=ReportResponse ) return chat_completion.choices[0].message.content async def gemini(self,prompt): # try: response = await gemini_client.aio.models.generate_content( model='gemini-1.5-flash', contents = prompt, config=types.GenerateContentConfig( system_instruction=self.research_prompt, max_output_tokens= 4096, temperature= 0.1 ) ) return response.text # except Exception as e: # print(e) # return '' def google_custom_search(self,query): """ Make a request to Google Custom Search API Args: query (str): Search query api_key (str): Your Google API key cx (str): Your Programmable Search Engine ID Returns: dict: JSON response from the API """ base_url = "https://www.googleapis.com/customsearch/v1" en_query = f"{query}, Indian Judgements" params = { 'q': en_query, 'key': GOOGS_APIKEY, 'cx': SEARCH_ENGINE_ID, 'cr':'countryIN', 'gl': 'in', } try: response = requests.get(base_url, params=params,verify=False) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: print(f"An error occurred: {e}") return None def extract_text_from_html(self,url): try: headers = { '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', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5' } response = requests.get(url, headers=headers, verify=False) soup = BeautifulSoup(response.text, 'html.parser') for element in soup(['script', 'style']): element.decompose() text_chunks = [] content_tags = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'div'] for tag in soup.find_all(content_tags): text = tag.get_text(strip=True) if len(text) < 3: continue if tag.name in ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div']: text = f"\n{text}\n" elif tag.name == 'li': text = f"• {text}\n" text = re.sub(r'\s+', ' ', text).strip() if text: text_chunks.append(text) text = ' '.join(text_chunks) text = re.sub(r'\s+', ' ', text) text = re.sub(r'\n\s*\n', '\n\n', text) except Exception as e: print(e) text = '' return text.strip() async def langchain_extracter(self,url): try: loader = WebBaseLoader(web_paths=[url],verify_ssl=False,continue_on_failure = True) docs = [] async for doc in loader.alazy_load(): docs.append(doc) return docs[0].page_content except Exception as ex: print(f"Error occured while requesting url : {url} exception : {ex}") def pdfreader(self,url): ext_txt = '' try: response = requests.get(url) # Open the PDF with PyMuPDF with fitz.open(stream=response.content, filetype="pdf") as doc: ext_txt = '' for page_num, page in enumerate(doc, start=1): text = page.get_text() ext_txt+=text # print(f"--- Page {page_num} ---\n{text}\n") except: print(url) return ext_txt async def run_search(self,query): self.results = self.google_custom_search(query) self.url_items = [] for item in self.results['items']: if len(self.url_items) < 12: temp = { "title" : item["title"], "link" : item["link"], "snippet" : item["snippet"] } self.url_items.append(temp) for item in self.url_items: if item['link'].endswith(".pdf"): item['text'] = self.pdfreader(item['link']) else: item['text'] = await self.langchain_extracter(item['link']) batch_size = 3 batches = [self.url_items[i:i+batch_size] for i in range(0, len(self.url_items), batch_size)] tasks = [] for batch in batches: context_prompt = f""" {batch} {query} """ tasks.append(self.gemini(context_prompt)) # response = await self.gemini(context_promt) batch_responses = await asyncio.gather(*tasks) reports = [resp for resp in batch_responses] print(reports) stream_responses = await self.gpt4omini(str(reports)) return stream_responses