waveshaker commited on
Commit
2d39fe7
·
verified ·
1 Parent(s): c8106d6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -51
app.py CHANGED
@@ -648,16 +648,27 @@ class GenerateRequest(BaseModel):
648
  char_strength: float = 1.0
649
  base_lora_states: list = []
650
 
 
 
 
651
  _model_switch_lock = threading.Lock()
652
 
653
  def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str = None, request: Request = None):
654
  global _last_used_architecture, _last_used_unet
655
 
656
  _current_generation_task_id.set(task_id)
657
- tasks_status[task_id] = {"status": "processing", "message": "⏳ Queue for GPU..."}
 
 
 
 
658
  print(f"[Token探针] task={task_id[:8]} | route_token_present={bool(ip_token)}", flush=True)
659
 
660
  try:
 
 
 
 
661
  download_start = time.time()
662
  prepare_env(req.char_enable, req.char_lora, req.unet_choice, task_id=task_id)
663
  real_download_time = round(time.time() - download_start, 2)
@@ -668,20 +679,24 @@ def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str =
668
  if need_heavy_load:
669
  with _model_switch_lock:
670
  if _last_used_architecture != current_arch:
671
- tasks_status[task_id]["message"] = f"📦 Queue for GPU... (Loading Base Model: {current_arch.upper()})"
 
672
  _last_used_architecture = current_arch
673
  _last_used_unet = req.unet_choice
674
  elif _last_used_unet != req.unet_choice:
675
- tasks_status[task_id]["message"] = "🔄 Queue for GPU... (Swapping Model Checkpoint)"
 
676
  _last_used_unet = req.unet_choice
677
  else:
678
- tasks_status[task_id]["message"] = "🎨 Rendering image (GPU processing)..."
 
679
 
680
  final_seed = req.seed if req.seed >= 0 else random.randint(0, 2**32 - 1)
681
- tasks_status[task_id]["seed"] = final_seed
 
 
 
682
 
683
- tasks_status[task_id]["queue_start_time"] = time.time()
684
- tasks_status[task_id]["message"] = "⏳ Requesting GPU resources..."
685
  print(f"[GPU 探针] 🔴 发起 Request,申请 GPU 资源...", flush=True)
686
 
687
  ctx = contextvars.copy_context()
@@ -689,15 +704,6 @@ def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str =
689
  def _run_generate():
690
  if request is not None:
691
  LocalContext.request.set(request)
692
-
693
- _req_in_ctx = LocalContext.request.get(None)
694
- _token_in_ctx = _req_in_ctx.headers.get("x-ip-token") if _req_in_ctx is not None else None
695
- print(
696
- f"[Token探针] task={task_id[:8]} | ctx_request_present={_req_in_ctx is not None}"
697
- f" | ctx_token_present={bool(_token_in_ctx)}",
698
- flush=True,
699
- )
700
-
701
  return generate(
702
  req.prompt, req.unet_choice, req.custom_w, req.custom_h,
703
  req.steps, req.cfg, final_seed, req.sampler, req.scheduler,
@@ -706,27 +712,18 @@ def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str =
706
  task_id=task_id,
707
  )
708
 
 
709
  image_path, real_workflow = ctx.run(_run_generate)
710
 
711
- # 🌟 重点:把真正的 workflow 转成字符串
712
- real_workflow_str = json.dumps(real_workflow, ensure_ascii=False)
713
-
714
- tasks_status[task_id]["message"] = "✨ Processing output..."
715
-
716
  from PIL import Image
717
 
718
- # 提取文件名,并确保存成 webp
719
  original_filename = os.path.basename(image_path)
720
  webp_filename = original_filename.replace(".png", ".webp")
721
-
722
- # 🌟 核心修改 1:定义物理保存路径
723
  output_webp_path = os.path.join(OUTPUT, webp_filename)
724
 
725
  with Image.open(image_path) as img:
726
- # 1. 获取原始元数据(ComfyUI 存的 PNG 里本身就带完整的 JSON 数据)
727
  metadata = img.info
728
-
729
- # 2. 构建标准的 EXIF 标签(���全照抄 GitHub 完美方案)
730
  PROMPT_TAG = 0x0110
731
  EXTRA_METADATA_TAG = 0x010f
732
  output_metadata = img.getexif()
@@ -738,11 +735,10 @@ def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str =
738
  output_metadata[EXTRA_METADATA_TAG] = "Workflow:" + value
739
  EXTRA_METADATA_TAG -= 1
740
 
741
- # 3. 转换 RGB(防止 WebP 保存报错)
742
  if img.mode in ("RGBA", "P"):
743
  img = img.convert("RGB")
744
 
745
- # 4. 🌟 核心修改 2:直接保存到磁盘,不再写入内存
746
  img.save(
747
  output_webp_path,
748
  "WEBP",
@@ -752,16 +748,14 @@ def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str =
752
  exif=output_metadata
753
  )
754
 
755
- # 删除原来的 PNG,节省空间
756
  try:
757
  os.remove(image_path)
758
  except Exception:
759
  pass
760
 
761
- # 🌟 核心修改 3:构建前端可以直接访问的 URL
762
- # 注意:前端/后端如果在同一个根目录,用 /output/ 即可。如果跨域,请换成你的 API_BASE_URL
763
  image_url = f"/output/{webp_filename}"
764
 
 
765
  final_queue = 0
766
  final_workflow = 0
767
  final_load_time = 0
@@ -775,26 +769,30 @@ def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str =
775
  final_workflow = saved_metrics.get("workflow", 0)
776
  final_load_time = saved_metrics.get("load_time", 0)
777
  os.remove(metric_file)
778
- except Exception as e:
779
- print(f"读取指标文件失败: {e}")
780
-
781
- tasks_status[task_id] = {
782
- "status": "success",
783
- "image": image_url, # 👈 核心修改 4:直接把 URL 传回去
784
- "filename": webp_filename,
785
- "seed": final_seed,
786
- "metrics": {
787
- "download": real_download_time,
788
- "queue": final_queue,
789
- "workflow": final_workflow,
790
- "load_time": final_load_time,
791
- "steps": req.steps,
792
- "resolved_seed": final_seed
793
- },
794
- "anonymous": ip_token is None,
795
- }
 
 
 
796
  except Exception as e:
797
- tasks_status[task_id] = {"status": "error", "message": str(e)}
 
798
  finally:
799
  _current_generation_task_id.set(None)
800
 
 
648
  char_strength: float = 1.0
649
  base_lora_states: list = []
650
 
651
+ import threading
652
+ # 专门用于保护 tasks_status 字典的状态锁
653
+ _status_lock = threading.RLock()
654
  _model_switch_lock = threading.Lock()
655
 
656
  def background_generate_task(task_id: str, req: GenerateRequest, ip_token: str = None, request: Request = None):
657
  global _last_used_architecture, _last_used_unet
658
 
659
  _current_generation_task_id.set(task_id)
660
+
661
+ # 初始状态
662
+ with _status_lock:
663
+ tasks_status[task_id] = {"status": "processing", "message": "⏳ Queue for GPU..."}
664
+
665
  print(f"[Token探针] task={task_id[:8]} | route_token_present={bool(ip_token)}", flush=True)
666
 
667
  try:
668
+ # --- 阶段 1:环境准备与模型下载 ---
669
+ with _status_lock:
670
+ tasks_status[task_id]["message"] = "📥 Downloading LoRA / Preparing environment..."
671
+
672
  download_start = time.time()
673
  prepare_env(req.char_enable, req.char_lora, req.unet_choice, task_id=task_id)
674
  real_download_time = round(time.time() - download_start, 2)
 
679
  if need_heavy_load:
680
  with _model_switch_lock:
681
  if _last_used_architecture != current_arch:
682
+ with _status_lock:
683
+ tasks_status[task_id]["message"] = f"📦 Loading Base Model: {current_arch.upper()}..."
684
  _last_used_architecture = current_arch
685
  _last_used_unet = req.unet_choice
686
  elif _last_used_unet != req.unet_choice:
687
+ with _status_lock:
688
+ tasks_status[task_id]["message"] = "🔄 Swapping Model Checkpoint..."
689
  _last_used_unet = req.unet_choice
690
  else:
691
+ with _status_lock:
692
+ tasks_status[task_id]["message"] = "🎨 GPU processing..."
693
 
694
  final_seed = req.seed if req.seed >= 0 else random.randint(0, 2**32 - 1)
695
+ with _status_lock:
696
+ tasks_status[task_id]["seed"] = final_seed
697
+ tasks_status[task_id]["queue_start_time"] = time.time()
698
+ tasks_status[task_id]["message"] = "⏳ Requesting GPU resources..."
699
 
 
 
700
  print(f"[GPU 探针] 🔴 发起 Request,申请 GPU 资源...", flush=True)
701
 
702
  ctx = contextvars.copy_context()
 
704
  def _run_generate():
705
  if request is not None:
706
  LocalContext.request.set(request)
 
 
 
 
 
 
 
 
 
707
  return generate(
708
  req.prompt, req.unet_choice, req.custom_w, req.custom_h,
709
  req.steps, req.cfg, final_seed, req.sampler, req.scheduler,
 
712
  task_id=task_id,
713
  )
714
 
715
+ # --- 阶段 2:核心执行(阻塞式,前端此时只看到进度条走动) ---
716
  image_path, real_workflow = ctx.run(_run_generate)
717
 
718
+ # --- 阶段 3:死磕后处理(前端此时处于静默等待,避免出现“快好了”的错觉) ---
 
 
 
 
719
  from PIL import Image
720
 
 
721
  original_filename = os.path.basename(image_path)
722
  webp_filename = original_filename.replace(".png", ".webp")
 
 
723
  output_webp_path = os.path.join(OUTPUT, webp_filename)
724
 
725
  with Image.open(image_path) as img:
 
726
  metadata = img.info
 
 
727
  PROMPT_TAG = 0x0110
728
  EXTRA_METADATA_TAG = 0x010f
729
  output_metadata = img.getexif()
 
735
  output_metadata[EXTRA_METADATA_TAG] = "Workflow:" + value
736
  EXTRA_METADATA_TAG -= 1
737
 
 
738
  if img.mode in ("RGBA", "P"):
739
  img = img.convert("RGB")
740
 
741
+ # 🌟 性能妥协:method=4, quality=90,速度极快,肉眼无感
742
  img.save(
743
  output_webp_path,
744
  "WEBP",
 
748
  exif=output_metadata
749
  )
750
 
 
751
  try:
752
  os.remove(image_path)
753
  except Exception:
754
  pass
755
 
 
 
756
  image_url = f"/output/{webp_filename}"
757
 
758
+ # --- 阶段 4:提取指标 ---
759
  final_queue = 0
760
  final_workflow = 0
761
  final_load_time = 0
 
769
  final_workflow = saved_metrics.get("workflow", 0)
770
  final_load_time = saved_metrics.get("load_time", 0)
771
  os.remove(metric_file)
772
+ except Exception:
773
+ pass
774
+
775
+ # --- 阶段 5:高光时刻!直接抛出最终结果,抛弃一切中间态日志 ---
776
+ with _status_lock:
777
+ tasks_status[task_id] = {
778
+ "status": "success",
779
+ "image": image_url,
780
+ "filename": webp_filename,
781
+ "seed": final_seed,
782
+ "metrics": {
783
+ "download": real_download_time,
784
+ "queue": final_queue,
785
+ "workflow": final_workflow,
786
+ "load_time": final_load_time,
787
+ "steps": req.steps,
788
+ "resolved_seed": final_seed
789
+ },
790
+ "anonymous": ip_token is None,
791
+ }
792
+
793
  except Exception as e:
794
+ with _status_lock:
795
+ tasks_status[task_id] = {"status": "error", "message": str(e)}
796
  finally:
797
  _current_generation_task_id.set(None)
798