Spaces:
Running
Running
Second
Browse files- Dockerfile +0 -72
- __pycache__/run.cpython-312.pyc +0 -0
- app.py +89 -103
- requirements.txt +0 -2
- run.py +106 -283
- start.sh +0 -8
Dockerfile
DELETED
@@ -1,72 +0,0 @@
|
|
1 |
-
# Use a slim Python image for a smaller, faster build
|
2 |
-
FROM python:3.12-slim
|
3 |
-
|
4 |
-
# Set environment variables early (improves caching)
|
5 |
-
ENV SEARXNG_URL="https://search.endorisk.nl" \
|
6 |
-
SEARXNG_USERNAME="user" \
|
7 |
-
SEARXNG_PASSWORD="password" \
|
8 |
-
PATH="/home/user/.local/bin:$PATH"
|
9 |
-
|
10 |
-
# 1) Install system dependencies
|
11 |
-
RUN apt-get update -y && \
|
12 |
-
apt-get install -y --no-install-recommends \
|
13 |
-
git \
|
14 |
-
ffmpeg \
|
15 |
-
wget \
|
16 |
-
curl \
|
17 |
-
build-essential \
|
18 |
-
tmux && \
|
19 |
-
rm -rf /var/lib/apt/lists/*
|
20 |
-
|
21 |
-
# 2) Install Node.js (required for MCP server)
|
22 |
-
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
|
23 |
-
apt-get install -y --no-install-recommends nodejs && \
|
24 |
-
rm -rf /var/lib/apt/lists/*
|
25 |
-
|
26 |
-
# 3) Create a non-root user (uid 1000 is typical in Spaces)
|
27 |
-
RUN useradd -m -u 1000 user
|
28 |
-
|
29 |
-
WORKDIR /app
|
30 |
-
|
31 |
-
# 4) Clone the repositories
|
32 |
-
RUN git clone https://github.com/CultriX-Github/smolagents.git && \
|
33 |
-
git clone https://github.com/ihor-sokoliuk/mcp-searxng.git
|
34 |
-
|
35 |
-
# 5) Build the MCP server: install dependencies and build assets
|
36 |
-
WORKDIR /app/mcp-searxng
|
37 |
-
RUN echo "SEARXNG_USERNAME=user" > .env && \
|
38 |
-
echo "SEARXNG_PASSWORD=password" >> .env && \
|
39 |
-
cp .env /app/smolagents/examples/open_deep_research/.env && \
|
40 |
-
npm install && \
|
41 |
-
npm run build
|
42 |
-
|
43 |
-
# 6) Install Python dependencies
|
44 |
-
WORKDIR /app/smolagents/examples/open_deep_research
|
45 |
-
# Copy the local requirements file into the container to trigger caching if unchanged
|
46 |
-
COPY requirements.txt .
|
47 |
-
RUN pip install --no-cache-dir --upgrade pip && \
|
48 |
-
pip install --no-cache-dir -r requirements.txt --break-system-packages && \
|
49 |
-
pip install --no-cache-dir mcp --break-system-packages && \
|
50 |
-
pip install --no-cache-dir 'smolagents[litellm, mcp]' --break-system-packages
|
51 |
-
|
52 |
-
# 7) Create the downloads directory and fix permissions
|
53 |
-
RUN mkdir -p downloads && \
|
54 |
-
chown -R user:user /app/smolagents/examples/open_deep_research && \
|
55 |
-
chown -R user:user /app/mcp-searxng
|
56 |
-
|
57 |
-
# 8) Copy the custom startup and application files
|
58 |
-
COPY start.sh .
|
59 |
-
COPY app.py .
|
60 |
-
COPY run.py .
|
61 |
-
|
62 |
-
# 9) Ensure the startup script is executable
|
63 |
-
RUN chmod +x start.sh
|
64 |
-
|
65 |
-
# 10) Switch to the non-root user for runtime
|
66 |
-
USER user
|
67 |
-
|
68 |
-
# 11) Expose Gradio's default port
|
69 |
-
EXPOSE 7860
|
70 |
-
|
71 |
-
# 12) Set the default command to run the startup script
|
72 |
-
ENTRYPOINT ["python", "app.py"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__pycache__/run.cpython-312.pyc
CHANGED
Binary files a/__pycache__/run.cpython-312.pyc and b/__pycache__/run.cpython-312.pyc differ
|
|
app.py
CHANGED
@@ -1,108 +1,94 @@
|
|
1 |
-
import
|
2 |
import gradio as gr
|
3 |
-
|
4 |
-
import
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
}
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
conversation = []
|
42 |
-
try:
|
43 |
-
agent = create_agent(model_name=model_name)
|
44 |
-
answer = agent.run(question)
|
45 |
-
if isinstance(answer, str):
|
46 |
-
conversation = [
|
47 |
-
{"role": "user", "content": question},
|
48 |
-
{"role": "assistant", "content": answer}
|
49 |
-
]
|
50 |
-
else:
|
51 |
-
result = ""
|
52 |
-
for chunk in answer:
|
53 |
-
result += chunk
|
54 |
-
conversation = [
|
55 |
-
{"role": "user", "content": question},
|
56 |
-
{"role": "assistant", "content": result}
|
57 |
-
]
|
58 |
-
except Exception as e:
|
59 |
-
conversation = [
|
60 |
-
{"role": "user", "content": question},
|
61 |
-
{"role": "assistant", "content": f"An error occurred: {e}"}
|
62 |
-
]
|
63 |
-
finally:
|
64 |
-
root_logger.removeHandler(stream_handler)
|
65 |
-
stream_handler.close()
|
66 |
-
logs = log_buffer.getvalue()
|
67 |
-
return conversation, f"```\n{stdout_buffer.getvalue()}\n{logs}\n```"
|
68 |
-
|
69 |
-
def build_app():
|
70 |
-
with gr.Blocks(css=CSS) as demo:
|
71 |
-
# Title and header.
|
72 |
-
gr.HTML("<h1>SmolAgents Open Deep Search 🥳</h1>")
|
73 |
-
gr.Markdown("## Enhanced Agent UI")
|
74 |
-
|
75 |
-
# Configuration Accordion.
|
76 |
-
with gr.Accordion("Configuration (Click to Expand)", open=False):
|
77 |
-
openai_field = gr.Textbox(label="OPENAI_API_KEY", type="password", placeholder="Enter your OpenAI API key")
|
78 |
-
serper_field = gr.Textbox(label="SERPER_API_KEY", type="password", placeholder="Enter your Serper API key")
|
79 |
-
hf_field = gr.Textbox(label="HF_TOKEN", type="password", placeholder="Enter your Hugging Face Token")
|
80 |
-
gemini_field = gr.Textbox(label="GEMINI_API_KEY", type="password", placeholder="Enter your Gemini API key")
|
81 |
-
groq_field = gr.Textbox(label="GROQ_API_KEY", type="password", placeholder="Enter your Groq API key")
|
82 |
-
update_btn = gr.Button("Update Keys")
|
83 |
-
status_box = gr.Markdown("*(No keys set yet)*")
|
84 |
-
update_btn.click(fn=set_keys, inputs=[openai_field, serper_field, hf_field, gemini_field, groq_field], outputs=status_box)
|
85 |
-
|
86 |
-
# Placeholder for agent logs.
|
87 |
-
log_markdown = gr.Markdown(label="Agent Logs")
|
88 |
-
|
89 |
-
gr.Markdown("### Select a model and ask your question below:")
|
90 |
-
model_names = list(MODEL_CONFIGS.keys())
|
91 |
-
model_dropdown = gr.Dropdown(choices=model_names, label="Select Model", value="o1", allow_custom_value=True)
|
92 |
-
question_input = gr.Textbox(label="Your Question", placeholder="Enter your question here...")
|
93 |
-
submit_btn = gr.Button("Get Answer")
|
94 |
-
# Use Chatbot component with type "messages" for OpenAI-style dict format.
|
95 |
-
chatbot = gr.Chatbot(label="Answer", type="messages")
|
96 |
-
|
97 |
-
# Connect the answer function.
|
98 |
-
submit_btn.click(
|
99 |
-
fn=get_answer,
|
100 |
-
inputs=[question_input, model_dropdown],
|
101 |
-
outputs=[chatbot, log_markdown]
|
102 |
)
|
103 |
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
if __name__ == "__main__":
|
107 |
-
|
108 |
-
|
|
|
1 |
+
from run import create_agent
|
2 |
import gradio as gr
|
3 |
+
import os
|
4 |
+
from dotenv import load_dotenv
|
5 |
+
|
6 |
+
load_dotenv()
|
7 |
+
CONFIG_FILE = ".user_config.env"
|
8 |
+
|
9 |
+
def save_env_vars_to_file(env_vars):
|
10 |
+
print("[DEBUG] Saving user config to file")
|
11 |
+
with open(CONFIG_FILE, "w") as f:
|
12 |
+
for key, value in env_vars.items():
|
13 |
+
f.write(f"{key}={value}\n")
|
14 |
+
|
15 |
+
def launch_interface():
|
16 |
+
def setup_agent(question, model_id, hf_token, serpapi_key, use_custom_endpoint,
|
17 |
+
custom_api_endpoint, custom_api_key, search_provider, search_api_key, custom_search_url):
|
18 |
+
print("[DEBUG] Setting up agent with input question:", question)
|
19 |
+
|
20 |
+
if question.strip() == "":
|
21 |
+
return "Please enter a question."
|
22 |
+
|
23 |
+
endpoint = custom_api_endpoint if use_custom_endpoint else None
|
24 |
+
api_key = custom_api_key if use_custom_endpoint else None
|
25 |
+
|
26 |
+
save_env_vars_to_file({
|
27 |
+
"HF_TOKEN": hf_token,
|
28 |
+
"SERPAPI_API_KEY": serpapi_key,
|
29 |
+
})
|
30 |
+
|
31 |
+
print("[DEBUG] Instantiating agent with UI configuration")
|
32 |
+
agent = create_agent(
|
33 |
+
model_id=model_id,
|
34 |
+
hf_token=hf_token,
|
35 |
+
serpapi_key=serpapi_key,
|
36 |
+
custom_api_endpoint=endpoint,
|
37 |
+
custom_api_key=api_key,
|
38 |
+
search_provider=search_provider,
|
39 |
+
search_api_key=search_api_key,
|
40 |
+
custom_search_url=custom_search_url
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
)
|
42 |
|
43 |
+
return agent.run(question)
|
44 |
+
|
45 |
+
with gr.Blocks(theme=gr.themes.Base(), css=".gr-box { border-radius: 15px; padding: 20px; }") as demo:
|
46 |
+
gr.Markdown("# 🤖 SmolAgent Configurable Interface")
|
47 |
+
|
48 |
+
with gr.Row():
|
49 |
+
with gr.Column(scale=2):
|
50 |
+
question = gr.Textbox(label="🧠 Question", placeholder="Ask me anything...")
|
51 |
+
model_id = gr.Textbox(value="gpt-4o-mini", label="🧬 Model ID")
|
52 |
+
hf_token = gr.Textbox(value=os.getenv("HF_TOKEN", ""), label="🔑 HuggingFace Token", type="password")
|
53 |
+
serpapi_key = gr.Textbox(value=os.getenv("SERPAPI_API_KEY", ""), label="🔍 Serper API Key", type="password", visible=True)
|
54 |
+
use_custom_endpoint = gr.Checkbox(label="🌐 Use Custom API Endpoint")
|
55 |
+
custom_api_endpoint = gr.Textbox(label="🔌 Custom API Endpoint URL", placeholder="https://your-api-endpoint.com", visible=False)
|
56 |
+
custom_api_key = gr.Textbox(label="🔐 Custom API Endpoint Key", type="password", visible=False)
|
57 |
+
search_provider = gr.Dropdown(label="🔎 Search Provider", choices=["serper", "searxng"], value="serper")
|
58 |
+
search_api_key = gr.Textbox(label="🔑 Search Provider API Key (optional)", type="password", visible=False)
|
59 |
+
custom_search_url = gr.Textbox(label="🌐 Custom SearxNG Instance URL", placeholder="https://your-searxng-instance/search", visible=False)
|
60 |
+
submit_btn = gr.Button("🚀 Run Agent")
|
61 |
+
with gr.Column(scale=1):
|
62 |
+
output = gr.Textbox(label="📤 Answer", lines=15)
|
63 |
+
|
64 |
+
def update_search_visibility(provider):
|
65 |
+
return {
|
66 |
+
serpapi_key: gr.update(visible=(provider == "serper")),
|
67 |
+
custom_search_url: gr.update(visible=(provider == "searxng")),
|
68 |
+
search_api_key: gr.update(visible=(provider == "searxng")),
|
69 |
+
}
|
70 |
+
|
71 |
+
def update_custom_endpoint_visibility(checked):
|
72 |
+
return {
|
73 |
+
custom_api_endpoint: gr.update(visible=checked),
|
74 |
+
custom_api_key: gr.update(visible=checked),
|
75 |
+
}
|
76 |
+
|
77 |
+
search_provider.change(fn=update_search_visibility, inputs=search_provider,
|
78 |
+
outputs=[serpapi_key, custom_search_url, search_api_key])
|
79 |
+
|
80 |
+
use_custom_endpoint.change(fn=update_custom_endpoint_visibility, inputs=use_custom_endpoint,
|
81 |
+
outputs=[custom_api_endpoint, custom_api_key])
|
82 |
+
|
83 |
+
submit_btn.click(fn=setup_agent,
|
84 |
+
inputs=[question, model_id, hf_token, serpapi_key,
|
85 |
+
use_custom_endpoint, custom_api_endpoint, custom_api_key,
|
86 |
+
search_provider, search_api_key, custom_search_url],
|
87 |
+
outputs=output)
|
88 |
+
|
89 |
+
print("[DEBUG] Launching Gradio interface")
|
90 |
+
demo.launch()
|
91 |
|
92 |
if __name__ == "__main__":
|
93 |
+
launch_interface()
|
94 |
+
|
requirements.txt
CHANGED
@@ -1,5 +1,3 @@
|
|
1 |
-
gradio
|
2 |
-
uvicorn
|
3 |
dotenv
|
4 |
anthropic>=0.37.1
|
5 |
audioop-lts<1.0; python_version >= "3.13" # required to use pydub in Python >=3.13; LTS port of the removed Python builtin module audioop
|
|
|
|
|
|
|
1 |
dotenv
|
2 |
anthropic>=0.37.1
|
3 |
audioop-lts<1.0; python_version >= "3.13" # required to use pydub in Python >=3.13; LTS port of the removed Python builtin module audioop
|
run.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
import argparse
|
2 |
import os
|
3 |
-
import
|
|
|
4 |
from dotenv import load_dotenv
|
5 |
from huggingface_hub import login
|
6 |
from scripts.text_inspector_tool import TextInspectorTool
|
@@ -14,285 +15,86 @@ from scripts.text_web_browser import (
|
|
14 |
VisitTool,
|
15 |
)
|
16 |
from scripts.visual_qa import visualizer
|
|
|
17 |
from smolagents import (
|
18 |
CodeAgent,
|
19 |
-
DuckDuckGoSearchTool,
|
20 |
-
LiteLLMModel,
|
21 |
ToolCallingAgent,
|
|
|
|
|
|
|
22 |
)
|
23 |
|
24 |
-
# Initialize logging
|
25 |
-
logger = logging.getLogger("smolagents")
|
26 |
-
logger.setLevel(logging.INFO)
|
27 |
-
log_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
28 |
-
|
29 |
-
# Load environment variables
|
30 |
-
load_dotenv(override=True)
|
31 |
-
|
32 |
-
hf_token = os.getenv("HF_TOKEN")
|
33 |
-
if hf_token:
|
34 |
-
login(hf_token)
|
35 |
-
logger.info("Logged into Hugging Face Hub.")
|
36 |
-
else:
|
37 |
-
logger.warning("HF_TOKEN not found. Proceeding without authentication.")
|
38 |
-
|
39 |
AUTHORIZED_IMPORTS = [
|
40 |
-
"requests", "zipfile", "os", "pandas", "numpy", "sympy", "json", "bs4",
|
41 |
"pubchempy", "xml", "yahoo_finance", "Bio", "sklearn", "scipy", "pydub",
|
42 |
-
"io", "PIL", "chess", "PyPDF2", "pptx", "torch", "datetime", "fractions", "csv",
|
43 |
]
|
44 |
|
45 |
-
|
46 |
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
47 |
-
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
48 |
-
"Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
|
49 |
-
)
|
50 |
-
|
51 |
-
BROWSER_CONFIG = {
|
52 |
-
"viewport_size": 5120,
|
53 |
-
"downloads_folder": "downloads_folder",
|
54 |
-
"request_kwargs": {
|
55 |
-
"headers": {"User-Agent": USER_AGENT},
|
56 |
-
"timeout": 150,
|
57 |
-
"max_retries": 2,
|
58 |
-
},
|
59 |
-
"serpapi_key": os.getenv("SERPAPI_API_KEY"),
|
60 |
-
}
|
61 |
|
62 |
-
os.makedirs(f"./{BROWSER_CONFIG['downloads_folder']}", exist_ok=True)
|
63 |
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
"gpt-3.5-turbo": {
|
70 |
-
"litellm_params": {
|
71 |
-
"model_id": "openai/gpt-3.5-turbo",
|
72 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
73 |
-
"custom_role_conversions": custom_role_conversions,
|
74 |
-
"max_completion_tokens": 8192,
|
75 |
-
},
|
76 |
-
},
|
77 |
-
"gpt-3.5-turbo-16k": {
|
78 |
-
"litellm_params": {
|
79 |
-
"model_id": "openai/gpt-3.5-turbo-16k",
|
80 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
81 |
-
"custom_role_conversions": custom_role_conversions,
|
82 |
-
"max_completion_tokens": 16384,
|
83 |
-
},
|
84 |
-
},
|
85 |
-
"gpt-4o-mini": {
|
86 |
-
"litellm_params": {
|
87 |
-
"model_id": "openai/gpt-4o-mini",
|
88 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
89 |
-
"custom_role_conversions": custom_role_conversions,
|
90 |
-
"max_completion_tokens": 8192,
|
91 |
-
},
|
92 |
-
},
|
93 |
-
"chatgpt-4o-latest": {
|
94 |
-
"litellm_params": {
|
95 |
-
"model_id": "openai/chatgpt-4o-latest",
|
96 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
97 |
-
"custom_role_conversions": custom_role_conversions,
|
98 |
-
"max_completion_tokens": 8192,
|
99 |
-
},
|
100 |
-
},
|
101 |
-
"gpt-4-turbo": {
|
102 |
-
"litellm_params": {
|
103 |
-
"model_id": "openai/gpt-4-turbo",
|
104 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
105 |
-
"custom_role_conversions": custom_role_conversions,
|
106 |
-
"max_completion_tokens": 8192,
|
107 |
-
},
|
108 |
-
},
|
109 |
-
"gpt-4o": {
|
110 |
-
"litellm_params": {
|
111 |
-
"model_id": "openai/gpt-4o",
|
112 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
113 |
-
"custom_role_conversions": custom_role_conversions,
|
114 |
-
"max_completion_tokens": 8192,
|
115 |
-
},
|
116 |
-
},
|
117 |
-
"o1-mini": {
|
118 |
-
"litellm_params": {
|
119 |
-
"model_id": "openai/o1-mini",
|
120 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
121 |
-
"custom_role_conversions": custom_role_conversions,
|
122 |
-
"max_completion_tokens": 8192,
|
123 |
-
"reasoning_effort": "high",
|
124 |
-
},
|
125 |
-
},
|
126 |
-
"o1-preview": {
|
127 |
-
"litellm_params": {
|
128 |
-
"model_id": "openai/o1-preview",
|
129 |
-
"api_key": os.getenv("OPENAI_API_KEY"),
|
130 |
-
"custom_role_conversions": custom_role_conversions,
|
131 |
-
"max_completion_tokens": 8192,
|
132 |
-
"reasoning_effort": "high",
|
133 |
-
},
|
134 |
-
},
|
135 |
-
# HUGGINGFACE MODELS
|
136 |
-
"hf-llama-3.1-8B-instruct": {
|
137 |
-
"litellm_params": {
|
138 |
-
"model_id": "huggingface/meta-llama/Meta-Llama-3.1-8B-Instruct",
|
139 |
-
"api_key": os.getenv("HF_TOKEN"),
|
140 |
-
"custom_role_conversions": custom_role_conversions,
|
141 |
-
"max_completion_tokens": 8192,
|
142 |
-
},
|
143 |
-
},
|
144 |
-
"hf-DeepSeek-R1-Distill-Qwen-32B": {
|
145 |
-
"litellm_params": {
|
146 |
-
"model_id": "huggingface/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
|
147 |
-
"api_key": os.getenv("HF_TOKEN"),
|
148 |
-
"custom_role_conversions": custom_role_conversions,
|
149 |
-
"max_completion_tokens": 8192,
|
150 |
-
},
|
151 |
-
},
|
152 |
-
"hf-Qwen2.5-Coder-32B-Instruct": {
|
153 |
-
"litellm_params": {
|
154 |
-
"model_id": "huggingface/Qwen/Qwen2.5-Coder-32B-Instruct",
|
155 |
-
"api_key": os.getenv("HF_TOKEN"),
|
156 |
-
"custom_role_conversions": custom_role_conversions,
|
157 |
-
"max_completion_tokens": 8192,
|
158 |
-
},
|
159 |
-
},
|
160 |
-
"hf-QwQ-32B-Preview": {
|
161 |
-
"litellm_params": {
|
162 |
-
"model_id": "huggingface/Qwen/QwQ-32B-Preview",
|
163 |
-
"api_key": os.getenv("HF_TOKEN"),
|
164 |
-
"custom_role_conversions": custom_role_conversions,
|
165 |
-
"max_completion_tokens": 8192,
|
166 |
-
},
|
167 |
-
},
|
168 |
-
"hf-Llama-3.1-70B-Instruct": {
|
169 |
-
"litellm_params": {
|
170 |
-
"model_id": "huggingface/meta-llama/Llama-3.1-70B-Instruct",
|
171 |
-
"api_key": os.getenv("HF_TOKEN"),
|
172 |
-
"custom_role_conversions": custom_role_conversions,
|
173 |
-
"max_completion_tokens": 8192,
|
174 |
-
},
|
175 |
-
},
|
176 |
-
# GROQ MODELS
|
177 |
-
"groq-llama3-8b-8192": {
|
178 |
-
"litellm_params": {
|
179 |
-
"model_id": "groq/llama3-8b-8192",
|
180 |
-
"api_key": os.getenv("GROQ_API_KEY"),
|
181 |
-
"custom_role_conversions": custom_role_conversions,
|
182 |
-
"max_completion_tokens": 8192,
|
183 |
-
},
|
184 |
-
},
|
185 |
-
"groq-llama3-70b-8192": {
|
186 |
-
"litellm_params": {
|
187 |
-
"model_id": "groq/llama3-70b-8192",
|
188 |
-
"api_key": os.getenv("GROQ_API_KEY"),
|
189 |
-
"custom_role_conversions": custom_role_conversions,
|
190 |
-
"max_completion_tokens": 8192,
|
191 |
-
},
|
192 |
-
},
|
193 |
-
"groq-mixtral-8x7b-32768": {
|
194 |
-
"litellm_params": {
|
195 |
-
"model_id": "groq/mixtral-8x7b-32768",
|
196 |
-
"api_key": os.getenv("GROQ_API_KEY"),
|
197 |
-
"custom_role_conversions": custom_role_conversions,
|
198 |
-
"max_completion_tokens": 32768,
|
199 |
-
},
|
200 |
-
},
|
201 |
-
# GEMINI MODELS
|
202 |
-
"gemini-pro": {
|
203 |
-
"litellm_params": {
|
204 |
-
"model_id": "gemini/gemini-pro",
|
205 |
-
"api_key": os.getenv("GEMINI_API_KEY"),
|
206 |
-
"custom_role_conversions": custom_role_conversions,
|
207 |
-
"max_completion_tokens": 8192,
|
208 |
-
},
|
209 |
-
},
|
210 |
-
"gemini-1.5-pro": {
|
211 |
-
"litellm_params": {
|
212 |
-
"model_id": "gemini/gemini-1.5-pro",
|
213 |
-
"api_key": os.getenv("GEMINI_API_KEY"),
|
214 |
-
"custom_role_conversions": custom_role_conversions,
|
215 |
-
"max_completion_tokens": 8192,
|
216 |
-
},
|
217 |
-
},
|
218 |
-
"gemini-1.5-flash": {
|
219 |
-
"litellm_params": {
|
220 |
-
"model_id": "gemini/gemini-1.5-flash",
|
221 |
-
"api_key": os.getenv("GEMINI_API_KEY"),
|
222 |
-
"custom_role_conversions": custom_role_conversions,
|
223 |
-
"max_completion_tokens": 8192,
|
224 |
-
},
|
225 |
-
},
|
226 |
-
"gemini-pro-vision": {
|
227 |
-
"litellm_params": {
|
228 |
-
"model_id": "gemini/gemini-pro-vision",
|
229 |
-
"api_key": os.getenv("GEMINI_API_KEY"),
|
230 |
-
"custom_role_conversions": custom_role_conversions,
|
231 |
-
"max_completion_tokens": 8192,
|
232 |
-
},
|
233 |
-
},
|
234 |
-
"gemini-2.0-flash": {
|
235 |
-
"litellm_params": {
|
236 |
-
"model_id": "gemini/gemini-2.0-flash",
|
237 |
-
"api_key": os.getenv("GEMINI_API_KEY"),
|
238 |
-
"custom_role_conversions": custom_role_conversions,
|
239 |
-
"max_completion_tokens": 8192,
|
240 |
-
},
|
241 |
-
},
|
242 |
-
"gemini-2.0-flash-thinking-exp-01-21": {
|
243 |
-
"litellm_params": {
|
244 |
-
"model_id": "gemini/gemini-2.0-flash-thinking-exp-01-21",
|
245 |
-
"api_key": os.getenv("GEMINI_API_KEY"),
|
246 |
-
"custom_role_conversions": custom_role_conversions,
|
247 |
-
"max_completion_tokens": 8192,
|
248 |
-
},
|
249 |
-
},
|
250 |
-
# Default o1 model
|
251 |
-
"o1": {
|
252 |
-
"litellm_params": {
|
253 |
-
"model_id": "o1",
|
254 |
-
"custom_role_conversions": custom_role_conversions,
|
255 |
-
"max_completion_tokens": 8192,
|
256 |
-
"reasoning_effort": "high",
|
257 |
-
},
|
258 |
-
},
|
259 |
-
}
|
260 |
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
"question",
|
267 |
-
type=str,
|
268 |
-
help="Example: 'How many studio albums did Mercedes Sosa release before 2007?'"
|
269 |
-
)
|
270 |
-
parser.add_argument(
|
271 |
-
"--model-id",
|
272 |
-
type=str,
|
273 |
-
default="o1",
|
274 |
-
help="Model identifier (default: o1)"
|
275 |
-
)
|
276 |
-
return parser.parse_args()
|
277 |
|
278 |
-
|
279 |
-
|
280 |
-
raise ValueError(f"Model '{model_name}' is not a valid model. Available models are: {list(MODEL_CONFIGS.keys())}")
|
281 |
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
|
287 |
model = LiteLLMModel(**model_params)
|
288 |
-
|
289 |
-
text_limit = 100000
|
290 |
|
291 |
-
|
292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
|
294 |
WEB_TOOLS = [
|
295 |
-
|
296 |
VisitTool(browser),
|
297 |
PageUpTool(browser),
|
298 |
PageDownTool(browser),
|
@@ -301,49 +103,70 @@ def create_agent(model_name="o1"):
|
|
301 |
ArchiveSearchTool(browser),
|
302 |
TextInspectorTool(model, text_limit),
|
303 |
]
|
304 |
-
logger.info("Initialized web tools for ToolCallingAgent.")
|
305 |
|
306 |
text_webbrowser_agent = ToolCallingAgent(
|
307 |
model=model,
|
308 |
tools=WEB_TOOLS,
|
309 |
-
max_steps=
|
310 |
-
verbosity_level=
|
311 |
planning_interval=4,
|
312 |
name="search_agent",
|
313 |
-
description=
|
314 |
-
"A team member that will search the internet to answer your question. "
|
315 |
-
"Ask all questions that require browsing the web using complete sentences. "
|
316 |
-
"Provide as much context as possible, especially if searching within a specific timeframe."
|
317 |
-
),
|
318 |
provide_run_summary=True,
|
319 |
)
|
320 |
-
|
|
|
|
|
|
|
321 |
|
322 |
manager_agent = CodeAgent(
|
323 |
model=model,
|
324 |
tools=[visualizer, TextInspectorTool(model, text_limit)],
|
325 |
-
max_steps=
|
326 |
-
verbosity_level=
|
327 |
additional_authorized_imports=AUTHORIZED_IMPORTS,
|
328 |
planning_interval=4,
|
329 |
managed_agents=[text_webbrowser_agent],
|
330 |
)
|
331 |
-
|
|
|
332 |
return manager_agent
|
333 |
|
|
|
334 |
def main():
|
335 |
-
|
336 |
-
|
337 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
answer = agent.run(args.question)
|
339 |
-
|
340 |
-
|
341 |
-
else:
|
342 |
-
result = ""
|
343 |
-
for chunk in answer:
|
344 |
-
result += chunk
|
345 |
-
print(f"Got this answer: {result}")
|
346 |
-
logger.info("Agent has completed processing the question.")
|
347 |
|
348 |
if __name__ == "__main__":
|
349 |
main()
|
|
|
|
1 |
import argparse
|
2 |
import os
|
3 |
+
import threading
|
4 |
+
|
5 |
from dotenv import load_dotenv
|
6 |
from huggingface_hub import login
|
7 |
from scripts.text_inspector_tool import TextInspectorTool
|
|
|
15 |
VisitTool,
|
16 |
)
|
17 |
from scripts.visual_qa import visualizer
|
18 |
+
|
19 |
from smolagents import (
|
20 |
CodeAgent,
|
|
|
|
|
21 |
ToolCallingAgent,
|
22 |
+
LiteLLMModel,
|
23 |
+
DuckDuckGoSearchTool,
|
24 |
+
Tool,
|
25 |
)
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
AUTHORIZED_IMPORTS = [
|
28 |
+
"shell_gpt", "sgpt", "openai", "requests", "zipfile", "os", "pandas", "numpy", "sympy", "json", "bs4",
|
29 |
"pubchempy", "xml", "yahoo_finance", "Bio", "sklearn", "scipy", "pydub",
|
30 |
+
"yaml", "string", "secrets", "io", "PIL", "chess", "PyPDF2", "pptx", "torch", "datetime", "fractions", "csv",
|
31 |
]
|
32 |
|
33 |
+
append_answer_lock = threading.Lock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
|
|
35 |
|
36 |
+
def create_agent(
|
37 |
+
model_id="gpt-4o-mini",
|
38 |
+
hf_token=None,
|
39 |
+
serpapi_key=None,
|
40 |
+
custom_api_endpoint=None,
|
41 |
+
custom_api_key=None,
|
42 |
+
search_provider="serper",
|
43 |
+
search_api_key=None,
|
44 |
+
custom_search_url=None
|
45 |
+
):
|
46 |
+
print("[DEBUG] Creating agent with model_id:", model_id)
|
47 |
|
48 |
+
if hf_token:
|
49 |
+
print("[DEBUG] Logging into HuggingFace")
|
50 |
+
login(hf_token)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
+
model_params = {
|
53 |
+
"model_id": model_id,
|
54 |
+
"custom_role_conversions": {"tool-call": "assistant", "tool-response": "user"},
|
55 |
+
"max_completion_tokens": 8192,
|
56 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
+
if model_id == "gpt-4o-mini":
|
59 |
+
model_params["reasoning_effort"] = "high"
|
|
|
60 |
|
61 |
+
if custom_api_endpoint and custom_api_key:
|
62 |
+
print("[DEBUG] Using custom API endpoint:", custom_api_endpoint)
|
63 |
+
model_params["base_url"] = custom_api_endpoint
|
64 |
+
model_params["api_key"] = custom_api_key
|
65 |
|
66 |
model = LiteLLMModel(**model_params)
|
67 |
+
print("[DEBUG] Model initialized")
|
|
|
68 |
|
69 |
+
text_limit = 100000
|
70 |
+
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
|
71 |
+
|
72 |
+
browser_config = {
|
73 |
+
"viewport_size": 1024 * 5,
|
74 |
+
"downloads_folder": "downloads_folder",
|
75 |
+
"request_kwargs": {
|
76 |
+
"headers": {"User-Agent": user_agent},
|
77 |
+
"timeout": 300,
|
78 |
+
},
|
79 |
+
"serpapi_key": serpapi_key,
|
80 |
+
}
|
81 |
+
|
82 |
+
os.makedirs(f"./{browser_config['downloads_folder']}", exist_ok=True)
|
83 |
+
browser = SimpleTextBrowser(**browser_config)
|
84 |
+
print("[DEBUG] Browser initialized")
|
85 |
+
|
86 |
+
# Correct tool selection
|
87 |
+
if search_provider == "searxng":
|
88 |
+
print("[DEBUG] Using SearxNG-compatible DuckDuckGoSearchTool with base_url override")
|
89 |
+
search_tool = DuckDuckGoSearchTool()
|
90 |
+
if custom_search_url:
|
91 |
+
search_tool.base_url = custom_search_url # Override default DuckDuckGo URL (only if supported)
|
92 |
+
else:
|
93 |
+
print("[DEBUG] Using default DuckDuckGoSearchTool for Serper/standard search")
|
94 |
+
search_tool = DuckDuckGoSearchTool()
|
95 |
|
96 |
WEB_TOOLS = [
|
97 |
+
search_tool,
|
98 |
VisitTool(browser),
|
99 |
PageUpTool(browser),
|
100 |
PageDownTool(browser),
|
|
|
103 |
ArchiveSearchTool(browser),
|
104 |
TextInspectorTool(model, text_limit),
|
105 |
]
|
|
|
106 |
|
107 |
text_webbrowser_agent = ToolCallingAgent(
|
108 |
model=model,
|
109 |
tools=WEB_TOOLS,
|
110 |
+
max_steps=20,
|
111 |
+
verbosity_level=3,
|
112 |
planning_interval=4,
|
113 |
name="search_agent",
|
114 |
+
description="A team member that will search the internet to answer your question.",
|
|
|
|
|
|
|
|
|
115 |
provide_run_summary=True,
|
116 |
)
|
117 |
+
|
118 |
+
text_webbrowser_agent.prompt_templates["managed_agent"]["task"] += """You can navigate to .txt online files.
|
119 |
+
If a non-html page is in another format, especially .pdf or a Youtube video, use tool 'inspect_file_as_text' to inspect it.
|
120 |
+
Additionally, if after some searching you find out that you need more information to answer the question, you can use `final_answer` with your request for clarification as argument to request for more information."""
|
121 |
|
122 |
manager_agent = CodeAgent(
|
123 |
model=model,
|
124 |
tools=[visualizer, TextInspectorTool(model, text_limit)],
|
125 |
+
max_steps=16,
|
126 |
+
verbosity_level=3,
|
127 |
additional_authorized_imports=AUTHORIZED_IMPORTS,
|
128 |
planning_interval=4,
|
129 |
managed_agents=[text_webbrowser_agent],
|
130 |
)
|
131 |
+
|
132 |
+
print("[DEBUG] Agent fully initialized")
|
133 |
return manager_agent
|
134 |
|
135 |
+
|
136 |
def main():
|
137 |
+
print("[DEBUG] Loading environment variables")
|
138 |
+
load_dotenv(override=True)
|
139 |
+
|
140 |
+
parser = argparse.ArgumentParser()
|
141 |
+
parser.add_argument("question", type=str)
|
142 |
+
parser.add_argument("--model-id", type=str, default="gpt-4o-mini")
|
143 |
+
parser.add_argument("--hf-token", type=str, default=os.getenv("HF_TOKEN"))
|
144 |
+
parser.add_argument("--serpapi-key", type=str, default=os.getenv("SERPAPI_API_KEY"))
|
145 |
+
parser.add_argument("--custom-api-endpoint", type=str, default=None)
|
146 |
+
parser.add_argument("--custom-api-key", type=str, default=None)
|
147 |
+
parser.add_argument("--search-provider", type=str, default="serper")
|
148 |
+
parser.add_argument("--search-api-key", type=str, default=None)
|
149 |
+
parser.add_argument("--custom-search-url", type=str, default=None)
|
150 |
+
args = parser.parse_args()
|
151 |
+
|
152 |
+
print("[DEBUG] CLI arguments parsed:", args)
|
153 |
+
|
154 |
+
agent = create_agent(
|
155 |
+
model_id=args.model_id,
|
156 |
+
hf_token=args.hf_token,
|
157 |
+
serpapi_key=args.serpapi_key,
|
158 |
+
custom_api_endpoint=args.custom_api_endpoint,
|
159 |
+
custom_api_key=args.custom_api_key,
|
160 |
+
search_provider=args.search_provider,
|
161 |
+
search_api_key=args.search_api_key,
|
162 |
+
custom_search_url=args.custom_search_url,
|
163 |
+
)
|
164 |
+
|
165 |
+
print("[DEBUG] Running agent...")
|
166 |
answer = agent.run(args.question)
|
167 |
+
print(f"Got this answer: {answer}")
|
168 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
|
170 |
if __name__ == "__main__":
|
171 |
main()
|
172 |
+
|
start.sh
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
#!/bin/bash
|
2 |
-
# Exit immediately if a command exits with a non-zero status.
|
3 |
-
set -e
|
4 |
-
|
5 |
-
echo "Starting Gradio UI with enhanced performance optimizations..."
|
6 |
-
cd /app/smolagents/examples/open_deep_research
|
7 |
-
/bin/bash -c "python app.py &"
|
8 |
-
exec "$@"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|