Jan2000 commited on
Commit
27294a0
·
unverified ·
1 Parent(s): d909246

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -30
app.py CHANGED
@@ -11,7 +11,7 @@ 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):
@@ -36,7 +36,7 @@ def setup_logging():
36
  setup_logging()
37
  app = Flask(__name__)
38
 
39
- # ================== بخش پیکربندی Gemini (با تغییر) ==================
40
 
41
  GEMINI_MODEL_NAME = "gemini-2.5-flash"
42
  ALL_KEYS_STR = os.environ.get("ALL_GEMINI_API_KEYS", "")
@@ -58,6 +58,11 @@ def get_next_key_with_index():
58
  key_index_counter = (key_index_counter + 1) % len(GEMINI_API_KEYS)
59
  return key, current_index
60
 
 
 
 
 
 
61
  # ================== پایان بخش پیکربندی ====================
62
 
63
  @app.route('/')
@@ -67,8 +72,8 @@ def index():
67
  @app.route('/chat', methods=['POST'])
68
  def chat():
69
  if not GEMINI_API_KEYS:
70
- # اگر هیچ کلیدی نباشد چاره‌ای جز خطا نیست، اما این حالت نادری است
71
- return Response("data: [DONE]\n\n", mimetype='text/event-stream')
72
 
73
  data = request.json
74
  system_instruction = "تو چت بات هوش مصنوعی آلفا هستی و توسط برنامه هوش مصنوعی آلفا توسعه داده شدی. کمی با کاربران باحال و دوستانه صحبت کن و از ایموجی‌ها استفاده کن. همیشه پاسخ‌هایت را به زبان فارسی و یا هر زبانی که کاربر صحبت میکنه ارائه بده."
@@ -116,14 +121,16 @@ def chat():
116
  return Response("data: [DONE]\n\n", mimetype='text/event-stream')
117
 
118
  def stream_response():
119
- # تلاش برای تعداد زیادی بار (عملا تا وقتی یک کلید سالم پیدا شود)
120
- # ضرب در 2 یعنی هر کلید را دو بار شانس می دهیم اگر شبکه قطع و وصل شد
121
- max_attempts = len(GEMINI_API_KEYS) * 3
 
122
 
123
- for attempt in range(max_attempts):
 
124
  try:
125
  api_key, key_index = get_next_key_with_index()
126
- # logging.info(f"تلاش با کلید شماره {key_index + 1}...")
127
 
128
  api_endpoint = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL_NAME}:streamGenerateContent?key={api_key}&alt=sse"
129
 
@@ -141,17 +148,26 @@ def chat():
141
  "include_thoughts": True
142
  }
143
 
144
- # *** نکته مهم: Timeout بسیار کوتاه برای اتصال، تا سریع برود کلید بعدی ***
145
- # connect=4: اگر 4 ثانیه وصل نشد، ولش کن برو بعدی
146
- # read=20: اگر وسط کار 20 ثانیه دیتا نیامد، ولش کن برو بعدی
147
- with requests.post(api_endpoint, json=payload, stream=True, timeout=(4, 20)) as response:
 
 
 
 
 
 
 
 
 
 
 
148
 
149
- # اگر ارور 429 (محدودیت) یا هر ارور دیگری داد، سریع برو بعدی
150
- if response.status_code != 200:
151
- logging.warning(f"کلید {key_index + 1} با وضعیت {response.status_code} پاسخ نداد. تلاش با کلید بعدی...")
152
- continue
153
 
154
- # اگر موفق شد، شروع به ارسال کن و از تابع خارج شو (return)
155
  for line in response.iter_lines():
156
  if line:
157
  decoded_line = line.decode('utf-8')
@@ -163,6 +179,8 @@ def chat():
163
  for part in parts:
164
  if "text" not in part or not part["text"]:
165
  continue
 
 
166
  is_a_thought = part.get("thought") is True
167
  if show_thoughts and is_a_thought:
168
  thought_payload = {"type": "thought", "content": part["text"]}
@@ -173,24 +191,38 @@ def chat():
173
  except (json.JSONDecodeError, IndexError, KeyError):
174
  continue
175
 
176
- # اگر استریم بدون خطا تمام شد، کار تمام است
177
- return
178
-
 
 
 
 
 
 
 
 
 
 
179
  except Exception as e:
180
- # هر نوع خطایی (تایم اوت، شبکه و ...) رخ داد، فقط لاگ کن و برو کلید بعدی
181
- # هیچ خطایی به کاربر نشان نده
182
- logging.warning(f"خطا در کلید {key_index + 1}: {e} - رفتن به کلید بعدی")
183
- continue
184
 
185
- # اگر همه کلیدها تست شدند و نشد (خیلی بعید)، یک پیام خالی بفرست که ارور نده
186
- logging.critical("هیچ کلیدی کار نکرد.")
187
- # به جای ارور، یک پیام ساده میفرستیم که برنامه کرش نکند
188
- end_payload = {"choices": [{"delta": {"content": "..."}}]}
189
- yield f"data: {json.dumps(end_payload)}\n\n"
 
 
 
190
 
191
  return Response(stream_response(), mimetype='text/event-stream')
192
 
193
  if __name__ == '__main__':
 
 
194
  app.run(debug=True, host='0.0.0.0', port=os.environ.get("PORT", 7860))
195
 
196
  # --- END OF FILE app.py ---
 
11
  import requests
12
  import docx
13
 
14
+ # ================== بخش تنظیمات لاگ‌نویسی ==================
15
 
16
  class NoGrpcFilter(logging.Filter):
17
  def filter(self, record):
 
36
  setup_logging()
37
  app = Flask(__name__)
38
 
39
+ # ================== بخش پیکربندی Gemini ==================
40
 
41
  GEMINI_MODEL_NAME = "gemini-2.5-flash"
42
  ALL_KEYS_STR = os.environ.get("ALL_GEMINI_API_KEYS", "")
 
58
  key_index_counter = (key_index_counter + 1) % len(GEMINI_API_KEYS)
59
  return key, current_index
60
 
61
+ # تنظیمات تایم‌اوت برای درخواست‌ها به گوگل
62
+ # تایم‌اوت اول برای اتصال، دومی برای خواندن داده. مقادیر افزایش یافته تا پایداری بیشتر شود.
63
+ STREAM_CONNECT_TIMEOUT = 10
64
+ STREAM_READ_TIMEOUT = 40
65
+
66
  # ================== پایان بخش پیکربندی ====================
67
 
68
  @app.route('/')
 
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 = "تو چت بات هوش مصنوعی آلفا هستی و توسط برنامه هوش مصنوعی آلفا توسعه داده شدی. کمی با کاربران باحال و دوستانه صحبت کن و از ایموجی‌ها استفاده کن. همیشه پاسخ‌هایت را به زبان فارسی و یا هر زبانی که کاربر صحبت میکنه ارائه بده."
 
121
  return Response("data: [DONE]\n\n", mimetype='text/event-stream')
122
 
123
  def stream_response():
124
+ # تعداد دفعات تلاش کلی: به اندازه 2 برابر تعداد کلیدها تلاش میکنیم تا مطمئن شویم
125
+ max_attempts = len(GEMINI_API_KEYS) * 2
126
+ attempts = 0
127
+ last_error = None
128
 
129
+ while attempts < max_attempts:
130
+ attempts += 1
131
  try:
132
  api_key, key_index = get_next_key_with_index()
133
+ # logging.info(f"تلاش شماره {attempts}: استفاده از کلید ایندکس {key_index}")
134
 
135
  api_endpoint = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL_NAME}:streamGenerateContent?key={api_key}&alt=sse"
136
 
 
148
  "include_thoughts": True
149
  }
150
 
151
+ # ارسال درخواست به گوگل
152
+ with requests.post(api_endpoint, json=payload, stream=True, timeout=(STREAM_CONNECT_TIMEOUT, STREAM_READ_TIMEOUT)) as response:
153
+ # اگر خطای 429 (محدودیت نرخ) یا 5xx (خطای سرور گوگل) باشد
154
+ if response.status_code == 429 or response.status_code >= 500:
155
+ logging.warning(f"خطای {response.status_code} با کلید {key_index}. رفتن به کلید بعدی...")
156
+ last_error = f"Status Code: {response.status_code}"
157
+ continue # برو به کلید بعدی
158
+
159
+ # اگر خطای 403 (Forbidden/Invalid Key) باشد
160
+ if response.status_code == 403:
161
+ logging.warning(f"کلید {key_index} نامعتبر است (403). رفتن به کلید بعدی...")
162
+ last_error = "Invalid API Key (403)"
163
+ continue
164
+
165
+ response.raise_for_status()
166
 
167
+ # اگر موفق شدیم وصل بشیم، شروع به استریم میکنیم
168
+ # logging.info(f"اتصال موفق با کلید {key_index}. شروع استریم...")
 
 
169
 
170
+ data_received = False
171
  for line in response.iter_lines():
172
  if line:
173
  decoded_line = line.decode('utf-8')
 
179
  for part in parts:
180
  if "text" not in part or not part["text"]:
181
  continue
182
+
183
+ data_received = True
184
  is_a_thought = part.get("thought") is True
185
  if show_thoughts and is_a_thought:
186
  thought_payload = {"type": "thought", "content": part["text"]}
 
191
  except (json.JSONDecodeError, IndexError, KeyError):
192
  continue
193
 
194
+ # اگر دیتا با موفقیت دریافت شد و حلقه تمام شد، از تابع خارج میشویم
195
+ if data_received:
196
+ return
197
+ else:
198
+ # اگر وصل شدیم اما دیتایی نیامد (پاسخ خالی)، شاید مشکلی بوده، امتحان مجدد با کلید بعدی
199
+ last_error = "Empty response"
200
+ continue
201
+
202
+ except (requests.exceptions.Timeout, requests.exceptions.ConnectionError, requests.exceptions.ChunkedEncodingError) as e:
203
+ logging.warning(f"خطای شبکه/تایم‌اوت با کلید {key_index}: {str(e)}. تلاش مجدد با کلید بعدی...")
204
+ last_error = str(e)
205
+ continue # برو به کلید بعدی
206
+
207
  except Exception as e:
208
+ logging.error(f"خطای غیرمنتظره با کلید {key_index}: {e}")
209
+ last_error = str(e)
210
+ continue # برای اطمینان، حتی با خطای عجیب هم سعی میکنیم با کلید بعدی ادامه بدیم
 
211
 
212
+ # اگر همه تلاش‌ها شکست خورد
213
+ logging.critical("تمام کلیدها امتحان شدند و پاسخگو نبودند.")
214
+ # اینجا دیگر چاره‌ای نیست جز نمایش خطا، اما چون کاربر گفته خطا نبینه،
215
+ # می‌توانیم یک پیام مودبانه بفرستیم یا هیچ چیزی نفرستیم (که البته باعث میشه کاربر فکر کنه هنوز داره فکر میکنه)
216
+ # بهترین کار ارسال یک پیام خطای نرم است.
217
+ error_message = "سیستم در حال حاضر شلوغ است. لطفاً چند لحظه دیگر دوباره تلاش کنید."
218
+ error_payload = {"choices": [{"delta": {"content": error_message}}]} # به جای ارور، به عنوان متن چت میفرستیم
219
+ yield f"data: {json.dumps(error_payload)}\n\n"
220
 
221
  return Response(stream_response(), mimetype='text/event-stream')
222
 
223
  if __name__ == '__main__':
224
+ if GEMINI_API_KEYS:
225
+ logging.info(f"سیستم شروع به کار ��رد. {len(GEMINI_API_KEYS)} کلید شناسایی شد.")
226
  app.run(debug=True, host='0.0.0.0', port=os.environ.get("PORT", 7860))
227
 
228
  # --- END OF FILE app.py ---