subashpoudel commited on
Commit
be3a5c4
·
0 Parent(s):

Implemented the workflow and integrated in fast api

Browse files
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ myenv
2
+ .env
__pycache__/main.cpython-312.pyc ADDED
Binary file (985 Bytes). View file
 
langgraph.json ADDED
File without changes
main.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel
3
+ from my_agent.agent import build_graph
4
+ import pandas as pd
5
+
6
+ app = FastAPI()
7
+ graph = build_graph()
8
+
9
+ # Optional: define input schema
10
+ class RequestInput(BaseModel):
11
+ # query: list =[ "I want to make a promotional video of restaurant near lakeside"]
12
+ query: list
13
+
14
+
15
+ @app.post("/run")
16
+ def run_graph(input_data: RequestInput):
17
+ result = graph.invoke({'topic' : input_data.query})
18
+ return {'returned_story': result['final_story']}
19
+
my_agent/__init__.py ADDED
File without changes
my_agent/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (176 Bytes). View file
 
my_agent/__pycache__/agent.cpython-312.pyc ADDED
Binary file (1.5 kB). View file
 
my_agent/agent.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.graph import StateGraph, START, END
2
+ from .utils.state import State
3
+ from .utils.nodes import retrieve, generate_story, generate_brainstroming , generate_final_story, route_after_selection, select_preferred_topics
4
+
5
+ def build_graph():
6
+ builder = StateGraph(State)
7
+ builder.add_node(retrieve)
8
+ builder.add_node(generate_story)
9
+ builder.add_node(generate_brainstroming)
10
+ builder.add_node(select_preferred_topics)
11
+ builder.add_node(generate_final_story)
12
+
13
+
14
+ # Normal edges
15
+ builder.add_edge(START, "retrieve")
16
+ builder.add_edge("retrieve", "generate_story")
17
+ builder.add_edge("generate_story", "generate_brainstroming")
18
+ builder.add_edge("generate_brainstroming", "select_preferred_topics")
19
+
20
+ # Conditional edge
21
+ builder.add_conditional_edges("select_preferred_topics", route_after_selection,{True:'retrieve',False:'generate_final_story'})
22
+ builder.add_edge("generate_final_story",END)
23
+
24
+ return builder.compile()
my_agent/utils/__init__.py ADDED
File without changes
my_agent/utils/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (182 Bytes). View file
 
my_agent/utils/__pycache__/data_loader.cpython-312.pyc ADDED
Binary file (561 Bytes). View file
 
my_agent/utils/__pycache__/models_loader.cpython-312.pyc ADDED
Binary file (988 Bytes). View file
 
my_agent/utils/__pycache__/nodes.cpython-312.pyc ADDED
Binary file (9.13 kB). View file
 
my_agent/utils/__pycache__/state.cpython-312.pyc ADDED
Binary file (987 Bytes). View file
 
my_agent/utils/__pycache__/tools.cpython-312.pyc ADDED
Binary file (2.41 kB). View file
 
my_agent/utils/data_loader.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from datasets import load_dataset
2
+
3
+ def load_influencer_data():
4
+ dataset = load_dataset("subashdvorak/tiktok-agentic-story",revision="embedded")
5
+ data= dataset['train'].add_faiss_index('embeddings')
6
+ return data
7
+
8
+
9
+
my_agent/utils/models_loader.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from langchain_groq import ChatGroq
3
+ from sentence_transformers import SentenceTransformer
4
+ from huggingface_hub import login
5
+ from dotenv import load_dotenv
6
+ load_dotenv()
7
+ import os
8
+ from langchain_huggingface import HuggingFaceEndpoint
9
+ os.environ['HUGGINGFACEHUB_ACCESS_TOKEN']=os.getenv('HUGGINGFACEHUB_ACCESS_TOKEN')
10
+ login(os.environ['HUGGINGFACEHUB_ACCESS_TOKEN'])
11
+ os.environ['GROQ_API_KEY']=os.getenv('GROQ_API_KEY')
12
+
13
+ ST = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1")
14
+
15
+ llm = ChatGroq(
16
+ model="llama3-8b-8192",
17
+ temperature=0,
18
+ max_tokens=None,
19
+ timeout=None,
20
+ max_retries=2,
21
+
22
+ )
23
+
24
+
25
+
26
+
27
+
my_agent/utils/nodes.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import ast
3
+ from .state import State
4
+ from .tools import StoryFormatter, BrainstromTopicFormatter
5
+ from langchain_core.messages import SystemMessage
6
+ from .models_loader import llm , ST
7
+ from .data_loader import load_influencer_data
8
+
9
+
10
+ def retrieve(state: State) -> State:
11
+ print('Moving to retrieval process')
12
+ retrievals=[]
13
+ for topic in state.topic: # Loop through each topic
14
+ embedded_query = ST.encode(topic) # Embed each topic
15
+ data = load_influencer_data()
16
+ scores, retrieved_examples = data.get_nearest_examples("embeddings", embedded_query, k=1)
17
+
18
+ # Construct a list of dictionaries for this topic
19
+ result = [{user: story} for user, story in zip(retrieved_examples['username'], retrieved_examples['agentic_story'])]
20
+ retrievals.append(result)
21
+ print('Retrieval process completed......')
22
+ state.retrievals.append(retrievals)
23
+
24
+ print('The retrieval is:\n',state.retrievals )
25
+ # return State(messages="Retrieved",topic=state.topic,retrievals=state.retrievals)
26
+ return state
27
+
28
+ def generate_story(state:State)-> State:
29
+ topic=state.topic
30
+ print('The state retrieval is:',state.retrievals)
31
+ retrieval_list= state.retrievals[-1]
32
+ agentic_stories = []
33
+
34
+ for item in retrieval_list:
35
+ print('item:', item[-1].values())
36
+
37
+ agentic_stories.extend(item[-1].values()) # Add all stories to the list
38
+
39
+ retrieval = " ".join(agentic_stories)
40
+
41
+ if len(state.preferred_topics)==0:
42
+ template = f'''I want to create a detailed storyline for a video in any domain. You have to provide me that storyline what to include in the video.
43
+ Now, i am giving you the topic of the video. But the need is to generate the story focusing on the format that i'll provide to you.
44
+ You can use this format for the reference purpose, not for the exact similar generation. Th format is:\n{retrieval}.
45
+ \n\n Now let's start creating the storyline for my topic. The topic of the video is: \n\n{state.topic}'''
46
+ else:
47
+ template = f'''I want to create a detailed storyline for a video in the given topic. You have to provide me that storyline what to include in the video.
48
+ Now, i am giving you the topic of the video. But the need is to generate the story focusing on the format that i'll provide to you.
49
+ You can use this format for the reference purpose, not for the exact similar generation. The format is:\n{retrieval}.
50
+ \n\n Now let's start creating the storyline for my topic. The topic of the video is: \n\n{state.topic}\n\n
51
+
52
+ **Final Reminder** You have to strongly focus on these topics while creating the storyline: {state.preferred_topics[-1]}'''
53
+
54
+
55
+ messages = [SystemMessage(content=template)]
56
+ response = llm.bind_tools([StoryFormatter]).invoke(messages)
57
+ print('The response is:',response)
58
+ if hasattr(response, 'tool_calls') and response.tool_calls:
59
+ response = response.tool_calls[0]['args']
60
+ elif hasattr(response, 'content'):
61
+ response = response.content
62
+ else:
63
+ response = "No response"
64
+ state.stories.append(response)
65
+ # return State(messages="Story generated", topic=state.topic,stories=state.stories)
66
+ return state
67
+
68
+
69
+
70
+ def generate_brainstroming(state:State)-> State:
71
+ story=state.stories[-1]
72
+
73
+ template= f'''I want to brainstorm ways to diversify or improve a storyline in exactly 4 sentences.
74
+ The goal is to generate creative and actionable ideas that are not on the storyline on how the storyline can be expanded or modified for better engagement.
75
+ For example: If the storyline is about creating a promotional video for a restaurant, the new suggestions might include:
76
+ - I want to showcase the chef preparing a signature dish.
77
+ - I want to add a sequence of customers sharing their experiences at the restaurant.
78
+ - I want to highlight the farm-to-table sourcing of ingredients with a short segment showing local farms.
79
+ - I want to include a time-lapse of the restaurant transforming from day to night, capturing its unique ambiance.
80
+ - I want to feature a quick interview with the owner sharing the story behind the restaurant.
81
+ Now, I will provide you with the storyline. The storyline is:\n{story}'''
82
+
83
+ messages = [SystemMessage(content=template)]
84
+ response = llm.bind_tools([BrainstromTopicFormatter]).invoke(messages)
85
+ print('The response is:',response)
86
+ if hasattr(response, 'tool_calls') and response.tool_calls:
87
+ response = response.tool_calls[0]['args']
88
+ elif hasattr(response, 'content'):
89
+ response = response.content
90
+ else:
91
+ response = "No response"
92
+
93
+ state.brainstroming_topics.append(response)
94
+ print('The brainstroming topics are:',state.brainstroming_topics)
95
+ # return State(messages="Story generated",topic=state.topic,brainstroming_topics=state.brainstroming_topics)
96
+ return state
97
+
98
+
99
+
100
+ def select_preferred_topics(state: State)-> State:
101
+ print("---human_feedback---")
102
+
103
+ topic_values = list(state.brainstroming_topics[-1].values())
104
+
105
+ print("Available topics:")
106
+ for idx, topic in enumerate(topic_values, 1):
107
+ print(f"{idx}. {topic}")
108
+
109
+ raw_input_str = input("Enter the numbers of your preferred topics (comma-separated), or press Enter to skip: ").strip()
110
+
111
+ if not raw_input_str:
112
+ state.carry_on=False
113
+ print("No topics selected. Ending process.")
114
+ return state
115
+
116
+ try:
117
+ preferred_indices = [int(i.strip()) for i in raw_input_str.split(",")]
118
+ preferred_topics = [topic_values[i - 1] for i in preferred_indices if 0 < i <= len(topic_values)]
119
+ state.preferred_topics.append(preferred_topics)
120
+ except Exception:
121
+ state.carry_on=False
122
+ print("Invalid input. Please try again.")
123
+ return state
124
+
125
+ if not preferred_topics:
126
+ state.carry_on=False
127
+ print("No valid topics selected. Ending process.")
128
+ return state
129
+
130
+ print("You selected:")
131
+ print(preferred_topics)
132
+ state.carry_on=True
133
+ return state
134
+
135
+
136
+ def generate_final_story(state:State)-> State:
137
+ template = f'''I want to create a detailed storyline for a video in the given topic. You have to provide me that storyline what to include in the video.
138
+ Now, i am giving you the topic of the video. But the need is to generate the story focusing on the format that i'll provide to you.
139
+ You can use this format for the reference purpose, not for the exact similar generation. The format is:\n{state.retrievals[-1]}.
140
+ \n\n Now let's start creating the storyline for my topic. The topic of the video is: \n\n{state.topic}\n\n
141
+
142
+ **Final Reminder** You have to strongly focus on these topics while creating the storyline: {[item for sublist in state.preferred_topics for item in sublist]}'''
143
+ messages = [SystemMessage(content=template)]
144
+ response = llm.bind_tools([StoryFormatter]).invoke(messages)
145
+ print('The final response is:',response)
146
+ if hasattr(response, 'tool_calls') and response.tool_calls:
147
+ response = response.tool_calls[0]['args']
148
+ elif hasattr(response, 'content'):
149
+ response = response.content
150
+ else:
151
+ response = "No response"
152
+ state.final_story=response
153
+ state.stories.append(response)
154
+ return state
155
+
156
+
157
+
158
+ def route_after_selection(state:State):
159
+ print('The output is:',state.carry_on)
160
+ return state.carry_on
my_agent/utils/state.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, ConfigDict
2
+ from typing import Optional
3
+ import pandas as pd
4
+
5
+ class State(BaseModel):
6
+ carry_on: Optional[bool]=False
7
+ messages: Optional[str] = None
8
+ topic: list
9
+ brainstroming_topics: Optional[list] = []
10
+ preferred_topics: Optional[list] = []
11
+ stories : Optional[list]=[]
12
+ final_story: Optional[str]=None
13
+ retrievals : Optional[list]=[]
14
+ model_config = ConfigDict(arbitrary_types_allowed=True)
my_agent/utils/tools.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import SystemMessage
2
+ from langchain_groq import ChatGroq
3
+ from pydantic import BaseModel, Field
4
+ from dotenv import load_dotenv
5
+ load_dotenv()
6
+ import os
7
+ import numpy as np
8
+
9
+ os.environ['GROQ_API_KEY']=os.getenv('GROQ_API_KEY')
10
+
11
+ llm = ChatGroq(
12
+ model="llama3-8b-8192",
13
+ temperature=0,
14
+ max_tokens=None,
15
+ timeout=None,
16
+ max_retries=2,
17
+
18
+ )
19
+
20
+ class StoryFormatter(BaseModel):
21
+ """Always use this tool to structure your response to the user."""
22
+ story: str=Field(description="How to introduce the scene and set the tone. What is happening in the scene? Describe key visuals and actions")
23
+ narration:str=Field(description="Suggestions for narration or voiceover that complements the visuals." )
24
+ text_in_the_Video:str=Field(description="Propose important text overlays for key moments.")
25
+ transitions:str=Field(description="Smooth transitions between scenes to maintain flow.")
26
+ emotional_tone:str=Field(description="The mood and energy of the scenes (e.g., excitement, calm, tension, joy")
27
+ key_visuals:str=Field(description="Important props, locations, sound effects, or background music to enhance the video.")
28
+
29
+
30
+ class BrainstromTopicFormatter(BaseModel):
31
+ topic1:str=Field(description="First brainstorming topic of the story")
32
+ topic2:str=Field(description="Second brainstorming topic of the story")
33
+ topic3:str=Field(description="Third brainstorming topic of the story")
34
+ topic4:str=Field(description="Fourth brainstorming topic of the story")
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ langgraph
2
+ langsmith
3
+ langchain_groq
4
+ pydantic
5
+ datasets
6
+ faiss-cpu
7
+ dotenv
8
+ fastapi
9
+ uvicorn
10
+ numpy
11
+ pandas
12
+ langchain_huggingface