python_uml_class 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/test_run_new.log ADDED
@@ -0,0 +1,3083 @@
1
+ in_dir = .
2
+ ./lib/del_comment.py
3
+
4
+ |python3 lib/del_comment.py ./lib/del_comment.py > /tmp/pylint20260323-827-ocbr0w
5
+ block_count=0 cstruct_size=0 is_def=false import sys
6
+ block_count=0 cstruct_size=0 is_def=false import ast
7
+ block_count=0 cstruct_size=0 is_def=false import astor
8
+ block_count=0 cstruct_size=0 is_def=false import pprint
9
+ block_count=0 cstruct_size=0 is_def=false def remove_comments_from_code(code):
10
+ block_count=1 cstruct_size=0 is_def=true tree = ast.parse(code)
11
+ compo c_name=ast
12
+ block_count=1 cstruct_size=0 is_def=true for node in ast.walk(tree):
13
+ compo c_name=ast
14
+ block_count=2 cstruct_size=0 is_def=true if isinstance(node, ast.Expr) and isinstance(node.value, ast.Str
15
+ block_count=3 cstruct_size=0 is_def=true ) and isinstance(node.value.s, str):
16
+ block_count=3 cstruct_size=0 is_def=true if node.value.s.startswith(('#', '"""', "'''")):
17
+ compo c_name=node
18
+ endf of ./lib/del_comment.py
19
+ ./test/agent.py
20
+
21
+ |python3 lib/del_comment.py ./test/agent.py > /tmp/pylint20260323-827-hcxiok
22
+ block_count=0 cstruct_size=0 is_def=false import os
23
+ block_count=0 cstruct_size=0 is_def=false import sqlite3
24
+ block_count=0 cstruct_size=0 is_def=false import re
25
+ block_count=0 cstruct_size=0 is_def=false import json
26
+ block_count=0 cstruct_size=0 is_def=false import time
27
+ block_count=0 cstruct_size=0 is_def=false import shlex
28
+ block_count=0 cstruct_size=0 is_def=false import smtplib
29
+ block_count=0 cstruct_size=0 is_def=false from email.mime.text import MIMEText
30
+ compo c_name=email
31
+ block_count=0 cstruct_size=0 is_def=false from email.mime.multipart import MIMEMultipart
32
+ compo c_name=email
33
+ block_count=0 cstruct_size=0 is_def=false from typing import Optional, Type, Any, List, Dict
34
+ block_count=0 cstruct_size=0 is_def=false import urllib.request
35
+ compo c_name=urllib
36
+ block_count=0 cstruct_size=0 is_def=false import urllib.error
37
+ compo c_name=urllib
38
+ block_count=0 cstruct_size=0 is_def=false from dotenv import load_dotenv
39
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.tools import BaseTool, Tool
40
+ block_count=0 cstruct_size=0 is_def=false from pydantic import BaseModel, Field, model_validator
41
+ block_count=0 cstruct_size=0 is_def=false from langchain_google_genai import ChatGoogleGenerativeAI
42
+ block_count=0 cstruct_size=0 is_def=false from langchain_community.utilities import SerpAPIWrapper
43
+ block_count=0 cstruct_size=0 is_def=false from langchain_community.tools.tavily_search import TavilySearchResults
44
+ block_count=0 cstruct_size=0 is_def=false from googleapiclient.discovery import build
45
+ compo c_name=googleapiclient
46
+ block_count=0 cstruct_size=0 is_def=false import asyncio
47
+ block_count=0 cstruct_size=0 is_def=false from browser_use import Agent, BrowserProfile
48
+ block_count=0 cstruct_size=0 is_def=false from langchain_google_genai import ChatGoogleGenerativeAI
49
+ block_count=0 cstruct_size=0 is_def=false from browser_use.llm.google.chat import ChatGoogle
50
+ block_count=0 cstruct_size=0 is_def=false from langchain.agents import AgentExecutor, create_tool_calling_agent, create_react_agent
51
+ compo c_name=langchain
52
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.prompts import ChatPromptTemplate, PromptTemplate, MessagesPlaceholder
53
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.output_parsers import JsonOutputParser
54
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.messages import HumanMessage, AIMessage
55
+ block_count=0 cstruct_size=0 is_def=false dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
56
+ compo c_name=os
57
+ block_count=0 cstruct_size=0 is_def=false load_dotenv(dotenv_path, override=True)
58
+ block_count=0 cstruct_size=0 is_def=false DB_NAME = 'products.db'
59
+ block_count=0 cstruct_size=0 is_def=false def init_db():
60
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
61
+ compo c_name=sqlite3
62
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
63
+ compo c_name=conn
64
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
65
+ compo c_name=cursor
66
+ block_count=2 cstruct_size=0 is_def=true """
67
+ block_count=2 cstruct_size=0 is_def=true )
68
+ block_count=1 cstruct_size=0 is_def=true try:
69
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN model_number TEXT')
70
+ compo c_name=cursor
71
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
72
+ block_count=2 cstruct_size=0 is_def=true pass
73
+ block_count=1 cstruct_size=0 is_def=true try:
74
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN release_date TEXT')
75
+ compo c_name=cursor
76
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
77
+ block_count=2 cstruct_size=0 is_def=true pass
78
+ block_count=1 cstruct_size=0 is_def=true try:
79
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN ram TEXT')
80
+ compo c_name=cursor
81
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
82
+ block_count=2 cstruct_size=0 is_def=true pass
83
+ block_count=1 cstruct_size=0 is_def=true try:
84
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN ssd TEXT')
85
+ compo c_name=cursor
86
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
87
+ block_count=2 cstruct_size=0 is_def=true pass
88
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
89
+ compo c_name=cursor
90
+ block_count=2 cstruct_size=0 is_def=true """
91
+ block_count=2 cstruct_size=0 is_def=true )
92
+ block_count=1 cstruct_size=0 is_def=true conn.commit()
93
+ compo c_name=conn
94
+ block_count=1 cstruct_size=0 is_def=true conn.close()
95
+ compo c_name=conn
96
+ block_count=0 cstruct_size=0 is_def=true init_db()
97
+ block_count=0 cstruct_size=0 is_def=false class TavilySearchWrapper:
98
+ class_name=agent.TavilySearchWrapper
99
+ base_name=
100
+ block_count=1 cstruct_size=1 is_def=false def __init__(self):
101
+ block_count=2 cstruct_size=1 is_def=true self.api_key = os.getenv('TAVILY_API_KEY')
102
+ compo c_name=self
103
+ block_count=2 cstruct_size=1 is_def=true if not self.api_key:
104
+ compo c_name=self
105
+ block_count=3 cstruct_size=1 is_def=true raise ValueError('TAVILY_API_KEY must be set for Tavily Search.')
106
+ compo c_name=ValueError
107
+ block_count=2 cstruct_size=1 is_def=true self.tool = TavilySearchResults(api_key=self.api_key)
108
+ compo c_name=self
109
+ compo c_name=TavilySearchResults
110
+ block_count=1 cstruct_size=1 is_def=true def run(self, query: str) ->str:
111
+ block_count=2 cstruct_size=1 is_def=true try:
112
+ block_count=3 cstruct_size=1 is_def=true results = self.tool.invoke({'query': query})
113
+ compo c_name=self
114
+ block_count=3 cstruct_size=1 is_def=true formatted_results = []
115
+ block_count=3 cstruct_size=1 is_def=true for item in results:
116
+ block_count=4 cstruct_size=1 is_def=true content = item.get('content')
117
+ compo c_name=item
118
+ block_count=4 cstruct_size=1 is_def=true url = item.get('url')
119
+ compo c_name=item
120
+ block_count=4 cstruct_size=1 is_def=true formatted_results.append(f'Content: {content}\nURL: {url}\n')
121
+ block_count=3 cstruct_size=1 is_def=true return '\n'.join(formatted_results
122
+ block_count=4 cstruct_size=1 is_def=true ) if formatted_results else 'No results found.'
123
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
124
+ block_count=3 cstruct_size=1 is_def=true return f'Error during Tavily Search: {e}'
125
+ block_count=0 cstruct_size=1 is_def=true class BrowserUseSearchWrapper:
126
+ end of agent.TavilySearchWrapper
127
+ class_name=agent.BrowserUseSearchWrapper
128
+ base_name=
129
+ block_count=1 cstruct_size=1 is_def=false def __init__(self):
130
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
131
+ compo c_name=os
132
+ block_count=2 cstruct_size=1 is_def=true self.llm = ChatGoogle(model=model_name, api_key=os.getenv(
133
+ compo c_name=self
134
+ compo c_name=ChatGoogle
135
+ block_count=3 cstruct_size=1 is_def=true 'GOOGLE_API_KEY'))
136
+ block_count=2 cstruct_size=1 is_def=true user_agent = (
137
+ block_count=3 cstruct_size=1 is_def=true 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
138
+ block_count=3 cstruct_size=1 is_def=true )
139
+ block_count=2 cstruct_size=1 is_def=true self.browser_profile = BrowserProfile(headless=False, user_agent=
140
+ compo c_name=self
141
+ compo c_name=BrowserProfile
142
+ block_count=3 cstruct_size=1 is_def=true user_agent)
143
+ block_count=1 cstruct_size=1 is_def=true async def _search_async(self, query: str) ->str:
144
+ block_count=2 cstruct_size=1 is_def=false task = f"""
145
+ block_count=2 cstruct_size=1 is_def=false agent = Agent(task=task, llm=self.llm, browser_profile=self.
146
+ compo c_name=Agent
147
+ block_count=3 cstruct_size=1 is_def=false browser_profile)
148
+ block_count=2 cstruct_size=1 is_def=false result = await agent.run()
149
+ compo c_name=agent
150
+ block_count=2 cstruct_size=1 is_def=false return result.final_result()
151
+ compo c_name=result
152
+ block_count=1 cstruct_size=1 is_def=false def run(self, query: str) ->str:
153
+ block_count=2 cstruct_size=1 is_def=true try:
154
+ block_count=3 cstruct_size=1 is_def=true return asyncio.run(self._search_async(query))
155
+ compo c_name=asyncio
156
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
157
+ block_count=3 cstruct_size=1 is_def=true return f'Error during Browser Use Search: {e}'
158
+ block_count=0 cstruct_size=1 is_def=true def get_search_tool_func():
159
+ end of agent.BrowserUseSearchWrapper
160
+ block_count=1 cstruct_size=0 is_def=true provider = os.getenv('SEARCH_PROVIDER', 'serpapi')
161
+ compo c_name=os
162
+ block_count=1 cstruct_size=0 is_def=true if provider == 'tavily_api':
163
+ block_count=2 cstruct_size=0 is_def=true return TavilySearchWrapper()
164
+ compo c_name=TavilySearchWrapper
165
+ block_count=1 cstruct_size=0 is_def=true elif provider == 'browser_use':
166
+ block_count=2 cstruct_size=0 is_def=true return BrowserUseSearchWrapper()
167
+ compo c_name=BrowserUseSearchWrapper
168
+ block_count=1 cstruct_size=0 is_def=true else:
169
+ block_count=2 cstruct_size=0 is_def=true return SerpAPIWrapper()
170
+ compo c_name=SerpAPIWrapper
171
+ block_count=0 cstruct_size=0 is_def=true def get_all_products():
172
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
173
+ compo c_name=sqlite3
174
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
175
+ compo c_name=conn
176
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
177
+ compo c_name=cursor
178
+ block_count=2 cstruct_size=0 is_def=true 'SELECT id, name, store, price, url, description, model_number, release_date, ram, ssd, updated_at FROM products'
179
+ block_count=2 cstruct_size=0 is_def=true )
180
+ block_count=1 cstruct_size=0 is_def=true rows = cursor.fetchall()
181
+ compo c_name=cursor
182
+ block_count=1 cstruct_size=0 is_def=true conn.close()
183
+ compo c_name=conn
184
+ block_count=1 cstruct_size=0 is_def=true products = []
185
+ block_count=1 cstruct_size=0 is_def=true for r in rows:
186
+ block_count=2 cstruct_size=0 is_def=true products.append({'id': r[0], 'name': r[1], 'store': r[2], 'price':
187
+ compo c_name=products
188
+ block_count=3 cstruct_size=0 is_def=true r[3], 'url': r[4], 'description': r[5], 'model_number': r[6] if
189
+ block_count=3 cstruct_size=0 is_def=true len(r) > 6 else '', 'release_date': r[7] if len(r) > 7 else '',
190
+ block_count=3 cstruct_size=0 is_def=true 'ram': r[8] if len(r) > 8 else '', 'ssd': r[9] if len(r) > 9 else
191
+ block_count=3 cstruct_size=0 is_def=true '', 'updated_at': r[10] if len(r) > 10 else ''})
192
+ block_count=1 cstruct_size=0 is_def=true return products
193
+ block_count=0 cstruct_size=0 is_def=true def parse_price_val(p_str):
194
+ block_count=1 cstruct_size=0 is_def=true if not p_str:
195
+ block_count=2 cstruct_size=0 is_def=true return float('inf')
196
+ block_count=1 cstruct_size=0 is_def=true s = str(p_str).replace(',', '')
197
+ block_count=1 cstruct_size=0 is_def=true match_man = re.search('(\\d+(\\.\\d+)?)万', s)
198
+ compo c_name=re
199
+ block_count=1 cstruct_size=0 is_def=true if match_man:
200
+ block_count=2 cstruct_size=0 is_def=true try:
201
+ block_count=3 cstruct_size=0 is_def=true val = float(match_man.group(1)) * 10000
202
+ block_count=3 cstruct_size=0 is_def=true return int(val)
203
+ block_count=2 cstruct_size=0 is_def=true except:
204
+ block_count=3 cstruct_size=0 is_def=true pass
205
+ block_count=1 cstruct_size=0 is_def=true nums = re.findall('\\d+', s)
206
+ compo c_name=re
207
+ block_count=1 cstruct_size=0 is_def=true return int(''.join(nums)) if nums else float('inf')
208
+ block_count=0 cstruct_size=0 is_def=true def extract_alphanumeric(s: str) ->str:
209
+ block_count=1 cstruct_size=0 is_def=true """Extracts only alphanumeric characters from a string and converts to lowercase for robust comparison."""
210
+ block_count=1 cstruct_size=0 is_def=true if not s:
211
+ block_count=2 cstruct_size=0 is_def=true return ''
212
+ block_count=1 cstruct_size=0 is_def=true return re.sub('[^a-zA-Z0-9]', '', str(s)).lower()
213
+ compo c_name=re
214
+ block_count=0 cstruct_size=0 is_def=true def parse_date_val(d_str: str) ->str:
215
+ block_count=1 cstruct_size=0 is_def=true """
216
+ block_count=1 cstruct_size=0 is_def=true if not d_str:
217
+ block_count=2 cstruct_size=0 is_def=true return ''
218
+ block_count=1 cstruct_size=0 is_def=true nums = re.findall('\\d+', str(d_str))
219
+ compo c_name=re
220
+ block_count=1 cstruct_size=0 is_def=true if len(nums) >= 2:
221
+ block_count=2 cstruct_size=0 is_def=true year = nums[0]
222
+ block_count=2 cstruct_size=0 is_def=true month = nums[1].zfill(2)
223
+ block_count=2 cstruct_size=0 is_def=true return f'{year}{month}'
224
+ block_count=1 cstruct_size=0 is_def=true elif len(nums) == 1:
225
+ block_count=2 cstruct_size=0 is_def=true return nums[0]
226
+ block_count=1 cstruct_size=0 is_def=true else:
227
+ block_count=2 cstruct_size=0 is_def=true return extract_alphanumeric(d_str)
228
+ block_count=0 cstruct_size=0 is_def=true def is_similar_model(m1: str, m2: str) ->bool:
229
+ block_count=1 cstruct_size=0 is_def=true """
230
+ block_count=1 cstruct_size=0 is_def=true am1 = extract_alphanumeric(m1)
231
+ block_count=1 cstruct_size=0 is_def=true am2 = extract_alphanumeric(m2)
232
+ block_count=1 cstruct_size=0 is_def=true if not am1 and not am2:
233
+ block_count=2 cstruct_size=0 is_def=true return True
234
+ block_count=1 cstruct_size=0 is_def=true if not am1 or not am2:
235
+ block_count=2 cstruct_size=0 is_def=true return False
236
+ block_count=1 cstruct_size=0 is_def=true return am1 in am2 or am2 in am1
237
+ block_count=0 cstruct_size=0 is_def=true def save_agent_log(query, steps):
238
+ block_count=1 cstruct_size=0 is_def=true """Saves the agent's scratchpad (intermediate steps) to the database."""
239
+ block_count=1 cstruct_size=0 is_def=true if not steps:
240
+ block_count=2 cstruct_size=0 is_def=true return
241
+ block_count=1 cstruct_size=0 is_def=true log_content = []
242
+ block_count=1 cstruct_size=0 is_def=true for action, observation in steps:
243
+ block_count=2 cstruct_size=0 is_def=true if isinstance(action, list):
244
+ block_count=3 cstruct_size=0 is_def=true for a in action:
245
+ block_count=4 cstruct_size=0 is_def=true log_content.append(f'Tool: {a.tool}')
246
+ block_count=4 cstruct_size=0 is_def=true log_content.append(f'Input: {a.tool_input}')
247
+ block_count=4 cstruct_size=0 is_def=true log_content.append(f'Log: {a.log}')
248
+ block_count=2 cstruct_size=0 is_def=true else:
249
+ block_count=3 cstruct_size=0 is_def=true log_content.append(f'Tool: {action.tool}')
250
+ block_count=3 cstruct_size=0 is_def=true log_content.append(f'Input: {action.tool_input}')
251
+ block_count=3 cstruct_size=0 is_def=true log_content.append(f'Log: {action.log}')
252
+ block_count=2 cstruct_size=0 is_def=true log_content.append(f'Observation: {observation}')
253
+ block_count=2 cstruct_size=0 is_def=true log_content.append('-' * 20)
254
+ block_count=1 cstruct_size=0 is_def=true scratchpad_text = '\n'.join(log_content)
255
+ block_count=1 cstruct_size=0 is_def=true try:
256
+ block_count=2 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
257
+ compo c_name=sqlite3
258
+ block_count=2 cstruct_size=0 is_def=true cursor = conn.cursor()
259
+ compo c_name=conn
260
+ block_count=2 cstruct_size=0 is_def=true cursor.execute(
261
+ compo c_name=cursor
262
+ block_count=3 cstruct_size=0 is_def=true 'INSERT INTO agent_logs (query, scratchpad) VALUES (?, ?)', (
263
+ block_count=3 cstruct_size=0 is_def=true query, scratchpad_text))
264
+ block_count=2 cstruct_size=0 is_def=true conn.commit()
265
+ compo c_name=conn
266
+ block_count=2 cstruct_size=0 is_def=true conn.close()
267
+ compo c_name=conn
268
+ block_count=2 cstruct_size=0 is_def=true print(f' [Log saved to database]')
269
+ block_count=1 cstruct_size=0 is_def=true except Exception as e:
270
+ block_count=2 cstruct_size=0 is_def=true print(f'Error saving log: {e}')
271
+ block_count=0 cstruct_size=0 is_def=true def get_all_agent_logs():
272
+ block_count=1 cstruct_size=0 is_def=true """Fetches all agent logs from the database."""
273
+ block_count=1 cstruct_size=0 is_def=true try:
274
+ block_count=2 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
275
+ compo c_name=sqlite3
276
+ block_count=2 cstruct_size=0 is_def=true cursor = conn.cursor()
277
+ compo c_name=conn
278
+ block_count=2 cstruct_size=0 is_def=true cursor.execute(
279
+ compo c_name=cursor
280
+ block_count=3 cstruct_size=0 is_def=true 'SELECT query, scratchpad FROM agent_logs ORDER BY timestamp DESC')
281
+ block_count=2 cstruct_size=0 is_def=true rows = cursor.fetchall()
282
+ compo c_name=cursor
283
+ block_count=2 cstruct_size=0 is_def=true conn.close()
284
+ compo c_name=conn
285
+ block_count=2 cstruct_size=0 is_def=true logs = []
286
+ block_count=2 cstruct_size=0 is_def=true for r in rows:
287
+ block_count=3 cstruct_size=0 is_def=true logs.append(f'Query: {r[0]}\nLog:\n{r[1]}\n')
288
+ compo c_name=logs
289
+ block_count=2 cstruct_size=0 is_def=true return '\n'.join(logs)
290
+ block_count=1 cstruct_size=0 is_def=true except Exception as e:
291
+ block_count=2 cstruct_size=0 is_def=true print(f'Error fetching logs: {e}')
292
+ block_count=2 cstruct_size=0 is_def=true return ''
293
+ block_count=0 cstruct_size=0 is_def=true def send_email_notification(subject: str, body: str):
294
+ block_count=1 cstruct_size=0 is_def=true """Sends an email notification."""
295
+ block_count=1 cstruct_size=0 is_def=true smtp_server = os.getenv('EMAIL_SMTP_SERVER')
296
+ compo c_name=os
297
+ block_count=1 cstruct_size=0 is_def=true smtp_port = os.getenv('EMAIL_SMTP_PORT')
298
+ compo c_name=os
299
+ block_count=1 cstruct_size=0 is_def=true sender_email = os.getenv('EMAIL_SENDER_ADDRESS')
300
+ compo c_name=os
301
+ block_count=1 cstruct_size=0 is_def=true sender_password = os.getenv('EMAIL_SENDER_PASSWORD')
302
+ compo c_name=os
303
+ block_count=1 cstruct_size=0 is_def=true receiver_email = os.getenv('EMAIL_RECEIVER_ADDRESS')
304
+ compo c_name=os
305
+ block_count=1 cstruct_size=0 is_def=true if not all([smtp_server, smtp_port, sender_email, receiver_email]):
306
+ block_count=2 cstruct_size=0 is_def=true print(
307
+ block_count=3 cstruct_size=0 is_def=true 'Email configuration missing (Server, Port, Sender, Receiver). Skipping notification.'
308
+ block_count=3 cstruct_size=0 is_def=true )
309
+ block_count=2 cstruct_size=0 is_def=true return
310
+ block_count=1 cstruct_size=0 is_def=true try:
311
+ block_count=2 cstruct_size=0 is_def=true msg = MIMEMultipart()
312
+ compo c_name=MIMEMultipart
313
+ block_count=2 cstruct_size=0 is_def=true msg['From'] = sender_email
314
+ block_count=2 cstruct_size=0 is_def=true msg['To'] = receiver_email
315
+ block_count=2 cstruct_size=0 is_def=true msg['Subject'] = subject
316
+ block_count=2 cstruct_size=0 is_def=true msg.attach(MIMEText(body, 'plain'))
317
+ compo c_name=msg
318
+ compo c_name=MIMEText
319
+ block_count=2 cstruct_size=0 is_def=true server = smtplib.SMTP(smtp_server, int(smtp_port))
320
+ compo c_name=SMTP
321
+ block_count=2 cstruct_size=0 is_def=true server.starttls()
322
+ compo c_name=server
323
+ block_count=2 cstruct_size=0 is_def=true if sender_password:
324
+ block_count=3 cstruct_size=0 is_def=true server.login(sender_email, sender_password)
325
+ compo c_name=server
326
+ block_count=2 cstruct_size=0 is_def=true server.send_message(msg)
327
+ compo c_name=server
328
+ block_count=2 cstruct_size=0 is_def=true server.quit()
329
+ compo c_name=server
330
+ block_count=2 cstruct_size=0 is_def=true print(f'Email notification sent: {subject}')
331
+ block_count=1 cstruct_size=0 is_def=true except Exception as e:
332
+ block_count=2 cstruct_size=0 is_def=true print(f'Failed to send email: {e}')
333
+ block_count=0 cstruct_size=0 is_def=true class SaveProductInput(BaseModel):
334
+ class_name=agent.SaveProductInput
335
+ base_name=BaseModel
336
+ block_count=1 cstruct_size=1 is_def=false name: str = Field(description='Name of the product')
337
+ compo c_name=Field
338
+ block_count=1 cstruct_size=1 is_def=false store: str = Field(description='Name of the store selling the product')
339
+ compo c_name=Field
340
+ block_count=1 cstruct_size=1 is_def=false price: str = Field(description='Price of the product')
341
+ compo c_name=Field
342
+ block_count=1 cstruct_size=1 is_def=false url: Optional[str] = Field(description='URL of the product page',
343
+ compo c_name=Field
344
+ block_count=2 cstruct_size=1 is_def=false default='')
345
+ block_count=1 cstruct_size=1 is_def=false description: Optional[str] = Field(description=
346
+ compo c_name=Field
347
+ block_count=2 cstruct_size=1 is_def=false 'Brief description of the product', default='')
348
+ block_count=1 cstruct_size=1 is_def=false model_number: Optional[str] = Field(description=
349
+ compo c_name=Field
350
+ block_count=2 cstruct_size=1 is_def=false 'Model number (型番) of the product', default='')
351
+ block_count=1 cstruct_size=1 is_def=false release_date: Optional[str] = Field(description=
352
+ compo c_name=Field
353
+ block_count=2 cstruct_size=1 is_def=false 'Release date (発売日) of the product', default='')
354
+ block_count=1 cstruct_size=1 is_def=false ram: Optional[str] = Field(description='RAM size', default='')
355
+ compo c_name=Field
356
+ block_count=1 cstruct_size=1 is_def=false ssd: Optional[str] = Field(description='SSD size', default='')
357
+ compo c_name=Field
358
+ block_count=1 cstruct_size=1 is_def=false @model_validator(mode='before')
359
+ block_count=1 cstruct_size=1 is_def=false @classmethod
360
+ block_count=1 cstruct_size=1 is_def=false def parse_json_input(cls, data: Any) ->Any:
361
+ block_count=2 cstruct_size=1 is_def=true if isinstance(data, dict):
362
+ block_count=3 cstruct_size=1 is_def=true if 'name' in data and ('store' not in data or 'price' not in data):
363
+ block_count=4 cstruct_size=1 is_def=true name_val = data['name']
364
+ block_count=4 cstruct_size=1 is_def=true if isinstance(name_val, str) and name_val.strip().startswith(
365
+ block_count=5 cstruct_size=1 is_def=true '{') and name_val.strip().endswith('}'):
366
+ block_count=5 cstruct_size=1 is_def=true try:
367
+ block_count=6 cstruct_size=1 is_def=true parsed = json.loads(name_val)
368
+ compo c_name=json
369
+ block_count=6 cstruct_size=1 is_def=true if isinstance(parsed, dict):
370
+ block_count=7 cstruct_size=1 is_def=true data = parsed
371
+ block_count=5 cstruct_size=1 is_def=true except json.JSONDecodeError:
372
+ block_count=6 cstruct_size=1 is_def=true pass
373
+ block_count=2 cstruct_size=1 is_def=true if isinstance(data, dict) and 'price' in data:
374
+ block_count=3 cstruct_size=1 is_def=true if isinstance(data['price'], (int, float)):
375
+ block_count=4 cstruct_size=1 is_def=true data['price'] = str(data['price'])
376
+ block_count=2 cstruct_size=1 is_def=true return data
377
+ block_count=0 cstruct_size=1 is_def=true class SaveProductTool(BaseTool):
378
+ end of agent.SaveProductInput
379
+ class_name=agent.SaveProductTool
380
+ base_name=BaseTool
381
+ block_count=1 cstruct_size=1 is_def=false name = 'save_product'
382
+ block_count=1 cstruct_size=1 is_def=false description = (
383
+ block_count=2 cstruct_size=1 is_def=false 'Saves product information (name, store, price, url, description, model_number, release_date, ram, ssd) to the database.'
384
+ block_count=2 cstruct_size=1 is_def=false )
385
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = SaveProductInput
386
+ block_count=1 cstruct_size=1 is_def=false def _run(self, name: str, store: str=None, price: str=None, url: str='',
387
+ block_count=2 cstruct_size=1 is_def=true description: str='', model_number: str='', release_date: str='',
388
+ block_count=2 cstruct_size=1 is_def=true ram: str='', ssd: str='', **kwargs):
389
+ block_count=2 cstruct_size=1 is_def=true try:
390
+ block_count=3 cstruct_size=1 is_def=true parsed_data = {}
391
+ block_count=3 cstruct_size=1 is_def=true if isinstance(name, dict):
392
+ block_count=4 cstruct_size=1 is_def=true parsed_data = name
393
+ block_count=3 cstruct_size=1 is_def=true elif isinstance(name, str) and name.strip().startswith('{'
394
+ compo c_name=name
395
+ block_count=4 cstruct_size=1 is_def=true ) and name.strip().endswith('}'):
396
+ compo c_name=name
397
+ block_count=4 cstruct_size=1 is_def=true try:
398
+ block_count=5 cstruct_size=1 is_def=true parsed_data = json.loads(name)
399
+ compo c_name=json
400
+ block_count=4 cstruct_size=1 is_def=true except json.JSONDecodeError:
401
+ block_count=5 cstruct_size=1 is_def=true pass
402
+ block_count=3 cstruct_size=1 is_def=true if parsed_data:
403
+ block_count=4 cstruct_size=1 is_def=true if 'name' in parsed_data:
404
+ block_count=5 cstruct_size=1 is_def=true name = parsed_data['name']
405
+ block_count=4 cstruct_size=1 is_def=true if store is None:
406
+ block_count=5 cstruct_size=1 is_def=true store = parsed_data.get('store')
407
+ block_count=4 cstruct_size=1 is_def=true if price is None:
408
+ block_count=5 cstruct_size=1 is_def=true price = parsed_data.get('price')
409
+ block_count=4 cstruct_size=1 is_def=true if not url:
410
+ block_count=5 cstruct_size=1 is_def=true url = parsed_data.get('url', '')
411
+ block_count=4 cstruct_size=1 is_def=true if not description:
412
+ block_count=5 cstruct_size=1 is_def=true description = parsed_data.get('description', '')
413
+ block_count=4 cstruct_size=1 is_def=true if not model_number:
414
+ block_count=5 cstruct_size=1 is_def=true model_number = parsed_data.get('model_number', '')
415
+ block_count=4 cstruct_size=1 is_def=true if not release_date:
416
+ block_count=5 cstruct_size=1 is_def=true release_date = parsed_data.get('release_date', '')
417
+ block_count=4 cstruct_size=1 is_def=true if not ram:
418
+ block_count=5 cstruct_size=1 is_def=true ram = parsed_data.get('ram', '')
419
+ block_count=4 cstruct_size=1 is_def=true if not ssd:
420
+ block_count=5 cstruct_size=1 is_def=true ssd = parsed_data.get('ssd', '')
421
+ block_count=3 cstruct_size=1 is_def=true if store is None:
422
+ block_count=4 cstruct_size=1 is_def=true store = kwargs.get('store')
423
+ compo c_name=kwargs
424
+ block_count=3 cstruct_size=1 is_def=true if price is None:
425
+ block_count=4 cstruct_size=1 is_def=true price = kwargs.get('price')
426
+ compo c_name=kwargs
427
+ block_count=3 cstruct_size=1 is_def=true if not model_number:
428
+ block_count=4 cstruct_size=1 is_def=true model_number = kwargs.get('model_number', '')
429
+ compo c_name=kwargs
430
+ block_count=3 cstruct_size=1 is_def=true if not release_date:
431
+ block_count=4 cstruct_size=1 is_def=true release_date = kwargs.get('release_date', '')
432
+ compo c_name=kwargs
433
+ block_count=3 cstruct_size=1 is_def=true if not ram:
434
+ block_count=4 cstruct_size=1 is_def=true ram = kwargs.get('ram', '')
435
+ compo c_name=kwargs
436
+ block_count=3 cstruct_size=1 is_def=true if not ssd:
437
+ block_count=4 cstruct_size=1 is_def=true ssd = kwargs.get('ssd', '')
438
+ compo c_name=kwargs
439
+ block_count=3 cstruct_size=1 is_def=true if not name or not store or not price:
440
+ block_count=4 cstruct_size=1 is_def=true return (
441
+ block_count=5 cstruct_size=1 is_def=true f'Error: Required arguments missing. Name: {name}, Store: {store}, Price: {price}'
442
+ block_count=5 cstruct_size=1 is_def=true )
443
+ block_count=3 cstruct_size=1 is_def=true if not url or not description:
444
+ block_count=4 cstruct_size=1 is_def=true return (
445
+ block_count=5 cstruct_size=1 is_def=true f"Skipped saving product '{name}': URL or description is missing. URL: '{url}', Description: '{description}'"
446
+ block_count=5 cstruct_size=1 is_def=true )
447
+ block_count=3 cstruct_size=1 is_def=true if not url.startswith('http://') and not url.startswith('https://'
448
+ compo c_name=url
449
+ block_count=4 cstruct_size=1 is_def=true ):
450
+ block_count=4 cstruct_size=1 is_def=true return (
451
+ block_count=5 cstruct_size=1 is_def=true f"Skipped saving product '{name}': URL must start with 'http://' or 'https://'. URL: '{url}'"
452
+ block_count=5 cstruct_size=1 is_def=true )
453
+ block_count=3 cstruct_size=1 is_def=true if isinstance(price, (int, float)):
454
+ block_count=4 cstruct_size=1 is_def=true price = str(price)
455
+ block_count=3 cstruct_size=1 is_def=true price_val = parse_price_val(price)
456
+ block_count=3 cstruct_size=1 is_def=true if price_val == float('inf'):
457
+ block_count=4 cstruct_size=1 is_def=true if not re.search('\\d', str(price)):
458
+ compo c_name=re
459
+ block_count=5 cstruct_size=1 is_def=true return (
460
+ block_count=6 cstruct_size=1 is_def=true f"Skipped saving product '{name}': Price info is missing or invalid ('{price}')."
461
+ block_count=6 cstruct_size=1 is_def=true )
462
+ block_count=3 cstruct_size=1 is_def=true conn = sqlite3.connect(DB_NAME)
463
+ compo c_name=sqlite3
464
+ block_count=3 cstruct_size=1 is_def=true cursor = conn.cursor()
465
+ compo c_name=conn
466
+ block_count=3 cstruct_size=1 is_def=true cursor.execute(
467
+ compo c_name=cursor
468
+ block_count=4 cstruct_size=1 is_def=true 'SELECT id, store, price, url FROM products WHERE name = ?',
469
+ block_count=4 cstruct_size=1 is_def=true (name,))
470
+ block_count=3 cstruct_size=1 is_def=true rows = cursor.fetchall()
471
+ compo c_name=cursor
472
+ block_count=3 cstruct_size=1 is_def=true items = []
473
+ block_count=3 cstruct_size=1 is_def=true for r in rows:
474
+ block_count=4 cstruct_size=1 is_def=true items.append({'id': r[0], 'store': r[1], 'price_str': r[2],
475
+ compo c_name=items
476
+ block_count=5 cstruct_size=1 is_def=true 'price_val': parse_price_val(r[2]), 'url': r[3]})
477
+ block_count=3 cstruct_size=1 is_def=true new_price_val = parse_price_val(price)
478
+ block_count=3 cstruct_size=1 is_def=true msg = ''
479
+ block_count=3 cstruct_size=1 is_def=true items.sort(key=lambda x: x['price_val'])
480
+ compo c_name=items
481
+ block_count=3 cstruct_size=1 is_def=true current_cheapest = items[0] if items else None
482
+ block_count=3 cstruct_size=1 is_def=true should_save = False
483
+ block_count=3 cstruct_size=1 is_def=true should_update = False
484
+ block_count=3 cstruct_size=1 is_def=true if not current_cheapest:
485
+ block_count=4 cstruct_size=1 is_def=true should_save = True
486
+ block_count=3 cstruct_size=1 is_def=true elif new_price_val < current_cheapest['price_val']:
487
+ block_count=4 cstruct_size=1 is_def=true should_save = True
488
+ block_count=4 cstruct_size=1 is_def=true cursor.execute('DELETE FROM products WHERE name = ?', (name,))
489
+ compo c_name=cursor
490
+ block_count=4 cstruct_size=1 is_def=true msg_prefix = (
491
+ block_count=5 cstruct_size=1 is_def=true f"Found cheaper price! Updated {name} from {current_cheapest['store']} ({current_cheapest['price_str']}) to {store} ({price})."
492
+ block_count=5 cstruct_size=1 is_def=true )
493
+ block_count=3 cstruct_size=1 is_def=true elif new_price_val == current_cheapest['price_val']:
494
+ block_count=4 cstruct_size=1 is_def=true if store == current_cheapest['store']:
495
+ block_count=5 cstruct_size=1 is_def=true should_update = True
496
+ block_count=5 cstruct_size=1 is_def=true msg_prefix = f'Updated info for {name} at {store}.'
497
+ block_count=4 cstruct_size=1 is_def=true else:
498
+ block_count=5 cstruct_size=1 is_def=true msg = (
499
+ block_count=6 cstruct_size=1 is_def=true f"Product {name} exists with same price at {current_cheapest['store']}. Keeping existing."
500
+ block_count=6 cstruct_size=1 is_def=true )
501
+ block_count=3 cstruct_size=1 is_def=true elif store == current_cheapest['store']:
502
+ block_count=4 cstruct_size=1 is_def=true should_update = True
503
+ block_count=4 cstruct_size=1 is_def=true msg_prefix = (
504
+ block_count=5 cstruct_size=1 is_def=true f"Price increased for {name} at {store}: {current_cheapest['price_str']} -> {price}."
505
+ block_count=5 cstruct_size=1 is_def=true )
506
+ block_count=3 cstruct_size=1 is_def=true else:
507
+ block_count=4 cstruct_size=1 is_def=true msg = (
508
+ block_count=5 cstruct_size=1 is_def=true f"Product {name} exists cheaper at {current_cheapest['store']} ({current_cheapest['price_str']}). Ignoring {store} ({price})."
509
+ block_count=5 cstruct_size=1 is_def=true )
510
+ block_count=3 cstruct_size=1 is_def=true if should_save:
511
+ block_count=4 cstruct_size=1 is_def=true cursor.execute(
512
+ compo c_name=cursor
513
+ block_count=5 cstruct_size=1 is_def=true """
514
+ block_count=5 cstruct_size=1 is_def=true , (name, store, price, url, description, model_number,
515
+ block_count=5 cstruct_size=1 is_def=true release_date, ram, ssd))
516
+ block_count=4 cstruct_size=1 is_def=true if not msg:
517
+ block_count=5 cstruct_size=1 is_def=true msg = f'Saved product: {name} from {store} for {price}.'
518
+ block_count=4 cstruct_size=1 is_def=true else:
519
+ block_count=5 cstruct_size=1 is_def=true msg = msg_prefix
520
+ block_count=4 cstruct_size=1 is_def=true email_subject = f'Product Saved: {name}'
521
+ block_count=4 cstruct_size=1 is_def=true email_body = f"""Action: Saved (New or Cheaper)
522
+ block_count=4 cstruct_size=1 is_def=true send_email_notification(email_subject, email_body)
523
+ block_count=3 cstruct_size=1 is_def=true if should_update:
524
+ block_count=4 cstruct_size=1 is_def=true cursor.execute(
525
+ compo c_name=cursor
526
+ block_count=5 cstruct_size=1 is_def=true 'SELECT price, url, description, model_number, release_date, ram, ssd FROM products WHERE id = ?'
527
+ block_count=5 cstruct_size=1 is_def=true , (current_cheapest['id'],))
528
+ block_count=4 cstruct_size=1 is_def=true curr_row = cursor.fetchone()
529
+ compo c_name=cursor
530
+ block_count=4 cstruct_size=1 is_def=true curr_price_str = curr_row[0]
531
+ block_count=4 cstruct_size=1 is_def=true curr_url = curr_row[1]
532
+ block_count=4 cstruct_size=1 is_def=true curr_desc = curr_row[2]
533
+ block_count=4 cstruct_size=1 is_def=true curr_model = curr_row[3]
534
+ block_count=4 cstruct_size=1 is_def=true curr_release = curr_row[4]
535
+ block_count=4 cstruct_size=1 is_def=true curr_ram = curr_row[5] if len(curr_row) > 5 else ''
536
+ block_count=4 cstruct_size=1 is_def=true curr_ssd = curr_row[6] if len(curr_row) > 6 else ''
537
+ block_count=4 cstruct_size=1 is_def=true final_model = model_number if model_number else curr_model
538
+ block_count=4 cstruct_size=1 is_def=true final_release = release_date if release_date else curr_release
539
+ block_count=4 cstruct_size=1 is_def=true final_ram = ram if ram else curr_ram
540
+ block_count=4 cstruct_size=1 is_def=true final_ssd = ssd if ssd else curr_ssd
541
+ block_count=4 cstruct_size=1 is_def=true if (price != curr_price_str or url != curr_url or
542
+ block_count=5 cstruct_size=1 is_def=true description != curr_desc or final_model != curr_model or
543
+ block_count=5 cstruct_size=1 is_def=true final_release != curr_release or final_ram != curr_ram or
544
+ block_count=5 cstruct_size=1 is_def=true final_ssd != curr_ssd):
545
+ block_count=5 cstruct_size=1 is_def=true cursor.execute(
546
+ compo c_name=cursor
547
+ block_count=6 cstruct_size=1 is_def=true """
548
+ block_count=6 cstruct_size=1 is_def=true , (price, url, description, final_model,
549
+ block_count=6 cstruct_size=1 is_def=true final_release, final_ram, final_ssd, store,
550
+ block_count=6 cstruct_size=1 is_def=true current_cheapest['id']))
551
+ block_count=5 cstruct_size=1 is_def=true if not msg:
552
+ block_count=6 cstruct_size=1 is_def=true msg = f'Updated product {name} info.'
553
+ block_count=5 cstruct_size=1 is_def=true else:
554
+ block_count=6 cstruct_size=1 is_def=true msg = msg_prefix
555
+ block_count=5 cstruct_size=1 is_def=true email_subject = f'Product Updated: {name}'
556
+ block_count=5 cstruct_size=1 is_def=true email_body = f"""Action: Updated Info
557
+ block_count=5 cstruct_size=1 is_def=true send_email_notification(email_subject, email_body)
558
+ block_count=4 cstruct_size=1 is_def=true else:
559
+ block_count=5 cstruct_size=1 is_def=true msg = f'No changes for {name} at {store}.'
560
+ block_count=3 cstruct_size=1 is_def=true if should_save or should_update:
561
+ block_count=4 cstruct_size=1 is_def=true cursor.execute('SELECT id, price FROM products WHERE name = ?',
562
+ compo c_name=cursor
563
+ block_count=5 cstruct_size=1 is_def=true (name,))
564
+ block_count=4 cstruct_size=1 is_def=true rows = cursor.fetchall()
565
+ compo c_name=cursor
566
+ block_count=4 cstruct_size=1 is_def=true if len(rows) > 1:
567
+ block_count=5 cstruct_size=1 is_def=true rows_parsed = []
568
+ block_count=5 cstruct_size=1 is_def=true for r in rows:
569
+ block_count=6 cstruct_size=1 is_def=true rows_parsed.append({'id': r[0], 'val':
570
+ block_count=7 cstruct_size=1 is_def=true parse_price_val(r[1])})
571
+ block_count=5 cstruct_size=1 is_def=true rows_parsed.sort(key=lambda x: x['val'])
572
+ block_count=5 cstruct_size=1 is_def=true winner = rows_parsed[0]
573
+ block_count=5 cstruct_size=1 is_def=true for loser in rows_parsed[1:]:
574
+ block_count=6 cstruct_size=1 is_def=true cursor.execute('DELETE FROM products WHERE id = ?',
575
+ compo c_name=cursor
576
+ block_count=7 cstruct_size=1 is_def=true (loser['id'],))
577
+ block_count=5 cstruct_size=1 is_def=true msg += ' (Cleaned up duplicate records)'
578
+ block_count=3 cstruct_size=1 is_def=true conn.commit()
579
+ compo c_name=conn
580
+ block_count=3 cstruct_size=1 is_def=true conn.close()
581
+ compo c_name=conn
582
+ block_count=3 cstruct_size=1 is_def=true return msg
583
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
584
+ block_count=3 cstruct_size=1 is_def=true return f'Error saving product: {str(e)}'
585
+ block_count=0 cstruct_size=1 is_def=true class UpdatePricesInput(BaseModel):
586
+ end of agent.SaveProductTool
587
+ class_name=agent.UpdatePricesInput
588
+ base_name=BaseModel
589
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description='Optional query', default='')
590
+ compo c_name=Field
591
+ block_count=0 cstruct_size=1 is_def=false class UpdatePricesTool(BaseTool):
592
+ end of agent.UpdatePricesInput
593
+ class_name=agent.UpdatePricesTool
594
+ base_name=BaseTool
595
+ block_count=1 cstruct_size=1 is_def=false name = 'update_prices'
596
+ block_count=1 cstruct_size=1 is_def=false description = (
597
+ block_count=2 cstruct_size=1 is_def=false 'Accesses the registered URL for each product in the database directly to check stock, price, and specs. Updates info or deletes if unavailable.'
598
+ block_count=2 cstruct_size=1 is_def=false )
599
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = UpdatePricesInput
600
+ block_count=1 cstruct_size=1 is_def=false def _fetch_page_content(self, url: str) ->(bool, str, str):
601
+ block_count=2 cstruct_size=1 is_def=true """
602
+ block_count=2 cstruct_size=1 is_def=true if not url or not url.startswith('http'):
603
+ compo c_name=url
604
+ block_count=3 cstruct_size=1 is_def=true return False, 'Invalid URL', ''
605
+ block_count=2 cstruct_size=1 is_def=true try:
606
+ block_count=3 cstruct_size=1 is_def=true req = urllib.request.Request(url, headers={'User-Agent':
607
+ compo c_name=urllib
608
+ compo c_name=Request
609
+ block_count=4 cstruct_size=1 is_def=true 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
610
+ block_count=4 cstruct_size=1 is_def=true , 'Accept-Language': 'ja,en-US;q=0.9,en;q=0.8'})
611
+ block_count=3 cstruct_size=1 is_def=true with urllib.request.urlopen(req, timeout=15) as response:
612
+ compo c_name=urllib
613
+ block_count=4 cstruct_size=1 is_def=true html_content = response.read().decode('utf-8', errors='ignore')
614
+ compo c_name=response
615
+ block_count=4 cstruct_size=1 is_def=true bot_keywords = ['ロボットではありません', 'アクセスが制限されています', 'キャプチャ',
616
+ block_count=5 cstruct_size=1 is_def=true 'CAPTCHA', 'Are you a human?',
617
+ block_count=5 cstruct_size=1 is_def=true 'Please verify you are a human', 'Incapsula', 'Cloudflare']
618
+ block_count=4 cstruct_size=1 is_def=true html_lower = html_content.lower()
619
+ block_count=4 cstruct_size=1 is_def=true for kw in bot_keywords:
620
+ block_count=5 cstruct_size=1 is_def=true if kw.lower() in html_lower:
621
+ compo c_name=kw
622
+ block_count=6 cstruct_size=1 is_def=true return False, 'Bot Challenge Detected', ''
623
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<script.*?>.*?</script>', '',
624
+ compo c_name=re
625
+ block_count=5 cstruct_size=1 is_def=true html_content, flags=re.DOTALL | re.IGNORECASE)
626
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<style.*?>.*?</style>', '', clean_text,
627
+ compo c_name=re
628
+ block_count=5 cstruct_size=1 is_def=true flags=re.DOTALL | re.IGNORECASE)
629
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<img[^>]+alt="([^"]*)"[^>]*>', ' \\1 ',
630
+ compo c_name=re
631
+ block_count=5 cstruct_size=1 is_def=true clean_text, flags=re.IGNORECASE)
632
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub("<img[^>]+alt='([^']*)'[^>]*>", ' \\1 ',
633
+ compo c_name=re
634
+ block_count=5 cstruct_size=1 is_def=true clean_text, flags=re.IGNORECASE)
635
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<.*?>', ' ', clean_text)
636
+ compo c_name=re
637
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('\\s+', ' ', clean_text).strip()
638
+ compo c_name=re
639
+ block_count=4 cstruct_size=1 is_def=true if len(clean_text) > 10000:
640
+ block_count=5 cstruct_size=1 is_def=true clean_text = clean_text[:10000]
641
+ block_count=4 cstruct_size=1 is_def=true return True, 'Success', clean_text
642
+ block_count=2 cstruct_size=1 is_def=true except urllib.error.HTTPError as e:
643
+ compo c_name=urllib
644
+ block_count=3 cstruct_size=1 is_def=true if e.code == 404:
645
+ block_count=4 cstruct_size=1 is_def=true return False, '404 Not Found', ''
646
+ block_count=3 cstruct_size=1 is_def=true elif e.code == 410:
647
+ block_count=4 cstruct_size=1 is_def=true return False, '410 Gone', ''
648
+ block_count=3 cstruct_size=1 is_def=true elif e.code in [500, 502, 503, 504]:
649
+ block_count=4 cstruct_size=1 is_def=true return False, f'Retryable Server Error ({e.code})', ''
650
+ block_count=3 cstruct_size=1 is_def=true elif e.code == 403:
651
+ block_count=4 cstruct_size=1 is_def=true return False, '403 Forbidden (Possible Bot Block)', ''
652
+ block_count=3 cstruct_size=1 is_def=true else:
653
+ block_count=4 cstruct_size=1 is_def=true return False, f'HTTP Error {e.code}', ''
654
+ block_count=2 cstruct_size=1 is_def=true except urllib.error.URLError as e:
655
+ compo c_name=urllib
656
+ block_count=3 cstruct_size=1 is_def=true return False, f'URL Error: {e.reason}', ''
657
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
658
+ block_count=3 cstruct_size=1 is_def=true return False, f'Connection Error: {e}', ''
659
+ block_count=1 cstruct_size=1 is_def=true def _delete_product(self, product: dict, reason: str):
660
+ block_count=2 cstruct_size=1 is_def=true try:
661
+ block_count=3 cstruct_size=1 is_def=true conn = sqlite3.connect(DB_NAME)
662
+ compo c_name=sqlite3
663
+ block_count=3 cstruct_size=1 is_def=true cursor = conn.cursor()
664
+ compo c_name=conn
665
+ block_count=3 cstruct_size=1 is_def=true cursor.execute('DELETE FROM products WHERE id = ?', (product[
666
+ compo c_name=cursor
667
+ block_count=4 cstruct_size=1 is_def=true 'id'],))
668
+ block_count=3 cstruct_size=1 is_def=true conn.commit()
669
+ compo c_name=conn
670
+ block_count=3 cstruct_size=1 is_def=true conn.close()
671
+ compo c_name=conn
672
+ block_count=3 cstruct_size=1 is_def=true msg = f"Deleted {product['name']} at {product['store']} ({reason})"
673
+ block_count=3 cstruct_size=1 is_def=true print(f' {msg}')
674
+ block_count=3 cstruct_size=1 is_def=true email_subject = f"Product Deleted: {product['name']}"
675
+ block_count=3 cstruct_size=1 is_def=true email_body = f"""Action: Deleted (Unavailable/Not Found)
676
+ block_count=3 cstruct_size=1 is_def=true send_email_notification(email_subject, email_body)
677
+ block_count=3 cstruct_size=1 is_def=true return True
678
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
679
+ block_count=3 cstruct_size=1 is_def=true print(f' Error deleting product: {e}')
680
+ block_count=3 cstruct_size=1 is_def=true return False
681
+ block_count=1 cstruct_size=1 is_def=true def _run(self, query: str='', **kwargs):
682
+ block_count=2 cstruct_size=1 is_def=true print('\n--- Starting Price Update (Direct URL Access) ---')
683
+ block_count=2 cstruct_size=1 is_def=true products = get_all_products()
684
+ block_count=2 cstruct_size=1 is_def=true if not products:
685
+ block_count=3 cstruct_size=1 is_def=true return 'No products in database to update.'
686
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
687
+ compo c_name=os
688
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0)
689
+ compo c_name=ChatGoogleGenerativeAI
690
+ block_count=2 cstruct_size=1 is_def=true updated_count = 0
691
+ block_count=2 cstruct_size=1 is_def=true deleted_count = 0
692
+ block_count=2 cstruct_size=1 is_def=true for p in products:
693
+ block_count=3 cstruct_size=1 is_def=true name = p['name']
694
+ block_count=3 cstruct_size=1 is_def=true store = p['store']
695
+ block_count=3 cstruct_size=1 is_def=true url = p['url']
696
+ block_count=3 cstruct_size=1 is_def=true print(f"Checking: {name} at {store} (ID: {p['id']})")
697
+ block_count=3 cstruct_size=1 is_def=true if not url:
698
+ block_count=4 cstruct_size=1 is_def=true print(f' [Warning] No URL for this product. Skipping.')
699
+ block_count=4 cstruct_size=1 is_def=true continue
700
+ block_count=3 cstruct_size=1 is_def=true success, access_reason, page_text = self._fetch_page_content(url)
701
+ block_count=3 cstruct_size=1 is_def=true if not success:
702
+ block_count=4 cstruct_size=1 is_def=true if ('404 Not Found' in access_reason or '410 Gone' in
703
+ block_count=5 cstruct_size=1 is_def=true access_reason or 'Invalid URL' in access_reason):
704
+ block_count=5 cstruct_size=1 is_def=true print(
705
+ block_count=6 cstruct_size=1 is_def=true f' [Info] URL is dead ({access_reason}). Deleting product.'
706
+ block_count=6 cstruct_size=1 is_def=true )
707
+ block_count=5 cstruct_size=1 is_def=true if self._delete_product(p, access_reason):
708
+ block_count=6 cstruct_size=1 is_def=true deleted_count += 1
709
+ block_count=4 cstruct_size=1 is_def=true else:
710
+ block_count=5 cstruct_size=1 is_def=true print(
711
+ block_count=6 cstruct_size=1 is_def=true f' [Warning] Skipping update due to temporary/access error: {access_reason}'
712
+ block_count=6 cstruct_size=1 is_def=true )
713
+ block_count=4 cstruct_size=1 is_def=true continue
714
+ block_count=3 cstruct_size=1 is_def=true prompt = f"""
715
+ block_count=3 cstruct_size=1 is_def=true try:
716
+ block_count=4 cstruct_size=1 is_def=true response = llm.invoke(prompt)
717
+ compo c_name=llm
718
+ block_count=4 cstruct_size=1 is_def=true content = response.content
719
+ compo c_name=response
720
+ block_count=4 cstruct_size=1 is_def=true if '```json' in content:
721
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
722
+ compo c_name=content
723
+ block_count=4 cstruct_size=1 is_def=true elif '```' in content:
724
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
725
+ compo c_name=content
726
+ block_count=4 cstruct_size=1 is_def=true content = content.strip()
727
+ compo c_name=content
728
+ block_count=4 cstruct_size=1 is_def=true content = re.sub('\\\\(?![/"\\\\bfnrtu])', '\\\\\\\\', content)
729
+ compo c_name=re
730
+ block_count=4 cstruct_size=1 is_def=true try:
731
+ block_count=5 cstruct_size=1 is_def=true result_data = json.loads(content, strict=False)
732
+ compo c_name=json
733
+ block_count=4 cstruct_size=1 is_def=true except json.JSONDecodeError as e:
734
+ block_count=5 cstruct_size=1 is_def=true print(
735
+ block_count=6 cstruct_size=1 is_def=true f' [Warning] Failed to parse JSON: {e}. Attempting further cleanup.'
736
+ block_count=6 cstruct_size=1 is_def=true )
737
+ block_count=5 cstruct_size=1 is_def=true content = content.replace('\\', '')
738
+ compo c_name=content
739
+ block_count=5 cstruct_size=1 is_def=true result_data = json.loads(content, strict=False)
740
+ compo c_name=json
741
+ block_count=4 cstruct_size=1 is_def=true is_unavailable = result_data.get('is_unavailable', False)
742
+ block_count=4 cstruct_size=1 is_def=true unavailability_reason = result_data.get('unavailability_reason'
743
+ block_count=5 cstruct_size=1 is_def=true , 'ページ内に在庫なし・販売終了の記載あり')
744
+ block_count=4 cstruct_size=1 is_def=true if is_unavailable:
745
+ block_count=5 cstruct_size=1 is_def=true print(
746
+ block_count=6 cstruct_size=1 is_def=true f' [Info] LLM determined product is unavailable. Reason: {unavailability_reason}. Deleting product.'
747
+ block_count=6 cstruct_size=1 is_def=true )
748
+ block_count=5 cstruct_size=1 is_def=true if self._delete_product(p, unavailability_reason):
749
+ block_count=6 cstruct_size=1 is_def=true deleted_count += 1
750
+ block_count=4 cstruct_size=1 is_def=true else:
751
+ block_count=5 cstruct_size=1 is_def=true new_price = result_data.get('price', '')
752
+ block_count=5 cstruct_size=1 is_def=true new_desc = result_data.get('description', '')
753
+ block_count=5 cstruct_size=1 is_def=true new_model = result_data.get('model_number', '')
754
+ block_count=5 cstruct_size=1 is_def=true new_release = result_data.get('release_date', '')
755
+ block_count=5 cstruct_size=1 is_def=true new_ram = result_data.get('ram', '')
756
+ block_count=5 cstruct_size=1 is_def=true new_ssd = result_data.get('ssd', '')
757
+ block_count=5 cstruct_size=1 is_def=true if not new_price:
758
+ block_count=6 cstruct_size=1 is_def=true print(
759
+ block_count=7 cstruct_size=1 is_def=true f' [Warning] Could not extract price from page. Skipping update.'
760
+ block_count=7 cstruct_size=1 is_def=true )
761
+ block_count=6 cstruct_size=1 is_def=true continue
762
+ block_count=5 cstruct_size=1 is_def=true final_desc = new_desc if new_desc else p['description']
763
+ block_count=5 cstruct_size=1 is_def=true final_model = new_model if new_model else p.get(
764
+ block_count=6 cstruct_size=1 is_def=true 'model_number', '')
765
+ block_count=5 cstruct_size=1 is_def=true final_release = new_release if new_release else p.get(
766
+ block_count=6 cstruct_size=1 is_def=true 'release_date', '')
767
+ block_count=5 cstruct_size=1 is_def=true final_ram = new_ram if new_ram else p.get('ram', '')
768
+ block_count=5 cstruct_size=1 is_def=true final_ssd = new_ssd if new_ssd else p.get('ssd', '')
769
+ block_count=5 cstruct_size=1 is_def=true changes = []
770
+ block_count=5 cstruct_size=1 is_def=true new_price_val = parse_price_val(new_price)
771
+ block_count=5 cstruct_size=1 is_def=true old_price_val = parse_price_val(p['price'])
772
+ block_count=5 cstruct_size=1 is_def=true if new_price_val != old_price_val:
773
+ block_count=6 cstruct_size=1 is_def=true changes.append(f"Price ({p['price']} -> {new_price})")
774
+ compo c_name=changes
775
+ block_count=5 cstruct_size=1 is_def=true else:
776
+ block_count=6 cstruct_size=1 is_def=true new_price = p['price']
777
+ block_count=5 cstruct_size=1 is_def=true old_model = p.get('model_number', '')
778
+ block_count=5 cstruct_size=1 is_def=true if not is_similar_model(final_model, old_model):
779
+ block_count=6 cstruct_size=1 is_def=true changes.append(f'Model ({old_model} -> {final_model})')
780
+ compo c_name=changes
781
+ block_count=5 cstruct_size=1 is_def=true else:
782
+ block_count=6 cstruct_size=1 is_def=true final_model = old_model
783
+ block_count=5 cstruct_size=1 is_def=true old_release = p.get('release_date', '')
784
+ block_count=5 cstruct_size=1 is_def=true if parse_date_val(final_release) != parse_date_val(
785
+ block_count=6 cstruct_size=1 is_def=true old_release):
786
+ block_count=6 cstruct_size=1 is_def=true changes.append(
787
+ compo c_name=changes
788
+ block_count=7 cstruct_size=1 is_def=true f'Release Date ({old_release} -> {final_release})')
789
+ block_count=5 cstruct_size=1 is_def=true else:
790
+ block_count=6 cstruct_size=1 is_def=true final_release = old_release
791
+ block_count=5 cstruct_size=1 is_def=true old_ram = p.get('ram', '')
792
+ block_count=5 cstruct_size=1 is_def=true if extract_alphanumeric(final_ram) != extract_alphanumeric(
793
+ block_count=6 cstruct_size=1 is_def=true old_ram):
794
+ block_count=6 cstruct_size=1 is_def=true changes.append(f'RAM ({old_ram} -> {final_ram})')
795
+ compo c_name=changes
796
+ block_count=5 cstruct_size=1 is_def=true else:
797
+ block_count=6 cstruct_size=1 is_def=true final_ram = old_ram
798
+ block_count=5 cstruct_size=1 is_def=true old_ssd = p.get('ssd', '')
799
+ block_count=5 cstruct_size=1 is_def=true if extract_alphanumeric(final_ssd) != extract_alphanumeric(
800
+ block_count=6 cstruct_size=1 is_def=true old_ssd):
801
+ block_count=6 cstruct_size=1 is_def=true changes.append(f'SSD ({old_ssd} -> {final_ssd})')
802
+ compo c_name=changes
803
+ block_count=5 cstruct_size=1 is_def=true else:
804
+ block_count=6 cstruct_size=1 is_def=true final_ssd = old_ssd
805
+ block_count=5 cstruct_size=1 is_def=true if changes:
806
+ block_count=6 cstruct_size=1 is_def=true try:
807
+ block_count=7 cstruct_size=1 is_def=true conn = sqlite3.connect(DB_NAME)
808
+ compo c_name=sqlite3
809
+ block_count=7 cstruct_size=1 is_def=true cursor = conn.cursor()
810
+ compo c_name=conn
811
+ block_count=7 cstruct_size=1 is_def=true cursor.execute(
812
+ compo c_name=cursor
813
+ block_count=8 cstruct_size=1 is_def=true """
814
+ block_count=8 cstruct_size=1 is_def=true , (new_price, final_desc, final_model,
815
+ block_count=8 cstruct_size=1 is_def=true final_release, final_ram, final_ssd, p['id']))
816
+ block_count=7 cstruct_size=1 is_def=true conn.commit()
817
+ compo c_name=conn
818
+ block_count=7 cstruct_size=1 is_def=true if cursor.rowcount > 0:
819
+ compo c_name=cursor
820
+ block_count=8 cstruct_size=1 is_def=true updated_count += 1
821
+ block_count=8 cstruct_size=1 is_def=true changes_str = ', '.join(changes)
822
+ block_count=8 cstruct_size=1 is_def=true msg = (
823
+ block_count=9 cstruct_size=1 is_def=true f'Updated {name} at {store}. Changes: {changes_str}'
824
+ block_count=9 cstruct_size=1 is_def=true )
825
+ block_count=8 cstruct_size=1 is_def=true print(f' {msg}')
826
+ block_count=8 cstruct_size=1 is_def=true email_subject = f'Product Updated: {name}'
827
+ block_count=8 cstruct_size=1 is_def=true email_body = f"""Action: Updated Info (Direct URL Check)
828
+ block_count=8 cstruct_size=1 is_def=true send_email_notification(email_subject,
829
+ block_count=9 cstruct_size=1 is_def=true email_body)
830
+ block_count=7 cstruct_size=1 is_def=true conn.close()
831
+ compo c_name=conn
832
+ block_count=6 cstruct_size=1 is_def=true except Exception as e:
833
+ block_count=7 cstruct_size=1 is_def=true print(f' Error updating {name} at {store}: {e}')
834
+ block_count=5 cstruct_size=1 is_def=true else:
835
+ block_count=6 cstruct_size=1 is_def=true print(f' No spec/price changes for {name} at {store}.'
836
+ block_count=7 cstruct_size=1 is_def=true )
837
+ block_count=3 cstruct_size=1 is_def=true except Exception as e:
838
+ block_count=4 cstruct_size=1 is_def=true print(f' Error processing LLM response for {name}: {e}')
839
+ block_count=3 cstruct_size=1 is_def=true time.sleep(1)
840
+ compo c_name=time
841
+ block_count=2 cstruct_size=1 is_def=true return (
842
+ block_count=3 cstruct_size=1 is_def=true f'Price update complete. Updated {updated_count} items, Deleted {deleted_count} unavailable items.'
843
+ block_count=3 cstruct_size=1 is_def=true )
844
+ block_count=0 cstruct_size=1 is_def=true class SearchProductsInput(BaseModel):
845
+ end of agent.UpdatePricesTool
846
+ class_name=agent.SearchProductsInput
847
+ base_name=BaseModel
848
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description=
849
+ compo c_name=Field
850
+ block_count=2 cstruct_size=1 is_def=false 'Natural language query to search products in the database')
851
+ block_count=0 cstruct_size=1 is_def=false class SearchProductsTool(BaseTool):
852
+ end of agent.SearchProductsInput
853
+ class_name=agent.SearchProductsTool
854
+ base_name=BaseTool
855
+ block_count=1 cstruct_size=1 is_def=false name = 'search_products'
856
+ block_count=1 cstruct_size=1 is_def=false description = (
857
+ block_count=2 cstruct_size=1 is_def=false "Searches for products in the database using natural language queries (e.g., 'cheapest products', 'items with 16GB memory')."
858
+ block_count=2 cstruct_size=1 is_def=false )
859
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = SearchProductsInput
860
+ block_count=1 cstruct_size=1 is_def=false def _run(self, query: str, **kwargs):
861
+ block_count=2 cstruct_size=1 is_def=true print(f'\n--- Searching Database: {query} ---')
862
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
863
+ compo c_name=os
864
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0)
865
+ compo c_name=ChatGoogleGenerativeAI
866
+ block_count=2 cstruct_size=1 is_def=true prompt = f"""
867
+ block_count=2 cstruct_size=1 is_def=true try:
868
+ block_count=3 cstruct_size=1 is_def=true response = llm.invoke(prompt)
869
+ compo c_name=llm
870
+ block_count=3 cstruct_size=1 is_def=true content = response.content.strip()
871
+ compo c_name=response
872
+ block_count=3 cstruct_size=1 is_def=true if '```json' in content:
873
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
874
+ compo c_name=content
875
+ block_count=3 cstruct_size=1 is_def=true elif '```' in content:
876
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
877
+ compo c_name=content
878
+ block_count=3 cstruct_size=1 is_def=true criteria = json.loads(content)
879
+ compo c_name=json
880
+ block_count=3 cstruct_size=1 is_def=true print(f' Search Criteria: {criteria}')
881
+ block_count=3 cstruct_size=1 is_def=true all_products = get_all_products()
882
+ block_count=3 cstruct_size=1 is_def=true filtered_products = []
883
+ block_count=3 cstruct_size=1 is_def=true keyword_groups = criteria.get('keyword_groups', [])
884
+ compo c_name=criteria
885
+ block_count=3 cstruct_size=1 is_def=true exclude_keywords = criteria.get('exclude_keywords', [])
886
+ compo c_name=criteria
887
+ block_count=3 cstruct_size=1 is_def=true empty_fields = criteria.get('empty_fields', [])
888
+ compo c_name=criteria
889
+ block_count=3 cstruct_size=1 is_def=true sort_by = criteria.get('sort_by')
890
+ compo c_name=criteria
891
+ block_count=3 cstruct_size=1 is_def=true max_p = criteria.get('max_price')
892
+ compo c_name=criteria
893
+ block_count=3 cstruct_size=1 is_def=true min_p = criteria.get('min_price')
894
+ compo c_name=criteria
895
+ block_count=3 cstruct_size=1 is_def=true for p in all_products:
896
+ block_count=4 cstruct_size=1 is_def=true text_to_search = (p['name'] + ' ' + (p['description'] or ''
897
+ block_count=5 cstruct_size=1 is_def=true ) + ' ' + (p['url'] or '')).lower()
898
+ block_count=4 cstruct_size=1 is_def=true if empty_fields:
899
+ block_count=5 cstruct_size=1 is_def=true is_empty_match = True
900
+ block_count=5 cstruct_size=1 is_def=true for field in empty_fields:
901
+ block_count=6 cstruct_size=1 is_def=true val = p.get(field)
902
+ block_count=6 cstruct_size=1 is_def=true if val and str(val).strip():
903
+ block_count=7 cstruct_size=1 is_def=true is_empty_match = False
904
+ block_count=7 cstruct_size=1 is_def=true break
905
+ block_count=5 cstruct_size=1 is_def=true if not is_empty_match:
906
+ block_count=6 cstruct_size=1 is_def=true continue
907
+ block_count=4 cstruct_size=1 is_def=true if exclude_keywords:
908
+ block_count=5 cstruct_size=1 is_def=true should_exclude = False
909
+ block_count=5 cstruct_size=1 is_def=true for k in exclude_keywords:
910
+ block_count=6 cstruct_size=1 is_def=true if k.lower() in text_to_search:
911
+ block_count=7 cstruct_size=1 is_def=true should_exclude = True
912
+ block_count=7 cstruct_size=1 is_def=true break
913
+ block_count=5 cstruct_size=1 is_def=true if should_exclude:
914
+ block_count=6 cstruct_size=1 is_def=true continue
915
+ block_count=4 cstruct_size=1 is_def=true if keyword_groups:
916
+ block_count=5 cstruct_size=1 is_def=true all_groups_match = True
917
+ block_count=5 cstruct_size=1 is_def=true for group in keyword_groups:
918
+ block_count=6 cstruct_size=1 is_def=true group_match = False
919
+ block_count=6 cstruct_size=1 is_def=true for k in group:
920
+ block_count=7 cstruct_size=1 is_def=true if k.lower() in text_to_search:
921
+ block_count=8 cstruct_size=1 is_def=true group_match = True
922
+ block_count=8 cstruct_size=1 is_def=true break
923
+ block_count=6 cstruct_size=1 is_def=true if not group_match:
924
+ block_count=7 cstruct_size=1 is_def=true all_groups_match = False
925
+ block_count=7 cstruct_size=1 is_def=true break
926
+ block_count=5 cstruct_size=1 is_def=true if not all_groups_match:
927
+ block_count=6 cstruct_size=1 is_def=true continue
928
+ block_count=4 cstruct_size=1 is_def=true price_val = parse_price_val(p['price'])
929
+ block_count=4 cstruct_size=1 is_def=true if max_p is not None and price_val > max_p:
930
+ block_count=5 cstruct_size=1 is_def=true continue
931
+ block_count=4 cstruct_size=1 is_def=true if min_p is not None and price_val < min_p:
932
+ block_count=5 cstruct_size=1 is_def=true continue
933
+ block_count=4 cstruct_size=1 is_def=true p['price_val'] = price_val
934
+ block_count=4 cstruct_size=1 is_def=true filtered_products.append(p)
935
+ block_count=3 cstruct_size=1 is_def=true if sort_by == 'price_asc':
936
+ block_count=4 cstruct_size=1 is_def=true filtered_products.sort(key=lambda x: x['price_val'])
937
+ block_count=3 cstruct_size=1 is_def=true elif sort_by == 'price_desc':
938
+ block_count=4 cstruct_size=1 is_def=true filtered_products.sort(key=lambda x: x['price_val'],
939
+ block_count=5 cstruct_size=1 is_def=true reverse=True)
940
+ block_count=3 cstruct_size=1 is_def=true if not filtered_products:
941
+ block_count=4 cstruct_size=1 is_def=true return 'No products found matching your criteria.'
942
+ block_count=3 cstruct_size=1 is_def=true result_str = f'Found {len(filtered_products)} products:\n'
943
+ block_count=3 cstruct_size=1 is_def=true for p in filtered_products[:10]:
944
+ block_count=4 cstruct_size=1 is_def=true result_str += (
945
+ block_count=5 cstruct_size=1 is_def=true f"- [ID: {p['id']}] {p['name']} ({p['price']}) @ {p['store']}\n"
946
+ block_count=5 cstruct_size=1 is_def=true )
947
+ block_count=4 cstruct_size=1 is_def=true if p['description']:
948
+ block_count=5 cstruct_size=1 is_def=true result_str += f" Desc: {p['description'][:100]}...\n"
949
+ block_count=4 cstruct_size=1 is_def=true if p['url']:
950
+ block_count=5 cstruct_size=1 is_def=true result_str += f" URL: {p['url']}\n"
951
+ block_count=4 cstruct_size=1 is_def=true result_str += '\n'
952
+ block_count=3 cstruct_size=1 is_def=true return result_str
953
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
954
+ block_count=3 cstruct_size=1 is_def=true return f'Error executing search: {e}'
955
+ block_count=0 cstruct_size=1 is_def=true class FindSimilarProductsInput(BaseModel):
956
+ end of agent.SearchProductsTool
957
+ class_name=agent.FindSimilarProductsInput
958
+ base_name=BaseModel
959
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description='Optional query', default='')
960
+ compo c_name=Field
961
+ block_count=0 cstruct_size=1 is_def=false class FindSimilarProductsTool(BaseTool):
962
+ end of agent.FindSimilarProductsInput
963
+ class_name=agent.FindSimilarProductsTool
964
+ base_name=BaseTool
965
+ block_count=1 cstruct_size=1 is_def=false name = 'find_similar_products'
966
+ block_count=1 cstruct_size=1 is_def=false description = (
967
+ block_count=2 cstruct_size=1 is_def=false 'Searches for similar products to those in the database and adds the best ones if found.'
968
+ block_count=2 cstruct_size=1 is_def=false )
969
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = FindSimilarProductsInput
970
+ block_count=1 cstruct_size=1 is_def=false agent_logs: str = ''
971
+ block_count=1 cstruct_size=1 is_def=false def _run(self, query: str='', **kwargs):
972
+ block_count=2 cstruct_size=1 is_def=true print('\n--- Starting Similar Product Search ---')
973
+ block_count=2 cstruct_size=1 is_def=true products = get_all_products()
974
+ block_count=2 cstruct_size=1 is_def=true if not products:
975
+ block_count=3 cstruct_size=1 is_def=true return 'No products in database to base search on.'
976
+ block_count=2 cstruct_size=1 is_def=true target_products = []
977
+ block_count=2 cstruct_size=1 is_def=true if query:
978
+ block_count=3 cstruct_size=1 is_def=true print(f'Filtering products with query: {query}')
979
+ block_count=3 cstruct_size=1 is_def=true query_lower = query.lower()
980
+ compo c_name=query
981
+ block_count=3 cstruct_size=1 is_def=true for p in products:
982
+ block_count=4 cstruct_size=1 is_def=true if query_lower in p['name'].lower() or p['description'
983
+ block_count=5 cstruct_size=1 is_def=true ] and query_lower in p['description'].lower():
984
+ block_count=5 cstruct_size=1 is_def=true target_products.append(p)
985
+ block_count=2 cstruct_size=1 is_def=true else:
986
+ block_count=3 cstruct_size=1 is_def=true target_products = products
987
+ block_count=2 cstruct_size=1 is_def=true if not target_products:
988
+ block_count=3 cstruct_size=1 is_def=true return f"No products found matching query '{query}'."
989
+ block_count=2 cstruct_size=1 is_def=true unique_products = {}
990
+ block_count=2 cstruct_size=1 is_def=true for p in target_products:
991
+ block_count=3 cstruct_size=1 is_def=true if p['name'] not in unique_products:
992
+ block_count=4 cstruct_size=1 is_def=true unique_products[p['name']] = p
993
+ block_count=2 cstruct_size=1 is_def=true target_names = list(unique_products.keys())
994
+ block_count=2 cstruct_size=1 is_def=true print(
995
+ block_count=3 cstruct_size=1 is_def=true f'Found {len(target_names)} target products to find similar items for.'
996
+ block_count=3 cstruct_size=1 is_def=true )
997
+ block_count=2 cstruct_size=1 is_def=true logs_context = ''
998
+ block_count=2 cstruct_size=1 is_def=true if self.agent_logs:
999
+ compo c_name=self
1000
+ block_count=3 cstruct_size=1 is_def=true logs_context = f'\n参考情報 (過去の検索履歴):\n{self.agent_logs}\n'
1001
+ block_count=2 cstruct_size=1 is_def=true search = get_search_tool_func()
1002
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
1003
+ compo c_name=os
1004
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0)
1005
+ compo c_name=ChatGoogleGenerativeAI
1006
+ block_count=2 cstruct_size=1 is_def=true save_tool = SaveProductTool()
1007
+ compo c_name=SaveProductTool
1008
+ block_count=2 cstruct_size=1 is_def=true cached_similar_items = []
1009
+ block_count=2 cstruct_size=1 is_def=true max_targets = 5
1010
+ block_count=2 cstruct_size=1 is_def=true if len(target_names) > max_targets:
1011
+ block_count=3 cstruct_size=1 is_def=true print(f'Limiting search to first {max_targets} products.')
1012
+ block_count=3 cstruct_size=1 is_def=true target_names = target_names[:max_targets]
1013
+ block_count=2 cstruct_size=1 is_def=true for name in target_names:
1014
+ block_count=3 cstruct_size=1 is_def=true product_data = unique_products[name]
1015
+ block_count=3 cstruct_size=1 is_def=true description = product_data.get('description', '')
1016
+ block_count=3 cstruct_size=1 is_def=true print(f'Searching for similar items to: {name}')
1017
+ block_count=3 cstruct_size=1 is_def=true search_query = f'{name} 類似商品 おすすめ 比較 スペック'
1018
+ block_count=3 cstruct_size=1 is_def=true try:
1019
+ block_count=4 cstruct_size=1 is_def=true search_results = search.run(search_query)
1020
+ compo c_name=search
1021
+ block_count=3 cstruct_size=1 is_def=true except Exception as e:
1022
+ block_count=4 cstruct_size=1 is_def=true print(f'Search failed for {name}: {e}')
1023
+ block_count=4 cstruct_size=1 is_def=true continue
1024
+ block_count=3 cstruct_size=1 is_def=true prompt = f"""
1025
+ block_count=3 cstruct_size=1 is_def=true try:
1026
+ block_count=4 cstruct_size=1 is_def=true response = llm.invoke(prompt)
1027
+ compo c_name=llm
1028
+ block_count=4 cstruct_size=1 is_def=true content = response.content
1029
+ compo c_name=response
1030
+ block_count=4 cstruct_size=1 is_def=true if '```json' in content:
1031
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
1032
+ compo c_name=content
1033
+ block_count=4 cstruct_size=1 is_def=true elif '```' in content:
1034
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
1035
+ compo c_name=content
1036
+ block_count=4 cstruct_size=1 is_def=true items = json.loads(content)
1037
+ compo c_name=json
1038
+ block_count=4 cstruct_size=1 is_def=true if isinstance(items, list):
1039
+ block_count=5 cstruct_size=1 is_def=true for item in items:
1040
+ block_count=6 cstruct_size=1 is_def=true if item.get('name') == name:
1041
+ compo c_name=item
1042
+ block_count=7 cstruct_size=1 is_def=true continue
1043
+ block_count=6 cstruct_size=1 is_def=true cached_similar_items.append(item)
1044
+ block_count=6 cstruct_size=1 is_def=true print(
1045
+ block_count=7 cstruct_size=1 is_def=true f" Cached: {item.get('name')} ({item.get('price')})"
1046
+ block_count=7 cstruct_size=1 is_def=true )
1047
+ block_count=3 cstruct_size=1 is_def=true except Exception as e:
1048
+ block_count=4 cstruct_size=1 is_def=true print(f'Error processing similar items for {name}: {e}')
1049
+ block_count=3 cstruct_size=1 is_def=true time.sleep(1)
1050
+ compo c_name=time
1051
+ block_count=2 cstruct_size=1 is_def=true if not cached_similar_items:
1052
+ block_count=3 cstruct_size=1 is_def=true return 'No similar products found.'
1053
+ block_count=2 cstruct_size=1 is_def=true print(
1054
+ block_count=3 cstruct_size=1 is_def=true f'\nCached {len(cached_similar_items)} items. Selecting top 3 recommendations...'
1055
+ block_count=3 cstruct_size=1 is_def=true )
1056
+ block_count=2 cstruct_size=1 is_def=true selection_prompt = f"""
1057
+ block_count=2 cstruct_size=1 is_def=true added_count = 0
1058
+ block_count=2 cstruct_size=1 is_def=true try:
1059
+ block_count=3 cstruct_size=1 is_def=true response = llm.invoke(selection_prompt)
1060
+ compo c_name=llm
1061
+ block_count=3 cstruct_size=1 is_def=true content = response.content
1062
+ compo c_name=response
1063
+ block_count=3 cstruct_size=1 is_def=true if '```json' in content:
1064
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
1065
+ compo c_name=content
1066
+ block_count=3 cstruct_size=1 is_def=true elif '```' in content:
1067
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
1068
+ compo c_name=content
1069
+ block_count=3 cstruct_size=1 is_def=true top_picks = json.loads(content)
1070
+ compo c_name=json
1071
+ block_count=3 cstruct_size=1 is_def=true if isinstance(top_picks, list):
1072
+ block_count=4 cstruct_size=1 is_def=true for item in top_picks:
1073
+ block_count=5 cstruct_size=1 is_def=true print(f" Saving recommendation: {item.get('name')}")
1074
+ block_count=5 cstruct_size=1 is_def=true res = save_tool._run(name=item.get('name'), store=item.
1075
+ block_count=6 cstruct_size=1 is_def=true get('store', 'Unknown'), price=item.get('price'),
1076
+ block_count=6 cstruct_size=1 is_def=true url=item.get('url', ''), description=item.get(
1077
+ block_count=6 cstruct_size=1 is_def=true 'description', ''), model_number=item.get(
1078
+ block_count=6 cstruct_size=1 is_def=true 'model_number', ''), release_date=item.get(
1079
+ block_count=6 cstruct_size=1 is_def=true 'release_date', ''))
1080
+ block_count=5 cstruct_size=1 is_def=true print(f' -> {res}')
1081
+ block_count=5 cstruct_size=1 is_def=true added_count += 1
1082
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
1083
+ block_count=3 cstruct_size=1 is_def=true return f'Error selecting top recommendations: {e}'
1084
+ block_count=2 cstruct_size=1 is_def=true return (
1085
+ block_count=3 cstruct_size=1 is_def=true f'Similar product search complete. Added {added_count} recommended items.'
1086
+ block_count=3 cstruct_size=1 is_def=true )
1087
+ block_count=0 cstruct_size=1 is_def=true class CompareProductsInput(BaseModel):
1088
+ end of agent.FindSimilarProductsTool
1089
+ class_name=agent.CompareProductsInput
1090
+ base_name=BaseModel
1091
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description=
1092
+ compo c_name=Field
1093
+ block_count=2 cstruct_size=1 is_def=false "Optional category or query to filter products for comparison (e.g., 'laptop', 'monitor')."
1094
+ block_count=2 cstruct_size=1 is_def=false , default='')
1095
+ block_count=0 cstruct_size=1 is_def=false class CompareProductsTool(BaseTool):
1096
+ end of agent.CompareProductsInput
1097
+ class_name=agent.CompareProductsTool
1098
+ base_name=BaseTool
1099
+ block_count=1 cstruct_size=1 is_def=false name = 'compare_products'
1100
+ block_count=1 cstruct_size=1 is_def=false description = (
1101
+ block_count=2 cstruct_size=1 is_def=false 'Generates a comparison table of products (e.g. RAM, SSD, Price) and ranks them by recommendation. Saves the result as JSON.'
1102
+ block_count=2 cstruct_size=1 is_def=false )
1103
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = CompareProductsInput
1104
+ block_count=1 cstruct_size=1 is_def=false def _run(self, query: str='', **kwargs):
1105
+ block_count=2 cstruct_size=1 is_def=true print(f'\n--- Generating Product Comparison: {query} ---')
1106
+ block_count=2 cstruct_size=1 is_def=true products = get_all_products()
1107
+ block_count=2 cstruct_size=1 is_def=true if not products:
1108
+ block_count=3 cstruct_size=1 is_def=true return 'No products found in database.'
1109
+ block_count=2 cstruct_size=1 is_def=true target_products = []
1110
+ block_count=2 cstruct_size=1 is_def=true if query:
1111
+ block_count=3 cstruct_size=1 is_def=true query_lower = query.lower()
1112
+ compo c_name=query
1113
+ block_count=3 cstruct_size=1 is_def=true for p in products:
1114
+ block_count=4 cstruct_size=1 is_def=true text = (p['name'] + ' ' + (p['description'] or '')).lower()
1115
+ block_count=4 cstruct_size=1 is_def=true if query_lower in text:
1116
+ block_count=5 cstruct_size=1 is_def=true target_products.append(p)
1117
+ block_count=2 cstruct_size=1 is_def=true else:
1118
+ block_count=3 cstruct_size=1 is_def=true target_products = products
1119
+ block_count=2 cstruct_size=1 is_def=true if not target_products:
1120
+ block_count=3 cstruct_size=1 is_def=true return f"No products found matching '{query}'."
1121
+ block_count=2 cstruct_size=1 is_def=true CHUNK_SIZE = 5
1122
+ block_count=2 cstruct_size=1 is_def=true print(
1123
+ block_count=3 cstruct_size=1 is_def=true f'Step 1: Extracting specs from {len(target_products)} products in chunks of {CHUNK_SIZE}...'
1124
+ block_count=3 cstruct_size=1 is_def=true )
1125
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
1126
+ compo c_name=os
1127
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0,
1128
+ compo c_name=ChatGoogleGenerativeAI
1129
+ block_count=3 cstruct_size=1 is_def=true max_output_tokens=8192)
1130
+ block_count=2 cstruct_size=1 is_def=true extracted_specs = []
1131
+ block_count=2 cstruct_size=1 is_def=true try:
1132
+ block_count=3 cstruct_size=1 is_def=true for i in range(0, len(target_products), CHUNK_SIZE):
1133
+ block_count=4 cstruct_size=1 is_def=true chunk = target_products[i:i + CHUNK_SIZE]
1134
+ block_count=4 cstruct_size=1 is_def=true print(
1135
+ block_count=5 cstruct_size=1 is_def=true f' Processing chunk {i // CHUNK_SIZE + 1} ({len(chunk)} items)...'
1136
+ block_count=5 cstruct_size=1 is_def=true )
1137
+ block_count=4 cstruct_size=1 is_def=true prompt_extract = f"""
1138
+ block_count=4 cstruct_size=1 is_def=true response = llm.invoke(prompt_extract)
1139
+ compo c_name=llm
1140
+ block_count=4 cstruct_size=1 is_def=true content = response.content
1141
+ compo c_name=response
1142
+ block_count=4 cstruct_size=1 is_def=true if '```json' in content:
1143
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
1144
+ compo c_name=content
1145
+ block_count=4 cstruct_size=1 is_def=true elif '```' in content:
1146
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
1147
+ compo c_name=content
1148
+ block_count=4 cstruct_size=1 is_def=true content = content.strip()
1149
+ compo c_name=content
1150
+ block_count=4 cstruct_size=1 is_def=true try:
1151
+ block_count=5 cstruct_size=1 is_def=true chunk_data = json.loads(content)
1152
+ compo c_name=json
1153
+ block_count=4 cstruct_size=1 is_def=true except json.JSONDecodeError as e:
1154
+ block_count=5 cstruct_size=1 is_def=true print(
1155
+ block_count=6 cstruct_size=1 is_def=true f' [Warning] Failed to parse JSON in chunk {i // CHUNK_SIZE + 1}. Attempting aggressive recovery.'
1156
+ block_count=6 cstruct_size=1 is_def=true )
1157
+ block_count=5 cstruct_size=1 is_def=true print(f' Error detail: {e}')
1158
+ block_count=5 cstruct_size=1 is_def=true try:
1159
+ block_count=6 cstruct_size=1 is_def=true start_idx = content.find('[')
1160
+ compo c_name=content
1161
+ block_count=6 cstruct_size=1 is_def=true if start_idx != -1:
1162
+ block_count=7 cstruct_size=1 is_def=true clean_content = content[start_idx:]
1163
+ block_count=7 cstruct_size=1 is_def=true if not clean_content.rstrip().endswith(']'):
1164
+ block_count=8 cstruct_size=1 is_def=true last_brace = clean_content.rfind('}')
1165
+ block_count=8 cstruct_size=1 is_def=true if last_brace != -1:
1166
+ block_count=9 cstruct_size=1 is_def=true clean_content = clean_content[:
1167
+ block_count=10 cstruct_size=1 is_def=true last_brace + 1] + ']'
1168
+ block_count=8 cstruct_size=1 is_def=true else:
1169
+ block_count=9 cstruct_size=1 is_def=true clean_content += ']'
1170
+ block_count=7 cstruct_size=1 is_def=true chunk_data = json.loads(clean_content)
1171
+ compo c_name=json
1172
+ block_count=6 cstruct_size=1 is_def=true else:
1173
+ block_count=7 cstruct_size=1 is_def=true raise ValueError('No JSON list found.')
1174
+ compo c_name=ValueError
1175
+ block_count=5 cstruct_size=1 is_def=true except Exception as e2:
1176
+ block_count=6 cstruct_size=1 is_def=true print(
1177
+ block_count=7 cstruct_size=1 is_def=true f' [Error] Could not recover JSON even after aggressive repair: {e2}'
1178
+ block_count=7 cstruct_size=1 is_def=true )
1179
+ block_count=6 cstruct_size=1 is_def=true continue
1180
+ block_count=4 cstruct_size=1 is_def=true if isinstance(chunk_data, list):
1181
+ block_count=5 cstruct_size=1 is_def=true extracted_specs.extend(chunk_data)
1182
+ block_count=4 cstruct_size=1 is_def=true time.sleep(1)
1183
+ compo c_name=time
1184
+ block_count=3 cstruct_size=1 is_def=true print(
1185
+ block_count=4 cstruct_size=1 is_def=true f'Step 2: Ranking {len(extracted_specs)} products based on extracted specs...'
1186
+ block_count=4 cstruct_size=1 is_def=true )
1187
+ block_count=3 cstruct_size=1 is_def=true prompt_rank = f"""
1188
+ block_count=3 cstruct_size=1 is_def=true response_rank = llm.invoke(prompt_rank)
1189
+ compo c_name=llm
1190
+ block_count=3 cstruct_size=1 is_def=true content_rank = response_rank.content
1191
+ block_count=3 cstruct_size=1 is_def=true if '```json' in content_rank:
1192
+ block_count=4 cstruct_size=1 is_def=true content_rank = content_rank.split('```json')[1].split('```')[0]
1193
+ block_count=3 cstruct_size=1 is_def=true elif '```' in content_rank:
1194
+ block_count=4 cstruct_size=1 is_def=true content_rank = content_rank.split('```')[1].split('```')[0]
1195
+ block_count=3 cstruct_size=1 is_def=true content_rank = content_rank.strip()
1196
+ block_count=3 cstruct_size=1 is_def=true try:
1197
+ block_count=4 cstruct_size=1 is_def=true ranking_data = json.loads(content_rank)
1198
+ compo c_name=json
1199
+ block_count=3 cstruct_size=1 is_def=true except json.JSONDecodeError as e:
1200
+ block_count=4 cstruct_size=1 is_def=true print(
1201
+ block_count=5 cstruct_size=1 is_def=true f' [Warning] Failed to parse ranking JSON. Error: {e}. Attempting recovery.'
1202
+ block_count=5 cstruct_size=1 is_def=true )
1203
+ block_count=4 cstruct_size=1 is_def=true start_idx = content_rank.find('[')
1204
+ block_count=4 cstruct_size=1 is_def=true if start_idx != -1:
1205
+ block_count=5 cstruct_size=1 is_def=true clean_content = content_rank[start_idx:]
1206
+ block_count=5 cstruct_size=1 is_def=true if not clean_content.rstrip().endswith(']'):
1207
+ block_count=6 cstruct_size=1 is_def=true last_brace = clean_content.rfind('}')
1208
+ block_count=6 cstruct_size=1 is_def=true if last_brace != -1:
1209
+ block_count=7 cstruct_size=1 is_def=true clean_content = clean_content[:last_brace + 1
1210
+ block_count=8 cstruct_size=1 is_def=true ] + ']'
1211
+ block_count=6 cstruct_size=1 is_def=true else:
1212
+ block_count=7 cstruct_size=1 is_def=true clean_content += ']'
1213
+ block_count=5 cstruct_size=1 is_def=true try:
1214
+ block_count=6 cstruct_size=1 is_def=true ranking_data = json.loads(clean_content)
1215
+ compo c_name=json
1216
+ block_count=5 cstruct_size=1 is_def=true except Exception as e2:
1217
+ block_count=6 cstruct_size=1 is_def=true print(
1218
+ block_count=7 cstruct_size=1 is_def=true f' [Error] Could not recover ranking JSON: {e2}'
1219
+ block_count=7 cstruct_size=1 is_def=true )
1220
+ block_count=6 cstruct_size=1 is_def=true return (
1221
+ block_count=7 cstruct_size=1 is_def=true 'Error generating comparison: Invalid JSON format returned by LLM.'
1222
+ block_count=7 cstruct_size=1 is_def=true )
1223
+ block_count=4 cstruct_size=1 is_def=true else:
1224
+ block_count=5 cstruct_size=1 is_def=true return (
1225
+ block_count=6 cstruct_size=1 is_def=true 'Error generating comparison: Invalid JSON format returned by LLM.'
1226
+ block_count=6 cstruct_size=1 is_def=true )
1227
+ block_count=3 cstruct_size=1 is_def=true spec_dict = {item['id']: item for item in extracted_specs}
1228
+ block_count=3 cstruct_size=1 is_def=true target_dict = {item['id']: item for item in target_products}
1229
+ block_count=3 cstruct_size=1 is_def=true final_comparison_data = []
1230
+ block_count=3 cstruct_size=1 is_def=true for rank_item in ranking_data:
1231
+ block_count=4 cstruct_size=1 is_def=true p_id = rank_item.get('id')
1232
+ block_count=4 cstruct_size=1 is_def=true if p_id in spec_dict:
1233
+ block_count=5 cstruct_size=1 is_def=true merged = spec_dict[p_id].copy()
1234
+ block_count=5 cstruct_size=1 is_def=true merged['rank'] = rank_item.get('rank')
1235
+ block_count=5 cstruct_size=1 is_def=true merged['note'] = rank_item.get('note', '')
1236
+ block_count=5 cstruct_size=1 is_def=true if p_id in target_dict:
1237
+ block_count=6 cstruct_size=1 is_def=true merged['updated_at'] = target_dict[p_id].get(
1238
+ block_count=7 cstruct_size=1 is_def=true 'updated_at', '')
1239
+ block_count=5 cstruct_size=1 is_def=true final_comparison_data.append(merged)
1240
+ block_count=3 cstruct_size=1 is_def=true final_comparison_data.sort(key=lambda x: x.get('rank', 9999))
1241
+ block_count=3 cstruct_size=1 is_def=true for item in final_comparison_data:
1242
+ block_count=4 cstruct_size=1 is_def=true if 'model_number' not in item or item['model_number'] is None:
1243
+ block_count=5 cstruct_size=1 is_def=true item['model_number'] = ''
1244
+ block_count=4 cstruct_size=1 is_def=true if 'release_date' not in item or item['release_date'] is None:
1245
+ block_count=5 cstruct_size=1 is_def=true item['release_date'] = ''
1246
+ block_count=3 cstruct_size=1 is_def=true from datetime import datetime
1247
+ block_count=3 cstruct_size=1 is_def=true output_data = {'updated_at': datetime.now().strftime(
1248
+ compo c_name=datetime
1249
+ block_count=4 cstruct_size=1 is_def=true '%Y-%m-%d %H:%M:%S'), 'products': final_comparison_data}
1250
+ block_count=3 cstruct_size=1 is_def=true output_file = 'product_comparison.json'
1251
+ block_count=3 cstruct_size=1 is_def=true with open(output_file, 'w', encoding='utf-8') as f:
1252
+ block_count=4 cstruct_size=1 is_def=true json.dump(output_data, f, ensure_ascii=False, indent=2)
1253
+ compo c_name=json
1254
+ block_count=3 cstruct_size=1 is_def=true return (
1255
+ block_count=4 cstruct_size=1 is_def=true f'Comparison table generated and saved to {output_file}. Included {len(final_comparison_data)} ranked items.'
1256
+ block_count=4 cstruct_size=1 is_def=true )
1257
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
1258
+ block_count=3 cstruct_size=1 is_def=true return f'Error generating comparison: {e}'
1259
+ block_count=0 cstruct_size=1 is_def=true def display_products():
1260
+ end of agent.CompareProductsTool
1261
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
1262
+ compo c_name=sqlite3
1263
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
1264
+ compo c_name=conn
1265
+ block_count=1 cstruct_size=0 is_def=true cursor.execute('SELECT id, name, store, price FROM products')
1266
+ compo c_name=cursor
1267
+ block_count=1 cstruct_size=0 is_def=true rows = cursor.fetchall()
1268
+ compo c_name=cursor
1269
+ block_count=1 cstruct_size=0 is_def=true conn.close()
1270
+ compo c_name=conn
1271
+ block_count=1 cstruct_size=0 is_def=true if not rows:
1272
+ block_count=2 cstruct_size=0 is_def=true print('\nNo products saved yet.')
1273
+ block_count=2 cstruct_size=0 is_def=true return
1274
+ block_count=1 cstruct_size=0 is_def=true def parse_price_sort(p_str):
1275
+ block_count=2 cstruct_size=0 is_def=true nums = re.findall('\\d+', str(p_str).replace(',', ''))
1276
+ compo c_name=re
1277
+ block_count=2 cstruct_size=0 is_def=true return int(''.join(nums)) if nums else float('inf')
1278
+ block_count=1 cstruct_size=0 is_def=true rows.sort(key=lambda x: (x[1], parse_price_sort(x[3])))
1279
+ compo c_name=rows
1280
+ block_count=1 cstruct_size=0 is_def=false print('\n--- All Saved Products ---')
1281
+ block_count=1 cstruct_size=0 is_def=false print(f"{'ID':<5} {'Name':<40} {'Store':<20} {'Price':<15}")
1282
+ block_count=1 cstruct_size=0 is_def=false print('-' * 85)
1283
+ block_count=1 cstruct_size=0 is_def=false for row in rows:
1284
+ block_count=2 cstruct_size=0 is_def=false name_disp = row[1][:37] + '..' if len(row[1]) > 39 else row[1]
1285
+ block_count=2 cstruct_size=0 is_def=false store_disp = row[2][:18] + '..' if len(row[2]) > 20 else row[2]
1286
+ block_count=2 cstruct_size=0 is_def=false print(f'{row[0]:<5} {name_disp:<40} {store_disp:<20} {row[3]:<15}')
1287
+ block_count=1 cstruct_size=0 is_def=false print('-' * 85)
1288
+ block_count=0 cstruct_size=0 is_def=false def show_product_details(product_id):
1289
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
1290
+ compo c_name=sqlite3
1291
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
1292
+ compo c_name=conn
1293
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
1294
+ compo c_name=cursor
1295
+ block_count=2 cstruct_size=0 is_def=true 'SELECT id, name, store, price, url, description, model_number, release_date FROM products WHERE id = ?'
1296
+ block_count=2 cstruct_size=0 is_def=true , (product_id,))
1297
+ block_count=1 cstruct_size=0 is_def=true row = cursor.fetchone()
1298
+ compo c_name=cursor
1299
+ block_count=1 cstruct_size=0 is_def=true conn.close()
1300
+ compo c_name=conn
1301
+ block_count=1 cstruct_size=0 is_def=true if not row:
1302
+ block_count=2 cstruct_size=0 is_def=true print(f'\nProduct with ID {product_id} not found.')
1303
+ block_count=2 cstruct_size=0 is_def=true return
1304
+ block_count=1 cstruct_size=0 is_def=true print('\n--- Product Details ---')
1305
+ block_count=1 cstruct_size=0 is_def=true print(f'ID: {row[0]}')
1306
+ block_count=1 cstruct_size=0 is_def=true print(f'Name: {row[1]}')
1307
+ block_count=1 cstruct_size=0 is_def=true print(f'Store: {row[2]}')
1308
+ block_count=1 cstruct_size=0 is_def=true print(f'Price: {row[3]}')
1309
+ block_count=1 cstruct_size=0 is_def=true print(f"Model: {row[6] if len(row) > 6 else ''}")
1310
+ block_count=1 cstruct_size=0 is_def=true print(f"Release: {row[7] if len(row) > 7 else ''}")
1311
+ block_count=1 cstruct_size=0 is_def=true print(f'URL: {row[4]}')
1312
+ block_count=1 cstruct_size=0 is_def=true print(f'Description: {row[5]}')
1313
+ block_count=1 cstruct_size=0 is_def=true print('-' * 30)
1314
+ block_count=0 cstruct_size=0 is_def=true def delete_product_records(identifiers: List[str]):
1315
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
1316
+ compo c_name=sqlite3
1317
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
1318
+ compo c_name=conn
1319
+ block_count=1 cstruct_size=0 is_def=true deleted_count = 0
1320
+ block_count=1 cstruct_size=0 is_def=true errors = []
1321
+ block_count=1 cstruct_size=0 is_def=true print(f'\nAttempting to delete: {identifiers}')
1322
+ block_count=1 cstruct_size=0 is_def=true for identifier in identifiers:
1323
+ block_count=2 cstruct_size=0 is_def=true try:
1324
+ block_count=3 cstruct_size=0 is_def=true if identifier.isdigit():
1325
+ compo c_name=identifier
1326
+ block_count=4 cstruct_size=0 is_def=true cursor.execute('DELETE FROM products WHERE id = ?', (int(
1327
+ compo c_name=cursor
1328
+ block_count=5 cstruct_size=0 is_def=true identifier),))
1329
+ block_count=3 cstruct_size=0 is_def=true else:
1330
+ block_count=4 cstruct_size=0 is_def=true cursor.execute('DELETE FROM products WHERE name = ?', (
1331
+ compo c_name=cursor
1332
+ block_count=5 cstruct_size=0 is_def=true identifier,))
1333
+ block_count=3 cstruct_size=0 is_def=true if cursor.rowcount > 0:
1334
+ compo c_name=cursor
1335
+ block_count=4 cstruct_size=0 is_def=true deleted_count += cursor.rowcount
1336
+ compo c_name=cursor
1337
+ block_count=4 cstruct_size=0 is_def=true print(f' Deleted: {identifier}')
1338
+ block_count=3 cstruct_size=0 is_def=true else:
1339
+ block_count=4 cstruct_size=0 is_def=true errors.append(f'No product found with ID/Name: {identifier}')
1340
+ compo c_name=errors
1341
+ block_count=2 cstruct_size=0 is_def=true except Exception as e:
1342
+ block_count=3 cstruct_size=0 is_def=true errors.append(f'Error deleting {identifier}: {e}')
1343
+ compo c_name=errors
1344
+ block_count=1 cstruct_size=0 is_def=true conn.commit()
1345
+ compo c_name=conn
1346
+ block_count=1 cstruct_size=0 is_def=true conn.close()
1347
+ compo c_name=conn
1348
+ block_count=1 cstruct_size=0 is_def=true print(f'\nTotal deleted: {deleted_count}')
1349
+ block_count=1 cstruct_size=0 is_def=true if errors:
1350
+ block_count=2 cstruct_size=0 is_def=true print('Errors/Warnings:')
1351
+ block_count=2 cstruct_size=0 is_def=true for err in errors:
1352
+ block_count=3 cstruct_size=0 is_def=true print(f' - {err}')
1353
+ block_count=0 cstruct_size=0 is_def=true def main():
1354
+ block_count=1 cstruct_size=0 is_def=true if not os.getenv('GOOGLE_API_KEY'):
1355
+ compo c_name=os
1356
+ block_count=2 cstruct_size=0 is_def=true print('Error: GOOGLE_API_KEY not found.')
1357
+ block_count=2 cstruct_size=0 is_def=true return
1358
+ block_count=1 cstruct_size=0 is_def=true provider = os.getenv('SEARCH_PROVIDER', 'serpapi')
1359
+ compo c_name=os
1360
+ block_count=1 cstruct_size=0 is_def=true if provider == 'serpapi' and not os.getenv('SERPAPI_API_KEY'):
1361
+ compo c_name=os
1362
+ block_count=2 cstruct_size=0 is_def=true print('Error: SERPAPI_API_KEY not found.')
1363
+ block_count=2 cstruct_size=0 is_def=true return
1364
+ block_count=1 cstruct_size=0 is_def=true elif provider == 'tavily_api' and not os.getenv('TAVILY_API_KEY'):
1365
+ compo c_name=os
1366
+ block_count=2 cstruct_size=0 is_def=true print('Error: TAVILY_API_KEY not found for Tavily search.')
1367
+ block_count=2 cstruct_size=0 is_def=true return
1368
+ block_count=1 cstruct_size=0 is_def=true elif provider == 'browser_use':
1369
+ block_count=2 cstruct_size=0 is_def=true pass
1370
+ block_count=1 cstruct_size=0 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
1371
+ compo c_name=os
1372
+ block_count=1 cstruct_size=0 is_def=true print(f'Using model: {model_name}')
1373
+ block_count=1 cstruct_size=0 is_def=true print(f'Using Search Provider: {provider}')
1374
+ block_count=1 cstruct_size=0 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0,
1375
+ compo c_name=ChatGoogleGenerativeAI
1376
+ block_count=2 cstruct_size=0 is_def=true max_retries=10)
1377
+ block_count=1 cstruct_size=0 is_def=true search = get_search_tool_func()
1378
+ block_count=1 cstruct_size=0 is_def=true search_tool = Tool(name='google_search', description=
1379
+ compo c_name=Tool
1380
+ block_count=2 cstruct_size=0 is_def=true 'Search Google for recent results.', func=search.run)
1381
+ block_count=1 cstruct_size=0 is_def=true startup_logs = get_all_agent_logs()
1382
+ block_count=1 cstruct_size=0 is_def=true print(f'Loaded {len(startup_logs)} characters of agent logs.')
1383
+ block_count=1 cstruct_size=0 is_def=true save_tool = SaveProductTool()
1384
+ compo c_name=SaveProductTool
1385
+ block_count=1 cstruct_size=0 is_def=true db_search_tool = SearchProductsTool()
1386
+ compo c_name=SearchProductsTool
1387
+ block_count=1 cstruct_size=0 is_def=true update_tool = UpdatePricesTool()
1388
+ compo c_name=UpdatePricesTool
1389
+ block_count=1 cstruct_size=0 is_def=true similar_tool = FindSimilarProductsTool(agent_logs=startup_logs)
1390
+ compo c_name=FindSimilarProductsTool
1391
+ block_count=1 cstruct_size=0 is_def=true compare_tool = CompareProductsTool()
1392
+ compo c_name=CompareProductsTool
1393
+ block_count=1 cstruct_size=0 is_def=true tools = [search_tool, save_tool, db_search_tool, update_tool,
1394
+ block_count=2 cstruct_size=0 is_def=true similar_tool, compare_tool]
1395
+ block_count=1 cstruct_size=0 is_def=true prompt = ChatPromptTemplate.from_messages([('system',
1396
+ compo c_name=ChatPromptTemplate
1397
+ block_count=2 cstruct_size=0 is_def=true """あなたは、商品の検索、保存、価格更新、類似商品検索、比較表作成を行う有能なアシスタントです。
1398
+ block_count=2 cstruct_size=0 is_def=true ), MessagesPlaceholder(variable_name='chat_history'), ('human',
1399
+ compo c_name=MessagesPlaceholder
1400
+ block_count=2 cstruct_size=0 is_def=true '{input}'), ('placeholder', '{agent_scratchpad}')])
1401
+ block_count=1 cstruct_size=0 is_def=true agent = create_tool_calling_agent(llm, tools, prompt)
1402
+ block_count=1 cstruct_size=0 is_def=true agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True,
1403
+ compo c_name=AgentExecutor
1404
+ block_count=2 cstruct_size=0 is_def=true return_intermediate_steps=True)
1405
+ block_count=1 cstruct_size=0 is_def=true print('Advanced AI Agent initialized.')
1406
+ block_count=1 cstruct_size=0 is_def=true print(
1407
+ block_count=2 cstruct_size=0 is_def=true "Commands: 'list', 'show <ID>', 'update', 'similar', 'delete <ID/Name> ...', 'quit'"
1408
+ block_count=2 cstruct_size=0 is_def=true )
1409
+ block_count=1 cstruct_size=0 is_def=true chat_history = []
1410
+ block_count=1 cstruct_size=0 is_def=true while True:
1411
+ block_count=2 cstruct_size=0 is_def=true try:
1412
+ block_count=3 cstruct_size=0 is_def=true try:
1413
+ block_count=4 cstruct_size=0 is_def=true user_input = input('\nEnter command or search query: ')
1414
+ block_count=3 cstruct_size=0 is_def=true except EOFError:
1415
+ block_count=4 cstruct_size=0 is_def=true print('\nEOF detected. Exiting...')
1416
+ block_count=4 cstruct_size=0 is_def=true break
1417
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() in ['quit', 'exit']:
1418
+ block_count=4 cstruct_size=0 is_def=true break
1419
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() == 'list':
1420
+ block_count=4 cstruct_size=0 is_def=true display_products()
1421
+ block_count=4 cstruct_size=0 is_def=true continue
1422
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() == 'update':
1423
+ block_count=4 cstruct_size=0 is_def=true result = update_tool._run()
1424
+ block_count=4 cstruct_size=0 is_def=true print(result)
1425
+ block_count=4 cstruct_size=0 is_def=true continue
1426
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() == 'similar':
1427
+ block_count=4 cstruct_size=0 is_def=true result = similar_tool._run()
1428
+ block_count=4 cstruct_size=0 is_def=true print(result)
1429
+ block_count=4 cstruct_size=0 is_def=true continue
1430
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('compare'):
1431
+ block_count=4 cstruct_size=0 is_def=true parts = user_input.split(maxsplit=1)
1432
+ block_count=4 cstruct_size=0 is_def=true query = parts[1] if len(parts) > 1 else ''
1433
+ block_count=4 cstruct_size=0 is_def=true result = compare_tool._run(query)
1434
+ block_count=4 cstruct_size=0 is_def=true print(result)
1435
+ block_count=4 cstruct_size=0 is_def=true continue
1436
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('search_products '):
1437
+ block_count=4 cstruct_size=0 is_def=true query = user_input[16:].strip()
1438
+ block_count=4 cstruct_size=0 is_def=true if query:
1439
+ block_count=5 cstruct_size=0 is_def=true result = db_search_tool._run(query)
1440
+ block_count=5 cstruct_size=0 is_def=true print(result)
1441
+ block_count=4 cstruct_size=0 is_def=true else:
1442
+ block_count=5 cstruct_size=0 is_def=true print('Usage: search_products <query>')
1443
+ block_count=4 cstruct_size=0 is_def=true continue
1444
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('show '):
1445
+ block_count=4 cstruct_size=0 is_def=true parts = user_input.split()
1446
+ block_count=4 cstruct_size=0 is_def=true if len(parts) > 1 and parts[1].isdigit():
1447
+ block_count=5 cstruct_size=0 is_def=true show_product_details(int(parts[1]))
1448
+ block_count=4 cstruct_size=0 is_def=true else:
1449
+ block_count=5 cstruct_size=0 is_def=true print('Usage: show <product_id>')
1450
+ block_count=4 cstruct_size=0 is_def=true continue
1451
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('delete '):
1452
+ block_count=4 cstruct_size=0 is_def=true try:
1453
+ block_count=5 cstruct_size=0 is_def=true parts = shlex.split(user_input)
1454
+ compo c_name=shlex
1455
+ block_count=5 cstruct_size=0 is_def=true if len(parts) > 1:
1456
+ block_count=6 cstruct_size=0 is_def=true identifiers = parts[1:]
1457
+ block_count=6 cstruct_size=0 is_def=true delete_product_records(identifiers)
1458
+ block_count=5 cstruct_size=0 is_def=true else:
1459
+ block_count=6 cstruct_size=0 is_def=true print('Usage: delete <ID/Name> ...')
1460
+ block_count=4 cstruct_size=0 is_def=true except ValueError as e:
1461
+ block_count=5 cstruct_size=0 is_def=true print(f'Error parsing command: {e}')
1462
+ block_count=4 cstruct_size=0 is_def=true continue
1463
+ block_count=3 cstruct_size=0 is_def=true if user_input:
1464
+ block_count=4 cstruct_size=0 is_def=true print(f'\nProcessing: {user_input}...\n')
1465
+ block_count=4 cstruct_size=0 is_def=true result = agent_executor.invoke({'input': user_input,
1466
+ block_count=5 cstruct_size=0 is_def=true 'chat_history': chat_history})
1467
+ block_count=4 cstruct_size=0 is_def=true chat_history.append(HumanMessage(content=user_input))
1468
+ compo c_name=HumanMessage
1469
+ block_count=4 cstruct_size=0 is_def=true if isinstance(result['output'], str):
1470
+ block_count=5 cstruct_size=0 is_def=true chat_history.append(AIMessage(content=result['output']))
1471
+ compo c_name=AIMessage
1472
+ block_count=4 cstruct_size=0 is_def=true if 'intermediate_steps' in result:
1473
+ block_count=5 cstruct_size=0 is_def=true save_agent_log(user_input, result['intermediate_steps'])
1474
+ block_count=4 cstruct_size=0 is_def=true display_products()
1475
+ block_count=2 cstruct_size=0 is_def=true except KeyboardInterrupt:
1476
+ block_count=3 cstruct_size=0 is_def=true print('\nExiting...')
1477
+ block_count=3 cstruct_size=0 is_def=true break
1478
+ block_count=2 cstruct_size=0 is_def=true except Exception as e:
1479
+ block_count=3 cstruct_size=0 is_def=true print(f'An error occurred: {e}')
1480
+ block_count=0 cstruct_size=0 is_def=true if __name__ == '__main__':
1481
+ block_count=1 cstruct_size=0 is_def=false main()
1482
+ endf of ./test/agent.py
1483
+ ./test_script.py
1484
+
1485
+ |python3 lib/del_comment.py ./test_script.py > /tmp/pylint20260323-827-lminf3
1486
+ block_count=0 cstruct_size=0 is_def=false import os
1487
+ block_count=0 cstruct_size=0 is_def=false import sqlite3
1488
+ block_count=0 cstruct_size=0 is_def=false import re
1489
+ block_count=0 cstruct_size=0 is_def=false import json
1490
+ block_count=0 cstruct_size=0 is_def=false import time
1491
+ block_count=0 cstruct_size=0 is_def=false import shlex
1492
+ block_count=0 cstruct_size=0 is_def=false import smtplib
1493
+ block_count=0 cstruct_size=0 is_def=false from email.mime.text import MIMEText
1494
+ compo c_name=email
1495
+ block_count=0 cstruct_size=0 is_def=false from email.mime.multipart import MIMEMultipart
1496
+ compo c_name=email
1497
+ block_count=0 cstruct_size=0 is_def=false from typing import Optional, Type, Any, List, Dict
1498
+ block_count=0 cstruct_size=0 is_def=false import urllib.request
1499
+ compo c_name=urllib
1500
+ block_count=0 cstruct_size=0 is_def=false import urllib.error
1501
+ compo c_name=urllib
1502
+ block_count=0 cstruct_size=0 is_def=false from dotenv import load_dotenv
1503
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.tools import BaseTool, Tool
1504
+ block_count=0 cstruct_size=0 is_def=false from pydantic import BaseModel, Field, model_validator
1505
+ block_count=0 cstruct_size=0 is_def=false from langchain_google_genai import ChatGoogleGenerativeAI
1506
+ block_count=0 cstruct_size=0 is_def=false from langchain_community.utilities import SerpAPIWrapper
1507
+ block_count=0 cstruct_size=0 is_def=false from langchain_community.tools.tavily_search import TavilySearchResults
1508
+ block_count=0 cstruct_size=0 is_def=false from googleapiclient.discovery import build
1509
+ compo c_name=googleapiclient
1510
+ block_count=0 cstruct_size=0 is_def=false import asyncio
1511
+ block_count=0 cstruct_size=0 is_def=false from browser_use import Agent, BrowserProfile
1512
+ block_count=0 cstruct_size=0 is_def=false from langchain_google_genai import ChatGoogleGenerativeAI
1513
+ block_count=0 cstruct_size=0 is_def=false from browser_use.llm.google.chat import ChatGoogle
1514
+ block_count=0 cstruct_size=0 is_def=false from langchain.agents import AgentExecutor, create_tool_calling_agent, create_react_agent
1515
+ compo c_name=langchain
1516
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.prompts import ChatPromptTemplate, PromptTemplate, MessagesPlaceholder
1517
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.output_parsers import JsonOutputParser
1518
+ block_count=0 cstruct_size=0 is_def=false from langchain_core.messages import HumanMessage, AIMessage
1519
+ block_count=0 cstruct_size=0 is_def=false dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
1520
+ compo c_name=os
1521
+ block_count=0 cstruct_size=0 is_def=false load_dotenv(dotenv_path, override=True)
1522
+ block_count=0 cstruct_size=0 is_def=false DB_NAME = 'products.db'
1523
+ block_count=0 cstruct_size=0 is_def=false def init_db():
1524
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
1525
+ compo c_name=sqlite3
1526
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
1527
+ compo c_name=conn
1528
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
1529
+ compo c_name=cursor
1530
+ block_count=2 cstruct_size=0 is_def=true """
1531
+ block_count=2 cstruct_size=0 is_def=true )
1532
+ block_count=1 cstruct_size=0 is_def=true try:
1533
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN model_number TEXT')
1534
+ compo c_name=cursor
1535
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
1536
+ block_count=2 cstruct_size=0 is_def=true pass
1537
+ block_count=1 cstruct_size=0 is_def=true try:
1538
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN release_date TEXT')
1539
+ compo c_name=cursor
1540
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
1541
+ block_count=2 cstruct_size=0 is_def=true pass
1542
+ block_count=1 cstruct_size=0 is_def=true try:
1543
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN ram TEXT')
1544
+ compo c_name=cursor
1545
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
1546
+ block_count=2 cstruct_size=0 is_def=true pass
1547
+ block_count=1 cstruct_size=0 is_def=true try:
1548
+ block_count=2 cstruct_size=0 is_def=true cursor.execute('ALTER TABLE products ADD COLUMN ssd TEXT')
1549
+ compo c_name=cursor
1550
+ block_count=1 cstruct_size=0 is_def=true except sqlite3.OperationalError:
1551
+ block_count=2 cstruct_size=0 is_def=true pass
1552
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
1553
+ compo c_name=cursor
1554
+ block_count=2 cstruct_size=0 is_def=true """
1555
+ block_count=2 cstruct_size=0 is_def=true )
1556
+ block_count=1 cstruct_size=0 is_def=true conn.commit()
1557
+ compo c_name=conn
1558
+ block_count=1 cstruct_size=0 is_def=true conn.close()
1559
+ compo c_name=conn
1560
+ block_count=0 cstruct_size=0 is_def=true init_db()
1561
+ block_count=0 cstruct_size=0 is_def=false class TavilySearchWrapper:
1562
+ class_name=test_script.TavilySearchWrapper
1563
+ base_name=
1564
+ block_count=1 cstruct_size=1 is_def=false def __init__(self):
1565
+ block_count=2 cstruct_size=1 is_def=true self.api_key = os.getenv('TAVILY_API_KEY')
1566
+ compo c_name=self
1567
+ block_count=2 cstruct_size=1 is_def=true if not self.api_key:
1568
+ compo c_name=self
1569
+ block_count=3 cstruct_size=1 is_def=true raise ValueError('TAVILY_API_KEY must be set for Tavily Search.')
1570
+ compo c_name=ValueError
1571
+ block_count=2 cstruct_size=1 is_def=true self.tool = TavilySearchResults(api_key=self.api_key)
1572
+ compo c_name=self
1573
+ compo c_name=TavilySearchResults
1574
+ block_count=1 cstruct_size=1 is_def=true def run(self, query: str) ->str:
1575
+ block_count=2 cstruct_size=1 is_def=true try:
1576
+ block_count=3 cstruct_size=1 is_def=true results = self.tool.invoke({'query': query})
1577
+ compo c_name=self
1578
+ block_count=3 cstruct_size=1 is_def=true formatted_results = []
1579
+ block_count=3 cstruct_size=1 is_def=true for item in results:
1580
+ block_count=4 cstruct_size=1 is_def=true content = item.get('content')
1581
+ compo c_name=item
1582
+ block_count=4 cstruct_size=1 is_def=true url = item.get('url')
1583
+ compo c_name=item
1584
+ block_count=4 cstruct_size=1 is_def=true formatted_results.append(f'Content: {content}\nURL: {url}\n')
1585
+ block_count=3 cstruct_size=1 is_def=true return '\n'.join(formatted_results
1586
+ block_count=4 cstruct_size=1 is_def=true ) if formatted_results else 'No results found.'
1587
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
1588
+ block_count=3 cstruct_size=1 is_def=true return f'Error during Tavily Search: {e}'
1589
+ block_count=0 cstruct_size=1 is_def=true class BrowserUseSearchWrapper:
1590
+ end of test_script.TavilySearchWrapper
1591
+ class_name=test_script.BrowserUseSearchWrapper
1592
+ base_name=
1593
+ block_count=1 cstruct_size=1 is_def=false def __init__(self):
1594
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
1595
+ compo c_name=os
1596
+ block_count=2 cstruct_size=1 is_def=true self.llm = ChatGoogle(model=model_name, api_key=os.getenv(
1597
+ compo c_name=self
1598
+ compo c_name=ChatGoogle
1599
+ block_count=3 cstruct_size=1 is_def=true 'GOOGLE_API_KEY'))
1600
+ block_count=2 cstruct_size=1 is_def=true user_agent = (
1601
+ block_count=3 cstruct_size=1 is_def=true 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
1602
+ block_count=3 cstruct_size=1 is_def=true )
1603
+ block_count=2 cstruct_size=1 is_def=true self.browser_profile = BrowserProfile(headless=False, user_agent=
1604
+ compo c_name=self
1605
+ compo c_name=BrowserProfile
1606
+ block_count=3 cstruct_size=1 is_def=true user_agent)
1607
+ block_count=1 cstruct_size=1 is_def=true async def _search_async(self, query: str) ->str:
1608
+ block_count=2 cstruct_size=1 is_def=false task = f"""
1609
+ block_count=2 cstruct_size=1 is_def=false agent = Agent(task=task, llm=self.llm, browser_profile=self.
1610
+ compo c_name=Agent
1611
+ block_count=3 cstruct_size=1 is_def=false browser_profile)
1612
+ block_count=2 cstruct_size=1 is_def=false result = await agent.run()
1613
+ compo c_name=agent
1614
+ block_count=2 cstruct_size=1 is_def=false return result.final_result()
1615
+ compo c_name=result
1616
+ block_count=1 cstruct_size=1 is_def=false def run(self, query: str) ->str:
1617
+ block_count=2 cstruct_size=1 is_def=true try:
1618
+ block_count=3 cstruct_size=1 is_def=true return asyncio.run(self._search_async(query))
1619
+ compo c_name=asyncio
1620
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
1621
+ block_count=3 cstruct_size=1 is_def=true return f'Error during Browser Use Search: {e}'
1622
+ block_count=0 cstruct_size=1 is_def=true def get_search_tool_func():
1623
+ end of test_script.BrowserUseSearchWrapper
1624
+ block_count=1 cstruct_size=0 is_def=true provider = os.getenv('SEARCH_PROVIDER', 'serpapi')
1625
+ compo c_name=os
1626
+ block_count=1 cstruct_size=0 is_def=true if provider == 'tavily_api':
1627
+ block_count=2 cstruct_size=0 is_def=true return TavilySearchWrapper()
1628
+ compo c_name=TavilySearchWrapper
1629
+ block_count=1 cstruct_size=0 is_def=true elif provider == 'browser_use':
1630
+ block_count=2 cstruct_size=0 is_def=true return BrowserUseSearchWrapper()
1631
+ compo c_name=BrowserUseSearchWrapper
1632
+ block_count=1 cstruct_size=0 is_def=true else:
1633
+ block_count=2 cstruct_size=0 is_def=true return SerpAPIWrapper()
1634
+ compo c_name=SerpAPIWrapper
1635
+ block_count=0 cstruct_size=0 is_def=true def get_all_products():
1636
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
1637
+ compo c_name=sqlite3
1638
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
1639
+ compo c_name=conn
1640
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
1641
+ compo c_name=cursor
1642
+ block_count=2 cstruct_size=0 is_def=true 'SELECT id, name, store, price, url, description, model_number, release_date, ram, ssd, updated_at FROM products'
1643
+ block_count=2 cstruct_size=0 is_def=true )
1644
+ block_count=1 cstruct_size=0 is_def=true rows = cursor.fetchall()
1645
+ compo c_name=cursor
1646
+ block_count=1 cstruct_size=0 is_def=true conn.close()
1647
+ compo c_name=conn
1648
+ block_count=1 cstruct_size=0 is_def=true products = []
1649
+ block_count=1 cstruct_size=0 is_def=true for r in rows:
1650
+ block_count=2 cstruct_size=0 is_def=true products.append({'id': r[0], 'name': r[1], 'store': r[2], 'price':
1651
+ compo c_name=products
1652
+ block_count=3 cstruct_size=0 is_def=true r[3], 'url': r[4], 'description': r[5], 'model_number': r[6] if
1653
+ block_count=3 cstruct_size=0 is_def=true len(r) > 6 else '', 'release_date': r[7] if len(r) > 7 else '',
1654
+ block_count=3 cstruct_size=0 is_def=true 'ram': r[8] if len(r) > 8 else '', 'ssd': r[9] if len(r) > 9 else
1655
+ block_count=3 cstruct_size=0 is_def=true '', 'updated_at': r[10] if len(r) > 10 else ''})
1656
+ block_count=1 cstruct_size=0 is_def=true return products
1657
+ block_count=0 cstruct_size=0 is_def=true def parse_price_val(p_str):
1658
+ block_count=1 cstruct_size=0 is_def=true if not p_str:
1659
+ block_count=2 cstruct_size=0 is_def=true return float('inf')
1660
+ block_count=1 cstruct_size=0 is_def=true s = str(p_str).replace(',', '')
1661
+ block_count=1 cstruct_size=0 is_def=true match_man = re.search('(\\d+(\\.\\d+)?)万', s)
1662
+ compo c_name=re
1663
+ block_count=1 cstruct_size=0 is_def=true if match_man:
1664
+ block_count=2 cstruct_size=0 is_def=true try:
1665
+ block_count=3 cstruct_size=0 is_def=true val = float(match_man.group(1)) * 10000
1666
+ block_count=3 cstruct_size=0 is_def=true return int(val)
1667
+ block_count=2 cstruct_size=0 is_def=true except:
1668
+ block_count=3 cstruct_size=0 is_def=true pass
1669
+ block_count=1 cstruct_size=0 is_def=true nums = re.findall('\\d+', s)
1670
+ compo c_name=re
1671
+ block_count=1 cstruct_size=0 is_def=true return int(''.join(nums)) if nums else float('inf')
1672
+ block_count=0 cstruct_size=0 is_def=true def extract_alphanumeric(s: str) ->str:
1673
+ block_count=1 cstruct_size=0 is_def=true """Extracts only alphanumeric characters from a string and converts to lowercase for robust comparison."""
1674
+ block_count=1 cstruct_size=0 is_def=true if not s:
1675
+ block_count=2 cstruct_size=0 is_def=true return ''
1676
+ block_count=1 cstruct_size=0 is_def=true return re.sub('[^a-zA-Z0-9]', '', str(s)).lower()
1677
+ compo c_name=re
1678
+ block_count=0 cstruct_size=0 is_def=true def parse_date_val(d_str: str) ->str:
1679
+ block_count=1 cstruct_size=0 is_def=true """
1680
+ block_count=1 cstruct_size=0 is_def=true if not d_str:
1681
+ block_count=2 cstruct_size=0 is_def=true return ''
1682
+ block_count=1 cstruct_size=0 is_def=true nums = re.findall('\\d+', str(d_str))
1683
+ compo c_name=re
1684
+ block_count=1 cstruct_size=0 is_def=true if len(nums) >= 2:
1685
+ block_count=2 cstruct_size=0 is_def=true year = nums[0]
1686
+ block_count=2 cstruct_size=0 is_def=true month = nums[1].zfill(2)
1687
+ block_count=2 cstruct_size=0 is_def=true return f'{year}{month}'
1688
+ block_count=1 cstruct_size=0 is_def=true elif len(nums) == 1:
1689
+ block_count=2 cstruct_size=0 is_def=true return nums[0]
1690
+ block_count=1 cstruct_size=0 is_def=true else:
1691
+ block_count=2 cstruct_size=0 is_def=true return extract_alphanumeric(d_str)
1692
+ block_count=0 cstruct_size=0 is_def=true def is_similar_model(m1: str, m2: str) ->bool:
1693
+ block_count=1 cstruct_size=0 is_def=true """
1694
+ block_count=1 cstruct_size=0 is_def=true am1 = extract_alphanumeric(m1)
1695
+ block_count=1 cstruct_size=0 is_def=true am2 = extract_alphanumeric(m2)
1696
+ block_count=1 cstruct_size=0 is_def=true if not am1 and not am2:
1697
+ block_count=2 cstruct_size=0 is_def=true return True
1698
+ block_count=1 cstruct_size=0 is_def=true if not am1 or not am2:
1699
+ block_count=2 cstruct_size=0 is_def=true return False
1700
+ block_count=1 cstruct_size=0 is_def=true return am1 in am2 or am2 in am1
1701
+ block_count=0 cstruct_size=0 is_def=true def save_agent_log(query, steps):
1702
+ block_count=1 cstruct_size=0 is_def=true """Saves the agent's scratchpad (intermediate steps) to the database."""
1703
+ block_count=1 cstruct_size=0 is_def=true if not steps:
1704
+ block_count=2 cstruct_size=0 is_def=true return
1705
+ block_count=1 cstruct_size=0 is_def=true log_content = []
1706
+ block_count=1 cstruct_size=0 is_def=true for action, observation in steps:
1707
+ block_count=2 cstruct_size=0 is_def=true if isinstance(action, list):
1708
+ block_count=3 cstruct_size=0 is_def=true for a in action:
1709
+ block_count=4 cstruct_size=0 is_def=true log_content.append(f'Tool: {a.tool}')
1710
+ block_count=4 cstruct_size=0 is_def=true log_content.append(f'Input: {a.tool_input}')
1711
+ block_count=4 cstruct_size=0 is_def=true log_content.append(f'Log: {a.log}')
1712
+ block_count=2 cstruct_size=0 is_def=true else:
1713
+ block_count=3 cstruct_size=0 is_def=true log_content.append(f'Tool: {action.tool}')
1714
+ block_count=3 cstruct_size=0 is_def=true log_content.append(f'Input: {action.tool_input}')
1715
+ block_count=3 cstruct_size=0 is_def=true log_content.append(f'Log: {action.log}')
1716
+ block_count=2 cstruct_size=0 is_def=true log_content.append(f'Observation: {observation}')
1717
+ block_count=2 cstruct_size=0 is_def=true log_content.append('-' * 20)
1718
+ block_count=1 cstruct_size=0 is_def=true scratchpad_text = '\n'.join(log_content)
1719
+ block_count=1 cstruct_size=0 is_def=true try:
1720
+ block_count=2 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
1721
+ compo c_name=sqlite3
1722
+ block_count=2 cstruct_size=0 is_def=true cursor = conn.cursor()
1723
+ compo c_name=conn
1724
+ block_count=2 cstruct_size=0 is_def=true cursor.execute(
1725
+ compo c_name=cursor
1726
+ block_count=3 cstruct_size=0 is_def=true 'INSERT INTO agent_logs (query, scratchpad) VALUES (?, ?)', (
1727
+ block_count=3 cstruct_size=0 is_def=true query, scratchpad_text))
1728
+ block_count=2 cstruct_size=0 is_def=true conn.commit()
1729
+ compo c_name=conn
1730
+ block_count=2 cstruct_size=0 is_def=true conn.close()
1731
+ compo c_name=conn
1732
+ block_count=2 cstruct_size=0 is_def=true print(f' [Log saved to database]')
1733
+ block_count=1 cstruct_size=0 is_def=true except Exception as e:
1734
+ block_count=2 cstruct_size=0 is_def=true print(f'Error saving log: {e}')
1735
+ block_count=0 cstruct_size=0 is_def=true def get_all_agent_logs():
1736
+ block_count=1 cstruct_size=0 is_def=true """Fetches all agent logs from the database."""
1737
+ block_count=1 cstruct_size=0 is_def=true try:
1738
+ block_count=2 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
1739
+ compo c_name=sqlite3
1740
+ block_count=2 cstruct_size=0 is_def=true cursor = conn.cursor()
1741
+ compo c_name=conn
1742
+ block_count=2 cstruct_size=0 is_def=true cursor.execute(
1743
+ compo c_name=cursor
1744
+ block_count=3 cstruct_size=0 is_def=true 'SELECT query, scratchpad FROM agent_logs ORDER BY timestamp DESC')
1745
+ block_count=2 cstruct_size=0 is_def=true rows = cursor.fetchall()
1746
+ compo c_name=cursor
1747
+ block_count=2 cstruct_size=0 is_def=true conn.close()
1748
+ compo c_name=conn
1749
+ block_count=2 cstruct_size=0 is_def=true logs = []
1750
+ block_count=2 cstruct_size=0 is_def=true for r in rows:
1751
+ block_count=3 cstruct_size=0 is_def=true logs.append(f'Query: {r[0]}\nLog:\n{r[1]}\n')
1752
+ compo c_name=logs
1753
+ block_count=2 cstruct_size=0 is_def=true return '\n'.join(logs)
1754
+ block_count=1 cstruct_size=0 is_def=true except Exception as e:
1755
+ block_count=2 cstruct_size=0 is_def=true print(f'Error fetching logs: {e}')
1756
+ block_count=2 cstruct_size=0 is_def=true return ''
1757
+ block_count=0 cstruct_size=0 is_def=true def send_email_notification(subject: str, body: str):
1758
+ block_count=1 cstruct_size=0 is_def=true """Sends an email notification."""
1759
+ block_count=1 cstruct_size=0 is_def=true smtp_server = os.getenv('EMAIL_SMTP_SERVER')
1760
+ compo c_name=os
1761
+ block_count=1 cstruct_size=0 is_def=true smtp_port = os.getenv('EMAIL_SMTP_PORT')
1762
+ compo c_name=os
1763
+ block_count=1 cstruct_size=0 is_def=true sender_email = os.getenv('EMAIL_SENDER_ADDRESS')
1764
+ compo c_name=os
1765
+ block_count=1 cstruct_size=0 is_def=true sender_password = os.getenv('EMAIL_SENDER_PASSWORD')
1766
+ compo c_name=os
1767
+ block_count=1 cstruct_size=0 is_def=true receiver_email = os.getenv('EMAIL_RECEIVER_ADDRESS')
1768
+ compo c_name=os
1769
+ block_count=1 cstruct_size=0 is_def=true if not all([smtp_server, smtp_port, sender_email, receiver_email]):
1770
+ block_count=2 cstruct_size=0 is_def=true print(
1771
+ block_count=3 cstruct_size=0 is_def=true 'Email configuration missing (Server, Port, Sender, Receiver). Skipping notification.'
1772
+ block_count=3 cstruct_size=0 is_def=true )
1773
+ block_count=2 cstruct_size=0 is_def=true return
1774
+ block_count=1 cstruct_size=0 is_def=true try:
1775
+ block_count=2 cstruct_size=0 is_def=true msg = MIMEMultipart()
1776
+ compo c_name=MIMEMultipart
1777
+ block_count=2 cstruct_size=0 is_def=true msg['From'] = sender_email
1778
+ block_count=2 cstruct_size=0 is_def=true msg['To'] = receiver_email
1779
+ block_count=2 cstruct_size=0 is_def=true msg['Subject'] = subject
1780
+ block_count=2 cstruct_size=0 is_def=true msg.attach(MIMEText(body, 'plain'))
1781
+ compo c_name=msg
1782
+ compo c_name=MIMEText
1783
+ block_count=2 cstruct_size=0 is_def=true server = smtplib.SMTP(smtp_server, int(smtp_port))
1784
+ compo c_name=SMTP
1785
+ block_count=2 cstruct_size=0 is_def=true server.starttls()
1786
+ compo c_name=server
1787
+ block_count=2 cstruct_size=0 is_def=true if sender_password:
1788
+ block_count=3 cstruct_size=0 is_def=true server.login(sender_email, sender_password)
1789
+ compo c_name=server
1790
+ block_count=2 cstruct_size=0 is_def=true server.send_message(msg)
1791
+ compo c_name=server
1792
+ block_count=2 cstruct_size=0 is_def=true server.quit()
1793
+ compo c_name=server
1794
+ block_count=2 cstruct_size=0 is_def=true print(f'Email notification sent: {subject}')
1795
+ block_count=1 cstruct_size=0 is_def=true except Exception as e:
1796
+ block_count=2 cstruct_size=0 is_def=true print(f'Failed to send email: {e}')
1797
+ block_count=0 cstruct_size=0 is_def=true class SaveProductInput(BaseModel):
1798
+ class_name=test_script.SaveProductInput
1799
+ base_name=BaseModel
1800
+ block_count=1 cstruct_size=1 is_def=false name: str = Field(description='Name of the product')
1801
+ compo c_name=Field
1802
+ block_count=1 cstruct_size=1 is_def=false store: str = Field(description='Name of the store selling the product')
1803
+ compo c_name=Field
1804
+ block_count=1 cstruct_size=1 is_def=false price: str = Field(description='Price of the product')
1805
+ compo c_name=Field
1806
+ block_count=1 cstruct_size=1 is_def=false url: Optional[str] = Field(description='URL of the product page',
1807
+ compo c_name=Field
1808
+ block_count=2 cstruct_size=1 is_def=false default='')
1809
+ block_count=1 cstruct_size=1 is_def=false description: Optional[str] = Field(description=
1810
+ compo c_name=Field
1811
+ block_count=2 cstruct_size=1 is_def=false 'Brief description of the product', default='')
1812
+ block_count=1 cstruct_size=1 is_def=false model_number: Optional[str] = Field(description=
1813
+ compo c_name=Field
1814
+ block_count=2 cstruct_size=1 is_def=false 'Model number (型番) of the product', default='')
1815
+ block_count=1 cstruct_size=1 is_def=false release_date: Optional[str] = Field(description=
1816
+ compo c_name=Field
1817
+ block_count=2 cstruct_size=1 is_def=false 'Release date (発売日) of the product', default='')
1818
+ block_count=1 cstruct_size=1 is_def=false ram: Optional[str] = Field(description='RAM size', default='')
1819
+ compo c_name=Field
1820
+ block_count=1 cstruct_size=1 is_def=false ssd: Optional[str] = Field(description='SSD size', default='')
1821
+ compo c_name=Field
1822
+ block_count=1 cstruct_size=1 is_def=false @model_validator(mode='before')
1823
+ block_count=1 cstruct_size=1 is_def=false @classmethod
1824
+ block_count=1 cstruct_size=1 is_def=false def parse_json_input(cls, data: Any) ->Any:
1825
+ block_count=2 cstruct_size=1 is_def=true if isinstance(data, dict):
1826
+ block_count=3 cstruct_size=1 is_def=true if 'name' in data and ('store' not in data or 'price' not in data):
1827
+ block_count=4 cstruct_size=1 is_def=true name_val = data['name']
1828
+ block_count=4 cstruct_size=1 is_def=true if isinstance(name_val, str) and name_val.strip().startswith(
1829
+ block_count=5 cstruct_size=1 is_def=true '{') and name_val.strip().endswith('}'):
1830
+ block_count=5 cstruct_size=1 is_def=true try:
1831
+ block_count=6 cstruct_size=1 is_def=true parsed = json.loads(name_val)
1832
+ compo c_name=json
1833
+ block_count=6 cstruct_size=1 is_def=true if isinstance(parsed, dict):
1834
+ block_count=7 cstruct_size=1 is_def=true data = parsed
1835
+ block_count=5 cstruct_size=1 is_def=true except json.JSONDecodeError:
1836
+ block_count=6 cstruct_size=1 is_def=true pass
1837
+ block_count=2 cstruct_size=1 is_def=true if isinstance(data, dict) and 'price' in data:
1838
+ block_count=3 cstruct_size=1 is_def=true if isinstance(data['price'], (int, float)):
1839
+ block_count=4 cstruct_size=1 is_def=true data['price'] = str(data['price'])
1840
+ block_count=2 cstruct_size=1 is_def=true return data
1841
+ block_count=0 cstruct_size=1 is_def=true class SaveProductTool(BaseTool):
1842
+ end of test_script.SaveProductInput
1843
+ class_name=test_script.SaveProductTool
1844
+ base_name=BaseTool
1845
+ block_count=1 cstruct_size=1 is_def=false name = 'save_product'
1846
+ block_count=1 cstruct_size=1 is_def=false description = (
1847
+ block_count=2 cstruct_size=1 is_def=false 'Saves product information (name, store, price, url, description, model_number, release_date, ram, ssd) to the database.'
1848
+ block_count=2 cstruct_size=1 is_def=false )
1849
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = SaveProductInput
1850
+ block_count=1 cstruct_size=1 is_def=false def _run(self, name: str, store: str=None, price: str=None, url: str='',
1851
+ block_count=2 cstruct_size=1 is_def=true description: str='', model_number: str='', release_date: str='',
1852
+ block_count=2 cstruct_size=1 is_def=true ram: str='', ssd: str='', **kwargs):
1853
+ block_count=2 cstruct_size=1 is_def=true try:
1854
+ block_count=3 cstruct_size=1 is_def=true parsed_data = {}
1855
+ block_count=3 cstruct_size=1 is_def=true if isinstance(name, dict):
1856
+ block_count=4 cstruct_size=1 is_def=true parsed_data = name
1857
+ block_count=3 cstruct_size=1 is_def=true elif isinstance(name, str) and name.strip().startswith('{'
1858
+ compo c_name=name
1859
+ block_count=4 cstruct_size=1 is_def=true ) and name.strip().endswith('}'):
1860
+ compo c_name=name
1861
+ block_count=4 cstruct_size=1 is_def=true try:
1862
+ block_count=5 cstruct_size=1 is_def=true parsed_data = json.loads(name)
1863
+ compo c_name=json
1864
+ block_count=4 cstruct_size=1 is_def=true except json.JSONDecodeError:
1865
+ block_count=5 cstruct_size=1 is_def=true pass
1866
+ block_count=3 cstruct_size=1 is_def=true if parsed_data:
1867
+ block_count=4 cstruct_size=1 is_def=true if 'name' in parsed_data:
1868
+ block_count=5 cstruct_size=1 is_def=true name = parsed_data['name']
1869
+ block_count=4 cstruct_size=1 is_def=true if store is None:
1870
+ block_count=5 cstruct_size=1 is_def=true store = parsed_data.get('store')
1871
+ block_count=4 cstruct_size=1 is_def=true if price is None:
1872
+ block_count=5 cstruct_size=1 is_def=true price = parsed_data.get('price')
1873
+ block_count=4 cstruct_size=1 is_def=true if not url:
1874
+ block_count=5 cstruct_size=1 is_def=true url = parsed_data.get('url', '')
1875
+ block_count=4 cstruct_size=1 is_def=true if not description:
1876
+ block_count=5 cstruct_size=1 is_def=true description = parsed_data.get('description', '')
1877
+ block_count=4 cstruct_size=1 is_def=true if not model_number:
1878
+ block_count=5 cstruct_size=1 is_def=true model_number = parsed_data.get('model_number', '')
1879
+ block_count=4 cstruct_size=1 is_def=true if not release_date:
1880
+ block_count=5 cstruct_size=1 is_def=true release_date = parsed_data.get('release_date', '')
1881
+ block_count=4 cstruct_size=1 is_def=true if not ram:
1882
+ block_count=5 cstruct_size=1 is_def=true ram = parsed_data.get('ram', '')
1883
+ block_count=4 cstruct_size=1 is_def=true if not ssd:
1884
+ block_count=5 cstruct_size=1 is_def=true ssd = parsed_data.get('ssd', '')
1885
+ block_count=3 cstruct_size=1 is_def=true if store is None:
1886
+ block_count=4 cstruct_size=1 is_def=true store = kwargs.get('store')
1887
+ compo c_name=kwargs
1888
+ block_count=3 cstruct_size=1 is_def=true if price is None:
1889
+ block_count=4 cstruct_size=1 is_def=true price = kwargs.get('price')
1890
+ compo c_name=kwargs
1891
+ block_count=3 cstruct_size=1 is_def=true if not model_number:
1892
+ block_count=4 cstruct_size=1 is_def=true model_number = kwargs.get('model_number', '')
1893
+ compo c_name=kwargs
1894
+ block_count=3 cstruct_size=1 is_def=true if not release_date:
1895
+ block_count=4 cstruct_size=1 is_def=true release_date = kwargs.get('release_date', '')
1896
+ compo c_name=kwargs
1897
+ block_count=3 cstruct_size=1 is_def=true if not ram:
1898
+ block_count=4 cstruct_size=1 is_def=true ram = kwargs.get('ram', '')
1899
+ compo c_name=kwargs
1900
+ block_count=3 cstruct_size=1 is_def=true if not ssd:
1901
+ block_count=4 cstruct_size=1 is_def=true ssd = kwargs.get('ssd', '')
1902
+ compo c_name=kwargs
1903
+ block_count=3 cstruct_size=1 is_def=true if not name or not store or not price:
1904
+ block_count=4 cstruct_size=1 is_def=true return (
1905
+ block_count=5 cstruct_size=1 is_def=true f'Error: Required arguments missing. Name: {name}, Store: {store}, Price: {price}'
1906
+ block_count=5 cstruct_size=1 is_def=true )
1907
+ block_count=3 cstruct_size=1 is_def=true if not url or not description:
1908
+ block_count=4 cstruct_size=1 is_def=true return (
1909
+ block_count=5 cstruct_size=1 is_def=true f"Skipped saving product '{name}': URL or description is missing. URL: '{url}', Description: '{description}'"
1910
+ block_count=5 cstruct_size=1 is_def=true )
1911
+ block_count=3 cstruct_size=1 is_def=true if not url.startswith('http://') and not url.startswith('https://'
1912
+ compo c_name=url
1913
+ block_count=4 cstruct_size=1 is_def=true ):
1914
+ block_count=4 cstruct_size=1 is_def=true return (
1915
+ block_count=5 cstruct_size=1 is_def=true f"Skipped saving product '{name}': URL must start with 'http://' or 'https://'. URL: '{url}'"
1916
+ block_count=5 cstruct_size=1 is_def=true )
1917
+ block_count=3 cstruct_size=1 is_def=true if isinstance(price, (int, float)):
1918
+ block_count=4 cstruct_size=1 is_def=true price = str(price)
1919
+ block_count=3 cstruct_size=1 is_def=true price_val = parse_price_val(price)
1920
+ block_count=3 cstruct_size=1 is_def=true if price_val == float('inf'):
1921
+ block_count=4 cstruct_size=1 is_def=true if not re.search('\\d', str(price)):
1922
+ compo c_name=re
1923
+ block_count=5 cstruct_size=1 is_def=true return (
1924
+ block_count=6 cstruct_size=1 is_def=true f"Skipped saving product '{name}': Price info is missing or invalid ('{price}')."
1925
+ block_count=6 cstruct_size=1 is_def=true )
1926
+ block_count=3 cstruct_size=1 is_def=true conn = sqlite3.connect(DB_NAME)
1927
+ compo c_name=sqlite3
1928
+ block_count=3 cstruct_size=1 is_def=true cursor = conn.cursor()
1929
+ compo c_name=conn
1930
+ block_count=3 cstruct_size=1 is_def=true cursor.execute(
1931
+ compo c_name=cursor
1932
+ block_count=4 cstruct_size=1 is_def=true 'SELECT id, store, price, url FROM products WHERE name = ?',
1933
+ block_count=4 cstruct_size=1 is_def=true (name,))
1934
+ block_count=3 cstruct_size=1 is_def=true rows = cursor.fetchall()
1935
+ compo c_name=cursor
1936
+ block_count=3 cstruct_size=1 is_def=true items = []
1937
+ block_count=3 cstruct_size=1 is_def=true for r in rows:
1938
+ block_count=4 cstruct_size=1 is_def=true items.append({'id': r[0], 'store': r[1], 'price_str': r[2],
1939
+ compo c_name=items
1940
+ block_count=5 cstruct_size=1 is_def=true 'price_val': parse_price_val(r[2]), 'url': r[3]})
1941
+ block_count=3 cstruct_size=1 is_def=true new_price_val = parse_price_val(price)
1942
+ block_count=3 cstruct_size=1 is_def=true msg = ''
1943
+ block_count=3 cstruct_size=1 is_def=true items.sort(key=lambda x: x['price_val'])
1944
+ compo c_name=items
1945
+ block_count=3 cstruct_size=1 is_def=true current_cheapest = items[0] if items else None
1946
+ block_count=3 cstruct_size=1 is_def=true should_save = False
1947
+ block_count=3 cstruct_size=1 is_def=true should_update = False
1948
+ block_count=3 cstruct_size=1 is_def=true if not current_cheapest:
1949
+ block_count=4 cstruct_size=1 is_def=true should_save = True
1950
+ block_count=3 cstruct_size=1 is_def=true elif new_price_val < current_cheapest['price_val']:
1951
+ block_count=4 cstruct_size=1 is_def=true should_save = True
1952
+ block_count=4 cstruct_size=1 is_def=true cursor.execute('DELETE FROM products WHERE name = ?', (name,))
1953
+ compo c_name=cursor
1954
+ block_count=4 cstruct_size=1 is_def=true msg_prefix = (
1955
+ block_count=5 cstruct_size=1 is_def=true f"Found cheaper price! Updated {name} from {current_cheapest['store']} ({current_cheapest['price_str']}) to {store} ({price})."
1956
+ block_count=5 cstruct_size=1 is_def=true )
1957
+ block_count=3 cstruct_size=1 is_def=true elif new_price_val == current_cheapest['price_val']:
1958
+ block_count=4 cstruct_size=1 is_def=true if store == current_cheapest['store']:
1959
+ block_count=5 cstruct_size=1 is_def=true should_update = True
1960
+ block_count=5 cstruct_size=1 is_def=true msg_prefix = f'Updated info for {name} at {store}.'
1961
+ block_count=4 cstruct_size=1 is_def=true else:
1962
+ block_count=5 cstruct_size=1 is_def=true msg = (
1963
+ block_count=6 cstruct_size=1 is_def=true f"Product {name} exists with same price at {current_cheapest['store']}. Keeping existing."
1964
+ block_count=6 cstruct_size=1 is_def=true )
1965
+ block_count=3 cstruct_size=1 is_def=true elif store == current_cheapest['store']:
1966
+ block_count=4 cstruct_size=1 is_def=true should_update = True
1967
+ block_count=4 cstruct_size=1 is_def=true msg_prefix = (
1968
+ block_count=5 cstruct_size=1 is_def=true f"Price increased for {name} at {store}: {current_cheapest['price_str']} -> {price}."
1969
+ block_count=5 cstruct_size=1 is_def=true )
1970
+ block_count=3 cstruct_size=1 is_def=true else:
1971
+ block_count=4 cstruct_size=1 is_def=true msg = (
1972
+ block_count=5 cstruct_size=1 is_def=true f"Product {name} exists cheaper at {current_cheapest['store']} ({current_cheapest['price_str']}). Ignoring {store} ({price})."
1973
+ block_count=5 cstruct_size=1 is_def=true )
1974
+ block_count=3 cstruct_size=1 is_def=true if should_save:
1975
+ block_count=4 cstruct_size=1 is_def=true cursor.execute(
1976
+ compo c_name=cursor
1977
+ block_count=5 cstruct_size=1 is_def=true """
1978
+ block_count=5 cstruct_size=1 is_def=true , (name, store, price, url, description, model_number,
1979
+ block_count=5 cstruct_size=1 is_def=true release_date, ram, ssd))
1980
+ block_count=4 cstruct_size=1 is_def=true if not msg:
1981
+ block_count=5 cstruct_size=1 is_def=true msg = f'Saved product: {name} from {store} for {price}.'
1982
+ block_count=4 cstruct_size=1 is_def=true else:
1983
+ block_count=5 cstruct_size=1 is_def=true msg = msg_prefix
1984
+ block_count=4 cstruct_size=1 is_def=true email_subject = f'Product Saved: {name}'
1985
+ block_count=4 cstruct_size=1 is_def=true email_body = f"""Action: Saved (New or Cheaper)
1986
+ block_count=4 cstruct_size=1 is_def=true send_email_notification(email_subject, email_body)
1987
+ block_count=3 cstruct_size=1 is_def=true if should_update:
1988
+ block_count=4 cstruct_size=1 is_def=true cursor.execute(
1989
+ compo c_name=cursor
1990
+ block_count=5 cstruct_size=1 is_def=true 'SELECT price, url, description, model_number, release_date, ram, ssd FROM products WHERE id = ?'
1991
+ block_count=5 cstruct_size=1 is_def=true , (current_cheapest['id'],))
1992
+ block_count=4 cstruct_size=1 is_def=true curr_row = cursor.fetchone()
1993
+ compo c_name=cursor
1994
+ block_count=4 cstruct_size=1 is_def=true curr_price_str = curr_row[0]
1995
+ block_count=4 cstruct_size=1 is_def=true curr_url = curr_row[1]
1996
+ block_count=4 cstruct_size=1 is_def=true curr_desc = curr_row[2]
1997
+ block_count=4 cstruct_size=1 is_def=true curr_model = curr_row[3]
1998
+ block_count=4 cstruct_size=1 is_def=true curr_release = curr_row[4]
1999
+ block_count=4 cstruct_size=1 is_def=true curr_ram = curr_row[5] if len(curr_row) > 5 else ''
2000
+ block_count=4 cstruct_size=1 is_def=true curr_ssd = curr_row[6] if len(curr_row) > 6 else ''
2001
+ block_count=4 cstruct_size=1 is_def=true final_model = model_number if model_number else curr_model
2002
+ block_count=4 cstruct_size=1 is_def=true final_release = release_date if release_date else curr_release
2003
+ block_count=4 cstruct_size=1 is_def=true final_ram = ram if ram else curr_ram
2004
+ block_count=4 cstruct_size=1 is_def=true final_ssd = ssd if ssd else curr_ssd
2005
+ block_count=4 cstruct_size=1 is_def=true if (price != curr_price_str or url != curr_url or
2006
+ block_count=5 cstruct_size=1 is_def=true description != curr_desc or final_model != curr_model or
2007
+ block_count=5 cstruct_size=1 is_def=true final_release != curr_release or final_ram != curr_ram or
2008
+ block_count=5 cstruct_size=1 is_def=true final_ssd != curr_ssd):
2009
+ block_count=5 cstruct_size=1 is_def=true cursor.execute(
2010
+ compo c_name=cursor
2011
+ block_count=6 cstruct_size=1 is_def=true """
2012
+ block_count=6 cstruct_size=1 is_def=true , (price, url, description, final_model,
2013
+ block_count=6 cstruct_size=1 is_def=true final_release, final_ram, final_ssd, store,
2014
+ block_count=6 cstruct_size=1 is_def=true current_cheapest['id']))
2015
+ block_count=5 cstruct_size=1 is_def=true if not msg:
2016
+ block_count=6 cstruct_size=1 is_def=true msg = f'Updated product {name} info.'
2017
+ block_count=5 cstruct_size=1 is_def=true else:
2018
+ block_count=6 cstruct_size=1 is_def=true msg = msg_prefix
2019
+ block_count=5 cstruct_size=1 is_def=true email_subject = f'Product Updated: {name}'
2020
+ block_count=5 cstruct_size=1 is_def=true email_body = f"""Action: Updated Info
2021
+ block_count=5 cstruct_size=1 is_def=true send_email_notification(email_subject, email_body)
2022
+ block_count=4 cstruct_size=1 is_def=true else:
2023
+ block_count=5 cstruct_size=1 is_def=true msg = f'No changes for {name} at {store}.'
2024
+ block_count=3 cstruct_size=1 is_def=true if should_save or should_update:
2025
+ block_count=4 cstruct_size=1 is_def=true cursor.execute('SELECT id, price FROM products WHERE name = ?',
2026
+ compo c_name=cursor
2027
+ block_count=5 cstruct_size=1 is_def=true (name,))
2028
+ block_count=4 cstruct_size=1 is_def=true rows = cursor.fetchall()
2029
+ compo c_name=cursor
2030
+ block_count=4 cstruct_size=1 is_def=true if len(rows) > 1:
2031
+ block_count=5 cstruct_size=1 is_def=true rows_parsed = []
2032
+ block_count=5 cstruct_size=1 is_def=true for r in rows:
2033
+ block_count=6 cstruct_size=1 is_def=true rows_parsed.append({'id': r[0], 'val':
2034
+ block_count=7 cstruct_size=1 is_def=true parse_price_val(r[1])})
2035
+ block_count=5 cstruct_size=1 is_def=true rows_parsed.sort(key=lambda x: x['val'])
2036
+ block_count=5 cstruct_size=1 is_def=true winner = rows_parsed[0]
2037
+ block_count=5 cstruct_size=1 is_def=true for loser in rows_parsed[1:]:
2038
+ block_count=6 cstruct_size=1 is_def=true cursor.execute('DELETE FROM products WHERE id = ?',
2039
+ compo c_name=cursor
2040
+ block_count=7 cstruct_size=1 is_def=true (loser['id'],))
2041
+ block_count=5 cstruct_size=1 is_def=true msg += ' (Cleaned up duplicate records)'
2042
+ block_count=3 cstruct_size=1 is_def=true conn.commit()
2043
+ compo c_name=conn
2044
+ block_count=3 cstruct_size=1 is_def=true conn.close()
2045
+ compo c_name=conn
2046
+ block_count=3 cstruct_size=1 is_def=true return msg
2047
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
2048
+ block_count=3 cstruct_size=1 is_def=true return f'Error saving product: {str(e)}'
2049
+ block_count=0 cstruct_size=1 is_def=true class UpdatePricesInput(BaseModel):
2050
+ end of test_script.SaveProductTool
2051
+ class_name=test_script.UpdatePricesInput
2052
+ base_name=BaseModel
2053
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description='Optional query', default='')
2054
+ compo c_name=Field
2055
+ block_count=0 cstruct_size=1 is_def=false class UpdatePricesTool(BaseTool):
2056
+ end of test_script.UpdatePricesInput
2057
+ class_name=test_script.UpdatePricesTool
2058
+ base_name=BaseTool
2059
+ block_count=1 cstruct_size=1 is_def=false name = 'update_prices'
2060
+ block_count=1 cstruct_size=1 is_def=false description = (
2061
+ block_count=2 cstruct_size=1 is_def=false 'Accesses the registered URL for each product in the database directly to check stock, price, and specs. Updates info or deletes if unavailable.'
2062
+ block_count=2 cstruct_size=1 is_def=false )
2063
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = UpdatePricesInput
2064
+ block_count=1 cstruct_size=1 is_def=false def _fetch_page_content(self, url: str) ->(bool, str, str):
2065
+ block_count=2 cstruct_size=1 is_def=true """
2066
+ block_count=2 cstruct_size=1 is_def=true if not url or not url.startswith('http'):
2067
+ compo c_name=url
2068
+ block_count=3 cstruct_size=1 is_def=true return False, 'Invalid URL', ''
2069
+ block_count=2 cstruct_size=1 is_def=true try:
2070
+ block_count=3 cstruct_size=1 is_def=true req = urllib.request.Request(url, headers={'User-Agent':
2071
+ compo c_name=urllib
2072
+ compo c_name=Request
2073
+ block_count=4 cstruct_size=1 is_def=true 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
2074
+ block_count=4 cstruct_size=1 is_def=true , 'Accept-Language': 'ja,en-US;q=0.9,en;q=0.8'})
2075
+ block_count=3 cstruct_size=1 is_def=true with urllib.request.urlopen(req, timeout=15) as response:
2076
+ compo c_name=urllib
2077
+ block_count=4 cstruct_size=1 is_def=true html_content = response.read().decode('utf-8', errors='ignore')
2078
+ compo c_name=response
2079
+ block_count=4 cstruct_size=1 is_def=true bot_keywords = ['ロボットではありません', 'アクセスが制限されています', 'キャプチャ',
2080
+ block_count=5 cstruct_size=1 is_def=true 'CAPTCHA', 'Are you a human?',
2081
+ block_count=5 cstruct_size=1 is_def=true 'Please verify you are a human', 'Incapsula', 'Cloudflare']
2082
+ block_count=4 cstruct_size=1 is_def=true html_lower = html_content.lower()
2083
+ block_count=4 cstruct_size=1 is_def=true for kw in bot_keywords:
2084
+ block_count=5 cstruct_size=1 is_def=true if kw.lower() in html_lower:
2085
+ compo c_name=kw
2086
+ block_count=6 cstruct_size=1 is_def=true return False, 'Bot Challenge Detected', ''
2087
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<script.*?>.*?</script>', '',
2088
+ compo c_name=re
2089
+ block_count=5 cstruct_size=1 is_def=true html_content, flags=re.DOTALL | re.IGNORECASE)
2090
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<style.*?>.*?</style>', '', clean_text,
2091
+ compo c_name=re
2092
+ block_count=5 cstruct_size=1 is_def=true flags=re.DOTALL | re.IGNORECASE)
2093
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<img[^>]+alt="([^"]*)"[^>]*>', ' \\1 ',
2094
+ compo c_name=re
2095
+ block_count=5 cstruct_size=1 is_def=true clean_text, flags=re.IGNORECASE)
2096
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub("<img[^>]+alt='([^']*)'[^>]*>", ' \\1 ',
2097
+ compo c_name=re
2098
+ block_count=5 cstruct_size=1 is_def=true clean_text, flags=re.IGNORECASE)
2099
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('<.*?>', ' ', clean_text)
2100
+ compo c_name=re
2101
+ block_count=4 cstruct_size=1 is_def=true clean_text = re.sub('\\s+', ' ', clean_text).strip()
2102
+ compo c_name=re
2103
+ block_count=4 cstruct_size=1 is_def=true if len(clean_text) > 10000:
2104
+ block_count=5 cstruct_size=1 is_def=true clean_text = clean_text[:10000]
2105
+ block_count=4 cstruct_size=1 is_def=true return True, 'Success', clean_text
2106
+ block_count=2 cstruct_size=1 is_def=true except urllib.error.HTTPError as e:
2107
+ compo c_name=urllib
2108
+ block_count=3 cstruct_size=1 is_def=true if e.code == 404:
2109
+ block_count=4 cstruct_size=1 is_def=true return False, '404 Not Found', ''
2110
+ block_count=3 cstruct_size=1 is_def=true elif e.code == 410:
2111
+ block_count=4 cstruct_size=1 is_def=true return False, '410 Gone', ''
2112
+ block_count=3 cstruct_size=1 is_def=true elif e.code in [500, 502, 503, 504]:
2113
+ block_count=4 cstruct_size=1 is_def=true return False, f'Retryable Server Error ({e.code})', ''
2114
+ block_count=3 cstruct_size=1 is_def=true elif e.code == 403:
2115
+ block_count=4 cstruct_size=1 is_def=true return False, '403 Forbidden (Possible Bot Block)', ''
2116
+ block_count=3 cstruct_size=1 is_def=true else:
2117
+ block_count=4 cstruct_size=1 is_def=true return False, f'HTTP Error {e.code}', ''
2118
+ block_count=2 cstruct_size=1 is_def=true except urllib.error.URLError as e:
2119
+ compo c_name=urllib
2120
+ block_count=3 cstruct_size=1 is_def=true return False, f'URL Error: {e.reason}', ''
2121
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
2122
+ block_count=3 cstruct_size=1 is_def=true return False, f'Connection Error: {e}', ''
2123
+ block_count=1 cstruct_size=1 is_def=true def _delete_product(self, product: dict, reason: str):
2124
+ block_count=2 cstruct_size=1 is_def=true try:
2125
+ block_count=3 cstruct_size=1 is_def=true conn = sqlite3.connect(DB_NAME)
2126
+ compo c_name=sqlite3
2127
+ block_count=3 cstruct_size=1 is_def=true cursor = conn.cursor()
2128
+ compo c_name=conn
2129
+ block_count=3 cstruct_size=1 is_def=true cursor.execute('DELETE FROM products WHERE id = ?', (product[
2130
+ compo c_name=cursor
2131
+ block_count=4 cstruct_size=1 is_def=true 'id'],))
2132
+ block_count=3 cstruct_size=1 is_def=true conn.commit()
2133
+ compo c_name=conn
2134
+ block_count=3 cstruct_size=1 is_def=true conn.close()
2135
+ compo c_name=conn
2136
+ block_count=3 cstruct_size=1 is_def=true msg = f"Deleted {product['name']} at {product['store']} ({reason})"
2137
+ block_count=3 cstruct_size=1 is_def=true print(f' {msg}')
2138
+ block_count=3 cstruct_size=1 is_def=true email_subject = f"Product Deleted: {product['name']}"
2139
+ block_count=3 cstruct_size=1 is_def=true email_body = f"""Action: Deleted (Unavailable/Not Found)
2140
+ block_count=3 cstruct_size=1 is_def=true send_email_notification(email_subject, email_body)
2141
+ block_count=3 cstruct_size=1 is_def=true return True
2142
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
2143
+ block_count=3 cstruct_size=1 is_def=true print(f' Error deleting product: {e}')
2144
+ block_count=3 cstruct_size=1 is_def=true return False
2145
+ block_count=1 cstruct_size=1 is_def=true def _run(self, query: str='', **kwargs):
2146
+ block_count=2 cstruct_size=1 is_def=true print('\n--- Starting Price Update (Direct URL Access) ---')
2147
+ block_count=2 cstruct_size=1 is_def=true products = get_all_products()
2148
+ block_count=2 cstruct_size=1 is_def=true if not products:
2149
+ block_count=3 cstruct_size=1 is_def=true return 'No products in database to update.'
2150
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
2151
+ compo c_name=os
2152
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0)
2153
+ compo c_name=ChatGoogleGenerativeAI
2154
+ block_count=2 cstruct_size=1 is_def=true updated_count = 0
2155
+ block_count=2 cstruct_size=1 is_def=true deleted_count = 0
2156
+ block_count=2 cstruct_size=1 is_def=true for p in products:
2157
+ block_count=3 cstruct_size=1 is_def=true name = p['name']
2158
+ block_count=3 cstruct_size=1 is_def=true store = p['store']
2159
+ block_count=3 cstruct_size=1 is_def=true url = p['url']
2160
+ block_count=3 cstruct_size=1 is_def=true print(f"Checking: {name} at {store} (ID: {p['id']})")
2161
+ block_count=3 cstruct_size=1 is_def=true if not url:
2162
+ block_count=4 cstruct_size=1 is_def=true print(f' [Warning] No URL for this product. Skipping.')
2163
+ block_count=4 cstruct_size=1 is_def=true continue
2164
+ block_count=3 cstruct_size=1 is_def=true success, access_reason, page_text = self._fetch_page_content(url)
2165
+ block_count=3 cstruct_size=1 is_def=true if not success:
2166
+ block_count=4 cstruct_size=1 is_def=true if ('404 Not Found' in access_reason or '410 Gone' in
2167
+ block_count=5 cstruct_size=1 is_def=true access_reason or 'Invalid URL' in access_reason):
2168
+ block_count=5 cstruct_size=1 is_def=true print(
2169
+ block_count=6 cstruct_size=1 is_def=true f' [Info] URL is dead ({access_reason}). Deleting product.'
2170
+ block_count=6 cstruct_size=1 is_def=true )
2171
+ block_count=5 cstruct_size=1 is_def=true if self._delete_product(p, access_reason):
2172
+ block_count=6 cstruct_size=1 is_def=true deleted_count += 1
2173
+ block_count=4 cstruct_size=1 is_def=true else:
2174
+ block_count=5 cstruct_size=1 is_def=true print(
2175
+ block_count=6 cstruct_size=1 is_def=true f' [Warning] Skipping update due to temporary/access error: {access_reason}'
2176
+ block_count=6 cstruct_size=1 is_def=true )
2177
+ block_count=4 cstruct_size=1 is_def=true continue
2178
+ block_count=3 cstruct_size=1 is_def=true prompt = f"""
2179
+ block_count=3 cstruct_size=1 is_def=true try:
2180
+ block_count=4 cstruct_size=1 is_def=true response = llm.invoke(prompt)
2181
+ compo c_name=llm
2182
+ block_count=4 cstruct_size=1 is_def=true content = response.content
2183
+ compo c_name=response
2184
+ block_count=4 cstruct_size=1 is_def=true if '```json' in content:
2185
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
2186
+ compo c_name=content
2187
+ block_count=4 cstruct_size=1 is_def=true elif '```' in content:
2188
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
2189
+ compo c_name=content
2190
+ block_count=4 cstruct_size=1 is_def=true content = content.strip()
2191
+ compo c_name=content
2192
+ block_count=4 cstruct_size=1 is_def=true content = re.sub('\\\\(?![/"\\\\bfnrtu])', '\\\\\\\\', content)
2193
+ compo c_name=re
2194
+ block_count=4 cstruct_size=1 is_def=true try:
2195
+ block_count=5 cstruct_size=1 is_def=true result_data = json.loads(content, strict=False)
2196
+ compo c_name=json
2197
+ block_count=4 cstruct_size=1 is_def=true except json.JSONDecodeError as e:
2198
+ block_count=5 cstruct_size=1 is_def=true print(
2199
+ block_count=6 cstruct_size=1 is_def=true f' [Warning] Failed to parse JSON: {e}. Attempting further cleanup.'
2200
+ block_count=6 cstruct_size=1 is_def=true )
2201
+ block_count=5 cstruct_size=1 is_def=true content = content.replace('\\', '')
2202
+ compo c_name=content
2203
+ block_count=5 cstruct_size=1 is_def=true result_data = json.loads(content, strict=False)
2204
+ compo c_name=json
2205
+ block_count=4 cstruct_size=1 is_def=true is_unavailable = result_data.get('is_unavailable', False)
2206
+ block_count=4 cstruct_size=1 is_def=true unavailability_reason = result_data.get('unavailability_reason'
2207
+ block_count=5 cstruct_size=1 is_def=true , 'ページ内に在庫なし・販売終了の記載あり')
2208
+ block_count=4 cstruct_size=1 is_def=true if is_unavailable:
2209
+ block_count=5 cstruct_size=1 is_def=true print(
2210
+ block_count=6 cstruct_size=1 is_def=true f' [Info] LLM determined product is unavailable. Reason: {unavailability_reason}. Deleting product.'
2211
+ block_count=6 cstruct_size=1 is_def=true )
2212
+ block_count=5 cstruct_size=1 is_def=true if self._delete_product(p, unavailability_reason):
2213
+ block_count=6 cstruct_size=1 is_def=true deleted_count += 1
2214
+ block_count=4 cstruct_size=1 is_def=true else:
2215
+ block_count=5 cstruct_size=1 is_def=true new_price = result_data.get('price', '')
2216
+ block_count=5 cstruct_size=1 is_def=true new_desc = result_data.get('description', '')
2217
+ block_count=5 cstruct_size=1 is_def=true new_model = result_data.get('model_number', '')
2218
+ block_count=5 cstruct_size=1 is_def=true new_release = result_data.get('release_date', '')
2219
+ block_count=5 cstruct_size=1 is_def=true new_ram = result_data.get('ram', '')
2220
+ block_count=5 cstruct_size=1 is_def=true new_ssd = result_data.get('ssd', '')
2221
+ block_count=5 cstruct_size=1 is_def=true if not new_price:
2222
+ block_count=6 cstruct_size=1 is_def=true print(
2223
+ block_count=7 cstruct_size=1 is_def=true f' [Warning] Could not extract price from page. Skipping update.'
2224
+ block_count=7 cstruct_size=1 is_def=true )
2225
+ block_count=6 cstruct_size=1 is_def=true continue
2226
+ block_count=5 cstruct_size=1 is_def=true final_desc = new_desc if new_desc else p['description']
2227
+ block_count=5 cstruct_size=1 is_def=true final_model = new_model if new_model else p.get(
2228
+ block_count=6 cstruct_size=1 is_def=true 'model_number', '')
2229
+ block_count=5 cstruct_size=1 is_def=true final_release = new_release if new_release else p.get(
2230
+ block_count=6 cstruct_size=1 is_def=true 'release_date', '')
2231
+ block_count=5 cstruct_size=1 is_def=true final_ram = new_ram if new_ram else p.get('ram', '')
2232
+ block_count=5 cstruct_size=1 is_def=true final_ssd = new_ssd if new_ssd else p.get('ssd', '')
2233
+ block_count=5 cstruct_size=1 is_def=true changes = []
2234
+ block_count=5 cstruct_size=1 is_def=true new_price_val = parse_price_val(new_price)
2235
+ block_count=5 cstruct_size=1 is_def=true old_price_val = parse_price_val(p['price'])
2236
+ block_count=5 cstruct_size=1 is_def=true if new_price_val != old_price_val:
2237
+ block_count=6 cstruct_size=1 is_def=true changes.append(f"Price ({p['price']} -> {new_price})")
2238
+ compo c_name=changes
2239
+ block_count=5 cstruct_size=1 is_def=true else:
2240
+ block_count=6 cstruct_size=1 is_def=true new_price = p['price']
2241
+ block_count=5 cstruct_size=1 is_def=true old_model = p.get('model_number', '')
2242
+ block_count=5 cstruct_size=1 is_def=true if not is_similar_model(final_model, old_model):
2243
+ block_count=6 cstruct_size=1 is_def=true changes.append(f'Model ({old_model} -> {final_model})')
2244
+ compo c_name=changes
2245
+ block_count=5 cstruct_size=1 is_def=true else:
2246
+ block_count=6 cstruct_size=1 is_def=true final_model = old_model
2247
+ block_count=5 cstruct_size=1 is_def=true old_release = p.get('release_date', '')
2248
+ block_count=5 cstruct_size=1 is_def=true if parse_date_val(final_release) != parse_date_val(
2249
+ block_count=6 cstruct_size=1 is_def=true old_release):
2250
+ block_count=6 cstruct_size=1 is_def=true changes.append(
2251
+ compo c_name=changes
2252
+ block_count=7 cstruct_size=1 is_def=true f'Release Date ({old_release} -> {final_release})')
2253
+ block_count=5 cstruct_size=1 is_def=true else:
2254
+ block_count=6 cstruct_size=1 is_def=true final_release = old_release
2255
+ block_count=5 cstruct_size=1 is_def=true old_ram = p.get('ram', '')
2256
+ block_count=5 cstruct_size=1 is_def=true if extract_alphanumeric(final_ram) != extract_alphanumeric(
2257
+ block_count=6 cstruct_size=1 is_def=true old_ram):
2258
+ block_count=6 cstruct_size=1 is_def=true changes.append(f'RAM ({old_ram} -> {final_ram})')
2259
+ compo c_name=changes
2260
+ block_count=5 cstruct_size=1 is_def=true else:
2261
+ block_count=6 cstruct_size=1 is_def=true final_ram = old_ram
2262
+ block_count=5 cstruct_size=1 is_def=true old_ssd = p.get('ssd', '')
2263
+ block_count=5 cstruct_size=1 is_def=true if extract_alphanumeric(final_ssd) != extract_alphanumeric(
2264
+ block_count=6 cstruct_size=1 is_def=true old_ssd):
2265
+ block_count=6 cstruct_size=1 is_def=true changes.append(f'SSD ({old_ssd} -> {final_ssd})')
2266
+ compo c_name=changes
2267
+ block_count=5 cstruct_size=1 is_def=true else:
2268
+ block_count=6 cstruct_size=1 is_def=true final_ssd = old_ssd
2269
+ block_count=5 cstruct_size=1 is_def=true if changes:
2270
+ block_count=6 cstruct_size=1 is_def=true try:
2271
+ block_count=7 cstruct_size=1 is_def=true conn = sqlite3.connect(DB_NAME)
2272
+ compo c_name=sqlite3
2273
+ block_count=7 cstruct_size=1 is_def=true cursor = conn.cursor()
2274
+ compo c_name=conn
2275
+ block_count=7 cstruct_size=1 is_def=true cursor.execute(
2276
+ compo c_name=cursor
2277
+ block_count=8 cstruct_size=1 is_def=true """
2278
+ block_count=8 cstruct_size=1 is_def=true , (new_price, final_desc, final_model,
2279
+ block_count=8 cstruct_size=1 is_def=true final_release, final_ram, final_ssd, p['id']))
2280
+ block_count=7 cstruct_size=1 is_def=true conn.commit()
2281
+ compo c_name=conn
2282
+ block_count=7 cstruct_size=1 is_def=true if cursor.rowcount > 0:
2283
+ compo c_name=cursor
2284
+ block_count=8 cstruct_size=1 is_def=true updated_count += 1
2285
+ block_count=8 cstruct_size=1 is_def=true changes_str = ', '.join(changes)
2286
+ block_count=8 cstruct_size=1 is_def=true msg = (
2287
+ block_count=9 cstruct_size=1 is_def=true f'Updated {name} at {store}. Changes: {changes_str}'
2288
+ block_count=9 cstruct_size=1 is_def=true )
2289
+ block_count=8 cstruct_size=1 is_def=true print(f' {msg}')
2290
+ block_count=8 cstruct_size=1 is_def=true email_subject = f'Product Updated: {name}'
2291
+ block_count=8 cstruct_size=1 is_def=true email_body = f"""Action: Updated Info (Direct URL Check)
2292
+ block_count=8 cstruct_size=1 is_def=true send_email_notification(email_subject,
2293
+ block_count=9 cstruct_size=1 is_def=true email_body)
2294
+ block_count=7 cstruct_size=1 is_def=true conn.close()
2295
+ compo c_name=conn
2296
+ block_count=6 cstruct_size=1 is_def=true except Exception as e:
2297
+ block_count=7 cstruct_size=1 is_def=true print(f' Error updating {name} at {store}: {e}')
2298
+ block_count=5 cstruct_size=1 is_def=true else:
2299
+ block_count=6 cstruct_size=1 is_def=true print(f' No spec/price changes for {name} at {store}.'
2300
+ block_count=7 cstruct_size=1 is_def=true )
2301
+ block_count=3 cstruct_size=1 is_def=true except Exception as e:
2302
+ block_count=4 cstruct_size=1 is_def=true print(f' Error processing LLM response for {name}: {e}')
2303
+ block_count=3 cstruct_size=1 is_def=true time.sleep(1)
2304
+ compo c_name=time
2305
+ block_count=2 cstruct_size=1 is_def=true return (
2306
+ block_count=3 cstruct_size=1 is_def=true f'Price update complete. Updated {updated_count} items, Deleted {deleted_count} unavailable items.'
2307
+ block_count=3 cstruct_size=1 is_def=true )
2308
+ block_count=0 cstruct_size=1 is_def=true class SearchProductsInput(BaseModel):
2309
+ end of test_script.UpdatePricesTool
2310
+ class_name=test_script.SearchProductsInput
2311
+ base_name=BaseModel
2312
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description=
2313
+ compo c_name=Field
2314
+ block_count=2 cstruct_size=1 is_def=false 'Natural language query to search products in the database')
2315
+ block_count=0 cstruct_size=1 is_def=false class SearchProductsTool(BaseTool):
2316
+ end of test_script.SearchProductsInput
2317
+ class_name=test_script.SearchProductsTool
2318
+ base_name=BaseTool
2319
+ block_count=1 cstruct_size=1 is_def=false name = 'search_products'
2320
+ block_count=1 cstruct_size=1 is_def=false description = (
2321
+ block_count=2 cstruct_size=1 is_def=false "Searches for products in the database using natural language queries (e.g., 'cheapest products', 'items with 16GB memory')."
2322
+ block_count=2 cstruct_size=1 is_def=false )
2323
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = SearchProductsInput
2324
+ block_count=1 cstruct_size=1 is_def=false def _run(self, query: str, **kwargs):
2325
+ block_count=2 cstruct_size=1 is_def=true print(f'\n--- Searching Database: {query} ---')
2326
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
2327
+ compo c_name=os
2328
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0)
2329
+ compo c_name=ChatGoogleGenerativeAI
2330
+ block_count=2 cstruct_size=1 is_def=true prompt = f"""
2331
+ block_count=2 cstruct_size=1 is_def=true try:
2332
+ block_count=3 cstruct_size=1 is_def=true response = llm.invoke(prompt)
2333
+ compo c_name=llm
2334
+ block_count=3 cstruct_size=1 is_def=true content = response.content.strip()
2335
+ compo c_name=response
2336
+ block_count=3 cstruct_size=1 is_def=true if '```json' in content:
2337
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
2338
+ compo c_name=content
2339
+ block_count=3 cstruct_size=1 is_def=true elif '```' in content:
2340
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
2341
+ compo c_name=content
2342
+ block_count=3 cstruct_size=1 is_def=true criteria = json.loads(content)
2343
+ compo c_name=json
2344
+ block_count=3 cstruct_size=1 is_def=true print(f' Search Criteria: {criteria}')
2345
+ block_count=3 cstruct_size=1 is_def=true all_products = get_all_products()
2346
+ block_count=3 cstruct_size=1 is_def=true filtered_products = []
2347
+ block_count=3 cstruct_size=1 is_def=true keyword_groups = criteria.get('keyword_groups', [])
2348
+ compo c_name=criteria
2349
+ block_count=3 cstruct_size=1 is_def=true exclude_keywords = criteria.get('exclude_keywords', [])
2350
+ compo c_name=criteria
2351
+ block_count=3 cstruct_size=1 is_def=true empty_fields = criteria.get('empty_fields', [])
2352
+ compo c_name=criteria
2353
+ block_count=3 cstruct_size=1 is_def=true sort_by = criteria.get('sort_by')
2354
+ compo c_name=criteria
2355
+ block_count=3 cstruct_size=1 is_def=true max_p = criteria.get('max_price')
2356
+ compo c_name=criteria
2357
+ block_count=3 cstruct_size=1 is_def=true min_p = criteria.get('min_price')
2358
+ compo c_name=criteria
2359
+ block_count=3 cstruct_size=1 is_def=true for p in all_products:
2360
+ block_count=4 cstruct_size=1 is_def=true text_to_search = (p['name'] + ' ' + (p['description'] or ''
2361
+ block_count=5 cstruct_size=1 is_def=true ) + ' ' + (p['url'] or '')).lower()
2362
+ block_count=4 cstruct_size=1 is_def=true if empty_fields:
2363
+ block_count=5 cstruct_size=1 is_def=true is_empty_match = True
2364
+ block_count=5 cstruct_size=1 is_def=true for field in empty_fields:
2365
+ block_count=6 cstruct_size=1 is_def=true val = p.get(field)
2366
+ block_count=6 cstruct_size=1 is_def=true if val and str(val).strip():
2367
+ block_count=7 cstruct_size=1 is_def=true is_empty_match = False
2368
+ block_count=7 cstruct_size=1 is_def=true break
2369
+ block_count=5 cstruct_size=1 is_def=true if not is_empty_match:
2370
+ block_count=6 cstruct_size=1 is_def=true continue
2371
+ block_count=4 cstruct_size=1 is_def=true if exclude_keywords:
2372
+ block_count=5 cstruct_size=1 is_def=true should_exclude = False
2373
+ block_count=5 cstruct_size=1 is_def=true for k in exclude_keywords:
2374
+ block_count=6 cstruct_size=1 is_def=true if k.lower() in text_to_search:
2375
+ block_count=7 cstruct_size=1 is_def=true should_exclude = True
2376
+ block_count=7 cstruct_size=1 is_def=true break
2377
+ block_count=5 cstruct_size=1 is_def=true if should_exclude:
2378
+ block_count=6 cstruct_size=1 is_def=true continue
2379
+ block_count=4 cstruct_size=1 is_def=true if keyword_groups:
2380
+ block_count=5 cstruct_size=1 is_def=true all_groups_match = True
2381
+ block_count=5 cstruct_size=1 is_def=true for group in keyword_groups:
2382
+ block_count=6 cstruct_size=1 is_def=true group_match = False
2383
+ block_count=6 cstruct_size=1 is_def=true for k in group:
2384
+ block_count=7 cstruct_size=1 is_def=true if k.lower() in text_to_search:
2385
+ block_count=8 cstruct_size=1 is_def=true group_match = True
2386
+ block_count=8 cstruct_size=1 is_def=true break
2387
+ block_count=6 cstruct_size=1 is_def=true if not group_match:
2388
+ block_count=7 cstruct_size=1 is_def=true all_groups_match = False
2389
+ block_count=7 cstruct_size=1 is_def=true break
2390
+ block_count=5 cstruct_size=1 is_def=true if not all_groups_match:
2391
+ block_count=6 cstruct_size=1 is_def=true continue
2392
+ block_count=4 cstruct_size=1 is_def=true price_val = parse_price_val(p['price'])
2393
+ block_count=4 cstruct_size=1 is_def=true if max_p is not None and price_val > max_p:
2394
+ block_count=5 cstruct_size=1 is_def=true continue
2395
+ block_count=4 cstruct_size=1 is_def=true if min_p is not None and price_val < min_p:
2396
+ block_count=5 cstruct_size=1 is_def=true continue
2397
+ block_count=4 cstruct_size=1 is_def=true p['price_val'] = price_val
2398
+ block_count=4 cstruct_size=1 is_def=true filtered_products.append(p)
2399
+ block_count=3 cstruct_size=1 is_def=true if sort_by == 'price_asc':
2400
+ block_count=4 cstruct_size=1 is_def=true filtered_products.sort(key=lambda x: x['price_val'])
2401
+ block_count=3 cstruct_size=1 is_def=true elif sort_by == 'price_desc':
2402
+ block_count=4 cstruct_size=1 is_def=true filtered_products.sort(key=lambda x: x['price_val'],
2403
+ block_count=5 cstruct_size=1 is_def=true reverse=True)
2404
+ block_count=3 cstruct_size=1 is_def=true if not filtered_products:
2405
+ block_count=4 cstruct_size=1 is_def=true return 'No products found matching your criteria.'
2406
+ block_count=3 cstruct_size=1 is_def=true result_str = f'Found {len(filtered_products)} products:\n'
2407
+ block_count=3 cstruct_size=1 is_def=true for p in filtered_products[:10]:
2408
+ block_count=4 cstruct_size=1 is_def=true result_str += (
2409
+ block_count=5 cstruct_size=1 is_def=true f"- [ID: {p['id']}] {p['name']} ({p['price']}) @ {p['store']}\n"
2410
+ block_count=5 cstruct_size=1 is_def=true )
2411
+ block_count=4 cstruct_size=1 is_def=true if p['description']:
2412
+ block_count=5 cstruct_size=1 is_def=true result_str += f" Desc: {p['description'][:100]}...\n"
2413
+ block_count=4 cstruct_size=1 is_def=true if p['url']:
2414
+ block_count=5 cstruct_size=1 is_def=true result_str += f" URL: {p['url']}\n"
2415
+ block_count=4 cstruct_size=1 is_def=true result_str += '\n'
2416
+ block_count=3 cstruct_size=1 is_def=true return result_str
2417
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
2418
+ block_count=3 cstruct_size=1 is_def=true return f'Error executing search: {e}'
2419
+ block_count=0 cstruct_size=1 is_def=true class FindSimilarProductsInput(BaseModel):
2420
+ end of test_script.SearchProductsTool
2421
+ class_name=test_script.FindSimilarProductsInput
2422
+ base_name=BaseModel
2423
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description='Optional query', default='')
2424
+ compo c_name=Field
2425
+ block_count=0 cstruct_size=1 is_def=false class FindSimilarProductsTool(BaseTool):
2426
+ end of test_script.FindSimilarProductsInput
2427
+ class_name=test_script.FindSimilarProductsTool
2428
+ base_name=BaseTool
2429
+ block_count=1 cstruct_size=1 is_def=false name = 'find_similar_products'
2430
+ block_count=1 cstruct_size=1 is_def=false description = (
2431
+ block_count=2 cstruct_size=1 is_def=false 'Searches for similar products to those in the database and adds the best ones if found.'
2432
+ block_count=2 cstruct_size=1 is_def=false )
2433
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = FindSimilarProductsInput
2434
+ block_count=1 cstruct_size=1 is_def=false agent_logs: str = ''
2435
+ block_count=1 cstruct_size=1 is_def=false def _run(self, query: str='', **kwargs):
2436
+ block_count=2 cstruct_size=1 is_def=true print('\n--- Starting Similar Product Search ---')
2437
+ block_count=2 cstruct_size=1 is_def=true products = get_all_products()
2438
+ block_count=2 cstruct_size=1 is_def=true if not products:
2439
+ block_count=3 cstruct_size=1 is_def=true return 'No products in database to base search on.'
2440
+ block_count=2 cstruct_size=1 is_def=true target_products = []
2441
+ block_count=2 cstruct_size=1 is_def=true if query:
2442
+ block_count=3 cstruct_size=1 is_def=true print(f'Filtering products with query: {query}')
2443
+ block_count=3 cstruct_size=1 is_def=true query_lower = query.lower()
2444
+ compo c_name=query
2445
+ block_count=3 cstruct_size=1 is_def=true for p in products:
2446
+ block_count=4 cstruct_size=1 is_def=true if query_lower in p['name'].lower() or p['description'
2447
+ block_count=5 cstruct_size=1 is_def=true ] and query_lower in p['description'].lower():
2448
+ block_count=5 cstruct_size=1 is_def=true target_products.append(p)
2449
+ block_count=2 cstruct_size=1 is_def=true else:
2450
+ block_count=3 cstruct_size=1 is_def=true target_products = products
2451
+ block_count=2 cstruct_size=1 is_def=true if not target_products:
2452
+ block_count=3 cstruct_size=1 is_def=true return f"No products found matching query '{query}'."
2453
+ block_count=2 cstruct_size=1 is_def=true unique_products = {}
2454
+ block_count=2 cstruct_size=1 is_def=true for p in target_products:
2455
+ block_count=3 cstruct_size=1 is_def=true if p['name'] not in unique_products:
2456
+ block_count=4 cstruct_size=1 is_def=true unique_products[p['name']] = p
2457
+ block_count=2 cstruct_size=1 is_def=true target_names = list(unique_products.keys())
2458
+ block_count=2 cstruct_size=1 is_def=true print(
2459
+ block_count=3 cstruct_size=1 is_def=true f'Found {len(target_names)} target products to find similar items for.'
2460
+ block_count=3 cstruct_size=1 is_def=true )
2461
+ block_count=2 cstruct_size=1 is_def=true logs_context = ''
2462
+ block_count=2 cstruct_size=1 is_def=true if self.agent_logs:
2463
+ compo c_name=self
2464
+ block_count=3 cstruct_size=1 is_def=true logs_context = f'\n参考情報 (過去の検索履歴):\n{self.agent_logs}\n'
2465
+ block_count=2 cstruct_size=1 is_def=true search = get_search_tool_func()
2466
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
2467
+ compo c_name=os
2468
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0)
2469
+ compo c_name=ChatGoogleGenerativeAI
2470
+ block_count=2 cstruct_size=1 is_def=true save_tool = SaveProductTool()
2471
+ compo c_name=SaveProductTool
2472
+ block_count=2 cstruct_size=1 is_def=true cached_similar_items = []
2473
+ block_count=2 cstruct_size=1 is_def=true max_targets = 5
2474
+ block_count=2 cstruct_size=1 is_def=true if len(target_names) > max_targets:
2475
+ block_count=3 cstruct_size=1 is_def=true print(f'Limiting search to first {max_targets} products.')
2476
+ block_count=3 cstruct_size=1 is_def=true target_names = target_names[:max_targets]
2477
+ block_count=2 cstruct_size=1 is_def=true for name in target_names:
2478
+ block_count=3 cstruct_size=1 is_def=true product_data = unique_products[name]
2479
+ block_count=3 cstruct_size=1 is_def=true description = product_data.get('description', '')
2480
+ block_count=3 cstruct_size=1 is_def=true print(f'Searching for similar items to: {name}')
2481
+ block_count=3 cstruct_size=1 is_def=true search_query = f'{name} 類似商品 おすすめ 比較 スペック'
2482
+ block_count=3 cstruct_size=1 is_def=true try:
2483
+ block_count=4 cstruct_size=1 is_def=true search_results = search.run(search_query)
2484
+ compo c_name=search
2485
+ block_count=3 cstruct_size=1 is_def=true except Exception as e:
2486
+ block_count=4 cstruct_size=1 is_def=true print(f'Search failed for {name}: {e}')
2487
+ block_count=4 cstruct_size=1 is_def=true continue
2488
+ block_count=3 cstruct_size=1 is_def=true prompt = f"""
2489
+ block_count=3 cstruct_size=1 is_def=true try:
2490
+ block_count=4 cstruct_size=1 is_def=true response = llm.invoke(prompt)
2491
+ compo c_name=llm
2492
+ block_count=4 cstruct_size=1 is_def=true content = response.content
2493
+ compo c_name=response
2494
+ block_count=4 cstruct_size=1 is_def=true if '```json' in content:
2495
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
2496
+ compo c_name=content
2497
+ block_count=4 cstruct_size=1 is_def=true elif '```' in content:
2498
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
2499
+ compo c_name=content
2500
+ block_count=4 cstruct_size=1 is_def=true items = json.loads(content)
2501
+ compo c_name=json
2502
+ block_count=4 cstruct_size=1 is_def=true if isinstance(items, list):
2503
+ block_count=5 cstruct_size=1 is_def=true for item in items:
2504
+ block_count=6 cstruct_size=1 is_def=true if item.get('name') == name:
2505
+ compo c_name=item
2506
+ block_count=7 cstruct_size=1 is_def=true continue
2507
+ block_count=6 cstruct_size=1 is_def=true cached_similar_items.append(item)
2508
+ block_count=6 cstruct_size=1 is_def=true print(
2509
+ block_count=7 cstruct_size=1 is_def=true f" Cached: {item.get('name')} ({item.get('price')})"
2510
+ block_count=7 cstruct_size=1 is_def=true )
2511
+ block_count=3 cstruct_size=1 is_def=true except Exception as e:
2512
+ block_count=4 cstruct_size=1 is_def=true print(f'Error processing similar items for {name}: {e}')
2513
+ block_count=3 cstruct_size=1 is_def=true time.sleep(1)
2514
+ compo c_name=time
2515
+ block_count=2 cstruct_size=1 is_def=true if not cached_similar_items:
2516
+ block_count=3 cstruct_size=1 is_def=true return 'No similar products found.'
2517
+ block_count=2 cstruct_size=1 is_def=true print(
2518
+ block_count=3 cstruct_size=1 is_def=true f'\nCached {len(cached_similar_items)} items. Selecting top 3 recommendations...'
2519
+ block_count=3 cstruct_size=1 is_def=true )
2520
+ block_count=2 cstruct_size=1 is_def=true selection_prompt = f"""
2521
+ block_count=2 cstruct_size=1 is_def=true added_count = 0
2522
+ block_count=2 cstruct_size=1 is_def=true try:
2523
+ block_count=3 cstruct_size=1 is_def=true response = llm.invoke(selection_prompt)
2524
+ compo c_name=llm
2525
+ block_count=3 cstruct_size=1 is_def=true content = response.content
2526
+ compo c_name=response
2527
+ block_count=3 cstruct_size=1 is_def=true if '```json' in content:
2528
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
2529
+ compo c_name=content
2530
+ block_count=3 cstruct_size=1 is_def=true elif '```' in content:
2531
+ block_count=4 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
2532
+ compo c_name=content
2533
+ block_count=3 cstruct_size=1 is_def=true top_picks = json.loads(content)
2534
+ compo c_name=json
2535
+ block_count=3 cstruct_size=1 is_def=true if isinstance(top_picks, list):
2536
+ block_count=4 cstruct_size=1 is_def=true for item in top_picks:
2537
+ block_count=5 cstruct_size=1 is_def=true print(f" Saving recommendation: {item.get('name')}")
2538
+ block_count=5 cstruct_size=1 is_def=true res = save_tool._run(name=item.get('name'), store=item.
2539
+ block_count=6 cstruct_size=1 is_def=true get('store', 'Unknown'), price=item.get('price'),
2540
+ block_count=6 cstruct_size=1 is_def=true url=item.get('url', ''), description=item.get(
2541
+ block_count=6 cstruct_size=1 is_def=true 'description', ''), model_number=item.get(
2542
+ block_count=6 cstruct_size=1 is_def=true 'model_number', ''), release_date=item.get(
2543
+ block_count=6 cstruct_size=1 is_def=true 'release_date', ''))
2544
+ block_count=5 cstruct_size=1 is_def=true print(f' -> {res}')
2545
+ block_count=5 cstruct_size=1 is_def=true added_count += 1
2546
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
2547
+ block_count=3 cstruct_size=1 is_def=true return f'Error selecting top recommendations: {e}'
2548
+ block_count=2 cstruct_size=1 is_def=true return (
2549
+ block_count=3 cstruct_size=1 is_def=true f'Similar product search complete. Added {added_count} recommended items.'
2550
+ block_count=3 cstruct_size=1 is_def=true )
2551
+ block_count=0 cstruct_size=1 is_def=true class CompareProductsInput(BaseModel):
2552
+ end of test_script.FindSimilarProductsTool
2553
+ class_name=test_script.CompareProductsInput
2554
+ base_name=BaseModel
2555
+ block_count=1 cstruct_size=1 is_def=false query: str = Field(description=
2556
+ compo c_name=Field
2557
+ block_count=2 cstruct_size=1 is_def=false "Optional category or query to filter products for comparison (e.g., 'laptop', 'monitor')."
2558
+ block_count=2 cstruct_size=1 is_def=false , default='')
2559
+ block_count=0 cstruct_size=1 is_def=false class CompareProductsTool(BaseTool):
2560
+ end of test_script.CompareProductsInput
2561
+ class_name=test_script.CompareProductsTool
2562
+ base_name=BaseTool
2563
+ block_count=1 cstruct_size=1 is_def=false name = 'compare_products'
2564
+ block_count=1 cstruct_size=1 is_def=false description = (
2565
+ block_count=2 cstruct_size=1 is_def=false 'Generates a comparison table of products (e.g. RAM, SSD, Price) and ranks them by recommendation. Saves the result as JSON.'
2566
+ block_count=2 cstruct_size=1 is_def=false )
2567
+ block_count=1 cstruct_size=1 is_def=false args_schema: Type[BaseModel] = CompareProductsInput
2568
+ block_count=1 cstruct_size=1 is_def=false def _run(self, query: str='', **kwargs):
2569
+ block_count=2 cstruct_size=1 is_def=true print(f'\n--- Generating Product Comparison: {query} ---')
2570
+ block_count=2 cstruct_size=1 is_def=true products = get_all_products()
2571
+ block_count=2 cstruct_size=1 is_def=true if not products:
2572
+ block_count=3 cstruct_size=1 is_def=true return 'No products found in database.'
2573
+ block_count=2 cstruct_size=1 is_def=true target_products = []
2574
+ block_count=2 cstruct_size=1 is_def=true if query:
2575
+ block_count=3 cstruct_size=1 is_def=true query_lower = query.lower()
2576
+ compo c_name=query
2577
+ block_count=3 cstruct_size=1 is_def=true for p in products:
2578
+ block_count=4 cstruct_size=1 is_def=true text = (p['name'] + ' ' + (p['description'] or '')).lower()
2579
+ block_count=4 cstruct_size=1 is_def=true if query_lower in text:
2580
+ block_count=5 cstruct_size=1 is_def=true target_products.append(p)
2581
+ block_count=2 cstruct_size=1 is_def=true else:
2582
+ block_count=3 cstruct_size=1 is_def=true target_products = products
2583
+ block_count=2 cstruct_size=1 is_def=true if not target_products:
2584
+ block_count=3 cstruct_size=1 is_def=true return f"No products found matching '{query}'."
2585
+ block_count=2 cstruct_size=1 is_def=true CHUNK_SIZE = 5
2586
+ block_count=2 cstruct_size=1 is_def=true print(
2587
+ block_count=3 cstruct_size=1 is_def=true f'Step 1: Extracting specs from {len(target_products)} products in chunks of {CHUNK_SIZE}...'
2588
+ block_count=3 cstruct_size=1 is_def=true )
2589
+ block_count=2 cstruct_size=1 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
2590
+ compo c_name=os
2591
+ block_count=2 cstruct_size=1 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0,
2592
+ compo c_name=ChatGoogleGenerativeAI
2593
+ block_count=3 cstruct_size=1 is_def=true max_output_tokens=8192)
2594
+ block_count=2 cstruct_size=1 is_def=true extracted_specs = []
2595
+ block_count=2 cstruct_size=1 is_def=true try:
2596
+ block_count=3 cstruct_size=1 is_def=true for i in range(0, len(target_products), CHUNK_SIZE):
2597
+ block_count=4 cstruct_size=1 is_def=true chunk = target_products[i:i + CHUNK_SIZE]
2598
+ block_count=4 cstruct_size=1 is_def=true print(
2599
+ block_count=5 cstruct_size=1 is_def=true f' Processing chunk {i // CHUNK_SIZE + 1} ({len(chunk)} items)...'
2600
+ block_count=5 cstruct_size=1 is_def=true )
2601
+ block_count=4 cstruct_size=1 is_def=true prompt_extract = f"""
2602
+ block_count=4 cstruct_size=1 is_def=true response = llm.invoke(prompt_extract)
2603
+ compo c_name=llm
2604
+ block_count=4 cstruct_size=1 is_def=true content = response.content
2605
+ compo c_name=response
2606
+ block_count=4 cstruct_size=1 is_def=true if '```json' in content:
2607
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```json')[1].split('```')[0]
2608
+ compo c_name=content
2609
+ block_count=4 cstruct_size=1 is_def=true elif '```' in content:
2610
+ block_count=5 cstruct_size=1 is_def=true content = content.split('```')[1].split('```')[0]
2611
+ compo c_name=content
2612
+ block_count=4 cstruct_size=1 is_def=true content = content.strip()
2613
+ compo c_name=content
2614
+ block_count=4 cstruct_size=1 is_def=true try:
2615
+ block_count=5 cstruct_size=1 is_def=true chunk_data = json.loads(content)
2616
+ compo c_name=json
2617
+ block_count=4 cstruct_size=1 is_def=true except json.JSONDecodeError as e:
2618
+ block_count=5 cstruct_size=1 is_def=true print(
2619
+ block_count=6 cstruct_size=1 is_def=true f' [Warning] Failed to parse JSON in chunk {i // CHUNK_SIZE + 1}. Attempting aggressive recovery.'
2620
+ block_count=6 cstruct_size=1 is_def=true )
2621
+ block_count=5 cstruct_size=1 is_def=true print(f' Error detail: {e}')
2622
+ block_count=5 cstruct_size=1 is_def=true try:
2623
+ block_count=6 cstruct_size=1 is_def=true start_idx = content.find('[')
2624
+ compo c_name=content
2625
+ block_count=6 cstruct_size=1 is_def=true if start_idx != -1:
2626
+ block_count=7 cstruct_size=1 is_def=true clean_content = content[start_idx:]
2627
+ block_count=7 cstruct_size=1 is_def=true if not clean_content.rstrip().endswith(']'):
2628
+ block_count=8 cstruct_size=1 is_def=true last_brace = clean_content.rfind('}')
2629
+ block_count=8 cstruct_size=1 is_def=true if last_brace != -1:
2630
+ block_count=9 cstruct_size=1 is_def=true clean_content = clean_content[:
2631
+ block_count=10 cstruct_size=1 is_def=true last_brace + 1] + ']'
2632
+ block_count=8 cstruct_size=1 is_def=true else:
2633
+ block_count=9 cstruct_size=1 is_def=true clean_content += ']'
2634
+ block_count=7 cstruct_size=1 is_def=true chunk_data = json.loads(clean_content)
2635
+ compo c_name=json
2636
+ block_count=6 cstruct_size=1 is_def=true else:
2637
+ block_count=7 cstruct_size=1 is_def=true raise ValueError('No JSON list found.')
2638
+ compo c_name=ValueError
2639
+ block_count=5 cstruct_size=1 is_def=true except Exception as e2:
2640
+ block_count=6 cstruct_size=1 is_def=true print(
2641
+ block_count=7 cstruct_size=1 is_def=true f' [Error] Could not recover JSON even after aggressive repair: {e2}'
2642
+ block_count=7 cstruct_size=1 is_def=true )
2643
+ block_count=6 cstruct_size=1 is_def=true continue
2644
+ block_count=4 cstruct_size=1 is_def=true if isinstance(chunk_data, list):
2645
+ block_count=5 cstruct_size=1 is_def=true extracted_specs.extend(chunk_data)
2646
+ block_count=4 cstruct_size=1 is_def=true time.sleep(1)
2647
+ compo c_name=time
2648
+ block_count=3 cstruct_size=1 is_def=true print(
2649
+ block_count=4 cstruct_size=1 is_def=true f'Step 2: Ranking {len(extracted_specs)} products based on extracted specs...'
2650
+ block_count=4 cstruct_size=1 is_def=true )
2651
+ block_count=3 cstruct_size=1 is_def=true prompt_rank = f"""
2652
+ block_count=3 cstruct_size=1 is_def=true response_rank = llm.invoke(prompt_rank)
2653
+ compo c_name=llm
2654
+ block_count=3 cstruct_size=1 is_def=true content_rank = response_rank.content
2655
+ block_count=3 cstruct_size=1 is_def=true if '```json' in content_rank:
2656
+ block_count=4 cstruct_size=1 is_def=true content_rank = content_rank.split('```json')[1].split('```')[0]
2657
+ block_count=3 cstruct_size=1 is_def=true elif '```' in content_rank:
2658
+ block_count=4 cstruct_size=1 is_def=true content_rank = content_rank.split('```')[1].split('```')[0]
2659
+ block_count=3 cstruct_size=1 is_def=true content_rank = content_rank.strip()
2660
+ block_count=3 cstruct_size=1 is_def=true try:
2661
+ block_count=4 cstruct_size=1 is_def=true ranking_data = json.loads(content_rank)
2662
+ compo c_name=json
2663
+ block_count=3 cstruct_size=1 is_def=true except json.JSONDecodeError as e:
2664
+ block_count=4 cstruct_size=1 is_def=true print(
2665
+ block_count=5 cstruct_size=1 is_def=true f' [Warning] Failed to parse ranking JSON. Error: {e}. Attempting recovery.'
2666
+ block_count=5 cstruct_size=1 is_def=true )
2667
+ block_count=4 cstruct_size=1 is_def=true start_idx = content_rank.find('[')
2668
+ block_count=4 cstruct_size=1 is_def=true if start_idx != -1:
2669
+ block_count=5 cstruct_size=1 is_def=true clean_content = content_rank[start_idx:]
2670
+ block_count=5 cstruct_size=1 is_def=true if not clean_content.rstrip().endswith(']'):
2671
+ block_count=6 cstruct_size=1 is_def=true last_brace = clean_content.rfind('}')
2672
+ block_count=6 cstruct_size=1 is_def=true if last_brace != -1:
2673
+ block_count=7 cstruct_size=1 is_def=true clean_content = clean_content[:last_brace + 1
2674
+ block_count=8 cstruct_size=1 is_def=true ] + ']'
2675
+ block_count=6 cstruct_size=1 is_def=true else:
2676
+ block_count=7 cstruct_size=1 is_def=true clean_content += ']'
2677
+ block_count=5 cstruct_size=1 is_def=true try:
2678
+ block_count=6 cstruct_size=1 is_def=true ranking_data = json.loads(clean_content)
2679
+ compo c_name=json
2680
+ block_count=5 cstruct_size=1 is_def=true except Exception as e2:
2681
+ block_count=6 cstruct_size=1 is_def=true print(
2682
+ block_count=7 cstruct_size=1 is_def=true f' [Error] Could not recover ranking JSON: {e2}'
2683
+ block_count=7 cstruct_size=1 is_def=true )
2684
+ block_count=6 cstruct_size=1 is_def=true return (
2685
+ block_count=7 cstruct_size=1 is_def=true 'Error generating comparison: Invalid JSON format returned by LLM.'
2686
+ block_count=7 cstruct_size=1 is_def=true )
2687
+ block_count=4 cstruct_size=1 is_def=true else:
2688
+ block_count=5 cstruct_size=1 is_def=true return (
2689
+ block_count=6 cstruct_size=1 is_def=true 'Error generating comparison: Invalid JSON format returned by LLM.'
2690
+ block_count=6 cstruct_size=1 is_def=true )
2691
+ block_count=3 cstruct_size=1 is_def=true spec_dict = {item['id']: item for item in extracted_specs}
2692
+ block_count=3 cstruct_size=1 is_def=true target_dict = {item['id']: item for item in target_products}
2693
+ block_count=3 cstruct_size=1 is_def=true final_comparison_data = []
2694
+ block_count=3 cstruct_size=1 is_def=true for rank_item in ranking_data:
2695
+ block_count=4 cstruct_size=1 is_def=true p_id = rank_item.get('id')
2696
+ block_count=4 cstruct_size=1 is_def=true if p_id in spec_dict:
2697
+ block_count=5 cstruct_size=1 is_def=true merged = spec_dict[p_id].copy()
2698
+ block_count=5 cstruct_size=1 is_def=true merged['rank'] = rank_item.get('rank')
2699
+ block_count=5 cstruct_size=1 is_def=true merged['note'] = rank_item.get('note', '')
2700
+ block_count=5 cstruct_size=1 is_def=true if p_id in target_dict:
2701
+ block_count=6 cstruct_size=1 is_def=true merged['updated_at'] = target_dict[p_id].get(
2702
+ block_count=7 cstruct_size=1 is_def=true 'updated_at', '')
2703
+ block_count=5 cstruct_size=1 is_def=true final_comparison_data.append(merged)
2704
+ block_count=3 cstruct_size=1 is_def=true final_comparison_data.sort(key=lambda x: x.get('rank', 9999))
2705
+ block_count=3 cstruct_size=1 is_def=true for item in final_comparison_data:
2706
+ block_count=4 cstruct_size=1 is_def=true if 'model_number' not in item or item['model_number'] is None:
2707
+ block_count=5 cstruct_size=1 is_def=true item['model_number'] = ''
2708
+ block_count=4 cstruct_size=1 is_def=true if 'release_date' not in item or item['release_date'] is None:
2709
+ block_count=5 cstruct_size=1 is_def=true item['release_date'] = ''
2710
+ block_count=3 cstruct_size=1 is_def=true from datetime import datetime
2711
+ block_count=3 cstruct_size=1 is_def=true output_data = {'updated_at': datetime.now().strftime(
2712
+ compo c_name=datetime
2713
+ block_count=4 cstruct_size=1 is_def=true '%Y-%m-%d %H:%M:%S'), 'products': final_comparison_data}
2714
+ block_count=3 cstruct_size=1 is_def=true output_file = 'product_comparison.json'
2715
+ block_count=3 cstruct_size=1 is_def=true with open(output_file, 'w', encoding='utf-8') as f:
2716
+ block_count=4 cstruct_size=1 is_def=true json.dump(output_data, f, ensure_ascii=False, indent=2)
2717
+ compo c_name=json
2718
+ block_count=3 cstruct_size=1 is_def=true return (
2719
+ block_count=4 cstruct_size=1 is_def=true f'Comparison table generated and saved to {output_file}. Included {len(final_comparison_data)} ranked items.'
2720
+ block_count=4 cstruct_size=1 is_def=true )
2721
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
2722
+ block_count=3 cstruct_size=1 is_def=true return f'Error generating comparison: {e}'
2723
+ block_count=0 cstruct_size=1 is_def=true def display_products():
2724
+ end of test_script.CompareProductsTool
2725
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
2726
+ compo c_name=sqlite3
2727
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
2728
+ compo c_name=conn
2729
+ block_count=1 cstruct_size=0 is_def=true cursor.execute('SELECT id, name, store, price FROM products')
2730
+ compo c_name=cursor
2731
+ block_count=1 cstruct_size=0 is_def=true rows = cursor.fetchall()
2732
+ compo c_name=cursor
2733
+ block_count=1 cstruct_size=0 is_def=true conn.close()
2734
+ compo c_name=conn
2735
+ block_count=1 cstruct_size=0 is_def=true if not rows:
2736
+ block_count=2 cstruct_size=0 is_def=true print('\nNo products saved yet.')
2737
+ block_count=2 cstruct_size=0 is_def=true return
2738
+ block_count=1 cstruct_size=0 is_def=true def parse_price_sort(p_str):
2739
+ block_count=2 cstruct_size=0 is_def=true nums = re.findall('\\d+', str(p_str).replace(',', ''))
2740
+ compo c_name=re
2741
+ block_count=2 cstruct_size=0 is_def=true return int(''.join(nums)) if nums else float('inf')
2742
+ block_count=1 cstruct_size=0 is_def=true rows.sort(key=lambda x: (x[1], parse_price_sort(x[3])))
2743
+ compo c_name=rows
2744
+ block_count=1 cstruct_size=0 is_def=false print('\n--- All Saved Products ---')
2745
+ block_count=1 cstruct_size=0 is_def=false print(f"{'ID':<5} {'Name':<40} {'Store':<20} {'Price':<15}")
2746
+ block_count=1 cstruct_size=0 is_def=false print('-' * 85)
2747
+ block_count=1 cstruct_size=0 is_def=false for row in rows:
2748
+ block_count=2 cstruct_size=0 is_def=false name_disp = row[1][:37] + '..' if len(row[1]) > 39 else row[1]
2749
+ block_count=2 cstruct_size=0 is_def=false store_disp = row[2][:18] + '..' if len(row[2]) > 20 else row[2]
2750
+ block_count=2 cstruct_size=0 is_def=false print(f'{row[0]:<5} {name_disp:<40} {store_disp:<20} {row[3]:<15}')
2751
+ block_count=1 cstruct_size=0 is_def=false print('-' * 85)
2752
+ block_count=0 cstruct_size=0 is_def=false def show_product_details(product_id):
2753
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
2754
+ compo c_name=sqlite3
2755
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
2756
+ compo c_name=conn
2757
+ block_count=1 cstruct_size=0 is_def=true cursor.execute(
2758
+ compo c_name=cursor
2759
+ block_count=2 cstruct_size=0 is_def=true 'SELECT id, name, store, price, url, description, model_number, release_date FROM products WHERE id = ?'
2760
+ block_count=2 cstruct_size=0 is_def=true , (product_id,))
2761
+ block_count=1 cstruct_size=0 is_def=true row = cursor.fetchone()
2762
+ compo c_name=cursor
2763
+ block_count=1 cstruct_size=0 is_def=true conn.close()
2764
+ compo c_name=conn
2765
+ block_count=1 cstruct_size=0 is_def=true if not row:
2766
+ block_count=2 cstruct_size=0 is_def=true print(f'\nProduct with ID {product_id} not found.')
2767
+ block_count=2 cstruct_size=0 is_def=true return
2768
+ block_count=1 cstruct_size=0 is_def=true print('\n--- Product Details ---')
2769
+ block_count=1 cstruct_size=0 is_def=true print(f'ID: {row[0]}')
2770
+ block_count=1 cstruct_size=0 is_def=true print(f'Name: {row[1]}')
2771
+ block_count=1 cstruct_size=0 is_def=true print(f'Store: {row[2]}')
2772
+ block_count=1 cstruct_size=0 is_def=true print(f'Price: {row[3]}')
2773
+ block_count=1 cstruct_size=0 is_def=true print(f"Model: {row[6] if len(row) > 6 else ''}")
2774
+ block_count=1 cstruct_size=0 is_def=true print(f"Release: {row[7] if len(row) > 7 else ''}")
2775
+ block_count=1 cstruct_size=0 is_def=true print(f'URL: {row[4]}')
2776
+ block_count=1 cstruct_size=0 is_def=true print(f'Description: {row[5]}')
2777
+ block_count=1 cstruct_size=0 is_def=true print('-' * 30)
2778
+ block_count=0 cstruct_size=0 is_def=true def delete_product_records(identifiers: List[str]):
2779
+ block_count=1 cstruct_size=0 is_def=true conn = sqlite3.connect(DB_NAME)
2780
+ compo c_name=sqlite3
2781
+ block_count=1 cstruct_size=0 is_def=true cursor = conn.cursor()
2782
+ compo c_name=conn
2783
+ block_count=1 cstruct_size=0 is_def=true deleted_count = 0
2784
+ block_count=1 cstruct_size=0 is_def=true errors = []
2785
+ block_count=1 cstruct_size=0 is_def=true print(f'\nAttempting to delete: {identifiers}')
2786
+ block_count=1 cstruct_size=0 is_def=true for identifier in identifiers:
2787
+ block_count=2 cstruct_size=0 is_def=true try:
2788
+ block_count=3 cstruct_size=0 is_def=true if identifier.isdigit():
2789
+ compo c_name=identifier
2790
+ block_count=4 cstruct_size=0 is_def=true cursor.execute('DELETE FROM products WHERE id = ?', (int(
2791
+ compo c_name=cursor
2792
+ block_count=5 cstruct_size=0 is_def=true identifier),))
2793
+ block_count=3 cstruct_size=0 is_def=true else:
2794
+ block_count=4 cstruct_size=0 is_def=true cursor.execute('DELETE FROM products WHERE name = ?', (
2795
+ compo c_name=cursor
2796
+ block_count=5 cstruct_size=0 is_def=true identifier,))
2797
+ block_count=3 cstruct_size=0 is_def=true if cursor.rowcount > 0:
2798
+ compo c_name=cursor
2799
+ block_count=4 cstruct_size=0 is_def=true deleted_count += cursor.rowcount
2800
+ compo c_name=cursor
2801
+ block_count=4 cstruct_size=0 is_def=true print(f' Deleted: {identifier}')
2802
+ block_count=3 cstruct_size=0 is_def=true else:
2803
+ block_count=4 cstruct_size=0 is_def=true errors.append(f'No product found with ID/Name: {identifier}')
2804
+ compo c_name=errors
2805
+ block_count=2 cstruct_size=0 is_def=true except Exception as e:
2806
+ block_count=3 cstruct_size=0 is_def=true errors.append(f'Error deleting {identifier}: {e}')
2807
+ compo c_name=errors
2808
+ block_count=1 cstruct_size=0 is_def=true conn.commit()
2809
+ compo c_name=conn
2810
+ block_count=1 cstruct_size=0 is_def=true conn.close()
2811
+ compo c_name=conn
2812
+ block_count=1 cstruct_size=0 is_def=true print(f'\nTotal deleted: {deleted_count}')
2813
+ block_count=1 cstruct_size=0 is_def=true if errors:
2814
+ block_count=2 cstruct_size=0 is_def=true print('Errors/Warnings:')
2815
+ block_count=2 cstruct_size=0 is_def=true for err in errors:
2816
+ block_count=3 cstruct_size=0 is_def=true print(f' - {err}')
2817
+ block_count=0 cstruct_size=0 is_def=true def main():
2818
+ block_count=1 cstruct_size=0 is_def=true if not os.getenv('GOOGLE_API_KEY'):
2819
+ compo c_name=os
2820
+ block_count=2 cstruct_size=0 is_def=true print('Error: GOOGLE_API_KEY not found.')
2821
+ block_count=2 cstruct_size=0 is_def=true return
2822
+ block_count=1 cstruct_size=0 is_def=true provider = os.getenv('SEARCH_PROVIDER', 'serpapi')
2823
+ compo c_name=os
2824
+ block_count=1 cstruct_size=0 is_def=true if provider == 'serpapi' and not os.getenv('SERPAPI_API_KEY'):
2825
+ compo c_name=os
2826
+ block_count=2 cstruct_size=0 is_def=true print('Error: SERPAPI_API_KEY not found.')
2827
+ block_count=2 cstruct_size=0 is_def=true return
2828
+ block_count=1 cstruct_size=0 is_def=true elif provider == 'tavily_api' and not os.getenv('TAVILY_API_KEY'):
2829
+ compo c_name=os
2830
+ block_count=2 cstruct_size=0 is_def=true print('Error: TAVILY_API_KEY not found for Tavily search.')
2831
+ block_count=2 cstruct_size=0 is_def=true return
2832
+ block_count=1 cstruct_size=0 is_def=true elif provider == 'browser_use':
2833
+ block_count=2 cstruct_size=0 is_def=true pass
2834
+ block_count=1 cstruct_size=0 is_def=true model_name = os.getenv('MODEL_NAME', 'gemini-2.0-flash')
2835
+ compo c_name=os
2836
+ block_count=1 cstruct_size=0 is_def=true print(f'Using model: {model_name}')
2837
+ block_count=1 cstruct_size=0 is_def=true print(f'Using Search Provider: {provider}')
2838
+ block_count=1 cstruct_size=0 is_def=true llm = ChatGoogleGenerativeAI(model=model_name, temperature=0,
2839
+ compo c_name=ChatGoogleGenerativeAI
2840
+ block_count=2 cstruct_size=0 is_def=true max_retries=10)
2841
+ block_count=1 cstruct_size=0 is_def=true search = get_search_tool_func()
2842
+ block_count=1 cstruct_size=0 is_def=true search_tool = Tool(name='google_search', description=
2843
+ compo c_name=Tool
2844
+ block_count=2 cstruct_size=0 is_def=true 'Search Google for recent results.', func=search.run)
2845
+ block_count=1 cstruct_size=0 is_def=true startup_logs = get_all_agent_logs()
2846
+ block_count=1 cstruct_size=0 is_def=true print(f'Loaded {len(startup_logs)} characters of agent logs.')
2847
+ block_count=1 cstruct_size=0 is_def=true save_tool = SaveProductTool()
2848
+ compo c_name=SaveProductTool
2849
+ block_count=1 cstruct_size=0 is_def=true db_search_tool = SearchProductsTool()
2850
+ compo c_name=SearchProductsTool
2851
+ block_count=1 cstruct_size=0 is_def=true update_tool = UpdatePricesTool()
2852
+ compo c_name=UpdatePricesTool
2853
+ block_count=1 cstruct_size=0 is_def=true similar_tool = FindSimilarProductsTool(agent_logs=startup_logs)
2854
+ compo c_name=FindSimilarProductsTool
2855
+ block_count=1 cstruct_size=0 is_def=true compare_tool = CompareProductsTool()
2856
+ compo c_name=CompareProductsTool
2857
+ block_count=1 cstruct_size=0 is_def=true tools = [search_tool, save_tool, db_search_tool, update_tool,
2858
+ block_count=2 cstruct_size=0 is_def=true similar_tool, compare_tool]
2859
+ block_count=1 cstruct_size=0 is_def=true prompt = ChatPromptTemplate.from_messages([('system',
2860
+ compo c_name=ChatPromptTemplate
2861
+ block_count=2 cstruct_size=0 is_def=true """あなたは、商品の検索、保存、価格更新、類似商品検索、比較表作成を行う有能なアシスタントです。
2862
+ block_count=2 cstruct_size=0 is_def=true ), MessagesPlaceholder(variable_name='chat_history'), ('human',
2863
+ compo c_name=MessagesPlaceholder
2864
+ block_count=2 cstruct_size=0 is_def=true '{input}'), ('placeholder', '{agent_scratchpad}')])
2865
+ block_count=1 cstruct_size=0 is_def=true agent = create_tool_calling_agent(llm, tools, prompt)
2866
+ block_count=1 cstruct_size=0 is_def=true agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True,
2867
+ compo c_name=AgentExecutor
2868
+ block_count=2 cstruct_size=0 is_def=true return_intermediate_steps=True)
2869
+ block_count=1 cstruct_size=0 is_def=true print('Advanced AI Agent initialized.')
2870
+ block_count=1 cstruct_size=0 is_def=true print(
2871
+ block_count=2 cstruct_size=0 is_def=true "Commands: 'list', 'show <ID>', 'update', 'similar', 'delete <ID/Name> ...', 'quit'"
2872
+ block_count=2 cstruct_size=0 is_def=true )
2873
+ block_count=1 cstruct_size=0 is_def=true chat_history = []
2874
+ block_count=1 cstruct_size=0 is_def=true while True:
2875
+ block_count=2 cstruct_size=0 is_def=true try:
2876
+ block_count=3 cstruct_size=0 is_def=true try:
2877
+ block_count=4 cstruct_size=0 is_def=true user_input = input('\nEnter command or search query: ')
2878
+ block_count=3 cstruct_size=0 is_def=true except EOFError:
2879
+ block_count=4 cstruct_size=0 is_def=true print('\nEOF detected. Exiting...')
2880
+ block_count=4 cstruct_size=0 is_def=true break
2881
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() in ['quit', 'exit']:
2882
+ block_count=4 cstruct_size=0 is_def=true break
2883
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() == 'list':
2884
+ block_count=4 cstruct_size=0 is_def=true display_products()
2885
+ block_count=4 cstruct_size=0 is_def=true continue
2886
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() == 'update':
2887
+ block_count=4 cstruct_size=0 is_def=true result = update_tool._run()
2888
+ block_count=4 cstruct_size=0 is_def=true print(result)
2889
+ block_count=4 cstruct_size=0 is_def=true continue
2890
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower() == 'similar':
2891
+ block_count=4 cstruct_size=0 is_def=true result = similar_tool._run()
2892
+ block_count=4 cstruct_size=0 is_def=true print(result)
2893
+ block_count=4 cstruct_size=0 is_def=true continue
2894
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('compare'):
2895
+ block_count=4 cstruct_size=0 is_def=true parts = user_input.split(maxsplit=1)
2896
+ block_count=4 cstruct_size=0 is_def=true query = parts[1] if len(parts) > 1 else ''
2897
+ block_count=4 cstruct_size=0 is_def=true result = compare_tool._run(query)
2898
+ block_count=4 cstruct_size=0 is_def=true print(result)
2899
+ block_count=4 cstruct_size=0 is_def=true continue
2900
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('search_products '):
2901
+ block_count=4 cstruct_size=0 is_def=true query = user_input[16:].strip()
2902
+ block_count=4 cstruct_size=0 is_def=true if query:
2903
+ block_count=5 cstruct_size=0 is_def=true result = db_search_tool._run(query)
2904
+ block_count=5 cstruct_size=0 is_def=true print(result)
2905
+ block_count=4 cstruct_size=0 is_def=true else:
2906
+ block_count=5 cstruct_size=0 is_def=true print('Usage: search_products <query>')
2907
+ block_count=4 cstruct_size=0 is_def=true continue
2908
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('show '):
2909
+ block_count=4 cstruct_size=0 is_def=true parts = user_input.split()
2910
+ block_count=4 cstruct_size=0 is_def=true if len(parts) > 1 and parts[1].isdigit():
2911
+ block_count=5 cstruct_size=0 is_def=true show_product_details(int(parts[1]))
2912
+ block_count=4 cstruct_size=0 is_def=true else:
2913
+ block_count=5 cstruct_size=0 is_def=true print('Usage: show <product_id>')
2914
+ block_count=4 cstruct_size=0 is_def=true continue
2915
+ block_count=3 cstruct_size=0 is_def=true if user_input.lower().startswith('delete '):
2916
+ block_count=4 cstruct_size=0 is_def=true try:
2917
+ block_count=5 cstruct_size=0 is_def=true parts = shlex.split(user_input)
2918
+ compo c_name=shlex
2919
+ block_count=5 cstruct_size=0 is_def=true if len(parts) > 1:
2920
+ block_count=6 cstruct_size=0 is_def=true identifiers = parts[1:]
2921
+ block_count=6 cstruct_size=0 is_def=true delete_product_records(identifiers)
2922
+ block_count=5 cstruct_size=0 is_def=true else:
2923
+ block_count=6 cstruct_size=0 is_def=true print('Usage: delete <ID/Name> ...')
2924
+ block_count=4 cstruct_size=0 is_def=true except ValueError as e:
2925
+ block_count=5 cstruct_size=0 is_def=true print(f'Error parsing command: {e}')
2926
+ block_count=4 cstruct_size=0 is_def=true continue
2927
+ block_count=3 cstruct_size=0 is_def=true if user_input:
2928
+ block_count=4 cstruct_size=0 is_def=true print(f'\nProcessing: {user_input}...\n')
2929
+ block_count=4 cstruct_size=0 is_def=true result = agent_executor.invoke({'input': user_input,
2930
+ block_count=5 cstruct_size=0 is_def=true 'chat_history': chat_history})
2931
+ block_count=4 cstruct_size=0 is_def=true chat_history.append(HumanMessage(content=user_input))
2932
+ compo c_name=HumanMessage
2933
+ block_count=4 cstruct_size=0 is_def=true if isinstance(result['output'], str):
2934
+ block_count=5 cstruct_size=0 is_def=true chat_history.append(AIMessage(content=result['output']))
2935
+ compo c_name=AIMessage
2936
+ block_count=4 cstruct_size=0 is_def=true if 'intermediate_steps' in result:
2937
+ block_count=5 cstruct_size=0 is_def=true save_agent_log(user_input, result['intermediate_steps'])
2938
+ block_count=4 cstruct_size=0 is_def=true display_products()
2939
+ block_count=2 cstruct_size=0 is_def=true except KeyboardInterrupt:
2940
+ block_count=3 cstruct_size=0 is_def=true print('\nExiting...')
2941
+ block_count=3 cstruct_size=0 is_def=true break
2942
+ block_count=2 cstruct_size=0 is_def=true except Exception as e:
2943
+ block_count=3 cstruct_size=0 is_def=true print(f'An error occurred: {e}')
2944
+ block_count=0 cstruct_size=0 is_def=true if __name__ == '__main__':
2945
+ block_count=1 cstruct_size=0 is_def=false main()
2946
+ endf of ./test_script.py
2947
+ ./user_code.py
2948
+
2949
+ |python3 lib/del_comment.py ./user_code.py > /tmp/pylint20260323-827-ywofka
2950
+ block_count=0 cstruct_size=0 is_def=false import json
2951
+ block_count=0 cstruct_size=0 is_def=false import sqlite3
2952
+ block_count=0 cstruct_size=0 is_def=false import re
2953
+ block_count=0 cstruct_size=0 is_def=false from pydantic import BaseModel, Field
2954
+ block_count=0 cstruct_size=0 is_def=false class SaveProductTool:
2955
+ class_name=user_code.SaveProductTool
2956
+ base_name=
2957
+ block_count=1 cstruct_size=1 is_def=false def _run(self, name: str, store: str=None, price: str=None, url: str='',
2958
+ block_count=2 cstruct_size=1 is_def=true description: str='', model_number: str='', release_date: str='',
2959
+ block_count=2 cstruct_size=1 is_def=true ram: str='', ssd: str='', **kwargs):
2960
+ block_count=2 cstruct_size=1 is_def=true try:
2961
+ block_count=3 cstruct_size=1 is_def=true if should_save:
2962
+ block_count=4 cstruct_size=1 is_def=true cursor.execute(
2963
+ compo c_name=cursor
2964
+ block_count=5 cstruct_size=1 is_def=true """
2965
+ block_count=5 cstruct_size=1 is_def=true , (name, store, price, url, description, model_number,
2966
+ block_count=5 cstruct_size=1 is_def=true release_date, ram, ssd))
2967
+ block_count=4 cstruct_size=1 is_def=true if not msg:
2968
+ block_count=5 cstruct_size=1 is_def=true msg = f'Saved product: {name} from {store} for {price}.'
2969
+ block_count=4 cstruct_size=1 is_def=true else:
2970
+ block_count=5 cstruct_size=1 is_def=true msg = msg_prefix
2971
+ block_count=3 cstruct_size=1 is_def=true if should_update:
2972
+ block_count=4 cstruct_size=1 is_def=true if price != curr_price_str:
2973
+ block_count=5 cstruct_size=1 is_def=true cursor.execute(
2974
+ compo c_name=cursor
2975
+ block_count=6 cstruct_size=1 is_def=true """
2976
+ block_count=6 cstruct_size=1 is_def=true , (price, url, description, final_model,
2977
+ block_count=6 cstruct_size=1 is_def=true final_release, final_ram, final_ssd, store,
2978
+ block_count=6 cstruct_size=1 is_def=true current_cheapest['id']))
2979
+ block_count=5 cstruct_size=1 is_def=true if not msg:
2980
+ block_count=6 cstruct_size=1 is_def=true msg = f'Updated product {name} info.'
2981
+ block_count=5 cstruct_size=1 is_def=true else:
2982
+ block_count=6 cstruct_size=1 is_def=true msg = msg_prefix
2983
+ block_count=4 cstruct_size=1 is_def=true else:
2984
+ block_count=5 cstruct_size=1 is_def=true msg = f'No changes for {name} at {store}.'
2985
+ block_count=3 cstruct_size=1 is_def=true if should_save or should_update:
2986
+ block_count=4 cstruct_size=1 is_def=true cursor.execute('SELECT id, price FROM products WHERE name = ?',
2987
+ compo c_name=cursor
2988
+ block_count=5 cstruct_size=1 is_def=true (name,))
2989
+ block_count=4 cstruct_size=1 is_def=true rows = cursor.fetchall()
2990
+ compo c_name=cursor
2991
+ block_count=4 cstruct_size=1 is_def=true if len(rows) > 1:
2992
+ block_count=5 cstruct_size=1 is_def=true rows_parsed = []
2993
+ block_count=5 cstruct_size=1 is_def=true for r in rows:
2994
+ block_count=6 cstruct_size=1 is_def=true rows_parsed.append({'id': r[0], 'val':
2995
+ block_count=7 cstruct_size=1 is_def=true parse_price_val(r[1])})
2996
+ block_count=5 cstruct_size=1 is_def=true rows_parsed.sort(key=lambda x: x['val'])
2997
+ block_count=5 cstruct_size=1 is_def=true winner = rows_parsed[0]
2998
+ block_count=5 cstruct_size=1 is_def=true for loser in rows_parsed[1:]:
2999
+ block_count=6 cstruct_size=1 is_def=true cursor.execute('DELETE FROM products WHERE id = ?',
3000
+ compo c_name=cursor
3001
+ block_count=7 cstruct_size=1 is_def=true (loser['id'],))
3002
+ block_count=5 cstruct_size=1 is_def=true msg += ' (Cleaned up duplicate records)'
3003
+ block_count=3 cstruct_size=1 is_def=true conn.commit()
3004
+ compo c_name=conn
3005
+ block_count=3 cstruct_size=1 is_def=true conn.close()
3006
+ compo c_name=conn
3007
+ block_count=3 cstruct_size=1 is_def=true return msg
3008
+ block_count=2 cstruct_size=1 is_def=true except Exception as e:
3009
+ block_count=3 cstruct_size=1 is_def=true return f'Error saving product: {str(e)}'
3010
+ endf of ./user_code.py
3011
+ end of user_code.SaveProductTool
3012
+ m=agent.SaveProductTool
3013
+ m=agent.SaveProductTool
3014
+ m=test_script.SaveProductTool
3015
+ m=test_script.SaveProductTool
3016
+ m=user_code.SaveProductTool
3017
+ m=user_code.SaveProductTool
3018
+ m=agent.TavilySearchWrapper
3019
+ m=agent.TavilySearchWrapper
3020
+ m=test_script.TavilySearchWrapper
3021
+ m=test_script.TavilySearchWrapper
3022
+ m=agent.BrowserUseSearchWrapper
3023
+ m=agent.BrowserUseSearchWrapper
3024
+ m=test_script.BrowserUseSearchWrapper
3025
+ m=test_script.BrowserUseSearchWrapper
3026
+ m=agent.SaveProductTool
3027
+ m=agent.SaveProductTool
3028
+ m=test_script.SaveProductTool
3029
+ m=test_script.SaveProductTool
3030
+ m=user_code.SaveProductTool
3031
+ m=user_code.SaveProductTool
3032
+ m=agent.SearchProductsTool
3033
+ m=agent.SearchProductsTool
3034
+ m=test_script.SearchProductsTool
3035
+ m=test_script.SearchProductsTool
3036
+ m=agent.UpdatePricesTool
3037
+ m=agent.UpdatePricesTool
3038
+ m=test_script.UpdatePricesTool
3039
+ m=test_script.UpdatePricesTool
3040
+ m=agent.FindSimilarProductsTool
3041
+ m=agent.FindSimilarProductsTool
3042
+ m=test_script.FindSimilarProductsTool
3043
+ m=test_script.FindSimilarProductsTool
3044
+ m=agent.CompareProductsTool
3045
+ m=agent.CompareProductsTool
3046
+ m=test_script.CompareProductsTool
3047
+ m=test_script.CompareProductsTool
3048
+ m=agent.SaveProductTool
3049
+ m=agent.SaveProductTool
3050
+ m=test_script.SaveProductTool
3051
+ m=test_script.SaveProductTool
3052
+ m=user_code.SaveProductTool
3053
+ m=user_code.SaveProductTool
3054
+ m=agent.TavilySearchWrapper
3055
+ m=agent.TavilySearchWrapper
3056
+ m=test_script.TavilySearchWrapper
3057
+ m=test_script.TavilySearchWrapper
3058
+ m=agent.BrowserUseSearchWrapper
3059
+ m=agent.BrowserUseSearchWrapper
3060
+ m=test_script.BrowserUseSearchWrapper
3061
+ m=test_script.BrowserUseSearchWrapper
3062
+ m=agent.SaveProductTool
3063
+ m=agent.SaveProductTool
3064
+ m=test_script.SaveProductTool
3065
+ m=test_script.SaveProductTool
3066
+ m=user_code.SaveProductTool
3067
+ m=user_code.SaveProductTool
3068
+ m=agent.SearchProductsTool
3069
+ m=agent.SearchProductsTool
3070
+ m=test_script.SearchProductsTool
3071
+ m=test_script.SearchProductsTool
3072
+ m=agent.UpdatePricesTool
3073
+ m=agent.UpdatePricesTool
3074
+ m=test_script.UpdatePricesTool
3075
+ m=test_script.UpdatePricesTool
3076
+ m=agent.FindSimilarProductsTool
3077
+ m=agent.FindSimilarProductsTool
3078
+ m=test_script.FindSimilarProductsTool
3079
+ m=test_script.FindSimilarProductsTool
3080
+ m=agent.CompareProductsTool
3081
+ m=agent.CompareProductsTool
3082
+ m=test_script.CompareProductsTool
3083
+ m=test_script.CompareProductsTool