subashpoudel commited on
Commit
38cf703
·
1 Parent(s): f054586

Code refactoring

Browse files
api/routers/__pycache__/ideation.cpython-312.pyc CHANGED
Binary files a/api/routers/__pycache__/ideation.cpython-312.pyc and b/api/routers/__pycache__/ideation.cpython-312.pyc differ
 
api/routers/__pycache__/orchestration.cpython-312.pyc CHANGED
Binary files a/api/routers/__pycache__/orchestration.cpython-312.pyc and b/api/routers/__pycache__/orchestration.cpython-312.pyc differ
 
api/routers/__pycache__/show_analytics.cpython-312.pyc CHANGED
Binary files a/api/routers/__pycache__/show_analytics.cpython-312.pyc and b/api/routers/__pycache__/show_analytics.cpython-312.pyc differ
 
api/routers/ideation.py CHANGED
@@ -2,11 +2,12 @@ import ast
2
  from fastapi import APIRouter
3
  from fastapi.responses import StreamingResponse
4
  from api.stored_data import stored_data
5
- from src.genai.ideation_agent.agent import ideation_graph
6
  from langgraph.errors import GraphRecursionError
7
 
8
  router = APIRouter()
9
- idea_graph = ideation_graph()
 
10
 
11
  @router.post("/ideation")
12
  def ideation_endpoint():
 
2
  from fastapi import APIRouter
3
  from fastapi.responses import StreamingResponse
4
  from api.stored_data import stored_data
5
+ from src.genai.ideation_agent.agent import IdeationAgent
6
  from langgraph.errors import GraphRecursionError
7
 
8
  router = APIRouter()
9
+ agent = IdeationAgent()
10
+ idea_graph = agent.ideation_graph()
11
 
12
  @router.post("/ideation")
13
  def ideation_endpoint():
api/routers/orchestration.py CHANGED
@@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends
4
  from fastapi.responses import StreamingResponse
5
  from pydantic import BaseModel
6
  from api.stored_data import stored_data
7
- from src.genai.orchestration_agent.agent import orchestration_chat
8
  from typing import Optional
9
 
10
  class OrchestrationRequest(BaseModel):
@@ -12,11 +12,11 @@ class OrchestrationRequest(BaseModel):
12
  image_base64 : Optional[list] = []
13
 
14
  router= APIRouter()
15
-
16
  @router.post("/orchestration")
17
  def orchestration_endpoint(request:OrchestrationRequest):
18
  print('Image:',request.image_base64)
19
- result = orchestration_chat(request.message , request.image_base64)
20
  if result.image_caption != '': stored_data['image_caption']=result.image_caption
21
  if result.video_idea !='' or result.video_idea != 'null': stored_data['refined_ideation']= result.video_idea
22
  if result.video_story!='' or result.video_story!='null': stored_data['final_story']= result.video_story
 
4
  from fastapi.responses import StreamingResponse
5
  from pydantic import BaseModel
6
  from api.stored_data import stored_data
7
+ from src.genai.orchestration_agent.agent import OrchestrationAgent
8
  from typing import Optional
9
 
10
  class OrchestrationRequest(BaseModel):
 
12
  image_base64 : Optional[list] = []
13
 
14
  router= APIRouter()
15
+ agent = OrchestrationAgent()
16
  @router.post("/orchestration")
17
  def orchestration_endpoint(request:OrchestrationRequest):
18
  print('Image:',request.image_base64)
19
+ result = agent.chat(request.message , request.image_base64)
20
  if result.image_caption != '': stored_data['image_caption']=result.image_caption
21
  if result.video_idea !='' or result.video_idea != 'null': stored_data['refined_ideation']= result.video_idea
22
  if result.video_story!='' or result.video_story!='null': stored_data['final_story']= result.video_story
api/routers/show_analytics.py CHANGED
@@ -1,9 +1,9 @@
1
  from fastapi import APIRouter
2
  from api.stored_data import stored_data
3
- from src.genai.orchestration_agent.utils.utils import show_analytics
4
 
5
  router=APIRouter()
6
  @router.post("/show-analytics")
7
  def show_analytics_endpoint():
8
- response = show_analytics(stored_data['business_details'])
9
  return {'response': response}
 
1
  from fastapi import APIRouter
2
  from api.stored_data import stored_data
3
+ from src.genai.orchestration_agent.utils.utils import AnalyticsViewer
4
 
5
  router=APIRouter()
6
  @router.post("/show-analytics")
7
  def show_analytics_endpoint():
8
+ response = AnalyticsViewer(stored_data['business_details']).show_analytics()
9
  return {'response': response}
logs/access.log CHANGED
@@ -206,3 +206,38 @@
206
  2025-08-11 14:37:03,225 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/ideation
207
  2025-08-11 14:39:51,118 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/ideation
208
  2025-08-11 14:40:35,783 | INFO | access_logger | Response status: 200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  2025-08-11 14:37:03,225 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/ideation
207
  2025-08-11 14:39:51,118 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/ideation
208
  2025-08-11 14:40:35,783 | INFO | access_logger | Response status: 200
209
+ 2025-08-12 17:03:01,254 | INFO | access_logger | Request: GET http://127.0.0.1:8000/docs
210
+ 2025-08-12 17:03:01,592 | INFO | access_logger | Response status: 200
211
+ 2025-08-12 17:03:01,863 | INFO | access_logger | Request: GET http://127.0.0.1:8000/openapi.json
212
+ 2025-08-12 17:03:02,637 | INFO | access_logger | Response status: 200
213
+ 2025-08-12 17:03:14,189 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/show-analytics
214
+ 2025-08-12 17:03:25,264 | INFO | access_logger | Response status: 200
215
+ 2025-08-13 11:48:42,006 | INFO | access_logger | Request: GET http://127.0.0.1:8000/docs
216
+ 2025-08-13 11:48:43,706 | INFO | access_logger | Response status: 200
217
+ 2025-08-13 11:48:43,850 | INFO | access_logger | Request: GET http://127.0.0.1:8000/openapi.json
218
+ 2025-08-13 11:48:43,866 | INFO | access_logger | Response status: 200
219
+ 2025-08-13 11:48:54,938 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/show-analytics
220
+ 2025-08-13 11:48:54,942 | INFO | access_logger | Response status: 200
221
+ 2025-08-13 12:14:41,238 | INFO | access_logger | Request: GET http://127.0.0.1:8000/docs
222
+ 2025-08-13 12:14:41,260 | INFO | access_logger | Response status: 200
223
+ 2025-08-13 12:14:41,406 | INFO | access_logger | Request: GET http://127.0.0.1:8000/openapi.json
224
+ 2025-08-13 12:14:41,418 | INFO | access_logger | Response status: 200
225
+ 2025-08-13 12:14:46,506 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/show-analytics
226
+ 2025-08-13 12:14:46,510 | INFO | access_logger | Response status: 200
227
+ 2025-08-13 13:53:14,104 | INFO | access_logger | Request: GET http://127.0.0.1:8000/openapi.json
228
+ 2025-08-13 13:53:14,154 | INFO | access_logger | Response status: 200
229
+ 2025-08-13 13:53:22,748 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/show-analytics
230
+ 2025-08-13 13:53:24,417 | INFO | access_logger | Response status: 200
231
+ 2025-08-13 13:53:36,718 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/orchestration
232
+ 2025-08-13 13:53:44,587 | INFO | access_logger | Response status: 200
233
+ 2025-08-13 13:54:08,702 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/orchestration
234
+ 2025-08-13 13:54:18,367 | INFO | access_logger | Response status: 200
235
+ 2025-08-13 13:55:29,606 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/orchestration
236
+ 2025-08-13 13:55:45,000 | INFO | access_logger | Response status: 200
237
+ 2025-08-13 17:20:37,737 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/ideation
238
+ 2025-08-13 17:22:51,262 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/ideation
239
+ 2025-08-13 17:23:31,261 | INFO | access_logger | Response status: 200
240
+ 2025-08-13 17:24:19,755 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/show-analytics
241
+ 2025-08-13 17:24:22,399 | INFO | access_logger | Response status: 200
242
+ 2025-08-13 17:24:37,955 | INFO | access_logger | Request: POST http://127.0.0.1:8000/api/orchestration
243
+ 2025-08-13 17:24:51,218 | INFO | access_logger | Response status: 200
logs/app.log CHANGED
@@ -1 +1,5 @@
1
  2025-07-30 16:53:23,605 | INFO | app_logger | Showing Analytics of the influencers after context analysis.
 
 
 
 
 
1
  2025-07-30 16:53:23,605 | INFO | app_logger | Showing Analytics of the influencers after context analysis.
2
+ 2025-08-12 17:03:25,262 | INFO | app_logger | Showing Analytics of the influencers after context analysis.
3
+ 2025-08-13 11:48:54,941 | ERROR | app_logger | Error while showing analytics: retrieve_data_for_analytics() missing 1 required positional argument: 'business_details'
4
+ 2025-08-13 13:53:24,416 | INFO | app_logger | Showing Analytics of the influencers after context analysis.
5
+ 2025-08-13 17:24:22,398 | INFO | app_logger | Showing Analytics of the influencers after context analysis.
logs/errors.log CHANGED
@@ -0,0 +1 @@
 
 
1
+ 2025-08-13 12:14:46,509 | ERROR | error_logger | Error while showing analytics: retrieve_data_for_analytics() missing 1 required positional argument: 'business_details'
src/genai/ideation_agent/__pycache__/agent.cpython-312.pyc CHANGED
Binary files a/src/genai/ideation_agent/__pycache__/agent.cpython-312.pyc and b/src/genai/ideation_agent/__pycache__/agent.cpython-312.pyc differ
 
src/genai/ideation_agent/agent.py CHANGED
@@ -1,32 +1,33 @@
1
  from langgraph.graph import StateGraph, START, END , MessagesState
2
  from .utils.state import State
3
- from .utils.nodes import ideator , critic , format_response , validator1 , validator2 , route1_after_validation , route2_after_validation
4
  from langgraph.checkpoint.memory import MemorySaver
5
- memory = MemorySaver()
6
 
 
 
 
7
 
8
- def ideation_graph():
9
- graph_builder= StateGraph(State)
10
- graph_builder.add_node(ideator)
11
- graph_builder.add_node(critic)
12
- graph_builder.add_node(format_response)
13
- graph_builder.add_node(validator1)
14
- graph_builder.add_node(validator2)
15
 
 
 
 
 
 
 
16
 
17
- graph_builder.add_edge(START, "ideator") # Start the graph with node_1
18
- graph_builder.add_edge("ideator", "critic")
19
- graph_builder.add_edge("critic", "format_response")
20
- graph_builder.add_edge("format_response", "validator1")
21
- graph_builder.add_edge("validator1", "validator2")
22
- graph_builder.add_edge("validator2", END)
23
 
 
 
 
24
 
25
- # Use conditional routing from validator
26
- graph_builder.add_conditional_edges("validator1", route1_after_validation,{False:'critic',True:'validator2'})
27
- graph_builder.add_conditional_edges("validator2", route2_after_validation,{False:'critic',True:END})
28
-
29
- return graph_builder.compile(checkpointer=memory)
30
 
31
 
32
 
 
1
  from langgraph.graph import StateGraph, START, END , MessagesState
2
  from .utils.state import State
3
+ from .utils.nodes import IdeatorNode , CriticNode , FormatResponseNode, Validators , RoutingsAfterValidation
4
  from langgraph.checkpoint.memory import MemorySaver
 
5
 
6
+ class IdeationAgent:
7
+ def __init__(self):
8
+ self.memory = MemorySaver()
9
 
10
+ def ideation_graph(self):
11
+ graph_builder= StateGraph(State)
12
+ graph_builder.add_node("ideator", IdeatorNode().run)
13
+ graph_builder.add_node("critic", CriticNode().run)
14
+ graph_builder.add_node("format_response", FormatResponseNode().run)
15
+ graph_builder.add_node("validator1", Validators().run_validator1)
16
+ graph_builder.add_node("validator2", Validators().run_validator2)
17
 
18
+ graph_builder.add_edge(START, "ideator") # Start the graph with node_1
19
+ graph_builder.add_edge("ideator", "critic")
20
+ graph_builder.add_edge("critic", "format_response")
21
+ graph_builder.add_edge("format_response", "validator1")
22
+ graph_builder.add_edge("validator1", "validator2")
23
+ graph_builder.add_edge("validator2", END)
24
 
 
 
 
 
 
 
25
 
26
+ # Use conditional routing from validator
27
+ graph_builder.add_conditional_edges("validator1", RoutingsAfterValidation().route1,{False:'critic',True:'validator2'})
28
+ graph_builder.add_conditional_edges("validator2", RoutingsAfterValidation().route2,{False:'critic',True:END})
29
 
30
+ return graph_builder.compile(checkpointer=self.memory)
 
 
 
 
31
 
32
 
33
 
src/genai/ideation_agent/utils/__pycache__/nodes.cpython-312.pyc CHANGED
Binary files a/src/genai/ideation_agent/utils/__pycache__/nodes.cpython-312.pyc and b/src/genai/ideation_agent/utils/__pycache__/nodes.cpython-312.pyc differ
 
src/genai/ideation_agent/utils/__pycache__/tools.cpython-312.pyc CHANGED
Binary files a/src/genai/ideation_agent/utils/__pycache__/tools.cpython-312.pyc and b/src/genai/ideation_agent/utils/__pycache__/tools.cpython-312.pyc differ
 
src/genai/ideation_agent/utils/nodes.py CHANGED
@@ -1,179 +1,113 @@
1
  from .state import State , ValidationFormatter , ImproverResponseFormatter, CriticResponseFormatter
2
- from .tools import retrieve_tool
3
  from langgraph.prebuilt import create_react_agent
4
  from src.genai.utils.models_loader import ideator_llm, critic_llm , improver_llm , validator_llm, llm
5
  from langchain_core.messages import SystemMessage , HumanMessage
6
  from .prompts import ideator_prompt , critic_prompt , improver_prompt , validator_prompt, idea_refinement_prompt
7
 
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- ideator_agent = create_react_agent(
11
- model=ideator_llm,
12
- tools=[retrieve_tool]
13
- )
14
- critic_agent = create_react_agent(
15
- model=critic_llm,
16
- tools=[retrieve_tool]
17
- )
18
-
19
- improver_agent = create_react_agent(
20
- model=improver_llm,
21
- tools=[]
22
- )
23
 
24
 
 
 
 
 
25
 
26
- def ideator(state:State):
27
- template = ideator_prompt(state)
28
- # imdb_reference = retrieve_tool(state.business_details[-1])
29
- messages = [SystemMessage(content=template),
30
- HumanMessage(content=f'''The business_details is\n{state.business_details[-1]}\n
31
- The information of the image is:\n{state.image_caption[-1]}''')]
32
- try:
33
- response = ideator_agent.invoke({'messages':messages})
34
- print('Ideator Response:',response)
35
- response = response['messages'][-1].content
36
- state.ideator_response.append(response)
37
- print('Ideator Generated the story')
38
- return state
39
 
40
- except:
41
- response = ideator_llm.invoke(messages)
42
- print('Ideator backup Response:',response.content)
43
- state.ideator_response.append(response.content)
44
- return state
45
-
46
- def critic(state:State):
47
- template = critic_prompt(state)
48
- # imdb_reference= retrieve_tool(state.business_details[-1])
49
- messages = [SystemMessage(content=template),
50
- HumanMessage(content=f'''The business_details is\n{state.business_details[-1]}\n
51
- The information of the image is:\n{state.image_caption[-1]}''')]
52
 
53
- try:
54
- response = critic_agent.invoke({'messages':messages})
55
- response = response['messages'][-1].content
56
- print('Critic Response:',response)
57
- state.critic_response.append(response)
58
- print('Critic Evaluated the story')
59
- return state
60
 
61
- except:
62
- response = critic_llm.invoke(messages)
63
- print('Critic backup Response:',response.content)
64
- state.critic_response.append(response.content)
 
 
 
 
 
 
65
  return state
66
-
67
- def format_response(state:State):
68
- response_list = []
69
- messages = [SystemMessage(content='''Just extract all the 4 improved ideas and the faults of critic as it is from the critic's response'''),
70
- HumanMessage(content=f'''The critic's response is: \n {state.critic_response[-1]}''')]
71
- response = critic_llm.with_structured_output(CriticResponseFormatter).invoke(messages)
72
- response_list.append(response.improved_idea1)
73
- response_list.append(response.improved_idea2)
74
- response_list.append(response.improved_idea3)
75
- response_list.append(response.improved_idea4)
76
- state.formatted_response.append(str(response_list))
77
- state.ideator_fault.append(response.faults)
78
- print('Formatted Response:', response_list)
79
- return state
80
-
81
 
82
 
83
- # def improver(state:State):
84
- # response_list = []
85
- # template = improver_prompt(state)
86
- # messages = [SystemMessage(content=template),
87
- # HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}\n The information of the image is:\n{state.image_caption[-1]}''')]
88
- # print('Improver Prompt:',messages)
89
- # response = improver_llm.with_structured_output(ImproverResponseFormatter).invoke(messages)
90
- # response_list.append(response.improved_idea1)
91
- # response_list.append(response.improved_idea2)
92
- # response_list.append(response.improved_idea3)
93
- # response_list.append(response.improved_idea4)
94
 
95
- # state.improver_response.append(str(response_list))
96
- # state.critic_fault.append(response.faults)
97
- # print('Improver response:',response_list)
98
- # return state
99
 
 
 
100
 
101
 
102
- def validator1(state:State):
103
- template = validator_prompt(state)
104
- messages = [SystemMessage(content=template),
105
- HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}''')]
106
-
107
- response = validator_llm.with_structured_output(ValidationFormatter).invoke(messages)
108
- print(f'Validator 1 response: {response}')
109
- state.validator1_response.append(response.result)
110
- print('The state check:',state.validator1_response[-1])
111
- if 'not validated' in response.result:
112
- state.disagreement_reason.append(response.reason)
113
- return state
114
-
115
- def validator2(state:State):
116
- template = validator_prompt(state)
117
- messages = [SystemMessage(content=template),
118
- HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}''')]
119
-
120
- response = ideator_llm.with_structured_output(ValidationFormatter).invoke(messages)
121
- print(f'Validator 2 response: {response}')
122
- state.validator2_response.append(response.result)
123
- print('The state check:',state.validator2_response[-1])
124
- if 'not validated' in response.result:
125
- state.disagreement_reason.append(response.reason)
126
- return state
127
-
128
- # def validator3(state:State):
129
- # template = validator_prompt(state)
130
- # messages = [SystemMessage(content=template),
131
- # HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}''')]
132
-
133
- # response = critic_llm.with_structured_output(ValidationFormatter).invoke(messages)
134
- # print(f'Validator 3 response: {response}')
135
- # state.validator3_response.append(response.result)
136
- # print('The state check:',state.validator1_response[-1])
137
- # if 'not validated' in response.result:
138
- # state.disagreement_reason.append(response.reason)
139
- # return state
140
-
141
- # def validator4(state:State):
142
- # template = validator_prompt(state)
143
- # messages = [SystemMessage(content=template),
144
- # HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}''')]
145
-
146
- # response = improver_llm.with_structured_output(ValidationFormatter).invoke(messages)
147
- # print(f'Validator 4 response: {response}')
148
- # state.validator4_response.append(response.result)
149
- # print('The state check:',state.validator1_response[-1])
150
- # if 'not validated' in response.result:
151
- # state.disagreement_reason.append(response.reason)
152
- # return state
153
-
154
- def route1_after_validation(state:State):
155
- if 'not validated' in state.validator1_response[-1]:
156
- return False
157
- else:
158
- return True
159
-
160
-
161
- def route2_after_validation(state:State):
162
- if 'not validated' in state.validator2_response[-1]:
163
- return False
164
- else:
165
- return True
166
-
167
-
168
- # def route3_after_validation(state:State):
169
- # if 'not validated' in state.validator3_response[-1]:
170
- # return False
171
- # else:
172
- # return True
173
-
174
 
175
- # def route4_after_validation(state:State):
176
- # if 'not validated' in state.validator4_response[-1]:
177
- # return False
178
- # else:
179
- # return True
 
1
  from .state import State , ValidationFormatter , ImproverResponseFormatter, CriticResponseFormatter
2
+ from .tools import retrieve_imdb_ideas_tool , retrieve_influencers_data_tool
3
  from langgraph.prebuilt import create_react_agent
4
  from src.genai.utils.models_loader import ideator_llm, critic_llm , improver_llm , validator_llm, llm
5
  from langchain_core.messages import SystemMessage , HumanMessage
6
  from .prompts import ideator_prompt , critic_prompt , improver_prompt , validator_prompt, idea_refinement_prompt
7
 
8
 
9
+ class IdeatorNode:
10
+ def __init__(self):
11
+ self.ideator_agent = create_react_agent(model=ideator_llm, tools=[retrieve_imdb_ideas_tool])
12
+
13
+ def run(self, state:State):
14
+ template =ideator_prompt(state)
15
+ messages = [SystemMessage(content=template),
16
+ HumanMessage(content=f'''The business_details is\n{state.business_details[-1]}\n
17
+ The information of the image is:\n{state.image_caption[-1]}''')]
18
+ try:
19
+ response = self.ideator_agent.invoke({'messages':messages})
20
+ print('Ideator Response:',response)
21
+ response = response['messages'][-1].content
22
+ state.ideator_response.append(response)
23
+ print('Ideator Generated the story')
24
+ return state
25
+ except:
26
+ response = ideator_llm.invoke(messages)
27
+ print('Ideator backup Response:',response.content)
28
+ state.ideator_response.append(response.content)
29
+ return state
30
+
31
+
32
+ class CriticNode:
33
+ def __init__(self):
34
+ self.critic_agent = create_react_agent(model=critic_llm, tools=[retrieve_imdb_ideas_tool])
35
+
36
+ def run(self,state:State):
37
+ template = critic_prompt(state)
38
+ messages = [SystemMessage(content=template),
39
+ HumanMessage(content=f'''The business_details is\n{state.business_details[-1]}\n
40
+ The information of the image is:\n{state.image_caption[-1]}''')]
41
+
42
+ try:
43
+ response = self.critic_agent.invoke({'messages':messages})
44
+ response = response['messages'][-1].content
45
+ print('Critic Response:',response)
46
+ state.critic_response.append(response)
47
+ print('Critic Evaluated the story')
48
+ return state
49
+
50
+ except:
51
+ response = critic_llm.invoke(messages)
52
+ print('Critic backup Response:',response.content)
53
+ state.critic_response.append(response.content)
54
+ return state
55
+
56
+ class FormatResponseNode:
57
+ def __init__(self):
58
+ self.response_list = []
59
+
60
+ def run(self, state:State):
61
+ messages = [SystemMessage(content='''Just extract all the 4 improved ideas and the faults of critic as it is from the critic's response'''),
62
+ HumanMessage(content=f'''The critic's response is: \n {state.critic_response[-1]}''')]
63
+ response = critic_llm.with_structured_output(CriticResponseFormatter).invoke(messages)
64
+ self.response_list.append(response.improved_idea1)
65
+ self.response_list.append(response.improved_idea2)
66
+ self.response_list.append(response.improved_idea3)
67
+ self.response_list.append(response.improved_idea4)
68
+ state.formatted_response.append(str(self.response_list))
69
+ state.ideator_fault.append(response.faults)
70
+ print('Formatted Response:', self.response_list)
71
+ return state
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
 
75
+ class Validators:
76
+ def __init__(self):
77
+ self.validator_llm1 = validator_llm
78
+ self.validator_llm2 = improver_llm
79
 
80
+ def get_response(self,state, validator_llm):
81
+ template = validator_prompt(state)
82
+ messages = [SystemMessage(content=template),
83
+ HumanMessage(content=f'''The business_details is:\n{state.business_details[-1]}''')]
 
 
 
 
 
 
 
 
 
84
 
85
+ response = validator_llm.with_structured_output(ValidationFormatter).invoke(messages)
86
+ return response
 
 
 
 
 
 
 
 
 
 
87
 
 
 
 
 
 
 
 
88
 
89
+ def run_validator1(self, state:State):
90
+ response = self.get_response(state,self.validator_llm1)
91
+ state.validator1_response.append(response.result)
92
+ if 'not validated' in response.result: state.disagreement_reason.append(response.reason)
93
+ return state
94
+
95
+ def run_validator2(self, state:State):
96
+ response = self.get_response(state,self.validator_llm2)
97
+ state.validator2_response.append(response.result)
98
+ if 'not validated' in response.result: state.disagreement_reason.append(response.reason)
99
  return state
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
 
102
+ class RoutingsAfterValidation:
103
+ def __init__(self):
104
+ pass
 
 
 
 
 
 
 
 
105
 
106
+ def route1(self, state:State):
107
+ return 'not validated' not in state.validator1_response[-1]
 
 
108
 
109
+ def route2(self, state:State):
110
+ return 'not validated' not in state.validator2_response[-1]
111
 
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
 
 
 
 
 
src/genai/ideation_agent/utils/tools.py CHANGED
@@ -10,84 +10,87 @@ from src.genai.utils.models_loader import embedding_model
10
  from src.genai.utils.load_embeddings import caption_index , caption_df, ideas_index , ideas_df
11
  from src.genai.utils.utils import clean_text
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  @tool("influencers_data_retrieval_tool", args_schema=QueryFormatter, return_direct=False,description="Retrieve influencer-related data for a given query.")
14
- def retrieve_tool_old(business_details):
15
  '''
16
  Always invoke this tool.
17
  Retrieve influencer's data by semantic search of **business details**.
18
  '''
19
- query_embedding = np.array(embedding_model.embed_query(str(business_details))).reshape(1, -1).astype('float32')
20
- faiss.normalize_L2(query_embedding)
21
-
22
- top_k = len(caption_df)
23
- distances, indices = caption_index.search(query_embedding, top_k)
24
-
25
- similarity_threshold = 0.35
26
- selected = [(idx, sim) for idx, sim in zip(indices[0], distances[0]) if sim >= similarity_threshold]
27
-
28
- if not selected:
29
- return "No influencers found."
30
-
31
- # === Format results ===
32
- outer_list = []
33
- for rank, (idx, sim) in enumerate(selected, 1):
34
- row = caption_df.iloc[idx]
35
- res = {
36
- 'rank': rank,
37
- 'username': row['username'],
38
- 'visible_text_or_brandings': row['visible_texts_or_brandings'],
39
- 'likesCount': row['likesCount'],
40
- 'commentCount': row['commentCount'],
41
- 'product_or_service_details': row['product_or_service_details'],
42
- }
43
-
44
- inner_list = [
45
- f"[{res['rank']}]. The influencer name is: **{res['username']}** — Likes: **{res['likesCount']}**, Comments: **{res['commentCount']}**",
46
- f"The branding or promotion done is:\n{res['visible_text_or_brandings']}",
47
- f"The details of product or service is:\n{res['product_or_service_details']}"
48
- ]
49
- outer_list.append(inner_list)
50
-
51
- cleaned_response = clean_text(str(outer_list))
52
- encoding = tiktoken.encoding_for_model('gpt-4o-mini')
53
- tokens = encoding.encode(cleaned_response)
54
- trimmed_response = tokens[:1000]
55
- return encoding.decode(trimmed_response)
56
-
57
-
58
- # @tool("imdb_movies_ideas_retrieval_tool", args_schema=QueryFormatter, return_direct=False,description="Retrieve imdb movies-related idea for a given query.")
59
- def retrieve_tool(business_details):
60
  '''
61
  Always invoke this tool.
62
  Retrieve the ideas of imdb_movies by semantic search of **business details**.
63
  '''
64
- query_embedding = np.array(embedding_model.embed_query(str(business_details))).reshape(1, -1).astype('float32')
65
- faiss.normalize_L2(query_embedding)
66
-
67
- top_k = 10
68
- distances, indices = ideas_index.search(query_embedding, top_k)
69
-
70
- outer_list = []
71
- for rank, (idx, sim) in enumerate(zip(indices[0], distances[0]), 1):
72
- row = ideas_df.iloc[idx]
73
- res = {
74
- 'rank': rank,
75
- 'idea': row['idea'],
76
- }
77
-
78
- inner_list = [
79
- f"Idea [{res['rank']}]: **{res['idea']}\n**",
80
- ]
81
- outer_list.append(inner_list)
82
-
83
- cleaned_response = clean_text(str(outer_list))
84
- return str(cleaned_response)
85
-
86
- # business_details= {
87
- # "business_type": "restaurant",
88
- # "platform": "instagram",
89
- # "target_audience": "youths",
90
- # "business_goals": "to increase sales",
91
- # "offerings": "nepali local foods",
92
- # "Challenges_faced": "competition with other restaurants"
93
- # },
 
10
  from src.genai.utils.load_embeddings import caption_index , caption_df, ideas_index , ideas_df
11
  from src.genai.utils.utils import clean_text
12
 
13
+
14
+ class Retrieval:
15
+ def __init__(self, business_details):
16
+ self.business_details = business_details
17
+ self.query_embedding = np.array(embedding_model.embed_query(str(business_details))).reshape(1, -1).astype('float32')
18
+ faiss.normalize_L2(self.query_embedding)
19
+
20
+ def influencers_data(self):
21
+ top_k = len(caption_df)
22
+ distances, indices = caption_index.search(self.query_embedding, top_k)
23
+
24
+ similarity_threshold = 0.35
25
+ selected = [(idx, sim) for idx, sim in zip(indices[0], distances[0]) if sim >= similarity_threshold]
26
+
27
+ if not selected:
28
+ return "No influencers found."
29
+
30
+ # === Format results ===
31
+ outer_list = []
32
+ for rank, (idx, sim) in enumerate(selected, 1):
33
+ row = caption_df.iloc[idx]
34
+ res = {
35
+ 'rank': rank,
36
+ 'username': row['username'],
37
+ 'visible_text_or_brandings': row['visible_texts_or_brandings'],
38
+ 'likesCount': row['likesCount'],
39
+ 'commentCount': row['commentCount'],
40
+ 'product_or_service_details': row['product_or_service_details'],
41
+ }
42
+
43
+ inner_list = [
44
+ f"[{res['rank']}]. The influencer name is: **{res['username']}** — Likes: **{res['likesCount']}**, Comments: **{res['commentCount']}**",
45
+ f"The branding or promotion done is:\n{res['visible_text_or_brandings']}",
46
+ f"The details of product or service is:\n{res['product_or_service_details']}"
47
+ ]
48
+ outer_list.append(inner_list)
49
+
50
+ cleaned_response = clean_text(str(outer_list))
51
+ encoding = tiktoken.encoding_for_model('gpt-4o-mini')
52
+ tokens = encoding.encode(cleaned_response)
53
+ trimmed_response = tokens[:1000]
54
+ return encoding.decode(trimmed_response)
55
+
56
+ def imdb_ideas(self):
57
+ top_k = 10
58
+ distances, indices = ideas_index.search(self.query_embedding, top_k)
59
+
60
+ outer_list = []
61
+ for rank, (idx, sim) in enumerate(zip(indices[0], distances[0]), 1):
62
+ row = ideas_df.iloc[idx]
63
+ res = {
64
+ 'rank': rank,
65
+ 'idea': row['idea'],
66
+ }
67
+
68
+ inner_list = [
69
+ f"Idea [{res['rank']}]: **{res['idea']}\n**",
70
+ ]
71
+ outer_list.append(inner_list)
72
+
73
+ cleaned_response = clean_text(str(outer_list))
74
+ return str(cleaned_response)
75
+
76
+
77
+
78
+
79
  @tool("influencers_data_retrieval_tool", args_schema=QueryFormatter, return_direct=False,description="Retrieve influencer-related data for a given query.")
80
+ def retrieve_influencers_data_tool(business_details):
81
  '''
82
  Always invoke this tool.
83
  Retrieve influencer's data by semantic search of **business details**.
84
  '''
85
+ return Retrieval(business_details).influencers_data()
86
+
87
+
88
+ @tool("imdb_movies_ideas_retrieval_tool", args_schema=QueryFormatter, return_direct=False,description="Retrieve imdb movies-related idea for a given query.")
89
+ def retrieve_imdb_ideas_tool(business_details):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  '''
91
  Always invoke this tool.
92
  Retrieve the ideas of imdb_movies by semantic search of **business details**.
93
  '''
94
+ return Retrieval(business_details).imdb_ideas()
95
+
96
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/genai/orchestration_agent/__pycache__/agent.cpython-312.pyc CHANGED
Binary files a/src/genai/orchestration_agent/__pycache__/agent.cpython-312.pyc and b/src/genai/orchestration_agent/__pycache__/agent.cpython-312.pyc differ
 
src/genai/orchestration_agent/agent.py CHANGED
@@ -1,56 +1,64 @@
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 src.genai.utils.models_loader import llm_gpt
5
  from .utils.state import ValidationFormatter
6
- from .utils.utils import caption_image , extract_latest_response_block
7
- from .utils.tools import retrieve_data_for_orchestration
8
 
9
  import re
10
  from langchain_core.messages import SystemMessage
11
- memory = MemorySaver()
12
-
13
-
14
- def orchestration_graph():
15
- workflow = StateGraph(MessagesState)
16
- workflow.add_node("chatbot1", tool_return_node)
17
- workflow.add_node("chatbot2", extract_user_reference_node)
18
-
19
- workflow.add_edge(START, "chatbot1")
20
- workflow.add_edge('chatbot1', "chatbot2")
21
- workflow.add_edge('chatbot2', END)
22
- return workflow.compile(checkpointer=memory)
23
-
24
- user_input_history = []
25
- def orchestration_chat(user_input: str, image_base64=[]):
26
- print('Message Chunk:')
27
- global user_input_history
28
- user_input_history.append({'role': 'human', 'content': user_input})
29
-
30
- if len(image_base64)>0:
31
- caption_response = caption_image(image_base64, user_input)
32
- user_input_history.append({'role': 'image_caption', 'content': caption_response})
33
-
34
- print('Caption Response:', caption_response)
35
- else:
36
- caption_response =''
37
- if len(user_input_history)>4:
38
- user_input_history=user_input_history[-2:]
39
- print('Length of history', len(user_input_history))
40
- query_for_retrieval = ' '.join(
41
- [msg['content'] for msg in user_input_history if msg['role'] in ('human', 'image_caption')]
42
- )
43
-
44
- influencers_data = retrieve_data_for_orchestration(query_for_retrieval)
45
-
46
- agent = orchestration_graph()
47
- config = {"configurable": {"thread_id": "orchestration-thread"}}
48
- response = agent.invoke({"messages": [{'role':'human','content':user_input},
49
- {'role': 'function', 'name': 'data_of_influencers', 'content': influencers_data},
50
- {'role':'function','name':'information_of_image','content':caption_response}]}, config)['messages']
51
- print('Orchestrator Response', response)
52
- response=llm_gpt.with_structured_output(ValidationFormatter).invoke(extract_latest_response_block(response))
53
- return response
 
 
 
 
 
 
 
 
54
 
55
 
56
 
 
1
  from langgraph.graph import StateGraph, MessagesState, START, END
2
  from langgraph.checkpoint.memory import MemorySaver
3
+ from .utils.nodes import ToolReturnNode, ExtractUserReferenceNode
4
  from src.genai.utils.models_loader import llm_gpt
5
  from .utils.state import ValidationFormatter
6
+ from .utils.utils import ImageCaptioner, ResponseBlockExtractor
7
+ from .utils.tools import InfluencerRetrievalTool
8
 
9
  import re
10
  from langchain_core.messages import SystemMessage
11
+
12
+ class OrchestrationAgent:
13
+ def __init__(self):
14
+ self.memory = MemorySaver()
15
+ self.agent = self.orchestration_graph()
16
+ self.user_input_history=[]
17
+
18
+ def orchestration_graph(self):
19
+ workflow = StateGraph(MessagesState)
20
+ workflow.add_node("chatbot1", ToolReturnNode().run)
21
+ workflow.add_node("chatbot2", ExtractUserReferenceNode().run)
22
+
23
+ workflow.add_edge(START, "chatbot1")
24
+ workflow.add_edge('chatbot1', "chatbot2")
25
+ workflow.add_edge('chatbot2', END)
26
+ return workflow.compile(checkpointer=self.memory)
27
+
28
+ def trim_history(self):
29
+ if len(self.user_input_history)>4:
30
+ self.user_input_history=self.user_input_history[-2:]
31
+ print('Length of history', len(self.user_input_history))
32
+ query_for_retrieval = ' '.join(
33
+ [msg['content'] for msg in self.user_input_history if msg['role'] in ('human', 'image_caption')])
34
+ return query_for_retrieval
35
+
36
+ def caption_image(self,image_base64,user_input):
37
+ if len(image_base64)>0:
38
+ caption_response = ImageCaptioner().caption_image(image_base64,user_input)
39
+ self.user_input_history.append({'role': 'image_caption', 'content': caption_response})
40
+
41
+ print('Caption Response:', caption_response)
42
+ else:
43
+ caption_response =''
44
+ return caption_response
45
+
46
+
47
+ def chat(self,user_input: str, image_base64=[]):
48
+ print('Message Chunk:')
49
+ self.user_input_history.append({'role': 'human', 'content': user_input})
50
+ caption_response = self.caption_image(image_base64,user_input)
51
+ query_for_retrieval= self.trim_history()
52
+
53
+ influencers_data = InfluencerRetrievalTool().retrieve_for_orchestration(query_for_retrieval)
54
+
55
+ config = {"configurable": {"thread_id": "orchestration-thread"}}
56
+ response = self.agent.invoke({"messages": [{'role':'human','content':user_input},
57
+ {'role': 'function', 'name': 'data_of_influencers', 'content': influencers_data},
58
+ {'role':'function','name':'information_of_image','content':caption_response}]}, config)['messages']
59
+ print('Orchestrator Response', response)
60
+ response=llm_gpt.with_structured_output(ValidationFormatter).invoke(ResponseBlockExtractor(response).extract_latest())
61
+ return response
62
 
63
 
64
 
src/genai/orchestration_agent/utils/__pycache__/nodes.cpython-312.pyc CHANGED
Binary files a/src/genai/orchestration_agent/utils/__pycache__/nodes.cpython-312.pyc and b/src/genai/orchestration_agent/utils/__pycache__/nodes.cpython-312.pyc differ
 
src/genai/orchestration_agent/utils/__pycache__/tools.cpython-312.pyc CHANGED
Binary files a/src/genai/orchestration_agent/utils/__pycache__/tools.cpython-312.pyc and b/src/genai/orchestration_agent/utils/__pycache__/tools.cpython-312.pyc differ
 
src/genai/orchestration_agent/utils/__pycache__/utils.cpython-312.pyc CHANGED
Binary files a/src/genai/orchestration_agent/utils/__pycache__/utils.cpython-312.pyc and b/src/genai/orchestration_agent/utils/__pycache__/utils.cpython-312.pyc differ
 
src/genai/orchestration_agent/utils/nodes.py CHANGED
@@ -3,24 +3,38 @@ from langchain_core.messages import SystemMessage, HumanMessage
3
  from src.genai.utils.models_loader import llm_gpt
4
  from .state import ToolResponseFormatter, UserReferenceResponseFormatter
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
 
8
- def tool_return_node(state):
9
- if len(state["messages"]) > 23:
10
- state["messages"] = state["messages"][-18:]
11
- history = state["messages"]
12
- template = [SystemMessage(content=tool_return_prompt)] + history
13
- # print(template)
14
- response = llm_gpt.with_structured_output(ToolResponseFormatter).invoke(template)
15
- print(response)
16
- return {"messages": [{'role':'assistant','content':f'''The exact name of the tool is: {response}'''}]}
17
-
18
- def extract_user_reference_node(state):
19
- history = state['messages']
20
- latest_human_message = next(
21
- (msg for msg in reversed(history) if isinstance(msg, HumanMessage)),
22
- None
23
- )
24
- template = [SystemMessage(content=extract_user_reference_prompt), HumanMessage(content=latest_human_message.content)]
25
- response = llm_gpt.with_structured_output(UserReferenceResponseFormatter).invoke(template)
26
- return {'messages': [{'role':'assistant','content':f'''The video idea is: {response.video_idea} and the video story is: {response.video_story}'''}]}
 
3
  from src.genai.utils.models_loader import llm_gpt
4
  from .state import ToolResponseFormatter, UserReferenceResponseFormatter
5
 
6
+ class ToolReturnNode:
7
+ """Node for determining which tools to use based on user messages."""
8
+
9
+ def __init__(self, llm=llm_gpt):
10
+ self.llm = llm
11
+
12
+ def run(self, state):
13
+ if len(state["messages"]) > 23:
14
+ state["messages"] = state["messages"][-18:]
15
+ template = [SystemMessage(content=tool_return_prompt)] + state["messages"]
16
+ response = self.llm.with_structured_output(ToolResponseFormatter).invoke(template)
17
+ return {"messages": [{'role': 'assistant', 'content': f"The exact name of the tool is: {response}"}]}
18
+
19
+
20
+ class ExtractUserReferenceNode:
21
+ """Node for extracting video idea and story from user's messages."""
22
+
23
+ def __init__(self, llm=llm_gpt):
24
+ self.llm = llm
25
+
26
+ def run(self, state):
27
+ latest_human_message = next(
28
+ (msg for msg in reversed(state['messages']) if isinstance(msg, HumanMessage)),
29
+ None
30
+ )
31
+ template = [SystemMessage(content=extract_user_reference_prompt),
32
+ HumanMessage(content=latest_human_message.content)]
33
+ response = self.llm.with_structured_output(UserReferenceResponseFormatter).invoke(template)
34
+ return {'messages': [{
35
+ 'role': 'assistant',
36
+ 'content': f"The video idea is: {response.video_idea} and the video story is: {response.video_story}"
37
+ }]}
38
+
39
 
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/genai/orchestration_agent/utils/tools.py CHANGED
@@ -7,71 +7,54 @@ from src.genai.utils.models_loader import embedding_model
7
  from src.genai.utils.utils import clean_text
8
  import tiktoken
9
 
10
- def retrieve_data_for_analytics(business_details):
11
- '''
12
- Always invoke this tool.
13
- Retrieve influencer's data by semantic search of **business details**.
14
- '''
15
- # df = pd.read_csv('extracted_data.csv')
16
 
17
- # === Encode the query and search ===
18
- query_embedding = np.array(embedding_model.embed_query(str(business_details))).reshape(1, -1).astype('float32')
19
- top_k = 10
20
- distances, indices = caption_index.search(query_embedding, top_k)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- # === Format results ===
23
- results = []
24
- for i, idx in enumerate(indices[0]):
25
- likes = caption_df.iloc[idx]['likesCount']
26
- comments = caption_df.iloc[idx]['commentCount']
27
- res = {
28
- 'url': caption_df.iloc[idx]['videoUrl'],
29
- 'username': caption_df.iloc[idx]['username'],
30
- 'likesCount': int(likes) if pd.notnull(likes) else None,
31
- 'commentCount': int(comments) if pd.notnull(comments) else None
32
- }
33
- results.append(res)
34
 
35
- return results
36
 
37
- def retrieve_data_for_orchestration(query):
38
- query_embedding = np.array(embedding_model.embed_query(str(query))).reshape(1, -1).astype('float32')
39
- faiss.normalize_L2(query_embedding)
40
-
41
- top_k = len(caption_df)
42
- distances, indices = caption_index.search(query_embedding, top_k)
43
-
44
- similarity_threshold = 0.35
45
- selected = [(idx, sim) for idx, sim in zip(indices[0], distances[0]) if sim >= similarity_threshold]
46
-
47
- if not selected:
48
- return "No influencers found."
49
-
50
- # === Format results ===
51
- outer_list = []
52
- for rank, (idx, sim) in enumerate(selected, 1):
53
- row = caption_df.iloc[idx]
54
- res = {
55
- 'rank': rank,
56
- 'username': row['username'],
57
- 'visible_text_or_brandings': row['visible_texts_or_brandings'],
58
- 'likesCount': row['likesCount'],
59
- 'commentCount': row['commentCount'],
60
- 'product_or_service_details': row['product_or_service_details'],
61
- }
62
-
63
- inner_list = [
64
- f"[{res['rank']}]. The influencer name is: **{res['username']}** — Likes: **{res['likesCount']}**, Comments: **{res['commentCount']}**",
65
- f"The branding or promotion done is:\n{res['visible_text_or_brandings']}",
66
- f"The details of product or service is:\n{res['product_or_service_details']}"
67
- ]
68
- outer_list.append(inner_list)
69
-
70
- cleaned_response = clean_text(str(outer_list))
71
- encoding = tiktoken.encoding_for_model('gpt-4o-mini')
72
- tokens = encoding.encode(cleaned_response)
73
- trimmed_response = tokens[:1000]
74
- return encoding.decode(trimmed_response)
75
 
76
 
77
 
 
7
  from src.genai.utils.utils import clean_text
8
  import tiktoken
9
 
 
 
 
 
 
 
10
 
11
+ class InfluencerRetrievalTool:
12
+ """Tool for retrieving influencer data based on semantic search."""
13
+
14
+ def __init__(self):
15
+ self.df = caption_df
16
+ self.index = caption_index
17
+
18
+ def retrieve_for_analytics(self, business_details):
19
+ query_embedding = np.array(embedding_model.embed_query(str(business_details))).reshape(1, -1).astype('float32')
20
+ distances, indices = self.index.search(query_embedding, 10)
21
+ results = []
22
+ for idx in indices[0]:
23
+ row = self.df.iloc[idx]
24
+ results.append({
25
+ 'url': row['videoUrl'],
26
+ 'username': row['username'],
27
+ 'likesCount': int(row['likesCount']) if pd.notnull(row['likesCount']) else None,
28
+ 'commentCount': int(row['commentCount']) if pd.notnull(row['commentCount']) else None
29
+ })
30
+ return results
31
+
32
+ def retrieve_for_orchestration(self, query):
33
+ query_embedding = np.array(embedding_model.embed_query(str(query))).reshape(1, -1).astype('float32')
34
+ faiss.normalize_L2(query_embedding)
35
+ distances, indices = self.index.search(query_embedding, len(self.df))
36
+ similarity_threshold = 0.35
37
+ selected = [(idx, sim) for idx, sim in zip(indices[0], distances[0]) if sim >= similarity_threshold]
38
+ if not selected:
39
+ return "No influencers found."
40
+
41
+ outer_list = []
42
+ for rank, (idx, sim) in enumerate(selected, 1):
43
+ row = self.df.iloc[idx]
44
+ inner_list = [
45
+ f"[{rank}]. The influencer name is: **{row['username']}** — Likes: **{row['likesCount']}**, Comments: **{row['commentCount']}**",
46
+ f"The branding or promotion done is:\n{row['visible_texts_or_brandings']}",
47
+ f"The details of product or service is:\n{row['product_or_service_details']}"
48
+ ]
49
+ outer_list.append(inner_list)
50
+
51
+ cleaned_response = clean_text(str(outer_list))
52
+ encoding = tiktoken.encoding_for_model('gpt-4o-mini')
53
+ tokens = encoding.encode(cleaned_response)[:1000]
54
+ return encoding.decode(tokens)
55
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
 
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
 
60
 
src/genai/orchestration_agent/utils/utils.py CHANGED
@@ -6,63 +6,77 @@ import os
6
  from .prompts import captioning_prompt
7
  from src.genai.utils.models_loader import llm
8
  from langchain_core.messages import FunctionMessage , AIMessage
9
- from .tools import retrieve_data_for_analytics
10
  import re
11
  import logging
12
  app_logger = logging.getLogger("app_logger")
 
13
 
14
- def caption_image(image_base64,user_input):
15
- if len(image_base64)>0:
16
- print('Captioning image')
17
- client = Groq(api_key=os.environ.get('GROQ_API_KEY'))
18
 
19
- chat_completion = client.chat.completions.create(
20
- messages=[
21
- {
22
- "role": "user",
23
- "content": [
24
- {"type": "text", "text": captioning_prompt(user_input)},
25
- {
26
- "type": "image_url",
27
- "image_url": {
28
- "url": f"data:image/jpg;base64,{image_base64[-1]}",
 
 
 
 
29
  },
30
- },
31
- ],
32
- }
33
- ],
34
- model="meta-llama/llama-4-scout-17b-16e-instruct",
35
- max_completion_tokens=50,
36
- temperature = 1
37
- )
38
- response=chat_completion.choices[0].message.content
39
- return response
40
- else:
41
- return ''
42
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- def show_analytics(business_details):
45
- tool_response = retrieve_data_for_analytics(str(business_details))
46
- app_logger.info('Showing Analytics of the influencers after context analysis.')
47
- return tool_response
48
 
49
- def extract_latest_response_block(response):
50
- latest_block = []
51
- temp_block = []
52
 
53
- # Reverse iterate through the messages
54
- for message in reversed(response):
55
- if isinstance(message, (FunctionMessage, AIMessage)):
56
- temp_block.insert(0, message.content)
57
 
58
- # Once we collect 3 items in correct structure, stop
59
- if len(temp_block) == 3:
60
- if "tool=" in temp_block[1] and "query_response" in temp_block[1]:
61
- latest_block = temp_block
62
- break
63
- else:
64
- temp_block = []
65
- print('The latest block', latest_block)
66
- return latest_block
67
 
68
 
 
6
  from .prompts import captioning_prompt
7
  from src.genai.utils.models_loader import llm
8
  from langchain_core.messages import FunctionMessage , AIMessage
9
+ from .tools import InfluencerRetrievalTool
10
  import re
11
  import logging
12
  app_logger = logging.getLogger("app_logger")
13
+ error_logger = logging.getLogger("error_logger")
14
 
15
+ class ImageCaptioner:
16
+ def __init__(self, api_key=os.environ.get('GROQ_API_KEY')):
17
+ self.client = Groq(api_key=api_key)
 
18
 
19
+ def caption_image(self,image_base64,user_input):
20
+ if len(image_base64)>0:
21
+ print('Captioning image')
22
+ chat_completion = self.client.chat.completions.create(
23
+ messages=[
24
+ {
25
+ "role": "user",
26
+ "content": [
27
+ {"type": "text", "text": captioning_prompt(user_input)},
28
+ {
29
+ "type": "image_url",
30
+ "image_url": {
31
+ "url": f"data:image/jpg;base64,{image_base64[-1]}",
32
+ },
33
  },
34
+ ],
35
+ }
36
+ ],
37
+ model="meta-llama/llama-4-scout-17b-16e-instruct",
38
+ max_completion_tokens=50,
39
+ temperature = 1
40
+ )
41
+ response=chat_completion.choices[0].message.content
42
+ return response
43
+ else:
44
+ return ''
 
45
 
46
+ class AnalyticsViewer:
47
+ def __init__(self, business_details):
48
+ self.business_details = business_details
49
+
50
+ def show_analytics(self):
51
+ try:
52
+ tool_response = InfluencerRetrievalTool().retrieve_for_analytics(str(self.business_details))
53
+ app_logger.info('Showing Analytics of the influencers after context analysis.')
54
+ return tool_response
55
+ except Exception as e:
56
+ error_logger.error(f'Error while showing analytics: {e}')
57
+ return e
58
 
59
+ class ResponseBlockExtractor:
60
+ def __init__(self, response):
61
+ self.response = response
 
62
 
63
+ def extract_latest(self):
64
+ latest_block = []
65
+ temp_block = []
66
 
67
+ # Reverse iterate through the messages
68
+ for message in reversed(self.response):
69
+ if isinstance(message, (FunctionMessage, AIMessage)):
70
+ temp_block.insert(0, message.content)
71
 
72
+ # Once we collect 3 items in correct structure, stop
73
+ if len(temp_block) == 3:
74
+ if "tool=" in temp_block[1] and "query_response" in temp_block[1]:
75
+ latest_block = temp_block
76
+ break
77
+ else:
78
+ temp_block = []
79
+ print('The latest block', latest_block)
80
+ return latest_block
81
 
82