Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel, Field | |
| from langchain_core.tools import StructuredTool | |
| from langchain_community.tools import DuckDuckGoSearchResults | |
| from langchain.agents import AgentExecutor, create_react_agent | |
| from langchain.prompts import PromptTemplate | |
| from langchain_google_genai import GoogleGenerativeAI | |
| from dotenv import load_dotenv | |
| import requests | |
| import re | |
| import random | |
| # Class to define the schema for the greeting tool | |
| class GreetingTool(BaseModel): | |
| """ | |
| This is class that defines the schema for the greeting tool. | |
| Attributes: | |
| query (str): The user's input string, representing a greeting query. | |
| """ | |
| query: str = Field(title="Query", description="A greeting query to be processed.") | |
| # profession: str = Field(title="profession", description="profession of the user asking query.") | |
| # Function to process greeting queries | |
| def greeting_tool(query: str) -> str: | |
| """ | |
| This function Processes user's greeting query and responds appropriately. | |
| Args: | |
| query (str): The user's input, which will contain a greeting text. | |
| Returns: | |
| str: A response to the user's greeting, or a general introduction if no greeting is found. | |
| """ | |
| return llm.invoke(query) | |
| # Creating a structured tool from the greeting function | |
| greeting = StructuredTool.from_function( | |
| func=greeting_tool, | |
| name="Greetings", | |
| description="A tool for handling greeting queries.", | |
| args_schema=GreetingTool, | |
| return_direct=True | |
| ) | |
| # Class to define the schema for handling database calls | |
| class DbCall(BaseModel): | |
| """ | |
| This class defines the schema for making calls to the Vector Database. | |
| Attributes: | |
| query (str): The user's input string, represents a query to be processed by calling the Vector Database. | |
| """ | |
| query: str = Field(title="Query", description="A query to be processed by calling the Vector Database.") | |
| # profession: str = Field(title="profession", description="profession of the user asking query.") | |
| # Function to call the Vector Database and retrieve a response | |
| def calling_database(query) -> str: | |
| """ | |
| Calls Vector Database with the user's query to retrieve relevant content from the PDF. | |
| Args: | |
| query (str): The user's input query that will be sent to the Vector Database for processing. | |
| Returns: | |
| str: The text response from the Vector Database after processing the query. | |
| """ | |
| # print("\n\nquery : ", query) | |
| query_pattern = r'query:"(.*?)"' | |
| profession_pattern = r'profession:"(\S+)' | |
| # Use re.search to find matches | |
| query_match = re.search(query_pattern, query) | |
| profession_match = re.search(profession_pattern, query) | |
| # Extract values if matches are found | |
| query = query_match.group(1) if query_match else None | |
| profession = profession_match.group(1) if profession_match else None | |
| # print("query : ", query, " and profession : ", profession) | |
| # response = {"success":"Success"} | |
| response = requests.get(f"http://0.0.0.0:8000/get_response", params={"query": query, "profession": profession}).json() | |
| return response | |
| # Creating a structured tool for calling the database | |
| db_calling = StructuredTool.from_function( | |
| func=calling_database, | |
| name="Database Call", | |
| description="A tool for calling the Vector Database to answer queries related to the provided PDF content. Use this tool if you need any information regarding the pdf file.", | |
| args_schema=DbCall, | |
| return_direct=True | |
| ) | |
| # Class to define the schema for handling unrelated queries | |
| class SearchingWeb(BaseModel): | |
| """ | |
| This is class that defines the schema for Searching Internet for any resources. | |
| Attributes: | |
| query (str): The user's input string, representing a non-related query. | |
| """ | |
| query: str = Field(title="Query", description="A query not related to the topic of pdf file.") | |
| # profession: str = Field(title="profession", description="profession of the user asking query.") | |
| # Function to process unrelated queries | |
| def searching_web(query: str) -> list: | |
| """ | |
| This function Processes user's unrelated query to provide some resources link. | |
| Args: | |
| query (str): The user's input, which will contain an unrelated query with topic of pdf file. | |
| Returns: | |
| resources (list): A list of resources to user's query. It contains Title and url of the resource. | |
| """ | |
| search = DuckDuckGoSearchResults(safesearch = "on", max_results=10) | |
| results = search.invoke(query) | |
| try: | |
| # Regular expressions to match title and link | |
| title_pattern = r'title:\s*(.*?),\s*link:' | |
| link_pattern = r'link:\s*(https?://\S+)' | |
| # Extracting titles and links | |
| titles = re.findall(title_pattern, results) | |
| links = re.findall(link_pattern, results) | |
| # Combine titles and links | |
| results = list(zip(titles, links)) | |
| random.shuffle(results) | |
| print(results) | |
| # print(len(results)) | |
| return results[:4] | |
| except Exception as e: | |
| print(e) | |
| return e | |
| # Creating a structured tool from the searching_web function | |
| web_search = StructuredTool.from_function( | |
| func=searching_web, | |
| name="Web Searching", | |
| description="A tool for handling queries not related to topic of the pdf file.", | |
| args_schema=SearchingWeb, | |
| return_direct=True | |
| ) | |
| # Initialize the agent with the tool | |
| tools = [greeting, db_calling, web_search] | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| async def root(query: str, profession: str): | |
| """ | |
| FastAPI endpoint to handle GET requests and return a generated response for a user's query. | |
| Args: | |
| query (str): The query string input from the user, passed as a path parameter in the API request. | |
| Returns: | |
| dict: A dictionary containing the response generated from the query. | |
| """ | |
| global description | |
| print("User_query : " + query) | |
| try: | |
| # print("profession : ", profession) | |
| agent_input = {"query": query, "description": description, "profession": profession} | |
| response = agent_executor.invoke(agent_input) | |
| return response | |
| except Exception as e: | |
| print(e) | |
| return e | |
| class DescriptionRequest(BaseModel): | |
| description: str | |
| def send_desc(request: DescriptionRequest): | |
| """ | |
| FastAPI endpoint to handle POST requests for sending the description of the document to the agent. | |
| Args: | |
| description (str): The description of the document that will be used by the agent to generate responses. | |
| Returns: | |
| dict: A dictionary containing the status of the document description process. | |
| """ | |
| global description | |
| description = request.description | |
| # print("type(description)", type(description)) | |
| print("Description : ", description) | |
| if __name__ == "__main__": | |
| # Loading environment variables from the .env file | |
| load_dotenv() | |
| description = "" | |
| # Initializing the Google Generative AI (LLM) model with specific parameters for the agent | |
| llm = GoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.5) | |
| # Defining the prompt template for the agent to follow when answering questions | |
| template = '''You are a helpful chatbot. You answer to user query only if it is related to the information I am providing you at the end. | |
| You also consider the user's profession for better context when calling the Database tool. | |
| Answer the following questions as best you can. You have access to the following tools: | |
| {tools} | |
| Use the following format: | |
| Question: the input question you must answer | |
| Thought: you should always think about what to do | |
| Action: the action to take, should be one of [{tool_names}] | |
| Action Input: query:"{query}" and profession:"{profession}" | |
| Observation: the result of the action | |
| ... (this Thought/Action/Action Input/Observation can repeat N times) | |
| Thought: I now know the final answer | |
| Final Answer: the final answer to the original input question | |
| Below this is a formatted information of the content. | |
| information {description} | |
| Begin! | |
| Question: {query} and I am a {profession}. | |
| Thought:{agent_scratchpad}''' | |
| # print("tools : ", tools) | |
| # Creating a prompt template object from the defined template | |
| prompt = PromptTemplate.from_template(template) | |
| # Initializing an agent that uses the LLM and tools to respond to user queries | |
| # The tools variable is a list of structured tools that the agent can invoke | |
| agent = create_react_agent(llm, tools, prompt) | |
| # The agent_executor is responsible for executing the agent and managing tool usage | |
| agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) | |
| # Starting the FastAPI server using Uvicorn, making the app accessible at 0.0.0.0 on port 8080 | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=8080) | |