Opera8 commited on
Commit
768de33
·
verified ·
1 Parent(s): 57c2746

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -221
app.py DELETED
@@ -1,221 +0,0 @@
1
- # --- START OF FILE app.py ---
2
-
3
- import os
4
- import json
5
- import logging
6
- import threading
7
- import base64
8
- import io
9
- import time
10
- from flask import Flask, render_template, request, Response
11
- import requests
12
- import docx
13
-
14
- # ================== بخش تنظیمات لاگ‌نویسی ==================
15
-
16
- class NoGrpcFilter(logging.Filter):
17
- def filter(self, record):
18
- return not record.getMessage().startswith('ALTS creds ignored.')
19
-
20
- def setup_logging():
21
- log_format = '[%(asctime)s] [%(levelname)s]: %(message)s'
22
- date_format = '%Y-%m-%d %H:%M:%S'
23
- formatter = logging.Formatter(log_format, datefmt=date_format)
24
-
25
- root_logger = logging.getLogger()
26
- if root_logger.hasHandlers():
27
- root_logger.handlers.clear()
28
-
29
- console_handler = logging.StreamHandler()
30
- console_handler.setFormatter(formatter)
31
- console_handler.addFilter(NoGrpcFilter())
32
-
33
- root_logger.addHandler(console_handler)
34
- root_logger.setLevel(logging.INFO)
35
-
36
- setup_logging()
37
- app = Flask(__name__)
38
-
39
- # ================== بخش پیکربندی Gemini ==================
40
-
41
- # مدل 2.5 فلش بهترین مدل برای پردازش ویدیو است
42
- GEMINI_MODEL_NAME = "gemini-2.5-flash"
43
- ALL_KEYS_STR = os.environ.get("ALL_GEMINI_API_KEYS", "")
44
- GEMINI_API_KEYS = [key.strip() for key in ALL_KEYS_STR.split(',') if key.strip()]
45
-
46
- if not GEMINI_API_KEYS:
47
- logging.critical("هشدار: هیچ کلید API برای Gemini در Secrets تنظیم نشده است! (ALL_GEMINI_API_KEYS)")
48
-
49
- key_index_counter = 0
50
- key_lock = threading.Lock()
51
-
52
- def get_next_key_with_index():
53
- global key_index_counter
54
- with key_lock:
55
- if not GEMINI_API_KEYS:
56
- raise ValueError("لیست کلیدهای API خالی است.")
57
- current_index = key_index_counter
58
- key = GEMINI_API_KEYS[current_index]
59
- key_index_counter = (key_index_counter + 1) % len(GEMINI_API_KEYS)
60
- return key, current_index
61
-
62
- # افزایش تایم‌اوت برای آپلود ویدیو ضروری است
63
- STREAM_CONNECT_TIMEOUT = 20
64
- STREAM_READ_TIMEOUT = 120
65
-
66
- # ================== پایان بخش پیکربندی ====================
67
-
68
- @app.route('/')
69
- def index():
70
- return render_template('index.html')
71
-
72
- @app.route('/chat', methods=['POST'])
73
- def chat():
74
- if not GEMINI_API_KEYS:
75
- error_payload = {"type": "error", "message": "خطای سرور: هیچ کلید API پیکربندی نشده است."}
76
- return Response(f"data: {json.dumps(error_payload)}\n\n", status=500, mimetype='text/event-stream')
77
-
78
- data = request.json
79
- system_instruction = "تو چت بات هوش مصنوعی آلفا هستی. تو توانایی تحلیل دقیق ویدیو، صدا و تصویر و انواع فایل هارا را داری. اگر کاربر ویدیویی فرستاد، تمام فریم‌ها و صدای آن را بررسی کن و به سوالات پاسخ بده و یا بقیه فایل ها. همیشه پاسخ‌هایت را به زبان فارسی و یا هر زبانی که کاربر صحبت میکنه ارائه بده.اگر کسی از تو پرسید که توسط کی ساخته شدی تو میگی من توسط هوش مصنوعی آلفا توسعه داده شدم فقط زمانی که پرسید. در احوال پرسی از شکلک های متفاوت مناسب استفاده کن ."
80
-
81
- show_thoughts = data.get("show_thoughts", False)
82
-
83
- # بخش پردازش پیام‌ها و فایل DOCX و ویدیو
84
- gemini_messages = []
85
- for msg in data.get("messages", []):
86
- role = "model" if msg.get("role") == "assistant" else msg.get("role")
87
-
88
- processed_parts = []
89
- for part in msg.get("parts", []):
90
- if part.get("text"):
91
- processed_parts.append({"text": part["text"]})
92
-
93
- if part.get("base64Data") and part.get("mimeType"):
94
- mime_type = part["mimeType"]
95
-
96
- if mime_type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
97
- try:
98
- decoded_data = base64.b64decode(part["base64Data"])
99
- file_stream = io.BytesIO(decoded_data)
100
- document = docx.Document(file_stream)
101
- full_text = "\n".join([para.text for para in document.paragraphs])
102
-
103
- final_text_part = f"کاربر یک فایل Word آپلود کرد. محتوای متنی آن به شرح زیر است:\n\n---\n\n{full_text}\n\n---"
104
- processed_parts.append({"text": final_text_part})
105
- logging.info("فایل DOCX با موفقیت پردازش و متن آن استخراج شد.")
106
-
107
- except Exception as e:
108
- logging.error(f"خطا در پردازش فایل DOCX: {e}")
109
- processed_parts.append({"text": "[خطا: امکان پردازش فایل Word وجود نداشت.]"})
110
-
111
- else:
112
- # *** تغییر اصلی برای ویدیو اینجاست ***
113
- # اگر فایل ویدیویی بود، یک راهنمایی متنی اضافه می‌کنیم تا مدل گیج نشود
114
- if mime_type.startswith("video/"):
115
- processed_parts.append({"text": "این فایل یک ویدیو است. لطفا فریم‌ها، حرکات و صدای داخل ویدیو را با دقت تحلیل کن."})
116
-
117
- processed_parts.append({"inline_data": {"mime_type": part["mimeType"], "data": part["base64Data"]}})
118
-
119
- if processed_parts:
120
- if gemini_messages and gemini_messages[-1]["role"] == role:
121
- gemini_messages[-1]["parts"].extend(processed_parts)
122
- else:
123
- gemini_messages.append({"role": role, "parts": processed_parts})
124
-
125
- if not any(msg['role'] == 'user' for msg in gemini_messages):
126
- return Response("data: [DONE]\n\n", mimetype='text/event-stream')
127
-
128
- def stream_response():
129
- # چرخش بین کلیدها در صورت بروز خطا
130
- max_attempts = len(GEMINI_API_KEYS) * 2
131
- attempts = 0
132
- last_error = None
133
-
134
- while attempts < max_attempts:
135
- attempts += 1
136
- try:
137
- api_key, key_index = get_next_key_with_index()
138
-
139
- api_endpoint = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL_NAME}:streamGenerateContent?key={api_key}&alt=sse"
140
-
141
- payload = {
142
- "contents": gemini_messages,
143
- "systemInstruction": {"parts": [{"text": system_instruction}]},
144
- "tools": [{"google_search": {}}],
145
- "generationConfig": {
146
- "temperature": 0.7,
147
- }
148
- }
149
-
150
- if show_thoughts:
151
- payload["generationConfig"]["thinking_config"] = {
152
- "include_thoughts": True
153
- }
154
-
155
- # درخواست به گوگل با تایم‌اوت کنترل شده
156
- with requests.post(api_endpoint, json=payload, stream=True, timeout=(STREAM_CONNECT_TIMEOUT, STREAM_READ_TIMEOUT)) as response:
157
-
158
- # مدیریت خطاهای خاص گوگل (429, 500, 403) برای سوئیچ روی کلید بعدی
159
- if response.status_code == 429 or response.status_code >= 500:
160
- logging.warning(f"خطای {response.status_code} با کلید {key_index}. رفتن به کلید بعدی...")
161
- last_error = f"Status Code: {response.status_code}"
162
- continue
163
-
164
- if response.status_code == 403:
165
- logging.warning(f"کلید {key_index} نامعتبر است (403). رفتن به کلید بعدی...")
166
- last_error = "Invalid API Key (403)"
167
- continue
168
-
169
- response.raise_for_status()
170
-
171
- data_received = False
172
- for line in response.iter_lines():
173
- if line:
174
- decoded_line = line.decode('utf-8')
175
- if decoded_line.startswith('data: '):
176
- try:
177
- chunk_data = json.loads(decoded_line[6:])
178
- parts = chunk_data.get("candidates", [{}])[0].get("content", {}).get("parts", [])
179
-
180
- for part in parts:
181
- if "text" not in part or not part["text"]:
182
- continue
183
-
184
- data_received = True
185
- is_a_thought = part.get("thought") is True
186
- if show_thoughts and is_a_thought:
187
- thought_payload = {"type": "thought", "content": part["text"]}
188
- yield f"data: {json.dumps(thought_payload)}\n\n"
189
- elif not is_a_thought:
190
- sse_payload = {"choices": [{"delta": {"content": part["text"]}}]}
191
- yield f"data: {json.dumps(sse_payload)}\n\n"
192
- except (json.JSONDecodeError, IndexError, KeyError):
193
- continue
194
-
195
- if data_received:
196
- return
197
- else:
198
- last_error = "Empty response"
199
- continue
200
-
201
- except (requests.exceptions.Timeout, requests.exceptions.ConnectionError, requests.exceptions.ChunkedEncodingError) as e:
202
- logging.warning(f"خطای شبکه با کلید {key_index}: {str(e)}. تلاش مجدد...")
203
- last_error = str(e)
204
- continue
205
-
206
- except Exception as e:
207
- logging.error(f"خطای غیرمنتظره با کلید {key_index}: {e}")
208
- last_error = str(e)
209
- continue
210
-
211
- # اگر هیچ کلیدی کار نکرد، پیام خطای ملایم به کاربر بده (نه ارور قرمز)
212
- error_message = "سیستم در حال پردازش سنگین است. لطفا مجددا تلاش کنید."
213
- error_payload = {"choices": [{"delta": {"content": error_message}}]}
214
- yield f"data: {json.dumps(error_payload)}\n\n"
215
-
216
- return Response(stream_response(), mimetype='text/event-stream')
217
-
218
- if __name__ == '__main__':
219
- app.run(debug=True, host='0.0.0.0', port=os.environ.get("PORT", 7860))
220
-
221
- # --- END OF FILE app.py ---