Slicelayers commited on
Commit
544f302
·
verified ·
1 Parent(s): aba93f6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -16
app.py CHANGED
@@ -139,19 +139,22 @@ async def segment_and_inpaint(original_image_np: np.ndarray, sketchpad_image_np:
139
  """
140
  アップロードされた一枚絵とブラシで描かれたマスクを受け取り、
141
  マスクされた領域を分割し、欠損部分をAI補完する関数。
 
142
  """
143
- # 失敗時の統一リターン(6つの出力に対応)
144
  def fail(message):
145
  # 画像出力は全てNone, JSONとZIPは空文字列/None, ステータスにエラーメッセージ
146
- return None, None, None, "{}", None, f"❌ 処理失敗: {message}"
147
 
148
  if original_image_np is None:
149
- return fail("元の画像がアップロードされていません。")
150
-
 
 
151
  # 元画像の形状を取得(SketchpadがNoneだった場合の代替用)
152
  h, w, _ = original_image_np.shape
153
 
154
- # ★★★ 修正: Sketchpad入力の型チェックとデータ形式の強制 ★★★
155
 
156
  if not isinstance(sketchpad_image_np, np.ndarray) or sketchpad_image_np is None:
157
  # Sketchpadの入力がNumPy配列ではないか、Noneであった場合、
@@ -169,8 +172,9 @@ async def segment_and_inpaint(original_image_np: np.ndarray, sketchpad_image_np:
169
 
170
  elif sketchpad_image_np.ndim != 4 or sketchpad_image_np.shape[2] != 4:
171
  # 4次元配列ではない、または4チャンネルではない場合は不正と判断
172
- # このステップは前のステップで処理されるはずだが、念のため残す
173
- return fail(f"描画データ形式が不正です。(次元: {sketchpad_image_np.ndim}, チャンネル: {sketchpad_image_np.shape[2] if sketchpad_image_np.ndim >= 3 else 'N/A'})。")
 
174
 
175
  # PIL Image (元の画像) を取得
176
  original_image = Image.fromarray(original_image_np).convert("RGBA")
@@ -180,10 +184,11 @@ async def segment_and_inpaint(original_image_np: np.ndarray, sketchpad_image_np:
180
  sketch_mask_alpha = sketchpad_image_np[:, :, 3]
181
 
182
  # ユーザーが何も描画しなかった場合のチェック (アルファチャンネルが全てゼロ)
183
- # ブラシで描画した場合、アルファチャンネルは255の領域を持つはず
184
  if np.all(sketch_mask_alpha == 0):
185
  # SketchpadがNoneの場合もここに来る
186
- return fail("分割したいパーツをブラシで描画してください。(描画が検出されません)")
 
 
187
 
188
  # NumPy配列からPIL Imageのマスクに変換 (Lモード)
189
  hair_mask = Image.fromarray(sketch_mask_alpha, mode='L')
@@ -211,9 +216,13 @@ async def segment_and_inpaint(original_image_np: np.ndarray, sketchpad_image_np:
211
  inpaint_prompt or "マスクされた領域のキャラクターの顔と身体の肌、及び下に着ている服を、元のイラストのテイストに合わせて自然に補完してください。"
212
  )
213
  except gr.Error as e:
214
- return fail(f"AI補完APIエラー: {e}")
 
 
215
  except Exception as e:
216
- return fail(f"AI補完処理中に予期せぬエラー: {e}")
 
 
217
 
218
  # 3. 出力ファイルの準備とZIPファイルの作成
219
  output_parts = {
@@ -236,7 +245,7 @@ async def segment_and_inpaint(original_image_np: np.ndarray, sketchpad_image_np:
236
  zip_buffer = io.BytesIO()
237
  with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zipf:
238
  for name, img in output_parts.items():
239
- img_buffer = io.BytesIo()
240
  if img.mode != 'RGBA':
241
  img = img.convert('RGBA')
242
  img.save(img_buffer, format="PNG")
@@ -252,8 +261,8 @@ async def segment_and_inpaint(original_image_np: np.ndarray, sketchpad_image_np:
252
 
253
  print(f"--- 4. 全パーツZIPファイル {zip_file_path} の作成完了 ---")
254
 
255
- # 成功時のリターン (6つの出力)
256
- return (
257
  completed_body_part,
258
  hair_part,
259
  body_with_hole,
@@ -311,8 +320,8 @@ with gr.Blocks(theme=theme, title="Live2D素材自動分割・補完アプリ")
311
  gr.Markdown(
312
  """
313
  ### 📌 開発のポイント
314
- * **安定性の再強化:** GradioのSketchpadが予期せず `None` や非標準のNumPy配列返した場合でも、空透明な配列作成て処理を続行するとで型の不一致エラを徹底的に回避します。
315
- * **フィードバック改善:** AI処理開始時にステータスメセージ更新、ユーザーに待機を促します。
316
  """
317
  )
318
 
 
139
  """
140
  アップロードされた一枚絵とブラシで描かれたマスクを受け取り、
141
  マスクされた領域を分割し、欠損部分をAI補完する関数。
142
+ (この関数はasync generatorとして動作し、yieldで結果を返します)
143
  """
144
+ # 失敗時の統一リターン用タプルを生成
145
  def fail(message):
146
  # 画像出力は全てNone, JSONとZIPは空文字列/None, ステータスにエラーメッセージ
147
+ return (None, None, None, "{}", None, f"❌ 処理失敗: {message}")
148
 
149
  if original_image_np is None:
150
+ # 修正: return -> yield
151
+ yield fail("元の画像がアップロードされていません。")
152
+ return # Generatorを終了
153
+
154
  # 元画像の形状を取得(SketchpadがNoneだった場合の代替用)
155
  h, w, _ = original_image_np.shape
156
 
157
+ # ★★★ Sketchpad入力の型チェックとデータ形式の強制 ★★★
158
 
159
  if not isinstance(sketchpad_image_np, np.ndarray) or sketchpad_image_np is None:
160
  # Sketchpadの入力がNumPy配列ではないか、Noneであった場合、
 
172
 
173
  elif sketchpad_image_np.ndim != 4 or sketchpad_image_np.shape[2] != 4:
174
  # 4次元配列ではない、または4チャンネルではない場合は不正と判断
175
+ # 修正: return -> yield
176
+ yield fail(f"描画データ形式が不正です。(次元: {sketchpad_image_np.ndim}, チャンネル: {sketchpad_image_np.shape[2] if sketchpad_image_np.ndim >= 3 else 'N/A'})。")
177
+ return # Generatorを終了
178
 
179
  # PIL Image (元の画像) を取得
180
  original_image = Image.fromarray(original_image_np).convert("RGBA")
 
184
  sketch_mask_alpha = sketchpad_image_np[:, :, 3]
185
 
186
  # ユーザーが何も描画しなかった場合のチェック (アルファチャンネルが全てゼロ)
 
187
  if np.all(sketch_mask_alpha == 0):
188
  # SketchpadがNoneの場合もここに来る
189
+ # 修正: return -> yield
190
+ yield fail("分割したいパーツをブラシで描画してください。(描画が検出されません)")
191
+ return # Generatorを終了
192
 
193
  # NumPy配列からPIL Imageのマスクに変換 (Lモード)
194
  hair_mask = Image.fromarray(sketch_mask_alpha, mode='L')
 
216
  inpaint_prompt or "マスクされた領域のキャラクターの顔と身体の肌、及び下に着ている服を、元のイラストのテイストに合わせて自然に補完してください。"
217
  )
218
  except gr.Error as e:
219
+ # 修正: return -> yield
220
+ yield fail(f"AI補完APIエラー: {e}")
221
+ return # Generatorを終了
222
  except Exception as e:
223
+ # 修正: return -> yield
224
+ yield fail(f"AI補完処理中に予期せぬエラー: {e}")
225
+ return # Generatorを終了
226
 
227
  # 3. 出力ファイルの準備とZIPファイルの作成
228
  output_parts = {
 
245
  zip_buffer = io.BytesIO()
246
  with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zipf:
247
  for name, img in output_parts.items():
248
+ img_buffer = io.BytesIO()
249
  if img.mode != 'RGBA':
250
  img = img.convert('RGBA')
251
  img.save(img_buffer, format="PNG")
 
261
 
262
  print(f"--- 4. 全パーツZIPファイル {zip_file_path} の作成完了 ---")
263
 
264
+ # 成功時の最終結果をyield (6つの出力)
265
+ yield (
266
  completed_body_part,
267
  hair_part,
268
  body_with_hole,
 
320
  gr.Markdown(
321
  """
322
  ### 📌 開発のポイント
323
+ * **エラー解消:** `async def` 関数内で `yield`使用する場合の `SyntaxError` 解消ました。れにより処理ステタスが正くフィードバックされるようになります。
324
+ * **安定性再強化:** Sketchpadの入力データ型チェ引き続き強化ています。
325
  """
326
  )
327