suzmen commited on
Commit
dcf3155
·
verified ·
1 Parent(s): 595c165

Upload 64 files

Browse files
Files changed (1) hide show
  1. app/services/browser.py +45 -18
app/services/browser.py CHANGED
@@ -177,42 +177,69 @@ class BrowserEngine(threading.Thread):
177
 
178
  raise
179
 
180
- # Poll until the response stabilises
181
  last_text = ""
182
  unchanged_count = 0
183
  start_polling = asyncio.get_event_loop().time()
 
 
 
184
 
185
- # Smart stabilization:
186
- # - If text is empty, wait longer to give it time to start typing.
187
- # - If text exists, 2 seconds of silence is enough.
188
  while True:
189
- # Safety break: 90 seconds total
190
- if asyncio.get_event_loop().time() - start_polling > 90:
191
  print("[PhantomAPI] ⚠️ Hard timeout reached.")
192
  break
193
 
 
194
  elements = await page.query_selector_all(
195
  '[data-message-author-role="assistant"]'
196
  )
 
197
  if elements:
198
- current_text = await elements[-1].inner_text()
 
 
 
199
 
200
- if current_text == last_text:
201
- unchanged_count += 1
202
- else:
203
- if len(current_text) > len(last_text):
204
- print(f"[PhantomAPI] ⏳ Generating... ({len(current_text)} chars)")
205
- last_text = current_text
206
- unchanged_count = 0
207
 
208
- # Determine threshold
209
- threshold = 20 if len(last_text.strip()) == 0 else 4
 
 
 
 
 
 
 
 
210
 
211
- if unchanged_count >= threshold:
212
- break
 
 
 
 
 
 
 
 
 
 
 
213
 
214
  await asyncio.sleep(0.5)
215
 
 
 
 
 
 
 
 
 
216
  print(f"[PhantomAPI] ✨ Response complete ({len(last_text)} chars).")
217
  return last_text.strip()
218
 
 
177
 
178
  raise
179
 
180
+ # --- Response Polling (Two-Phase) ---
181
  last_text = ""
182
  unchanged_count = 0
183
  start_polling = asyncio.get_event_loop().time()
184
+ found_first_char = False
185
+
186
+ print("[PhantomAPI] ⏳ Phase 1: Waiting for first character...")
187
 
 
 
 
188
  while True:
189
+ # hard break: 120 seconds total
190
+ if asyncio.get_event_loop().time() - start_polling > 120:
191
  print("[PhantomAPI] ⚠️ Hard timeout reached.")
192
  break
193
 
194
+ # Target the actual content div if possible
195
  elements = await page.query_selector_all(
196
  '[data-message-author-role="assistant"]'
197
  )
198
+
199
  if elements:
200
+ # Look for markdown/prose inside the assistant bubble
201
+ container = elements[-1]
202
+ content_el = await container.query_selector(".markdown, .prose")
203
+ target = content_el if content_el else container
204
 
205
+ current_text = await target.inner_text()
206
+ current_text = current_text.strip()
 
 
 
 
 
207
 
208
+ # Phase 1: Wait for text to appear
209
+ if not found_first_char:
210
+ if len(current_text) > 0:
211
+ found_first_char = True
212
+ print(f"[PhantomAPI] 📢 First character detected! Phase 2: Monitoring stream...")
213
+ else:
214
+ # If we've waited > 60s for the first char, something is wrong
215
+ if asyncio.get_event_loop().time() - start_polling > 60:
216
+ print("[PhantomAPI] ❌ Giving up: No text appeared after 60s.")
217
+ break
218
 
219
+ # Phase 2: Monitor stability
220
+ if found_first_char:
221
+ if current_text == last_text:
222
+ unchanged_count += 1
223
+ else:
224
+ if len(current_text) > len(last_text):
225
+ print(f"[PhantomAPI] ⏳ Generating... ({len(current_text)} chars)")
226
+ last_text = current_text
227
+ unchanged_count = 0
228
+
229
+ # Once text starts, 2 seconds (4 iterations) of silence means done
230
+ if unchanged_count >= 4:
231
+ break
232
 
233
  await asyncio.sleep(0.5)
234
 
235
+ if not found_first_char:
236
+ # Fail diagnostics
237
+ print("[PhantomAPI] ❌ Final check: Assistant bubble was empty.")
238
+ bubble_html = await page.evaluate(
239
+ "() => document.querySelector('[data-message-author-role=\"assistant\"]')?.outerHTML"
240
+ )
241
+ print(f"[PhantomAPI] 📍 Bubble HTML: {bubble_html[:500]}")
242
+
243
  print(f"[PhantomAPI] ✨ Response complete ({len(last_text)} chars).")
244
  return last_text.strip()
245