Add proper planning with mcp support
Browse files- app.py +29 -6
- prompts/planning.py +14 -3
- requirements.txt +2 -0
- utils/huggingface_mcp_llamaindex.py +17 -0
app.py
CHANGED
@@ -6,7 +6,8 @@ import os
|
|
6 |
from utils.google_genai_llm import get_response, generate_with_gemini
|
7 |
from utils.utils import parse_json_codefences
|
8 |
from prompts.requirements_gathering import requirements_gathering_system_prompt
|
9 |
-
from prompts.planning import hf_query_gen_prompt
|
|
|
10 |
from prompts.devstral_coding_prompt import devstral_code_gen_sys_prompt, devstral_code_gen_user_prompt
|
11 |
from dotenv import load_dotenv
|
12 |
import os
|
@@ -231,7 +232,7 @@ def upload_file_handler(files):
|
|
231 |
return files
|
232 |
return []
|
233 |
|
234 |
-
def generate_plan(history, file_cache):
|
235 |
"""Generate a plan using the planning prompt and Gemini API"""
|
236 |
|
237 |
# Build conversation history
|
@@ -241,17 +242,39 @@ def generate_plan(history, file_cache):
|
|
241 |
conversation_history += f"User: {user_msg}\n"
|
242 |
if ai_msg:
|
243 |
conversation_history += f"Assistant: {ai_msg}\n"
|
244 |
-
|
245 |
# Format the prompt
|
246 |
-
formatted_prompt = hf_query_gen_prompt
|
247 |
-
|
|
|
248 |
# Get plan from Gemini
|
249 |
plan = generate_with_gemini(formatted_prompt, "Planning with gemini")
|
250 |
|
251 |
# Parse the plan
|
252 |
parsed_plan = parse_json_codefences(plan)
|
|
|
|
|
|
|
|
|
|
|
253 |
|
254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
|
256 |
def generate_code_with_devstral(plan_text, history, file_cache):
|
257 |
"""Generate code using the deployed Devstral model via Modal"""
|
|
|
6 |
from utils.google_genai_llm import get_response, generate_with_gemini
|
7 |
from utils.utils import parse_json_codefences
|
8 |
from prompts.requirements_gathering import requirements_gathering_system_prompt
|
9 |
+
from prompts.planning import hf_query_gen_prompt, hf_context_gen_prompt
|
10 |
+
from utils.huggingface_mcp_llamaindex import connect_and_get_tools, call_tool
|
11 |
from prompts.devstral_coding_prompt import devstral_code_gen_sys_prompt, devstral_code_gen_user_prompt
|
12 |
from dotenv import load_dotenv
|
13 |
import os
|
|
|
232 |
return files
|
233 |
return []
|
234 |
|
235 |
+
async def generate_plan(history, file_cache):
|
236 |
"""Generate a plan using the planning prompt and Gemini API"""
|
237 |
|
238 |
# Build conversation history
|
|
|
242 |
conversation_history += f"User: {user_msg}\n"
|
243 |
if ai_msg:
|
244 |
conversation_history += f"Assistant: {ai_msg}\n"
|
245 |
+
hf_query_gen_tool_details = await connect_and_get_tools()
|
246 |
# Format the prompt
|
247 |
+
formatted_prompt = hf_query_gen_prompt.format(
|
248 |
+
Tool_Details=hf_query_gen_tool_details
|
249 |
+
) + "\n\n" + conversation_history
|
250 |
# Get plan from Gemini
|
251 |
plan = generate_with_gemini(formatted_prompt, "Planning with gemini")
|
252 |
|
253 |
# Parse the plan
|
254 |
parsed_plan = parse_json_codefences(plan)
|
255 |
+
# Call tool to get tool calls
|
256 |
+
try:
|
257 |
+
tool_calls = await asyncio.gather(*[call_tool(step['tool'], step['args']) for step in parsed_plan])
|
258 |
+
except Exception as e:
|
259 |
+
tool_calls = []
|
260 |
|
261 |
+
if tool_calls!=[]:
|
262 |
+
formatted_context_prompt = hf_context_gen_prompt.format(
|
263 |
+
Conversation=conversation_history,
|
264 |
+
Tool_Calls=parsed_plan,
|
265 |
+
Results=tool_calls
|
266 |
+
)
|
267 |
+
context = generate_with_gemini(formatted_context_prompt, "Generating context for plan")
|
268 |
+
|
269 |
+
else:
|
270 |
+
formatted_context_prompt = hf_context_gen_prompt.format(
|
271 |
+
Conversation=conversation_history,
|
272 |
+
Tool_Calls=parsed_plan,
|
273 |
+
Results="Couldn't generate the tool calls results but use your knowledge about huggingface platform(models, datasets, spaces, training libraries, transfomers library etc.) as backup to generate the plan"
|
274 |
+
)
|
275 |
+
context = generate_with_gemini(formatted_context_prompt, "Generating context for plan")
|
276 |
+
|
277 |
+
return context
|
278 |
|
279 |
def generate_code_with_devstral(plan_text, history, file_cache):
|
280 |
"""Generate code using the deployed Devstral model via Modal"""
|
prompts/planning.py
CHANGED
@@ -16,13 +16,24 @@ Get detailed information about a specific model
|
|
16 |
Search for datasets with filters for author, tags, etc…
|
17 |
* Dataset Details
|
18 |
Get detailed information about a specific dataset
|
|
|
|
|
19 |
When the user describes a problem, respond with:
|
20 |
- A JSON list of tool-calls such as:
|
21 |
```json
|
22 |
[
|
23 |
-
{"tool": "
|
24 |
-
{"tool": "
|
25 |
]
|
26 |
```
|
27 |
Just provide the response in the provided json format without any suffix or prefix or any explanation.
|
28 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
Search for datasets with filters for author, tags, etc…
|
17 |
* Dataset Details
|
18 |
Get detailed information about a specific dataset
|
19 |
+
|
20 |
+
Complete_Tool_Details: {Tool_Details}
|
21 |
When the user describes a problem, respond with:
|
22 |
- A JSON list of tool-calls such as:
|
23 |
```json
|
24 |
[
|
25 |
+
{{"tool": "dataset_search", "args": {{"query": "...", "limit": 5}}}},
|
26 |
+
{{"tool": "model_search", "args": {{"query": "...", "limit": 3}}}}
|
27 |
]
|
28 |
```
|
29 |
Just provide the response in the provided json format without any suffix or prefix or any explanation.
|
30 |
+
"""
|
31 |
+
|
32 |
+
|
33 |
+
hf_context_gen_prompt="""Given the chat history between a user and chatbot about his data science problem and the requirements and the generated tool calls and planning to solve the problem using huggingface api and the results of the queries, generate a plan with context with all the details of the results of the queries and the problem statements which can be passed to an llm to generate a solution code for the problem using huggingface platform libraries and models, spaces, datasets etc.
|
34 |
+
|
35 |
+
Conversation: {Conversation}
|
36 |
+
Tool_Calls: {Tool_Calls}
|
37 |
+
Results: {Results}
|
38 |
+
|
39 |
+
Plan: """
|
requirements.txt
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
google-genai==1.19.0
|
|
|
2 |
gradio[mcp]==5.33.0
|
3 |
pandas==2.3.0
|
4 |
python-dotenv==1.0.1
|
@@ -6,3 +7,4 @@ openpyxl==3.1.5
|
|
6 |
Pillow==10.4.0
|
7 |
marker-pdf==1.7.4
|
8 |
modal==0.75.6
|
|
|
|
1 |
google-genai==1.19.0
|
2 |
+
mcp==1.9.1
|
3 |
gradio[mcp]==5.33.0
|
4 |
pandas==2.3.0
|
5 |
python-dotenv==1.0.1
|
|
|
7 |
Pillow==10.4.0
|
8 |
marker-pdf==1.7.4
|
9 |
modal==0.75.6
|
10 |
+
llama-index-tools-mcp
|
utils/huggingface_mcp_llamaindex.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llama_index.tools.mcp import BasicMCPClient
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
import os
|
4 |
+
load_dotenv()
|
5 |
+
|
6 |
+
async def connect_and_get_tools():
|
7 |
+
# Connect to an MCP server using different transports
|
8 |
+
http_client = BasicMCPClient("https://huggingface.co/mcp", headers={"Authorization": f"Bearer {os.getenv('HF_TOKEN')}"})
|
9 |
+
|
10 |
+
# List available tools
|
11 |
+
tools = await http_client.list_tools()
|
12 |
+
return tools
|
13 |
+
|
14 |
+
async def call_tool(tool_name, tool_args):
|
15 |
+
http_client = BasicMCPClient("https://huggingface.co/mcp", headers={"Authorization": f"Bearer {os.getenv('HF_TOKEN')}"})
|
16 |
+
result = await http_client.call_tool(tool_name, tool_args)
|
17 |
+
return result
|