Jan2000 commited on
Commit
63617fd
·
unverified ·
1 Parent(s): 5dab501

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -49
app.py CHANGED
@@ -57,13 +57,13 @@ def get_next_key_with_index():
57
  key_index_counter = (key_index_counter + 1) % len(GEMINI_API_KEYS)
58
  return key, current_index
59
 
60
- # *** START: MODIFIED - افزودن ثابت‌های جدید برای مهلت زمانی ***
61
- # مهلت زمانی (به ثانیه) برای شروع دریافت پاسخ از سرور
62
- STREAM_START_TIMEOUT = 4
63
- # مهلت زمانی (به ثانیه) برای دریافت هر قطعه جدید از داده در حین استریم
64
- # اگر در این مدت داده جدیدی نرسد، اتصال قطع و با کلید بعدی تلاش می‌شود
65
- STREAM_READ_TIMEOUT = 15
66
- # *** END: MODIFIED ***
67
 
68
  # ================== پایان بخش پیکربندی ====================
69
 
@@ -82,7 +82,7 @@ def chat():
82
 
83
  show_thoughts = data.get("show_thoughts", False)
84
 
85
- # بخش پردازش پیام‌ها و فایل DOCX (بدون تغییر باقی می‌ماند)
86
  gemini_messages = []
87
  for msg in data.get("messages", []):
88
  role = "model" if msg.get("role") == "assistant" else msg.get("role")
@@ -124,10 +124,14 @@ def chat():
124
 
125
  def stream_response():
126
  last_error = None
127
- for _ in range(len(GEMINI_API_KEYS)):
 
 
 
 
128
  try:
129
  api_key, key_index = get_next_key_with_index()
130
- logging.info(f"تلاش برای ارسال درخواست با کلید شماره {key_index + 1}...")
131
 
132
  api_endpoint = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL_NAME}:streamGenerateContent?key={api_key}&alt=sse"
133
 
@@ -145,19 +149,29 @@ def chat():
145
  "include_thoughts": True
146
  }
147
 
148
- # *** START: MODIFIED - استفاده از Timeout تفکیک شده ***
149
- # timeout اول برای اتصال اولیه، timeout دوم برای فاصله بین دریافت داده‌ها
150
- with requests.post(api_endpoint, json=payload, stream=True, timeout=(STREAM_START_TIMEOUT, STREAM_READ_TIMEOUT)) as response:
151
- # *** END: MODIFIED ***
152
- if response.status_code == 429:
153
- logging.warning(f"کلید شماره {key_index + 1} سهمیه آن تمام شده است. در حال تلاش با کلید بعدی...")
154
- last_error = "Rate limit exceeded"
155
- continue
 
 
 
 
 
 
 
 
 
156
 
157
- response.raise_for_status()
158
- logging.info(f"اتصال با کلید شماره {key_index + 1} موفقیت‌آمیز بود. در حال استریم پاسخ...")
159
 
160
- # بخش استریم پاسخ (بدون تغییر)
 
 
161
  for line in response.iter_lines():
162
  if line:
163
  decoded_line = line.decode('utf-8')
@@ -169,6 +183,8 @@ def chat():
169
  for part in parts:
170
  if "text" not in part or not part["text"]:
171
  continue
 
 
172
  is_a_thought = part.get("thought") is True
173
  if show_thoughts and is_a_thought:
174
  thought_payload = {"type": "thought", "content": part["text"]}
@@ -179,37 +195,42 @@ def chat():
179
  except (json.JSONDecodeError, IndexError, KeyError):
180
  continue
181
 
182
- logging.info(f"استریم با کلید شماره {key_index + 1} به پایان رسید.")
183
- return
184
-
185
- # *** START: MODIFIED - افزودن ReadTimeout به مدیریت خطا ***
186
- except (requests.exceptions.Timeout, requests.exceptions.ReadTimeout) as e:
187
- if isinstance(e, requests.exceptions.ReadTimeout):
188
- logging.warning(f"استریم با کلید شماره {key_index + 1} به دلیل عدم دریافت داده جدید متوقف شد (ReadTimeout). در حال تلاش با کلید بعدی...")
189
- last_error = f"ReadTimeout after {STREAM_READ_TIMEOUT} seconds of inactivity"
190
- else:
191
- logging.warning(f"مهلت زمانی برای اتصال با کلید شماره {key_index + 1} به پایان رسید (ConnectTimeout). در حال تلاش با کلید بعدی...")
192
- last_error = f"ConnectTimeout after {STREAM_START_TIMEOUT} seconds"
 
 
 
 
 
 
 
193
  continue
194
- # *** END: MODIFIED ***
195
-
196
- except requests.exceptions.HTTPError as e:
197
- if e.response.status_code == 403:
198
- logging.warning(f"کلید شماره {key_index + 1} نامعتبر است (Permission Denied). در حال تلاش با کلید بعدی...")
199
- last_error = e
200
- continue
201
- else:
202
- logging.error(f"خطای HTTP پیش‌بینی نشده در حین تلاش با کلید {key_index + 1}: {e}")
203
- last_error = e
204
- break
205
 
 
 
 
 
 
206
  except Exception as e:
207
- logging.error(f"خطای پیش‌بینی نشده در حین تلاش با کلید {key_index + 1}: {e}")
208
- last_error = e
209
- break
 
 
 
 
 
 
210
 
211
- error_message = f"متاسفانه تمام کلیدهای API موجود نامعتبر هستند یا سهمیه آنها به پایان رسیده است. لطفا بعدا تلاش کنید.\n\nآخرین خطا: {str(last_error)}"
212
- logging.critical("هیچ‌کدام از کلیدهای Gemini کار نکردند.")
213
  error_payload = {"type": "error", "message": error_message}
214
  yield f"data: {json.dumps(error_payload)}\n\n"
215
 
@@ -217,7 +238,7 @@ def chat():
217
 
218
  if __name__ == '__main__':
219
  if GEMINI_API_KEYS:
220
- logging.info(f"سیستم در حالت توسعه شروع به کار کرد. تعداد {len(GEMINI_API_KEYS)} کلید شناسایی شد.")
221
  app.run(debug=True, host='0.0.0.0', port=os.environ.get("PORT", 7860))
222
 
223
  # --- END OF FILE app.py ---
 
57
  key_index_counter = (key_index_counter + 1) % len(GEMINI_API_KEYS)
58
  return key, current_index
59
 
60
+ # *** START: OPTIMIZED TIMEOUT SETTINGS ***
61
+ # مهلت زمانی برای برقراری اتصال اولیه با سرور گوگل (اگر اینترنت قطع باشد یا سرور دان باشد سریع سوئیچ میکند)
62
+ STREAM_CONNECT_TIMEOUT = 10
63
+ # مهلت زمانی برای انتظار پردازش و دریافت پاسخ.
64
+ # برای فایل‌ها بسیار مهم است که این عدد بالا باشد (مثلا 100 ثانیه) تا وسط پردازش فایل قطع نکند.
65
+ STREAM_READ_TIMEOUT = 100
66
+ # *** END: OPTIMIZED TIMEOUT SETTINGS ***
67
 
68
  # ================== پایان بخش پیکربندی ====================
69
 
 
82
 
83
  show_thoughts = data.get("show_thoughts", False)
84
 
85
+ # بخش پردازش پیام‌ها و فایل DOCX
86
  gemini_messages = []
87
  for msg in data.get("messages", []):
88
  role = "model" if msg.get("role") == "assistant" else msg.get("role")
 
124
 
125
  def stream_response():
126
  last_error = None
127
+ # تلاش برای همه کلیدها تا زمانی که یکی جواب دهد
128
+ # ما یک کپی از لیست کلیدها میگیریم تا مطمئن شویم حلقه به اندازه تعداد کلیدها اجرا میشود
129
+ attempts = len(GEMINI_API_KEYS)
130
+
131
+ for i in range(attempts):
132
  try:
133
  api_key, key_index = get_next_key_with_index()
134
+ logging.info(f"تلاش {i+1} از {attempts}: ارسال درخواست با کلید شماره {key_index + 1}...")
135
 
136
  api_endpoint = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL_NAME}:streamGenerateContent?key={api_key}&alt=sse"
137
 
 
149
  "include_thoughts": True
150
  }
151
 
152
+ # استفاده از تنظیمات Timeout بهینه شده
153
+ # connect: زمان اتصال به سرور (سریع)
154
+ # read: زمان انتظار برای پردازش فایل و پاسخ (طولانی)
155
+ with requests.post(api_endpoint, json=payload, stream=True, timeout=(STREAM_CONNECT_TIMEOUT, STREAM_READ_TIMEOUT)) as response:
156
+
157
+ # بررسی خطاهای HTTP
158
+ if response.status_code != 200:
159
+ logging.warning(f"خطای سرور با کلید {key_index + 1}: کد {response.status_code} - متن: {response.text}")
160
+ # اگر محدودیت درخواست یا خطای سرور بود، برو کلید بعدی
161
+ if response.status_code in [429, 500, 502, 503, 504]:
162
+ last_error = f"HTTP {response.status_code}"
163
+ continue # پرش سریع به کلید بعدی
164
+ elif response.status_code == 403:
165
+ last_error = "Invalid API Key"
166
+ continue # پرش سریع
167
+ else:
168
+ response.raise_for_status() # برای سایر خطاها
169
 
170
+ logging.info(f"اتصال با کلید شماره {key_index + 1} برقرار شد. در حال دریافت داده...")
 
171
 
172
+ # اگر به اینجا رسیدیم یعنی اتصال موفق بوده و استریم شروع شده
173
+ # حالا داده‌ها را به کلاینت می‌فرستیم
174
+ has_sent_data = False
175
  for line in response.iter_lines():
176
  if line:
177
  decoded_line = line.decode('utf-8')
 
183
  for part in parts:
184
  if "text" not in part or not part["text"]:
185
  continue
186
+
187
+ has_sent_data = True
188
  is_a_thought = part.get("thought") is True
189
  if show_thoughts and is_a_thought:
190
  thought_payload = {"type": "thought", "content": part["text"]}
 
195
  except (json.JSONDecodeError, IndexError, KeyError):
196
  continue
197
 
198
+ # اگر حلقه تمام شد و دیتایی ارسال شد، یعنی موفقیت آمیز بوده
199
+ if has_sent_data:
200
+ logging.info(f"پاسخ کامل با کلید {key_index + 1} ارسال شد.")
201
+ return # خروج از کل تابع و پایان کار
202
+ else:
203
+ # اگر هیچ دیتایی نیامد اما کد 200 بود (مثلا پاسخ خالی)، باز هم موفقیت حساب میشه
204
+ return
205
+
206
+ except requests.exceptions.ConnectTimeout:
207
+ logging.warning(f"Timeout در اتصال با کلید {key_index + 1}. تلاش فوری با کلید بعدی...")
208
+ last_error = "Connection Timeout"
209
+ continue # تلاش با کلید بعدی
210
+
211
+ except requests.exceptions.ReadTimeout:
212
+ # اگر ReadTimeout رخ داد یعنی گوگل خیلی طولش داده، اما معمولا با 100 ثانیه رخ نمیده.
213
+ # اگر رخ داد یعنی سرور پاسخگو نیست، پس کلید بعدی.
214
+ logging.warning(f"ReadTimeout (عدم پاسخگویی طولانی) با کلید {key_index + 1}. تلاش با کلید بعدی...")
215
+ last_error = "Read Timeout"
216
  continue
 
 
 
 
 
 
 
 
 
 
 
217
 
218
+ except requests.exceptions.ConnectionError:
219
+ logging.warning(f"خطای شبکه (ConnectionError) با کلید {key_index + 1}. تلاش با کلید بعدی...")
220
+ last_error = "Network Error"
221
+ continue
222
+
223
  except Exception as e:
224
+ logging.error(f"خطای پیش‌بی��ی نشده با کلید {key_index + 1}: {e}")
225
+ last_error = str(e)
226
+ # برای خطاهای ناشناخته هم به کلید بعدی شانس میدهیم
227
+ continue
228
+
229
+ # اگر حلقه تمام شد و هیچ کلیدی موفق نشد:
230
+ error_message = "متاسفانه سرور پاسخگو نیست. لطفا دقایقی دیگر تلاش کنید."
231
+ if last_error:
232
+ logging.critical(f"تمام تلاش‌ها ناموفق بود. آخرین خطا: {last_error}")
233
 
 
 
234
  error_payload = {"type": "error", "message": error_message}
235
  yield f"data: {json.dumps(error_payload)}\n\n"
236
 
 
238
 
239
  if __name__ == '__main__':
240
  if GEMINI_API_KEYS:
241
+ logging.info(f"سیستم شروع به کار کرد. تعداد {len(GEMINI_API_KEYS)} کلید شناسایی شد.")
242
  app.run(debug=True, host='0.0.0.0', port=os.environ.get("PORT", 7860))
243
 
244
  # --- END OF FILE app.py ---