Opera8 commited on
Commit
718f1f0
·
verified ·
1 Parent(s): d05a2a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -55
app.py CHANGED
@@ -8,13 +8,19 @@ import time
8
  from datetime import date
9
  from fastapi import FastAPI, Request, BackgroundTasks
10
  from fastapi.responses import HTMLResponse, FileResponse, JSONResponse, RedirectResponse, StreamingResponse
 
 
11
  from fastapi.middleware.wsgi import WSGIMiddleware
12
 
13
- # 🟢 ایمپورت و فراخوانی ماژول مستقل روبیکا بات و صوتی
 
 
 
 
14
  from rubikabot import router as rubikabot_router
15
  from soti import router as soti_router
16
 
17
- # 🟢 ایمپورت فایل جدید اکشن (فلاسک) که از روی اسپیس tts3 کپی کرده‌اید
18
  import action
19
 
20
  app = FastAPI()
@@ -31,19 +37,7 @@ os.makedirs(USAGE_DIR, exist_ok=True)
31
  CLONE_USAGE_LIMIT = 1
32
  EDIT_USAGE_LIMIT = 5
33
 
34
- # 🟢 میان‌افزار هوشمند جهت تنظیم خودکار آدرس دامنه عمومی رانفلر شما در ماژول اکشن
35
- @app.middleware("http")
36
- async def set_space_url_middleware(request: Request, call_next):
37
- if not getattr(action, "SPACE_HOST", None):
38
- host = request.headers.get("host", "")
39
- if host:
40
- action.SPACE_HOST = host
41
- action.SPACE_URL = f"https://{host}"
42
- print(f"[Runflare Auto-Config] Set SPACE_URL dynamically to: {action.SPACE_URL}", flush=True)
43
- return await call_next(request)
44
-
45
  def get_client_ip(request: Request) -> str:
46
- """استخراج دقیق آی‌پی واقعی کاربر از پشت پروکسی‌های Cloudflare و هاست رانفلر"""
47
  cf_ip = request.headers.get("CF-Connecting-IP")
48
  if cf_ip:
49
  return cf_ip.strip()
@@ -54,7 +48,7 @@ def get_client_ip(request: Request) -> str:
54
  return request.client.host
55
  return "0.0.0.0"
56
 
57
- # --- بخش مدیریت دائمی اعتبار کلون صدا (ذخیره روی دیسک رانفلر) ---
58
  def get_local_clone_usage(key: str) -> dict:
59
  today_str = date.today().isoformat()
60
  safe_key = "".join([c for c in key if c.isalnum() or c in ["-", "_", "."]])
@@ -77,7 +71,6 @@ def save_local_clone_usage(key: str, data: dict):
77
  except: pass
78
 
79
  def check_local_clone_limit(fingerprint: str, ip: str) -> bool:
80
- """بررسی محدودیت کلون صدا: اگر اثر انگشت یا آی‌پی سهمیه‌اش پر باشد، بلاک می‌کند"""
81
  for key in [fingerprint, ip]:
82
  if not key: continue
83
  data = get_local_clone_usage(key)
@@ -86,14 +79,13 @@ def check_local_clone_limit(fingerprint: str, ip: str) -> bool:
86
  return False
87
 
88
  def use_local_clone(fingerprint: str, ip: str):
89
- """ثبت مصرف سهمیه کلون صدا روی هارد دیسک رانفلر"""
90
  for key in [fingerprint, ip]:
91
  if not key: continue
92
  data = get_local_clone_usage(key)
93
  data["count"] += 1
94
  save_local_clone_usage(key, data)
95
 
96
- # --- بخش مدیریت دائمی اعتبار ویرایش تصاویر (ذخیره روی دیسک رانفلر) ---
97
  def get_local_edit_usage(key: str) -> dict:
98
  current_week = date.today().isocalendar()[1]
99
  safe_key = "".join([c for c in key if c.isalnum() or c in ["-", "_", "."]])
@@ -116,7 +108,6 @@ def save_local_edit_usage(key: str, data: dict):
116
  except: pass
117
 
118
  def check_local_edit_limit(fingerprint: str, ip: str) -> bool:
119
- """بررسی محدودیت ادیت عکس: اگر اثر انگشت یا آی‌پی سهمیه هفتگی‌اش پر باشد، بلاک می‌کند"""
120
  for key in [fingerprint, ip]:
121
  if not key: continue
122
  data = get_local_edit_usage(key)
@@ -125,7 +116,6 @@ def check_local_edit_limit(fingerprint: str, ip: str) -> bool:
125
  return False
126
 
127
  def use_local_edit(fingerprint: str, ip: str):
128
- """ثبت مصرف سهمیه ویرایش عکس روی هارد دیسک رانفلر"""
129
  for key in [fingerprint, ip]:
130
  if not key: continue
131
  data = get_local_edit_usage(key)
@@ -134,18 +124,13 @@ def use_local_edit(fingerprint: str, ip: str):
134
 
135
 
136
  def clean_old_files():
137
- """پاکسازی خودکار فایل‌های قدیمی برای جلوگیری از پر شدن حافظه سرور"""
138
  now = time.time()
139
-
140
- # فایل‌های صوتی و جاب‌ها بعد از ۳۰ دقیقه (۱۸۰۰ ثانیه) حذف می‌شوند
141
  try:
142
  for f in os.listdir(JOBS_DIR):
143
  fpath = os.path.join(JOBS_DIR, f)
144
  if os.path.isfile(fpath) and os.stat(fpath).st_mtime < now - 1800:
145
  os.remove(fpath)
146
  except: pass
147
-
148
- # لاگ‌های اعتبار روزانه کاربران بعد از ۴۸ ساعت (۱۷۲۸۰۰ ثانیه) حذف می‌شوند
149
  try:
150
  for f in os.listdir(USAGE_DIR):
151
  fpath = os.path.join(USAGE_DIR, f)
@@ -154,9 +139,7 @@ def clean_old_files():
154
  except: pass
155
 
156
  def save_job_state(job_id: str, status: str, audio_data: bytes = None, error_message: str = None):
157
- """ذخیره وضعیت کار در فایل متنی مشترک دیسک"""
158
  clean_old_files()
159
-
160
  state = {
161
  "status": status,
162
  "error_message": error_message,
@@ -172,7 +155,6 @@ def save_job_state(job_id: str, status: str, audio_data: bytes = None, error_mes
172
  f.write(audio_data)
173
 
174
  def get_job_state(job_id: str):
175
- """خواندن وضعیت کار از فایل متنی مشترک دیسک"""
176
  state_file = os.path.join(JOBS_DIR, f"{job_id}.json")
177
  if not os.path.exists(state_file):
178
  return None
@@ -183,7 +165,6 @@ def get_job_state(job_id: str):
183
  return None
184
 
185
  def get_job_audio(job_id: str):
186
- """خواندن دیتای باینری صوتی ذخیره شده روی دیسک"""
187
  audio_file = os.path.join(JOBS_DIR, f"{job_id}.mp3")
188
  if os.path.exists(audio_file):
189
  try:
@@ -419,20 +400,19 @@ def get_hf_headers(request: Request):
419
  headers["X-Forwarded-For"] = request.client.host
420
  return headers
421
 
422
-
423
- # =================================================================
424
- # 4. بازنشانی آدرس‌ها و وب‌هوک‌های محلی اکشنز (جایگزین sada8888-tts3)
425
- # =================================================================
426
 
427
  @app.post("/api/generate")
428
  async def submit_job(request: Request, background_tasks: BackgroundTasks):
429
  payload = await request.json()
430
  headers = get_hf_headers(request)
431
 
432
- # 🟢 تشخیص هوشمند درخواست تولید عکس (ارسال مستقیم و محلی به فلاسکِ اکشن)
433
  if "action_name" in payload and "prompt" in payload:
434
  try:
435
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=120.0) as client:
 
 
436
  resp = await client.post("/api/generate", json=payload, headers=headers)
437
  return JSONResponse(resp.json(), status_code=resp.status_code)
438
  except Exception as e:
@@ -491,8 +471,9 @@ async def check_status(request: Request):
491
  else:
492
  return JSONResponse({"status": "processing"})
493
 
494
- # در غیر این صورت، هدایت درخواست بررسی وضعیت به فلاسک داخلی (کلون صدا یا تصویر)
495
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=30.0) as client:
 
496
  resp = await client.post("/api/check_status", json=payload, headers=get_hf_headers(request))
497
  return JSONResponse(resp.json(), status_code=resp.status_code)
498
  except Exception as e:
@@ -519,7 +500,6 @@ async def podcast_status_proxy(request: Request):
519
  # =================================================================
520
  # 5. سرویس استودیوی پادکست و مسیریابی هوشمند دیتابیس‌ها
521
  # =================================================================
522
- HF_PODCAST_SPACE_URL = "https://sada8888-tts2.hf.space"
523
 
524
  @app.get("/podcast", response_class=HTMLResponse)
525
  @app.get("/podcast/", response_class=HTMLResponse)
@@ -541,8 +521,9 @@ async def smart_check_credit(request: Request):
541
  resp = await client.post(url, json=payload, headers=headers)
542
  return JSONResponse(resp.json(), status_code=resp.status_code)
543
  else:
544
- # 🟢 فراخوانی مستقیم و داخلی فلاسک رانفلر
545
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=30.0) as client:
 
546
  resp = await client.post("/api/check-credit", json=payload, headers=headers)
547
  return JSONResponse(resp.json(), status_code=resp.status_code)
548
  except Exception as e:
@@ -561,8 +542,9 @@ async def smart_use_credit(request: Request):
561
  resp = await client.post(url, json=payload, headers=headers)
562
  return JSONResponse(resp.json(), status_code=resp.status_code)
563
  else:
564
- # 🟢 فراخوانی مستقیم و داخلی فلاسک رانفلر
565
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=30.0) as client:
 
566
  resp = await client.post("/api/use-credit", json=payload, headers=headers)
567
  return JSONResponse(resp.json(), status_code=resp.status_code)
568
  except Exception as e:
@@ -656,7 +638,8 @@ async def proxy_check_image_credit(request: Request):
656
  try:
657
  body = await request.body()
658
  headers = get_hf_headers(request)
659
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=30.0) as client:
 
660
  resp = await client.post("/api/check-image-credit", content=body, headers=headers)
661
  return JSONResponse(resp.json(), status_code=resp.status_code)
662
  except Exception as e:
@@ -667,7 +650,8 @@ async def proxy_use_image_credit(request: Request):
667
  try:
668
  body = await request.body()
669
  headers = get_hf_headers(request)
670
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=30.0) as client:
 
671
  resp = await client.post("/api/use-image-credit", content=body, headers=headers)
672
  return JSONResponse(resp.json(), status_code=resp.status_code)
673
  except Exception as e:
@@ -685,12 +669,9 @@ async def proxy_check_edit_credit(request: Request):
685
  if subscription_status == 'paid':
686
  return JSONResponse({"credits_remaining": "unlimited", "limit_reached": False})
687
 
688
- # بررسی دائمی قفل دوگانه (آی‌پی + اثر انگشت) از دیسک رانفلر
689
  limit_reached = check_local_edit_limit(fingerprint, client_ip)
690
-
691
  current_week = date.today().isocalendar()[1]
692
 
693
- # بررسی بدترین سناریوی سهمیه هفتگی دیسکی
694
  rem_fp = 0
695
  if fingerprint:
696
  rec = get_local_edit_usage(fingerprint)
@@ -730,14 +711,15 @@ async def proxy_use_edit_credit(request: Request):
730
  except Exception as e:
731
  return JSONResponse({"status": "error", "message": f"error: {str(e)}"}, status_code=500)
732
 
733
- # --- پروکسی درخواست‌های تولید و ویرایش به فلاسک داخلی رانفلر ---
734
  @app.post("/api/generate-video")
735
  async def proxy_generate_video(request: Request):
736
  try:
737
  body = await request.body()
738
  headers = get_hf_headers(request)
739
 
740
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=300.0) as client:
 
741
  resp = await client.post("/api/generate-video", content=body, headers=headers)
742
  try:
743
  return JSONResponse(resp.json(), status_code=resp.status_code)
@@ -752,7 +734,8 @@ async def proxy_merge_videos(request: Request):
752
  body = await request.body()
753
  headers = get_hf_headers(request)
754
 
755
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=400.0) as client:
 
756
  resp = await client.post("/api/merge-videos", content=body, headers=headers)
757
 
758
  if resp.status_code == 200:
@@ -774,7 +757,8 @@ async def proxy_merge_videos(request: Request):
774
  async def proxy_video_status(request: Request, run_id: str):
775
  try:
776
  headers = get_hf_headers(request)
777
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=30.0) as client:
 
778
  resp = await client.get(f"/api/status/{run_id}", headers=headers)
779
  return JSONResponse(resp.json(), status_code=resp.status_code)
780
  except Exception as e:
@@ -782,7 +766,6 @@ async def proxy_video_status(request: Request, run_id: str):
782
 
783
  @app.get("/static/images/{filename}")
784
  async def proxy_static_images(request: Request, filename: str):
785
- """خوانش مستقیم فایل‌های ساخته شده گیت‌هاب اکشنز از روی دیسک محلی رانفلر بدون مصرف ترافیک شبکه"""
786
  local_path = os.path.join("static/images", filename)
787
  if os.path.exists(local_path):
788
  media_type = "application/octet-stream"
@@ -804,7 +787,8 @@ async def proxy_edit_image(request: Request):
804
  body = await request.body()
805
  headers = get_hf_headers(request)
806
 
807
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=120.0) as client:
 
808
  resp = await client.post("/api/edit", content=body, headers=headers)
809
  try:
810
  return JSONResponse(resp.json(), status_code=resp.status_code)
@@ -819,7 +803,8 @@ async def proxy_gemma_chat(request: Request):
819
  body = await request.body()
820
  headers = get_hf_headers(request)
821
 
822
- async with httpx.AsyncClient(app=action.app, base_url="http://local", timeout=120.0) as client:
 
823
  resp = await client.post("/api/chat", content=body, headers=headers)
824
  try:
825
  return JSONResponse(resp.json(), status_code=resp.status_code)
@@ -833,5 +818,4 @@ async def proxy_gemma_chat(request: Request):
833
  # 7. یکپارچه‌سازی وب‌سرور داخلی فلاسک رانفلر و اجرای همزمان (WSGI)
834
  # =================================================================
835
 
836
- # 🟢 اتصال مستقیم هسته وب‌سرور فلاسک به یوویکورن رانفلر به عنوان نرم‌افزار مکمل اصلی
837
  app.mount("/", WSGIMiddleware(action.app))
 
8
  from datetime import date
9
  from fastapi import FastAPI, Request, BackgroundTasks
10
  from fastapi.responses import HTMLResponse, FileResponse, JSONResponse, RedirectResponse, StreamingResponse
11
+
12
+ # 🟢 اضافه کردن این خط به هدر فایل جهت لود شدن درست وب‌سرور فلاسک
13
  from fastapi.middleware.wsgi import WSGIMiddleware
14
 
15
+ # ایمپورت و فراخوانی ماژول مستقل روبیکا بات و صوتی
16
+ from rubikabot import router as rubikabot_router
17
+ from soti import router as soti_router
18
+
19
+ # ایمپورت و فراخوانی ماژول مستقل روبیکا بات و صوتی
20
  from rubikabot import router as rubikabot_router
21
  from soti import router as soti_router
22
 
23
+ # ایمپورت فایل فلاسک که به اسم action.py ذخیره کرده‌اید
24
  import action
25
 
26
  app = FastAPI()
 
37
  CLONE_USAGE_LIMIT = 1
38
  EDIT_USAGE_LIMIT = 5
39
 
 
 
 
 
 
 
 
 
 
 
 
40
  def get_client_ip(request: Request) -> str:
 
41
  cf_ip = request.headers.get("CF-Connecting-IP")
42
  if cf_ip:
43
  return cf_ip.strip()
 
48
  return request.client.host
49
  return "0.0.0.0"
50
 
51
+ # --- بخش مدیریت دائمی اعتبار کلون صدا ---
52
  def get_local_clone_usage(key: str) -> dict:
53
  today_str = date.today().isoformat()
54
  safe_key = "".join([c for c in key if c.isalnum() or c in ["-", "_", "."]])
 
71
  except: pass
72
 
73
  def check_local_clone_limit(fingerprint: str, ip: str) -> bool:
 
74
  for key in [fingerprint, ip]:
75
  if not key: continue
76
  data = get_local_clone_usage(key)
 
79
  return False
80
 
81
  def use_local_clone(fingerprint: str, ip: str):
 
82
  for key in [fingerprint, ip]:
83
  if not key: continue
84
  data = get_local_clone_usage(key)
85
  data["count"] += 1
86
  save_local_clone_usage(key, data)
87
 
88
+ # --- بخش مدیریت دائمی اعتبار ویرایش تصاویر ---
89
  def get_local_edit_usage(key: str) -> dict:
90
  current_week = date.today().isocalendar()[1]
91
  safe_key = "".join([c for c in key if c.isalnum() or c in ["-", "_", "."]])
 
108
  except: pass
109
 
110
  def check_local_edit_limit(fingerprint: str, ip: str) -> bool:
 
111
  for key in [fingerprint, ip]:
112
  if not key: continue
113
  data = get_local_edit_usage(key)
 
116
  return False
117
 
118
  def use_local_edit(fingerprint: str, ip: str):
 
119
  for key in [fingerprint, ip]:
120
  if not key: continue
121
  data = get_local_edit_usage(key)
 
124
 
125
 
126
  def clean_old_files():
 
127
  now = time.time()
 
 
128
  try:
129
  for f in os.listdir(JOBS_DIR):
130
  fpath = os.path.join(JOBS_DIR, f)
131
  if os.path.isfile(fpath) and os.stat(fpath).st_mtime < now - 1800:
132
  os.remove(fpath)
133
  except: pass
 
 
134
  try:
135
  for f in os.listdir(USAGE_DIR):
136
  fpath = os.path.join(USAGE_DIR, f)
 
139
  except: pass
140
 
141
  def save_job_state(job_id: str, status: str, audio_data: bytes = None, error_message: str = None):
 
142
  clean_old_files()
 
143
  state = {
144
  "status": status,
145
  "error_message": error_message,
 
155
  f.write(audio_data)
156
 
157
  def get_job_state(job_id: str):
 
158
  state_file = os.path.join(JOBS_DIR, f"{job_id}.json")
159
  if not os.path.exists(state_file):
160
  return None
 
165
  return None
166
 
167
  def get_job_audio(job_id: str):
 
168
  audio_file = os.path.join(JOBS_DIR, f"{job_id}.mp3")
169
  if os.path.exists(audio_file):
170
  try:
 
400
  headers["X-Forwarded-For"] = request.client.host
401
  return headers
402
 
403
+ HF_PODCAST_SPACE_URL = "https://sada8888-tts2.hf.space"
 
 
 
404
 
405
  @app.post("/api/generate")
406
  async def submit_job(request: Request, background_tasks: BackgroundTasks):
407
  payload = await request.json()
408
  headers = get_hf_headers(request)
409
 
410
+ # 🟢 تشخیص هوشمند درخواست تولید عکس (ارسال به فلاسک اکشن به کمک WSGITransport)
411
  if "action_name" in payload and "prompt" in payload:
412
  try:
413
+ # 🟢 ساخت ترنسپورت رسمی سازگار با آخرین نسخه httpx
414
+ transport = httpx.WSGITransport(app=action.app)
415
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=120.0) as client:
416
  resp = await client.post("/api/generate", json=payload, headers=headers)
417
  return JSONResponse(resp.json(), status_code=resp.status_code)
418
  except Exception as e:
 
471
  else:
472
  return JSONResponse({"status": "processing"})
473
 
474
+ # هدایت درخواست بررسی وضعیت به فلاسک داخلی با WSGITransport
475
+ transport = httpx.WSGITransport(app=action.app)
476
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=30.0) as client:
477
  resp = await client.post("/api/check_status", json=payload, headers=get_hf_headers(request))
478
  return JSONResponse(resp.json(), status_code=resp.status_code)
479
  except Exception as e:
 
500
  # =================================================================
501
  # 5. سرویس استودیوی پادکست و مسیریابی هوشمند دیتابیس‌ها
502
  # =================================================================
 
503
 
504
  @app.get("/podcast", response_class=HTMLResponse)
505
  @app.get("/podcast/", response_class=HTMLResponse)
 
521
  resp = await client.post(url, json=payload, headers=headers)
522
  return JSONResponse(resp.json(), status_code=resp.status_code)
523
  else:
524
+ # 🟢 فراخوانی مستقیم و داخلی فلاسک رانفلر با WSGITransport
525
+ transport = httpx.WSGITransport(app=action.app)
526
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=30.0) as client:
527
  resp = await client.post("/api/check-credit", json=payload, headers=headers)
528
  return JSONResponse(resp.json(), status_code=resp.status_code)
529
  except Exception as e:
 
542
  resp = await client.post(url, json=payload, headers=headers)
543
  return JSONResponse(resp.json(), status_code=resp.status_code)
544
  else:
545
+ # 🟢 فراخوانی مستقیم و داخلی فلاسک رانفلر با WSGITransport
546
+ transport = httpx.WSGITransport(app=action.app)
547
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=30.0) as client:
548
  resp = await client.post("/api/use-credit", json=payload, headers=headers)
549
  return JSONResponse(resp.json(), status_code=resp.status_code)
550
  except Exception as e:
 
638
  try:
639
  body = await request.body()
640
  headers = get_hf_headers(request)
641
+ transport = httpx.WSGITransport(app=action.app)
642
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=30.0) as client:
643
  resp = await client.post("/api/check-image-credit", content=body, headers=headers)
644
  return JSONResponse(resp.json(), status_code=resp.status_code)
645
  except Exception as e:
 
650
  try:
651
  body = await request.body()
652
  headers = get_hf_headers(request)
653
+ transport = httpx.WSGITransport(app=action.app)
654
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=30.0) as client:
655
  resp = await client.post("/api/use-image-credit", content=body, headers=headers)
656
  return JSONResponse(resp.json(), status_code=resp.status_code)
657
  except Exception as e:
 
669
  if subscription_status == 'paid':
670
  return JSONResponse({"credits_remaining": "unlimited", "limit_reached": False})
671
 
 
672
  limit_reached = check_local_edit_limit(fingerprint, client_ip)
 
673
  current_week = date.today().isocalendar()[1]
674
 
 
675
  rem_fp = 0
676
  if fingerprint:
677
  rec = get_local_edit_usage(fingerprint)
 
711
  except Exception as e:
712
  return JSONResponse({"status": "error", "message": f"error: {str(e)}"}, status_code=500)
713
 
714
+ # --- پروکسی درخواست‌های تولید و ویرایش به فلاسک داخلی با WSGITransport ---
715
  @app.post("/api/generate-video")
716
  async def proxy_generate_video(request: Request):
717
  try:
718
  body = await request.body()
719
  headers = get_hf_headers(request)
720
 
721
+ transport = httpx.WSGITransport(app=action.app)
722
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=300.0) as client:
723
  resp = await client.post("/api/generate-video", content=body, headers=headers)
724
  try:
725
  return JSONResponse(resp.json(), status_code=resp.status_code)
 
734
  body = await request.body()
735
  headers = get_hf_headers(request)
736
 
737
+ transport = httpx.WSGITransport(app=action.app)
738
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=400.0) as client:
739
  resp = await client.post("/api/merge-videos", content=body, headers=headers)
740
 
741
  if resp.status_code == 200:
 
757
  async def proxy_video_status(request: Request, run_id: str):
758
  try:
759
  headers = get_hf_headers(request)
760
+ transport = httpx.WSGITransport(app=action.app)
761
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=30.0) as client:
762
  resp = await client.get(f"/api/status/{run_id}", headers=headers)
763
  return JSONResponse(resp.json(), status_code=resp.status_code)
764
  except Exception as e:
 
766
 
767
  @app.get("/static/images/{filename}")
768
  async def proxy_static_images(request: Request, filename: str):
 
769
  local_path = os.path.join("static/images", filename)
770
  if os.path.exists(local_path):
771
  media_type = "application/octet-stream"
 
787
  body = await request.body()
788
  headers = get_hf_headers(request)
789
 
790
+ transport = httpx.WSGITransport(app=action.app)
791
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=120.0) as client:
792
  resp = await client.post("/api/edit", content=body, headers=headers)
793
  try:
794
  return JSONResponse(resp.json(), status_code=resp.status_code)
 
803
  body = await request.body()
804
  headers = get_hf_headers(request)
805
 
806
+ transport = httpx.WSGITransport(app=action.app)
807
+ async with httpx.AsyncClient(transport=transport, base_url="http://local", timeout=120.0) as client:
808
  resp = await client.post("/api/chat", content=body, headers=headers)
809
  try:
810
  return JSONResponse(resp.json(), status_code=resp.status_code)
 
818
  # 7. یکپارچه‌سازی وب‌سرور داخلی فلاسک رانفلر و اجرای همزمان (WSGI)
819
  # =================================================================
820
 
 
821
  app.mount("/", WSGIMiddleware(action.app))