Dmitry1313 commited on
Commit
388bdd0
·
verified ·
1 Parent(s): 18ad1ba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -20
app.py CHANGED
@@ -1,12 +1,13 @@
1
  #!/usr/bin/env python3
2
  """
3
- 🎨 FaceFusion API для Hugging Face Spaces — FIXED VERSION
4
- Skip NSFW filter (avoid open_nsfw hash error)
5
- ✅ Read UploadFile once and reuse bytes (fix 0b on retry)
 
6
  ✅ ghost_3_256 maximum quality
7
  """
8
 
9
- import os, sys, tempfile, subprocess, logging, shutil, time, io
10
  from pathlib import Path
11
  from contextlib import asynccontextmanager
12
  from fastapi import FastAPI, File, UploadFile, HTTPException, Query
@@ -20,13 +21,14 @@ async def lifespan(app: FastAPI):
20
  logger.info("🚀 FaceFusion CPU API (ghost_3_256) starting...")
21
  logger.info("📁 Cache: /tmp/facefusion_cache")
22
  logger.info("⚙️ Default: ghost_3_256 + gfpgan_1.4")
23
- logger.info("🔕 NSFW filter: disabled (avoid hash errors)")
 
24
  logger.info("⏱️ Timeout: 900s")
25
  logger.info("✅ API ready!")
26
  yield
27
  logger.info("👋 API shutting down...")
28
 
29
- app = FastAPI(title="FaceFusion CPU API — High Quality", version="2.1", lifespan=lifespan)
30
 
31
  FACEFUSION_DIR = Path("/facefusion")
32
  FACEFUSION_PY = FACEFUSION_DIR / "facefusion.py"
@@ -48,19 +50,22 @@ CONFIG = {
48
  "output_image_quality": "90",
49
  "timeout_high_quality": 900,
50
  "timeout_standard": 600,
51
- "skip_download": False, # 🔥 Разрешить докачку если модель повреждена
52
  "log_level": "error",
53
  }
54
 
 
 
 
55
  AVAILABLE_SWAPPERS = ["ghost_3_256", "ghost_2_256", "ghost_1_256", "inswapper_128", "simswap_256"]
56
- AVAILABLE_ENHANCERS = ["gfpgan_1.4", "gfpgan_1.3", "codeformer", None]
57
 
58
  @app.get("/")
59
  async def root():
60
  return {
61
  "service": "FaceFusion CPU API — High Quality",
62
- "version": "2.1",
63
  "default_swapper": CONFIG["face_swapper"],
 
64
  "status": "running"
65
  }
66
 
@@ -89,7 +94,6 @@ async def swap_face(
89
 
90
  logger.info(f"📥 Request: source={len(source_bytes)}b, target={len(target_bytes)}b")
91
 
92
- # Нормализуем enhancer_model
93
  if enhancer_model and enhancer_model.lower() == "none":
94
  enhancer_model = None
95
 
@@ -103,12 +107,11 @@ async def swap_face(
103
  logger.info(f"🔄 Attempt {attempt}/{len(models_to_try)}: {model}")
104
 
105
  try:
106
- # 🔥 ПЕРЕДАЁМ bytes, а не UploadFile — можно читать много раз!
107
  result = await _process_face_swap(
108
  source_bytes=source_bytes,
109
  target_bytes=target_bytes,
110
  swapper_model=model,
111
- enhancer_model=enhancer_model if attempt == 1 else None, # Без enhancer для fallback
112
  enhance_blend=enhance_blend,
113
  timeout=CONFIG["timeout_high_quality"] if model.startswith("ghost") else CONFIG["timeout_standard"]
114
  )
@@ -141,15 +144,14 @@ async def _process_face_swap(
141
 
142
  logger.info(f"🔧 Processing: swapper={swapper_model}, enhancer={enhancer_model}")
143
 
144
- # 🔥 ЗАПИСЫВАЕМ bytes в файлы (можно вызывать много раз)
145
  source_path.write_bytes(source_bytes)
146
  target_path.write_bytes(target_bytes)
147
 
148
- # Формируем CLI команду
149
  processors = ["face_swapper"]
150
  if enhancer_model:
151
  processors.append("face_enhancer")
152
 
 
153
  cmd = [
154
  "python", str(FACEFUSION_PY),
155
  "headless-run",
@@ -163,11 +165,11 @@ async def _process_face_swap(
163
  "--face-mask-padding", *map(str, CONFIG["face_mask_padding"]),
164
  "--output-image-resolution", CONFIG["output_image_resolution"],
165
  "--output-image-quality", CONFIG["output_image_quality"],
166
- "--skip-nsfw-filter", # 🔥 ОТКЛЮЧАЕМ NSFW ФИЛЬТР (избегаем open_nsfw hash error)
167
  "--log-level", CONFIG["log_level"],
168
  ]
169
 
170
- # 🔥 Не используем --skip-download если модель может быть повреждена
171
  if CONFIG["skip_download"]:
172
  cmd.append("--skip-download")
173
 
@@ -182,10 +184,12 @@ async def _process_face_swap(
182
  logger.info(f"🚀 Running: {' '.join(cmd)}")
183
  process_start = time.time()
184
 
 
 
 
185
  process = subprocess.Popen(
186
  cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
187
- text=True, cwd=str(FACEFUSION_DIR),
188
- env={**os.environ, "OMP_NUM_THREADS": "4"}
189
  )
190
 
191
  try:
@@ -199,8 +203,8 @@ async def _process_face_swap(
199
  logger.info(f"⏱️ Done in {elapsed:.1f}s, code={process.returncode}")
200
 
201
  if stderr:
202
- # Фильтруем harmless libpng warnings
203
- stderr_clean = '\n'.join(l for l in stderr.split('\n') if 'iCCP' not in l)
204
  if stderr_clean.strip():
205
  logger.info(f"📋 STDERR: {stderr_clean[-400:]}")
206
 
 
1
  #!/usr/bin/env python3
2
  """
3
+ 🎨 FaceFusion API для Hugging Face Spaces — FINAL FIXED VERSION
4
+ Disable NSFW via ENV variable (not CLI arg)
5
+ ✅ Read UploadFile once and reuse bytes
6
+ ✅ Allow model re-download if corrupted
7
  ✅ ghost_3_256 maximum quality
8
  """
9
 
10
+ import os, sys, tempfile, subprocess, logging, shutil, time
11
  from pathlib import Path
12
  from contextlib import asynccontextmanager
13
  from fastapi import FastAPI, File, UploadFile, HTTPException, Query
 
21
  logger.info("🚀 FaceFusion CPU API (ghost_3_256) starting...")
22
  logger.info("📁 Cache: /tmp/facefusion_cache")
23
  logger.info("⚙️ Default: ghost_3_256 + gfpgan_1.4")
24
+ logger.info("🔕 NSFW filter: disabled via ENV")
25
+ logger.info("🔄 Model re-download: enabled")
26
  logger.info("⏱️ Timeout: 900s")
27
  logger.info("✅ API ready!")
28
  yield
29
  logger.info("👋 API shutting down...")
30
 
31
+ app = FastAPI(title="FaceFusion CPU API — High Quality", version="2.2", lifespan=lifespan)
32
 
33
  FACEFUSION_DIR = Path("/facefusion")
34
  FACEFUSION_PY = FACEFUSION_DIR / "facefusion.py"
 
50
  "output_image_quality": "90",
51
  "timeout_high_quality": 900,
52
  "timeout_standard": 600,
53
+ "skip_download": False, # 🔥 Разрешить перескачку если модель повреждена
54
  "log_level": "error",
55
  }
56
 
57
+ # 🔥 Отключаем NSFW фильтр через ENV переменную
58
+ os.environ["FACEFUSION_CONTENT_ANALYSER"] = "none"
59
+
60
  AVAILABLE_SWAPPERS = ["ghost_3_256", "ghost_2_256", "ghost_1_256", "inswapper_128", "simswap_256"]
 
61
 
62
  @app.get("/")
63
  async def root():
64
  return {
65
  "service": "FaceFusion CPU API — High Quality",
66
+ "version": "2.2",
67
  "default_swapper": CONFIG["face_swapper"],
68
+ "nsfw_disabled": os.environ.get("FACEFUSION_CONTENT_ANALYSER") == "none",
69
  "status": "running"
70
  }
71
 
 
94
 
95
  logger.info(f"📥 Request: source={len(source_bytes)}b, target={len(target_bytes)}b")
96
 
 
97
  if enhancer_model and enhancer_model.lower() == "none":
98
  enhancer_model = None
99
 
 
107
  logger.info(f"🔄 Attempt {attempt}/{len(models_to_try)}: {model}")
108
 
109
  try:
 
110
  result = await _process_face_swap(
111
  source_bytes=source_bytes,
112
  target_bytes=target_bytes,
113
  swapper_model=model,
114
+ enhancer_model=enhancer_model if attempt == 1 else None,
115
  enhance_blend=enhance_blend,
116
  timeout=CONFIG["timeout_high_quality"] if model.startswith("ghost") else CONFIG["timeout_standard"]
117
  )
 
144
 
145
  logger.info(f"🔧 Processing: swapper={swapper_model}, enhancer={enhancer_model}")
146
 
 
147
  source_path.write_bytes(source_bytes)
148
  target_path.write_bytes(target_bytes)
149
 
 
150
  processors = ["face_swapper"]
151
  if enhancer_model:
152
  processors.append("face_enhancer")
153
 
154
+ # 🔥 CLI команда БЕЗ --skip-nsfw-filter (не поддерживается)
155
  cmd = [
156
  "python", str(FACEFUSION_PY),
157
  "headless-run",
 
165
  "--face-mask-padding", *map(str, CONFIG["face_mask_padding"]),
166
  "--output-image-resolution", CONFIG["output_image_resolution"],
167
  "--output-image-quality", CONFIG["output_image_quality"],
168
+ # ❌ УБРАЛ: --skip-nsfw-filter (не поддерживается в этой версии)
169
  "--log-level", CONFIG["log_level"],
170
  ]
171
 
172
+ # ��� skip-download=False по умолчанию — разрешаем перескачку моделей
173
  if CONFIG["skip_download"]:
174
  cmd.append("--skip-download")
175
 
 
184
  logger.info(f"🚀 Running: {' '.join(cmd)}")
185
  process_start = time.time()
186
 
187
+ # 🔥 Передаём ENV с отключённым NSFW
188
+ env = {**os.environ, "OMP_NUM_THREADS": "4", "FACEFUSION_CONTENT_ANALYSER": "none"}
189
+
190
  process = subprocess.Popen(
191
  cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
192
+ text=True, cwd=str(FACEFUSION_DIR), env=env
 
193
  )
194
 
195
  try:
 
203
  logger.info(f"⏱️ Done in {elapsed:.1f}s, code={process.returncode}")
204
 
205
  if stderr:
206
+ # Фильтруем harmless warnings
207
+ stderr_clean = '\n'.join(l for l in stderr.split('\n') if 'iCCP' not in l and 'libpng' not in l)
208
  if stderr_clean.strip():
209
  logger.info(f"📋 STDERR: {stderr_clean[-400:]}")
210