Luis Vizcaya commited on
Commit
b95f82b
·
1 Parent(s): 27827fb

requirements.txt updated

Browse files
Files changed (2) hide show
  1. app.py +36 -29
  2. requirements.txt +160 -9
app.py CHANGED
@@ -6,6 +6,15 @@ import time
6
  from typing import List, Dict, Generator
7
  from dotenv import load_dotenv
8
 
 
 
 
 
 
 
 
 
 
9
  # Import our agents from the src directory
10
  from src.clarifier import Clarifier
11
  from src.planner import Planner
@@ -18,7 +27,8 @@ load_dotenv()
18
 
19
  def get_secret(key):
20
  val = os.getenv(key)
21
- return val if val is not None else ""
 
22
 
23
  HF_KEY = get_secret("HF_KEY")
24
  TAVILY_API_KEY = get_secret("TAVILY_API_KEY")
@@ -28,8 +38,8 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(
28
  logger = logging.getLogger(__name__)
29
 
30
  # --- MODELS ---
31
- # Using the most stable serverless models to avoid 401 router issues
32
- CLARIFIER_MODEL = 'Qwen/Qwen2.5-7B-Instruct'
33
  PLANNER_MODEL = 'Qwen/Qwen2.5-7B-Instruct'
34
  SPLITTER_MODEL = 'Qwen/Qwen2.5-7B-Instruct'
35
  COORDINATOR_MODEL = 'Qwen/Qwen2.5-7B-Instruct'
@@ -47,17 +57,19 @@ theme = gr.themes.Soft(
47
  def start_clarification(topic, hf_key, state):
48
  if not topic:
49
  return gr.update(), "### ⚠️ Warning\nPlease enter a topic.", state, gr.update()
50
- if not hf_key or hf_key.strip() == "":
51
- return gr.update(), "### ⚠️ Warning\nPlease provide a valid Hugging Face Token in the configuration panel.", state, gr.update()
 
 
52
 
53
  state["initial_topic"] = topic
54
- clarifier = Clarifier(model_name=CLARIFIER_MODEL, hf_key=hf_key.strip())
55
  try:
56
  suggestions = clarifier.get_suggestions(topic)
57
  state["suggestions"] = suggestions
58
 
59
  if not suggestions:
60
- return gr.update(), "### ❌ Error\nNo suggestions received. Please check if your HF Token has access to the models.", state, gr.update()
61
 
62
  suggestion_md = "### 💡 Refine Your Topic\n\nChoose one of the suggested directions or enter a custom one below:\n\n"
63
  for i, s in enumerate(suggestions):
@@ -67,7 +79,7 @@ def start_clarification(topic, hf_key, state):
67
  except Exception as e:
68
  error_msg = str(e)
69
  if "401" in error_msg:
70
- error_msg = "401 Unauthorized: Your Hugging Face Token is invalid or doesn't have permissions for the Inference API."
71
  return gr.update(), f"### ❌ Error\n{error_msg}", state, gr.update()
72
 
73
  def select_suggestion(index, custom_topic, state):
@@ -77,17 +89,16 @@ def select_suggestion(index, custom_topic, state):
77
  sug = state["suggestions"][int(index)-1]
78
  state["final_topic"] = f"{sug['title']}: {sug['description']}"
79
  else:
80
- # ENSURE 4 ITEMS ARE RETURNED
81
  return gr.update(), "### ⚠️ Warning\nPlease select an option or enter a custom topic.", state, gr.update()
82
 
83
  return gr.update(visible=True), f"### 🎯 Target Topic\n**{state['final_topic']}**", state, gr.update(visible=False)
84
 
85
  def generate_strategy(hf_key, state):
86
- hf_key = hf_key.strip()
87
- if not hf_key:
88
  return "### ⚠️ Warning\nHF Key missing.", state, gr.update()
89
 
90
- planner = Planner(model_name=PLANNER_MODEL, hf_key=hf_key)
91
  try:
92
  plan = planner.plan(state["final_topic"])
93
  state["research_plan"] = plan
@@ -96,11 +107,11 @@ def generate_strategy(hf_key, state):
96
  return f"### ❌ Error\n{str(e)}", state, gr.update()
97
 
98
  def decompose_tasks(hf_key, state):
99
- hf_key = hf_key.strip()
100
- if not hf_key:
101
  return "### ⚠️ Warning\nHF Key missing.", state, gr.update()
102
 
103
- splitter = Splitter(model_name=SPLITTER_MODEL, hf_key=hf_key)
104
  try:
105
  subtasks = splitter.split(state["research_plan"])
106
  state["subtasks"] = subtasks
@@ -118,23 +129,22 @@ def run_research(hf_key, tavily_key, state):
118
  from src.prompts import SUBAGENT_DIRECTION, COORDINATOR_DIRECTION
119
  from tavily import TavilyClient
120
 
121
- hf_key = hf_key.strip()
122
- tavily_key = tavily_key.strip()
123
 
124
- if not hf_key:
125
  yield "### ❌ Error\nHF Token missing.", state, gr.update(), ""
126
  return
127
- if not tavily_key:
128
  yield "### ❌ Error\nTavily API Key missing.", state, gr.update(), ""
129
  return
130
 
131
- tavily_client = TavilyClient(api_key=tavily_key)
132
 
133
  @tool
134
  def web_search(query: str) -> str:
135
  """
136
  Search the web for real-time information using Tavily.
137
-
138
  Args:
139
  query: The search query to look up.
140
  """
@@ -146,8 +156,8 @@ def run_research(hf_key, tavily_key, state):
146
  except Exception as e:
147
  return f"Search failed: {e}"
148
 
149
- coordinator_model = InferenceClientModel(model_id=COORDINATOR_MODEL, api_key=hf_key)
150
- subagent_model = InferenceClientModel(model_id=SUBAGENT_MODEL, api_key=hf_key)
151
 
152
  current_findings = []
153
  log_content = "### 🔍 Agentic Research Progress\n\n"
@@ -162,7 +172,7 @@ def run_research(hf_key, tavily_key, state):
162
  t_title = task['title']
163
  t_desc = task['description']
164
 
165
- log_content += f"**Agent working on:** {t_title}...\n"
166
  yield log_content, state, gr.update(), ""
167
 
168
  subagent = CodeAgent(
@@ -206,14 +216,11 @@ def run_research(hf_key, tavily_key, state):
206
  final_report = response.content
207
  if "<think>" in final_report and "</think>" in final_report:
208
  final_report = final_report.split("</think>")[-1].strip()
209
- elif "<think>" in final_report:
210
- final_report = final_report.split("<think>")[-1].strip()
211
- if "\n\n" in final_report: final_report = final_report.split("\n\n", 1)[-1]
212
 
213
  log_content += "### 🖋️ Review: Polishing and Finalizing...\n"
214
  yield log_content, state, gr.update(), ""
215
 
216
- reviewer = Reviewer(model_name=REVIEWER_MODEL, hf_key=hf_key)
217
  polished_report = reviewer.review(final_report)
218
  state["final_report"] = polished_report
219
 
@@ -265,7 +272,7 @@ with gr.Blocks(theme=theme, title="Deep Research Agent") as demo:
265
  # STEP 1: Introduction
266
  with gr.Column(visible=True) as step1_col:
267
  gr.Markdown("## 1️⃣ What are you researching?")
268
- topic_input = gr.Textbox(label="Enter a broad topic or research question:", placeholder="e.g., Future of Fusion Energy")
269
  start_btn = gr.Button("Clarify Topic ➡️", variant="primary")
270
 
271
  # STEP 2: Refinement
 
6
  from typing import List, Dict, Generator
7
  from dotenv import load_dotenv
8
 
9
+ # Try to use truststore for corporate network compatibility (local only)
10
+ if not os.getenv("SPACE_ID"):
11
+ try:
12
+ import truststore
13
+ truststore.inject_into_ssl()
14
+ print("💡 Truststore injected (Corporate SSL mode)")
15
+ except ImportError:
16
+ pass
17
+
18
  # Import our agents from the src directory
19
  from src.clarifier import Clarifier
20
  from src.planner import Planner
 
27
 
28
  def get_secret(key):
29
  val = os.getenv(key)
30
+ # Strip spaces in case the .env has "KEY = VALUE"
31
+ return val.strip() if val is not None else ""
32
 
33
  HF_KEY = get_secret("HF_KEY")
34
  TAVILY_API_KEY = get_secret("TAVILY_API_KEY")
 
38
  logger = logging.getLogger(__name__)
39
 
40
  # --- MODELS ---
41
+ # Using highly stable serverless models
42
+ CLARIFIER_MODEL = 'HuggingFaceH4/zephyr-7b-beta'
43
  PLANNER_MODEL = 'Qwen/Qwen2.5-7B-Instruct'
44
  SPLITTER_MODEL = 'Qwen/Qwen2.5-7B-Instruct'
45
  COORDINATOR_MODEL = 'Qwen/Qwen2.5-7B-Instruct'
 
57
  def start_clarification(topic, hf_key, state):
58
  if not topic:
59
  return gr.update(), "### ⚠️ Warning\nPlease enter a topic.", state, gr.update()
60
+
61
+ clean_key = hf_key.strip() if hf_key else ""
62
+ if not clean_key:
63
+ return gr.update(), "### ⚠️ Warning\nPlease provide a valid Hugging Face Token.", state, gr.update()
64
 
65
  state["initial_topic"] = topic
66
+ clarifier = Clarifier(model_name=CLARIFIER_MODEL, hf_key=clean_key)
67
  try:
68
  suggestions = clarifier.get_suggestions(topic)
69
  state["suggestions"] = suggestions
70
 
71
  if not suggestions:
72
+ return gr.update(), "### ❌ Error\nNo suggestions received. This usually means the HF Token is invalid or the model is overloaded.", state, gr.update()
73
 
74
  suggestion_md = "### 💡 Refine Your Topic\n\nChoose one of the suggested directions or enter a custom one below:\n\n"
75
  for i, s in enumerate(suggestions):
 
79
  except Exception as e:
80
  error_msg = str(e)
81
  if "401" in error_msg:
82
+ error_msg = "401 Unauthorized: Your Hugging Face Token is invalid for the Inference API. Please generate a new 'Write' token at hf.co/settings/tokens"
83
  return gr.update(), f"### ❌ Error\n{error_msg}", state, gr.update()
84
 
85
  def select_suggestion(index, custom_topic, state):
 
89
  sug = state["suggestions"][int(index)-1]
90
  state["final_topic"] = f"{sug['title']}: {sug['description']}"
91
  else:
 
92
  return gr.update(), "### ⚠️ Warning\nPlease select an option or enter a custom topic.", state, gr.update()
93
 
94
  return gr.update(visible=True), f"### 🎯 Target Topic\n**{state['final_topic']}**", state, gr.update(visible=False)
95
 
96
  def generate_strategy(hf_key, state):
97
+ clean_key = hf_key.strip() if hf_key else ""
98
+ if not clean_key:
99
  return "### ⚠️ Warning\nHF Key missing.", state, gr.update()
100
 
101
+ planner = Planner(model_name=PLANNER_MODEL, hf_key=clean_key)
102
  try:
103
  plan = planner.plan(state["final_topic"])
104
  state["research_plan"] = plan
 
107
  return f"### ❌ Error\n{str(e)}", state, gr.update()
108
 
109
  def decompose_tasks(hf_key, state):
110
+ clean_key = hf_key.strip() if hf_key else ""
111
+ if not clean_key:
112
  return "### ⚠️ Warning\nHF Key missing.", state, gr.update()
113
 
114
+ splitter = Splitter(model_name=SPLITTER_MODEL, hf_key=clean_key)
115
  try:
116
  subtasks = splitter.split(state["research_plan"])
117
  state["subtasks"] = subtasks
 
129
  from src.prompts import SUBAGENT_DIRECTION, COORDINATOR_DIRECTION
130
  from tavily import TavilyClient
131
 
132
+ clean_hf = hf_key.strip() if hf_key else ""
133
+ clean_tavily = tavily_key.strip() if tavily_key else ""
134
 
135
+ if not clean_hf:
136
  yield "### ❌ Error\nHF Token missing.", state, gr.update(), ""
137
  return
138
+ if not clean_tavily:
139
  yield "### ❌ Error\nTavily API Key missing.", state, gr.update(), ""
140
  return
141
 
142
+ tavily_client = TavilyClient(api_key=clean_tavily)
143
 
144
  @tool
145
  def web_search(query: str) -> str:
146
  """
147
  Search the web for real-time information using Tavily.
 
148
  Args:
149
  query: The search query to look up.
150
  """
 
156
  except Exception as e:
157
  return f"Search failed: {e}"
158
 
159
+ coordinator_model = InferenceClientModel(model_id=COORDINATOR_MODEL, api_key=clean_hf)
160
+ subagent_model = InferenceClientModel(model_id=SUBAGENT_MODEL, api_key=clean_hf)
161
 
162
  current_findings = []
163
  log_content = "### 🔍 Agentic Research Progress\n\n"
 
172
  t_title = task['title']
173
  t_desc = task['description']
174
 
175
+ log_content += f"**Agent {i+1} working on:** {t_title}...\n"
176
  yield log_content, state, gr.update(), ""
177
 
178
  subagent = CodeAgent(
 
216
  final_report = response.content
217
  if "<think>" in final_report and "</think>" in final_report:
218
  final_report = final_report.split("</think>")[-1].strip()
 
 
 
219
 
220
  log_content += "### 🖋️ Review: Polishing and Finalizing...\n"
221
  yield log_content, state, gr.update(), ""
222
 
223
+ reviewer = Reviewer(model_name=REVIEWER_MODEL, hf_key=clean_hf)
224
  polished_report = reviewer.review(final_report)
225
  state["final_report"] = polished_report
226
 
 
272
  # STEP 1: Introduction
273
  with gr.Column(visible=True) as step1_col:
274
  gr.Markdown("## 1️⃣ What are you researching?")
275
+ topic_input = gr.Textbox(label="Enter a broad topic or research question:", placeholder="e.g., Target market for sustainable polymers in Europe")
276
  start_btn = gr.Button("Clarify Topic ➡️", variant="primary")
277
 
278
  # STEP 2: Refinement
requirements.txt CHANGED
@@ -1,9 +1,160 @@
1
- huggingface_hub
2
- gradio
3
- python-dotenv
4
- pydantic
5
- smolagents
6
- tavily-python
7
- requests
8
- certifi
9
- fpdf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==24.1.0
2
+ altair==5.5.0
3
+ altgraph==0.17.5
4
+ annotated-doc==0.0.4
5
+ annotated-types==0.7.0
6
+ anyio==4.9.0
7
+ asttokens==3.0.0
8
+ attrs==25.3.0
9
+ audioop-lts==0.2.2
10
+ azure-core==1.35.0
11
+ azure-identity==1.23.0
12
+ blinker==1.9.0
13
+ brotli==1.2.0
14
+ cachetools==6.1.0
15
+ certifi==2025.8.3
16
+ cffi==1.17.1
17
+ charset-normalizer==3.4.2
18
+ click==8.2.1
19
+ cloudpickle==3.1.1
20
+ colorama==0.4.6
21
+ comm==0.2.3
22
+ contourpy==1.3.2
23
+ cryptography==45.0.5
24
+ cycler==0.12.1
25
+ debugpy==1.8.16
26
+ decorator==5.2.1
27
+ distlib==0.4.0
28
+ distro==1.9.0
29
+ exceptiongroup==1.3.0
30
+ executing==2.2.0
31
+ Farama-Notifications==0.0.4
32
+ fastapi==0.128.0
33
+ fastjsonschema==2.21.2
34
+ ffmpy==1.0.0
35
+ filelock==3.19.1
36
+ fonttools==4.59.0
37
+ fsspec==2025.12.0
38
+ gitdb==4.0.12
39
+ GitPython==3.1.44
40
+ gradio==6.2.0
41
+ gradio_client==2.0.2
42
+ greenlet==3.3.0
43
+ groovy==0.1.2
44
+ gymnasium==1.1.1
45
+ h11==0.16.0
46
+ hf-xet==1.2.0
47
+ holidays==0.78
48
+ httpcore==1.0.9
49
+ httpx==0.28.1
50
+ httpx-sse==0.4.1
51
+ huggingface_hub==1.2.3
52
+ idna==3.10
53
+ ipykernel==6.30.1
54
+ ipython==8.37.0
55
+ ipython_pygments_lexers==1.1.1
56
+ jedi==0.19.2
57
+ Jinja2==3.1.6
58
+ jiter==0.10.0
59
+ joblib==1.5.1
60
+ jsonschema==4.25.1
61
+ jsonschema-specifications==2025.9.1
62
+ jupyter_client==8.6.3
63
+ jupyter_core==5.8.1
64
+ kiwisolver==1.4.8
65
+ llvmlite==0.44.0
66
+ logging==0.4.9.6
67
+ markdown-it-py==3.0.0
68
+ MarkupSafe==3.0.2
69
+ matplotlib==3.10.5
70
+ matplotlib-inline==0.1.7
71
+ mcp==1.11.0
72
+ mdurl==0.1.2
73
+ msal==1.32.3
74
+ msal-extensions==1.3.1
75
+ narwhals==2.4.0
76
+ nbformat==5.10.4
77
+ nest-asyncio==1.6.0
78
+ networkx==3.4.2
79
+ numba==0.61.2
80
+ numpy==2.2.6
81
+ openai==1.90.0
82
+ orjson==3.11.5
83
+ packaging==25.0
84
+ pandas==2.3.1
85
+ parso==0.8.5
86
+ patsy==1.0.1
87
+ pefile==2024.8.26
88
+ pillow==11.3.0
89
+ platformdirs==4.3.8
90
+ plotly==6.3.0
91
+ prompt_toolkit==3.0.51
92
+ protobuf==6.31.1
93
+ psutil==7.0.0
94
+ PuLP==3.2.2
95
+ pure_eval==0.2.3
96
+ pyarrow==20.0.0
97
+ pycparser==2.22
98
+ pydantic==2.11.7
99
+ pydantic-settings==2.10.1
100
+ pydantic_core==2.33.2
101
+ pydeck==0.9.1
102
+ pydub==0.25.1
103
+ pyenv-win==3.1.1
104
+ Pygments==2.19.2
105
+ pyinstaller==6.17.0
106
+ pyinstaller-hooks-contrib==2025.11
107
+ PyJWT==2.10.1
108
+ pyodbc==5.2.0
109
+ pyparsing==3.2.3
110
+ python-dateutil==2.9.0.post0
111
+ python-dotenv==1.1.1
112
+ python-multipart==0.0.20
113
+ pytz==2025.2
114
+ pywin32==311
115
+ pywin32-ctypes==0.2.3
116
+ PyYAML==6.0.3
117
+ pyzmq==27.0.2
118
+ referencing==0.36.2
119
+ requests==2.32.4
120
+ rich==14.1.0
121
+ rpds-py==0.27.1
122
+ safehttpx==0.1.7
123
+ scikit-learn==1.7.1
124
+ scipy==1.15.3
125
+ semantic-version==2.10.0
126
+ setuptools==80.9.0
127
+ shap==0.48.0
128
+ shellingham==1.5.4
129
+ six==1.17.0
130
+ slicer==0.0.8
131
+ smmap==5.0.2
132
+ sniffio==1.3.1
133
+ SQLAlchemy==2.0.45
134
+ sse-starlette==2.4.1
135
+ stack-data==0.6.3
136
+ starlette==0.47.1
137
+ statsmodels==0.14.5
138
+ streamlit==1.46.0
139
+ tabulate==0.9.0
140
+ tenacity==9.1.2
141
+ termcolor==3.1.0
142
+ threadpoolctl==3.6.0
143
+ toml==0.10.2
144
+ tomlkit==0.13.3
145
+ tornado==6.5.2
146
+ tqdm==4.67.1
147
+ traitlets==5.14.3
148
+ truststore==0.10.4
149
+ typer==0.21.0
150
+ typer-slim==0.21.0
151
+ typing-inspection==0.4.1
152
+ typing_extensions==4.14.1
153
+ tzdata==2025.2
154
+ urllib3==2.5.0
155
+ uv==0.7.20
156
+ uvicorn==0.35.0
157
+ virtualenv==20.34.0
158
+ watchdog==6.0.0
159
+ wcwidth==0.2.13
160
+ xgboost==3.0.4