Opera8 commited on
Commit
dc95380
·
verified ·
1 Parent(s): 0db564c

Upload app (2) (13).py

Browse files
Files changed (1) hide show
  1. app (2) (13).py +580 -0
app (2) (13).py ADDED
@@ -0,0 +1,580 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import asyncio
4
+ import uvicorn
5
+ from fastapi import FastAPI, Form, File, UploadFile, HTTPException
6
+ from fastapi.responses import HTMLResponse, JSONResponse
7
+ from playwright.async_api import async_playwright
8
+
9
+ app = FastAPI()
10
+ UPLOAD_DIR = "temp_uploads"
11
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
12
+
13
+ # لایه فرانت‌اند چت‌باکس فوتوریستی با استایل شیشه‌ای (Glassmorphism)
14
+ HTML_CHAT_INTERFACE = """
15
+ <!DOCTYPE html>
16
+ <html lang="fa" dir="rtl">
17
+ <head>
18
+ <meta charset="UTF-8">
19
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
20
+ <title>Google AI Free Chatbot + Vision</title>
21
+ <style>
22
+ :root {
23
+ --bg-gradient: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
24
+ --glass-bg: rgba(30, 41, 59, 0.7);
25
+ --glass-border: rgba(255, 255, 255, 0.08);
26
+ --text-main: #f8fafc;
27
+ --accent-color: #38bdf8;
28
+ --user-bubble: linear-gradient(135deg, #0284c7 0%, #0369a1 100%);
29
+ --ai-bubble: rgba(255, 255, 255, 0.06);
30
+ }
31
+
32
+ body {
33
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Tahoma, sans-serif;
34
+ margin: 0;
35
+ padding: 0;
36
+ background: var(--bg-gradient);
37
+ color: var(--text-main);
38
+ height: 100vh;
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: center;
42
+ overflow: hidden;
43
+ }
44
+
45
+ .chat-container {
46
+ width: 100%;
47
+ max-width: 850px;
48
+ height: 85vh;
49
+ background: var(--glass-bg);
50
+ backdrop-filter: blur(16px);
51
+ -webkit-backdrop-filter: blur(16px);
52
+ border: 1px solid var(--glass-border);
53
+ border-radius: 24px;
54
+ display: flex;
55
+ flex-direction: column;
56
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
57
+ margin: 20px;
58
+ }
59
+
60
+ .chat-header {
61
+ padding: 20px 24px;
62
+ border-bottom: 1px solid var(--glass-border);
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 12px;
66
+ }
67
+
68
+ .chat-header .status-dot {
69
+ width: 10px;
70
+ height: 10px;
71
+ background: #4ade80;
72
+ border-radius: 50%;
73
+ box-shadow: 0 0 10px #4ade80;
74
+ }
75
+
76
+ .chat-header h2 {
77
+ margin: 0;
78
+ font-size: 18px;
79
+ font-weight: 600;
80
+ color: var(--accent-color);
81
+ }
82
+
83
+ .messages-box {
84
+ flex: 1;
85
+ padding: 24px;
86
+ overflow-y: auto;
87
+ display: flex;
88
+ flex-direction: column;
89
+ gap: 16px;
90
+ }
91
+
92
+ .messages-box::-webkit-scrollbar { width: 6px; }
93
+ .messages-box::-webkit-scrollbar-track { background: transparent; }
94
+ .messages-box::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.1); border-radius: 10px; }
95
+
96
+ .message {
97
+ max-width: 75%;
98
+ padding: 14px 18px;
99
+ border-radius: 18px;
100
+ font-size: 15px;
101
+ line-height: 1.6;
102
+ word-wrap: break-word;
103
+ animation: fadeIn 0.3s ease forwards;
104
+ }
105
+
106
+ .message.user {
107
+ background: var(--user-bubble);
108
+ align-self: flex-start;
109
+ border-bottom-right-radius: 4px;
110
+ box-shadow: 0 4px 12px rgba(2, 132, 199, 0.2);
111
+ }
112
+
113
+ .message.ai {
114
+ background: var(--ai-bubble);
115
+ border: 1px solid var(--glass-border);
116
+ align-self: flex-end;
117
+ border-bottom-left-radius: 4px;
118
+ white-space: pre-wrap;
119
+ }
120
+
121
+ .input-wrapper {
122
+ border-top: 1px solid var(--glass-border);
123
+ background: rgba(15, 23, 42, 0.4);
124
+ border-bottom-left-radius: 24px;
125
+ border-bottom-right-radius: 24px;
126
+ padding: 15px 24px;
127
+ display: flex;
128
+ flex-direction: column;
129
+ gap: 10px;
130
+ }
131
+
132
+ .preview-container {
133
+ display: none;
134
+ align-items: center;
135
+ gap: 10px;
136
+ background: rgba(255, 255, 255, 0.05);
137
+ padding: 8px 12px;
138
+ border-radius: 10px;
139
+ width: fit-content;
140
+ border: 1px solid var(--glass-border);
141
+ }
142
+
143
+ .preview-container img {
144
+ width: 40px;
145
+ height: 40px;
146
+ object-fit: cover;
147
+ border-radius: 6px;
148
+ }
149
+
150
+ .preview-container .remove-btn {
151
+ color: #ef4444;
152
+ cursor: pointer;
153
+ font-weight: bold;
154
+ font-size: 14px;
155
+ }
156
+
157
+ .input-area {
158
+ display: flex;
159
+ gap: 12px;
160
+ align-items: center;
161
+ }
162
+
163
+ .input-area input[type="text"] {
164
+ flex: 1;
165
+ background: rgba(255, 255, 255, 0.05);
166
+ border: 1px solid var(--glass-border);
167
+ padding: 14px 20px;
168
+ border-radius: 14px;
169
+ color: white;
170
+ font-size: 15px;
171
+ outline: none;
172
+ transition: all 0.2s;
173
+ }
174
+
175
+ .input-area input[type="text"]:focus {
176
+ border-color: var(--accent-color);
177
+ background: rgba(255, 255, 255, 0.08);
178
+ box-shadow: 0 0 12px rgba(56, 189, 248, 0.15);
179
+ }
180
+
181
+ .upload-label {
182
+ background: rgba(255, 255, 255, 0.05);
183
+ border: 1px solid var(--glass-border);
184
+ padding: 12px;
185
+ border-radius: 14px;
186
+ cursor: pointer;
187
+ display: flex;
188
+ align-items: center;
189
+ justify-content: center;
190
+ transition: all 0.2s;
191
+ }
192
+
193
+ .upload-label:hover {
194
+ background: rgba(255, 255, 255, 0.1);
195
+ border-color: var(--accent-color);
196
+ }
197
+
198
+ .upload-label svg {
199
+ width: 22px;
200
+ height: 22px;
201
+ fill: var(--text-main);
202
+ }
203
+
204
+ .input-area button {
205
+ background: var(--accent-color);
206
+ color: #0f172a;
207
+ border: none;
208
+ padding: 14px 24px;
209
+ border-radius: 14px;
210
+ font-size: 15px;
211
+ font-weight: bold;
212
+ cursor: pointer;
213
+ transition: all 0.2s;
214
+ }
215
+
216
+ .input-area button:hover {
217
+ background: #7dd3fc;
218
+ transform: translateY(-1px);
219
+ }
220
+
221
+ .input-area button:disabled {
222
+ background: #64748b;
223
+ color: #1e293b;
224
+ cursor: not-allowed;
225
+ transform: none;
226
+ }
227
+
228
+ .typing-indicator {
229
+ display: flex;
230
+ gap: 5px;
231
+ padding: 12px 18px;
232
+ background: var(--ai-bubble);
233
+ border-radius: 12px;
234
+ align-self: flex-end;
235
+ border: 1px solid var(--glass-border);
236
+ }
237
+
238
+ .typing-indicator span {
239
+ width: 8px;
240
+ height: 8px;
241
+ background: var(--accent-color);
242
+ border-radius: 50%;
243
+ animation: bounce 1.4s infinite ease-in-out both;
244
+ }
245
+ .typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
246
+ .typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
247
+
248
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
249
+ @keyframes bounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1.0); } }
250
+ </style>
251
+ </head>
252
+ <body>
253
+
254
+ <div class="chat-container">
255
+ <div class="chat-header">
256
+ <div class="status-dot"></div>
257
+ <h2>دستیار مالتی‌مدال گوگل (متن + تصویر کاملاً رایگان)</h2>
258
+ </div>
259
+ <div class="messages-box" id="messagesBox">
260
+ <div class="message ai">سلام! من متصل به هوشواره گوگل هستم. می‌توانید علاوه بر متن، تصویر هم برایم بفرستید تا بررسی کنم.</div>
261
+ </div>
262
+
263
+ <div class="input-wrapper">
264
+ <div class="preview-container" id="previewContainer">
265
+ <img src="" id="imagePreview">
266
+ <span class="remove-btn" onclick="removeSelectedImage()">✕ حذف</span>
267
+ </div>
268
+
269
+ <div class="input-area">
270
+ <input type="file" id="fileInput" accept="image/*" style="display: none;" onchange="previewImage(event)">
271
+ <label for="fileInput" class="upload-label" title="آپلود تصویر">
272
+ <svg viewBox="0 0 24 24"><path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.66 1.34 3 3 3s3-1.34 3-3V5c0-2.48-2.02-4.5-4.5-4.5S7 2.52 7 5v12.5c0 3.59 2.91 6.5 6.5 6.5s6.5-2.91 6.5-6V6h-1.5z"/></svg>
273
+ </label>
274
+
275
+ <input type="text" id="userInput" placeholder="پیام یا توضیح مربوط به تصویر را بنویسید..." onkeypress="handleKeyPress(event)">
276
+ <button id="sendBtn" onclick="sendMessage()">ارسال</button>
277
+ </div>
278
+ </div>
279
+ </div>
280
+
281
+ <script>
282
+ const messagesBox = document.getElementById('messagesBox');
283
+ const userInput = document.getElementById('userInput');
284
+ const fileInput = document.getElementById('fileInput');
285
+ const sendBtn = document.getElementById('sendBtn');
286
+ const previewContainer = document.getElementById('previewContainer');
287
+ const imagePreview = document.getElementById('imagePreview');
288
+
289
+ function handleKeyPress(e) {
290
+ if (e.key === 'Enter') sendMessage();
291
+ }
292
+
293
+ function previewImage(event) {
294
+ const file = event.target.files[0];
295
+ if (file) {
296
+ const reader = new FileReader();
297
+ reader.onload = function(e) {
298
+ imagePreview.src = e.target.result;
299
+ previewContainer.style.display = 'flex';
300
+ }
301
+ reader.readAsDataURL(file);
302
+ }
303
+ }
304
+
305
+ function removeSelectedImage() {
306
+ fileInput.value = '';
307
+ previewContainer.style.display = 'none';
308
+ imagePreview.src = '';
309
+ }
310
+
311
+ async function sendMessage() {
312
+ const text = userInput.value.trim();
313
+ const file = fileInput.files[0];
314
+ if (!text && !file) return;
315
+
316
+ if (file) appendImageMessage(imagePreview.src, 'user');
317
+ if (text) appendMessage(text, 'user');
318
+
319
+ userInput.value = '';
320
+ removeSelectedImage();
321
+ setLoading(true);
322
+
323
+ const formData = new FormData();
324
+ formData.append('message', text || "این تصویر را تحلیل کن");
325
+ if (file) formData.append('image', file);
326
+
327
+ try {
328
+ const response = await fetch('/api/chat', { method: 'POST', body: formData });
329
+ const data = await response.json();
330
+
331
+ if (response.ok) {
332
+ appendMessage(data.response, 'ai');
333
+ } else {
334
+ appendMessage("خطا: " + (data.detail || "مشکلی در دریافت پاسخ رخ داد."), 'ai');
335
+ }
336
+ } catch (error) {
337
+ appendMessage("خطای شبکه: دریافت پاسخ از سرور انجام نشد.", 'ai');
338
+ } finally {
339
+ setLoading(false);
340
+ }
341
+ }
342
+
343
+ function appendMessage(text, sender) {
344
+ const msgDiv = document.createElement('div');
345
+ msgDiv.classList.add('message', sender);
346
+ msgDiv.innerText = text;
347
+ messagesBox.appendChild(msgDiv);
348
+ messagesBox.scrollTop = messagesBox.scrollHeight;
349
+ }
350
+
351
+ function appendImageMessage(src, sender) {
352
+ const msgDiv = document.createElement('div');
353
+ msgDiv.classList.add('message', sender);
354
+ msgDiv.style.padding = '8px';
355
+ const img = document.createElement('img');
356
+ img.src = src;
357
+ img.style.maxWidth = '200px';
358
+ img.style.maxHeight = '200px';
359
+ img.style.borderRadius = '12px';
360
+ img.style.display = 'block';
361
+ msgDiv.appendChild(img);
362
+ messagesBox.appendChild(msgDiv);
363
+ messagesBox.scrollTop = messagesBox.scrollHeight;
364
+ }
365
+
366
+ function setLoading(isLoading) {
367
+ if (isLoading) {
368
+ userInput.disabled = true;
369
+ sendBtn.disabled = true;
370
+ const indicator = document.createElement('div');
371
+ indicator.classList.add('typing-indicator');
372
+ indicator.id = 'typingIndicator';
373
+ indicator.innerHTML = '<span></span><span></span><span></span>';
374
+ messagesBox.appendChild(indicator);
375
+ messagesBox.scrollTop = messagesBox.scrollHeight;
376
+ } else {
377
+ userInput.disabled = false;
378
+ sendBtn.disabled = false;
379
+ const indicator = document.getElementById('typingIndicator');
380
+ if (indicator) indicator.remove();
381
+ userInput.focus();
382
+ }
383
+ }
384
+ </script>
385
+ </body>
386
+ </html>
387
+ """
388
+
389
+ @app.get("/", response_class=HTMLResponse)
390
+ async def chat_interface():
391
+ return HTML_CHAT_INTERFACE
392
+
393
+ @app.post("/api/chat")
394
+ async def chat_endpoint(message: str = Form(...), image: UploadFile = File(None)):
395
+ saved_image_path = None
396
+
397
+ if image:
398
+ try:
399
+ saved_image_path = os.path.join(UPLOAD_DIR, f"{int(time.time())}_{image.filename}")
400
+ with open(saved_image_path, "wb") as buffer:
401
+ buffer.write(await image.read())
402
+ except Exception as e:
403
+ raise HTTPException(status_code=500, detail=f"خطا در ذخیره‌سازی تصویر: {str(e)}")
404
+
405
+ url = "https://www.google.com/search?q=سلام&udm=50"
406
+ ai_response = ""
407
+
408
+ async with async_playwright() as p:
409
+ try:
410
+ browser = await p.chromium.launch(
411
+ headless=True,
412
+ args=[
413
+ "--no-sandbox",
414
+ "--disable-setuid-sandbox",
415
+ "--disable-dev-shm-usage",
416
+ "--disable-blink-features=AutomationControlled"
417
+ ]
418
+ )
419
+
420
+ context = await browser.new_context(
421
+ user_agent="Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36",
422
+ viewport={"width": 412, "height": 915},
423
+ locale="fa-IR",
424
+ timezone_id="Asia/Tehran"
425
+ )
426
+
427
+ page = await context.new_page()
428
+ await page.goto(url, wait_until="networkidle", timeout=45000)
429
+ await page.wait_for_timeout(3000)
430
+
431
+ # پروسه مالتی‌مدال و انتقال تصویر با ضریب ایمنی بالا و گام‌های مستقل خطا‌پذیر
432
+ if saved_image_path and os.path.exists(saved_image_path):
433
+ uploaded = False
434
+
435
+ # استراتژی ۱: تلاش برای تزریق مستقیم به لایه بارگذاری فایل (بدون نیاز به کلیک و باز کردن منو)
436
+ try:
437
+ file_input = await page.query_selector("input[type='file']")
438
+ if file_input:
439
+ await file_input.set_input_files(saved_image_path)
440
+ await page.wait_for_timeout(3000)
441
+ uploaded = True
442
+ print("Direct file input injection succeeded.")
443
+ except Exception as e:
444
+ print(f"Direct injection bypassed: {e}")
445
+
446
+ # استراتژی ۲: اگر تزریق مستقیم عمل نکرد، کلیک روی آیکون پلاس با تایم‌اوت کوتاه و باز کردن منوی گالری
447
+ if not uploaded:
448
+ try:
449
+ # فوکوس روی کادر چت با تایم‌اوت ۲ ثانیه‌ای برای باز شدن ابزارهای کناری
450
+ chat_inputs = await page.query_selector_all("textarea, input[type='text'], [contenteditable='true']")
451
+ for inp in chat_inputs:
452
+ try:
453
+ if await inp.is_visible():
454
+ await inp.click(timeout=2000)
455
+ await page.wait_for_timeout(500)
456
+ break
457
+ except:
458
+ continue
459
+
460
+ # پیدا کردن آیکون مثبت یا دوربین و فعال‌سازی شبیه‌ساز فایل چوزر
461
+ elements = await page.query_selector_all("button, div[role='button'], svg, [aria-label]")
462
+ for el in elements:
463
+ try:
464
+ if await el.is_visible():
465
+ aria = (await el.get_attribute("aria-label") or "").lower()
466
+ html = (await el.inner_html() or "").lower()
467
+ text = (await el.inner_text() or "").lower()
468
+ combined = aria + html + text
469
+
470
+ if any(k in combined for k in ["+", "plus", "camera", "lens", "دوربین", "تصویر", "عکس"]):
471
+ async with page.expect_file_chooser(timeout=3000) as fc_info:
472
+ await el.click(timeout=2000) # تایم‌اوت امن ۲ ثانیه‌ای به جای ۳۰ ثانیه معطلی
473
+ file_chooser = await fc_info.value
474
+ await file_chooser.set_files(saved_image_path)
475
+ await page.wait_for_timeout(3000)
476
+ uploaded = True
477
+ print("Uploaded via main UI icon trigger.")
478
+ break
479
+ except:
480
+ continue
481
+ except Exception as e:
482
+ print(f"UI icon flow failed: {e}")
483
+
484
+ # استراتژی ۳: کلیک مستقیم روی منوی پاپ‌آپ پایینی (گالری یا فایل‌ها) در صورت باز شدن لایه شیت گوگل
485
+ if not uploaded:
486
+ try:
487
+ menu_items = await page.query_selector_all("div, span, button, p")
488
+ for item in menu_items:
489
+ try:
490
+ item_text = (await item.inner_text() or "").strip()
491
+ if item_text in ["گالری", "فایل‌ها", "Gallery", "Files"]:
492
+ if await item.is_visible():
493
+ async with page.expect_file_chooser(timeout=3000) as fc_info:
494
+ await item.click(timeout=2000)
495
+ file_chooser = await fc_info.value
496
+ await file_chooser.set_files(saved_image_path)
497
+ await page.wait_for_timeout(3000)
498
+ uploaded = True
499
+ print("Uploaded via bottom sheet item click.")
500
+ break
501
+ except:
502
+ continue
503
+ except Exception as e:
504
+ print(f"Bottom sheet workflow failed: {e}")
505
+
506
+ # یافتن کادر متنی گفتگو جهت وارد کردن متن پیام کاربر
507
+ input_box = None
508
+ candidates = await page.query_selector_all("textarea, input, [contenteditable='true']")
509
+ for el in candidates:
510
+ try:
511
+ if await el.is_visible():
512
+ placeholder = await el.get_attribute("placeholder") or ""
513
+ if any(w in placeholder for w in ["بپرسید", "ask", "پیام", "چطور", "هرچه"]):
514
+ input_box = el
515
+ break
516
+ except:
517
+ continue
518
+
519
+ if not input_box:
520
+ input_box = await page.query_selector("textarea") or await page.query_selector("input[type='text']")
521
+
522
+ if input_box:
523
+ await input_box.focus()
524
+ await input_box.fill(message)
525
+ await page.wait_for_timeout(500)
526
+ await input_box.press("Enter")
527
+
528
+ # کلیک بر روی آیکون ارسال فرم (فلش آبی بالا) با استفاده از زمان‌بندی محدود ۲ ثانیه‌ای
529
+ try:
530
+ send_buttons = await page.query_selector_all("button, [role='button']")
531
+ for btn in send_buttons:
532
+ if await btn.is_visible():
533
+ aria = (await btn.get_attribute("aria-label") or "").lower()
534
+ if any(w in aria for w in ["send", "ارسال", "arrow", "up"]):
535
+ await btn.click(timeout=2000)
536
+ break
537
+ except:
538
+ pass
539
+
540
+ # انتظار تعمدی به مدت ۹ ثانیه جهت تایپ کامل جواب توسط هوش مصنوعی گوگل
541
+ await page.wait_for_timeout(9000)
542
+
543
+ full_text = await page.evaluate("() => document.body.innerText")
544
+ await browser.close()
545
+
546
+ # فیلترسازی خطوط خروجی برای تمیز کردن تگ‌های اضافی سرچ گوگل
547
+ lines = full_text.split('\n')
548
+ cleaned_lines = []
549
+ skip_headers = ["تصاویر", "ویدیوها", "اخبار", "نقشه‌ها", "خرید کردن", "کتاب‌ها", "مالی", "حالت موضوع‌محور", "ورود"]
550
+
551
+ for line in lines:
552
+ line_str = line.strip()
553
+ if not line_str:
554
+ continue
555
+ if any(header in line_str for header in skip_headers):
556
+ continue
557
+ if "در پاسخ‌های" in line_str or "بیشتر بدانید" in line_str:
558
+ continue
559
+ cleaned_lines.append(line_str)
560
+
561
+ ai_response = "\n".join(cleaned_lines)
562
+ if not ai_response:
563
+ ai_response = full_text
564
+
565
+ except Exception as e:
566
+ if 'browser' in locals():
567
+ await browser.close()
568
+ raise HTTPException(status_code=500, detail=f"خطا در رندر سرور هوش مصنوعی: {str(e)}")
569
+ finally:
570
+ # پاکسازی حتمی فایل تصویر از روی سرور داکر
571
+ if saved_image_path and os.path.exists(saved_image_path):
572
+ try:
573
+ os.remove(saved_image_path)
574
+ except:
575
+ pass
576
+
577
+ return JSONResponse(content={"response": ai_response})
578
+
579
+ if __name__ == "__main__":
580
+ uvicorn.run(app, host="0.0.0.0", port=7860)