sayed99 commited on
Commit
4826e54
·
1 Parent(s): 9570ac3

project transferred to Langgraph implementation. |

Browse files

Add .gitignore, enhance app.py with Azure OpenAI integration, update README for setup instructions, and modify requirements.txt for new dependencies

Files changed (7) hide show
  1. .gitignore +149 -0
  2. README.md +36 -1
  3. app.py +79 -24
  4. requirements.txt +7 -1
  5. retriever.py +80 -26
  6. test_tavily.py +182 -0
  7. tools.py +113 -50
.gitignore ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Environment variables
2
+ .env
3
+
4
+ # Python
5
+ # Byte-compiled / optimized / DLL files
6
+ __pycache__/
7
+ *.py[cod]
8
+ *$py.class
9
+
10
+ # C extensions
11
+ *.so
12
+
13
+ # Distribution / packaging
14
+ .Python
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ lib/
22
+ lib64/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ wheels/
27
+ pip-wheel-metadata/
28
+ share/python-wheels/
29
+ *.egg-info/
30
+ .installed.cfg
31
+ *.egg
32
+ MANIFEST
33
+
34
+ # PyInstaller
35
+ # Usually these files are written by a python script from a template
36
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
37
+ *.manifest
38
+ *.spec
39
+
40
+ # Installer logs
41
+ pip-log.txt
42
+ pip-delete-this-directory.txt
43
+
44
+ # Unit test / coverage reports
45
+ htmlcov/
46
+ .tox/
47
+ .nox/
48
+ .coverage
49
+ .coverage.*
50
+ .cache
51
+ nosetests.xml
52
+ coverage.xml
53
+ *.cover
54
+ *.py,cover
55
+ .hypothesis/
56
+ .pytest_cache/
57
+
58
+ # Translations
59
+ *.mo
60
+ *.pot
61
+
62
+ # Django stuff:
63
+ *.log
64
+ local_settings.py
65
+ db.sqlite3
66
+ db.sqlite3-journal
67
+
68
+ # Flask stuff:
69
+ instance/
70
+ .webassets-cache
71
+
72
+ # Scrapy stuff:
73
+ .scrapy
74
+
75
+ # Sphinx documentation
76
+ docs/_build/
77
+
78
+ # PyBuilder
79
+ target/
80
+
81
+ # Jupyter Notebook
82
+ .ipynb_checkpoints
83
+
84
+ # IPython
85
+ profile_default/
86
+ ipython_config.py
87
+
88
+ # pyenv
89
+ .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ #Pipfile.lock
97
+
98
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
99
+ __pypackages__/
100
+
101
+ # Celery stuff
102
+ celerybeat-schedule
103
+ celerybeat.pid
104
+
105
+ # SageMath parsed files
106
+ *.sage.py
107
+
108
+ # Environments
109
+ .env
110
+ .venv
111
+ env/
112
+ venv/
113
+ ENV/
114
+ env.bak/
115
+ venv.bak/
116
+
117
+ # Spyder project settings
118
+ .spyderproject
119
+ .spyproject
120
+
121
+ # Rope project settings
122
+ .ropeproject
123
+
124
+ # mkdocs documentation
125
+ /site
126
+
127
+ # mypy
128
+ .mypy_cache/
129
+ .dmypy.json
130
+ dmypy.json
131
+
132
+ # Pyre type checker
133
+ .pyre/
134
+
135
+ # IDE
136
+ .vscode/
137
+ .idea/
138
+ *.swp
139
+ *.swo
140
+ *~
141
+
142
+ # OS
143
+ .DS_Store
144
+ .DS_Store?
145
+ ._*
146
+ .Spotlight-V100
147
+ .Trashes
148
+ ehthumbs.db
149
+ Thumbs.db
README.md CHANGED
@@ -10,4 +10,39 @@ pinned: false
10
  license: apache-2.0
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  license: apache-2.0
11
  ---
12
 
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
14
+
15
+ # Agentic RAG with LangGraph
16
+
17
+ A simple agentic RAG system using LangGraph with Azure OpenAI.
18
+
19
+ ## Setup
20
+
21
+ 1. **Install dependencies:**
22
+
23
+ ```bash
24
+ pip install -r requirements.txt
25
+ ```
26
+
27
+ 2. **Create `.env` file in the project root:**
28
+
29
+ ```
30
+ AZURE_OPENAI_ENDPOINT=your_azure_endpoint
31
+ AZURE_OPENAI_API_KEY=your_api_key
32
+ AZURE_OPENAI_DEPLOYMENT_NAME=your_deployment_name
33
+ AZURE_OPENAI_API_VERSION=2024-02-01
34
+ ```
35
+
36
+ ## Run
37
+
38
+ ```bash
39
+ python app.py
40
+ ```
41
+
42
+ The agent will automatically query for "Lady Ada Lovelace" and show the response.
43
+
44
+ ## Tools Available
45
+
46
+ - **Guest Info**: Retrieves guest information from the dataset
47
+ - **Weather Info**: Provides dummy weather data
48
+ - **Hub Stats**: Gets Hugging Face model statistics
app.py CHANGED
@@ -1,33 +1,88 @@
1
- import gradio as gr
2
- import random
3
- from smolagents import GradioUI, CodeAgent, HfApiModel
 
 
 
 
 
 
 
 
4
 
5
- # Import our custom tools from their modules
6
- from tools import DuckDuckGoSearchTool, WeatherInfoTool, HubStatsTool
7
- from retriever import load_guest_dataset
8
 
9
- # Initialize the Hugging Face model
10
- model = HfApiModel()
11
 
12
- # Initialize the web search tool
13
- search_tool = DuckDuckGoSearchTool()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- # Initialize the weather tool
16
- weather_info_tool = WeatherInfoTool()
17
 
18
- # Initialize the Hub stats tool
19
- hub_stats_tool = HubStatsTool()
20
 
21
- # Load the guest dataset and initialize the guest info tool
22
- guest_info_tool = load_guest_dataset()
 
23
 
24
- # Create Alfred with all the tools
25
- alfred = CodeAgent(
26
- tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool],
27
- model=model,
28
- add_base_tools=True, # Add any additional base tools
29
- planning_interval=3 # Enable planning every 3 steps
 
30
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- if __name__ == "__main__":
33
- GradioUI(alfred).launch()
 
 
 
 
1
+ import os
2
+ from typing import TypedDict, Annotated
3
+ from dotenv import load_dotenv
4
+ from langgraph.graph.message import add_messages
5
+ from langchain_core.messages import AnyMessage, HumanMessage, AIMessage
6
+ from langgraph.prebuilt import ToolNode
7
+ from langgraph.graph import START, StateGraph
8
+ from langgraph.prebuilt import tools_condition
9
+ from langchain_openai import AzureChatOpenAI
10
+ from retriever import guest_info_tool
11
+ from tools import weather_info_tool, hub_stats_tool, news_search_tool
12
 
13
+ load_dotenv()
 
 
14
 
 
 
15
 
16
+ chat = AzureChatOpenAI(
17
+ azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
18
+ api_key=os.getenv("AZURE_OPENAI_API_KEY"),
19
+ deployment_name=os.getenv("DEPLOYMENT_NAME"),
20
+ openai_api_version=os.getenv("OPENAI_API_VERSION"),
21
+ temperature=0.75,
22
+ streaming=True,
23
+ verbose=True
24
+ )
25
+
26
+ tools = [guest_info_tool, weather_info_tool, hub_stats_tool, news_search_tool]
27
+ chat_with_tools = chat.bind_tools(tools)
28
+
29
+
30
+ class AgentState(TypedDict):
31
+ messages: Annotated[list[AnyMessage], add_messages]
32
+
33
+
34
+ def assistant(state: AgentState):
35
+ return {
36
+ "messages": [chat_with_tools.invoke(state["messages"])],
37
+ }
38
 
 
 
39
 
40
+ # The graph
41
+ builder = StateGraph(AgentState)
42
 
43
+ # Define nodes: these do the work
44
+ builder.add_node("assistant", assistant)
45
+ builder.add_node("tools", ToolNode(tools))
46
 
47
+ # Define edges: these determine how the control flow moves
48
+ builder.add_edge(START, "assistant")
49
+ builder.add_conditional_edges(
50
+ "assistant",
51
+ # If the latest message requires a tool, route to tools
52
+ # Otherwise, provide a direct response
53
+ tools_condition,
54
  )
55
+ builder.add_edge("tools", "assistant")
56
+
57
+ # Compile with debug mode for verbosity
58
+ alfred = builder.compile(debug=True)
59
+
60
+ messages = [HumanMessage(
61
+ content="One of our guests is from Qwen. What can you tell me about their most recent popular AI model(search about it )?")]
62
+
63
+ print("🔍 Starting Agent Execution...")
64
+ print("="*50)
65
+
66
+ # Use stream instead of invoke to see step-by-step execution
67
+ final_messages = None
68
+ for step in alfred.stream({"messages": messages}):
69
+ print(f"📍 Current Step: {list(step.keys())}")
70
+ for node_name, node_output in step.items():
71
+ print(f"🔧 Node '{node_name}' output:")
72
+ if 'messages' in node_output:
73
+ latest_message = node_output['messages'][-1]
74
+ # Keep track of final messages
75
+ final_messages = node_output['messages']
76
+ print(f" Type: {type(latest_message).__name__}")
77
+ if hasattr(latest_message, 'content'):
78
+ print(f" Content: {latest_message.content[:200]}...")
79
+ if hasattr(latest_message, 'tool_calls') and latest_message.tool_calls:
80
+ print(f" Tool Calls: {latest_message.tool_calls}")
81
+ print("-" * 30)
82
+
83
 
84
+ print("\n"*3)
85
+ print("="*50)
86
+ print("🎩 Alfred's Final Response:")
87
+ if final_messages:
88
+ print(final_messages[-1].content)
requirements.txt CHANGED
@@ -2,4 +2,10 @@ datasets
2
  smolagents
3
  langchain-community
4
  rank_bm25
5
- duckduckgo-search
 
 
 
 
 
 
 
2
  smolagents
3
  langchain-community
4
  rank_bm25
5
+ duckduckgo-search
6
+ python-dotenv
7
+ langchain
8
+ langchain-openai
9
+ langgraph
10
+ huggingface_hub
11
+ langchain-tavily
retriever.py CHANGED
@@ -1,36 +1,30 @@
1
- from smolagents import Tool
2
  from langchain_community.retrievers import BM25Retriever
3
  from langchain.docstore.document import Document
 
4
  import datasets
 
 
 
5
 
 
6
 
7
- class GuestInfoRetrieverTool(Tool):
8
- name = "guest_info_retriever"
9
- description = "Retrieves detailed information about gala guests based on their name or relation."
10
- inputs = {
11
- "query": {
12
- "type": "string",
13
- "description": "The name or relation of the guest you want information about."
14
- }
15
- }
16
- output_type = "string"
17
-
18
- def __init__(self, docs):
19
- self.is_initialized = False
20
- self.retriever = BM25Retriever.from_documents(docs)
21
-
22
-
23
- def forward(self, query: str):
24
- results = self.retriever.get_relevant_documents(query)
25
- if results:
26
- return "\n\n".join([doc.page_content for doc in results[:3]])
27
- else:
28
- return "No matching guest information found."
29
 
30
 
31
  def load_guest_dataset():
32
  # Load the dataset
33
- guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train")
 
34
 
35
  # Convert dataset entries into Document objects
36
  docs = [
@@ -46,8 +40,68 @@ def load_guest_dataset():
46
  for guest in guest_dataset
47
  ]
48
 
49
- # Return the tool
50
- return GuestInfoRetrieverTool(docs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
 
 
 
52
 
53
 
 
 
 
 
 
 
1
+ from langchain.tools import Tool
2
  from langchain_community.retrievers import BM25Retriever
3
  from langchain.docstore.document import Document
4
+ from langchain_core.messages import HumanMessage
5
  import datasets
6
+ from langchain_openai import AzureChatOpenAI
7
+ import os
8
+ from dotenv import load_dotenv
9
 
10
+ load_dotenv()
11
 
12
+ # Create LLM instance once
13
+ conversation_llm = AzureChatOpenAI(
14
+ azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
15
+ api_key=os.getenv("AZURE_OPENAI_API_KEY"),
16
+ deployment_name=os.getenv("DEPLOYMENT_NAME"),
17
+ openai_api_version=os.getenv("OPENAI_API_VERSION"),
18
+ temperature=0.75,
19
+ streaming=False,
20
+ verbose=False
21
+ )
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
 
24
  def load_guest_dataset():
25
  # Load the dataset
26
+ guest_dataset = datasets.load_dataset(
27
+ "agents-course/unit3-invitees", split="train")
28
 
29
  # Convert dataset entries into Document objects
30
  docs = [
 
40
  for guest in guest_dataset
41
  ]
42
 
43
+ return docs
44
+
45
+
46
+ docs = load_guest_dataset()
47
+ bm25_retriever = BM25Retriever.from_documents(docs)
48
+
49
+
50
+ def generate_conversation_starter(description: str) -> str:
51
+ """Generate a conversation starter based on guest description"""
52
+ try:
53
+ generate_prompt = (
54
+ f"Generate a very simple and short conversation starter from the description of the person.\n\n"
55
+ f"For example:\n"
56
+ f"Description: Rear Admiral Grace Hopper was a trailblazer in computer programming and helped invent the first compiler. "
57
+ f"She's passionate about teaching and loves telling stories about debugging.\n\n"
58
+ f"Conversation Starter: Ask her about the time she found a real bug in a computer — she loves that story!\n\n"
59
+ f"Description: {description}\n\n"
60
+ f"Conversation Starter:"
61
+ )
62
+
63
+ response = conversation_llm.invoke(
64
+ [HumanMessage(content=generate_prompt)])
65
+ return response.content.strip()
66
+ except Exception:
67
+ return "Ask them about their background and interests!"
68
+
69
+
70
+ def retrieve_info_from_name(query: str) -> str:
71
+ """Retrieves detailed information about gala guests based on their name or relation."""
72
+ results = bm25_retriever.invoke(query)
73
+ if results:
74
+ guest_info_with_starters = []
75
+
76
+ for i, doc in enumerate(results[:3], 1):
77
+ guest_info = doc.page_content
78
+
79
+ # Extract description from the content
80
+ lines = guest_info.split('\n')
81
+ description = ""
82
+ for line in lines:
83
+ if line.startswith("Description:"):
84
+ description = line.replace("Description:", "").strip()
85
+ break
86
+
87
+ # Add guest info
88
+ result_text = f"Guest {i}:\n{guest_info}"
89
+
90
+ # Add conversation starter if description exists
91
+ if description:
92
+ conversation_starter = generate_conversation_starter(
93
+ description)
94
+ result_text += f"\n💬 Conversation Starter: {conversation_starter}"
95
+
96
+ guest_info_with_starters.append(result_text)
97
 
98
+ return "\n\n" + "="*50 + "\n\n".join(guest_info_with_starters)
99
+ else:
100
+ return "No matching guest information found."
101
 
102
 
103
+ guest_info_tool = Tool(
104
+ name="guest_info_retriever",
105
+ func=retrieve_info_from_name,
106
+ description="Retrieves detailed information about gala guests based on their name or relation, including conversation starters."
107
+ )
test_tavily.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ from langchain_tavily import TavilySearch
4
+
5
+ # Load environment variables
6
+ load_dotenv()
7
+
8
+
9
+ def test_tavily_search():
10
+ """Test the Tavily search functionality independently"""
11
+
12
+ print("🔍 Testing Tavily Search Tool...")
13
+ print("="*50)
14
+
15
+ # Check if API key is available
16
+ api_key = os.getenv("TAVILY_API_KEY")
17
+ if not api_key:
18
+ print("❌ Error: TAVILY_API_KEY not found in environment variables")
19
+ print("Please add TAVILY_API_KEY to your .env file")
20
+ return
21
+
22
+ print(f"✅ API Key found: {api_key[:10]}...{api_key[-4:]}")
23
+
24
+ try:
25
+ # Initialize Tavily search
26
+ print("\n🚀 Initializing Tavily search...")
27
+ tavily_search = TavilySearch(
28
+ api_key=api_key,
29
+ max_results=2,
30
+ topic="general",
31
+ search_depth="basic",
32
+ include_answer=True,
33
+ include_raw_content=False,
34
+ include_images=False
35
+ )
36
+ print("✅ Tavily search initialized successfully")
37
+
38
+ # Test search query
39
+ test_query = "latest portugal won"
40
+ print(f"\n🔎 Searching for: '{test_query}'")
41
+
42
+ # Perform the search
43
+ results = tavily_search.invoke({"query": test_query})
44
+
45
+ print(f"\n📊 Results type: {type(results)}")
46
+ print(
47
+ f"📊 Results length: {len(results) if hasattr(results, '__len__') else 'N/A'}")
48
+
49
+ # Display results
50
+ print("\n📰 Raw Results:")
51
+ print("-" * 30)
52
+ print(results)
53
+ print("-" * 30)
54
+
55
+ # Process and format results
56
+ if isinstance(results, list) and results:
57
+ print(f"\n✅ Found {len(results)} results")
58
+ formatted_news = f"📰 Latest News about '{test_query}':\n\n"
59
+
60
+ for i, result in enumerate(results, 1):
61
+ print(f"\n🔍 Processing result {i}:")
62
+ print(f" Type: {type(result)}")
63
+
64
+ if isinstance(result, dict):
65
+ print(f" Keys: {list(result.keys())}")
66
+ title = result.get('title', 'No title')
67
+ content = result.get('content', 'No content available')
68
+ url = result.get('url', 'No URL')
69
+
70
+ formatted_news += f"{i}. **{title}**\n"
71
+ formatted_news += f" Summary: {content[:200]}...\n"
72
+ formatted_news += f" Source: {url}\n\n"
73
+ else:
74
+ # Handle case where result is a string
75
+ formatted_news += f"{i}. {str(result)[:300]}...\n\n"
76
+
77
+ print(f"\n📝 Formatted Output:")
78
+ print("="*50)
79
+ print(formatted_news)
80
+ print("="*50)
81
+
82
+ else:
83
+ print(f"❌ No results found or unexpected result format")
84
+ print(f"Results: {results}")
85
+
86
+ except Exception as e:
87
+ print(f"❌ Error during search: {e}")
88
+ print(f"Error type: {type(e)}")
89
+ import traceback
90
+ print(f"Full traceback:\n{traceback.format_exc()}")
91
+
92
+
93
+ def test_tavily_raw():
94
+ """Test the raw Tavily search functionality"""
95
+
96
+ print("🔍 Testing Raw Tavily Search...")
97
+ print("="*50)
98
+
99
+ # Check if API key is available
100
+ api_key = os.getenv("TAVILY_API_KEY")
101
+ if not api_key:
102
+ print("❌ Error: TAVILY_API_KEY not found in environment variables")
103
+ return False
104
+
105
+ try:
106
+ # Initialize Tavily search
107
+ tavily_search = TavilySearch(
108
+ api_key=api_key,
109
+ max_results=2,
110
+ topic="general",
111
+ search_depth="basic",
112
+ include_answer=True,
113
+ include_raw_content=False,
114
+ include_images=False
115
+ )
116
+
117
+ # Test search query
118
+ test_query = "latest portugal won"
119
+ print(f"🔎 Searching for: '{test_query}'")
120
+
121
+ # Perform the search
122
+ results = tavily_search.invoke({"query": test_query})
123
+
124
+ print(f"✅ Raw search successful!")
125
+ print(f"📊 Results type: {type(results)}")
126
+ if isinstance(results, dict) and 'results' in results:
127
+ print(f"📊 Number of results: {len(results['results'])}")
128
+ return True
129
+ return False
130
+
131
+ except Exception as e:
132
+ print(f"❌ Raw search failed: {e}")
133
+ return False
134
+
135
+
136
+ def test_tools_function():
137
+ """Test our get_latest_news function from tools.py"""
138
+
139
+ print("\n🔧 Testing get_latest_news Function...")
140
+ print("="*50)
141
+
142
+ try:
143
+ # Import our function
144
+ from tools import get_latest_news
145
+
146
+ # Test the function
147
+ test_query = "portugal won"
148
+ print(f"🔎 Testing with query: '{test_query}'")
149
+
150
+ result = get_latest_news(test_query)
151
+
152
+ print("✅ Function executed successfully!")
153
+ print("\n📰 Function Output:")
154
+ print("-" * 50)
155
+ print(result)
156
+ print("-" * 50)
157
+
158
+ return True
159
+
160
+ except Exception as e:
161
+ print(f"❌ Function test failed: {e}")
162
+ import traceback
163
+ print(f"Full traceback:\n{traceback.format_exc()}")
164
+ return False
165
+
166
+
167
+ if __name__ == "__main__":
168
+ print("🧪 Running Tavily Tests...\n")
169
+
170
+ # Test 1: Raw Tavily
171
+ raw_success = test_tavily_raw()
172
+
173
+ # Test 2: Our function
174
+ if raw_success:
175
+ function_success = test_tools_function()
176
+
177
+ if function_success:
178
+ print("\n🎉 All tests passed! The news search tool is working correctly.")
179
+ else:
180
+ print("\n⚠️ Raw search works but our function has issues.")
181
+ else:
182
+ print("\n❌ Raw search failed - check your API key and connection.")
tools.py CHANGED
@@ -1,56 +1,119 @@
1
- from smolagents import DuckDuckGoSearchTool
2
- from smolagents import Tool
3
  import random
 
4
  from huggingface_hub import list_models
 
 
 
 
 
 
5
 
6
 
7
  # Initialize the DuckDuckGo search tool
8
- #search_tool = DuckDuckGoSearchTool()
9
-
10
-
11
- class WeatherInfoTool(Tool):
12
- name = "weather_info"
13
- description = "Fetches dummy weather information for a given location."
14
- inputs = {
15
- "location": {
16
- "type": "string",
17
- "description": "The location to get weather information for."
18
- }
19
- }
20
- output_type = "string"
21
-
22
- def forward(self, location: str):
23
- # Dummy weather data
24
- weather_conditions = [
25
- {"condition": "Rainy", "temp_c": 15},
26
- {"condition": "Clear", "temp_c": 25},
27
- {"condition": "Windy", "temp_c": 20}
28
- ]
29
- # Randomly select a weather condition
30
- data = random.choice(weather_conditions)
31
- return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C"
32
-
33
- class HubStatsTool(Tool):
34
- name = "hub_stats"
35
- description = "Fetches the most downloaded model from a specific author on the Hugging Face Hub."
36
- inputs = {
37
- "author": {
38
- "type": "string",
39
- "description": "The username of the model author/organization to find models from."
40
- }
41
- }
42
- output_type = "string"
43
-
44
- def forward(self, author: str):
45
- try:
46
- # List models from the specified author, sorted by downloads
47
- models = list(list_models(author=author, sort="downloads", direction=-1, limit=1))
48
-
49
- if models:
50
- model = models[0]
51
- return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads."
52
- else:
53
- return f"No models found for author {author}."
54
- except Exception as e:
55
- return f"Error fetching models for {author}: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
 
 
1
+ from langchain.tools import Tool
 
2
  import random
3
+ import os
4
  from huggingface_hub import list_models
5
+ # from langchain_tavily import TavilySearch
6
+ from langchain_community.tools import DuckDuckGoSearchRun
7
+
8
+ from dotenv import load_dotenv
9
+
10
+ load_dotenv()
11
 
12
 
13
  # Initialize the DuckDuckGo search tool
14
+ search_tool = DuckDuckGoSearchRun()
15
+
16
+
17
+
18
+ def get_weather_info(location: str) -> str:
19
+ """Fetches dummy weather information for a given location."""
20
+ # Dummy weather data
21
+ weather_conditions = [
22
+ {"condition": "Rainy", "temp_c": 15},
23
+ {"condition": "Clear", "temp_c": 25},
24
+ {"condition": "Windy", "temp_c": 20},
25
+ ]
26
+ # Randomly select a weather condition
27
+ data = random.choice(weather_conditions)
28
+ return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C"
29
+
30
+
31
+ def get_hub_stats(author: str) -> str:
32
+ """Fetches the most downloaded model from a specific author on the Hugging Face Hub."""
33
+ try:
34
+ # List models from the specified author, sorted by downloads
35
+ models = list(list_models(
36
+ author=author, sort="downloads", direction=-1, limit=1))
37
+
38
+ if models:
39
+ model = models[0]
40
+ return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads."
41
+ else:
42
+ return f"No models found for author {author}."
43
+ except Exception as e:
44
+ return f"Error fetching models for {author}: {str(e)}"
45
+
46
+
47
+ # def get_latest_news(topic: str) -> str:
48
+ # """Fetches the latest news about a specific topic using Tavily search."""
49
+ # try:
50
+ # # Initialize Tavily search with API key from environment
51
+ # tavily_search = TavilySearch(
52
+ # api_key=os.getenv("TAVILY_API_KEY"),
53
+ # max_results=2,
54
+ # topic="general",
55
+ # search_depth="basic",
56
+ # include_answer=True,
57
+ # include_raw_content=False,
58
+ # include_images=False
59
+ # )
60
+
61
+ # # Search for news about the topic
62
+ # response = tavily_search.invoke(
63
+ # {"query": f"latest news about {topic}"})
64
+
65
+ # # Handle the correct Tavily response format
66
+ # if isinstance(response, dict) and 'results' in response:
67
+ # results = response['results']
68
+ # answer = response.get('answer', '')
69
+
70
+ # if results:
71
+ # # Format the results nicely
72
+ # formatted_news = f"📰 Latest News about '{topic}':\n\n"
73
+
74
+ # # Add AI-generated answer if available
75
+ # if answer:
76
+ # formatted_news += f"🤖 **Quick Summary**: {answer}\n\n"
77
+
78
+ # # Add detailed results
79
+ # formatted_news += "📋 **Detailed Results**:\n\n"
80
+ # for i, result in enumerate(results, 1):
81
+ # title = result.get('title', 'No title')
82
+ # content = result.get('content', 'No content available')
83
+ # url = result.get('url', 'No URL')
84
+ # score = result.get('score', 0)
85
+
86
+ # formatted_news += f"{i}. **{title}**\n"
87
+ # formatted_news += f" 📄 Summary: {content}\n"
88
+ # formatted_news += f" 🔗 Source: {url}\n"
89
+ # formatted_news += f" ⭐ Relevance: {score:.2f}\n\n"
90
+
91
+ # return formatted_news
92
+ # else:
93
+ # return f"No recent news found about '{topic}'. Please try a different search term."
94
+ # else:
95
+ # return f"Unexpected response format from search. Raw response: {str(response)[:500]}..."
96
+
97
+ # except Exception as e:
98
+ # return f"Error fetching news about '{topic}': {str(e)}. Please check your Tavily API key and try again."
99
+
100
+
101
+ weather_info_tool = Tool(
102
+ name="weather_info",
103
+ func=get_weather_info,
104
+ description="Fetches dummy weather information for a given location."
105
+ )
106
+
107
+ hub_stats_tool = Tool(
108
+ name="hub_stats",
109
+ func=get_hub_stats,
110
+ description="Fetches the most downloaded model from a specific author on the Hugging Face Hub."
111
+ )
112
+
113
+ # news_search_tool = Tool(
114
+ # name="news_search",
115
+ # func=get_latest_news,
116
+ # description="Fetches the latest news about a specific topic using Tavily search. Provide a topic or keyword to search for recent news articles."
117
+ # )
118
 
119
+ news_search_tool = search_tool