Priyanshi Saxena commited on
Commit
c52b367
·
1 Parent(s): 2c26464

feat: more features

Browse files
README_simple.md ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Web3 Research Co-Pilot
3
+ emoji: 🚀
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: docker
7
+ sdk_version: "latest"
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ # 🚀 Web3 Research Co-Pilot
13
+
14
+ AI-powered cryptocurrency research assistant with real-time Web3 data analysis.
15
+
16
+ **Live Demo**: https://archcoder-web3-copilot.hf.space
17
+
18
+ ## Quick Start
19
+
20
+ 1. **Install dependencies**:
21
+ ```bash
22
+ pip install -r requirements.txt
23
+ ```
24
+
25
+ 2. **Set up API key**:
26
+ ```bash
27
+ export GEMINI_API_KEY="your_gemini_api_key"
28
+ ```
29
+
30
+ 3. **Run**:
31
+ ```bash
32
+ python app.py
33
+ ```
34
+
35
+ 4. **Open**: http://localhost:7860
36
+
37
+ ## Features
38
+
39
+ - 🤖 **AI Analysis** with Google Gemini
40
+ - 📊 **Real-time Data** from CoinGecko, DeFiLlama, Etherscan
41
+ - 📈 **Interactive Charts** and visualizations
42
+ - 💼 **Professional UI** with FastAPI
43
+
44
+ ## API Keys
45
+
46
+ - **Required**: [GEMINI_API_KEY](https://aistudio.google.com/)
47
+ - **Optional**: COINGECKO_API_KEY, ETHERSCAN_API_KEY
48
+
49
+ ## Deploy to HuggingFace Spaces
50
+
51
+ ```bash
52
+ git remote add hf https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
53
+ git push hf main
54
+ ```
55
+
56
+ ## Usage Examples
57
+
58
+ - "What's Bitcoin's current price?"
59
+ - "Show top DeFi protocols by TVL"
60
+ - "Analyze Ethereum gas prices"
61
+ - "Compare BTC vs ETH performance"
62
+
63
+ ---
64
+
65
+ Built with ❤️ for Web3 research
src/tools/base_tool.py CHANGED
@@ -1,7 +1,7 @@
1
  from abc import ABC, abstractmethod
2
- from typing import Dict, Any, Optional
3
  from langchain.tools import BaseTool
4
- from pydantic import BaseModel, Field, PrivateAttr
5
  import asyncio
6
  import aiohttp
7
  import hashlib
@@ -14,7 +14,19 @@ logger = get_logger(__name__)
14
 
15
  class Web3ToolInput(BaseModel):
16
  query: str = Field(description="Search query or parameter")
17
- filters: Optional[Dict[str, Any]] = Field(default=None, description="Additional filters")
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  class BaseWeb3Tool(BaseTool, ABC):
20
  name: str = "base_web3_tool"
@@ -72,33 +84,11 @@ class BaseWeb3Tool(BaseTool, ABC):
72
  key_data = f"{url}:{json.dumps(params, sort_keys=True)}"
73
  return hashlib.md5(key_data.encode()).hexdigest()[:16]
74
 
75
- def _run(self, query: str, filters: Optional[Dict[str, Any]] = None) -> str:
76
  return asyncio.run(self._arun(query, filters))
77
-
78
- def run(self, tool_input: Dict[str, Any]) -> str:
79
- """Handle both direct calls and LangChain tool calling format"""
80
- if isinstance(tool_input, dict):
81
- query = tool_input.get('query', '')
82
- filters = tool_input.get('filters')
83
- else:
84
- # Fallback for string input
85
- query = str(tool_input)
86
- filters = None
87
- return self._run(query, filters)
88
-
89
- async def arun(self, tool_input: Dict[str, Any]) -> str:
90
- """Async version of run method"""
91
- if isinstance(tool_input, dict):
92
- query = tool_input.get('query', '')
93
- filters = tool_input.get('filters')
94
- else:
95
- # Fallback for string input
96
- query = str(tool_input)
97
- filters = None
98
- return await self._arun(query, filters)
99
 
100
  @abstractmethod
101
- async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None) -> str:
102
  pass
103
 
104
  async def cleanup(self):
 
1
  from abc import ABC, abstractmethod
2
+ from typing import Dict, Any, Optional, Union
3
  from langchain.tools import BaseTool
4
+ from pydantic import BaseModel, Field, PrivateAttr, field_validator
5
  import asyncio
6
  import aiohttp
7
  import hashlib
 
14
 
15
  class Web3ToolInput(BaseModel):
16
  query: str = Field(description="Search query or parameter")
17
+ filters: Optional[Union[Dict[str, Any], str]] = Field(default=None, description="Additional filters (dict) or filter type (string)")
18
+
19
+ @field_validator('filters')
20
+ @classmethod
21
+ def validate_filters(cls, v):
22
+ if v is None:
23
+ return None
24
+ if isinstance(v, str):
25
+ # Convert string filter to dict format
26
+ return {"type": v}
27
+ if isinstance(v, dict):
28
+ return v
29
+ return None
30
 
31
  class BaseWeb3Tool(BaseTool, ABC):
32
  name: str = "base_web3_tool"
 
84
  key_data = f"{url}:{json.dumps(params, sort_keys=True)}"
85
  return hashlib.md5(key_data.encode()).hexdigest()[:16]
86
 
87
+ def _run(self, query: str, filters: Optional[Dict[str, Any]] = None, **kwargs) -> str:
88
  return asyncio.run(self._arun(query, filters))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  @abstractmethod
91
+ async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None, **kwargs) -> str:
92
  pass
93
 
94
  async def cleanup(self):
src/tools/coingecko_tool.py CHANGED
@@ -23,7 +23,7 @@ class CoinGeckoTool(BaseWeb3Tool):
23
  def __init__(self):
24
  super().__init__()
25
 
26
- async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None) -> str:
27
  filters = filters or {}
28
  try:
29
  # Check cache first
 
23
  def __init__(self):
24
  super().__init__()
25
 
26
+ async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None, **kwargs) -> str:
27
  filters = filters or {}
28
  try:
29
  # Check cache first
src/tools/defillama_tool.py CHANGED
@@ -17,7 +17,7 @@ class DeFiLlamaTool(BaseWeb3Tool):
17
  def __init__(self):
18
  super().__init__()
19
 
20
- async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None) -> str:
21
  try:
22
  filters = filters or {}
23
 
 
17
  def __init__(self):
18
  super().__init__()
19
 
20
+ async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None, **kwargs) -> str:
21
  try:
22
  filters = filters or {}
23
 
src/tools/etherscan_tool.py CHANGED
@@ -25,7 +25,7 @@ class EtherscanTool(BaseWeb3Tool):
25
  if not self.enabled:
26
  logger.warning("Etherscan API key not configured - limited functionality")
27
 
28
- async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None) -> str:
29
  if not self.enabled:
30
  return "⚠️ **Etherscan Service Limited**\n\nEtherscan functionality requires an API key.\nGet yours free at: https://etherscan.io/apis\n\nSet environment variable: `ETHERSCAN_API_KEY=your_key`"
31
 
 
25
  if not self.enabled:
26
  logger.warning("Etherscan API key not configured - limited functionality")
27
 
28
+ async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None, **kwargs) -> str:
29
  if not self.enabled:
30
  return "⚠️ **Etherscan Service Limited**\n\nEtherscan functionality requires an API key.\nGet yours free at: https://etherscan.io/apis\n\nSet environment variable: `ETHERSCAN_API_KEY=your_key`"
31