infinityonline commited on
Commit
b06958b
ยท
verified ยท
1 Parent(s): 6304f51

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +40 -57
main.py CHANGED
@@ -77,7 +77,6 @@ class AsyncBrowserThread(threading.Thread):
77
  "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
78
  )
79
 
80
- # ู‚ุจูˆู„ ุงู„ุดุฑูˆุท ู…ุฑุฉ ูˆุงุญุฏุฉ ุนู†ุฏ ุงู„ุฅู‚ู„ุงุน
81
  setup_page = await self.persistent_context.new_page()
82
  try:
83
  print("[SERVER] Opening duck.ai for setup...")
@@ -102,9 +101,10 @@ class AsyncBrowserThread(threading.Thread):
102
  async def _chat(self, model_label: str, prompt: str) -> str:
103
  page = await self.persistent_context.new_page()
104
  try:
105
- page.set_default_timeout(30000)
 
106
 
107
- # โ”€โ”€ 1. ูุชุญ ุตูุญุฉ ุฌุฏูŠุฏุฉ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
108
  await page.goto(
109
  "https://duckduckgo.com/aichat", wait_until="domcontentloaded"
110
  )
@@ -121,12 +121,10 @@ class AsyncBrowserThread(threading.Thread):
121
  pass
122
 
123
  # โ”€โ”€ 3. ุงู†ุชุธุงุฑ textarea โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
124
- await page.wait_for_selector(
125
- 'textarea[name="user-prompt"]', timeout=30000
126
- )
127
  print("[DUCK] Input ready โœ“")
128
 
129
- # โ”€โ”€ 4. ุชุบูŠูŠุฑ ุงู„ู†ู…ูˆุฐุฌ ุจุทุฑูŠู‚ุฉ ุขู…ู†ุฉ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
130
  try:
131
  model_btn = page.locator('button[data-testid="model-select-button"]')
132
  current_text = await model_btn.inner_text()
@@ -145,27 +143,18 @@ class AsyncBrowserThread(threading.Thread):
145
  print(f"[DUCK] Model โ†’ {model_label} โœ“")
146
  else:
147
  await page.keyboard.press("Escape")
148
- print(f"[DUCK] Model not found, using default")
149
 
150
- # ุงู†ุชุธุฑ ุฅุนุงุฏุฉ render ุจุนุฏ ุชุบูŠูŠุฑ ุงู„ู†ู…ูˆุฐุฌ
151
  await asyncio.sleep(3)
152
  await page.wait_for_selector(
153
- 'textarea[name="user-prompt"]',
154
- state="visible",
155
- timeout=15000
156
  )
157
  print("[DUCK] Textarea re-confirmed โœ“")
158
 
159
  except Exception as e:
160
  print(f"[DUCK] Model select (non-fatal): {e}")
161
- await page.wait_for_selector(
162
- 'textarea[name="user-prompt"]',
163
- state="visible",
164
- timeout=10000
165
- )
166
-
167
- # โ”€โ”€ 5. ูƒุชุงุจุฉ ุงู„ุฑุณุงู„ุฉ ุจู€ JavaScript โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
168
- # ูŠุชุฌุงูˆุฒ React's synthetic events ูˆูŠุถู…ู† ุชูุนูŠู„ ุฒุฑ Send
169
  await page.evaluate(
170
  """
171
  (text) => {
@@ -175,40 +164,40 @@ class AsyncBrowserThread(threading.Thread):
175
  window.HTMLTextAreaElement.prototype, 'value'
176
  ).set;
177
  nativeSetter.call(ta, text);
178
- ta.dispatchEvent(new InputEvent('input', { bubbles: true }));
179
  ta.dispatchEvent(new Event('change', { bubbles: true }));
180
  ta.focus();
181
  }
182
  """,
183
  prompt
184
  )
185
- await asyncio.sleep(1.5)
186
 
187
  # โ”€โ”€ 6. ุฅุฑุณุงู„ ุงู„ุฑุณุงู„ุฉ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
188
- send_btn = page.locator('button[type="submit"][aria-label="Send"]')
189
-
190
- # ุงู†ุชุธุฑ ุญุชู‰ 5 ุซูˆุงู† ู„ุฒุฑ Send
191
- send_enabled = False
192
- for _ in range(10):
193
  is_disabled = await send_btn.get_attribute("disabled")
194
  if is_disabled is None:
195
- send_enabled = True
196
- break
197
- await asyncio.sleep(0.5)
 
 
198
 
199
- if send_enabled:
200
- await send_btn.click()
201
- print(f"[DUCK] Sent via button โœ“ ({len(prompt)} chars)")
202
- else:
203
- # fallback: Enter ุนู„ู‰ ุงู„ู€ textarea
204
  ta = page.locator('textarea[name="user-prompt"]')
205
  await ta.click()
206
- await asyncio.sleep(0.3)
207
  await page.keyboard.press("Enter")
208
- print(f"[DUCK] Sent via Enter โœ“ ({len(prompt)} chars)")
 
 
209
 
210
  # โ”€โ”€ 7. ุงู†ุชุธุงุฑ ุจุฏุก ุงู„ุฑุฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
211
- await asyncio.sleep(2)
212
  response_started = False
213
  try:
214
  stop_btn = page.locator('button[aria-label="Stop generating"]')
@@ -216,11 +205,10 @@ class AsyncBrowserThread(threading.Thread):
216
  print("[DUCK] Response started โœ“")
217
  response_started = True
218
  except Exception:
219
- print("[DUCK] Stop btn not detected, will watch for content...")
220
 
221
  # โ”€โ”€ 8. ุงู†ุชุธุงุฑ ุงูƒุชู…ุงู„ ุงู„ุฑุฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
222
- page.set_default_timeout(120000)
223
- max_wait = 120
224
  elapsed = 0
225
 
226
  if response_started:
@@ -231,17 +219,16 @@ class AsyncBrowserThread(threading.Thread):
231
  'button[aria-label="Stop generating"]:not([disabled])'
232
  ).count()
233
  if still_running == 0:
234
- print(f"[DUCK] Response complete (~{elapsed}s) โœ“")
235
  break
236
  else:
237
- # ุงู†ุชุธุฑ ุธู‡ูˆุฑ article (ู…ุญุชูˆู‰ ุงู„ุฑุฏ)
238
  while elapsed < max_wait:
239
  await asyncio.sleep(2)
240
  elapsed += 2
241
- arts = await page.locator('article').count()
242
- if arts > 0:
243
- await asyncio.sleep(5)
244
- print(f"[DUCK] Content appeared (~{elapsed}s) โœ“")
245
  break
246
 
247
  await asyncio.sleep(2)
@@ -249,31 +236,26 @@ class AsyncBrowserThread(threading.Thread):
249
  # โ”€โ”€ 9. ุงุณุชุฎุฑุงุฌ ุงู„ุฑุฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
250
  response_text = await page.evaluate("""
251
  () => {
252
- // ุทุฑูŠู‚ุฉ 1: article
253
  const articles = document.querySelectorAll('article');
254
  if (articles.length > 0) {
255
  return articles[articles.length - 1].innerText.trim();
256
  }
257
- // ุทุฑูŠู‚ุฉ 2: class ูŠุญุชูˆูŠ message
258
  const msgDivs = document.querySelectorAll(
259
  '[class*="message"]:not([class*="user"])' +
260
  ':not([class*="User"]):not([class*="input"])'
261
  );
262
  if (msgDivs.length > 0) {
263
  const valid = [...msgDivs].filter(el =>
264
- el.innerText &&
265
- el.innerText.trim().length > 20 &&
266
  !el.querySelector('textarea')
267
  );
268
  if (valid.length > 0) {
269
  return valid[valid.length - 1].innerText.trim();
270
  }
271
  }
272
- // ุทุฑูŠู‚ุฉ 3: ุฃุทูˆู„ div ู†ุธูŠู
273
  const divs = [...document.querySelectorAll('div')].filter(el =>
274
  el.children.length < 10 &&
275
- el.innerText &&
276
- el.innerText.trim().length > 50 &&
277
  !el.querySelector('textarea') &&
278
  !el.querySelector('button[type="submit"]')
279
  );
@@ -286,7 +268,6 @@ class AsyncBrowserThread(threading.Thread):
286
  }
287
  """)
288
 
289
- # fallback ู†ู‡ุงุฆูŠ
290
  if not response_text or len(response_text.strip()) < 10:
291
  await asyncio.sleep(5)
292
  response_text = await page.evaluate("""
@@ -312,7 +293,7 @@ class AsyncBrowserThread(threading.Thread):
312
  future = asyncio.run_coroutine_threadsafe(
313
  self._chat(model_label, prompt), self.loop
314
  )
315
- return future.result(timeout=200)
316
 
317
 
318
  browser_engine = AsyncBrowserThread()
@@ -344,7 +325,9 @@ def _build_prompt(messages: list) -> str:
344
  if not content.strip():
345
  continue
346
  if role == "system":
347
- parts.append(f"=== SYSTEM INSTRUCTIONS ===\n{content}\n=== END INSTRUCTIONS ===")
 
 
348
  elif role == "assistant":
349
  parts.append(f"[Assistant]: {content}")
350
  else:
 
77
  "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
78
  )
79
 
 
80
  setup_page = await self.persistent_context.new_page()
81
  try:
82
  print("[SERVER] Opening duck.ai for setup...")
 
101
  async def _chat(self, model_label: str, prompt: str) -> str:
102
  page = await self.persistent_context.new_page()
103
  try:
104
+ # !! timeout ูˆุงุญุฏ ูƒุจูŠุฑ ู„ูƒู„ ุงู„ุตูุญุฉ โ€” ู„ุง ูŠูุบูŠูŽู‘ุฑ ุฃุจุฏุงู‹
105
+ page.set_default_timeout(180000)
106
 
107
+ # โ”€โ”€ 1. ูุชุญ ุงู„ุตูุญุฉ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
108
  await page.goto(
109
  "https://duckduckgo.com/aichat", wait_until="domcontentloaded"
110
  )
 
121
  pass
122
 
123
  # โ”€โ”€ 3. ุงู†ุชุธุงุฑ textarea โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
124
+ await page.wait_for_selector('textarea[name="user-prompt"]')
 
 
125
  print("[DUCK] Input ready โœ“")
126
 
127
+ # โ”€โ”€ 4. ุชุบูŠูŠุฑ ุงู„ู†ู…ูˆุฐุฌ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
128
  try:
129
  model_btn = page.locator('button[data-testid="model-select-button"]')
130
  current_text = await model_btn.inner_text()
 
143
  print(f"[DUCK] Model โ†’ {model_label} โœ“")
144
  else:
145
  await page.keyboard.press("Escape")
146
+ print("[DUCK] Model not found, using default")
147
 
 
148
  await asyncio.sleep(3)
149
  await page.wait_for_selector(
150
+ 'textarea[name="user-prompt"]', state="visible"
 
 
151
  )
152
  print("[DUCK] Textarea re-confirmed โœ“")
153
 
154
  except Exception as e:
155
  print(f"[DUCK] Model select (non-fatal): {e}")
156
+
157
+ # โ”€โ”€ 5. ุญู‚ู† ุงู„ู†ุต ุนุจุฑ JavaScript โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
 
 
 
 
 
158
  await page.evaluate(
159
  """
160
  (text) => {
 
164
  window.HTMLTextAreaElement.prototype, 'value'
165
  ).set;
166
  nativeSetter.call(ta, text);
167
+ ta.dispatchEvent(new InputEvent('input', { bubbles: true }));
168
  ta.dispatchEvent(new Event('change', { bubbles: true }));
169
  ta.focus();
170
  }
171
  """,
172
  prompt
173
  )
174
+ await asyncio.sleep(2)
175
 
176
  # โ”€โ”€ 6. ุฅุฑุณุงู„ ุงู„ุฑุณุงู„ุฉ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
177
+ # ู…ุญุงูˆู„ุฉ 1: ุฒุฑ Submit
178
+ sent = False
179
+ try:
180
+ send_btn = page.locator('button[type="submit"][aria-label="Send"]')
 
181
  is_disabled = await send_btn.get_attribute("disabled")
182
  if is_disabled is None:
183
+ await send_btn.click()
184
+ print(f"[DUCK] Sent via button โœ“")
185
+ sent = True
186
+ except Exception:
187
+ pass
188
 
189
+ # ู…ุญุงูˆู„ุฉ 2: Enter ู…ุจุงุดุฑุฉ
190
+ if not sent:
 
 
 
191
  ta = page.locator('textarea[name="user-prompt"]')
192
  await ta.click()
193
+ await asyncio.sleep(0.5)
194
  await page.keyboard.press("Enter")
195
+ print(f"[DUCK] Sent via Enter โœ“")
196
+
197
+ print(f"[DUCK] Prompt length: {len(prompt)} chars")
198
 
199
  # โ”€โ”€ 7. ุงู†ุชุธุงุฑ ุจุฏุก ุงู„ุฑุฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
200
+ await asyncio.sleep(3)
201
  response_started = False
202
  try:
203
  stop_btn = page.locator('button[aria-label="Stop generating"]')
 
205
  print("[DUCK] Response started โœ“")
206
  response_started = True
207
  except Exception:
208
+ print("[DUCK] Stop btn not detected, watching for content...")
209
 
210
  # โ”€โ”€ 8. ุงู†ุชุธุงุฑ ุงูƒุชู…ุงู„ ุงู„ุฑุฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
211
+ max_wait = 150
 
212
  elapsed = 0
213
 
214
  if response_started:
 
219
  'button[aria-label="Stop generating"]:not([disabled])'
220
  ).count()
221
  if still_running == 0:
222
+ print(f"[DUCK] Complete (~{elapsed}s) โœ“")
223
  break
224
  else:
225
+ # ุงู†ุชุธุฑ ุธู‡ูˆุฑ article
226
  while elapsed < max_wait:
227
  await asyncio.sleep(2)
228
  elapsed += 2
229
+ if await page.locator('article').count() > 0:
230
+ await asyncio.sleep(6)
231
+ print(f"[DUCK] Article appeared (~{elapsed}s) โœ“")
 
232
  break
233
 
234
  await asyncio.sleep(2)
 
236
  # โ”€โ”€ 9. ุงุณุชุฎุฑุงุฌ ุงู„ุฑุฏ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
237
  response_text = await page.evaluate("""
238
  () => {
 
239
  const articles = document.querySelectorAll('article');
240
  if (articles.length > 0) {
241
  return articles[articles.length - 1].innerText.trim();
242
  }
 
243
  const msgDivs = document.querySelectorAll(
244
  '[class*="message"]:not([class*="user"])' +
245
  ':not([class*="User"]):not([class*="input"])'
246
  );
247
  if (msgDivs.length > 0) {
248
  const valid = [...msgDivs].filter(el =>
249
+ el.innerText && el.innerText.trim().length > 20 &&
 
250
  !el.querySelector('textarea')
251
  );
252
  if (valid.length > 0) {
253
  return valid[valid.length - 1].innerText.trim();
254
  }
255
  }
 
256
  const divs = [...document.querySelectorAll('div')].filter(el =>
257
  el.children.length < 10 &&
258
+ el.innerText && el.innerText.trim().length > 50 &&
 
259
  !el.querySelector('textarea') &&
260
  !el.querySelector('button[type="submit"]')
261
  );
 
268
  }
269
  """)
270
 
 
271
  if not response_text or len(response_text.strip()) < 10:
272
  await asyncio.sleep(5)
273
  response_text = await page.evaluate("""
 
293
  future = asyncio.run_coroutine_threadsafe(
294
  self._chat(model_label, prompt), self.loop
295
  )
296
+ return future.result(timeout=210)
297
 
298
 
299
  browser_engine = AsyncBrowserThread()
 
325
  if not content.strip():
326
  continue
327
  if role == "system":
328
+ parts.append(
329
+ f"=== SYSTEM INSTRUCTIONS ===\n{content}\n=== END INSTRUCTIONS ==="
330
+ )
331
  elif role == "assistant":
332
  parts.append(f"[Assistant]: {content}")
333
  else: