Akjava's picture
add info
2f90526
raw
history blame
6.57 kB
# Copyright 2024-2025 Akihito Miyazaki.
# This code is derived from the DuckDuckGoSearchTool class,
# originally part of the HuggingFace smolagents library.
# https://github.com/huggingface/smolagents
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import threading
from typing import Optional
from dotenv import load_dotenv
import gradio as gr
from smolagents import (
CodeAgent,
LiteLLMModel,
DuckDuckGoSearchTool,
)
from smolagents.agent_types import AgentText, AgentImage, AgentAudio
from smolagents.gradio_ui import pull_messages_from_step, handle_agent_output_types
from huggingface_hub import InferenceClient
from extra_search_tools import (
PrioritySearchTool,
BraveSearchTool,
GoogleCustomSearchTool,
)
def hf_chat(api_key, model, text):
client = InferenceClient(api_key=api_key)
messages = [
{
"role": "user",
"content": text,
}
]
stream = client.chat.completions.create(
model=model, messages=messages, max_tokens=6000, stream=False
)
return stream.choices[0].message.content
load_dotenv(override=True)
# login(os.getenv("HF_TOKEN"))
append_answer_lock = threading.Lock()
# without below chat will duplicate
custom_role_conversions = {"tool-call": "assistant", "tool-response": "user"}
model = LiteLLMModel(
"groq/llama3-8b-8192",
api_base="https://api.groq.com/openai/v1",
max_completion_tokens=500,
api_key=os.getenv("GROQ_API_KEY"), # Groq API
)
search_tool = PrioritySearchTool(
[
DuckDuckGoSearchTool(),
GoogleCustomSearchTool("YOUR_ENGINE_KEY"),
BraveSearchTool(),
],
"history.json",
)
WEB_TOOLS = [search_tool]
max_steps = 1
# Agent creation in a factory function
def create_agent():
print("create agent")
"""Creates a fresh agent instance for each session"""
return CodeAgent(
model=model,
tools=WEB_TOOLS,
max_steps=max_steps,
verbosity_level=1,
)
def stream_to_gradio(
agent,
task: str,
reset_agent_memory: bool = False,
additional_args: Optional[dict] = None,
):
"""Runs an agent with the given task and streams the messages from the agent as gradio ChatMessages."""
steps = 0
for step_log in agent.run(
task, stream=True, reset=reset_agent_memory, additional_args=additional_args
):
# I dont know the reason but call more steps
steps += 1
if steps <= max_steps:
for message in pull_messages_from_step(
step_log,
):
yield message
final_answer = step_log # Last log is the run's final_answer
final_answer = handle_agent_output_types(final_answer)
# print(final_answer)
if isinstance(final_answer, AgentText):
yield gr.ChatMessage(
role="assistant",
content=f"**Final answer:**\n{final_answer.to_string()}",
)
elif isinstance(final_answer, AgentImage):
yield gr.ChatMessage(
role="assistant",
content={"path": final_answer.to_string(), "mime_type": "image/png"},
)
elif isinstance(final_answer, AgentAudio):
yield gr.ChatMessage(
role="assistant",
content={"path": final_answer.to_string(), "mime_type": "audio/wav"},
)
else:
yield gr.ChatMessage(
role="assistant", content=f"**Final answer:** {str(final_answer)}"
)
class GradioUI:
"""A one-line interface to launch your agent in Gradio"""
def __init__(self, file_upload_folder: str | None = None):
self.file_upload_folder = file_upload_folder
if self.file_upload_folder is not None:
if not os.path.exists(file_upload_folder):
os.mkdir(file_upload_folder)
def interact_with_agent(self, prompt, messages, session_state):
# Get or create session-specific agent
if "agent" not in session_state:
session_state["agent"] = create_agent()
messages.append(gr.ChatMessage(role="user", content=prompt))
yield messages
# Use session's agent instance
for msg in stream_to_gradio(
session_state["agent"], task=prompt, reset_agent_memory=False
):
messages.append(msg)
pass
yield messages
yield messages
def launch(self, **kwargs):
with gr.Blocks(theme="ocean", fill_height=True) as demo:
gr.Markdown("""# Smolagents - ExtraSearchtools!
- [Google Custom Search](https://developers.google.com/custom-search/v1/overview) tool Free 100 per day
- [Brave Search](https://brave.com/search/api/) tool Free 2000 per month
- PrioritySearchTool - try duckduckgo fist and then use google
- PrioritySearchTool - json-save function
Built with [smolagents](https://github.com/huggingface/smolagents).This Demo only work duckduckgo if it's not rate-limited.Duplicate and set your own secret key
""")
# Add session state to store session-specific data
session_state = gr.State({}) # Initialize empty state for each session
chatbot = gr.Chatbot(
label="ExtraSearchtools",
type="messages",
avatar_images=(
None,
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/mascot_smol.png",
),
scale=1,
)
text_input = gr.Textbox(
lines=1, label="Your request", value="What is smolagents?"
)
text_input.submit(
self.interact_with_agent,
# Include session_state in function calls
[text_input, chatbot, gr.State({})],
[chatbot],
)
demo.launch(debug=True, share=True, **kwargs)
if __name__ == "__main__":
GradioUI().launch() # not support auto update restart by yourself :AttributeError: module '__main__' has no attribute 'demo'