Mayank2027 commited on
Commit
1d653b0
ยท
verified ยท
1 Parent(s): 44e6dc5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +308 -196
app.py CHANGED
@@ -1,212 +1,324 @@
1
- """Main application - Runs Gemma-2B with tools on CPU"""
2
-
3
  import torch
4
  from transformers import AutoTokenizer, AutoModelForCausalLM
5
- import warnings
6
- warnings.filterwarnings("ignore")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- from tools import execute_tool, TOOL_REGISTRY, TOOL_DESCRIPTIONS
9
- from router_client import ToolRouter
 
 
 
 
 
 
 
10
 
11
- class ToolAugmentedAgent:
12
- """AI agent with tool-calling capabilities"""
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- def __init__(self):
15
- print("=" * 50)
16
- print("Loading Tool-Augmented Agent...")
17
- print("=" * 50)
18
-
19
- # Load the model on CPU
20
- print("\n๐Ÿ“ฅ Loading Gemma-2B-Uncensored model (this will take a moment)...")
21
- self.model_name = "sirev/Gemma-2b-Uncensored-v1"
22
-
23
- self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
24
- self.model = AutoModelForCausalLM.from_pretrained(
25
- self.model_name,
26
- torch_dtype=torch.float32, # Use float32 for CPU
27
- low_cpu_mem_usage=True
28
- )
29
-
30
- print(f"โœ… Model loaded on CPU")
31
- print(f"๐Ÿ“Š Model parameters: {sum(p.numel() for p in self.model.parameters()) / 1e9:.1f}B")
32
-
33
- # Initialize the tool router
34
- print("๐Ÿ”„ Initializing tool router...")
35
- self.router = ToolRouter(use_hosted_api=True)
36
-
37
- # Available tools
38
- self.available_tools = list(TOOL_REGISTRY.keys())
39
- print(f"๐Ÿ”ง Available tools: {len(self.available_tools)}")
40
- print(f" {', '.join(self.available_tools[:10])}...")
41
- print("=" * 50)
42
-
43
- def generate_response(self, prompt: str, max_length: int = 512) -> str:
44
- """Generate response from the model"""
45
- inputs = self.tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1024)
46
-
47
- with torch.no_grad():
48
- outputs = self.model.generate(
49
- **inputs,
50
- max_new_tokens=max_length,
51
- temperature=0.7,
52
- do_sample=True,
53
- top_p=0.9,
54
- pad_token_id=self.tokenizer.eos_token_id
55
- )
56
-
57
- response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
58
- # Remove the input prompt from the response
59
- response = response[len(prompt):].strip()
60
- return response if response else "I couldn't generate a response."
61
 
62
- def process_task(self, user_query: str, verbose: bool = True) -> str:
63
- """Process a user query by selecting and executing appropriate tools"""
64
-
65
- print(f"\n๐Ÿ“ User: {user_query}")
66
- print("-" * 40)
67
-
68
- # Step 1: Route to find relevant tools
69
- print("๐Ÿ” Selecting tools for this task...")
70
- selected_tools = self.router.route(user_query, k=3)
71
-
72
- if not selected_tools:
73
- # If no specific tools found, use web search as default
74
- selected_tools = ["web_search"]
75
-
76
- print(f" Selected tools: {', '.join(selected_tools)}")
77
-
78
- # Step 2: Execute tools and collect results
79
- print("\n๐Ÿ”ง Executing tools...")
80
- tool_results = []
81
-
82
- for tool_name in selected_tools:
83
- if tool_name in TOOL_REGISTRY:
84
- print(f" โ†’ Running {tool_name}...")
85
-
86
- # Different tools need different parameters
87
- if tool_name == "web_search":
88
- result = execute_tool(tool_name, query=user_query)
89
- elif tool_name == "fetch_url":
90
- # Extract URL from query if present
91
- import re
92
- urls = re.findall(r'https?://[^\s]+', user_query)
93
- if urls:
94
- result = execute_tool(tool_name, url=urls[0])
95
- else:
96
- result = {"success": False, "error": "No URL found in query"}
97
- elif tool_name == "scholar_search":
98
- result = execute_tool(tool_name, query=user_query)
99
- elif tool_name == "get_news":
100
- # Extract topic from query
101
- topic = user_query.replace("news", "").replace("about", "").strip()
102
- result = execute_tool(tool_name, topic=topic or "general")
103
- elif tool_name == "wikipedia":
104
- result = execute_tool(tool_name, topic=user_query[:50])
105
- elif tool_name == "weather":
106
- # Extract city from query
107
- import re
108
- cities = re.findall(r'in (\w+)', user_query)
109
- city = cities[0] if cities else "London"
110
- result = execute_tool(tool_name, city=city)
111
- elif tool_name == "calculate":
112
- result = execute_tool(tool_name, expression=user_query)
113
- elif tool_name in ["extract_dates", "extract_emails", "extract_urls", "summarize"]:
114
- # These need text input, use the query as text
115
- result = execute_tool(tool_name, text=user_query)
116
- else:
117
- result = execute_tool(tool_name)
118
-
119
- tool_results.append({
120
- "tool": tool_name,
121
- "result": result
122
- })
123
-
124
- # Show result preview
125
- if result.get("success"):
126
- preview = str(result)[:100] + "..."
127
- print(f" โœ“ {preview}")
128
- else:
129
- print(f" โœ— Error: {result.get('error', 'Unknown error')}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  else:
131
- print(f" โ†’ Tool {tool_name} not found in registry")
132
-
133
- # Step 3: Prepare context for the LLM
134
- print("\n๐Ÿค– Generating final response...")
135
-
136
- context = f"""You are a helpful AI assistant with access to various tools. Based on the tool results below, answer the user's question naturally.
 
 
 
 
 
 
137
 
138
- User question: {user_query}
139
 
140
  Tool results:
141
- """
142
- for tr in tool_results:
143
- if tr["result"].get("success"):
144
- context += f"\n[{tr['tool']}]: {tr['result']}\n"
145
- else:
146
- context += f"\n[{tr['tool']}] Error: {tr['result'].get('error', 'Failed')}\n"
147
 
148
- context += """
149
 
150
- Please provide a clear, helpful answer based on the information above. If the tools didn't provide useful results, say so and offer alternatives."""
 
 
 
 
 
 
 
 
 
 
151
 
152
- # Step 4: Generate final response
153
- response = self.generate_response(context, max_length=400)
154
-
155
- print("\n" + "=" * 40)
156
- print(f"๐Ÿค– Assistant: {response}")
157
- print("=" * 40)
158
-
159
- return response
160
-
161
- def interactive_mode(self):
162
- """Run in interactive mode"""
163
- print("\n" + "=" * 50)
164
- print("๐ŸŸข Tool-Augmented Agent Ready!")
165
- print("=" * 50)
166
- print("Available tools:")
167
- for i, tool in enumerate(self.available_tools[:15], 1):
168
- print(f" {i}. {tool}")
169
- print(" ...")
170
- print("\nType 'exit' to quit, 'help' for tool descriptions\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
- while True:
173
- try:
174
- query = input("\n๐Ÿ’ฌ You: ").strip()
175
-
176
- if query.lower() == 'exit':
177
- print("Goodbye! ๐Ÿ‘‹")
178
- break
179
- elif query.lower() == 'help':
180
- print("\n๐Ÿ“š Tool Descriptions:")
181
- for tool, desc in list(TOOL_DESCRIPTIONS.items())[:20]:
182
- print(f" โ€ข {tool}: {desc}")
183
- continue
184
-
185
- if query:
186
- self.process_task(query)
187
-
188
- except KeyboardInterrupt:
189
- print("\n\nInterrupted. Goodbye!")
190
- break
191
- except Exception as e:
192
- print(f"\nโŒ Error: {e}")
193
- print("Please try again.")
194
-
195
- def main():
196
- """Main entry point"""
197
- agent = ToolAugmentedAgent()
198
-
199
- # Example queries to demonstrate functionality
200
- print("\n๐Ÿ“‹ Try these example queries:")
201
- print(" โ€ข 'Search for recent developments in AI'")
202
- print(" โ€ข 'What's the weather in Tokyo?'")
203
- print(" โ€ข 'Calculate 15 * 87 + 23'")
204
- print(" โ€ข 'Get today's news about space exploration'")
205
- print(" โ€ข 'Find academic papers about quantum computing'")
206
- print(" โ€ข 'Summarize: [paste long text]'")
207
-
208
- # Start interactive mode
209
- agent.interactive_mode()
210
 
211
  if __name__ == "__main__":
212
- main()
 
 
 
1
  import torch
2
  from transformers import AutoTokenizer, AutoModelForCausalLM
3
+ import requests
4
+ import re
5
+ from datetime import datetime
6
+ from typing import List
7
+ import gradio as gr
8
+
9
+ # ============================================
10
+ # TOOLS
11
+ # ============================================
12
+
13
+ def web_search(query: str) -> str:
14
+ """Search the web"""
15
+ try:
16
+ url = f"https://api.duckduckgo.com/?q={query}&format=json&no_html=1"
17
+ r = requests.get(url, timeout=10)
18
+ data = r.json()
19
+ results = []
20
+ for topic in data.get("RelatedTopics", [])[:3]:
21
+ if isinstance(topic, dict) and "Text" in topic:
22
+ results.append(topic["Text"][:300])
23
+ return "\n".join(results) if results else "No results found"
24
+ except Exception as e:
25
+ return f"Search failed: {str(e)}"
26
+
27
+ def wikipedia(topic: str) -> str:
28
+ """Get Wikipedia summary"""
29
+ try:
30
+ url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{topic.replace(' ', '_')}"
31
+ r = requests.get(url, timeout=10)
32
+ data = r.json()
33
+ return data.get("extract", "Not found")[:1000]
34
+ except Exception as e:
35
+ return f"Wikipedia lookup failed: {str(e)}"
36
+
37
+ def get_weather(city: str) -> str:
38
+ """Get weather for a city"""
39
+ try:
40
+ r = requests.get(f"https://wttr.in/{city}?format=%C:+%t", timeout=10)
41
+ return f"Weather in {city}: {r.text.strip()}"
42
+ except Exception as e:
43
+ return f"Weather lookup failed: {str(e)}"
44
+
45
+ def calculate(expression: str) -> str:
46
+ """Calculate math expression"""
47
+ # Clean the expression
48
+ expression = re.sub(r'[^0-9+\-*/().%]', '', expression)
49
+ if not expression:
50
+ return "Please provide a math expression like '2+2' or '15 * 3'"
51
+ try:
52
+ result = eval(expression)
53
+ return f"{expression} = {result}"
54
+ except Exception as e:
55
+ return f"Calculation error: {str(e)}"
56
+
57
+ def get_time() -> str:
58
+ """Get current time"""
59
+ return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
60
+
61
+ def summarize_text(text: str) -> str:
62
+ """Simple summarization"""
63
+ if len(text) < 50:
64
+ return "Text too short to summarize. Please provide at least 50 characters."
65
+ sentences = re.split(r'[.!?]+', text)
66
+ key_sentences = [s.strip() for s in sentences if len(s.strip()) > 30][:3]
67
+ if not key_sentences:
68
+ return text[:300] + "..."
69
+ return ". ".join(key_sentences) + "."
70
 
71
+ # Tool mapping
72
+ TOOLS = {
73
+ "web_search": web_search,
74
+ "wikipedia": wikipedia,
75
+ "weather": get_weather,
76
+ "calculate": calculate,
77
+ "current_time": get_time,
78
+ "summarize": summarize_text,
79
+ }
80
 
81
+ # ============================================
82
+ # ROUTER
83
+ # ============================================
84
+
85
+ def route_task(task: str) -> List[str]:
86
+ """Simple keyword-based router"""
87
+ task_lower = task.lower()
88
+ routing = {
89
+ "web_search": ["search", "google", "find", "look up", "internet", "news", "latest"],
90
+ "wikipedia": ["wiki", "wikipedia", "who is", "what is", "tell me about"],
91
+ "weather": ["weather", "temperature", "rain", "sunny", "forecast"],
92
+ "calculate": ["calculate", "math", "plus", "minus", "times", "divide", "=", "+", "-", "*", "/"],
93
+ "current_time": ["time", "date", "today", "now"],
94
+ "summarize": ["summarize", "summary", "tl;dr", "shorten"],
95
+ }
96
 
97
+ selected = []
98
+ for tool, keywords in routing.items():
99
+ if any(k in task_lower for k in keywords):
100
+ selected.append(tool)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
+ # Always include web_search if nothing else matches
103
+ return selected[:3] if selected else ["web_search"]
104
+
105
+ # ============================================
106
+ # LOAD MODEL (with better error handling)
107
+ # ============================================
108
+
109
+ print("๐Ÿ“ฅ Loading Gemma-2B model... (this takes 2-3 minutes on first run)")
110
+
111
+ try:
112
+ tokenizer = AutoTokenizer.from_pretrained("sirev/Gemma-2b-Uncensored-v1")
113
+ model = AutoModelForCausalLM.from_pretrained(
114
+ "sirev/Gemma-2b-Uncensored-v1",
115
+ torch_dtype=torch.float32,
116
+ low_cpu_mem_usage=True
117
+ )
118
+ print("โœ… Model loaded successfully!")
119
+ except Exception as e:
120
+ print(f"โŒ Failed to load model: {e}")
121
+ # Fallback to a smaller model if Gemma fails
122
+ print("๐Ÿ”„ Trying fallback model...")
123
+ tokenizer = AutoTokenizer.from_pretrained("microsoft/phi-2")
124
+ model = AutoModelForCausalLM.from_pretrained(
125
+ "microsoft/phi-2",
126
+ torch_dtype=torch.float32,
127
+ low_cpu_mem_usage=True
128
+ )
129
+ print("โœ… Fallback model loaded!")
130
+
131
+ def generate_response(prompt: str) -> str:
132
+ """Generate response from the model"""
133
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1024)
134
+ outputs = model.generate(
135
+ **inputs,
136
+ max_new_tokens=300,
137
+ temperature=0.7,
138
+ do_sample=True,
139
+ pad_token_id=tokenizer.eos_token_id
140
+ )
141
+ response = tokenizer.decode(outputs[0], skip_special_tokens=True)
142
+ # Remove the input prompt from the response
143
+ response = response[len(prompt):].strip()
144
+ return response if response else "I couldn't generate a response."
145
+
146
+ # ============================================
147
+ # AGENT FUNCTION
148
+ # ============================================
149
+
150
+ def run_agent(user_query: str, history: list = None) -> str:
151
+ """Main agent function - called by Gradio"""
152
+
153
+ if not user_query or user_query.strip() == "":
154
+ return "Please enter a question."
155
+
156
+ print(f"๐Ÿ“ Processing: {user_query}")
157
+
158
+ # Step 1: Route to find relevant tools
159
+ tools_to_use = route_task(user_query)
160
+ print(f"๐Ÿ”ง Selected tools: {tools_to_use}")
161
+
162
+ # Step 2: Execute tools
163
+ tool_results = []
164
+ for tool in tools_to_use:
165
+ try:
166
+ if tool == "web_search":
167
+ result = web_search(user_query)
168
+ elif tool == "wikipedia":
169
+ # Extract topic (simple: take first few words, excluding question words)
170
+ words = user_query.lower().split()
171
+ stop_words = {"what", "who", "where", "when", "why", "how", "is", "are", "tell", "me", "about"}
172
+ topic_words = [w for w in user_query.split() if w.lower() not in stop_words][:4]
173
+ topic = ' '.join(topic_words) if topic_words else user_query[:50]
174
+ result = wikipedia(topic)
175
+ elif tool == "weather":
176
+ # Extract city
177
+ words = user_query.split()
178
+ city = "London"
179
+ if "in" in words:
180
+ city = words[words.index("in") + 1]
181
+ elif "for" in words:
182
+ city = words[words.index("for") + 1]
183
+ result = get_weather(city)
184
+ elif tool == "calculate":
185
+ # Extract math expression
186
+ math_match = re.search(r'[\d\s\+\-\*/\(\)\.\%]+', user_query)
187
+ expr = math_match.group(0) if math_match else user_query
188
+ result = calculate(expr)
189
+ elif tool == "current_time":
190
+ result = get_time()
191
+ elif tool == "summarize":
192
+ result = summarize_text(user_query)
193
  else:
194
+ result = f"Tool '{tool}' not implemented"
195
+
196
+ tool_results.append(f"๐Ÿ”น {tool}: {result[:400]}")
197
+ print(f" โœ“ {tool} executed")
198
+ except Exception as e:
199
+ tool_results.append(f"๐Ÿ”ธ {tool}: Error - {str(e)[:100]}")
200
+ print(f" โœ— {tool} failed: {e}")
201
+
202
+ # Step 3: Generate response with LLM
203
+ tool_context = "\n".join(tool_results) if tool_results else "No tools were executed."
204
+
205
+ context = f"""You are a helpful AI assistant. Answer the user's question based on the tool results below.
206
 
207
+ User: {user_query}
208
 
209
  Tool results:
210
+ {tool_context}
 
 
 
 
 
211
 
212
+ Please provide a clear, helpful answer based on the information above. If the tools didn't provide useful information, say so and offer to help differently."""
213
 
214
+ print("๐Ÿค– Generating response...")
215
+ response = generate_response(context)
216
+
217
+ # Add tool info prefix for transparency
218
+ if len(tools_to_use) <= 2:
219
+ final_response = f"๐Ÿ”ง {', '.join(tools_to_use)}\n\n{response}"
220
+ else:
221
+ final_response = f"๐Ÿ”ง {len(tools_to_use)} tools used\n\n{response}"
222
+
223
+ print("โœ… Done")
224
+ return final_response
225
 
226
+ # ============================================
227
+ # GRADIO INTERFACE
228
+ # ============================================
229
+
230
+ # Example queries for users to try
231
+ examples = [
232
+ "What is artificial intelligence?",
233
+ "Search for latest news about space exploration",
234
+ "What's the weather in Tokyo?",
235
+ "Calculate 25 * 4 + 10",
236
+ "What time is it?",
237
+ "Summarize: The quick brown fox jumps over the lazy dog. This is a test sentence. The end.",
238
+ "Tell me about quantum computing",
239
+ ]
240
+
241
+ # CSS for better appearance
242
+ css = """
243
+ .gradio-container {
244
+ max-width: 900px !important;
245
+ margin: auto !important;
246
+ }
247
+ h1 {
248
+ text-align: center;
249
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
250
+ -webkit-background-clip: text;
251
+ -webkit-text-fill-color: transparent;
252
+ }
253
+ """
254
+
255
+ with gr.Blocks(title="Tool-Augmented AI Assistant", css=css, theme=gr.themes.Soft()) as demo:
256
+ gr.Markdown("""
257
+ # ๐Ÿ› ๏ธ Tool-Augmented AI Assistant
258
+
259
+ ### Powered by Gemma-2B-Uncensored + 6 Tools
260
+ """)
261
+
262
+ with gr.Row():
263
+ with gr.Column(scale=4):
264
+ chatbot = gr.Chatbot(height=500, label="Conversation")
265
+ with gr.Column(scale=1):
266
+ gr.Markdown("""
267
+ ### ๐Ÿš€ Available Tools
268
+ - ๐Ÿ” **Web Search** - Search the internet
269
+ - ๐Ÿ“š **Wikipedia** - Encyclopedia lookup
270
+ - โ›… **Weather** - Current conditions
271
+ - ๐Ÿงฎ **Calculator** - Math operations
272
+ - โฐ **Current Time** - Date and time
273
+ - ๐Ÿ“ **Summarizer** - Shorten long text
274
+ """)
275
+
276
+ with gr.Row():
277
+ msg = gr.Textbox(
278
+ label="Your Question",
279
+ placeholder="Type anything... (e.g., 'Search for AI news' or 'Weather in Paris')",
280
+ scale=4
281
+ )
282
+ submit_btn = gr.Button("Send", variant="primary", scale=1)
283
+
284
+ clear_btn = gr.Button("Clear Conversation", variant="secondary")
285
+
286
+ gr.Markdown("""
287
+ ### ๐Ÿ’ก Example Questions
288
+ """)
289
+
290
+ gr.Examples(
291
+ examples=examples,
292
+ inputs=msg,
293
+ label="Click any example to try"
294
+ )
295
+
296
+ gr.Markdown("""
297
+ ---
298
+ *Note: Runs on CPU, so responses take 5-15 seconds. The model is uncensored - use responsibly.*
299
+ """)
300
+
301
+ # State for conversation history
302
+ state = gr.State([])
303
+
304
+ def respond(message, chat_history):
305
+ if not message or not message.strip():
306
+ return "", chat_history
307
 
308
+ response = run_agent(message)
309
+ chat_history.append((message, response))
310
+ return "", chat_history
311
+
312
+ def clear_chat():
313
+ return [], []
314
+
315
+ msg.submit(respond, [msg, state], [msg, state])
316
+ submit_btn.click(respond, [msg, state], [msg, state])
317
+ clear_btn.click(clear_chat, None, [chatbot, state])
318
+
319
+ # ============================================
320
+ # LAUNCH
321
+ # ============================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
  if __name__ == "__main__":
324
+ demo.launch()