cgoncalves commited on
Commit
f4a94cb
·
1 Parent(s): 47694cc

Update space

Browse files
Files changed (5) hide show
  1. .gitignore +57 -0
  2. app.py +71 -51
  3. requirements.txt +15 -1
  4. retriever.py +47 -0
  5. tools.py +85 -0
.gitignore ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+
11
+ # Virtual environments
12
+ venv/
13
+ env/
14
+ .env
15
+ .venv/
16
+ ENV/
17
+
18
+ # IDE specific files
19
+ .idea/
20
+ .vscode/
21
+ *.swp
22
+ *.swo
23
+
24
+ # Jupyter Notebook
25
+ .ipynb_checkpoints
26
+
27
+ # Testing
28
+ .coverage
29
+ htmlcov/
30
+ .pytest_cache/
31
+ .tox/
32
+
33
+ # Logs
34
+ *.log
35
+
36
+ # Local development settings
37
+ .env.local
38
+ .env.development.local
39
+ .env.test.local
40
+ .env.production.local
41
+
42
+ # Dependencies
43
+ pip-log.txt
44
+ pip-delete-this-directory.txt
45
+
46
+ # Documentation
47
+ docs/_build/
48
+
49
+ # mypy
50
+ .mypy_cache/
51
+ .dmypy.json
52
+ dmypy.json
53
+
54
+ # chroma
55
+ chroma_db/
56
+
57
+
app.py CHANGED
@@ -1,64 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
- from huggingface_hub import InferenceClient
3
 
4
- """
5
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
6
- """
7
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
8
 
 
 
 
 
 
 
9
 
10
- def respond(
11
- message,
12
- history: list[tuple[str, str]],
13
- system_message,
14
- max_tokens,
15
- temperature,
16
- top_p,
17
- ):
18
- messages = [{"role": "system", "content": system_message}]
19
 
20
- for val in history:
21
- if val[0]:
22
- messages.append({"role": "user", "content": val[0]})
23
- if val[1]:
24
- messages.append({"role": "assistant", "content": val[1]})
25
 
26
- messages.append({"role": "user", "content": message})
 
 
27
 
28
- response = ""
29
 
30
- for message in client.chat_completion(
31
- messages,
32
- max_tokens=max_tokens,
33
- stream=True,
34
- temperature=temperature,
35
- top_p=top_p,
36
- ):
37
- token = message.choices[0].delta.content
38
 
39
- response += token
40
- yield response
 
 
 
41
 
 
 
 
 
 
 
42
 
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- demo = gr.ChatInterface(
47
- respond,
48
- additional_inputs=[
49
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
50
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
51
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
52
- gr.Slider(
53
- minimum=0.1,
54
- maximum=1.0,
55
- value=0.95,
56
- step=0.05,
57
- label="Top-p (nucleus sampling)",
58
- ),
59
- ],
60
- )
61
 
 
 
 
 
 
62
 
63
- if __name__ == "__main__":
64
- demo.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, SystemMessage
6
+ from langgraph.prebuilt import ToolNode
7
+ from langgraph.graph import START, StateGraph
8
+ from langgraph.prebuilt import tools_condition
9
+ from langgraph.checkpoint.memory import MemorySaver
10
+ from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace
11
+ from langfuse.callback import CallbackHandler
12
+ from retriever import guest_info_tool
13
+ from tools import search_tool, weather_info_tool, hub_stats_tool
14
+
15
  import gradio as gr
 
16
 
17
+ load_dotenv()
 
 
 
18
 
19
+ # Initialize Langfuse
20
+ langfuse_handler = CallbackHandler(
21
+ secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
22
+ public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
23
+ host=os.getenv("LANGFUSE_HOST"),
24
+ )
25
 
26
+ # Generate the chat interface, including the tools
27
+ llm = HuggingFaceEndpoint(
28
+ repo_id="Qwen/Qwen2.5-Coder-32B-Instruct",
29
+ huggingfacehub_api_token=os.getenv("HUGGINGFACEHUB_API_TOKEN")
30
+ )
31
+ chat = ChatHuggingFace(llm=llm, verbose=True)
32
+ tools = [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool]
33
+ chat_with_tools = chat.bind_tools(tools)
 
34
 
 
 
 
 
 
35
 
36
+ # Define the AgentState structure
37
+ class AgentState(TypedDict):
38
+ messages: Annotated[list[AnyMessage], add_messages]
39
 
 
40
 
41
+ def assistant(state: AgentState):
42
+ # Define the system prompt (this is not part of the conversation history)
43
+ system_message = SystemMessage(content="""You are Alfred, a helpful and sophisticated assistant.
 
 
 
 
 
44
 
45
+ Your capabilities:
46
+ - Answer questions using your knowledge
47
+ - Search the web for recent or factual information using the DuckDuckGoSearchResults tool
48
+ - Retrieve information about guests using the guest_info_tool
49
+ - Use weather_info_tool to give information about the weather
50
 
51
+ Guidelines:
52
+ - Be concise, polite and helpful
53
+ - When you don't know something, use the appropriate tool rather than guessing
54
+ - For guest information requests, always use the guest_info_tool first
55
+ - For factual or current information, use the search tool
56
+ - Present information in a clear, organized manner
57
 
58
+ Always think carefully about which tool is most appropriate for the user's request.
59
+ """)
60
+ # Call the agent with the system prompt and conversation history (state messages)
61
+ assistant_response = chat_with_tools.invoke([system_message] + state.get("messages"))
62
+ # Return the updated conversation state including the new assistant response
63
+ return {"messages": state.get("messages") + [assistant_response]}
64
+
65
+ # Build the graph
66
+ builder = StateGraph(AgentState)
67
+ builder.add_node("assistant", assistant)
68
+ builder.add_node("tools", ToolNode(tools))
69
+ builder.add_edge(START, "assistant")
70
+ builder.add_conditional_edges("assistant", tools_condition)
71
+ builder.add_edge("tools", "assistant")
72
+ checkpointer = MemorySaver()
73
+ alfred = builder.compile(checkpointer=checkpointer)
74
+ config = {"configurable": {"thread_id": "1"}, "callbacks": [langfuse_handler]}
 
75
 
76
+ # Gradio chat function
77
+ def chat_fn(message, history):
78
+ state = {"messages": [HumanMessage(content=message)]}
79
+ result = alfred.invoke(state, config)
80
+ return result["messages"][-1].content
81
 
82
+ # Launch Gradio interface
83
+ interface = gr.ChatInterface(fn=chat_fn,type="messages")
84
+ interface.launch()
requirements.txt CHANGED
@@ -1 +1,15 @@
1
- huggingface_hub==0.25.2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ huggingface_hub>=0.28.1
2
+ chromadb>=1.0.0
3
+ datasets>=3.5.0
4
+ duckduckgo-search>=2025.4.4
5
+ gradio>=5.23.3
6
+ langchain>=0.3.23
7
+ langchain-community>=0.3.21
8
+ langchain-huggingface>=0.1.2
9
+ langfuse>=2.60.2
10
+ langgraph>=0.3.25
11
+ langsmith>=0.3.24
12
+ pydantic>=2.11.2
13
+ python-dotenv>=1.1.0
14
+ rank-bm25>=0.2.2
15
+ sentence-transformers>=4.0.2
retriever.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datasets
2
+ import os
3
+
4
+ from langchain.docstore.document import Document
5
+ from langchain_core.tools import Tool
6
+ from langchain_community.vectorstores import Chroma
7
+ from langchain_huggingface import HuggingFaceEmbeddings
8
+
9
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
10
+
11
+ # Load the dataset
12
+ guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train")
13
+
14
+ # Convert dataset entries into Document objects
15
+ docs = [
16
+ Document(
17
+ page_content="\n".join([
18
+ f"Name: {guest['name']}",
19
+ f"Relation: {guest['relation']}",
20
+ f"Description: {guest['description']}",
21
+ f"Email: {guest['email']}"
22
+ ]),
23
+ metadata={"name": guest["name"]}
24
+ )
25
+ for guest in guest_dataset
26
+ ]
27
+
28
+ # Create embedding model
29
+ embeddings = HuggingFaceEmbeddings()
30
+
31
+ # Create Chroma vector store
32
+ vector_store = Chroma.from_documents(documents=docs, embedding=embeddings, persist_directory="./chroma_db")
33
+ retriever = vector_store.as_retriever(search_kwargs={"k": 3})
34
+
35
+ def extract_text(query: str) -> str:
36
+ """Retrieves detailed information about gala guests based on their name or relation."""
37
+ results = retriever.invoke(query)
38
+ if results:
39
+ return "\n\n".join([doc.page_content for doc in results])
40
+ else:
41
+ return "No matching guest information found."
42
+
43
+ guest_info_tool = Tool(
44
+ name="guest_info_retriever",
45
+ func=extract_text,
46
+ description="Retrieves detailed information about gala guests based on their name or relation."
47
+ )
tools.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import os
3
+
4
+ from huggingface_hub import list_models
5
+ from langchain_community.tools import DuckDuckGoSearchResults
6
+ from langchain.tools import Tool
7
+ from dotenv import load_dotenv
8
+
9
+ # Make sure environment variables are loaded
10
+ load_dotenv()
11
+
12
+
13
+ def get_weather_info(location: str) -> str:
14
+ """Fetches real weather information for a given location using WeatherAPI.com."""
15
+ api_key = os.getenv("WEATHERAPI_KEY")
16
+ if not api_key:
17
+ return "Error: WeatherAPI key not found. Please set the WEATHERAPI_KEY environment variable."
18
+
19
+ base_url = "http://api.weatherapi.com/v1/current.json"
20
+ params = {
21
+ "key": api_key,
22
+ "q": location,
23
+ "aqi": "no" # You can change this to "yes" if you want air quality info
24
+ }
25
+
26
+ try:
27
+ response = requests.get(base_url, params=params)
28
+ data = response.json()
29
+
30
+ if response.status_code == 200:
31
+ # Extract relevant information from the response
32
+ location_data = data.get("location", {})
33
+ current_data = data.get("current", {})
34
+
35
+ location_name = location_data.get("name", "Unknown")
36
+ region = location_data.get("region", "Unknown")
37
+ country = location_data.get("country", "Unknown")
38
+ temp_c = current_data.get("temp_c", "N/A")
39
+ feelslike_c = current_data.get("feelslike_c", "N/A")
40
+ condition_text = current_data.get("condition", {}).get("text", "N/A")
41
+ humidity = current_data.get("humidity", "N/A")
42
+ wind_kph = current_data.get("wind_kph", "N/A")
43
+
44
+ return (
45
+ f"Weather in {location_name}, {region}, {country}: {condition_text}, "
46
+ f"{temp_c}°C (feels like {feelslike_c}°C). Humidity: {humidity}%, Wind: {wind_kph} kph"
47
+ )
48
+ else:
49
+ error_message = data.get("error", {}).get("message", "Unknown error")
50
+ return f"Error fetching weather data: {error_message}"
51
+
52
+ except Exception as e:
53
+ return f"An error occurred while fetching weather data: {str(e)}"
54
+
55
+
56
+ # Initialize the tool
57
+ weather_info_tool = Tool(
58
+ name="get_weather_info",
59
+ func=get_weather_info,
60
+ description="Fetches real weather information for a given location. Provide the city name and optionally the country code (e.g., 'London' or 'London,UK')."
61
+ )
62
+
63
+
64
+ def get_hub_stats(author: str) -> str:
65
+ """Fetches the most downloaded model from a specific author on the Hugging Face Hub."""
66
+ try:
67
+ # List models from the specified author, sorted by downloads
68
+ models = list(list_models(author=author, sort="downloads", direction=-1, limit=1))
69
+
70
+ if models:
71
+ model = models[0]
72
+ return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads."
73
+ else:
74
+ return f"No models found for author {author}."
75
+ except Exception as e:
76
+ return f"Error fetching models for {author}: {str(e)}"
77
+
78
+ # Initialize the tool
79
+ hub_stats_tool = Tool(
80
+ name="get_hub_stats",
81
+ func=get_hub_stats,
82
+ description="Fetches the most downloaded model from a specific author on the Hugging Face Hub."
83
+ )
84
+
85
+ search_tool = DuckDuckGoSearchResults()