Spaces:
Sleeping
Sleeping
Commit
·
6874dac
1
Parent(s):
fa8520f
Next commit
Browse files- __pycache__/main.cpython-312.pyc +0 -0
- brainstroming_agent/utils/__pycache__/prompts.cpython-312.pyc +0 -0
- brainstroming_agent/utils/__pycache__/tools.cpython-312.pyc +0 -0
- brainstroming_agent/utils/__pycache__/utils.cpython-312.pyc +0 -0
- brainstroming_agent/utils/prompts.py +26 -22
- brainstroming_agent/utils/tools.py +49 -0
- brainstroming_agent/utils/utils.py +26 -13
- dummy_state.py +53 -51
- human_refined_ideation/utils/prompts.py +1 -0
- ideation_agent/utils/__pycache__/nodes.cpython-312.pyc +0 -0
- ideation_agent/utils/__pycache__/prompts.cpython-312.pyc +0 -0
- ideation_agent/utils/__pycache__/state.cpython-312.pyc +0 -0
- ideation_agent/utils/nodes.py +4 -3
- ideation_agent/utils/prompts.py +5 -1
- ideation_agent/utils/state.py +1 -0
- main.py +33 -16
- orchestration_agent/agent.py +15 -8
- orchestration_agent/utils/nodes.py +19 -8
- orchestration_agent/utils/prompts.py +153 -25
- orchestration_agent/utils/state.py +16 -3
- orchestration_agent/utils/tools.py +45 -0
- orchestration_agent/utils/utils.py +31 -0
- test.py +52 -0
- utils/__pycache__/data_loader.cpython-312.pyc +0 -0
- utils/__pycache__/models_loader.cpython-312.pyc +0 -0
- utils/data_loader.py +2 -2
- utils/models_loader.py +16 -9
__pycache__/main.cpython-312.pyc
CHANGED
|
Binary files a/__pycache__/main.cpython-312.pyc and b/__pycache__/main.cpython-312.pyc differ
|
|
|
brainstroming_agent/utils/__pycache__/prompts.cpython-312.pyc
CHANGED
|
Binary files a/brainstroming_agent/utils/__pycache__/prompts.cpython-312.pyc and b/brainstroming_agent/utils/__pycache__/prompts.cpython-312.pyc differ
|
|
|
brainstroming_agent/utils/__pycache__/tools.cpython-312.pyc
CHANGED
|
Binary files a/brainstroming_agent/utils/__pycache__/tools.cpython-312.pyc and b/brainstroming_agent/utils/__pycache__/tools.cpython-312.pyc differ
|
|
|
brainstroming_agent/utils/__pycache__/utils.cpython-312.pyc
CHANGED
|
Binary files a/brainstroming_agent/utils/__pycache__/utils.cpython-312.pyc and b/brainstroming_agent/utils/__pycache__/utils.cpython-312.pyc differ
|
|
|
brainstroming_agent/utils/prompts.py
CHANGED
|
@@ -74,27 +74,31 @@ Only generate ideas that have **not already appeared** in the storyline.
|
|
| 74 |
|
| 75 |
|
| 76 |
def final_story_prompt(final_state):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
return(
|
| 78 |
-
|
| 79 |
-
You are a senior video content strategist responsible for crafting the **final, polished storyline** for a promotional video. This will be the definitive version, so it must be complete, well-structured, visually rich, and highly satisfying to the client.
|
| 80 |
-
|
| 81 |
-
You will be provided with:
|
| 82 |
-
- A **video idea** by a human,
|
| 83 |
-
- A list of **preferred focus topics** (brainstormed and selected),
|
| 84 |
-
- Detailed **business information**, and
|
| 85 |
-
- **Influencer-generated content** as creative reference (not mandatory to include directly).
|
| 86 |
-
|
| 87 |
-
**Your task**:
|
| 88 |
-
Generate a **scene-by-scene video storyline** in around 300 words that:
|
| 89 |
-
- Fully aligns with the business goals and identity (fun, emotional, luxurious, or professional),
|
| 90 |
-
- Strongly integrates all preferred topics from the human (these represent the core focus),
|
| 91 |
-
- Uses influencer data and image cues **only as inspiration** for tone, emotion, or visual cues,
|
| 92 |
-
- Is logically structured (beginning, middle, end) and cinematic in detail,
|
| 93 |
-
- Ensures each scene flows into the next, building engagement and narrative strength.
|
| 94 |
-
|
| 95 |
-
This is the final creative delivery. The storyline should feel **complete, emotionally resonant, and visually engaging** — ready for a director to begin production.
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
You have to strongly focus on these topics while creating the storyline: {[item for sublist in final_state['preferred_topics'] for item in sublist]}'''
|
| 99 |
-
)
|
| 100 |
|
|
|
|
| 74 |
|
| 75 |
|
| 76 |
def final_story_prompt(final_state):
|
| 77 |
+
if 'preferred_topics' in final_state:
|
| 78 |
+
important_part= f'''**Very Important**
|
| 79 |
+
You have to strongly focus on these topics while creating the storyline: {[item for sublist in final_state['preferred_topics'] for item in sublist]}'''
|
| 80 |
+
else:
|
| 81 |
+
important_part=''
|
| 82 |
+
|
| 83 |
return(
|
| 84 |
+
f'''
|
| 85 |
+
You are a senior video content strategist responsible for crafting the **final, polished storyline** for a promotional video. This will be the definitive version, so it must be complete, well-structured, visually rich, and highly satisfying to the client.
|
| 86 |
+
|
| 87 |
+
You will be provided with:
|
| 88 |
+
- A **video idea** by a human,
|
| 89 |
+
- A list of **preferred focus topics** (brainstormed and selected),
|
| 90 |
+
- Detailed **business information**, and
|
| 91 |
+
- **Influencer-generated content** as creative reference (not mandatory to include directly).
|
| 92 |
+
|
| 93 |
+
**Your task**:
|
| 94 |
+
Generate a **scene-by-scene video storyline** in around 300 words that:
|
| 95 |
+
- Fully aligns with the business goals and identity (fun, emotional, luxurious, or professional),
|
| 96 |
+
- Strongly integrates all preferred topics from the human (these represent the core focus),
|
| 97 |
+
- Uses influencer data and image cues **only as inspiration** for tone, emotion, or visual cues,
|
| 98 |
+
- Is logically structured (beginning, middle, end) and cinematic in detail,
|
| 99 |
+
- Ensures each scene flows into the next, building engagement and narrative strength.
|
| 100 |
+
|
| 101 |
+
This is the final creative delivery. The storyline should feel **complete, emotionally resonant, and visually engaging** — ready for a director to begin production.
|
| 102 |
+
{important_part}'''
|
| 103 |
+
)
|
|
|
|
|
|
|
| 104 |
|
brainstroming_agent/utils/tools.py
CHANGED
|
@@ -64,3 +64,52 @@ def retrieve_tool(video_topic):
|
|
| 64 |
outer_list.append(inner_list)
|
| 65 |
|
| 66 |
return str(outer_list)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
outer_list.append(inner_list)
|
| 65 |
|
| 66 |
return str(outer_list)
|
| 67 |
+
|
| 68 |
+
def retrieve_manual(video_topic):
|
| 69 |
+
'''
|
| 70 |
+
Always invoke this tool.
|
| 71 |
+
Retrieve influencer's data by semantic search of **video topic**.
|
| 72 |
+
'''
|
| 73 |
+
# === Load CSV ===
|
| 74 |
+
csv_path = 'extracted_data.csv'
|
| 75 |
+
df = pd.read_csv(csv_path)
|
| 76 |
+
|
| 77 |
+
# === Parse stored embeddings ===
|
| 78 |
+
df['embeddings'] = df['embeddings'].apply(lambda x: ast.literal_eval(x) if isinstance(x, str) else x)
|
| 79 |
+
embeddings = np.vstack(df['embeddings'].values).astype('float32')
|
| 80 |
+
|
| 81 |
+
# === Build FAISS index ===
|
| 82 |
+
dimension = embeddings.shape[1]
|
| 83 |
+
index = faiss.IndexFlatL2(dimension)
|
| 84 |
+
index.add(embeddings)
|
| 85 |
+
|
| 86 |
+
# === Load SentenceTransformer model ===
|
| 87 |
+
|
| 88 |
+
# === Encode the query and search ===
|
| 89 |
+
query_embedding = ST.encode(str(video_topic)).reshape(1, -1).astype('float32')
|
| 90 |
+
top_k=5
|
| 91 |
+
distances, indices = index.search(query_embedding, top_k)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
# === Format results ===
|
| 96 |
+
outer_list = []
|
| 97 |
+
for i, idx in enumerate(indices[0]):
|
| 98 |
+
res = {
|
| 99 |
+
'rank': i + 1,
|
| 100 |
+
'username': df.iloc[idx]['username'],
|
| 101 |
+
'story': df.iloc[idx]['story'],
|
| 102 |
+
'visible_text_or_brandings': df.iloc[idx]['visible_texts_or_brandings'],
|
| 103 |
+
'likesCount': df.iloc[idx]['likesCount'],
|
| 104 |
+
'commentCount': df.iloc[idx]['commentCount'],
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
inner_list = []
|
| 108 |
+
inner_list.append(f"[{res['rank']}]. The influencer name is: **{res['username']}** — Likes: **{res['likesCount']}**, Comments: **{res['commentCount']}**")
|
| 109 |
+
inner_list.append(f"The story of that particular video is:\n{res['story']}")
|
| 110 |
+
inner_list.append(f"The branding or promotion done is:\n{res['visible_text_or_brandings']}")
|
| 111 |
+
|
| 112 |
+
outer_list.append(inner_list)
|
| 113 |
+
|
| 114 |
+
return str(outer_list)
|
| 115 |
+
|
brainstroming_agent/utils/utils.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
|
| 2 |
from langchain_core.messages import SystemMessage, ToolMessage, HumanMessage
|
| 3 |
-
from .tools import retrieve_tool
|
| 4 |
import base64
|
| 5 |
from PIL import Image
|
| 6 |
from io import BytesIO
|
|
@@ -19,25 +19,38 @@ from utils.models_loader import ST , llm
|
|
| 19 |
|
| 20 |
|
| 21 |
|
|
|
|
| 22 |
def generate_final_story(final_state):
|
| 23 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
template = final_story_prompt(final_state)
|
|
|
|
| 25 |
messages = [SystemMessage(content=template),
|
| 26 |
-
|
| 27 |
-
ToolMessage(content=f'''The business details is:\n{final_state['business_details']}\nThe data of influencers is:\n{final_state['retrievals'][-1]}''',tool_call_id='final_story_tool')]
|
| 28 |
-
print('The message of final story:',messages)
|
| 29 |
-
|
| 30 |
react_agent=create_react_agent(
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
response = react_agent.invoke({'messages':messages})
|
| 35 |
response = response['messages'][-1].content
|
| 36 |
return response
|
| 37 |
-
|
| 38 |
-
else:
|
| 39 |
-
return final_state['stories'][-1]
|
| 40 |
-
|
| 41 |
|
| 42 |
|
| 43 |
def encode_image_to_base64(uploaded_file: UploadFile) -> str:
|
|
|
|
| 1 |
|
| 2 |
from langchain_core.messages import SystemMessage, ToolMessage, HumanMessage
|
| 3 |
+
from .tools import retrieve_tool , retrieve_manual
|
| 4 |
import base64
|
| 5 |
from PIL import Image
|
| 6 |
from io import BytesIO
|
|
|
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
+
|
| 23 |
def generate_final_story(final_state):
|
| 24 |
+
if 'preferred_topics' in final_state:
|
| 25 |
+
if len(final_state['preferred_topics'])>0:
|
| 26 |
+
template = final_story_prompt(final_state)
|
| 27 |
+
messages = [SystemMessage(content=template),
|
| 28 |
+
HumanMessage(content=f'''The idea of the video is:\n{final_state['idea']}\n '''),
|
| 29 |
+
ToolMessage(content=f'''The business details is:\n{final_state['business_details']}\nThe data of influencers is:\n{final_state['retrievals'][-1]}''',tool_call_id='final_story_tool')]
|
| 30 |
+
print('The message of final story:',messages)
|
| 31 |
+
|
| 32 |
+
react_agent=create_react_agent(
|
| 33 |
+
model=llm,
|
| 34 |
+
tools=[])
|
| 35 |
+
|
| 36 |
+
response = react_agent.invoke({'messages':messages})
|
| 37 |
+
response = response['messages'][-1].content
|
| 38 |
+
return response
|
| 39 |
+
|
| 40 |
+
else:
|
| 41 |
+
return final_state['stories'][-1]
|
| 42 |
+
else:
|
| 43 |
template = final_story_prompt(final_state)
|
| 44 |
+
influencers_data = retrieve_manual(final_state)
|
| 45 |
messages = [SystemMessage(content=template),
|
| 46 |
+
ToolMessage(content=f'''The business details is:\n{str(final_state)}\nThe data of influencers is:\n{influencers_data}''',tool_call_id='final_story_tool')]
|
|
|
|
|
|
|
|
|
|
| 47 |
react_agent=create_react_agent(
|
| 48 |
+
model=llm,
|
| 49 |
+
tools=[])
|
|
|
|
| 50 |
response = react_agent.invoke({'messages':messages})
|
| 51 |
response = response['messages'][-1].content
|
| 52 |
return response
|
| 53 |
+
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
|
| 56 |
def encode_image_to_base64(uploaded_file: UploadFile) -> str:
|
dummy_state.py
CHANGED
|
@@ -17,56 +17,58 @@ stored_data['final_ideation']= ['''A street magician performs tricks, leaving a
|
|
| 17 |
'''A young Nepali woman discovers a hidden strength within herself while hiking the Himalayas. She returns home, and her fitness journey begins at our gym. With the help of our personal trainers, she transforms her body and mind. The gym becomes her sanctuary, and her transformation inspires others to find their inner strength.''']
|
| 18 |
|
| 19 |
stored_data['human_ideation_interactions'] = []
|
| 20 |
-
stored_data['refined_ideation'] = '''A street magician's trick fails, inspiring a fitness journey. Months later, he fuses magic with strength, showcasing transformation. Meanwhile, a fitness coach bonds with foodies over health, sparking a community workout group, blending fun and fitness.'''
|
| 21 |
|
| 22 |
|
| 23 |
-
stored_data['brainstroming_response']={
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
|
|
| 17 |
'''A young Nepali woman discovers a hidden strength within herself while hiking the Himalayas. She returns home, and her fitness journey begins at our gym. With the help of our personal trainers, she transforms her body and mind. The gym becomes her sanctuary, and her transformation inspires others to find their inner strength.''']
|
| 18 |
|
| 19 |
stored_data['human_ideation_interactions'] = []
|
| 20 |
+
# stored_data['refined_ideation'] = '''A street magician's trick fails, inspiring a fitness journey. Months later, he fuses magic with strength, showcasing transformation. Meanwhile, a fitness coach bonds with foodies over health, sparking a community workout group, blending fun and fitness.'''
|
| 21 |
|
| 22 |
|
| 23 |
+
# stored_data['brainstroming_response']={
|
| 24 |
+
# "carry_on": 'false',
|
| 25 |
+
# "idea": [
|
| 26 |
+
# "A street magician performs tricks that leave a crowd in awe, but one trick falters, leading him to hit the gym for strength training. While hiking to find inspiration, he slips near a hidden waterfall, but a fitness enthusiast saves him. This encounter sparks a friendship, and together they form a hiking and fitness club, blending magic with nature and strength. Their journey inspires the community to embrace fitness as a way to transform lives, showcasing how personal growth can captivate and unite people."
|
| 27 |
+
# ],
|
| 28 |
+
# "brainstroming_topics": [
|
| 29 |
+
# {
|
| 30 |
+
# "topic1": "Incorporate a time-lapse sequence showcasing the magician's transformation from a city performer to a nature-loving fitness enthusiast, highlighting the contrast between urban and natural environments.",
|
| 31 |
+
# "topic2": "Introduce a subplot where the magician and the fitness enthusiast collaborate with local environmental organizations to promote eco-friendly fitness practices and community involvement.",
|
| 32 |
+
# "topic3": "Add a dramatic twist where the magician must overcome a personal fear or phobia, such as acrophobia, to complete a challenging hike or fitness feat, emphasizing the emotional and mental aspects of personal growth.",
|
| 33 |
+
# "topic4": "Develop a secondary character, a young and aspiring magician who joins the hiking and fitness club, allowing the story to explore mentorship, generational connections, and the passing of knowledge from one magician to the next."
|
| 34 |
+
# },
|
| 35 |
+
# {
|
| 36 |
+
# "topic1": "Incorporate a 'Member of the Month' segment, where a club member shares their personal transformation story, highlighting the impact of the club on their life, and showcasing their achievements through a mix of interviews, workout footage, and before-and-after photos.",
|
| 37 |
+
# "topic2": "Develop a 'Nature Escape' series, where the club organizes guided hikes and outdoor activities in unique, breathtaking locations, capturing the experiences through drone footage, time-lapses, and member testimonials, to inspire viewers to connect with nature and fitness.",
|
| 38 |
+
# "topic3": "Create a 'Fitness Challenge' series, where club members participate in fun, themed workouts, such as a 'Mountain Madness' hike or a 'River Run' challenge, and share their progress on social media using a branded hashtag, encouraging viewers to join in and share their own fitness journeys.",
|
| 39 |
+
# "topic4": "Produce a 'Behind-the-Scenes' documentary-style video, showcasing the club's community events, such as fitness festivals, charity runs, or wellness workshops, and highlighting the club's impact on the local community, to create an emotional connection with viewers and showcase the club's values and mission."
|
| 40 |
+
# }
|
| 41 |
+
# ],
|
| 42 |
+
# "preferred_topics": [],
|
| 43 |
+
# "stories": [
|
| 44 |
+
# "**Promotional Video Storyline: \"Transforming Lives through Fitness and Nature\"**\n\n**Scene 1: Introduction to the Street Magician**\nThe video opens with a street magician performing mesmerizing tricks for a crowd in a bustling city square. The magician's skills and charisma leave the audience in awe, with people clapping and cheering for more. This scene showcases the magician's talent and sets the tone for the story.\n\n**Scene 2: The Faltering Trick**\nAs the magician attempts a particularly complex trick, it falters, and the crowd's enthusiasm wanes. The magician, feeling defeated, realizes the need to improve physical strength and endurance to perfect the craft. This scene introduces the idea that even the most skilled individuals can face challenges and require personal growth.\n\n**Scene 3: Hitting the Gym**\nThe magician decides to join a gym to enhance physical strength and endurance. The scene cuts to a modern gym setting, where the magician begins a rigorous strength training program. This scene highlights the importance of fitness in achieving personal goals.\n\n**Scene 4: The Encounter with the Fitness Enthusiast**\nWhile hiking to find inspiration, the magician slips near a hidden waterfall and is saved by a fitness enthusiast. This chance encounter sparks a friendship between the two, as they bond over their shared passion for fitness and nature. The scene showcases the beauty of the natural environment and the importance of human connections.\n\n**Scene 5: Forming the Hiking and Fitness Club**\nThe magician and the fitness enthusiast decide to form a hiking and fitness club, blending magic with nature and strength. The club attracts like-minded individuals who share a passion for fitness, nature, and personal growth. This scene highlights the power of community and the transformative impact of shared experiences.\n\n**Scene 6: Inspiring the Community**\nAs the club grows, its members inspire the community to embrace fitness as a way to transform lives. The video showcases heartwarming moments of club members supporting and motivating each other, as well as the positive impact on their physical and mental well-being. This scene emphasizes the potential for fitness to unite people and drive personal growth.\n\n**Scene 7: The Grand Finale**\nThe video concludes with a grand finale, where the magician performs an awe-inspiring trick, combining magic with fitness and nature. The crowd is mesmerized, and the magician's journey comes full circle. The final scene reinforces the message that personal growth, fitness, and community can lead to extraordinary achievements.\n\n**Visuals and Tone:**\nThroughout the video, the tone will be a mix of fun, emotional, and professional, reflecting the brand's personality. The visuals will be engaging, with a balance of close-ups, wide shots, and aerial footage to showcase the beauty of nature and the magic of the performances. The color palette will be vibrant, with a focus on blues and greens to represent fitness, nature, and growth.\n\n**Influencer Content Inspiration:**\nThe video will draw inspiration from influencer content, such as the scenic hiking videos and fitness journeys shared by **divyadhakal_** and **munachiya**. The video will incorporate similar visual elements, such as breathtaking landscapes, to create an immersive experience for the audience.\n\n**Core Message:**\nThe video will align with the business's core message, highlighting the importance of fitness, community, and personal growth. The story will showcase how the brand's offerings, such as personal training, group fitness classes, and wellness programs, can help individuals transform their lives and achieve their goals.",
|
| 45 |
+
# "**Promotional Video Storyline: \"Transforming Lives through Fitness and Nature\"**\n\n**Scene 1: Introduction to the Street Magician**\nThe video opens with a street magician performing mesmerizing tricks for a crowd in a bustling city square. The magician's skills are impressive, leaving the audience in awe. However, during one trick, the magician falters, and the crowd gasps in disappointment.\n\n**Scene 2: The Magician's Journey to Self-Improvement**\nThe magician, determined to regain the crowd's admiration, decides to hit the gym for strength training. The scene cuts to the magician working out, sweating, and pushing themselves to improve their physical abilities.\n\n**Scene 3: Finding Inspiration in Nature**\nWhile hiking to find inspiration, the magician slips near a hidden waterfall. Just as they're about to fall, a fitness enthusiast, who is also an avid hiker, saves them. This encounter sparks a friendship between the two.\n\n**Scene 4: Forming a Hiking and Fitness Club**\nThe magician and the fitness enthusiast decide to form a hiking and fitness club, blending magic with nature and strength. The club's mission is to inspire others to transform their lives through fitness and outdoor activities.\n\n**Scene 5: Community Engagement and Growth**\nAs the club grows, the community becomes increasingly engaged. Members share their personal stories of transformation, and the club becomes a supportive network for people to achieve their fitness goals. The video showcases the club's activities, such as group hikes, fitness classes, and workshops.\n\n**Scene 6: Overcoming Challenges and Celebrating Successes**\nThe video highlights the challenges faced by the club members, such as overcoming fear, building confidence, and pushing past physical limitations. However, it also celebrates the successes, such as completing a difficult hike, achieving a personal best, or simply finding a sense of belonging.\n\n**Scene 7: The Power of Friendship and Community**\nThe magician and the fitness enthusiast's friendship is at the heart of the club's success. The video showcases their bond, as well as the connections formed among club members. The scene cuts to a montage of members supporting and encouraging each other, demonstrating the power of community and friendship.\n\n**Scene 8: Conclusion and Call to Action**\nThe video concludes with a shot of the magician performing a final, impressive trick, surrounded by the club members. The camera pans out to reveal the breathtaking natural scenery, symbolizing the transformative power of fitness and nature. The final shot is a call to action, encouraging viewers to join the club and start their own transformation journey.\n\n**Visuals and Tone:**\nThe video will feature a mix of urban and natural settings, with a vibrant color palette and an uplifting soundtrack. The tone will be inspirational, emotional, and fun, reflecting the brand's personality and core message. The visuals will be engaging, with a mix of close-ups, wide shots, and aerial footage to capture the beauty of nature and the energy of the club's activities.\n\n**Influencer Content Inspiration:**\nThe video will draw inspiration from influencer content, such as breathtaking outdoor scenery, fitness motivation, and personal stories of transformation. The tone and style will be similar to that of **divyadhakal_** and **munachiya**, with a focus on showcasing the beauty of nature and the power of community.\n\n**Image Insights:**\nAlthough there are no specific image insights provided, the video will incorporate stunning visuals of natural scenery, fitness activities, and community engagement. The images will be used to tell a story, evoke emotions, and inspire viewers to take action.\n\nThis promotional video storyline aligns with the business's core message, showcasing how personal growth can captivate and unite people. The video will drive engagement, inspire viewers to join the club, and promote the brand's offerings, ultimately contributing to the business's goals of expanding gym branches and building a strong fitness community."
|
| 46 |
+
# ],
|
| 47 |
+
# "final_story": [],
|
| 48 |
+
# "retrievals": [
|
| 49 |
+
# [
|
| 50 |
+
# "[['[1]. The influencer name is: **divyadhakal_** — Likes: **704**, Comments: **9**', 'The story of that particular video is:\\nThe video opens with a breathtaking scene of a hiker trekking alongside a turquoise lake, set against a backdrop of majestic mountains and a bright blue sky dotted with fluffy white clouds. The scene sets a tone of serene adventure and personal reflection. The hiker moves steadily along the rocky shoreline, their pace deliberate and measured. The overall narrative encourages a reflective outlook on challenging times, suggesting they hold the potential for personal growth and future appreciation.', 'The branding or promotion done is:\\nThe video features one line of text overlayed on the scene \"One day you\\'ll look back on this time and all you\\'ll see is magic\"'], ['[2]. The influencer name is: **divyadhakal_** — Likes: **360**, Comments: **4**', 'The story of that particular video is:\\nThe video begins with a ground-level shot focusing on a pair of gray running shoes on a grassy, somewhat dry terrain. The view gradually elevates to reveal a landscape of brown hills and scattered trees. The shot then pans upwards, revealing a majestic, snow-capped mountain range in the distance against a cloudy sky. The visuals suggest a journey into a scenic, natural environment.', 'The branding or promotion done is:\\nThere are no visible texts or brandings in the video.'], ['[3]. The influencer name is: **divyadhakal_** — Likes: **256**, Comments: **5**', 'The story of that particular video is:\\nThe video opens with a scene set during the blue hour, indicating twilight, on a grassy hillside or tea plantation. The scene is peaceful but shrouded in mystery, creating a tranquil and reflective atmosphere. A person walks uphill, carrying a glowing cube-shaped lantern. The distant lights of a village and a road with moving vehicles hint at civilization nearby, juxtaposed against the natural, secluded setting.', 'The branding or promotion done is:\\nThere are no visible texts or brandings in the video.'], ['[4]. The influencer name is: **divyadhakal_** — Likes: **2366**, Comments: **32**', \"The story of that particular video is:\\nThe video opens with a shot of a person walking towards a massive waterfall. The environment is lush and green, with mist from the waterfall filling the air. The initial shots establish a sense of adventure, peace, and the beauty of nature. The focus quickly shifts to the individual's journey towards self-discovery. The main action is the person walking, then standing with arms outstretched, embracing the scenery. The waterfall is the dominant visual element, symbolizing power, renewal, and a grand sense of nature.\", 'The branding or promotion done is:\\nThe only visible text is a comment on the video saying \"Tyo waterfall chai Kun ho sts\"'], ['[5]. The influencer name is: **divyadhakal_** — Likes: **1181**, Comments: **37**', 'The story of that particular video is:\\nThe video presents a concise and inspirational story of recovery and rehabilitation. The storyline follows the progression from post-surgery immobility to active fitness, highlighting the character\\'s determination and the positive outcome of her efforts. The text \"5 months post-surgery\" frames the entire narrative, while the visual transitions and upbeat music reinforce the theme of progress and accomplishment. The video targets individuals interested in health, fitness, and overcoming physical challenges, offering a message of hope and motivation for anyone undergoing a similar journey.', 'The branding or promotion done is:\\n* \"5 months post-surgery\" is a recurring text overlay that provides context to the video.* The gym equipment visible at the end of the video has \"FITNESS\" visible on it.'], ['[6]. The influencer name is: **divyadhakal_** — Likes: **1644**, Comments: **8**', 'The story of that particular video is:\\nThe video begins with a scenic view of a hiker walking along a dirt path in a forest, accompanied by a voiceover expressing that journeys don’t always go as planned. The tone is thoughtful and adventurous. The visuals then shift to the hiker preparing gear, facing rain with an umbrella, and cooking food over an open fire during the hike. The video also showcases the hikers descending a hill on a forested slope.', 'The branding or promotion done is:\\n* “CAMP” is visible on the female hiker’s helmet.'], ['[7]. The influencer name is: **munachiya** — Likes: **1363**, Comments: **9**', 'The story of that particular video is:\\nThe scene opens with a person carrying a large bundle of greenery against the backdrop of snow-capped mountains. It is followed by two more people carrying greeneries and walking in the same path. The visual suggests a rural or mountainous region, with a focus on the natural landscape.', 'The branding or promotion done is:\\nThe video displays the texts “The world is not in your books and maps” and “It’s out there”.'], ['[8]. The influencer name is: **munachiya** — Likes: **495**, Comments: **4**', 'The story of that particular video is:\\nThe video depicts a humorous take on trekking as a solution to personal problems. It transitions from a forest path to a snow-covered mountain and concludes with a river crossing, visually representing a challenging journey.', 'The branding or promotion done is:\\n @munachiya (Instagram handle) Text overlay: My last two brain cells after manipulating me into thinking that trekking to a remote destination will fix all my problems'], ['[9]. The influencer name is: **munachiya** — Likes: **103**, Comments: **4**', 'The story of that particular video is:\\nThe scene opens with a person approaching a multi-tiered waterfall, expressing awe and freedom. Key visuals include the lush green landscape and cascading water. The person then spreading their arms.', 'The branding or promotion done is:\\nThe sweatshirt of the person has the text \"Surfer 81 Venice Beach\"'], ['[10]. The influencer name is: **divyadhakal_** — Likes: **561**, Comments: **3**', 'The story of that particular video is:\\nThe video opens with a shot of a lone hiker, seen from behind, facing a breathtaking mountain range under a clear blue sky. This immediately establishes a tone of adventure, solitude, and introspection. The hiker is positioned on a rocky path, suggesting a challenging journey. As the music starts, the hiker raises their arms, in a gesture of embracing the vastness of the nature. The visual focus is on the expansive landscape.', 'The branding or promotion done is:\\nThe text overlay \"Anyone will listen to people talk about you, but who will take the stand for you instead of listening is what counts...\" appears at the top of the screen.']]"
|
| 51 |
+
# ],
|
| 52 |
+
# [
|
| 53 |
+
# "[['[1]. The influencer name is: **divyadhakal_** — Likes: **704**, Comments: **9**', 'The story of that particular video is:\\nThe video opens with a breathtaking scene of a hiker trekking alongside a turquoise lake, set against a backdrop of majestic mountains and a bright blue sky dotted with fluffy white clouds. The scene sets a tone of serene adventure and personal reflection. The hiker moves steadily along the rocky shoreline, their pace deliberate and measured. The overall narrative encourages a reflective outlook on challenging times, suggesting they hold the potential for personal growth and future appreciation.', 'The branding or promotion done is:\\nThe video features one line of text overlayed on the scene \"One day you\\'ll look back on this time and all you\\'ll see is magic\"'], ['[2]. The influencer name is: **divyadhakal_** — Likes: **360**, Comments: **4**', 'The story of that particular video is:\\nThe video begins with a ground-level shot focusing on a pair of gray running shoes on a grassy, somewhat dry terrain. The view gradually elevates to reveal a landscape of brown hills and scattered trees. The shot then pans upwards, revealing a majestic, snow-capped mountain range in the distance against a cloudy sky. The visuals suggest a journey into a scenic, natural environment.', 'The branding or promotion done is:\\nThere are no visible texts or brandings in the video.'], ['[3]. The influencer name is: **divyadhakal_** — Likes: **256**, Comments: **5**', 'The story of that particular video is:\\nThe video opens with a scene set during the blue hour, indicating twilight, on a grassy hillside or tea plantation. The scene is peaceful but shrouded in mystery, creating a tranquil and reflective atmosphere. A person walks uphill, carrying a glowing cube-shaped lantern. The distant lights of a village and a road with moving vehicles hint at civilization nearby, juxtaposed against the natural, secluded setting.', 'The branding or promotion done is:\\nThere are no visible texts or brandings in the video.'], ['[4]. The influencer name is: **divyadhakal_** — Likes: **2366**, Comments: **32**', \"The story of that particular video is:\\nThe video opens with a shot of a person walking towards a massive waterfall. The environment is lush and green, with mist from the waterfall filling the air. The initial shots establish a sense of adventure, peace, and the beauty of nature. The focus quickly shifts to the individual's journey towards self-discovery. The main action is the person walking, then standing with arms outstretched, embracing the scenery. The waterfall is the dominant visual element, symbolizing power, renewal, and a grand sense of nature.\", 'The branding or promotion done is:\\nThe only visible text is a comment on the video saying \"Tyo waterfall chai Kun ho sts\"'], ['[5]. The influencer name is: **divyadhakal_** — Likes: **1181**, Comments: **37**', 'The story of that particular video is:\\nThe video presents a concise and inspirational story of recovery and rehabilitation. The storyline follows the progression from post-surgery immobility to active fitness, highlighting the character\\'s determination and the positive outcome of her efforts. The text \"5 months post-surgery\" frames the entire narrative, while the visual transitions and upbeat music reinforce the theme of progress and accomplishment. The video targets individuals interested in health, fitness, and overcoming physical challenges, offering a message of hope and motivation for anyone undergoing a similar journey.', 'The branding or promotion done is:\\n* \"5 months post-surgery\" is a recurring text overlay that provides context to the video.* The gym equipment visible at the end of the video has \"FITNESS\" visible on it.'], ['[6]. The influencer name is: **divyadhakal_** — Likes: **1644**, Comments: **8**', 'The story of that particular video is:\\nThe video begins with a scenic view of a hiker walking along a dirt path in a forest, accompanied by a voiceover expressing that journeys don’t always go as planned. The tone is thoughtful and adventurous. The visuals then shift to the hiker preparing gear, facing rain with an umbrella, and cooking food over an open fire during the hike. The video also showcases the hikers descending a hill on a forested slope.', 'The branding or promotion done is:\\n* “CAMP” is visible on the female hiker’s helmet.'], ['[7]. The influencer name is: **munachiya** — Likes: **1363**, Comments: **9**', 'The story of that particular video is:\\nThe scene opens with a person carrying a large bundle of greenery against the backdrop of snow-capped mountains. It is followed by two more people carrying greeneries and walking in the same path. The visual suggests a rural or mountainous region, with a focus on the natural landscape.', 'The branding or promotion done is:\\nThe video displays the texts “The world is not in your books and maps” and “It’s out there”.'], ['[8]. The influencer name is: **munachiya** — Likes: **495**, Comments: **4**', 'The story of that particular video is:\\nThe video depicts a humorous take on trekking as a solution to personal problems. It transitions from a forest path to a snow-covered mountain and concludes with a river crossing, visually representing a challenging journey.', 'The branding or promotion done is:\\n @munachiya (Instagram handle) Text overlay: My last two brain cells after manipulating me into thinking that trekking to a remote destination will fix all my problems'], ['[9]. The influencer name is: **munachiya** — Likes: **103**, Comments: **4**', 'The story of that particular video is:\\nThe scene opens with a person approaching a multi-tiered waterfall, expressing awe and freedom. Key visuals include the lush green landscape and cascading water. The person then spreading their arms.', 'The branding or promotion done is:\\nThe sweatshirt of the person has the text \"Surfer 81 Venice Beach\"'], ['[10]. The influencer name is: **divyadhakal_** — Likes: **561**, Comments: **3**', 'The story of that particular video is:\\nThe video opens with a shot of a lone hiker, seen from behind, facing a breathtaking mountain range under a clear blue sky. This immediately establishes a tone of adventure, solitude, and introspection. The hiker is positioned on a rocky path, suggesting a challenging journey. As the music starts, the hiker raises their arms, in a gesture of embracing the vastness of the nature. The visual focus is on the expansive landscape.', 'The branding or promotion done is:\\nThe text overlay \"Anyone will listen to people talk about you, but who will take the stand for you instead of listening is what counts...\" appears at the top of the screen.']]"
|
| 54 |
+
# ]
|
| 55 |
+
# ],
|
| 56 |
+
# "business_details": {
|
| 57 |
+
# "business_type": "fitness and gym",
|
| 58 |
+
# "platform": "Instagram, TikTok",
|
| 59 |
+
# "target_audience": "young Nepali adults (ages 18–40) who are health-conscious and active on social media",
|
| 60 |
+
# "business_goals": "to expand gym branches across all major cities of Nepal and build a strong fitness community",
|
| 61 |
+
# "offerings": "personal training, group fitness classes, modern workout equipment, nutrition guidance, and wellness programs",
|
| 62 |
+
# "Challenges_faced": "attracting loyal members, standing out in a competitive market, and promoting consistent engagement"
|
| 63 |
+
# },
|
| 64 |
+
# "latest_preferred_topics": [],
|
| 65 |
+
# "images": [
|
| 66 |
+
# 'null'
|
| 67 |
+
# ],
|
| 68 |
+
# "image_captions": [
|
| 69 |
+
# 'null'
|
| 70 |
+
# 'null'
|
| 71 |
+
# ]
|
| 72 |
+
# }
|
| 73 |
+
|
| 74 |
+
long_term_memory = {}
|
human_refined_ideation/utils/prompts.py
CHANGED
|
@@ -19,6 +19,7 @@ The four ideas will be provided to you through a tool.
|
|
| 19 |
- **No explanations, no headers, no labels.**
|
| 20 |
- **Do not ask the user anything back.**
|
| 21 |
- Remember, the length of your refined idea have to be **same as the length of other ideas**.
|
|
|
|
| 22 |
|
| 23 |
|
| 24 |
You must function like a deterministic idea-refiner — each input must result in a single, story-rich output idea.
|
|
|
|
| 19 |
- **No explanations, no headers, no labels.**
|
| 20 |
- **Do not ask the user anything back.**
|
| 21 |
- Remember, the length of your refined idea have to be **same as the length of other ideas**.
|
| 22 |
+
- Even if user asks to generate story based on some idea, you are **not allowed** to to generate the story. Just return that idea only as it is.
|
| 23 |
|
| 24 |
|
| 25 |
You must function like a deterministic idea-refiner — each input must result in a single, story-rich output idea.
|
ideation_agent/utils/__pycache__/nodes.cpython-312.pyc
CHANGED
|
Binary files a/ideation_agent/utils/__pycache__/nodes.cpython-312.pyc and b/ideation_agent/utils/__pycache__/nodes.cpython-312.pyc differ
|
|
|
ideation_agent/utils/__pycache__/prompts.cpython-312.pyc
CHANGED
|
Binary files a/ideation_agent/utils/__pycache__/prompts.cpython-312.pyc and b/ideation_agent/utils/__pycache__/prompts.cpython-312.pyc differ
|
|
|
ideation_agent/utils/__pycache__/state.cpython-312.pyc
CHANGED
|
Binary files a/ideation_agent/utils/__pycache__/state.cpython-312.pyc and b/ideation_agent/utils/__pycache__/state.cpython-312.pyc differ
|
|
|
ideation_agent/utils/nodes.py
CHANGED
|
@@ -25,7 +25,8 @@ improver_agent = create_react_agent(
|
|
| 25 |
def ideator(state:State):
|
| 26 |
template = ideator_prompt(state)
|
| 27 |
messages = [SystemMessage(content=template),
|
| 28 |
-
HumanMessage(content=f'''The business_details is
|
|
|
|
| 29 |
try:
|
| 30 |
response = ideator_agent.invoke({'messages':messages})
|
| 31 |
response = response['messages'][-1].content
|
|
@@ -43,7 +44,7 @@ def ideator(state:State):
|
|
| 43 |
def critic(state:State):
|
| 44 |
template = critic_prompt(state)
|
| 45 |
messages = [SystemMessage(content=template),
|
| 46 |
-
HumanMessage(content=f'''The business_details is\n{state.business_details[-1]}\n''')]
|
| 47 |
|
| 48 |
try:
|
| 49 |
response = critic_agent.invoke({'messages':messages})
|
|
@@ -64,7 +65,7 @@ def improver(state:State):
|
|
| 64 |
response_list = []
|
| 65 |
template = improver_prompt(state)
|
| 66 |
messages = [SystemMessage(content=template),
|
| 67 |
-
HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}''')]
|
| 68 |
print('Improver Prompt:',messages)
|
| 69 |
response = improver_llm.with_structured_output(ImproverResponseFormatter).invoke(messages)
|
| 70 |
response_list.append(response.improved_idea1)
|
|
|
|
| 25 |
def ideator(state:State):
|
| 26 |
template = ideator_prompt(state)
|
| 27 |
messages = [SystemMessage(content=template),
|
| 28 |
+
HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}\n
|
| 29 |
+
The information of the image is:\n{state.image_caption[-1]}''')]
|
| 30 |
try:
|
| 31 |
response = ideator_agent.invoke({'messages':messages})
|
| 32 |
response = response['messages'][-1].content
|
|
|
|
| 44 |
def critic(state:State):
|
| 45 |
template = critic_prompt(state)
|
| 46 |
messages = [SystemMessage(content=template),
|
| 47 |
+
HumanMessage(content=f'''The business_details is\n{state.business_details[-1]}\n The information of the image is:\n{state.image_caption[-1]}''')]
|
| 48 |
|
| 49 |
try:
|
| 50 |
response = critic_agent.invoke({'messages':messages})
|
|
|
|
| 65 |
response_list = []
|
| 66 |
template = improver_prompt(state)
|
| 67 |
messages = [SystemMessage(content=template),
|
| 68 |
+
HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}\n The information of the image is:\n{state.image_caption[-1]}''')]
|
| 69 |
print('Improver Prompt:',messages)
|
| 70 |
response = improver_llm.with_structured_output(ImproverResponseFormatter).invoke(messages)
|
| 71 |
response_list.append(response.improved_idea1)
|
ideation_agent/utils/prompts.py
CHANGED
|
@@ -6,6 +6,7 @@ def ideator_prompt(state):
|
|
| 6 |
You are a **bold, imaginative, and culturally-attuned video ideator** trusted by top global brands to craft **crisp, original, and high-impact video concepts** for social platforms like TikTok, Instagram, and YouTube.
|
| 7 |
|
| 8 |
Your task is to create **exactly 4 highly original video ideas**, each in **exactly 40 words**. These are not scripts or taglines — they are **powerful conceptual seeds**: short, visual, emotionally charged ideas that can spark full videos. Your ideas should feel fresh, scroll-stopping, and deeply resonant with today’s audiences.
|
|
|
|
| 9 |
|
| 10 |
---
|
| 11 |
|
|
@@ -78,6 +79,8 @@ Now, based on the video business details above, generate **four original, 40-wor
|
|
| 78 |
def critic_prompt(state):
|
| 79 |
return f"""
|
| 80 |
You are a sharp, imaginative, and detail-oriented **video idea critic**. You’ve been assigned to **critique 4 video ideas** created by another ideator and then **refine or improve** them.
|
|
|
|
|
|
|
| 81 |
|
| 82 |
Your job is twofold:
|
| 83 |
1. **Identify flaws** (if any) in one or more of the ideas — repetition, weak twist, boring start, lack of connection to business, etc.
|
|
@@ -134,6 +137,7 @@ def improver_prompt(state):
|
|
| 134 |
|
| 135 |
return f"""
|
| 136 |
You are a highly skilled, creative, and discerning **video concept improver**. Two previous agents — the *Ideator* and the *Critic* — have worked on this task. Now, it’s your job to **analyze both**, identify any faults in the *critic's refinements*, and deliver the **final, most powerful version** of the 4 video ideas.
|
|
|
|
| 137 |
|
| 138 |
---
|
| 139 |
|
|
@@ -265,4 +269,4 @@ The user will do some request to enhance their ideas. You have to creatively pro
|
|
| 265 |
|
| 266 |
|
| 267 |
You must function like a deterministic idea-refiner — each input must result in a single, story-rich output idea.
|
| 268 |
-
"""
|
|
|
|
| 6 |
You are a **bold, imaginative, and culturally-attuned video ideator** trusted by top global brands to craft **crisp, original, and high-impact video concepts** for social platforms like TikTok, Instagram, and YouTube.
|
| 7 |
|
| 8 |
Your task is to create **exactly 4 highly original video ideas**, each in **exactly 40 words**. These are not scripts or taglines — they are **powerful conceptual seeds**: short, visual, emotionally charged ideas that can spark full videos. Your ideas should feel fresh, scroll-stopping, and deeply resonant with today’s audiences.
|
| 9 |
+
If some **valid and usuable information** of image is provided to you by the user, you have to **strongly focus** in that information of image because that is the reference of what type of idea does the user wants.
|
| 10 |
|
| 11 |
---
|
| 12 |
|
|
|
|
| 79 |
def critic_prompt(state):
|
| 80 |
return f"""
|
| 81 |
You are a sharp, imaginative, and detail-oriented **video idea critic**. You’ve been assigned to **critique 4 video ideas** created by another ideator and then **refine or improve** them.
|
| 82 |
+
If some **valid and usuable information** of image is provided to you by the user, you have to **strongly focus** in that information of image because that is the reference of what type of idea does the user wants.
|
| 83 |
+
|
| 84 |
|
| 85 |
Your job is twofold:
|
| 86 |
1. **Identify flaws** (if any) in one or more of the ideas — repetition, weak twist, boring start, lack of connection to business, etc.
|
|
|
|
| 137 |
|
| 138 |
return f"""
|
| 139 |
You are a highly skilled, creative, and discerning **video concept improver**. Two previous agents — the *Ideator* and the *Critic* — have worked on this task. Now, it’s your job to **analyze both**, identify any faults in the *critic's refinements*, and deliver the **final, most powerful version** of the 4 video ideas.
|
| 140 |
+
If some **valid and usuable information** of image is provided to you by the user, you have to **strongly focus** in that information of image because that is the reference of what type of idea does the user wants.
|
| 141 |
|
| 142 |
---
|
| 143 |
|
|
|
|
| 269 |
|
| 270 |
|
| 271 |
You must function like a deterministic idea-refiner — each input must result in a single, story-rich output idea.
|
| 272 |
+
"""
|
ideation_agent/utils/state.py
CHANGED
|
@@ -14,6 +14,7 @@ class State(BaseModel):
|
|
| 14 |
validator3_response: Annotated[list[str],operator.add] = []
|
| 15 |
validator4_response: Annotated[list[str],operator.add] = []
|
| 16 |
disagreement_reason: Annotated[list[str],operator.add] = []
|
|
|
|
| 17 |
|
| 18 |
class QueryFormatter(BaseModel):
|
| 19 |
business_details: str = Field(description="The details of the business that user passes to the agent")
|
|
|
|
| 14 |
validator3_response: Annotated[list[str],operator.add] = []
|
| 15 |
validator4_response: Annotated[list[str],operator.add] = []
|
| 16 |
disagreement_reason: Annotated[list[str],operator.add] = []
|
| 17 |
+
image_caption: Annotated[list[str],operator.add] = []
|
| 18 |
|
| 19 |
class QueryFormatter(BaseModel):
|
| 20 |
business_details: str = Field(description="The details of the business that user passes to the agent")
|
main.py
CHANGED
|
@@ -9,13 +9,13 @@ from business_interaction_agent.agent import BusinessInteractionChatbot
|
|
| 9 |
from context_analysis_agent.utils.utils import save_to_db
|
| 10 |
import ast
|
| 11 |
from orchestration_agent.agent import orchestration_chat
|
| 12 |
-
from orchestration_agent.utils.utils import caption_image
|
| 13 |
from brainstroming_agent.utils.utils import encode_image_to_base64 , generate_final_story, generate_image
|
| 14 |
from idea_to_budget_agent.agent import budget_calculator
|
| 15 |
from ideation_agent.agent import ideation_graph
|
| 16 |
from langgraph.errors import GraphRecursionError
|
| 17 |
from human_refined_ideation.agent import human_refined_idea
|
| 18 |
-
from dummy_state import stored_data
|
| 19 |
import json
|
| 20 |
|
| 21 |
# Store brainstorming results per thread_id
|
|
@@ -37,10 +37,20 @@ class OrchestrationRequest(BaseModel):
|
|
| 37 |
def orchestration_endpoint(request:OrchestrationRequest):
|
| 38 |
print('Image:',request.image_base64)
|
| 39 |
result = orchestration_chat(request.message , request.image_base64)
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
class UserMessage(BaseModel):
|
| 46 |
message: str
|
|
@@ -60,6 +70,10 @@ def context_analysis(msg: UserMessage):
|
|
| 60 |
return {"response": response, "business_details": details, "complete": True}
|
| 61 |
return {"response": response, "complete": False}
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
|
| 65 |
@app.post("/business-interaction")
|
|
@@ -77,7 +91,8 @@ def ideation_endpoint():
|
|
| 77 |
try:
|
| 78 |
result = idea_graph.invoke(
|
| 79 |
{
|
| 80 |
-
'business_details': [stored_data['business_details']]
|
|
|
|
| 81 |
},
|
| 82 |
config=config,
|
| 83 |
)
|
|
@@ -126,10 +141,10 @@ def brainstroming_endpoint(
|
|
| 126 |
request: BrainstormRequest, # 🔥 Full JSON body here
|
| 127 |
):
|
| 128 |
result = brainstrom_graph.invoke({
|
| 129 |
-
'idea': [stored_data
|
| 130 |
'images': request.image_base64_list,
|
| 131 |
'latest_preferred_topics': request.preferred_topics,
|
| 132 |
-
'business_details':
|
| 133 |
},
|
| 134 |
config={"configurable": {"thread_id": request.thread_id}})
|
| 135 |
|
|
@@ -141,21 +156,23 @@ def brainstroming_endpoint(
|
|
| 141 |
|
| 142 |
@app.post("/generate-final-story")
|
| 143 |
def generate_final_story_endpoint():
|
| 144 |
-
final_story =
|
|
|
|
|
|
|
| 145 |
stored_data['final_story']=final_story
|
| 146 |
return {
|
| 147 |
'response': final_story
|
| 148 |
}
|
| 149 |
-
stored_data['final_story']= '''A cinematic journey follows a street magician\'s
|
| 150 |
-
metamorphosis from a mere trickster to a powerful performer, as he transforms his act with newfound physical strength, effortlessly executing death-defying stunts, and inspiring a captivated crowd to take action, all set against a
|
| 151 |
-
backdrop of urban grandeur and pulsing energy.'''
|
| 152 |
|
| 153 |
|
| 154 |
@app.post("/generate-image")
|
| 155 |
def generate_image_endpoint():
|
| 156 |
-
image = generate_image(str(stored_data
|
| 157 |
-
,str(stored_data
|
| 158 |
-
,str(stored_data
|
| 159 |
stored_data['generated_image']=image
|
| 160 |
return {
|
| 161 |
'response':image
|
|
|
|
| 9 |
from context_analysis_agent.utils.utils import save_to_db
|
| 10 |
import ast
|
| 11 |
from orchestration_agent.agent import orchestration_chat
|
| 12 |
+
from orchestration_agent.utils.utils import caption_image , show_analytics
|
| 13 |
from brainstroming_agent.utils.utils import encode_image_to_base64 , generate_final_story, generate_image
|
| 14 |
from idea_to_budget_agent.agent import budget_calculator
|
| 15 |
from ideation_agent.agent import ideation_graph
|
| 16 |
from langgraph.errors import GraphRecursionError
|
| 17 |
from human_refined_ideation.agent import human_refined_idea
|
| 18 |
+
from dummy_state import stored_data, long_term_memory
|
| 19 |
import json
|
| 20 |
|
| 21 |
# Store brainstorming results per thread_id
|
|
|
|
| 37 |
def orchestration_endpoint(request:OrchestrationRequest):
|
| 38 |
print('Image:',request.image_base64)
|
| 39 |
result = orchestration_chat(request.message , request.image_base64)
|
| 40 |
+
if result.image_caption != '':
|
| 41 |
+
stored_data['image_caption']=result.image_caption
|
| 42 |
+
if result.video_idea !='' or result.video_idea != 'null':
|
| 43 |
+
stored_data['refined_ideation']= result.video_idea
|
| 44 |
+
if result.video_story!='' or result.video_story!='null':
|
| 45 |
+
stored_data['final_story']= result.video_story
|
| 46 |
+
print('Idea:',stored_data['refined_ideation'])
|
| 47 |
+
print('Story:', stored_data['final_story'])
|
| 48 |
+
|
| 49 |
+
return {'tool_response': result.tool ,
|
| 50 |
+
'message_response': result.query_response,
|
| 51 |
+
'image_caption':result.image_caption,
|
| 52 |
+
'video_idea': result.video_idea,
|
| 53 |
+
'video_story': result.video_story}
|
| 54 |
|
| 55 |
class UserMessage(BaseModel):
|
| 56 |
message: str
|
|
|
|
| 70 |
return {"response": response, "business_details": details, "complete": True}
|
| 71 |
return {"response": response, "complete": False}
|
| 72 |
|
| 73 |
+
@app.post("/show-analytics")
|
| 74 |
+
def show_analytics_endpoint():
|
| 75 |
+
response = show_analytics(stored_data['business_details'])
|
| 76 |
+
return {'response': response}
|
| 77 |
|
| 78 |
|
| 79 |
@app.post("/business-interaction")
|
|
|
|
| 91 |
try:
|
| 92 |
result = idea_graph.invoke(
|
| 93 |
{
|
| 94 |
+
'business_details': [stored_data['business_details']],
|
| 95 |
+
'image_caption': [stored_data['image_caption'] if 'image_caption' in stored_data else ""]
|
| 96 |
},
|
| 97 |
config=config,
|
| 98 |
)
|
|
|
|
| 141 |
request: BrainstormRequest, # 🔥 Full JSON body here
|
| 142 |
):
|
| 143 |
result = brainstrom_graph.invoke({
|
| 144 |
+
'idea': [stored_data.get('refined_ideation', '')],
|
| 145 |
'images': request.image_base64_list,
|
| 146 |
'latest_preferred_topics': request.preferred_topics,
|
| 147 |
+
'business_details': stored_data['business_details']
|
| 148 |
},
|
| 149 |
config={"configurable": {"thread_id": request.thread_id}})
|
| 150 |
|
|
|
|
| 156 |
|
| 157 |
@app.post("/generate-final-story")
|
| 158 |
def generate_final_story_endpoint():
|
| 159 |
+
final_story = generate_final_story(
|
| 160 |
+
stored_data.get("brainstroming_response") or stored_data.get("business_details")
|
| 161 |
+
)
|
| 162 |
stored_data['final_story']=final_story
|
| 163 |
return {
|
| 164 |
'response': final_story
|
| 165 |
}
|
| 166 |
+
# stored_data['final_story']= '''A cinematic journey follows a street magician\'s
|
| 167 |
+
# metamorphosis from a mere trickster to a powerful performer, as he transforms his act with newfound physical strength, effortlessly executing death-defying stunts, and inspiring a captivated crowd to take action, all set against a
|
| 168 |
+
# backdrop of urban grandeur and pulsing energy.'''
|
| 169 |
|
| 170 |
|
| 171 |
@app.post("/generate-image")
|
| 172 |
def generate_image_endpoint():
|
| 173 |
+
image = generate_image(str(stored_data.get('final_story',''))
|
| 174 |
+
,str(stored_data.get('business_details'))
|
| 175 |
+
,str(stored_data.get('refined_ideation','')))
|
| 176 |
stored_data['generated_image']=image
|
| 177 |
return {
|
| 178 |
'response':image
|
orchestration_agent/agent.py
CHANGED
|
@@ -1,30 +1,37 @@
|
|
| 1 |
from langgraph.graph import StateGraph, MessagesState, START, END
|
| 2 |
from langgraph.checkpoint.memory import MemorySaver
|
| 3 |
-
from .utils.nodes import
|
| 4 |
-
from utils.models_loader import
|
| 5 |
from .utils.state import ValidationFormatter
|
| 6 |
-
from .utils.utils import caption_image
|
|
|
|
| 7 |
import re
|
|
|
|
| 8 |
memory = MemorySaver()
|
| 9 |
|
| 10 |
|
| 11 |
def orchestration_graph():
|
| 12 |
workflow = StateGraph(MessagesState)
|
| 13 |
-
workflow.add_node("
|
| 14 |
-
workflow.
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
| 16 |
return workflow.compile(checkpointer=memory)
|
| 17 |
|
| 18 |
def orchestration_chat(user_input: str, image_base64=[]):
|
| 19 |
if len(image_base64)>0:
|
| 20 |
caption_response = caption_image(image_base64, user_input)
|
|
|
|
| 21 |
else:
|
| 22 |
caption_response =''
|
| 23 |
|
| 24 |
agent = orchestration_graph()
|
| 25 |
config = {"configurable": {"thread_id": "orchestration-thread"}}
|
| 26 |
-
response = agent.invoke({"messages": [
|
| 27 |
-
|
|
|
|
| 28 |
return response
|
| 29 |
|
| 30 |
|
|
|
|
| 1 |
from langgraph.graph import StateGraph, MessagesState, START, END
|
| 2 |
from langgraph.checkpoint.memory import MemorySaver
|
| 3 |
+
from .utils.nodes import tool_return_node, extract_user_reference_node
|
| 4 |
+
from utils.models_loader import llm_gpt
|
| 5 |
from .utils.state import ValidationFormatter
|
| 6 |
+
from .utils.utils import caption_image , extract_latest_response_block
|
| 7 |
+
|
| 8 |
import re
|
| 9 |
+
from langchain_core.messages import SystemMessage
|
| 10 |
memory = MemorySaver()
|
| 11 |
|
| 12 |
|
| 13 |
def orchestration_graph():
|
| 14 |
workflow = StateGraph(MessagesState)
|
| 15 |
+
workflow.add_node("chatbot1", tool_return_node)
|
| 16 |
+
workflow.add_node("chatbot2", extract_user_reference_node)
|
| 17 |
+
|
| 18 |
+
workflow.add_edge(START, "chatbot1")
|
| 19 |
+
workflow.add_edge('chatbot1', "chatbot2")
|
| 20 |
+
workflow.add_edge('chatbot2', END)
|
| 21 |
return workflow.compile(checkpointer=memory)
|
| 22 |
|
| 23 |
def orchestration_chat(user_input: str, image_base64=[]):
|
| 24 |
if len(image_base64)>0:
|
| 25 |
caption_response = caption_image(image_base64, user_input)
|
| 26 |
+
print('Caption Response:', caption_response)
|
| 27 |
else:
|
| 28 |
caption_response =''
|
| 29 |
|
| 30 |
agent = orchestration_graph()
|
| 31 |
config = {"configurable": {"thread_id": "orchestration-thread"}}
|
| 32 |
+
response = agent.invoke({"messages": [{'role':'human','content':user_input},{'role':'function','name':'information_of_image','content':caption_response}]}, config)['messages']
|
| 33 |
+
# template = [SystemMessage(content=final_validator_prompt)] + response
|
| 34 |
+
response=llm_gpt.with_structured_output(ValidationFormatter).invoke(extract_latest_response_block(response))
|
| 35 |
return response
|
| 36 |
|
| 37 |
|
orchestration_agent/utils/nodes.py
CHANGED
|
@@ -1,11 +1,22 @@
|
|
| 1 |
-
from .prompts import
|
| 2 |
from langchain_core.messages import SystemMessage
|
| 3 |
-
from utils.models_loader import
|
| 4 |
-
from .state import
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
|
|
|
| 8 |
history = state["messages"]
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .prompts import tool_return_prompt , extract_user_reference_prompt
|
| 2 |
from langchain_core.messages import SystemMessage
|
| 3 |
+
from utils.models_loader import llm_gpt
|
| 4 |
+
from .state import ToolResponseFormatter, UserReferenceResponseFormatter
|
| 5 |
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def tool_return_node(state):
|
| 9 |
history = state["messages"]
|
| 10 |
+
template = [SystemMessage(content=tool_return_prompt)] + history
|
| 11 |
+
# print(template)
|
| 12 |
+
response = llm_gpt.with_structured_output(ToolResponseFormatter).invoke(template)
|
| 13 |
+
print(response)
|
| 14 |
+
return {"messages": [{'role':'assistant','content':f'''The exact name of the tool is: {response}'''}]}
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def extract_user_reference_node(state):
|
| 19 |
+
history = state['messages']
|
| 20 |
+
template = [SystemMessage(content=extract_user_reference_prompt)] + history
|
| 21 |
+
response = llm_gpt.with_structured_output(UserReferenceResponseFormatter).invoke(template)
|
| 22 |
+
return {'messages': [{'role':'assistant','content':f'''The video idea is: {response.video_idea} and the video story is: {response.video_story}'''}]}
|
orchestration_agent/utils/prompts.py
CHANGED
|
@@ -1,16 +1,18 @@
|
|
| 1 |
-
|
| 2 |
-
You are a
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
1. `tool`: the most appropriate tool name from the list below (or `null` if not applicable)
|
| 7 |
-
2. `message`: a clear, helpful message to show to the user. This can be a question, guidance or even an action confirmation depending on the user query. You can guide the user according to their intention.
|
| 8 |
-
3. 'image_caption' : Information of the image if provided, otherwise return a text of **No any information**.
|
| 9 |
---
|
| 10 |
|
| 11 |
### Available Tools:
|
| 12 |
-
1. **ideation** → Use if the user wants to create
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
3. **generate-story** → Use if the user talks about **creating the story** from their idea **OR** if the user talks about **creating story with brainstorming**.
|
| 15 |
4. **generate-ultimate-story** → Use if the user is ready for a final or ultimate story/script based on ideas and already brainstormed topics from the previous tool called **generate-story**.
|
| 16 |
Remember one thing, **generate-ultimate-story** is never invoked without invoking **generate-story**.
|
|
@@ -18,28 +20,154 @@ Your job is to analyze the **user's input** only **not the information of the im
|
|
| 18 |
|
| 19 |
---
|
| 20 |
|
| 21 |
-
###
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
---
|
| 29 |
|
| 30 |
-
###
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
"""
|
| 37 |
|
| 38 |
|
| 39 |
|
|
|
|
| 40 |
def captioning_prompt(user_input):
|
| 41 |
-
return f
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
tool_return_prompt_old = """
|
| 2 |
+
You are a AI orchestration agent that reads the user's message and decides which one of the following tools should be called next. You're perfect at analyzing the intention of the user.
|
| 3 |
+
|
| 4 |
+
Your job is to analyze the **user's input** and return a response with:
|
| 5 |
+
`tool`: the most appropriate tool name from the list below (or `null` if not applicable)
|
|
|
|
|
|
|
|
|
|
| 6 |
---
|
| 7 |
|
| 8 |
### Available Tools:
|
| 9 |
+
1. **ideation** → Use if the user wants to create some video ideas. Also, If user says that they didn't like any of the previous ideas and want to genrate again, you have to trigger this again.
|
| 10 |
+
|
| 11 |
+
2. **human-idea-refining** → Use if the user:
|
| 12 |
+
Likes some idea, locks some idea or if they gives feedback or asks to improve/change ideas.
|
| 13 |
+
Trigger this if user locks or likes some ideas OR they want to modify the created ideas according to their requirements.
|
| 14 |
+
This is the part where human locks the idea generated by AI or want to modify ideas.
|
| 15 |
+
|
| 16 |
3. **generate-story** → Use if the user talks about **creating the story** from their idea **OR** if the user talks about **creating story with brainstorming**.
|
| 17 |
4. **generate-ultimate-story** → Use if the user is ready for a final or ultimate story/script based on ideas and already brainstormed topics from the previous tool called **generate-story**.
|
| 18 |
Remember one thing, **generate-ultimate-story** is never invoked without invoking **generate-story**.
|
|
|
|
| 20 |
|
| 21 |
---
|
| 22 |
|
| 23 |
+
### Output Format:
|
| 24 |
+
"tool": "the exact name of the tool" OR "null".
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
tool_return_prompt = """
|
| 31 |
+
You are an AI orchestration agent and a friendly assistant built to help businesses and brands find influencers and generate content ideas, stories, and visuals.
|
| 32 |
+
|
| 33 |
+
Your job is to:
|
| 34 |
+
1. **Read the user's message carefully** and identify their intent.
|
| 35 |
+
2. **Return exactly two things**:
|
| 36 |
+
- `tools`: a Python-style list of tool names (from the ordered list below) that match the user’s intent.
|
| 37 |
+
- `query_response`: a short, friendly, and helpful reply that aligns with the tools you've selected.
|
| 38 |
+
|
| 39 |
+
Your `tools` output must:
|
| 40 |
+
- Always be a **Python-style list**, even if only one tool is selected.
|
| 41 |
+
- **Respect the sequence** of tools listed below. If more than one tool is needed, always list them in this order (regardless of how the user wrote them).
|
| 42 |
+
- Only include tools that are strictly necessary.
|
| 43 |
+
|
| 44 |
+
Your `query_response` must:
|
| 45 |
+
- Always match and acknowledge the user's request.
|
| 46 |
+
- Be aligned with the selected tools.
|
| 47 |
+
- Never say something is impossible if a tool exists for it.
|
| 48 |
|
| 49 |
---
|
| 50 |
|
| 51 |
+
### Available Tools (in execution order — use this order in your response):
|
| 52 |
+
|
| 53 |
+
1. **ideation** → Trigger if the user:
|
| 54 |
+
- Wants to generate the video ideas
|
| 55 |
+
- Asks for new or fresh ideas
|
| 56 |
+
- If the user didn't like previous ideas and wants ideas again, you have to return this again.
|
| 57 |
+
|
| 58 |
+
2. **human-idea-refining** → Trigger if the user:
|
| 59 |
+
- Says they liked, loved, locked, or selected specific ideas
|
| 60 |
+
- Gives feedback, asks for improvement, merging, or editing of ideas
|
| 61 |
+
- Refers to using or building on a specific idea (e.g., “based on idea 2”)
|
| 62 |
+
- This is the part where human locks the idea generated by AI or want to modify ideas.
|
| 63 |
+
|
| 64 |
+
3. **generate-story** → Trigger if the user:
|
| 65 |
+
- Wants to generate a story or says that they want to brainstorm
|
| 66 |
+
- Says things like “create a story”, “make a plot”, or “brainstorm a storyline” etc.
|
| 67 |
+
- This is the part where the user gets the story of their selected or refined idea.
|
| 68 |
+
|
| 69 |
+
4. **generate-ultimate-story** → Trigger only if:
|
| 70 |
+
- The user is asking for the **final**, polished, or complete story
|
| 71 |
+
- And has already done previous story brainstorming
|
| 72 |
+
- Never trigger this tool alone unless `generate-story` has been used before
|
| 73 |
+
|
| 74 |
+
5. **generate-image** → Trigger if the user:
|
| 75 |
+
- Wants a visual, image, or scene created from the final story
|
| 76 |
+
|
| 77 |
+
---
|
| 78 |
+
|
| 79 |
+
### Special Clarifications (Important Rules):
|
| 80 |
+
|
| 81 |
+
- If a user says:
|
| 82 |
+
> “Generate story based on idea 4”
|
| 83 |
+
This means they selected/liked idea 4 → so return:
|
| 84 |
+
`"tools": ["human-idea-refining", "generate-story"]`
|
| 85 |
+
|
| 86 |
+
- If a user says:
|
| 87 |
+
> “Create an image of the final script”
|
| 88 |
+
→ Return: `["generate-image"]`
|
| 89 |
+
|
| 90 |
+
- If a user says:
|
| 91 |
+
> “I want a final version of this story”
|
| 92 |
+
→ Return: `["generate-ultimate-story"]` (but only if `generate-story` was used before)
|
| 93 |
+
|
| 94 |
+
- If a user gives feedback or says “improve this idea” → Return `["human-idea-refining"]`
|
| 95 |
+
|
| 96 |
+
- If a user just wants help with finding influencers or advice → Return `"tools": []` but still respond helpfully via `query_response`.
|
| 97 |
|
| 98 |
+
---
|
| 99 |
+
|
| 100 |
+
### Influencer Assistant Note:
|
| 101 |
+
|
| 102 |
+
You're also an intelligent assistant for brands looking to collaborate with influencers. If the user asks about influencer suggestions, trends, or insights (even without tool triggers), give friendly, useful replies using the influencer data provided to you.
|
| 103 |
+
|
| 104 |
+
---
|
| 105 |
+
|
| 106 |
+
### Output Format (always this exact format):
|
| 107 |
+
|
| 108 |
+
"tools": ["tool_1", "tool_2"], // or [] if nothing applies
|
| 109 |
+
"query_response": "Short, clear, and friendly message to the user"
|
| 110 |
+
|
| 111 |
+
"""
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
extract_user_reference_prompt = """
|
| 116 |
+
You are an information extractor, NOT a creative assistant. Your ONLY job is to extract video ideas and video stories from user queries **if and only if** they are explicitly written by the user. Do not create, generate, or imagine anything on your own.
|
| 117 |
+
|
| 118 |
+
STRICT RULES:
|
| 119 |
+
1. If the user has **explicitly written** a video idea or video story, extract them as-is. Do NOT rephrase, summarize, or interpret them.
|
| 120 |
+
2. If the user has **not clearly provided** a video idea or story in their message, you MUST return **null** for both.
|
| 121 |
+
3. You are NEVER allowed to generate or suggest a video idea or story yourself. This includes guessing or inferring based on the user's intent or tone. If it's not clearly written by the user, ignore it.
|
| 122 |
|
| 123 |
+
CLUES to look for (non-exhaustive but helpful):
|
| 124 |
+
- "Here is the video idea:"
|
| 125 |
+
- "This is the story I want to use:"
|
| 126 |
+
- "My video idea is..."
|
| 127 |
+
- "The story goes like this..."
|
| 128 |
+
- "Video idea:" / "Video story:"
|
| 129 |
+
|
| 130 |
+
Any other type of message (e.g., “I want to generate ideas”, “Give me suggestions”, “Brainstorm with me”) must result in:
|
| 131 |
+
|
| 132 |
+
video_idea: null
|
| 133 |
+
video_story: null
|
| 134 |
+
|
| 135 |
+
Output format (always return exactly like this):
|
| 136 |
+
video_idea: [the exact video idea or null]
|
| 137 |
+
video_story: [the exact video story or null]
|
| 138 |
"""
|
| 139 |
|
| 140 |
|
| 141 |
|
| 142 |
+
|
| 143 |
def captioning_prompt(user_input):
|
| 144 |
+
return f"""
|
| 145 |
+
You are an expert visual interpreter that reads images and generates helpful descriptions.
|
| 146 |
+
|
| 147 |
+
### Task:
|
| 148 |
+
- If the user explicitly asks to generate an idea, story, or caption **based on the image**, then:
|
| 149 |
+
- Understand what part or element the user is referring to.
|
| 150 |
+
- Generate a caption or descriptive summary aligned with that intent.
|
| 151 |
+
|
| 152 |
+
- If the user’s input **does not reference the image**, simply:
|
| 153 |
+
- Generate a general caption for the image that summarizes its content and visual information.
|
| 154 |
+
- Keep it concise and limited to **within 100 words**.
|
| 155 |
+
|
| 156 |
+
### User Input:
|
| 157 |
+
{user_input}
|
| 158 |
+
|
| 159 |
+
### Output:
|
| 160 |
+
Respond only with the **image_caption** based on the image and the user's instruction.
|
| 161 |
+
"""
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def show_analytics_prompt():
|
| 165 |
+
return f"""
|
| 166 |
+
|
| 167 |
+
You're a perfect and intelligent analyst that shows the analytics of the influencers to the brands.
|
| 168 |
+
You're provided with the analytics of the influencers through the tool.
|
| 169 |
+
Display that analytics to the brand focusing on how those influencers can help them in their business problems. Don't miss any of the influencers from the tool. Give their whole analytics clearly.
|
| 170 |
+
Clearly mention all the likes, comments of those influencers also.
|
| 171 |
+
The details of business is provided to you by the human.
|
| 172 |
+
|
| 173 |
+
"""
|
orchestration_agent/utils/state.py
CHANGED
|
@@ -1,7 +1,20 @@
|
|
| 1 |
from pydantic import BaseModel, Field
|
|
|
|
| 2 |
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
class ValidationFormatter(BaseModel):
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
+
from typing import List
|
| 3 |
|
| 4 |
|
| 5 |
+
class ToolResponseFormatter(BaseModel):
|
| 6 |
+
tool: List[str] = Field(description="Returns the name of the tool, tools, or an empty list.")
|
| 7 |
+
query_response: str = Field(description="Returns the response of the user query.")
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class UserReferenceResponseFormatter(BaseModel):
|
| 12 |
+
video_idea: str = Field(description="Returns the video idea as it is, otherwise return null")
|
| 13 |
+
video_story: str = Field(description="Returns the video story as it is, otherwise return null")
|
| 14 |
+
|
| 15 |
class ValidationFormatter(BaseModel):
|
| 16 |
+
tool: List[str] = Field(description="Returns the name of the tool or tools as it is.")
|
| 17 |
+
query_response: str = Field(description="Returns the reply of query as it is.")
|
| 18 |
+
image_caption: str = Field(description="Returns the information of image as it is.")
|
| 19 |
+
video_idea: str = Field(description="Returns the video idea as it is.")
|
| 20 |
+
video_story: str = Field(description="Returns the video story as it is.")
|
orchestration_agent/utils/tools.py
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import faiss
|
| 2 |
+
import ast
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import numpy as np
|
| 5 |
+
from utils.models_loader import ST
|
| 6 |
+
import json
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def retrieve_tool(business_details):
|
| 10 |
+
'''
|
| 11 |
+
Always invoke this tool.
|
| 12 |
+
Retrieve influencer's data by semantic search of **business details**.
|
| 13 |
+
'''
|
| 14 |
+
# === Load CSV ===
|
| 15 |
+
csv_path = 'extracted_data.csv'
|
| 16 |
+
df = pd.read_csv(csv_path)
|
| 17 |
+
|
| 18 |
+
# === Parse stored embeddings ===
|
| 19 |
+
df['embeddings'] = df['embeddings'].apply(lambda x: ast.literal_eval(x) if isinstance(x, str) else x)
|
| 20 |
+
embeddings = np.vstack(df['embeddings'].values).astype('float32')
|
| 21 |
+
|
| 22 |
+
# === Build FAISS index ===
|
| 23 |
+
dimension = embeddings.shape[1]
|
| 24 |
+
index = faiss.IndexFlatL2(dimension)
|
| 25 |
+
index.add(embeddings)
|
| 26 |
+
|
| 27 |
+
# === Encode the query and search ===
|
| 28 |
+
query_embedding = ST.encode(str(business_details)).reshape(1, -1).astype('float32')
|
| 29 |
+
top_k = 30
|
| 30 |
+
distances, indices = index.search(query_embedding, top_k)
|
| 31 |
+
|
| 32 |
+
# === Format results ===
|
| 33 |
+
results = []
|
| 34 |
+
for i, idx in enumerate(indices[0]):
|
| 35 |
+
res = {
|
| 36 |
+
'url': df.iloc[idx]['videoUrl'],
|
| 37 |
+
'username': df.iloc[idx]['username'],
|
| 38 |
+
'likesCount': int(df.iloc[idx]['likesCount']),
|
| 39 |
+
'commentCount': int(df.iloc[idx]['commentCount'])
|
| 40 |
+
}
|
| 41 |
+
results.append(res)
|
| 42 |
+
|
| 43 |
+
return results
|
| 44 |
+
|
| 45 |
+
|
orchestration_agent/utils/utils.py
CHANGED
|
@@ -4,6 +4,10 @@ import ast
|
|
| 4 |
from groq import Groq
|
| 5 |
import os
|
| 6 |
from .prompts import captioning_prompt
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
def caption_image(image_base64,user_input):
|
|
@@ -36,3 +40,30 @@ def caption_image(image_base64,user_input):
|
|
| 36 |
return ''
|
| 37 |
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
from groq import Groq
|
| 5 |
import os
|
| 6 |
from .prompts import captioning_prompt
|
| 7 |
+
from utils.models_loader import llm
|
| 8 |
+
from langchain_core.messages import FunctionMessage , AIMessage
|
| 9 |
+
from .tools import retrieve_tool
|
| 10 |
+
from.prompts import show_analytics_prompt
|
| 11 |
|
| 12 |
|
| 13 |
def caption_image(image_base64,user_input):
|
|
|
|
| 40 |
return ''
|
| 41 |
|
| 42 |
|
| 43 |
+
def show_analytics(business_details):
|
| 44 |
+
|
| 45 |
+
tool_response = retrieve_tool(str(business_details))
|
| 46 |
+
# template = [SystemMessage(content=show_analytics_prompt()),
|
| 47 |
+
# HumanMessage(content=str(business_details)),
|
| 48 |
+
# ToolMessage(content=tool_response, tool_call_id='analytics_id')]
|
| 49 |
+
# response = llm.invoke(template).content
|
| 50 |
+
return tool_response
|
| 51 |
+
|
| 52 |
+
def extract_latest_response_block(response):
|
| 53 |
+
latest_block = []
|
| 54 |
+
temp_block = []
|
| 55 |
+
|
| 56 |
+
# Reverse iterate through the messages
|
| 57 |
+
for message in reversed(response):
|
| 58 |
+
if isinstance(message, (FunctionMessage, AIMessage)):
|
| 59 |
+
temp_block.insert(0, message.content)
|
| 60 |
+
|
| 61 |
+
# Once we collect 3 items in correct structure, stop
|
| 62 |
+
if len(temp_block) == 3:
|
| 63 |
+
if "tool=" in temp_block[1] and "query_response" in temp_block[1]:
|
| 64 |
+
latest_block = temp_block
|
| 65 |
+
break
|
| 66 |
+
else:
|
| 67 |
+
temp_block = []
|
| 68 |
+
|
| 69 |
+
return latest_block
|
test.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import faiss
|
| 2 |
+
import ast
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import numpy as np
|
| 5 |
+
from utils.models_loader import ST
|
| 6 |
+
import json
|
| 7 |
+
|
| 8 |
+
def retrieve_tool(business_details):
|
| 9 |
+
'''
|
| 10 |
+
Always invoke this tool.
|
| 11 |
+
Retrieve influencer's data by semantic search of **business details**.
|
| 12 |
+
'''
|
| 13 |
+
# === Load CSV ===
|
| 14 |
+
csv_path = 'extracted_data.csv'
|
| 15 |
+
df = pd.read_csv(csv_path)
|
| 16 |
+
|
| 17 |
+
# === Parse stored embeddings ===
|
| 18 |
+
df['embeddings'] = df['embeddings'].apply(lambda x: ast.literal_eval(x) if isinstance(x, str) else x)
|
| 19 |
+
embeddings = np.vstack(df['embeddings'].values).astype('float32')
|
| 20 |
+
|
| 21 |
+
# === Build FAISS index ===
|
| 22 |
+
dimension = embeddings.shape[1]
|
| 23 |
+
index = faiss.IndexFlatL2(dimension)
|
| 24 |
+
index.add(embeddings)
|
| 25 |
+
|
| 26 |
+
# === Encode the query and search ===
|
| 27 |
+
query_embedding = ST.encode(str(business_details)).reshape(1, -1).astype('float32')
|
| 28 |
+
top_k = 15
|
| 29 |
+
distances, indices = index.search(query_embedding, top_k)
|
| 30 |
+
|
| 31 |
+
# === Format results ===
|
| 32 |
+
results = []
|
| 33 |
+
for i, idx in enumerate(indices[0]):
|
| 34 |
+
res = {
|
| 35 |
+
'username': df.iloc[idx]['username'],
|
| 36 |
+
'likesCount': int(df.iloc[idx]['likesCount']),
|
| 37 |
+
'commentCount': int(df.iloc[idx]['commentCount'])
|
| 38 |
+
}
|
| 39 |
+
results.append(res)
|
| 40 |
+
|
| 41 |
+
return results
|
| 42 |
+
|
| 43 |
+
details = {
|
| 44 |
+
"business_type": "fitness and gym",
|
| 45 |
+
"platform": "Instagram, TikTok",
|
| 46 |
+
"target_audience": "young Nepali adults (ages 18–40) who are health-conscious and active on social media",
|
| 47 |
+
"business_goals": "to expand gym branches across all major cities of Nepal and build a strong fitness community",
|
| 48 |
+
"offerings": "personal training, group fitness classes, modern workout equipment, nutrition guidance, and wellness programs",
|
| 49 |
+
"Challenges_faced": "attracting loyal members, standing out in a competitive market, and promoting consistent engagement"
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
print(retrieve_tool(details))
|
utils/__pycache__/data_loader.cpython-312.pyc
CHANGED
|
Binary files a/utils/__pycache__/data_loader.cpython-312.pyc and b/utils/__pycache__/data_loader.cpython-312.pyc differ
|
|
|
utils/__pycache__/models_loader.cpython-312.pyc
CHANGED
|
Binary files a/utils/__pycache__/models_loader.cpython-312.pyc and b/utils/__pycache__/models_loader.cpython-312.pyc differ
|
|
|
utils/data_loader.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
|
| 2 |
from datasets import load_dataset
|
| 3 |
|
| 4 |
-
# print("Loading dataset and indexing FAISS...") # Optional: for debugging
|
| 5 |
|
| 6 |
dataset = load_dataset("subashdvorak/tiktok-formatted-story-v2", revision="embedded")
|
| 7 |
data = dataset['train'].add_faiss_index('embeddings')
|
| 8 |
-
|
| 9 |
def load_influencer_data():
|
| 10 |
return data
|
|
|
|
|
|
|
|
|
| 1 |
|
| 2 |
from datasets import load_dataset
|
| 3 |
|
|
|
|
| 4 |
|
| 5 |
dataset = load_dataset("subashdvorak/tiktok-formatted-story-v2", revision="embedded")
|
| 6 |
data = dataset['train'].add_faiss_index('embeddings')
|
|
|
|
| 7 |
def load_influencer_data():
|
| 8 |
return data
|
| 9 |
+
|
| 10 |
+
|
utils/models_loader.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
from langchain_groq import ChatGroq
|
| 2 |
from langchain_openai import ChatOpenAI
|
| 3 |
-
|
|
|
|
|
|
|
| 4 |
# from huggingface_hub import InferenceClient
|
| 5 |
from huggingface_hub import login
|
| 6 |
from dotenv import load_dotenv
|
|
@@ -14,8 +16,11 @@ login(os.environ['HUGGINGFACEHUB_ACCESS_TOKEN'])
|
|
| 14 |
os.environ['GROQ_API_KEY']=os.getenv('GROQ_API_KEY')
|
| 15 |
|
| 16 |
|
|
|
|
|
|
|
|
|
|
| 17 |
llm = ChatGroq(
|
| 18 |
-
model="llama-3.
|
| 19 |
temperature=0.7,
|
| 20 |
|
| 21 |
)
|
|
@@ -46,10 +51,12 @@ class HFEmbeddingAPI:
|
|
| 46 |
return np.array(embeddings[0]) if len(embeddings) == 1 else np.array(embeddings)
|
| 47 |
|
| 48 |
# Instantiate your API-backed "SentenceTransformer"
|
| 49 |
-
ST = HFEmbeddingAPI(
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
)
|
|
|
|
|
|
|
| 53 |
|
| 54 |
# Initiated the models for ideation
|
| 55 |
|
|
@@ -78,9 +85,9 @@ improver_llm = ChatOpenAI(
|
|
| 78 |
# temperature=0.7,
|
| 79 |
# max_tokens=500,
|
| 80 |
# )
|
| 81 |
-
ideator_llm =
|
| 82 |
-
critic_llm =
|
| 83 |
-
validator_llm =
|
| 84 |
|
| 85 |
|
| 86 |
# validator_llm = ChatGroq(
|
|
|
|
| 1 |
from langchain_groq import ChatGroq
|
| 2 |
from langchain_openai import ChatOpenAI
|
| 3 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 4 |
+
|
| 5 |
+
from sentence_transformers import SentenceTransformer
|
| 6 |
# from huggingface_hub import InferenceClient
|
| 7 |
from huggingface_hub import login
|
| 8 |
from dotenv import load_dotenv
|
|
|
|
| 16 |
os.environ['GROQ_API_KEY']=os.getenv('GROQ_API_KEY')
|
| 17 |
|
| 18 |
|
| 19 |
+
|
| 20 |
+
# llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash")
|
| 21 |
+
|
| 22 |
llm = ChatGroq(
|
| 23 |
+
model="llama-3.1-8b-instant",
|
| 24 |
temperature=0.7,
|
| 25 |
|
| 26 |
)
|
|
|
|
| 51 |
return np.array(embeddings[0]) if len(embeddings) == 1 else np.array(embeddings)
|
| 52 |
|
| 53 |
# Instantiate your API-backed "SentenceTransformer"
|
| 54 |
+
# ST = HFEmbeddingAPI(
|
| 55 |
+
# api_url="https://router.huggingface.co/hf-inference/models/mixedbread-ai/mxbai-embed-large-v1/pipeline/feature-extraction",
|
| 56 |
+
# token=os.environ.get('HUGGINGFACEHUB_ACCESS_TOKEN')
|
| 57 |
+
# )
|
| 58 |
+
|
| 59 |
+
ST = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1")
|
| 60 |
|
| 61 |
# Initiated the models for ideation
|
| 62 |
|
|
|
|
| 85 |
# temperature=0.7,
|
| 86 |
# max_tokens=500,
|
| 87 |
# )
|
| 88 |
+
ideator_llm = llm
|
| 89 |
+
critic_llm = llm
|
| 90 |
+
validator_llm = llm
|
| 91 |
|
| 92 |
|
| 93 |
# validator_llm = ChatGroq(
|