Spaces:
Sleeping
Sleeping
Full research (Tavily+RAG) works
Browse files
notebooks/transcript_agents.ipynb
CHANGED
|
@@ -1,8 +1,15 @@
|
|
| 1 |
{
|
| 2 |
"cells": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
{
|
| 4 |
"cell_type": "code",
|
| 5 |
-
"execution_count":
|
| 6 |
"metadata": {},
|
| 7 |
"outputs": [],
|
| 8 |
"source": [
|
|
@@ -15,7 +22,7 @@
|
|
| 15 |
},
|
| 16 |
{
|
| 17 |
"cell_type": "code",
|
| 18 |
-
"execution_count":
|
| 19 |
"metadata": {},
|
| 20 |
"outputs": [],
|
| 21 |
"source": [
|
|
@@ -24,9 +31,18 @@
|
|
| 24 |
},
|
| 25 |
{
|
| 26 |
"cell_type": "code",
|
| 27 |
-
"execution_count":
|
| 28 |
"metadata": {},
|
| 29 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
"source": [
|
| 31 |
"%load_ext autoreload\n",
|
| 32 |
"%autoreload 2\n"
|
|
@@ -34,10 +50,13 @@
|
|
| 34 |
},
|
| 35 |
{
|
| 36 |
"cell_type": "code",
|
| 37 |
-
"execution_count":
|
| 38 |
"metadata": {},
|
| 39 |
"outputs": [],
|
| 40 |
"source": [
|
|
|
|
|
|
|
|
|
|
| 41 |
"\n",
|
| 42 |
"load_dotenv()\n",
|
| 43 |
"\n",
|
|
@@ -48,12 +67,15 @@
|
|
| 48 |
" os.environ[key_name] = getpass.getpass(prompt_message)\n",
|
| 49 |
"\n",
|
| 50 |
"set_api_key_if_not_present(\"OPENAI_API_KEY\")\n",
|
| 51 |
-
"set_api_key_if_not_present(\"TAVILY_API_KEY\")"
|
|
|
|
|
|
|
|
|
|
| 52 |
]
|
| 53 |
},
|
| 54 |
{
|
| 55 |
"cell_type": "code",
|
| 56 |
-
"execution_count":
|
| 57 |
"metadata": {},
|
| 58 |
"outputs": [],
|
| 59 |
"source": [
|
|
@@ -70,100 +92,189 @@
|
|
| 70 |
},
|
| 71 |
{
|
| 72 |
"cell_type": "code",
|
| 73 |
-
"execution_count":
|
| 74 |
"metadata": {},
|
| 75 |
"outputs": [],
|
| 76 |
"source": [
|
| 77 |
-
"import functools\n",
|
| 78 |
-
"import operator\n",
|
| 79 |
-
"from typing import Annotated, List, TypedDict\n",
|
| 80 |
"\n",
|
| 81 |
-
"from langchain_core.messages import
|
| 82 |
"from langchain_openai.chat_models import ChatOpenAI\n",
|
| 83 |
"\n",
|
| 84 |
-
"
|
| 85 |
-
" messages: Annotated[List[BaseMessage], operator.add]\n",
|
| 86 |
-
" team_members: List[str]\n",
|
| 87 |
-
" next: str"
|
| 88 |
]
|
| 89 |
},
|
| 90 |
{
|
| 91 |
"cell_type": "code",
|
| 92 |
-
"execution_count":
|
| 93 |
"metadata": {},
|
| 94 |
"outputs": [],
|
| 95 |
"source": [
|
| 96 |
-
"
|
|
|
|
| 97 |
]
|
| 98 |
},
|
| 99 |
{
|
| 100 |
"cell_type": "code",
|
| 101 |
-
"execution_count":
|
| 102 |
"metadata": {},
|
| 103 |
"outputs": [],
|
| 104 |
"source": [
|
| 105 |
-
"
|
| 106 |
-
"\n",
|
| 107 |
-
"adobe_help_search = TavilySearchResults(max_results=5,include_domains=[\"helpx.adobe.com\"])"
|
| 108 |
]
|
| 109 |
},
|
| 110 |
{
|
| 111 |
-
"cell_type": "
|
| 112 |
-
"execution_count": 9,
|
| 113 |
"metadata": {},
|
| 114 |
-
"outputs": [],
|
| 115 |
"source": [
|
| 116 |
-
"
|
| 117 |
-
"\n",
|
| 118 |
-
"adobe_help_agent = create_agent(\n",
|
| 119 |
-
" llm_tool_calling,\n",
|
| 120 |
-
" [adobe_help_search],\n",
|
| 121 |
-
" \"You are a research assistant who can search\"\n",
|
| 122 |
-
" \"for Adobe Photoshop help topics using the tavily search engine.\"\n",
|
| 123 |
-
" \"Users may provide you with partial questions - try your best to determine their intent.\"\n",
|
| 124 |
-
" \"If sending a request to search, craft your query so that it enhances user's ability\"\n",
|
| 125 |
-
" \"to receive a helpful answer.\",\n",
|
| 126 |
-
")\n",
|
| 127 |
-
"adobe_help_node = functools.partial(agent_node, agent=adobe_help_agent, name=\"AdobeHelp\")"
|
| 128 |
]
|
| 129 |
},
|
| 130 |
{
|
| 131 |
"cell_type": "code",
|
| 132 |
-
"execution_count":
|
| 133 |
"metadata": {},
|
| 134 |
"outputs": [],
|
| 135 |
"source": [
|
| 136 |
-
"
|
|
|
|
|
|
|
|
|
|
| 137 |
]
|
| 138 |
},
|
| 139 |
{
|
| 140 |
"cell_type": "code",
|
| 141 |
-
"execution_count":
|
| 142 |
"metadata": {},
|
| 143 |
"outputs": [
|
| 144 |
{
|
| 145 |
"data": {
|
| 146 |
"text/plain": [
|
| 147 |
-
"{'
|
| 148 |
-
"
|
| 149 |
-
"
|
| 150 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
]
|
| 152 |
},
|
| 153 |
-
"execution_count":
|
| 154 |
"metadata": {},
|
| 155 |
"output_type": "execute_result"
|
| 156 |
}
|
| 157 |
],
|
| 158 |
"source": [
|
| 159 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
]
|
| 161 |
},
|
| 162 |
{
|
| 163 |
"cell_type": "markdown",
|
| 164 |
"metadata": {},
|
| 165 |
"source": [
|
| 166 |
-
"# Data Preparation\n",
|
| 167 |
"\n",
|
| 168 |
"First, we will read in the transcripts of the videos and convert them to Documents\n",
|
| 169 |
"with appropriate metadata."
|
|
@@ -171,7 +282,7 @@
|
|
| 171 |
},
|
| 172 |
{
|
| 173 |
"cell_type": "code",
|
| 174 |
-
"execution_count":
|
| 175 |
"metadata": {},
|
| 176 |
"outputs": [],
|
| 177 |
"source": [
|
|
@@ -184,13 +295,6 @@
|
|
| 184 |
"data:List[Dict[str,Any]] = await load_json_files(filename)\n"
|
| 185 |
]
|
| 186 |
},
|
| 187 |
-
{
|
| 188 |
-
"cell_type": "markdown",
|
| 189 |
-
"metadata": {},
|
| 190 |
-
"source": [
|
| 191 |
-
"## R - retrieval"
|
| 192 |
-
]
|
| 193 |
-
},
|
| 194 |
{
|
| 195 |
"cell_type": "markdown",
|
| 196 |
"metadata": {},
|
|
@@ -200,7 +304,7 @@
|
|
| 200 |
},
|
| 201 |
{
|
| 202 |
"cell_type": "code",
|
| 203 |
-
"execution_count":
|
| 204 |
"metadata": {},
|
| 205 |
"outputs": [],
|
| 206 |
"source": [
|
|
@@ -209,151 +313,150 @@
|
|
| 209 |
"\n",
|
| 210 |
"client = QdrantClient(path=\":memory:\")\n",
|
| 211 |
"\n",
|
| 212 |
-
"
|
| 213 |
-
"if
|
| 214 |
-
" await
|
| 215 |
]
|
| 216 |
},
|
| 217 |
{
|
| 218 |
"cell_type": "markdown",
|
| 219 |
"metadata": {},
|
| 220 |
"source": [
|
| 221 |
-
"##
|
| 222 |
-
"\n",
|
| 223 |
-
"We will use a 4.1-nano to generate answers."
|
| 224 |
]
|
| 225 |
},
|
| 226 |
{
|
| 227 |
"cell_type": "code",
|
| 228 |
-
"execution_count":
|
| 229 |
"metadata": {},
|
| 230 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
"source": [
|
| 232 |
-
"from
|
| 233 |
-
"from pstuts_rag.rag import RAGChainFactory\n",
|
| 234 |
"from langchain_openai import ChatOpenAI\n",
|
| 235 |
"from langchain_core.tools import tool\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
"\n",
|
| 237 |
-
"
|
| 238 |
-
"get_videos = rag_factory.get_rag_chain(llm=ChatOpenAI(model=params.tool_calling_model))\n",
|
| 239 |
-
"\n",
|
| 240 |
-
"@tool\n",
|
| 241 |
-
"def get_videos_call(\n",
|
| 242 |
-
" query: Annotated[str, \"Query to pose to Photoshop training video transcript archive\"]\n",
|
| 243 |
-
" ):\n",
|
| 244 |
-
" \"\"\"Extract information from Photoshop training video archive.\"\"\"\n",
|
| 245 |
-
" return get_videos.invoke({\"question\" : query})\n",
|
| 246 |
-
"\n",
|
| 247 |
-
"get_videos_agent = create_agent(\n",
|
| 248 |
-
" llm_tool_calling,\n",
|
| 249 |
-
" [get_videos_call],\n",
|
| 250 |
-
" \"\"\"You are an expert trainer in Adobe Photoshop who\n",
|
| 251 |
-
" has an archive of training videos at her disposal.\n",
|
| 252 |
-
" You can request transcripts of those videos and then summarize and shape \n",
|
| 253 |
-
" them to provide helpful answers.\"\"\"\n",
|
| 254 |
-
")\n",
|
| 255 |
-
"\n",
|
| 256 |
-
"get_videos_node = functools.partial(agent_node, \n",
|
| 257 |
-
" agent=get_videos_agent,\n",
|
| 258 |
-
" name=\"VideoArchiveSearch\")\n"
|
| 259 |
]
|
| 260 |
},
|
| 261 |
{
|
| 262 |
"cell_type": "code",
|
| 263 |
-
"execution_count":
|
| 264 |
"metadata": {},
|
| 265 |
"outputs": [
|
| 266 |
{
|
| 267 |
-
"
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
"execution_count": 25,
|
| 273 |
-
"metadata": {},
|
| 274 |
-
"output_type": "execute_result"
|
| 275 |
}
|
| 276 |
],
|
| 277 |
"source": [
|
| 278 |
-
"
|
| 279 |
-
"retval"
|
| 280 |
]
|
| 281 |
},
|
| 282 |
{
|
| 283 |
"cell_type": "code",
|
| 284 |
-
"execution_count":
|
| 285 |
"metadata": {},
|
| 286 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
"source": [
|
| 288 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
]
|
| 290 |
},
|
| 291 |
{
|
| 292 |
"cell_type": "code",
|
| 293 |
-
"execution_count":
|
| 294 |
"metadata": {},
|
| 295 |
"outputs": [],
|
| 296 |
"source": [
|
| 297 |
"from pstuts_rag.agents import create_team_supervisor\n",
|
|
|
|
| 298 |
"supervisor_agent = create_team_supervisor(\n",
|
| 299 |
" llm_tool_calling,\n",
|
| 300 |
-
"
|
| 301 |
-
"\n",
|
| 302 |
-
"Workers\n",
|
| 303 |
-
"• VideoArchiveSearch – retrieves videos related to the query \n",
|
| 304 |
-
"• AdobeHelp – searches Adobe’s documentation and training resources \n",
|
| 305 |
-
"\n",
|
| 306 |
-
"Routing Rules\n",
|
| 307 |
-
"1. Topic Extraction \n",
|
| 308 |
-
" • Read the user’s request and identify a concise research topic (e.g. “Photoshop timeline keyframes”).\n",
|
| 309 |
-
"\n",
|
| 310 |
-
"2. Primary Preference \n",
|
| 311 |
-
" • First invoke VideoArchiveSearch with that topic. \n",
|
| 312 |
-
" • If VideoArchiveSearch returns “I don’t know” or “no results,” fall back to AdobeHelp.\n",
|
| 313 |
-
"\n",
|
| 314 |
-
"3. AdobeHelp Behavior \n",
|
| 315 |
-
" • When routing to AdobeHelp, always also check for related training videos in Adobe’s library.\n",
|
| 316 |
-
"\n",
|
| 317 |
-
"4. Research-Only \n",
|
| 318 |
-
" • Only invoke workers that perform research tasks.\n",
|
| 319 |
-
"\n",
|
| 320 |
-
"5. Completion \n",
|
| 321 |
-
" • When neither worked can provide value, go to FINISH. If AdobeHelp\n",
|
| 322 |
-
" expands the list of topics, make sure to attempt to search for them with the\n",
|
| 323 |
-
" VideoArchiveSearch.\n",
|
| 324 |
-
"\n",
|
| 325 |
-
"Response Format\n",
|
| 326 |
-
"<WorkerName>: <Research Topic>\n",
|
| 327 |
-
"\n",
|
| 328 |
-
"Example:\n",
|
| 329 |
-
"VideoArchiveSearch: exporting vector layers from After Effects\n",
|
| 330 |
-
"\n",
|
| 331 |
-
"And, once there’s no further research needed:\n",
|
| 332 |
-
"FINISH\n",
|
| 333 |
-
"\"\"\",\n",
|
| 334 |
" [\"VideoArchiveSearch\", \"AdobeHelp\"],\n",
|
| 335 |
")\n",
|
| 336 |
"\n"
|
| 337 |
]
|
| 338 |
},
|
| 339 |
-
{
|
| 340 |
-
"cell_type": "markdown",
|
| 341 |
-
"metadata": {},
|
| 342 |
-
"source": [
|
| 343 |
-
"## Graph Creation"
|
| 344 |
-
]
|
| 345 |
-
},
|
| 346 |
{
|
| 347 |
"cell_type": "code",
|
| 348 |
-
"execution_count":
|
| 349 |
"metadata": {},
|
| 350 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 351 |
"source": [
|
| 352 |
"from langgraph.graph import END, StateGraph\n",
|
| 353 |
"\n",
|
| 354 |
"adobe_help_graph = StateGraph(PsTutsTeamState)\n",
|
| 355 |
"\n",
|
| 356 |
-
"adobe_help_graph.add_node(\"VideoArchiveSearch\",
|
| 357 |
"adobe_help_graph.add_node(\"AdobeHelp\", adobe_help_node)\n",
|
| 358 |
"adobe_help_graph.add_node(\"supervisor\", supervisor_agent)\n",
|
| 359 |
"\n",
|
|
@@ -370,24 +473,14 @@
|
|
| 370 |
" {\"VideoArchiveSearch\":\"VideoArchiveSearch\",\n",
|
| 371 |
" \"AdobeHelp\":\"AdobeHelp\", \n",
|
| 372 |
" \"FINISH\": END},\n",
|
| 373 |
-
")\n"
|
| 374 |
-
"adobe_help_graph.set_entry_point(\"supervisor\")\n",
|
| 375 |
-
"adobe_help_compiled = adobe_help_graph.compile()"
|
| 376 |
]
|
| 377 |
},
|
| 378 |
{
|
| 379 |
"cell_type": "code",
|
| 380 |
-
"execution_count":
|
| 381 |
"metadata": {},
|
| 382 |
-
"outputs": [
|
| 383 |
-
{
|
| 384 |
-
"name": "stderr",
|
| 385 |
-
"output_type": "stream",
|
| 386 |
-
"text": [
|
| 387 |
-
"Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.\n"
|
| 388 |
-
]
|
| 389 |
-
}
|
| 390 |
-
],
|
| 391 |
"source": [
|
| 392 |
"adobe_help_graph.set_entry_point(\"supervisor\")\n",
|
| 393 |
"compiled_research_graph = adobe_help_graph.compile()"
|
|
@@ -395,7 +488,7 @@
|
|
| 395 |
},
|
| 396 |
{
|
| 397 |
"cell_type": "code",
|
| 398 |
-
"execution_count":
|
| 399 |
"metadata": {},
|
| 400 |
"outputs": [],
|
| 401 |
"source": [
|
|
@@ -405,7 +498,7 @@
|
|
| 405 |
},
|
| 406 |
{
|
| 407 |
"cell_type": "code",
|
| 408 |
-
"execution_count":
|
| 409 |
"metadata": {},
|
| 410 |
"outputs": [
|
| 411 |
{
|
|
@@ -420,10 +513,10 @@
|
|
| 420 |
" * \n",
|
| 421 |
" +------------+ \n",
|
| 422 |
" | supervisor | \n",
|
| 423 |
-
"
|
| 424 |
-
"
|
| 425 |
-
"
|
| 426 |
-
"
|
| 427 |
"+-----------+ +--------------------+ +---------+ \n",
|
| 428 |
"| AdobeHelp | | VideoArchiveSearch | | __end__ | \n",
|
| 429 |
"+-----------+ +--------------------+ +---------+ \n"
|
|
@@ -439,7 +532,7 @@
|
|
| 439 |
},
|
| 440 |
{
|
| 441 |
"cell_type": "code",
|
| 442 |
-
"execution_count":
|
| 443 |
"metadata": {},
|
| 444 |
"outputs": [],
|
| 445 |
"source": [
|
|
@@ -471,7 +564,7 @@
|
|
| 471 |
},
|
| 472 |
{
|
| 473 |
"cell_type": "code",
|
| 474 |
-
"execution_count":
|
| 475 |
"metadata": {},
|
| 476 |
"outputs": [
|
| 477 |
{
|
|
@@ -483,11 +576,66 @@
|
|
| 483 |
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 484 |
"Name: VideoArchiveSearch\n",
|
| 485 |
"\n",
|
| 486 |
-
"Layers in Photoshop
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
"\n",
|
| 488 |
-
"
|
| 489 |
"\n",
|
| 490 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 491 |
"---\n",
|
| 492 |
"{'supervisor': {'next': 'FINISH'}}\n",
|
| 493 |
"---\n"
|
|
@@ -495,7 +643,7 @@
|
|
| 495 |
}
|
| 496 |
],
|
| 497 |
"source": [
|
| 498 |
-
"demo_research_chain(\"
|
| 499 |
]
|
| 500 |
},
|
| 501 |
{
|
|
|
|
| 1 |
{
|
| 2 |
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# Adobe research unit"
|
| 8 |
+
]
|
| 9 |
+
},
|
| 10 |
{
|
| 11 |
"cell_type": "code",
|
| 12 |
+
"execution_count": 282,
|
| 13 |
"metadata": {},
|
| 14 |
"outputs": [],
|
| 15 |
"source": [
|
|
|
|
| 22 |
},
|
| 23 |
{
|
| 24 |
"cell_type": "code",
|
| 25 |
+
"execution_count": 283,
|
| 26 |
"metadata": {},
|
| 27 |
"outputs": [],
|
| 28 |
"source": [
|
|
|
|
| 31 |
},
|
| 32 |
{
|
| 33 |
"cell_type": "code",
|
| 34 |
+
"execution_count": 284,
|
| 35 |
"metadata": {},
|
| 36 |
+
"outputs": [
|
| 37 |
+
{
|
| 38 |
+
"name": "stdout",
|
| 39 |
+
"output_type": "stream",
|
| 40 |
+
"text": [
|
| 41 |
+
"The autoreload extension is already loaded. To reload it, use:\n",
|
| 42 |
+
" %reload_ext autoreload\n"
|
| 43 |
+
]
|
| 44 |
+
}
|
| 45 |
+
],
|
| 46 |
"source": [
|
| 47 |
"%load_ext autoreload\n",
|
| 48 |
"%autoreload 2\n"
|
|
|
|
| 50 |
},
|
| 51 |
{
|
| 52 |
"cell_type": "code",
|
| 53 |
+
"execution_count": 285,
|
| 54 |
"metadata": {},
|
| 55 |
"outputs": [],
|
| 56 |
"source": [
|
| 57 |
+
"from uuid import uuid4\n",
|
| 58 |
+
"\n",
|
| 59 |
+
"unique_id = uuid4().hex[0:8]\n",
|
| 60 |
"\n",
|
| 61 |
"load_dotenv()\n",
|
| 62 |
"\n",
|
|
|
|
| 67 |
" os.environ[key_name] = getpass.getpass(prompt_message)\n",
|
| 68 |
"\n",
|
| 69 |
"set_api_key_if_not_present(\"OPENAI_API_KEY\")\n",
|
| 70 |
+
"set_api_key_if_not_present(\"TAVILY_API_KEY\")\n",
|
| 71 |
+
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
|
| 72 |
+
"os.environ[\"LANGCHAIN_PROJECT\"] = f\"AIE - MBUDISIC - CERT - {unique_id}\"\n",
|
| 73 |
+
"set_api_key_if_not_present(\"LANGCHAIN_API_KEY\")\n"
|
| 74 |
]
|
| 75 |
},
|
| 76 |
{
|
| 77 |
"cell_type": "code",
|
| 78 |
+
"execution_count": 286,
|
| 79 |
"metadata": {},
|
| 80 |
"outputs": [],
|
| 81 |
"source": [
|
|
|
|
| 92 |
},
|
| 93 |
{
|
| 94 |
"cell_type": "code",
|
| 95 |
+
"execution_count": 287,
|
| 96 |
"metadata": {},
|
| 97 |
"outputs": [],
|
| 98 |
"source": [
|
|
|
|
|
|
|
|
|
|
| 99 |
"\n",
|
| 100 |
+
"from langchain_core.messages import HumanMessage\n",
|
| 101 |
"from langchain_openai.chat_models import ChatOpenAI\n",
|
| 102 |
"\n",
|
| 103 |
+
"from pstuts_rag.agents import PsTutsTeamState\n"
|
|
|
|
|
|
|
|
|
|
| 104 |
]
|
| 105 |
},
|
| 106 |
{
|
| 107 |
"cell_type": "code",
|
| 108 |
+
"execution_count": 288,
|
| 109 |
"metadata": {},
|
| 110 |
"outputs": [],
|
| 111 |
"source": [
|
| 112 |
+
"test_query = PsTutsTeamState(messages=[HumanMessage(content=\"What are layers?\")],\n",
|
| 113 |
+
" team_members=[], next=\"\")"
|
| 114 |
]
|
| 115 |
},
|
| 116 |
{
|
| 117 |
"cell_type": "code",
|
| 118 |
+
"execution_count": 289,
|
| 119 |
"metadata": {},
|
| 120 |
"outputs": [],
|
| 121 |
"source": [
|
| 122 |
+
"llm_tool_calling = ChatOpenAI(model=params.tool_calling_model,temperature=0)"
|
|
|
|
|
|
|
| 123 |
]
|
| 124 |
},
|
| 125 |
{
|
| 126 |
+
"cell_type": "markdown",
|
|
|
|
| 127 |
"metadata": {},
|
|
|
|
| 128 |
"source": [
|
| 129 |
+
"## Tavily"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
]
|
| 131 |
},
|
| 132 |
{
|
| 133 |
"cell_type": "code",
|
| 134 |
+
"execution_count": 290,
|
| 135 |
"metadata": {},
|
| 136 |
"outputs": [],
|
| 137 |
"source": [
|
| 138 |
+
"from pstuts_rag.agent_tavily import create_tavily_node\n",
|
| 139 |
+
"\n",
|
| 140 |
+
"\n",
|
| 141 |
+
"adobe_help_node, adobe_help_agent,adobe_search = create_tavily_node(llm=llm_tool_calling,name=\"AdobeHelp\")"
|
| 142 |
]
|
| 143 |
},
|
| 144 |
{
|
| 145 |
"cell_type": "code",
|
| 146 |
+
"execution_count": 291,
|
| 147 |
"metadata": {},
|
| 148 |
"outputs": [
|
| 149 |
{
|
| 150 |
"data": {
|
| 151 |
"text/plain": [
|
| 152 |
+
"[{'title': 'Top 4 reasons to crop your photo',\n",
|
| 153 |
+
" 'url': 'https://helpx.adobe.com/lv/photoshop/how-to/cropping-photo-basics.html',\n",
|
| 154 |
+
" 'content': 'Cropping is the easiest way to remove unwanted objects or people at the edges of a photograph. Anything outside the crop boundary will disappear from your image',\n",
|
| 155 |
+
" 'score': 0.585789},\n",
|
| 156 |
+
" {'title': 'Crop, resize, and resample images in Photoshop Elements',\n",
|
| 157 |
+
" 'url': 'https://helpx.adobe.com/au/photoshop-elements/kb/crop-resize-resample-photoshop-elements.html',\n",
|
| 158 |
+
" 'content': 'When you crop an image, you trim away material from the edges to show a smaller area, often for artistic reasons.',\n",
|
| 159 |
+
" 'score': 0.585789},\n",
|
| 160 |
+
" {'title': 'How to crop and straighten photos in Photoshop',\n",
|
| 161 |
+
" 'url': 'https://helpx.adobe.com/photoshop/using/crop-straighten-photos.html',\n",
|
| 162 |
+
" 'content': \"Try it in the app\\nYou'll get a sample file to follow along with as you learn how to crop photos.\\nOpen Photoshop\\nCropping is the process of removing portions of a photo to create focus or strengthen the composition. Use the Crop tool to crop and straighten photos in Photoshop. The Crop tool is non-destructive, and you can choose to retain the cropped pixels to optimize the crop boundaries later. The Crop tool also provides intuitive methods to straighten a photo while cropping. [...] Press Enter (Windows) or Return (Mac OS) to crop the photo.\\n\\n\\nContent-Aware Fill on Crop\\nIntroduced in Photoshop CC 2015.5 release\\nPhotoshop now uses content-aware technology to intelligently fill in the gaps when you use the Crop tool for straightening or rotating an image, or expanding your canvas beyond the image's original size. \\nFollow these steps:\\n\\n\\nFrom the toolbar, select the Crop Tool (). Crop borders display on the edges of the photo. [...] See the video Adjust perspective in a photo for more information.\\nResize the canvas using the Crop tool\\nYou can use the Crop tool to resize the image canvas.\\n\\n\\nFrom the toolbar, select the Crop Tool\\xa0. Crop borders display on the edges of the image.\\n\\n\\nDrag the crop handles outwards to enlarge the canvas. Use the Alt/Option modifier key to enlarge from all sides.\\n\\n\\nPress Enter (Windows) or Return (Mac OS) to confirm the action.\",\n",
|
| 163 |
+
" 'score': 0.5826579},\n",
|
| 164 |
+
" {'title': 'Crop images in Photoshop Elements',\n",
|
| 165 |
+
" 'url': 'https://helpx.adobe.com/ca/photoshop-elements/using/cropping.html',\n",
|
| 166 |
+
" 'content': 'The Crop tool removes the part of an image surrounding the selection. Crop to remove distractive background elements and create a focus on',\n",
|
| 167 |
+
" 'score': 0.5367749},\n",
|
| 168 |
+
" {'title': 'Crop a photo using the Crop tool',\n",
|
| 169 |
+
" 'url': 'https://helpx.adobe.com/photoshop/using/tool-techniques/crop-tool.html',\n",
|
| 170 |
+
" 'content': 'The Crop tool allows you to select an area of a photo and remove or crop everything outside the selected area. Photoshop Crop Tool.',\n",
|
| 171 |
+
" 'score': 0.49567938}]"
|
| 172 |
]
|
| 173 |
},
|
| 174 |
+
"execution_count": 291,
|
| 175 |
"metadata": {},
|
| 176 |
"output_type": "execute_result"
|
| 177 |
}
|
| 178 |
],
|
| 179 |
"source": [
|
| 180 |
+
"adobe_search(\"What is crop?\")"
|
| 181 |
+
]
|
| 182 |
+
},
|
| 183 |
+
{
|
| 184 |
+
"cell_type": "code",
|
| 185 |
+
"execution_count": 292,
|
| 186 |
+
"metadata": {},
|
| 187 |
+
"outputs": [],
|
| 188 |
+
"source": [
|
| 189 |
+
"retval = adobe_help_agent.invoke({\"input\":\"What is crop?\",\"messages\":[],\"team_members\":[],\"next\":[]}),\n"
|
| 190 |
+
]
|
| 191 |
+
},
|
| 192 |
+
{
|
| 193 |
+
"cell_type": "code",
|
| 194 |
+
"execution_count": 293,
|
| 195 |
+
"metadata": {},
|
| 196 |
+
"outputs": [
|
| 197 |
+
{
|
| 198 |
+
"name": "stdout",
|
| 199 |
+
"output_type": "stream",
|
| 200 |
+
"text": [
|
| 201 |
+
"('To create and use clipping masks in Adobe Photoshop, follow these steps:\\n'\n",
|
| 202 |
+
" '\\n'\n",
|
| 203 |
+
" '1. Arrange your layers in the Layers panel so that the layer you want to use '\n",
|
| 204 |
+
" 'as a mask is directly below the layer you want to mask.\\n'\n",
|
| 205 |
+
" '\\n'\n",
|
| 206 |
+
" '2. Select the top layer (the one you want to be clipped) in the Layers '\n",
|
| 207 |
+
" 'panel.\\n'\n",
|
| 208 |
+
" '\\n'\n",
|
| 209 |
+
" '3. Choose Layer > Create Clipping Mask from the menu. Alternatively, you can '\n",
|
| 210 |
+
" 'right-click the top layer and select \"Create Clipping Mask.\"\\n'\n",
|
| 211 |
+
" '\\n'\n",
|
| 212 |
+
" '4. The top layer will now be clipped to the shape and transparency of the '\n",
|
| 213 |
+
" 'layer below it, meaning it will only show through where the bottom layer has '\n",
|
| 214 |
+
" 'pixels.\\n'\n",
|
| 215 |
+
" '\\n'\n",
|
| 216 |
+
" 'You can use two or more layers as a clipping mask, and you can release the '\n",
|
| 217 |
+
" 'clipping mask by selecting the clipped layer and choosing Layer > Release '\n",
|
| 218 |
+
" 'Clipping Mask.\\n'\n",
|
| 219 |
+
" '\\n'\n",
|
| 220 |
+
" \"For more detailed instructions, you can visit Adobe's official help page on \"\n",
|
| 221 |
+
" 'clipping masks:\\n'\n",
|
| 222 |
+
" 'https://helpx.adobe.com/photoshop/using/revealing-layers-clipping-masks.html')\n"
|
| 223 |
+
]
|
| 224 |
+
}
|
| 225 |
+
],
|
| 226 |
+
"source": [
|
| 227 |
+
"from pprint import pp\n",
|
| 228 |
+
"pp(retval[0][\"output\"])"
|
| 229 |
+
]
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"cell_type": "code",
|
| 233 |
+
"execution_count": 294,
|
| 234 |
+
"metadata": {},
|
| 235 |
+
"outputs": [],
|
| 236 |
+
"source": [
|
| 237 |
+
"output = adobe_help_node(test_query)"
|
| 238 |
+
]
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"cell_type": "code",
|
| 242 |
+
"execution_count": 295,
|
| 243 |
+
"metadata": {},
|
| 244 |
+
"outputs": [
|
| 245 |
+
{
|
| 246 |
+
"name": "stdout",
|
| 247 |
+
"output_type": "stream",
|
| 248 |
+
"text": [
|
| 249 |
+
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 250 |
+
"Name: AdobeHelp\n",
|
| 251 |
+
"\n",
|
| 252 |
+
"Layers in Adobe Photoshop are fundamental elements that allow you to work on different parts of an image independently without affecting other parts. Think of layers as stacked, transparent sheets of glass, where each layer can contain images, text, effects, or objects. You can edit, move, and apply changes to one layer without altering the content on other layers.\n",
|
| 253 |
+
"\n",
|
| 254 |
+
"Layers help you make nondestructive edits by stacking and managing images, text, and graphics separately. They are arranged in a stack in the Layers panel, usually located in the bottom right of the workspace. You can add multiple layers to composite images, add text, apply filters, and create complex designs.\n",
|
| 255 |
+
"\n",
|
| 256 |
+
"The bottommost layer is often the Background layer, which is locked by default but can be converted to a regular layer for more flexibility.\n",
|
| 257 |
+
"\n",
|
| 258 |
+
"In summary, layers let you:\n",
|
| 259 |
+
"- Work on different elements independently\n",
|
| 260 |
+
"- Apply effects and adjustments to specific parts\n",
|
| 261 |
+
"- Rearrange content by changing the stacking order\n",
|
| 262 |
+
"- Control opacity and blending modes for creative effects\n",
|
| 263 |
+
"\n",
|
| 264 |
+
"For more details, you can visit Adobe's official help page about layers: \n",
|
| 265 |
+
"https://helpx.adobe.com/photoshop/web/edit-images/manage-layers/about-layers.html\n"
|
| 266 |
+
]
|
| 267 |
+
}
|
| 268 |
+
],
|
| 269 |
+
"source": [
|
| 270 |
+
"output[\"messages\"][-1].pretty_print()"
|
| 271 |
]
|
| 272 |
},
|
| 273 |
{
|
| 274 |
"cell_type": "markdown",
|
| 275 |
"metadata": {},
|
| 276 |
"source": [
|
| 277 |
+
"## Data Preparation\n",
|
| 278 |
"\n",
|
| 279 |
"First, we will read in the transcripts of the videos and convert them to Documents\n",
|
| 280 |
"with appropriate metadata."
|
|
|
|
| 282 |
},
|
| 283 |
{
|
| 284 |
"cell_type": "code",
|
| 285 |
+
"execution_count": 296,
|
| 286 |
"metadata": {},
|
| 287 |
"outputs": [],
|
| 288 |
"source": [
|
|
|
|
| 295 |
"data:List[Dict[str,Any]] = await load_json_files(filename)\n"
|
| 296 |
]
|
| 297 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
{
|
| 299 |
"cell_type": "markdown",
|
| 300 |
"metadata": {},
|
|
|
|
| 304 |
},
|
| 305 |
{
|
| 306 |
"cell_type": "code",
|
| 307 |
+
"execution_count": 297,
|
| 308 |
"metadata": {},
|
| 309 |
"outputs": [],
|
| 310 |
"source": [
|
|
|
|
| 313 |
"\n",
|
| 314 |
"client = QdrantClient(path=\":memory:\")\n",
|
| 315 |
"\n",
|
| 316 |
+
"datastore_manager = DatastoreManager(qdrant_client=client,name=\"local_test\")\n",
|
| 317 |
+
"if datastore_manager.count_docs() == 0:\n",
|
| 318 |
+
" await datastore_manager.populate_database(raw_docs=data)"
|
| 319 |
]
|
| 320 |
},
|
| 321 |
{
|
| 322 |
"cell_type": "markdown",
|
| 323 |
"metadata": {},
|
| 324 |
"source": [
|
| 325 |
+
"## RAG Agent"
|
|
|
|
|
|
|
| 326 |
]
|
| 327 |
},
|
| 328 |
{
|
| 329 |
"cell_type": "code",
|
| 330 |
+
"execution_count": 298,
|
| 331 |
"metadata": {},
|
| 332 |
+
"outputs": [
|
| 333 |
+
{
|
| 334 |
+
"name": "stdout",
|
| 335 |
+
"output_type": "stream",
|
| 336 |
+
"text": [
|
| 337 |
+
"<built-in function repr>\n"
|
| 338 |
+
]
|
| 339 |
+
}
|
| 340 |
+
],
|
| 341 |
"source": [
|
| 342 |
+
"from pstuts_rag.agent_rag import create_rag_node\n",
|
|
|
|
| 343 |
"from langchain_openai import ChatOpenAI\n",
|
| 344 |
"from langchain_core.tools import tool\n",
|
| 345 |
+
"rag_node, rag_search = create_rag_node(retriever=datastore_manager.get_retriever(),\n",
|
| 346 |
+
" llm=ChatOpenAI(model=\"gpt-4.1-mini\",temperature=0),\n",
|
| 347 |
+
" name=\"VideoArchiveSearch\" )\n",
|
| 348 |
+
"\n"
|
| 349 |
+
]
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"cell_type": "code",
|
| 353 |
+
"execution_count": 299,
|
| 354 |
+
"metadata": {},
|
| 355 |
+
"outputs": [],
|
| 356 |
+
"source": [
|
| 357 |
"\n",
|
| 358 |
+
"retval = rag_search(\"What is Seinfeld?\")\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 359 |
]
|
| 360 |
},
|
| 361 |
{
|
| 362 |
"cell_type": "code",
|
| 363 |
+
"execution_count": 300,
|
| 364 |
"metadata": {},
|
| 365 |
"outputs": [
|
| 366 |
{
|
| 367 |
+
"name": "stdout",
|
| 368 |
+
"output_type": "stream",
|
| 369 |
+
"text": [
|
| 370 |
+
"\"I don't know. This isn’t covered in the training videos.\"\n"
|
| 371 |
+
]
|
|
|
|
|
|
|
|
|
|
| 372 |
}
|
| 373 |
],
|
| 374 |
"source": [
|
| 375 |
+
"from pprint import pp\n",
|
| 376 |
+
"pp(retval)"
|
| 377 |
]
|
| 378 |
},
|
| 379 |
{
|
| 380 |
"cell_type": "code",
|
| 381 |
+
"execution_count": 301,
|
| 382 |
"metadata": {},
|
| 383 |
+
"outputs": [
|
| 384 |
+
{
|
| 385 |
+
"name": "stdout",
|
| 386 |
+
"output_type": "stream",
|
| 387 |
+
"text": [
|
| 388 |
+
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 389 |
+
"Name: VideoArchiveSearch\n",
|
| 390 |
+
"\n",
|
| 391 |
+
"Layers are the building blocks of any image in Photoshop CC. You can think of layers like separate flat panes of glass stacked on top of each other, with each layer containing separate pieces of content. Some parts of a layer can be transparent, allowing you to see through to the layers below. This setup lets you edit parts of an image independently without affecting the rest of the image. You work with layers in the Layers panel, where you can toggle their visibility on and off using the Eye icon. (See explanation around 0:28–2:00 and 1:25–2:32 in the video) 🎨🖼️\n",
|
| 392 |
+
"**REFERENCES**\n",
|
| 393 |
+
"[\n",
|
| 394 |
+
" {\n",
|
| 395 |
+
" \"title\": \"Understand layers\",\n",
|
| 396 |
+
" \"source\": \"https://images-tv.adobe.com/avp/vr/b758b4c4-2a74-41f4-8e67-e2f2eab83c6a/f810fc5b-2b04-4e23-8fa4-5c532e7de6f8/e268fe4d-e5c7-415c-9f5c-d34d024b14d8_20170727011753.1280x720at2400_h264.mp4\",\n",
|
| 397 |
+
" \"start\": 0.47,\n",
|
| 398 |
+
" \"stop\": 62.14\n",
|
| 399 |
+
" },\n",
|
| 400 |
+
" {\n",
|
| 401 |
+
" \"title\": \"Understand layers\",\n",
|
| 402 |
+
" \"source\": \"https://images-tv.adobe.com/avp/vr/b758b4c4-2a74-41f4-8e67-e2f2eab83c6a/f810fc5b-2b04-4e23-8fa4-5c532e7de6f8/e268fe4d-e5c7-415c-9f5c-d34d024b14d8_20170727011753.1280x720at2400_h264.mp4\",\n",
|
| 403 |
+
" \"start\": 85.75,\n",
|
| 404 |
+
" \"stop\": 152.97\n",
|
| 405 |
+
" }\n",
|
| 406 |
+
"]\n"
|
| 407 |
+
]
|
| 408 |
+
}
|
| 409 |
+
],
|
| 410 |
"source": [
|
| 411 |
+
"rag_output = rag_node(test_query)\n",
|
| 412 |
+
"rag_output[\"messages\"][-1].pretty_print()"
|
| 413 |
+
]
|
| 414 |
+
},
|
| 415 |
+
{
|
| 416 |
+
"cell_type": "markdown",
|
| 417 |
+
"metadata": {},
|
| 418 |
+
"source": [
|
| 419 |
+
"## Graph Creation"
|
| 420 |
]
|
| 421 |
},
|
| 422 |
{
|
| 423 |
"cell_type": "code",
|
| 424 |
+
"execution_count": 302,
|
| 425 |
"metadata": {},
|
| 426 |
"outputs": [],
|
| 427 |
"source": [
|
| 428 |
"from pstuts_rag.agents import create_team_supervisor\n",
|
| 429 |
+
"from pstuts_rag.prompt_templates import SUPERVISOR_SYSTEM\n",
|
| 430 |
"supervisor_agent = create_team_supervisor(\n",
|
| 431 |
" llm_tool_calling,\n",
|
| 432 |
+
" SUPERVISOR_SYSTEM,\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
" [\"VideoArchiveSearch\", \"AdobeHelp\"],\n",
|
| 434 |
")\n",
|
| 435 |
"\n"
|
| 436 |
]
|
| 437 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 438 |
{
|
| 439 |
"cell_type": "code",
|
| 440 |
+
"execution_count": 303,
|
| 441 |
"metadata": {},
|
| 442 |
+
"outputs": [
|
| 443 |
+
{
|
| 444 |
+
"data": {
|
| 445 |
+
"text/plain": [
|
| 446 |
+
"<langgraph.graph.state.StateGraph at 0x71685a01e120>"
|
| 447 |
+
]
|
| 448 |
+
},
|
| 449 |
+
"execution_count": 303,
|
| 450 |
+
"metadata": {},
|
| 451 |
+
"output_type": "execute_result"
|
| 452 |
+
}
|
| 453 |
+
],
|
| 454 |
"source": [
|
| 455 |
"from langgraph.graph import END, StateGraph\n",
|
| 456 |
"\n",
|
| 457 |
"adobe_help_graph = StateGraph(PsTutsTeamState)\n",
|
| 458 |
"\n",
|
| 459 |
+
"adobe_help_graph.add_node(\"VideoArchiveSearch\", rag_node)\n",
|
| 460 |
"adobe_help_graph.add_node(\"AdobeHelp\", adobe_help_node)\n",
|
| 461 |
"adobe_help_graph.add_node(\"supervisor\", supervisor_agent)\n",
|
| 462 |
"\n",
|
|
|
|
| 473 |
" {\"VideoArchiveSearch\":\"VideoArchiveSearch\",\n",
|
| 474 |
" \"AdobeHelp\":\"AdobeHelp\", \n",
|
| 475 |
" \"FINISH\": END},\n",
|
| 476 |
+
")\n"
|
|
|
|
|
|
|
| 477 |
]
|
| 478 |
},
|
| 479 |
{
|
| 480 |
"cell_type": "code",
|
| 481 |
+
"execution_count": 304,
|
| 482 |
"metadata": {},
|
| 483 |
+
"outputs": [],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 484 |
"source": [
|
| 485 |
"adobe_help_graph.set_entry_point(\"supervisor\")\n",
|
| 486 |
"compiled_research_graph = adobe_help_graph.compile()"
|
|
|
|
| 488 |
},
|
| 489 |
{
|
| 490 |
"cell_type": "code",
|
| 491 |
+
"execution_count": 305,
|
| 492 |
"metadata": {},
|
| 493 |
"outputs": [],
|
| 494 |
"source": [
|
|
|
|
| 498 |
},
|
| 499 |
{
|
| 500 |
"cell_type": "code",
|
| 501 |
+
"execution_count": 306,
|
| 502 |
"metadata": {},
|
| 503 |
"outputs": [
|
| 504 |
{
|
|
|
|
| 513 |
" * \n",
|
| 514 |
" +------------+ \n",
|
| 515 |
" | supervisor | \n",
|
| 516 |
+
" .....+------------+..... \n",
|
| 517 |
+
" .... . .... \n",
|
| 518 |
+
" ..... . ..... \n",
|
| 519 |
+
" ... . ... \n",
|
| 520 |
"+-----------+ +--------------------+ +---------+ \n",
|
| 521 |
"| AdobeHelp | | VideoArchiveSearch | | __end__ | \n",
|
| 522 |
"+-----------+ +--------------------+ +---------+ \n"
|
|
|
|
| 532 |
},
|
| 533 |
{
|
| 534 |
"cell_type": "code",
|
| 535 |
+
"execution_count": 307,
|
| 536 |
"metadata": {},
|
| 537 |
"outputs": [],
|
| 538 |
"source": [
|
|
|
|
| 564 |
},
|
| 565 |
{
|
| 566 |
"cell_type": "code",
|
| 567 |
+
"execution_count": 308,
|
| 568 |
"metadata": {},
|
| 569 |
"outputs": [
|
| 570 |
{
|
|
|
|
| 576 |
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 577 |
"Name: VideoArchiveSearch\n",
|
| 578 |
"\n",
|
| 579 |
+
"Layers are the building blocks of any image in Photoshop CC. You can think of layers like separate flat panes of glass stacked on top of each other, where each layer contains separate pieces of content. Some parts of a layer can be transparent, allowing you to see through to the layers below. This setup lets you edit parts of an image independently without affecting the rest of the image. You work with layers in the Layers panel, where you can toggle their visibility on and off to see what each layer contains (explained around 0:28 to 1:03 and 1:25 to 2:33 in the video).\n",
|
| 580 |
+
"**REFERENCES**\n",
|
| 581 |
+
"[\n",
|
| 582 |
+
" {\n",
|
| 583 |
+
" \"title\": \"Understand layers\",\n",
|
| 584 |
+
" \"source\": \"https://images-tv.adobe.com/avp/vr/b758b4c4-2a74-41f4-8e67-e2f2eab83c6a/f810fc5b-2b04-4e23-8fa4-5c532e7de6f8/e268fe4d-e5c7-415c-9f5c-d34d024b14d8_20170727011753.1280x720at2400_h264.mp4\",\n",
|
| 585 |
+
" \"start\": 0.47,\n",
|
| 586 |
+
" \"stop\": 62.14\n",
|
| 587 |
+
" },\n",
|
| 588 |
+
" {\n",
|
| 589 |
+
" \"title\": \"Understand layers\",\n",
|
| 590 |
+
" \"source\": \"https://images-tv.adobe.com/avp/vr/b758b4c4-2a74-41f4-8e67-e2f2eab83c6a/f810fc5b-2b04-4e23-8fa4-5c532e7de6f8/e268fe4d-e5c7-415c-9f5c-d34d024b14d8_20170727011753.1280x720at2400_h264.mp4\",\n",
|
| 591 |
+
" \"start\": 85.75,\n",
|
| 592 |
+
" \"stop\": 152.97\n",
|
| 593 |
+
" }\n",
|
| 594 |
+
"]\n",
|
| 595 |
+
"---\n",
|
| 596 |
+
"{'supervisor': {'next': 'FINISH'}}\n",
|
| 597 |
+
"---\n"
|
| 598 |
+
]
|
| 599 |
+
}
|
| 600 |
+
],
|
| 601 |
+
"source": [
|
| 602 |
+
"demo_research_chain(\"What are layers?\")"
|
| 603 |
+
]
|
| 604 |
+
},
|
| 605 |
+
{
|
| 606 |
+
"cell_type": "code",
|
| 607 |
+
"execution_count": 309,
|
| 608 |
+
"metadata": {},
|
| 609 |
+
"outputs": [
|
| 610 |
+
{
|
| 611 |
+
"name": "stdout",
|
| 612 |
+
"output_type": "stream",
|
| 613 |
+
"text": [
|
| 614 |
+
"{'supervisor': {'next': 'VideoArchiveSearch'}}\n",
|
| 615 |
+
"---\n",
|
| 616 |
+
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 617 |
+
"Name: VideoArchiveSearch\n",
|
| 618 |
+
"\n",
|
| 619 |
+
"I don't know. This isn’t covered in the training videos.\n",
|
| 620 |
+
"---\n",
|
| 621 |
+
"{'supervisor': {'next': 'AdobeHelp'}}\n",
|
| 622 |
+
"---\n",
|
| 623 |
+
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 624 |
+
"Name: AdobeHelp\n",
|
| 625 |
"\n",
|
| 626 |
+
"To crop a layer in Adobe Photoshop, you can use the Crop tool in a way that targets the active layer or a selection within that layer. Here's how to do it:\n",
|
| 627 |
"\n",
|
| 628 |
+
"1. Select the layer you want to crop by clicking its thumbnail in the Layers panel.\n",
|
| 629 |
+
"2. Choose the Crop tool from the toolbar.\n",
|
| 630 |
+
"3. A bounding box will appear around the active layer or your selection.\n",
|
| 631 |
+
"4. Drag the handles of the bounding box to set the crop size.\n",
|
| 632 |
+
"5. You can also rotate the layer by moving the rotation dial below the bounding box if needed.\n",
|
| 633 |
+
"6. Once you have the desired crop area, apply the crop.\n",
|
| 634 |
+
"\n",
|
| 635 |
+
"This method allows you to crop and rotate an active layer or the contents of a selection non-destructively.\n",
|
| 636 |
+
"\n",
|
| 637 |
+
"For more details, you can visit Adobe's official help page on cropping and rotating layers:\n",
|
| 638 |
+
"https://helpx.adobe.com/photoshop/using/crop-move-rotate-photos.html\n",
|
| 639 |
"---\n",
|
| 640 |
"{'supervisor': {'next': 'FINISH'}}\n",
|
| 641 |
"---\n"
|
|
|
|
| 643 |
}
|
| 644 |
],
|
| 645 |
"source": [
|
| 646 |
+
"demo_research_chain(\"How do we crop a layer?\")"
|
| 647 |
]
|
| 648 |
},
|
| 649 |
{
|
pstuts_rag/pstuts_rag/agent_rag.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pstuts_rag.prompt_templates import AGENT_SYSTEM, RAG_PROMPT_TEMPLATES
|
| 2 |
+
from .rag import RAGChainFactory
|
| 3 |
+
from langchain_core.vectorstores import VectorStoreRetriever
|
| 4 |
+
from langchain_core.tools import tool
|
| 5 |
+
from typing import Annotated
|
| 6 |
+
from langchain_core.runnables import RunnableLambda
|
| 7 |
+
from .agents import agent_node, create_agent
|
| 8 |
+
from langchain_core.language_models.chat_models import BaseChatModel
|
| 9 |
+
import functools
|
| 10 |
+
from langchain_core.output_parsers import StrOutputParser
|
| 11 |
+
from langchain_core.prompts import ChatPromptTemplate
|
| 12 |
+
from operator import itemgetter
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def create_rag_node(
|
| 16 |
+
llm: BaseChatModel,
|
| 17 |
+
retriever: VectorStoreRetriever,
|
| 18 |
+
name: str = "VideoSearch",
|
| 19 |
+
):
|
| 20 |
+
"""Create a RAG node for the agent graph.
|
| 21 |
+
|
| 22 |
+
Args:
|
| 23 |
+
llm: The language model to use
|
| 24 |
+
retriever: The retriever to use for RAG
|
| 25 |
+
name: The name of the node
|
| 26 |
+
|
| 27 |
+
Returns:
|
| 28 |
+
tuple: (node, search_function)
|
| 29 |
+
"""
|
| 30 |
+
rag_factory = RAGChainFactory(retriever=retriever)
|
| 31 |
+
rag_chain = rag_factory.get_rag_chain(llm=llm)
|
| 32 |
+
|
| 33 |
+
def search_transcripts(query: str) -> str:
|
| 34 |
+
"""Search through video transcripts to find relevant information about Photoshop.
|
| 35 |
+
|
| 36 |
+
Args:
|
| 37 |
+
query: The search query about Photoshop features or techniques
|
| 38 |
+
|
| 39 |
+
Returns:
|
| 40 |
+
str: Relevant information from the video transcripts
|
| 41 |
+
"""
|
| 42 |
+
result = rag_chain.invoke(
|
| 43 |
+
{"question": query, "input": query, "query": query}
|
| 44 |
+
)
|
| 45 |
+
return result.content
|
| 46 |
+
|
| 47 |
+
# Create a simple agent that just does the search
|
| 48 |
+
def search_agent(state):
|
| 49 |
+
# Extract query from input or messages
|
| 50 |
+
query = state.get("input", None)
|
| 51 |
+
if not query and state.get("messages", []):
|
| 52 |
+
last_message = state["messages"][-1]
|
| 53 |
+
query = (
|
| 54 |
+
last_message.content
|
| 55 |
+
if hasattr(last_message, "content")
|
| 56 |
+
else str(last_message)
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
if not query:
|
| 60 |
+
return {"output": "No query found in input or messages"}
|
| 61 |
+
|
| 62 |
+
result = search_transcripts(query)
|
| 63 |
+
return {"output": result}
|
| 64 |
+
|
| 65 |
+
# Use agent_node to create the node
|
| 66 |
+
rag_node = functools.partial(
|
| 67 |
+
agent_node, agent=RunnableLambda(search_agent), name=name
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
return rag_node, search_transcripts
|
pstuts_rag/pstuts_rag/agent_tavily.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Callable, Tuple
|
| 2 |
+
from langchain_community.tools.tavily_search import TavilySearchResults
|
| 3 |
+
from .agents import create_agent, agent_node
|
| 4 |
+
from langchain_core.language_models.chat_models import BaseChatModel
|
| 5 |
+
import functools
|
| 6 |
+
from langchain.agents.agent import AgentExecutor
|
| 7 |
+
from .prompt_templates import TAVILY_SYSTEM
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def create_tavily_node(
|
| 11 |
+
llm: BaseChatModel, name: str = "AdobeHelp"
|
| 12 |
+
) -> Tuple[Callable, AgentExecutor, TavilySearchResults]:
|
| 13 |
+
"""Initialize tool, agent, and node for Tavily search of helpx.adobe.com.
|
| 14 |
+
|
| 15 |
+
This function sets up a search agent that can query Adobe Photoshop help topics
|
| 16 |
+
using the Tavily search engine, specifically targeting helpx.adobe.com.
|
| 17 |
+
|
| 18 |
+
Args:
|
| 19 |
+
llm: The language model to power the agent.
|
| 20 |
+
name: The name to assign to the agent node. Defaults to "AdobeHelp".
|
| 21 |
+
|
| 22 |
+
Returns:
|
| 23 |
+
Tuple containing:
|
| 24 |
+
- A callable node function that can be added to a graph
|
| 25 |
+
- The configured agent executor
|
| 26 |
+
- The Tavily search tool instance
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
adobe_help_search = TavilySearchResults(
|
| 30 |
+
max_results=5, include_domains=["helpx.adobe.com"]
|
| 31 |
+
)
|
| 32 |
+
adobe_help_agent = create_agent(
|
| 33 |
+
llm=llm, tools=[adobe_help_search], system_prompt=TAVILY_SYSTEM
|
| 34 |
+
)
|
| 35 |
+
adobe_help_node = functools.partial(
|
| 36 |
+
agent_node, agent=adobe_help_agent, name=name
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
return adobe_help_node, adobe_help_agent, adobe_help_search
|
pstuts_rag/pstuts_rag/agents.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
from typing import Any, Callable, List, Optional, TypedDict, Union
|
| 2 |
-
|
| 3 |
from langchain.agents import AgentExecutor, create_openai_functions_agent
|
| 4 |
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser
|
| 5 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
@@ -13,13 +13,19 @@ from langgraph.graph import END, StateGraph
|
|
| 13 |
import pstuts_rag.prompt_templates
|
| 14 |
|
| 15 |
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
"""agent_node calls the invoke function of the agent Runnable"""
|
| 18 |
# Initialize team_members if it's not already in the state
|
| 19 |
if "team_members" not in state:
|
| 20 |
state["team_members"] = []
|
| 21 |
result = agent.invoke(state)
|
| 22 |
-
return {"messages": [HumanMessage(content=result[
|
| 23 |
|
| 24 |
|
| 25 |
def create_agent(
|
|
@@ -31,10 +37,7 @@ def create_agent(
|
|
| 31 |
system_prompt += pstuts_rag.prompt_templates.AGENT_SYSTEM
|
| 32 |
prompt = ChatPromptTemplate.from_messages(
|
| 33 |
[
|
| 34 |
-
(
|
| 35 |
-
"system",
|
| 36 |
-
system_prompt,
|
| 37 |
-
),
|
| 38 |
MessagesPlaceholder(variable_name="messages"),
|
| 39 |
MessagesPlaceholder(variable_name="agent_scratchpad"),
|
| 40 |
]
|
|
|
|
| 1 |
+
from typing import Any, Callable, List, Optional, TypedDict, Union, Annotated
|
| 2 |
+
import operator
|
| 3 |
from langchain.agents import AgentExecutor, create_openai_functions_agent
|
| 4 |
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser
|
| 5 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
|
|
| 13 |
import pstuts_rag.prompt_templates
|
| 14 |
|
| 15 |
|
| 16 |
+
class PsTutsTeamState(TypedDict):
|
| 17 |
+
messages: Annotated[List[BaseMessage], operator.add]
|
| 18 |
+
team_members: List[str]
|
| 19 |
+
next: str
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def agent_node(state, agent, name, outputfield: str = "output"):
|
| 23 |
"""agent_node calls the invoke function of the agent Runnable"""
|
| 24 |
# Initialize team_members if it's not already in the state
|
| 25 |
if "team_members" not in state:
|
| 26 |
state["team_members"] = []
|
| 27 |
result = agent.invoke(state)
|
| 28 |
+
return {"messages": [HumanMessage(content=result[outputfield], name=name)]}
|
| 29 |
|
| 30 |
|
| 31 |
def create_agent(
|
|
|
|
| 37 |
system_prompt += pstuts_rag.prompt_templates.AGENT_SYSTEM
|
| 38 |
prompt = ChatPromptTemplate.from_messages(
|
| 39 |
[
|
| 40 |
+
("system", system_prompt),
|
|
|
|
|
|
|
|
|
|
| 41 |
MessagesPlaceholder(variable_name="messages"),
|
| 42 |
MessagesPlaceholder(variable_name="agent_scratchpad"),
|
| 43 |
]
|
pstuts_rag/pstuts_rag/prompt_templates.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
| 1 |
-
from typing import
|
| 2 |
|
| 3 |
-
RAG_PROMPT_TEMPLATES:
|
| 4 |
|
| 5 |
-
RAG_PROMPT_TEMPLATES
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
"""\
|
| 9 |
You are a helpful and friendly Photoshop expert.
|
| 10 |
|
| 11 |
Your job is to answer user questions based **only** on transcript excerpts from training videos. These transcripts include **timestamps** that indicate when in the video the information was spoken.
|
|
@@ -32,14 +31,11 @@ The transcript is from **spoken audio**, so it may include informal phrasing, fi
|
|
| 32 |
- ❌ Don't guess or summarize from general knowledge.
|
| 33 |
- ❌ Don’t fabricate steps, names, or features not in the transcript.
|
| 34 |
- ❌ Don’t omit the fallback response when required.
|
| 35 |
-
"""
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
(
|
| 41 |
-
"user",
|
| 42 |
-
"""\
|
| 43 |
### Question
|
| 44 |
{question}
|
| 45 |
|
|
@@ -48,9 +44,8 @@ NEVER invent the explanation. ALWAYS use ONLY the context information.
|
|
| 48 |
### Context
|
| 49 |
{context}
|
| 50 |
|
| 51 |
-
"""
|
| 52 |
-
|
| 53 |
-
)
|
| 54 |
SUPERVISOR_SYSTEM = """Given the conversation above, who should act next? Or should we FINISH?
|
| 55 |
If the last answer was 'I don't know', do not FINISH.
|
| 56 |
Select one of: {options}"""
|
|
@@ -58,6 +53,64 @@ Select one of: {options}"""
|
|
| 58 |
AGENT_SYSTEM = """Work autonomously according to your specialty, using the tools available to you.
|
| 59 |
Do not ask for clarification.
|
| 60 |
Your other team members (and other teams) will collaborate with you with their own specialties.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
You are chosen for a reason! You are one of the following team members: {team_members}.
|
| 63 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Dict
|
| 2 |
|
| 3 |
+
RAG_PROMPT_TEMPLATES: Dict[str, str] = {}
|
| 4 |
|
| 5 |
+
RAG_PROMPT_TEMPLATES[
|
| 6 |
+
"system"
|
| 7 |
+
] = """\
|
|
|
|
| 8 |
You are a helpful and friendly Photoshop expert.
|
| 9 |
|
| 10 |
Your job is to answer user questions based **only** on transcript excerpts from training videos. These transcripts include **timestamps** that indicate when in the video the information was spoken.
|
|
|
|
| 31 |
- ❌ Don't guess or summarize from general knowledge.
|
| 32 |
- ❌ Don’t fabricate steps, names, or features not in the transcript.
|
| 33 |
- ❌ Don’t omit the fallback response when required.
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
RAG_PROMPT_TEMPLATES[
|
| 37 |
+
"user"
|
| 38 |
+
] = """\
|
|
|
|
|
|
|
|
|
|
| 39 |
### Question
|
| 40 |
{question}
|
| 41 |
|
|
|
|
| 44 |
### Context
|
| 45 |
{context}
|
| 46 |
|
| 47 |
+
"""
|
| 48 |
+
|
|
|
|
| 49 |
SUPERVISOR_SYSTEM = """Given the conversation above, who should act next? Or should we FINISH?
|
| 50 |
If the last answer was 'I don't know', do not FINISH.
|
| 51 |
Select one of: {options}"""
|
|
|
|
| 53 |
AGENT_SYSTEM = """Work autonomously according to your specialty, using the tools available to you.
|
| 54 |
Do not ask for clarification.
|
| 55 |
Your other team members (and other teams) will collaborate with you with their own specialties.
|
| 56 |
+
Assume that the question is related to Adobe Photoshop.
|
| 57 |
+
|
| 58 |
+
If you find URLs in your context, make sure to emit them in your output as well
|
| 59 |
+
if you use them to generate the text.
|
| 60 |
|
| 61 |
You are chosen for a reason! You are one of the following team members: {team_members}.
|
| 62 |
"""
|
| 63 |
+
|
| 64 |
+
TAVILY_SYSTEM = """
|
| 65 |
+
You are a research assistant who can search
|
| 66 |
+
for Adobe Photoshop help topics using the tavily search engine.
|
| 67 |
+
Users may provide you with partial questions - try your best to determine their intent.
|
| 68 |
+
|
| 69 |
+
If Tavily provides no references, respond with "I don't know".
|
| 70 |
+
|
| 71 |
+
IMPORTANT: Include ALL urls from all references Tavily provides.
|
| 72 |
+
Separate them from the rest of the text using a line containing "**URL**"
|
| 73 |
+
"""
|
| 74 |
+
|
| 75 |
+
SUPERVISOR_SYSTEM = """You are the Supervisor for an agentic RAG system. Your job is to
|
| 76 |
+
interpret the user's request, extract the core research topic, and decide which
|
| 77 |
+
research-focused worker to invoke next. Reply only with the next worker and the
|
| 78 |
+
subject to research, or FINISH when the workflow is complete.
|
| 79 |
+
|
| 80 |
+
Workers
|
| 81 |
+
• VideoArchiveSearch – retrieves videos related to the query
|
| 82 |
+
• AdobeHelp – searches Adobe's documentation and training resources
|
| 83 |
+
|
| 84 |
+
Routing Rules
|
| 85 |
+
1. Topic Extraction
|
| 86 |
+
• Read the user's request and identify a concise research topic (e.g.
|
| 87 |
+
"Photoshop timeline keyframes").
|
| 88 |
+
|
| 89 |
+
2. Primary Preference
|
| 90 |
+
• First invoke VideoArchiveSearch with that topic.
|
| 91 |
+
• If VideoArchiveSearch returns "I don't know" or "no results," fall back to
|
| 92 |
+
AdobeHelp.
|
| 93 |
+
|
| 94 |
+
3. AdobeHelp Behavior
|
| 95 |
+
• Use specific queries to ask AdobeHelp for answers.
|
| 96 |
+
• Always provide URL for the page where you found answers.
|
| 97 |
+
• If returned answer contains new technical terms, query VideoArchiveSearch
|
| 98 |
+
to see if there are any videos on the topic.
|
| 99 |
+
|
| 100 |
+
4. Research-Only
|
| 101 |
+
• Only invoke workers that perform research tasks.
|
| 102 |
+
|
| 103 |
+
5. Completion
|
| 104 |
+
• When neither worked can provide value, go to FINISH. If AdobeHelp
|
| 105 |
+
expands the list of topics, make sure to attempt to search for them with the
|
| 106 |
+
VideoArchiveSearch.
|
| 107 |
+
|
| 108 |
+
Response Format
|
| 109 |
+
<WorkerName>: <Research Topic>
|
| 110 |
+
|
| 111 |
+
Example:
|
| 112 |
+
VideoArchiveSearch: exporting vector layers from After Effects
|
| 113 |
+
|
| 114 |
+
And, once there's no further research needed:
|
| 115 |
+
FINISH
|
| 116 |
+
"""
|
pstuts_rag/pstuts_rag/rag.py
CHANGED
|
@@ -90,9 +90,11 @@ class RAGChainFactory:
|
|
| 90 |
context=input["context"]
|
| 91 |
)
|
| 92 |
|
| 93 |
-
text_w_references =
|
| 94 |
-
|
| 95 |
-
|
|
|
|
|
|
|
| 96 |
|
| 97 |
output: AIMessage = answer.model_copy(
|
| 98 |
update={
|
|
@@ -138,9 +140,11 @@ class RAGChainFactory:
|
|
| 138 |
}
|
| 139 |
|
| 140 |
self.prompt_template = ChatPromptTemplate.from_messages(
|
| 141 |
-
RAG_PROMPT_TEMPLATES
|
| 142 |
)
|
| 143 |
|
|
|
|
|
|
|
| 144 |
def get_rag_chain(
|
| 145 |
self,
|
| 146 |
llm: BaseChatModel = ChatOpenAI(model="gpt-4.1-mini", temperature=0),
|
|
|
|
| 90 |
context=input["context"]
|
| 91 |
)
|
| 92 |
|
| 93 |
+
text_w_references = answer.content
|
| 94 |
+
if "I don't know" not in answer.content:
|
| 95 |
+
text_w_references = "\n".join(
|
| 96 |
+
[str(text_w_references), "**REFERENCES**", references]
|
| 97 |
+
)
|
| 98 |
|
| 99 |
output: AIMessage = answer.model_copy(
|
| 100 |
update={
|
|
|
|
| 140 |
}
|
| 141 |
|
| 142 |
self.prompt_template = ChatPromptTemplate.from_messages(
|
| 143 |
+
list(RAG_PROMPT_TEMPLATES.items())
|
| 144 |
)
|
| 145 |
|
| 146 |
+
print(repr)
|
| 147 |
+
|
| 148 |
def get_rag_chain(
|
| 149 |
self,
|
| 150 |
llm: BaseChatModel = ChatOpenAI(model="gpt-4.1-mini", temperature=0),
|