Download agent.py from PrashantKansagara9880/GenAI-Hackathon: direct link, hf CLI and curl.
- Browser
- Download file 6.79 kB
-
https://huggingface.co/spaces/PrashantKansagara9880/GenAI-Hackathon/resolve/main/agent.py
- Command line
-
hf download hf://spaces/PrashantKansagara9880/GenAI-Hackathon/agent.py
-
curl -L -o agent.py https://huggingface.co/spaces/PrashantKansagara9880/GenAI-Hackathon/resolve/main/agent.py
6.79 kB
| import json | |
| import os | |
| from safety import safe_call | |
| class Agent: | |
| def __init__(self, llm, tools, max_steps=5): | |
| self.llm = llm | |
| self.tools = {tool.name: tool for tool in tools} | |
| self.max_steps = max_steps | |
| self.memory = {} | |
| self.current_image=None | |
| if os.path.exists("memory.json"): | |
| with open("memory.json", "r") as f: | |
| self.memory = json.load(f) | |
| else: | |
| self.memory = {} | |
| def call_llm(self, prompt): | |
| return self.llm.invoke(prompt) | |
| def execute_tool(self, tool_name, tool_input, thread_id): | |
| if tool_name not in self.tools: | |
| raise ValueError(f"Tool '{tool_name}' does not exist.") | |
| if tool_name == "search_documents": | |
| return self.tools[tool_name].func( | |
| tool_input, | |
| thread_id | |
| ) | |
| elif tool_name == "describe_image": | |
| if self.current_image is None: | |
| raise ValueError("No image has been uploaded.") | |
| else: | |
| return self.tools[tool_name].invoke(self.current_image) | |
| else: | |
| return self.tools[tool_name].invoke(tool_input) | |
| def persist_memory(self): | |
| with open("memory.json", "w") as f: | |
| json.dump(self.memory, f, indent=4) | |
| def _build_prompt(self, user_query, scratchpad,history): | |
| tool_descriptions = "\n".join( | |
| f"- {name}" for name in self.tools.keys() | |
| ) | |
| return f""" | |
| You are an AI Agent. | |
| Available tools: | |
| {tool_descriptions} | |
| search_documents | |
| Search the user's uploaded documents for information relevent to the query.Use this when the | |
| user asks about content from a PDF they uploaded, or references 'the document', 'my notes', | |
| or 'the file'. | |
| Do NOT use this for general knowledge or current events | |
| web_search | |
| Use this tool to search the web for real-time information. | |
| Input: a search query string. | |
| Output: a summary of the most relevant search results. | |
| Use this for current events, news, live prices, or anything published after 2024. | |
| describe_image | |
| Use ONLY when an uploaded image must be analysed. | |
| You MUST respond ONLY with valid JSON. | |
| If you need a tool: | |
| {{ | |
| "action": "tool", | |
| "tool_name": "<tool_name>", | |
| "tool_input": "<query>" | |
| }} | |
| If the tool you are using is describe_image then you can respond like this: | |
| {{ | |
| "action": "tool", | |
| "tool_name": "<tool_name>", | |
| "tool_input": "CURRENT_IMAGE" | |
| }} | |
| here CURRENT_IMAGE is a special keyword that tells the agent to use the image that was last uploaded by the user. | |
| Never invent another value.Never include the image itself.The runtime will automatically replace CURRENT_IMAGE with the uploaded image. | |
| If you have enough information to answer the user's question, respond like this: | |
| {{ | |
| "action": "final", | |
| "answer": "<answer>" | |
| }} | |
| Conversation history: | |
| {history} | |
| Current user question: | |
| {user_query} | |
| Previous reasoning: | |
| {scratchpad} | |
| """ | |
| def save_message(self, thread_id, role, content): | |
| if thread_id not in self.memory: | |
| self.memory[thread_id] = [] | |
| self.memory[thread_id].append( | |
| { | |
| "role": role, | |
| "content": content | |
| } | |
| ) | |
| self.persist_memory() | |
| def get_history(self, thread_id): | |
| return self.memory.get(thread_id, []) | |
| def final_summary(self,user_query,scratchpad,thread_id,history): | |
| summary_prompt = f""" | |
| History: | |
| {history} | |
| Question: | |
| {user_query} | |
| Collected facts: | |
| {scratchpad} | |
| Write a concise answer for the user. | |
| """ | |
| response = self.call_llm(summary_prompt) | |
| if isinstance(response, str): | |
| return response | |
| answer = response.content | |
| self.save_message(thread_id,"assistant",answer) | |
| return answer | |
| def run(self, user_query,thread_id): | |
| scratchpad = "" | |
| self.save_message( | |
| thread_id, | |
| "user", | |
| user_query | |
| ) | |
| history = self.get_history(thread_id) | |
| for step in range(self.max_steps): | |
| prompt = self._build_prompt( | |
| user_query=user_query, | |
| scratchpad=scratchpad, | |
| history=history | |
| ) | |
| response = self.call_llm(prompt) | |
| if isinstance(response, str): | |
| return response, scratchpad | |
| text = response.content | |
| try: | |
| decision = json.loads(text) | |
| except Exception: | |
| return (f"Invalid JSON returned:\n{text}",scratchpad) | |
| action = decision.get("action") | |
| if action not in ("tool", "final"): | |
| return ( | |
| "โ ๏ธ The planner returned an invalid action.", | |
| scratchpad | |
| ) | |
| if action == "final": | |
| return self.final_summary(user_query,scratchpad,thread_id,history),scratchpad | |
| if action == "tool": | |
| tool_name = decision["tool_name"] | |
| tool_input = decision["tool_input"] | |
| result = self.execute_tool( | |
| tool_name, | |
| tool_input, | |
| thread_id | |
| ) | |
| if result == "No documents uploaded yet": | |
| return ( | |
| "๐ No document has been uploaded yet.\n\n" | |
| "Please upload a PDF in the **Document QA** tab first.", | |
| scratchpad | |
| ) | |
| if result == "No relevant content found in the uploaded documents.": | |
| return ( | |
| "I couldn't find information about that in the uploaded document.", | |
| scratchpad | |
| ) | |
| tool_failed = (isinstance(result, str) and | |
| (result.startswith("โ ๏ธ") | |
| or result.startswith("โ") | |
| or result.startswith("๐") | |
| or result.startswith("๐") | |
| or result.startswith("๐ซ") | |
| ) | |
| ) | |
| scratchpad += f""" | |
| Step {step+1} | |
| Tool Used: | |
| {tool_name} | |
| Tool Input: | |
| {tool_input} | |
| Tool Result: | |
| {result} | |
| """ | |
| if tool_failed: | |
| continue | |
| return ("Maximum reasoning steps exceeded.",scratchpad) |