Spaces:
Sleeping
Sleeping
Priyanshi Saxena
commited on
Commit
Β·
2fe0e75
1
Parent(s):
6bf47a1
new
Browse files- app.py +1 -1
- src/agent/research_agent.py +96 -64
- src/tools/chart_data_tool.py +19 -14
app.py
CHANGED
|
@@ -513,7 +513,7 @@ async def process_query_stream(request: QueryRequest):
|
|
| 513 |
await asyncio.sleep(0.5)
|
| 514 |
|
| 515 |
# Send final result
|
| 516 |
-
yield f"data: {json.dumps({'type': 'result', 'data': result.
|
| 517 |
|
| 518 |
except asyncio.TimeoutError:
|
| 519 |
processing_time = (datetime.now() - start_time).total_seconds()
|
|
|
|
| 513 |
await asyncio.sleep(0.5)
|
| 514 |
|
| 515 |
# Send final result
|
| 516 |
+
yield f"data: {json.dumps({'type': 'result', 'data': result.model_dump(), 'progress': 100})}\n\n"
|
| 517 |
|
| 518 |
except asyncio.TimeoutError:
|
| 519 |
processing_time = (datetime.now() - start_time).total_seconds()
|
src/agent/research_agent.py
CHANGED
|
@@ -58,12 +58,12 @@ class Web3ResearchAgent:
|
|
| 58 |
"""Initialize Gemini LLM"""
|
| 59 |
try:
|
| 60 |
self.llm = ChatGoogleGenerativeAI(
|
| 61 |
-
model="gemini-
|
| 62 |
google_api_key=config.GEMINI_API_KEY,
|
| 63 |
temperature=0.1
|
| 64 |
)
|
| 65 |
self.gemini_available = True
|
| 66 |
-
logger.info("β
Gemini initialized")
|
| 67 |
except Exception as e:
|
| 68 |
logger.warning(f"Gemini initialization failed: {e}")
|
| 69 |
self.gemini_available = False
|
|
@@ -261,41 +261,57 @@ Just list the tool names:"""
|
|
| 261 |
|
| 262 |
# Step 2: Execute relevant tools
|
| 263 |
tool_results = []
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
# Handle chart_data_provider with proper parameters
|
| 271 |
-
if tool_name == "chart_data_provider":
|
| 272 |
-
# Extract chart type from query or default to price_chart
|
| 273 |
-
chart_type = "price_chart" # Default
|
| 274 |
-
symbol = "bitcoin" # Default
|
| 275 |
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
chart_type = "
|
| 280 |
-
|
| 281 |
-
chart_type = "gas_tracker"
|
| 282 |
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
|
| 289 |
-
result
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
|
| 300 |
# Step 3: Generate final response with tool results using AI Safety
|
| 301 |
context = "\n".join(tool_results) if tool_results else "No tool data available - provide general information."
|
|
@@ -405,38 +421,54 @@ Respond with only the tool names, comma-separated (no explanations)."""
|
|
| 405 |
|
| 406 |
# Step 2: Execute tools (same logic as Ollama version)
|
| 407 |
tool_results = []
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
# Handle chart_data_provider with proper parameters
|
| 415 |
-
if tool_name == "chart_data_provider":
|
| 416 |
-
chart_type = "price_chart"
|
| 417 |
-
symbol = "bitcoin"
|
| 418 |
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
chart_type = "market_overview"
|
| 423 |
-
elif "gas" in query.lower():
|
| 424 |
-
chart_type = "gas_tracker"
|
| 425 |
-
|
| 426 |
-
if "ethereum" in query.lower() or "eth" in query.lower():
|
| 427 |
-
symbol = "ethereum"
|
| 428 |
-
elif "bitcoin" in query.lower() or "btc" in query.lower():
|
| 429 |
symbol = "bitcoin"
|
| 430 |
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
|
| 441 |
# Step 3: Generate final response with Gemini
|
| 442 |
context = "\n".join(tool_results) if tool_results else "No tool data available - provide general information."
|
|
@@ -474,7 +506,7 @@ Respond with only the tool names, comma-separated (no explanations)."""
|
|
| 474 |
"result": final_response,
|
| 475 |
"sources": [],
|
| 476 |
"metadata": {
|
| 477 |
-
"llm_used": f"Gemini ({self.llm.model_name if hasattr(self.llm, 'model_name') else 'gemini-
|
| 478 |
"tools_used": suggested_tools,
|
| 479 |
"timestamp": datetime.now().isoformat()
|
| 480 |
}
|
|
|
|
| 58 |
"""Initialize Gemini LLM"""
|
| 59 |
try:
|
| 60 |
self.llm = ChatGoogleGenerativeAI(
|
| 61 |
+
model="gemini-2.0-flash-lite", # Updated to Gemini 2.0 Flash-Lite
|
| 62 |
google_api_key=config.GEMINI_API_KEY,
|
| 63 |
temperature=0.1
|
| 64 |
)
|
| 65 |
self.gemini_available = True
|
| 66 |
+
logger.info("β
Gemini initialized with gemini-2.0-flash-lite")
|
| 67 |
except Exception as e:
|
| 68 |
logger.warning(f"Gemini initialization failed: {e}")
|
| 69 |
self.gemini_available = False
|
|
|
|
| 261 |
|
| 262 |
# Step 2: Execute relevant tools
|
| 263 |
tool_results = []
|
| 264 |
+
try:
|
| 265 |
+
for tool_name in suggested_tools:
|
| 266 |
+
tool = next((t for t in self.tools if t.name == tool_name), None)
|
| 267 |
+
if tool:
|
| 268 |
+
try:
|
| 269 |
+
logger.info(f"π§ Executing {tool_name}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
|
| 271 |
+
# Handle chart_data_provider with proper parameters
|
| 272 |
+
if tool_name == "chart_data_provider":
|
| 273 |
+
# Extract chart type from query or default to price_chart
|
| 274 |
+
chart_type = "price_chart" # Default
|
| 275 |
+
symbol = "bitcoin" # Default
|
|
|
|
| 276 |
|
| 277 |
+
if "defi" in query.lower() or "tvl" in query.lower():
|
| 278 |
+
chart_type = "defi_tvl"
|
| 279 |
+
elif "market" in query.lower() or "overview" in query.lower():
|
| 280 |
+
chart_type = "market_overview"
|
| 281 |
+
elif "gas" in query.lower():
|
| 282 |
+
chart_type = "gas_tracker"
|
| 283 |
+
|
| 284 |
+
# Extract symbol if mentioned
|
| 285 |
+
if "ethereum" in query.lower() or "eth" in query.lower():
|
| 286 |
+
symbol = "ethereum"
|
| 287 |
+
elif "bitcoin" in query.lower() or "btc" in query.lower():
|
| 288 |
+
symbol = "bitcoin"
|
| 289 |
+
|
| 290 |
+
result = await tool._arun(chart_type=chart_type, symbol=symbol)
|
| 291 |
+
else:
|
| 292 |
+
# Other tools use the query directly
|
| 293 |
+
result = await tool._arun(query)
|
| 294 |
|
| 295 |
+
logger.info(f"π {tool_name} result preview: {str(result)[:200]}...")
|
| 296 |
+
tool_results.append(f"=== {tool_name} Results ===\n{result}\n")
|
| 297 |
+
except Exception as e:
|
| 298 |
+
logger.error(f"Tool {tool_name} failed: {e}")
|
| 299 |
+
tool_results.append(f"=== {tool_name} Error ===\nTool failed: {str(e)}\n")
|
| 300 |
+
finally:
|
| 301 |
+
# Cleanup tool session if available
|
| 302 |
+
if hasattr(tool, 'cleanup'):
|
| 303 |
+
try:
|
| 304 |
+
await tool.cleanup()
|
| 305 |
+
except Exception:
|
| 306 |
+
pass # Ignore cleanup errors
|
| 307 |
+
finally:
|
| 308 |
+
# Ensure all tools are cleaned up
|
| 309 |
+
for tool in self.tools:
|
| 310 |
+
if hasattr(tool, 'cleanup'):
|
| 311 |
+
try:
|
| 312 |
+
await tool.cleanup()
|
| 313 |
+
except Exception:
|
| 314 |
+
pass
|
| 315 |
|
| 316 |
# Step 3: Generate final response with tool results using AI Safety
|
| 317 |
context = "\n".join(tool_results) if tool_results else "No tool data available - provide general information."
|
|
|
|
| 421 |
|
| 422 |
# Step 2: Execute tools (same logic as Ollama version)
|
| 423 |
tool_results = []
|
| 424 |
+
try:
|
| 425 |
+
for tool_name in suggested_tools:
|
| 426 |
+
tool = next((t for t in self.tools if t.name == tool_name), None)
|
| 427 |
+
if tool:
|
| 428 |
+
try:
|
| 429 |
+
logger.info(f"π§ Executing {tool_name}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 430 |
|
| 431 |
+
# Handle chart_data_provider with proper parameters
|
| 432 |
+
if tool_name == "chart_data_provider":
|
| 433 |
+
chart_type = "price_chart"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 434 |
symbol = "bitcoin"
|
| 435 |
|
| 436 |
+
if "defi" in query.lower() or "tvl" in query.lower():
|
| 437 |
+
chart_type = "defi_tvl"
|
| 438 |
+
elif "market" in query.lower() or "overview" in query.lower():
|
| 439 |
+
chart_type = "market_overview"
|
| 440 |
+
elif "gas" in query.lower():
|
| 441 |
+
chart_type = "gas_tracker"
|
| 442 |
+
|
| 443 |
+
if "ethereum" in query.lower() or "eth" in query.lower():
|
| 444 |
+
symbol = "ethereum"
|
| 445 |
+
elif "bitcoin" in query.lower() or "btc" in query.lower():
|
| 446 |
+
symbol = "bitcoin"
|
| 447 |
+
|
| 448 |
+
result = await tool._arun(chart_type=chart_type, symbol=symbol)
|
| 449 |
+
else:
|
| 450 |
+
result = await tool._arun(query)
|
| 451 |
+
|
| 452 |
+
logger.info(f"π {tool_name} result preview: {str(result)[:200]}...")
|
| 453 |
+
tool_results.append(f"=== {tool_name} Results ===\n{result}\n")
|
| 454 |
+
except Exception as e:
|
| 455 |
+
logger.error(f"Tool {tool_name} failed: {e}")
|
| 456 |
+
tool_results.append(f"=== {tool_name} Error ===\nTool failed: {str(e)}\n")
|
| 457 |
+
finally:
|
| 458 |
+
# Cleanup tool session if available
|
| 459 |
+
if hasattr(tool, 'cleanup'):
|
| 460 |
+
try:
|
| 461 |
+
await tool.cleanup()
|
| 462 |
+
except Exception:
|
| 463 |
+
pass # Ignore cleanup errors
|
| 464 |
+
finally:
|
| 465 |
+
# Ensure all tools are cleaned up
|
| 466 |
+
for tool in self.tools:
|
| 467 |
+
if hasattr(tool, 'cleanup'):
|
| 468 |
+
try:
|
| 469 |
+
await tool.cleanup()
|
| 470 |
+
except Exception:
|
| 471 |
+
pass
|
| 472 |
|
| 473 |
# Step 3: Generate final response with Gemini
|
| 474 |
context = "\n".join(tool_results) if tool_results else "No tool data available - provide general information."
|
|
|
|
| 506 |
"result": final_response,
|
| 507 |
"sources": [],
|
| 508 |
"metadata": {
|
| 509 |
+
"llm_used": f"Gemini ({self.llm.model_name if hasattr(self.llm, 'model_name') else 'gemini-1.5-flash'})",
|
| 510 |
"tools_used": suggested_tools,
|
| 511 |
"timestamp": datetime.now().isoformat()
|
| 512 |
}
|
src/tools/chart_data_tool.py
CHANGED
|
@@ -50,39 +50,44 @@ class ChartDataTool(BaseTool):
|
|
| 50 |
return asyncio.run(self._arun(chart_type, symbol, timeframe, protocols, network))
|
| 51 |
|
| 52 |
async def _arun(self, chart_type: str, symbol: str = None, timeframe: str = "30d",
|
| 53 |
-
|
| 54 |
-
"""
|
| 55 |
try:
|
| 56 |
logger.info(f"Providing {chart_type} data for {symbol or 'general'}")
|
| 57 |
|
| 58 |
-
# Convert timeframe to days
|
| 59 |
-
days = self._parse_timeframe(timeframe)
|
| 60 |
-
|
| 61 |
if chart_type == "price_chart":
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
| 63 |
elif chart_type == "market_overview":
|
| 64 |
-
|
| 65 |
elif chart_type == "defi_tvl":
|
| 66 |
-
|
| 67 |
elif chart_type == "portfolio_pie":
|
| 68 |
-
|
| 69 |
elif chart_type == "gas_tracker":
|
| 70 |
-
|
| 71 |
else:
|
| 72 |
-
|
| 73 |
"chart_type": "error",
|
| 74 |
"error": f"Unknown chart type: {chart_type}",
|
| 75 |
"available_types": ["price_chart", "market_overview", "defi_tvl", "portfolio_pie", "gas_tracker"]
|
| 76 |
})
|
| 77 |
-
|
|
|
|
|
|
|
| 78 |
except Exception as e:
|
| 79 |
-
logger.error(f"Chart data
|
| 80 |
return json.dumps({
|
| 81 |
"chart_type": "error",
|
| 82 |
"error": str(e),
|
| 83 |
"message": "Failed to generate chart data"
|
| 84 |
})
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
| 86 |
async def _get_price_chart_data(self, symbol: str, days: int) -> str:
|
| 87 |
"""Get price chart data with fallback for API failures"""
|
| 88 |
try:
|
|
|
|
| 50 |
return asyncio.run(self._arun(chart_type, symbol, timeframe, protocols, network))
|
| 51 |
|
| 52 |
async def _arun(self, chart_type: str, symbol: str = None, timeframe: str = "30d",
|
| 53 |
+
protocols: List[str] = None, network: str = "ethereum") -> str:
|
| 54 |
+
"""Asynchronous execution with proper session cleanup"""
|
| 55 |
try:
|
| 56 |
logger.info(f"Providing {chart_type} data for {symbol or 'general'}")
|
| 57 |
|
|
|
|
|
|
|
|
|
|
| 58 |
if chart_type == "price_chart":
|
| 59 |
+
if not symbol:
|
| 60 |
+
symbol = "bitcoin" # Default symbol
|
| 61 |
+
days = {"1d": 1, "7d": 7, "30d": 30, "90d": 90, "365d": 365}.get(timeframe, 30)
|
| 62 |
+
result = await self._get_price_chart_data(symbol, days)
|
| 63 |
elif chart_type == "market_overview":
|
| 64 |
+
result = await self._get_market_overview_data()
|
| 65 |
elif chart_type == "defi_tvl":
|
| 66 |
+
result = await self._get_defi_tvl_data(protocols)
|
| 67 |
elif chart_type == "portfolio_pie":
|
| 68 |
+
result = await self._get_portfolio_data()
|
| 69 |
elif chart_type == "gas_tracker":
|
| 70 |
+
result = await self._get_gas_tracker_data(network)
|
| 71 |
else:
|
| 72 |
+
result = json.dumps({
|
| 73 |
"chart_type": "error",
|
| 74 |
"error": f"Unknown chart type: {chart_type}",
|
| 75 |
"available_types": ["price_chart", "market_overview", "defi_tvl", "portfolio_pie", "gas_tracker"]
|
| 76 |
})
|
| 77 |
+
|
| 78 |
+
return result
|
| 79 |
+
|
| 80 |
except Exception as e:
|
| 81 |
+
logger.error(f"Chart data generation failed: {e}")
|
| 82 |
return json.dumps({
|
| 83 |
"chart_type": "error",
|
| 84 |
"error": str(e),
|
| 85 |
"message": "Failed to generate chart data"
|
| 86 |
})
|
| 87 |
+
finally:
|
| 88 |
+
# Ensure session cleanup
|
| 89 |
+
await self.cleanup()
|
| 90 |
+
|
| 91 |
async def _get_price_chart_data(self, symbol: str, days: int) -> str:
|
| 92 |
"""Get price chart data with fallback for API failures"""
|
| 93 |
try:
|