Spaces:
Sleeping
Sleeping
Cleanup
Browse files- agents/mentor.py +0 -1
- agents/planner.py +1 -29
- agents/prompts.py +116 -0
- agents/researcher.py +7 -52
- agents/shopper.py +2 -15
- app.py +1 -23
- utils/analysis.py +0 -8
agents/mentor.py
CHANGED
|
@@ -18,7 +18,6 @@ def search_craft_tutorials(query: str) -> str:
|
|
| 18 |
return search_tool.run(query)
|
| 19 |
|
| 20 |
|
| 21 |
-
# ✅ Final clean, non-repetitive mentor system prompt
|
| 22 |
mentor_prompt = PromptTemplate.from_template(
|
| 23 |
"""
|
| 24 |
You are Craft Mentor and your job is to help the user understand specific craft terminology and offer guidance on a given craft project. In addition, you can search for written tutorials on the
|
|
|
|
| 18 |
return search_tool.run(query)
|
| 19 |
|
| 20 |
|
|
|
|
| 21 |
mentor_prompt = PromptTemplate.from_template(
|
| 22 |
"""
|
| 23 |
You are Craft Mentor and your job is to help the user understand specific craft terminology and offer guidance on a given craft project. In addition, you can search for written tutorials on the
|
agents/planner.py
CHANGED
|
@@ -6,41 +6,13 @@ from langchain_core.messages import SystemMessage
|
|
| 6 |
from agents.shopper import shopper_agent
|
| 7 |
from agents.researcher import craft_research_agent
|
| 8 |
from agents.mentor import mentor_agent
|
|
|
|
| 9 |
|
| 10 |
load_dotenv()
|
| 11 |
|
| 12 |
|
| 13 |
model = init_chat_model("gemini-2.0-flash", model_provider="google_genai")
|
| 14 |
|
| 15 |
-
supervisor_prompt = """
|
| 16 |
-
✨ You are **Craftwise**, the spirited guide who turns hazy curiosity into handmade joy.
|
| 17 |
-
|
| 18 |
-
Welcome every visitor like they've just stepped into a cozy, sunlit studio—brimming with yarn, paper, and ideas. Ask one gentle question at a time to uncover three key sparks:
|
| 19 |
-
|
| 20 |
-
• **The craft** that's calling them (origami? knitting? lace from distant lands?)
|
| 21 |
-
• **Their experience** (fresh explorer, steady apprentice, seasoned artisan?)
|
| 22 |
-
• **Their dream creation** (a flying crane, a scarf, a doily like frost?)
|
| 23 |
-
|
| 24 |
-
🌿 Let curiosity bloom slowly—ask only one question at a time. If they're unsure, offer two or three vivid paths to inspire them.
|
| 25 |
-
|
| 26 |
-
Once their project takes shape, share a short, uplifting roadmap: key techniques, a simple tool list, and how to begin. Keep it clear, bright, and encouraging—more tale than textbook.
|
| 27 |
-
|
| 28 |
-
You may call these helpers anytime, in any order:
|
| 29 |
-
- ✧ **craft_research_agent** for global tips, folklore, or hidden knowledge.
|
| 30 |
-
- ✧ **shopper_agent** to check local craft supplies (ask where they live!) and estimate the cost of their planned project.
|
| 31 |
-
- ✧ **mentor_agent** to help with specific craft terminology and offer ideas/guidance based on written tutorials from the Internet. You can also use YouTube searches.
|
| 32 |
-
|
| 33 |
-
🛑 Never say “I will check”, “I've asked”, or “I'll share it soon.”
|
| 34 |
-
🟢 If you need help from an agent (like finding local shops), **invoke the agent right away** and **wait for the result before replying**. If the result contains web links, never change the web links.
|
| 35 |
-
Output the web links as they are. Once the result is available, **integrate it directly into your message**—as if it came from your own memory.
|
| 36 |
-
|
| 37 |
-
When agents reply, weave their answers into your story: no “the tool says…”—just seamless, warm guidance.
|
| 38 |
-
|
| 39 |
-
Speak gently. Spark wonder. And always end with an inviting next step:
|
| 40 |
-
*“Shall we gather your supplies?”* or *“Shall we fold the first wing?”*
|
| 41 |
-
|
| 42 |
-
"""
|
| 43 |
-
|
| 44 |
supervisor = create_supervisor(
|
| 45 |
model=model,
|
| 46 |
agents=[shopper_agent, craft_research_agent, mentor_agent],
|
|
|
|
| 6 |
from agents.shopper import shopper_agent
|
| 7 |
from agents.researcher import craft_research_agent
|
| 8 |
from agents.mentor import mentor_agent
|
| 9 |
+
from agents.prompts import supervisor_prompt
|
| 10 |
|
| 11 |
load_dotenv()
|
| 12 |
|
| 13 |
|
| 14 |
model = init_chat_model("gemini-2.0-flash", model_provider="google_genai")
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
supervisor = create_supervisor(
|
| 17 |
model=model,
|
| 18 |
agents=[shopper_agent, craft_research_agent, mentor_agent],
|
agents/prompts.py
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain.prompts import PromptTemplate
|
| 2 |
+
|
| 3 |
+
language_detection_prompt = PromptTemplate.from_template(
|
| 4 |
+
"""Given the name or description of a craft: "{craft}", determine which language would likely return the most useful search results online.
|
| 5 |
+
Respond only with the name of the language (e.g. 'Bulgarian', 'Japanese', 'English')."""
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
translate_prompt = PromptTemplate.from_template(
|
| 9 |
+
"""Translate the following text into English:
|
| 10 |
+
|
| 11 |
+
---
|
| 12 |
+
{text}
|
| 13 |
+
---
|
| 14 |
+
"""
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
summarize_prompt = PromptTemplate.from_template(
|
| 18 |
+
"""Summarize the following content as a craft introduction for beginners. Include what the craft is, materials used, and a basic starting point:
|
| 19 |
+
|
| 20 |
+
---
|
| 21 |
+
{text}
|
| 22 |
+
---
|
| 23 |
+
"""
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
research_agent_prompt = PromptTemplate.from_template(
|
| 27 |
+
"""
|
| 28 |
+
You are a helpful craft researcher assistant.
|
| 29 |
+
|
| 30 |
+
Your job is to research traditional or exotic crafts — such as Bulgarian lacework — using reliable online sources (in the language of origin if needed), and return a beginner-friendly summary that teaches the user what the craft is and how to get started.
|
| 31 |
+
Use the available tools to find the relevant information.
|
| 32 |
+
Please follow this exact structure in your response:
|
| 33 |
+
|
| 34 |
+
=== What is it? ===
|
| 35 |
+
Explain what this craft is, where it comes from, and what makes it unique or culturally important.
|
| 36 |
+
|
| 37 |
+
=== Types or Styles ===
|
| 38 |
+
If relevant, briefly describe any subtypes, styles, or traditions within the craft (if they exist). If not relevant, exclude this section from the answer.
|
| 39 |
+
|
| 40 |
+
=== Materials Needed ===
|
| 41 |
+
List the essential tools or materials required to practice the craft.
|
| 42 |
+
|
| 43 |
+
=== How to Get Started ===
|
| 44 |
+
Explain how a beginner can start — mention basic techniques, patterns, or entry-level projects.
|
| 45 |
+
|
| 46 |
+
=== Cultural or Historical Context ===
|
| 47 |
+
Add interesting background info if available (e.g., where/when it was traditionally practiced).
|
| 48 |
+
|
| 49 |
+
Keep the tone friendly, and informative — like you're introducing the craft to someone who's curious but knows nothing yet.
|
| 50 |
+
|
| 51 |
+
DO NOT add any introduction or closing lines. Just return the structured content above.
|
| 52 |
+
"""
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
shopper_prompt = PromptTemplate.from_template(
|
| 56 |
+
"""
|
| 57 |
+
You are a shopper agent specifically designed for shopping for craft tools and supplies.
|
| 58 |
+
Given a list of supplies (e.g. 300g silk yarn, 3mm needles), your task is to find online shops or physical shops on Google Maps where the supplies can be bought.
|
| 59 |
+
Additionally, you need to calculate the total estimated cost of the craft project based on the needed and available supplies.
|
| 60 |
+
INSTRUCTIONS:
|
| 61 |
+
- For every item in the supplies list, make a Google search to find relevant online shops in the user's location.
|
| 62 |
+
- If possible, infer the item prices in the online shops and calculate the total estimated cost of the project based on the retrieved prices per item and available math tools (add, divide, multiply).
|
| 63 |
+
- If for some products you cannot infer prices, just say you don't know how much the item will cost.
|
| 64 |
+
- In addition, search for physical stores on Google Maps in the user's location and return them as an alternative.
|
| 65 |
+
- Return the list of items with where to buy them, and the total cost of the project.
|
| 66 |
+
"""
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
supervisor_prompt = """
|
| 70 |
+
✨ You are **Craftwise**, the spirited guide who turns hazy curiosity into handmade joy.
|
| 71 |
+
|
| 72 |
+
Welcome every visitor like they've just stepped into a cozy, sunlit studio—brimming with yarn, paper, and ideas. Ask one gentle question at a time to uncover three key sparks:
|
| 73 |
+
|
| 74 |
+
• **The craft** that's calling them (origami? knitting? lace from distant lands?)
|
| 75 |
+
• **Their experience** (fresh explorer, steady apprentice, seasoned artisan?)
|
| 76 |
+
• **Their dream creation** (a flying crane, a scarf, a doily like frost?)
|
| 77 |
+
|
| 78 |
+
🌿 Let curiosity bloom slowly—ask only one question at a time. If they're unsure, offer two or three vivid paths to inspire them.
|
| 79 |
+
|
| 80 |
+
Once their project takes shape, share a short, uplifting roadmap: key techniques, a simple tool list, and how to begin. Keep it clear, bright, and encouraging—more tale than textbook.
|
| 81 |
+
|
| 82 |
+
You may call these helpers anytime, in any order:
|
| 83 |
+
- ✧ **craft_research_agent** for global tips, folklore, or hidden knowledge.
|
| 84 |
+
- ✧ **shopper_agent** to check local craft supplies (ask where they live!) and estimate the cost of their planned project.
|
| 85 |
+
- ✧ **mentor_agent** to help with specific craft terminology and offer ideas/guidance based on written tutorials from the Internet. You can also use YouTube searches.
|
| 86 |
+
|
| 87 |
+
🛑 Never say "I will check", "I've asked", or "I'll share it soon."
|
| 88 |
+
🟢 If you need help from an agent (like finding local shops), **invoke the agent right away** and **wait for the result before replying**. If the result contains web links, never change the web links.
|
| 89 |
+
Output the web links as they are. Once the result is available, **integrate it directly into your message**—as if it came from your own memory.
|
| 90 |
+
|
| 91 |
+
When agents reply, weave their answers into your story: no "the tool says..."—just seamless, warm guidance.
|
| 92 |
+
|
| 93 |
+
Speak gently. Spark wonder. And always end with an inviting next step:
|
| 94 |
+
*"Shall we gather your supplies?"* or *"Shall we fold the first wing?"*
|
| 95 |
+
|
| 96 |
+
"""
|
| 97 |
+
|
| 98 |
+
video_intent_prompt = PromptTemplate.from_template("""
|
| 99 |
+
You are a helpful assistant that determines whether a user is asking for a video tutorial explicitly.
|
| 100 |
+
Answer only \"yes\" or \"no\". If there's no mention of the user asking for a video tutorial, always return no.
|
| 101 |
+
|
| 102 |
+
User message: {message}
|
| 103 |
+
""")
|
| 104 |
+
|
| 105 |
+
extraction_prompt = PromptTemplate.from_template("""
|
| 106 |
+
You are an assistant that extracts structured information from a conversation between a user and an assistant.
|
| 107 |
+
Extract the following fields:
|
| 108 |
+
1. project – what the user wants to create or work on (e.g., paper crane, knitted scarf)
|
| 109 |
+
2. craft – what type of craft it involves (e.g., origami, knitting, crochet)
|
| 110 |
+
3. experience level – the user's skill level (one of beginner, intermediate, advanced, or "\"). If you cannot classify as beginner, intermediate, advanced, return empty string as a value
|
| 111 |
+
4. query - this refers to what the user is actually looking for, it can be the project itself (e.g. knitting) or a specific technique related to it (e.g. how to cast on). Return the query as 3 words max.
|
| 112 |
+
Return ONLY a JSON object with these keys: "project", "craft", "experience_level", "query".
|
| 113 |
+
|
| 114 |
+
Conversation:
|
| 115 |
+
{conversation}
|
| 116 |
+
""")
|
agents/researcher.py
CHANGED
|
@@ -3,11 +3,17 @@ from langchain.chat_models import init_chat_model
|
|
| 3 |
from langgraph.prebuilt import create_react_agent
|
| 4 |
from langchain.tools import tool
|
| 5 |
from langchain_community.tools.tavily_search import TavilySearchResults
|
| 6 |
-
from langchain.prompts import PromptTemplate
|
| 7 |
from langchain.chains.llm import LLMChain
|
| 8 |
from langchain_core.messages import SystemMessage
|
| 9 |
from langchain_core.output_parsers.string import StrOutputParser
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
load_dotenv()
|
| 13 |
|
|
@@ -15,12 +21,6 @@ load_dotenv()
|
|
| 15 |
model = init_chat_model("gemini-2.0-flash", model_provider="google_genai")
|
| 16 |
|
| 17 |
|
| 18 |
-
# Prompt template
|
| 19 |
-
language_detection_prompt = PromptTemplate.from_template(
|
| 20 |
-
"""Given the name or description of a craft: "{craft}", determine which language would likely return the most useful search results online.
|
| 21 |
-
Respond only with the name of the language (e.g. 'Bulgarian', 'Japanese', 'English')."""
|
| 22 |
-
)
|
| 23 |
-
|
| 24 |
# Chain using your model
|
| 25 |
language_detection_chain = LLMChain(llm=model, prompt=language_detection_prompt, output_parser=StrOutputParser())
|
| 26 |
|
|
@@ -39,14 +39,6 @@ def web_search_in_language(query: str) -> str:
|
|
| 39 |
return search_tool.run(query)
|
| 40 |
|
| 41 |
# Tool 3: Translate text to English
|
| 42 |
-
translate_prompt = PromptTemplate.from_template(
|
| 43 |
-
"""Translate the following text into English:
|
| 44 |
-
|
| 45 |
-
---
|
| 46 |
-
{text}
|
| 47 |
-
---
|
| 48 |
-
"""
|
| 49 |
-
)
|
| 50 |
translate_chain = LLMChain(llm=model, prompt=translate_prompt, output_parser=StrOutputParser())
|
| 51 |
|
| 52 |
@tool
|
|
@@ -63,14 +55,6 @@ def translate_to_english(text: str) -> str:
|
|
| 63 |
|
| 64 |
|
| 65 |
# Tool 4: Summarize translated content
|
| 66 |
-
summarize_prompt = PromptTemplate.from_template(
|
| 67 |
-
"""Summarize the following content as a craft introduction for beginners. Include what the craft is, materials used, and a basic starting point:
|
| 68 |
-
|
| 69 |
-
---
|
| 70 |
-
{text}
|
| 71 |
-
---
|
| 72 |
-
"""
|
| 73 |
-
)
|
| 74 |
summarize_chain = LLMChain(llm=model, prompt=summarize_prompt, output_parser=StrOutputParser())
|
| 75 |
|
| 76 |
@tool
|
|
@@ -86,35 +70,6 @@ def summarize_craft_intro(text: str) -> str:
|
|
| 86 |
return summarize_chain.run({"text": text})
|
| 87 |
|
| 88 |
|
| 89 |
-
research_agent_prompt = PromptTemplate.from_template(
|
| 90 |
-
"""
|
| 91 |
-
You are a helpful craft researcher assistant.
|
| 92 |
-
|
| 93 |
-
Your job is to research traditional or exotic crafts — such as Bulgarian lacework — using reliable online sources (in the language of origin if needed), and return a beginner-friendly summary that teaches the user what the craft is and how to get started.
|
| 94 |
-
Use the available tools to find the relevant information.
|
| 95 |
-
Please follow this exact structure in your response:
|
| 96 |
-
|
| 97 |
-
=== What is it? ===
|
| 98 |
-
Explain what this craft is, where it comes from, and what makes it unique or culturally important.
|
| 99 |
-
|
| 100 |
-
=== Types or Styles ===
|
| 101 |
-
If relevant, briefly describe any subtypes, styles, or traditions within the craft (if they exist). If not relevant, exclude this section from the answer.
|
| 102 |
-
|
| 103 |
-
=== Materials Needed ===
|
| 104 |
-
List the essential tools or materials required to practice the craft.
|
| 105 |
-
|
| 106 |
-
=== How to Get Started ===
|
| 107 |
-
Explain how a beginner can start — mention basic techniques, patterns, or entry-level projects.
|
| 108 |
-
|
| 109 |
-
=== Cultural or Historical Context ===
|
| 110 |
-
Add interesting background info if available (e.g., where/when it was traditionally practiced).
|
| 111 |
-
|
| 112 |
-
Keep the tone friendly, and informative — like you're introducing the craft to someone who’s curious but knows nothing yet.
|
| 113 |
-
|
| 114 |
-
DO NOT add any introduction or closing lines. Just return the structured content above.
|
| 115 |
-
"""
|
| 116 |
-
)
|
| 117 |
-
|
| 118 |
# Define the agent
|
| 119 |
craft_research_agent = create_react_agent(
|
| 120 |
model=model,
|
|
|
|
| 3 |
from langgraph.prebuilt import create_react_agent
|
| 4 |
from langchain.tools import tool
|
| 5 |
from langchain_community.tools.tavily_search import TavilySearchResults
|
|
|
|
| 6 |
from langchain.chains.llm import LLMChain
|
| 7 |
from langchain_core.messages import SystemMessage
|
| 8 |
from langchain_core.output_parsers.string import StrOutputParser
|
| 9 |
|
| 10 |
+
from agents.prompts import (
|
| 11 |
+
language_detection_prompt,
|
| 12 |
+
research_agent_prompt,
|
| 13 |
+
summarize_prompt,
|
| 14 |
+
translate_prompt,
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
|
| 18 |
load_dotenv()
|
| 19 |
|
|
|
|
| 21 |
model = init_chat_model("gemini-2.0-flash", model_provider="google_genai")
|
| 22 |
|
| 23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
# Chain using your model
|
| 25 |
language_detection_chain = LLMChain(llm=model, prompt=language_detection_prompt, output_parser=StrOutputParser())
|
| 26 |
|
|
|
|
| 39 |
return search_tool.run(query)
|
| 40 |
|
| 41 |
# Tool 3: Translate text to English
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
translate_chain = LLMChain(llm=model, prompt=translate_prompt, output_parser=StrOutputParser())
|
| 43 |
|
| 44 |
@tool
|
|
|
|
| 55 |
|
| 56 |
|
| 57 |
# Tool 4: Summarize translated content
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
summarize_chain = LLMChain(llm=model, prompt=summarize_prompt, output_parser=StrOutputParser())
|
| 59 |
|
| 60 |
@tool
|
|
|
|
| 70 |
return summarize_chain.run({"text": text})
|
| 71 |
|
| 72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
# Define the agent
|
| 74 |
craft_research_agent = create_react_agent(
|
| 75 |
model=model,
|
agents/shopper.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
|
| 2 |
import os
|
| 3 |
import googlemaps
|
| 4 |
from dotenv import load_dotenv
|
|
@@ -6,10 +5,10 @@ from langgraph.prebuilt import create_react_agent
|
|
| 6 |
from langchain.chat_models import init_chat_model
|
| 7 |
from langchain.tools import tool
|
| 8 |
from langchain_community.tools.tavily_search import TavilySearchResults
|
| 9 |
-
from langchain_core.prompts import PromptTemplate
|
| 10 |
from langchain_core.messages import SystemMessage
|
| 11 |
from googlemaps.places import places_nearby
|
| 12 |
from geopy.geocoders import Nominatim
|
|
|
|
| 13 |
|
| 14 |
|
| 15 |
load_dotenv()
|
|
@@ -102,19 +101,7 @@ def find_products_with_prices(query: str) -> str:
|
|
| 102 |
|
| 103 |
return "\n\n".join(output) if output else "No results found."
|
| 104 |
|
| 105 |
-
|
| 106 |
-
"""
|
| 107 |
-
You are a shopper agent specifically designed for shopping for craft tools and supplies.
|
| 108 |
-
Given a list of supplies (e.g. 300g silk yarn, 3mm needles), your task is to find online shops or physical shops on Google Maps where the supplies can be bought.
|
| 109 |
-
Additionally, you need to calculate the total estimated cost of the craft project based on the needed and available supplies.
|
| 110 |
-
INSTRUCTIONS:
|
| 111 |
-
- For every item in the supplies list, make a Google search to find relevant online shops in the user's location.
|
| 112 |
-
- If possible, infer the item prices in the online shops and calculate the total estimated cost of the project based on the retrieved prices per item and available math tools (add, divide, multiply).
|
| 113 |
-
- If for some products you cannot infer prices, just say you don't know how much the item will cost.
|
| 114 |
-
- In addition, search for physical stores on Google Maps in the user's location and return them as an alternative.
|
| 115 |
-
- Return the list of items with where to buy them, and the total cost of the project.
|
| 116 |
-
"""
|
| 117 |
-
)
|
| 118 |
|
| 119 |
shopper_agent = create_react_agent(
|
| 120 |
model=model,
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import googlemaps
|
| 3 |
from dotenv import load_dotenv
|
|
|
|
| 5 |
from langchain.chat_models import init_chat_model
|
| 6 |
from langchain.tools import tool
|
| 7 |
from langchain_community.tools.tavily_search import TavilySearchResults
|
|
|
|
| 8 |
from langchain_core.messages import SystemMessage
|
| 9 |
from googlemaps.places import places_nearby
|
| 10 |
from geopy.geocoders import Nominatim
|
| 11 |
+
from agents.prompts import shopper_prompt
|
| 12 |
|
| 13 |
|
| 14 |
load_dotenv()
|
|
|
|
| 101 |
|
| 102 |
return "\n\n".join(output) if output else "No results found."
|
| 103 |
|
| 104 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
shopper_agent = create_react_agent(
|
| 107 |
model=model,
|
app.py
CHANGED
|
@@ -15,6 +15,7 @@ from agents.planner import supervisor
|
|
| 15 |
from utils.custom_css import CUSTOM_CSS
|
| 16 |
from utils.search import search_youtube
|
| 17 |
from utils.state import CraftState
|
|
|
|
| 18 |
|
| 19 |
load_dotenv()
|
| 20 |
|
|
@@ -35,13 +36,6 @@ state = {
|
|
| 35 |
|
| 36 |
main_state = CraftState()
|
| 37 |
|
| 38 |
-
video_intent_prompt = PromptTemplate.from_template("""
|
| 39 |
-
You are a helpful assistant that determines whether a user is asking for a video tutorial explicitly.
|
| 40 |
-
Answer only "yes" or "no". If there's no mention of the user asking for a video tutorial, always return no.
|
| 41 |
-
|
| 42 |
-
User message: {message}
|
| 43 |
-
""")
|
| 44 |
-
|
| 45 |
def detect_video_request(state: CraftState, model: Runnable, messages) -> CraftState:
|
| 46 |
experience = extract_project_craft_experience(messages=messages, model=model)
|
| 47 |
state.project = experience['project']
|
|
@@ -119,21 +113,6 @@ def encode_file_to_media_message(file_path: str):
|
|
| 119 |
return [{"type": "text", "text": "Unsupported file type uploaded."}]
|
| 120 |
|
| 121 |
|
| 122 |
-
|
| 123 |
-
# Define prompt template
|
| 124 |
-
extraction_prompt = PromptTemplate.from_template("""
|
| 125 |
-
You are an assistant that extracts structured information from a conversation between a user and an assistant.
|
| 126 |
-
Extract the following fields:
|
| 127 |
-
1. project – what the user wants to create or work on (e.g., paper crane, knitted scarf)
|
| 128 |
-
2. craft – what type of craft it involves (e.g., origami, knitting, crochet)
|
| 129 |
-
3. experience level – the user's skill level (one of beginner, intermediate, advanced, or ""). If you cannot classify as beginner, intermediate, advanced, return empty string as a value
|
| 130 |
-
4. query - this refers to what the user is actually looking for, it can be the project itself (e.g. knitting) or a specific technique related to it (e.g. how to cast on). Return the query as 3 words max.
|
| 131 |
-
Return ONLY a JSON object with these keys: "project", "craft", "experience_level", "query".
|
| 132 |
-
|
| 133 |
-
Conversation:
|
| 134 |
-
{conversation}
|
| 135 |
-
""")
|
| 136 |
-
|
| 137 |
# Function to extract structured data
|
| 138 |
def extract_project_craft_experience(messages: list, model: Runnable) -> dict:
|
| 139 |
conversation = "\n".join(
|
|
@@ -153,7 +132,6 @@ def extract_project_craft_experience(messages: list, model: Runnable) -> dict:
|
|
| 153 |
}
|
| 154 |
|
| 155 |
|
| 156 |
-
|
| 157 |
def chat_with_agent(message, history):
|
| 158 |
# Convert history to LangChain messages
|
| 159 |
messages = []
|
|
|
|
| 15 |
from utils.custom_css import CUSTOM_CSS
|
| 16 |
from utils.search import search_youtube
|
| 17 |
from utils.state import CraftState
|
| 18 |
+
from agents.prompts import video_intent_prompt, extraction_prompt
|
| 19 |
|
| 20 |
load_dotenv()
|
| 21 |
|
|
|
|
| 36 |
|
| 37 |
main_state = CraftState()
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
def detect_video_request(state: CraftState, model: Runnable, messages) -> CraftState:
|
| 40 |
experience = extract_project_craft_experience(messages=messages, model=model)
|
| 41 |
state.project = experience['project']
|
|
|
|
| 113 |
return [{"type": "text", "text": "Unsupported file type uploaded."}]
|
| 114 |
|
| 115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
# Function to extract structured data
|
| 117 |
def extract_project_craft_experience(messages: list, model: Runnable) -> dict:
|
| 118 |
conversation = "\n".join(
|
|
|
|
| 132 |
}
|
| 133 |
|
| 134 |
|
|
|
|
| 135 |
def chat_with_agent(message, history):
|
| 136 |
# Convert history to LangChain messages
|
| 137 |
messages = []
|
utils/analysis.py
CHANGED
|
@@ -14,14 +14,6 @@ def _encode_file(file_path: str) -> str:
|
|
| 14 |
return base64.b64encode(f.read()).decode("utf-8")
|
| 15 |
|
| 16 |
|
| 17 |
-
def safe_json_parse(obj):
|
| 18 |
-
if isinstance(obj, str):
|
| 19 |
-
return json.loads(obj)
|
| 20 |
-
elif isinstance(obj, dict):
|
| 21 |
-
return obj # already parsed
|
| 22 |
-
else:
|
| 23 |
-
raise TypeError(f"Expected JSON string or dict, got {type(obj)}")
|
| 24 |
-
|
| 25 |
def extract_json(response: str) -> dict:
|
| 26 |
# Match inside ```json ... ```
|
| 27 |
match = re.search(r"```(?:json)?\s*({.*?})\s*```", response, re.DOTALL)
|
|
|
|
| 14 |
return base64.b64encode(f.read()).decode("utf-8")
|
| 15 |
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
def extract_json(response: str) -> dict:
|
| 18 |
# Match inside ```json ... ```
|
| 19 |
match = re.search(r"```(?:json)?\s*({.*?})\s*```", response, re.DOTALL)
|