lemdaddy commited on
Commit
d068566
·
1 Parent(s): 9c400b9

second commit

Browse files
.gitignore CHANGED
@@ -109,4 +109,7 @@ dmypy.json
109
  .idea/
110
 
111
  # Mac OS
112
- .DS_Store
 
 
 
 
109
  .idea/
110
 
111
  # Mac OS
112
+ .DS_Store
113
+
114
+ TODO.md
115
+ run.py
README.md ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ChatXBT Web3 AI Assitant Service
2
+
3
+ AI-powered unification and execution protocol for web3 applications
4
+
5
+ ## Requirements
6
+
7
+ The list below contains all the requirements needed to have a complete developer environment to sart working on this project.
8
+ Follow the links to install or update these tools on your machine.
9
+
10
+ 1. [Python 3.12+](https://www.python.org/downloads/release/python-3120/)
11
+ 2. [Pyenv](https://github.com/pyenv/pyenv)
12
+ 3. [Pip Installer](https://pip.pypa.io/en/stable/installation/)
13
+ 4. [Python Venv](https://docs.python.org/3/library/venv.html)
14
+
15
+ ## Installation
16
+
17
+ 1. Clone the repository: `git clone https://github.com/ChatXBT/chatxbt-web3-ai-assistant.git`
18
+ 2. Get a copy of the `\`.env`\` file from the project manager`
19
+ 3. Create a virtual environment: `python -m venv env`
20
+ 4. Activate the virtual environment: `source env/bin/activate`
21
+ 4. Install the dependencies: `pip install -r requirements.txt`
22
+ 5. Run the application: `chainlit run chatxbt-assistant.py -w`
23
+ 6. Open the application in your browser: `http://localhost:8000`
24
+
25
+ ## Development
26
+
27
+ The project is structured as follows:
28
+
29
+ 1. src/data_sources: `a list of data sources that can be used to retrieve data for the AI assistant.`
30
+ 2. src/databases: `a list of databases that can be used to store data for the AI assistant.`
31
+ 3. src/libs: `a list of libraries that can be used to extend the classes and functions servicing the AI assistant.`
32
+ 4. src/llms: `a list of language models powered libs that can be used to power the AI assistant.`
33
+ 5. src/search_services: `a list of search services that can be used to retrieve data for the AI assistant.`
34
+ 6. src/tools: `a list of tools that can be used to extend the functionality of the AI assistant.`
35
+
36
+ ## Guides
37
+
38
+ 1. Follow the development, structure and documentation patterns of the `src/tools/coin_data_toolkit.py` to build custom toolkits
39
+ 2. Follow the development, structure and documentation patterns of the `src/tools/coin_data_toolkit.py` to build classes
40
+ 3. Pay attention to the `constants` variables and `caching` decorators to optimize perfomance of class functions/methods across the project
41
+ 4. Create new classes in the appropriate folders to maintain an organized codebase and project
42
+ 5. After installing any new package run `` to update the dependency requirements list
43
+ 6. Expose RPC functions for SDKs that do not support python runtime. use [DeepKit](https://deepkit.io/documentation/rpc) and [BunJS](https://bun.sh/) if possible.
44
+
45
+ ## Deplopyment to producton
46
+
47
+ To be finalised and added
48
+
49
+ ## TODO
50
+
51
+ TODO: Add deployment instructions
52
+ TODO: Setup CI/CD pipelines for automatic deployment
53
+ TODO: Setup and integrate `LitLLM` instance for LLM service high availability
54
+ TODO: Add RPC class for remmote method calls to other chatxbt services written in other launguages such as `JS`, `TS` & `GO`
55
+ TODO: Write enough unit test to ensure class and function input and output correctness
ai_functions.py DELETED
@@ -1,60 +0,0 @@
1
- from pydantic import BaseModel, Field
2
- from typing import Dict, Optional, Type
3
-
4
- from data_sources.coin_gecko import CoinGecko
5
- from src.data_sources.cryptocompare import CryptoCompare
6
-
7
- from langchain.tools.base import BaseTool
8
-
9
- class CryptoCoinPrice(BaseModel):
10
- """Represents the prices of a coin in various currencies."""
11
- prices: Dict[str, float] = Field(..., description="Prices in various currencies")
12
-
13
- class CryptoCoinPriceData(BaseModel):
14
- """Encapsulates both CoinGecko and CryptoCompare price data."""
15
- coingecko_price: Dict[str, CryptoCoinPrice] = Field(..., description="CoinGecko prices for various coins")
16
- crypto_compare_price: Dict[str, CryptoCoinPrice] = Field(..., description="CryptoCompare prices for various coins")
17
-
18
- class PriceInput(BaseModel):
19
- coin_id: str = Field(..., description="The ID of the cryptocurrency coin to retrieve prices for")
20
- vs_currency: str = Field("usd", description="The currency to compare against")
21
-
22
- class CryptoCoinPriceOutput(BaseModel):
23
- price_data: CryptoCoinPriceData
24
-
25
- class CryptoCoinPriceTool(BaseTool):
26
- name = "CryptoCoinPriceTool"
27
- description = "Fetches price data for a given cryptocurrency coin from CoinGecko and CryptoCompare"
28
- args_schema: Type[BaseModel] = PriceInput
29
- return_direct: bool = True
30
-
31
- def __init__(self, id: Optional[str] = None):
32
- self.id = id
33
- self.coingecko = CoinGecko()
34
- self.crypto_compare = CryptoCompare()
35
-
36
- def _run(self, coin_id: str, vs_currency: str = "usd") -> CryptoCoinPriceData:
37
- coingecko_price_data = self.coingecko.get_coin_price(ids=[coin_id], vs_currencies=[vs_currency])
38
- crypto_compare_price_data = self.crypto_compare.get_coin_price(ids=[coin_id], vs_currencies=[vs_currency])
39
-
40
- coingecko_price = {}
41
- crypto_compare_price = {}
42
-
43
- if coin_id in coingecko_price_data:
44
- coingecko_price[coin_id] = CryptoCoinPrice(prices=coingecko_price_data[coin_id])
45
- else:
46
- print(f"Warning: CoinGecko data for {coin_id} not found.")
47
-
48
- if coin_id.upper() in crypto_compare_price_data:
49
- crypto_compare_price[coin_id] = CryptoCoinPrice(prices=crypto_compare_price_data[coin_id.upper()])
50
- else:
51
- print(f"Warning: CryptoCompare data for {coin_id} not found.")
52
-
53
- return CryptoCoinPriceData(
54
- coingecko_price=coingecko_price,
55
- crypto_compare_price=crypto_compare_price
56
- )
57
-
58
- def __call__(self, inputs: PriceInput) -> CryptoCoinPriceOutput:
59
- price_data = self._run(inputs.coin_id, inputs.vs_currency)
60
- return CryptoCoinPriceOutput(price_data=price_data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
chainlit.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Welcome to Chainlit! 🚀🤖
2
+
3
+ Hi there, Developer! 👋 We're excited to have you on board. Chainlit is a powerful tool designed to help you prototype, debug and share applications built on top of LLMs.
4
+
5
+ ## Useful Links 🔗
6
+
7
+ - **Documentation:** Get started with our comprehensive [Chainlit Documentation](https://docs.chainlit.io) 📚
8
+ - **Discord Community:** Join our friendly [Chainlit Discord](https://discord.gg/k73SQ3FyUh) to ask questions, share your projects, and connect with other developers! 💬
9
+
10
+ We can't wait to see what you create with Chainlit! Happy coding! 💻😊
11
+
12
+ ## Welcome screen
13
+
14
+ To modify the welcome screen, edit the `chainlit.md` file at the root of your project. If you do not want a welcome screen, just leave this file empty.
chat-app.py DELETED
@@ -1,55 +0,0 @@
1
- from dotenv import load_dotenv
2
-
3
- from langchain.chains import LLMMathChain
4
- from langchain.llms.openai import OpenAI
5
- from langchain.chat_models import ChatOpenAI
6
- from langchain.utilities.serpapi import SerpAPIWrapper
7
- from langchain.agents import initialize_agent, Tool, AgentExecutor
8
- import chainlit as cl
9
-
10
- from src.tools.crypto_coin_price_tool import CryptoCoinPriceTool
11
-
12
- load_dotenv()
13
-
14
- @cl.on_chat_start
15
- def start():
16
- llm = ChatOpenAI(temperature=0, streaming=True)
17
- llm1 = OpenAI(temperature=0, streaming=True)
18
- search = SerpAPIWrapper()
19
- get_crypto_coin_price = CryptoCoinPriceTool()
20
- llm_math_chain = LLMMathChain.from_llm(llm=llm, verbose=True)
21
-
22
- tools = [
23
- Tool(
24
- name="Search",
25
- func=search.run,
26
- description="useful for when you need to answer questions about current events. You should ask targeted questions",
27
- handle_tool_error=True,
28
- ),
29
- Tool(
30
- name="Calculator",
31
- func=llm_math_chain.run,
32
- description="useful for when you need to answer questions about math",
33
- handle_tool_error=True,
34
- ),
35
- Tool(
36
- name=get_crypto_coin_price.name,
37
- func=get_crypto_coin_price.run,
38
- description=get_crypto_coin_price.description,
39
- handle_tool_error=True,
40
- ),
41
- ]
42
- agent = initialize_agent(
43
- tools, llm1, agent="chat-zero-shot-react-description", verbose=True, handle_parsing_errors=True
44
- )
45
- cl.user_session.set("agent", agent)
46
-
47
-
48
- @cl.on_message
49
- async def main(message: cl.Message):
50
- agent = cl.user_session.get("agent") # type: AgentExecutor
51
- cb = cl.LangchainCallbackHandler(stream_final_answer=True)
52
-
53
- await cl.make_async(agent.run)(message.content, callbacks=[cb])
54
-
55
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
chatxbt-assistant.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ load_dotenv()
4
+
5
+ import chainlit as cl
6
+ from phi.assistant import Assistant
7
+ from phi.tools.duckduckgo import DuckDuckGo
8
+ from phi.llm.openai import OpenAIChat
9
+ from phi.tools.yfinance import YFinanceTools
10
+ from src.tools.coin_data_toolkit import CryptoDataTools
11
+
12
+
13
+ # assistant = Assistant(tools=[DuckDuckGo()], show_tool_calls=True)
14
+ # assistant.print_response("Whats happening in France?", markdown=True)
15
+
16
+ # f_assistant = Assistant(
17
+ # llm=OpenAIChat(model="gpt-4o"),
18
+ # tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True, company_news=True)],
19
+ # show_tool_calls=True,
20
+ # markdown=True,
21
+ # )
22
+ # f_assistant.print_response("What is the stock price of NVDA")
23
+ # f_assistant.print_response("Write a comparison between NVDA and AMD, use all tools available.")
24
+
25
+ @cl.on_chat_start
26
+ def start():
27
+ is_dev_mode = True if os.getenv("DEV_MODE") else False
28
+
29
+ # Initialize the assistant
30
+ cxbt_assistant = Assistant(
31
+ llm=OpenAIChat(model="gpt-4o"),
32
+ tools=[CryptoDataTools(), DuckDuckGo(), YFinanceTools(stock_price=True)],
33
+ show_tool_calls= is_dev_mode,
34
+ markdown=True,
35
+ )
36
+
37
+ # Set the assistant in the user session
38
+ cl.user_session.set("agent", cxbt_assistant)
39
+
40
+ @cl.on_message
41
+ async def main(message: cl.Message):
42
+ # Retrieve the assistant from the user session
43
+ agent = cl.user_session.get("agent")
44
+
45
+ # Process the user message using the assistant
46
+ # response = agent.run(message.content, stream=True)
47
+ response = ""
48
+ for delta in agent.run(message.content, stream=True):
49
+ response += delta
50
+
51
+ # Send the response back to the user
52
+ await cl.Message(content=response).send()
53
+
54
+ # Run the Chainlit application
55
+ if __name__ == "__main__":
56
+ cl.run()
sample.env ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ OPENAI_API_KEY=""
2
+
3
+ GROQ_API_KEY=""
4
+
5
+ LANGCHAIN_TRACING_V2=""
6
+ LANGCHAIN_ENDPOINT=""
7
+ LANGCHAIN_API_KEY=""
8
+
9
+ JINA_READER_API_KEY=""
10
+
11
+ EXA_API_KEY=""
12
+
13
+ SERPAPI_API_KEY=""
14
+
15
+ CRYPTOCOMPARE_API_KEY=""
16
+
17
+ COINGECKO_PRO_API_KEY=""
18
+ COINGECKO_DEMO_API_KEY=""
19
+
20
+ UPSTASH_REDIS_REST_URL=""
21
+ UPSTASH_REDIS_REST_TOKEN=""
22
+ UPSTASH_REDIS_HOST=""
23
+ UPSTASH_REDIS_PORT=""
24
+ UPSTASH_REDIS_PASSWORD=""
25
+ UPSTASH_REDIS_CONNECTION_STRING=""
26
+
27
+ LOGFIRE_TOKEN=""
28
+ LOG_LEVEL=""
src/data_sources/coin_gecko.py CHANGED
@@ -1,7 +1,7 @@
1
  import os
2
  from dotenv import load_dotenv
3
  from src.databases.redis import REDIS_CACHED
4
- from src.libs.constants import ONE_HOUR_IN_SECONDS, ONE_MONTH_IN_SECONDS
5
  from src.libs.logger import logger
6
  from coingecko import CoinGeckoProClient, CoinGeckoDemoClient
7
 
@@ -16,9 +16,9 @@ class CoinGecko:
16
  else:
17
  self.cgc = CoinGeckoDemoClient(api_key=os.getenv('COINGECKO_DEMO_API_KEY'))
18
 
19
- @redis_cache(ttl=ONE_HOUR_IN_SECONDS)
20
  @logger.instrument()
21
- def get_coin_price(self, ids: list, vs_currencies: list, cache_ttl: int = None) -> dict:
22
  # logger.debug(f"ids: {ids}")
23
  # logger.debug(f"vs_currencies: {vs_currencies}")
24
 
 
1
  import os
2
  from dotenv import load_dotenv
3
  from src.databases.redis import REDIS_CACHED
4
+ from src.libs.constants import ONE_HOUR_IN_SECONDS, ONE_MINUTE_IN_SECONDS, ONE_MONTH_IN_SECONDS
5
  from src.libs.logger import logger
6
  from coingecko import CoinGeckoProClient, CoinGeckoDemoClient
7
 
 
16
  else:
17
  self.cgc = CoinGeckoDemoClient(api_key=os.getenv('COINGECKO_DEMO_API_KEY'))
18
 
19
+ @redis_cache(ttl=ONE_MINUTE_IN_SECONDS)
20
  @logger.instrument()
21
+ def get_coin_price(self, ids: list[str], vs_currencies: list[str], cache_ttl: int = None) -> dict:
22
  # logger.debug(f"ids: {ids}")
23
  # logger.debug(f"vs_currencies: {vs_currencies}")
24
 
src/data_sources/cryptocompare.py CHANGED
@@ -38,7 +38,7 @@ class CryptoCompare:
38
 
39
  @redis_cache(ttl=ONE_MINUTE_IN_SECONDS)
40
  @logger.instrument()
41
- def get_coin_price(self, ids: list, vs_currencies: list, cache_ttl: int = None) -> dict:
42
 
43
  url = f"{self.CRYPTO_COMPARE_BASE_URL}data/pricemulti"
44
  # logger.debug(url)
@@ -59,5 +59,6 @@ class CryptoCompare:
59
  response.raise_for_status() # Raise an exception if the request was unsuccessful
60
  return response.json()
61
  except httpx.HTTPError as e:
62
- logger.debug(f"An error occurred while making the request: {e}")
 
63
  return None
 
38
 
39
  @redis_cache(ttl=ONE_MINUTE_IN_SECONDS)
40
  @logger.instrument()
41
+ def get_coin_price(self, ids: list[str], vs_currencies: list[str], cache_ttl: int = None) -> dict:
42
 
43
  url = f"{self.CRYPTO_COMPARE_BASE_URL}data/pricemulti"
44
  # logger.debug(url)
 
59
  response.raise_for_status() # Raise an exception if the request was unsuccessful
60
  return response.json()
61
  except httpx.HTTPError as e:
62
+ # logger.debug(f"An error occurred while making the request: {e}")
63
+ print(f"An error occurred while making the request: {e}")
64
  return None
src/databases/redis.py CHANGED
@@ -1,5 +1,5 @@
1
- import json
2
  import os
 
3
  from dotenv import load_dotenv
4
  from upstash_redis import Redis
5
  from src.libs.logger import logger
 
 
1
  import os
2
+ import json
3
  from dotenv import load_dotenv
4
  from upstash_redis import Redis
5
  from src.libs.logger import logger
src/libs/logger.py CHANGED
@@ -1,17 +1,17 @@
1
  import os
2
  from dotenv import load_dotenv
3
 
4
- import logfire
5
 
6
  load_dotenv()
7
 
8
- logfire.configure(
9
  token=os.getenv('LOGFIRE_TOKEN'),
10
- pydantic_plugin=logfire.PydanticPlugin(record='all'),
11
- console=logfire.ConsoleOptions(min_log_level= os.getenv('LOG_LEVEL'))
12
  )
13
- logfire.instrument_redis()
14
- logfire.instrument_httpx()
15
- logfire.instrument_requests()
16
 
17
- logger = logfire
 
1
  import os
2
  from dotenv import load_dotenv
3
 
4
+ import logfire as lf
5
 
6
  load_dotenv()
7
 
8
+ lf.configure(
9
  token=os.getenv('LOGFIRE_TOKEN'),
10
+ pydantic_plugin=lf.PydanticPlugin(record='all'),
11
+ console=lf.ConsoleOptions(min_log_level= os.getenv('LOG_LEVEL'))
12
  )
13
+ lf.instrument_redis()
14
+ lf.instrument_httpx()
15
+ lf.instrument_requests()
16
 
17
+ logger = lf
src/libs/redis.py DELETED
@@ -1,14 +0,0 @@
1
- keys = {
2
- "cryptocompare": {
3
- "top_exchanges": "top_exchanges",
4
- "all_exchanges": "all_exchanges",
5
- "top_assets": "top_assets",
6
- "all_assets": "all_assets",
7
- },
8
- "coingecko": {
9
- "top_exchanges": "top_exchanges",
10
- "all_exchanges": "all_exchanges",
11
- "top_assets": "top_assets",
12
- "all_assets": "all_assets",
13
- }
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/requirements.txt DELETED
@@ -1,8 +0,0 @@
1
- auto_mix_prep==0.2.0
2
- httpx==0.27.0
3
- logfire==0.42.0
4
- pyjsonq==1.0.2
5
- python-dotenv==1.0.1
6
- scrapegraphai==1.6.0
7
- ulid==1.1
8
- upstash_redis==1.1.0
 
 
 
 
 
 
 
 
 
src/tools/coin_data_toolkit.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ from phi.tools import Toolkit
4
+ from phi.utils.log import logger
5
+
6
+ from src.data_sources.coin_gecko import CoinGecko
7
+ from src.data_sources.cryptocompare import CryptoCompare
8
+
9
+ class CryptoDataTools(Toolkit):
10
+ def __init__(self):
11
+ super().__init__(name="crypto_data_tools")
12
+ self.register(self.get_coin_price)
13
+ self.coingecko = CoinGecko()
14
+ self.crypto_compare = CryptoCompare()
15
+
16
+ def get_coin_price(self, coin_id: str, vs_currency: str = "usd") -> str:
17
+ """
18
+ Fetches the price data for a given cryptocurrency coin from CoinGecko and CryptoCompare.
19
+
20
+ Args:
21
+ coin_id (str): The unique identifier for the cryptocurrency coin.
22
+ vs_currency (str, optional): The currency to which the coin price will be compared. Defaults to "usd".
23
+
24
+ Returns:
25
+ str: A JSON string containing the price data from CoinGecko and CryptoCompare for the specified coin.
26
+
27
+ Raises:
28
+ Exception: If an error occurs while fetching the price data.
29
+
30
+ Example:
31
+ >>> get_coin_price("bitcoin", "eur")
32
+ """
33
+ logger.info(f"Fetching price data for {coin_id} cryptocurrency coin from CoinGecko and CryptoCompare")
34
+ try:
35
+ coingecko_price = {}
36
+ crypto_compare_price = {}
37
+
38
+ coingecko_price_data = self.coingecko.get_coin_price(ids=[coin_id], vs_currencies=[vs_currency])
39
+ crypto_compare_price_data = self.crypto_compare.get_coin_price(ids=[coin_id], vs_currencies=[vs_currency])
40
+
41
+ logger.debug(f"coingecko_price_data: {coingecko_price_data}")
42
+ logger.debug(f"crypto_compare_price_data: {crypto_compare_price_data}")
43
+
44
+ if coin_id in coingecko_price_data:
45
+ coingecko_price[coin_id] = coingecko_price_data[coin_id]
46
+ else:
47
+ logger.warning(f"Warning: CoinGecko data for {coin_id} not found.")
48
+
49
+ if coin_id.upper() in crypto_compare_price_data:
50
+ crypto_compare_price[coin_id] = crypto_compare_price_data[coin_id.upper()]
51
+ else:
52
+ logger.warning(f"Warning: CryptoCompare data for {coin_id} not found.")
53
+
54
+ logger.debug(f"respons {coingecko_price}")
55
+ logger.debug(f"respons {crypto_compare_price}")
56
+
57
+ return f"{(coingecko_price, crypto_compare_price)}"
58
+ except Exception as e:
59
+ logger.warning(f"Failed to fetch price data for {coin_id}: {e}")
60
+ return f"Error: {e}"
src/tools/crypto_coin_price_tool.py DELETED
@@ -1,60 +0,0 @@
1
- from pydantic import BaseModel, Field
2
- from typing import Dict, Optional, Type
3
-
4
- from src.data_sources.coin_gecko import CoinGecko
5
- from src.data_sources.cryptocompare import CryptoCompare
6
-
7
- from langchain.tools.base import BaseTool
8
-
9
- class CryptoCoinPrice(BaseModel):
10
- """Represents the prices of a coin in various currencies."""
11
- prices: Dict[str, float] = Field(..., description="Prices in various currencies")
12
-
13
- class CryptoCoinPriceData(BaseModel):
14
- """Encapsulates both CoinGecko and CryptoCompare price data."""
15
- coingecko_price: Dict[str, CryptoCoinPrice] = Field(..., description="CoinGecko prices for various coins")
16
- crypto_compare_price: Dict[str, CryptoCoinPrice] = Field(..., description="CryptoCompare prices for various coins")
17
-
18
- class PriceInput(BaseModel):
19
- coin_id: str = Field(..., description="The ID of the cryptocurrency coin to retrieve prices for")
20
- vs_currency: str = Field("usd", description="The currency to compare against")
21
-
22
- class CryptoCoinPriceOutput(BaseModel):
23
- price_data: CryptoCoinPriceData
24
-
25
- class CryptoCoinPriceTool(BaseTool):
26
- name = "CryptoCoinPriceTool"
27
- description = "Fetches price data for a given cryptocurrency coin from CoinGecko and CryptoCompare"
28
- args_schema: Type[BaseModel] = PriceInput
29
- return_direct: bool = True
30
-
31
- def __init__(self, id: Optional[str] = None):
32
- self.id = id
33
- self.coingecko = CoinGecko()
34
- self.crypto_compare = CryptoCompare()
35
-
36
- def _run(self, coin_id: str, vs_currency: str = "usd") -> CryptoCoinPriceData:
37
- coingecko_price_data = self.coingecko.get_coin_price(ids=[coin_id], vs_currencies=[vs_currency])
38
- crypto_compare_price_data = self.crypto_compare.get_coin_price(ids=[coin_id], vs_currencies=[vs_currency])
39
-
40
- coingecko_price = {}
41
- crypto_compare_price = {}
42
-
43
- if coin_id in coingecko_price_data:
44
- coingecko_price[coin_id] = CryptoCoinPrice(prices=coingecko_price_data[coin_id])
45
- else:
46
- print(f"Warning: CoinGecko data for {coin_id} not found.")
47
-
48
- if coin_id.upper() in crypto_compare_price_data:
49
- crypto_compare_price[coin_id] = CryptoCoinPrice(prices=crypto_compare_price_data[coin_id.upper()])
50
- else:
51
- print(f"Warning: CryptoCompare data for {coin_id} not found.")
52
-
53
- return CryptoCoinPriceData(
54
- coingecko_price=coingecko_price,
55
- crypto_compare_price=crypto_compare_price
56
- )
57
-
58
- def __call__(self, inputs: PriceInput) -> CryptoCoinPriceOutput:
59
- price_data = self._run(inputs.coin_id, inputs.vs_currency)
60
- return CryptoCoinPriceOutput(price_data=price_data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/xbt-core.py DELETED
@@ -1,43 +0,0 @@
1
- import os
2
- import httpx
3
- import urllib.parse
4
- from typing import Self
5
- from pyjsonq import JsonQ
6
- from dotenv import load_dotenv
7
-
8
- load_dotenv()
9
-
10
- JINA_SEARCH_BASE_ENDPOINT = "r.jina.ai"
11
- JINA_READER_BASE_ENDPOINT = "s.jina.ai"
12
-
13
- class XBTCore:
14
- def __init__(self) -> None:
15
- self.value = 0
16
- self.JINA_SEARCH_BASE_ENDPOINT = "s.jina.ai"
17
- self.JINA_READER_BASE_ENDPOINT = "r.jina.ai"
18
-
19
- def search_web_with_jina(self, search_query: str=False) -> Self:
20
- url = self.JINA_SEARCH_BASE_ENDPOINT
21
- encoded_search_query = urllib.parse.quote(search_query)
22
-
23
- try:
24
- with httpx.Client() as client:
25
- response = client.get(f"{url}/{encoded_search_query}")
26
- response.raise_for_status()
27
- return response.json()
28
- except httpx.HTTPError as e:
29
- print(f"An error occurred: {e}")
30
- return None
31
-
32
- def read_website_with_jina(self, website_url: str=False) -> Self:
33
- url = self.JINA_READER_BASE_ENDPOINT
34
-
35
- try:
36
- with httpx.Client() as client:
37
- response = client.get(f"{url}/{website_url}")
38
- response.raise_for_status()
39
- return response.json()
40
- except httpx.HTTPError as e:
41
- print(f"An error occurred: {e}")
42
- return None
43
-