Raghoottam commited on
Commit
94e215a
·
verified ·
1 Parent(s): 3c4c930

Create agent.py

Browse files
Files changed (1) hide show
  1. agent.py +290 -0
agent.py ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """LangGraph Agent - Complete bypass of problematic vector store"""
2
+ import os
3
+ import json
4
+ from dotenv import load_dotenv
5
+ from langgraph.graph import START, StateGraph, MessagesState
6
+ from langgraph.prebuilt import tools_condition
7
+ from langgraph.prebuilt import ToolNode
8
+ from langchain_groq import ChatGroq
9
+ from langchain_community.tools.tavily_search import TavilySearchResults
10
+ from langchain_community.document_loaders import WikipediaLoader
11
+ from langchain_community.document_loaders import ArxivLoader
12
+ from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
13
+ from langchain_core.tools import tool
14
+ from supabase.client import Client, create_client
15
+
16
+ load_dotenv()
17
+
18
+ @tool
19
+ def multiply(a: int, b: int) -> int:
20
+ """Multiply two numbers."""
21
+ return a * b
22
+
23
+ @tool
24
+ def add(a: int, b: int) -> int:
25
+ """Add two numbers."""
26
+ return a + b
27
+
28
+ @tool
29
+ def subtract(a: int, b: int) -> int:
30
+ """Subtract two numbers."""
31
+ return a - b
32
+
33
+ @tool
34
+ def divide(a: int, b: int) -> int:
35
+ """Divide two numbers."""
36
+ if b == 0:
37
+ raise ValueError("Cannot divide by zero.")
38
+ return a / b
39
+
40
+ @tool
41
+ def modulus(a: int, b: int) -> int:
42
+ """Get the modulus of two numbers."""
43
+ return a % b
44
+
45
+ @tool
46
+ def wiki_search(query: str) -> str:
47
+ """Search Wikipedia for a query and return maximum 2 results."""
48
+ try:
49
+ search_docs = WikipediaLoader(query=query, load_max_docs=2).load()
50
+ formatted_docs = []
51
+ for doc in search_docs:
52
+ source = "Wikipedia"
53
+ if hasattr(doc, 'metadata') and isinstance(doc.metadata, dict):
54
+ source = doc.metadata.get('source', 'Wikipedia')
55
+ formatted_docs.append(f"Source: {source}\n{doc.page_content[:1000]}...")
56
+
57
+ return "\n\n---\n\n".join(formatted_docs)
58
+ except Exception as e:
59
+ return f"Error searching Wikipedia: {str(e)}"
60
+
61
+ @tool
62
+ def web_search(query: str) -> str:
63
+ """Search the web using Tavily."""
64
+ try:
65
+ search_tool = TavilySearchResults(max_results=3)
66
+ results = search_tool.invoke(query)
67
+
68
+ if isinstance(results, list):
69
+ formatted_results = []
70
+ for result in results:
71
+ if isinstance(result, dict):
72
+ url = result.get('url', 'Unknown')
73
+ content = result.get('content', '')[:1000]
74
+ formatted_results.append(f"Source: {url}\n{content}...")
75
+ return "\n\n---\n\n".join(formatted_results)
76
+ return str(results)
77
+ except Exception as e:
78
+ return f"Error searching web: {str(e)}"
79
+
80
+ @tool
81
+ def arxiv_search(query: str) -> str:
82
+ """Search Arxiv for academic papers."""
83
+ try:
84
+ search_docs = ArxivLoader(query=query, load_max_docs=3).load()
85
+ formatted_docs = []
86
+ for doc in search_docs:
87
+ source = "ArXiv"
88
+ if hasattr(doc, 'metadata') and isinstance(doc.metadata, dict):
89
+ source = doc.metadata.get('source', 'ArXiv')
90
+ formatted_docs.append(f"Source: {source}\n{doc.page_content[:1000]}...")
91
+
92
+ return "\n\n---\n\n".join(formatted_docs)
93
+ except Exception as e:
94
+ return f"Error searching ArXiv: {str(e)}"
95
+
96
+ # Raw Supabase search function that bypasses LangChain entirely
97
+ def raw_supabase_search(query: str, supabase_client):
98
+ """Direct Supabase search without any LangChain components"""
99
+ try:
100
+ # Simple text-based search using Supabase's built-in functions
101
+ # This assumes you have a simple text search function in your database
102
+ result = supabase_client.table('documents').select('content').text_search('content', query).limit(1).execute()
103
+
104
+ if result.data:
105
+ return result.data[0]['content']
106
+ else:
107
+ # Fallback: get any document (for testing)
108
+ result = supabase_client.table('documents').select('content').limit(1).execute()
109
+ if result.data:
110
+ return result.data[0]['content']
111
+ return "No documents found in database"
112
+
113
+ except Exception as e:
114
+ return f"Database search error: {str(e)}"
115
+
116
+ # Alternative: Use simple SQL query
117
+ def simple_sql_search(query: str, supabase_client):
118
+ """Simple SQL-based search"""
119
+ try:
120
+ # Use a simple SQL query to avoid metadata issues
121
+ sql_query = f"""
122
+ SELECT content
123
+ FROM documents
124
+ WHERE content ILIKE '%{query}%'
125
+ LIMIT 1
126
+ """
127
+ result = supabase_client.rpc('execute_sql', {'query': sql_query}).execute()
128
+
129
+ if result.data:
130
+ return result.data[0]['content']
131
+ return "No matching documents found"
132
+
133
+ except Exception as e:
134
+ return f"SQL search error: {str(e)}"
135
+
136
+ # Load system prompt
137
+ try:
138
+ with open("system_prompt.txt", "r", encoding="utf-8") as f:
139
+ system_prompt = f.read()
140
+ except FileNotFoundError:
141
+ system_prompt = "You are a helpful AI assistant."
142
+
143
+ sys_msg = SystemMessage(content=system_prompt)
144
+
145
+ # Initialize Supabase without vector store
146
+ supabase_url = "https://ajnakgegqblhwltzkzbz.supabase.co"
147
+ supabase_key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFqbmFrZ2VncWJsaHdsdHpremJ6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDkyMDgxODgsImV4cCI6MjA2NDc4NDE4OH0.b9RPF-5otedg4yiaQu_uhOgYpXVXd9D_0oR-9cluUjo"
148
+
149
+ try:
150
+ supabase_client = create_client(supabase_url, supabase_key)
151
+ except Exception as e:
152
+ print(f"Warning: Could not initialize Supabase client: {e}")
153
+ supabase_client = None
154
+
155
+ tools = [
156
+ multiply,
157
+ add,
158
+ subtract,
159
+ divide,
160
+ modulus,
161
+ wiki_search,
162
+ web_search,
163
+ arxiv_search,
164
+ ]
165
+
166
+ def build_graph(provider: str = "groq"):
167
+ """Build the graph without problematic vector store operations"""
168
+ if provider == "groq":
169
+ llm = ChatGroq(
170
+ model="qwen-qwq-32b",
171
+ api_key="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",
172
+ temperature=0
173
+ )
174
+ else:
175
+ raise ValueError("Invalid provider. Choose 'groq'.")
176
+
177
+ def retriever(state: MessagesState):
178
+ """Retriever that actually searches based on query"""
179
+ try:
180
+ query = state["messages"][-1].content.lower()
181
+
182
+ if supabase_client is None:
183
+ return {"messages": [AIMessage(content="I don't have access to my knowledge base right now. Let me help you using my general knowledge or search tools instead. What would you like to know?")]}
184
+
185
+ print(f"Searching for: {query}") # Debug print
186
+
187
+ # Try text-based search in the content
188
+ try:
189
+ # Search for documents containing query terms
190
+ result = supabase_client.table('documents').select('content')\
191
+ .ilike('content', f'%{query}%')\
192
+ .limit(3).execute()
193
+
194
+ if result.data and len(result.data) > 0:
195
+ print(f"Found {len(result.data)} results") # Debug print
196
+
197
+ # Get the most relevant result
198
+ content = result.data[0].get('content', '')
199
+
200
+ # Look for final answer pattern
201
+ if "Final answer :" in content:
202
+ answer = content.split("Final answer :")[-1].strip()
203
+ else:
204
+ # Take relevant portion
205
+ answer = content.strip()[:800]
206
+ if len(content) > 800:
207
+ answer += "..."
208
+
209
+ return {"messages": [AIMessage(content=answer)]}
210
+ else:
211
+ print("No matching documents found") # Debug print
212
+
213
+ except Exception as e:
214
+ print(f"Text search failed: {e}")
215
+
216
+ # Fallback: Instead of returning same document, provide helpful response
217
+ return {"messages": [AIMessage(content=f"I couldn't find specific information about '{query}' in my knowledge base. Let me try to help you with my general knowledge, or would you like me to search the web for current information?")]}
218
+
219
+ except Exception as e:
220
+ return {"messages": [AIMessage(content=f"I'm having trouble accessing my knowledge base right now. How can I help you using web search or my general knowledge instead?")]}
221
+
222
+ # Build simple graph
223
+ builder = StateGraph(MessagesState)
224
+ builder.add_node("retriever", retriever)
225
+ builder.set_entry_point("retriever")
226
+ builder.set_finish_point("retriever")
227
+
228
+ return builder.compile()
229
+
230
+ # RECOMMENDED: Use this function instead of build_graph()
231
+ def build_working_graph(provider: str = "groq"):
232
+ """Build a fully functional graph that actually works for different questions"""
233
+ if provider == "groq":
234
+ llm = ChatGroq(
235
+ model="qwen-qwq-32b",
236
+ api_key="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",
237
+ temperature=0
238
+ )
239
+ else:
240
+ raise ValueError("Invalid provider.")
241
+
242
+ llm_with_tools = llm.bind_tools(tools)
243
+
244
+ def assistant(state: MessagesState):
245
+ """Assistant that can provide different answers for different questions"""
246
+ # Add system message to the conversation
247
+ messages = [sys_msg] + state["messages"]
248
+ response = llm_with_tools.invoke(messages)
249
+ return {"messages": [response]}
250
+
251
+ # Build the graph
252
+ builder = StateGraph(MessagesState)
253
+ builder.add_node("assistant", assistant)
254
+ builder.add_node("tools", ToolNode(tools))
255
+
256
+ builder.set_entry_point("assistant")
257
+ builder.add_conditional_edges("assistant", tools_condition)
258
+ builder.add_edge("tools", "assistant")
259
+
260
+ return builder.compile()
261
+
262
+ # Test function
263
+ def test_graph():
264
+ """Test the graph builds successfully"""
265
+ print("Building working graph (recommended)...")
266
+ try:
267
+ graph = build_working_graph()
268
+ print("✓ Working graph built successfully!")
269
+ return graph
270
+ except Exception as e:
271
+ print(f"✗ Working graph failed: {e}")
272
+
273
+ print("Testing retriever-based graph...")
274
+ try:
275
+ graph1 = build_graph()
276
+ print("✓ Retriever graph built successfully!")
277
+ return graph1
278
+ except Exception as e:
279
+ print(f"✗ Retriever graph failed: {e}")
280
+ return None
281
+
282
+ if __name__ == "__main__":
283
+ question = "When was a picture of St. Thomas Aquinas first added to the Wikipedia page on the Principle of double effect?"
284
+
285
+ graph = test_graph()
286
+
287
+ messages = [HumanMessage(content=question)]
288
+ messages = graph.invoke({"messages": messages})
289
+ for m in messages["messages"]:
290
+ m.pretty_print()