wadmjada commited on
Commit
0b3a596
·
verified ·
1 Parent(s): 2dcd75b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -74
app.py CHANGED
@@ -1,11 +1,10 @@
1
  # ===================================================================
2
  #
3
- #   【最終版v3】AIペルソナ選択式 Gradioアプリ (環境自動判定対応)
4
  #
5
  # ===================================================================
6
 
7
  # ライブラリのインポート
8
- print("⚙️ 必要なライブラリをインポートします...")
9
  import torch
10
  import torch.nn as nn
11
  import warnings
@@ -18,59 +17,52 @@ from peft import PeftModel
18
  import gradio as gr
19
  from PIL import Image
20
 
21
- # ログレベルを設定
22
  logging.basicConfig(level=logging.INFO)
23
  logger = logging.getLogger(__name__)
24
-
25
  warnings.filterwarnings("ignore")
26
 
27
- # --- グローバル変数 ---
28
  MODELS_CACHE = {}
29
  CURRENT_PERSONA = None
30
- BASE_MODEL = None # ベースモデルをグローバルに保持
31
  TOKENIZER = None
32
  CLIP_MODEL = None
33
  CLIP_PROCESSOR = None
34
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
35
 
36
- # ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
37
- # ★★★ 実行環境を自動で判定し、モデルへのパスを正しく設定します ★★★
38
- # ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
39
  if 'SPACE_ID' in os.environ:
40
- print("✅ Hugging Face Spaces環境で実行中")
41
- # Hugging Face Spacesでは、アップロードされたファイルはルートにあります
42
  MODEL_BASE_PATH = '.'
43
  else:
44
  try:
45
  from google.colab import drive
46
- print("\n🔗 Googleドライブをマウントします...")
47
  drive.mount('/content/drive', force_remount=True)
48
  MODEL_BASE_PATH = '/content/drive/MyDrive'
49
- print("✅ Google Colab環境で実行中")
50
  except ImportError:
51
- print("⚠️ ローカル環境として実行します。'./models'フォルダにモデルを配置してください。")
52
- # ローカルPCで実行する場合、このコードと同じ階層に'models'フォルダを作成し、
53
- # その中に`final_model_`で始まるフォルダ群を配置してください。
54
  MODEL_BASE_PATH = './models'
55
 
56
- print(f"🖥️ 使用デバイス: {DEVICE}")
57
- print(f"📂 モデルデータの検索パス: {MODEL_BASE_PATH}")
58
 
59
 
60
  # --- モデル定義 ---
61
  class MultimodalModel(nn.Module):
62
- def __init__(self, base_model, face_embedding_dim):
63
  super().__init__()
64
- self.base_model = base_model
65
- self.face_injector = nn.Linear(face_embedding_dim, self.base_model.config.hidden_size)
66
 
67
  def forward(self, input_ids, attention_mask, face_embedding, **kwargs):
68
  try:
69
- target_device = self.base_model.get_input_embeddings().weight.device
70
- target_dtype = self.base_model.get_input_embeddings().weight.dtype
71
 
72
  self.face_injector.to(target_device, dtype=target_dtype)
73
- inputs_embeds = self.base_model.get_input_embeddings()(input_ids)
74
  injected_face_features = self.face_injector(face_embedding.to(target_device, dtype=target_dtype))
75
 
76
  conditioned_embeds = torch.cat([injected_face_features.unsqueeze(1), inputs_embeds], dim=1)
@@ -78,11 +70,8 @@ class MultimodalModel(nn.Module):
78
  torch.ones(attention_mask.shape[0], 1, device=target_device, dtype=attention_mask.dtype),
79
  attention_mask
80
  ], dim=1)
81
-
82
- if "inputs" in kwargs:
83
- kwargs["inputs"] = kwargs["inputs"].to(target_device)
84
-
85
- return self.base_model.generate(
86
  inputs_embeds=conditioned_embeds,
87
  attention_mask=new_attention_mask,
88
  **kwargs
@@ -92,46 +81,16 @@ class MultimodalModel(nn.Module):
92
  traceback.print_exc()
93
  raise
94
 
95
- # --- モデルロード関連の関数 ---
96
- @torch.no_grad()
97
- def get_available_models():
98
- """利用可能なモデルのリストを取得"""
99
- try:
100
- if not os.path.exists(MODEL_BASE_PATH):
101
- logger.warning(f"モデルディレクトリが存在しません: {MODEL_BASE_PATH}")
102
- return []
103
-
104
- model_paths = glob.glob(os.path.join(MODEL_BASE_PATH, "final_model_*"))
105
- if not model_paths:
106
- logger.warning(f"モデルファイルが見つかりません: {MODEL_BASE_PATH}に final_model_* がありません。")
107
- return []
108
-
109
- model_names = sorted([os.path.basename(p).replace("final_model_", "").replace("_", " ") for p in model_paths])
110
- return model_names
111
- except Exception as e:
112
- logger.error(f"モデル検索エラー: {e}")
113
- return []
114
 
115
  @torch.no_grad()
116
- def load_model_and_dependencies(person_name, progress=gr.Progress()):
117
- """全ての依存モデルと指定された人物モデルをロード"""
118
- global BASE_MODEL, FINAL_MODEL, CURRENT_PERSONA, TOKENIZER, CLIP_MODEL, CLIP_PROCESSOR
119
-
120
  try:
121
- # --- 共通モデル(Tokenizer, CLIP, Base LLM)の初期化 ---
122
- progress(0, desc="🔄 コアモデルを準備中...")
123
- if TOKENIZER is None:
124
- logger.info("📝 Tokenizerをロード中...")
125
- TOKENIZER = AutoTokenizer.from_pretrained("rinna/nekomata-7b-instruction", trust_remote_code=True)
126
- TOKENIZER.pad_token = TOKENIZER.eos_token
127
- logger.info("✅ Tokenizerのロード完了")
128
-
129
- if CLIP_MODEL is None or CLIP_PROCESSOR is None:
130
- logger.info("📷 CLIP画像エンコーダーをロード中...")
131
- CLIP_MODEL = CLIPModel.from_pretrained("openai/clip-vit-large-patch14").to(DEVICE)
132
- CLIP_PROCESSOR = CLIPProcessor.from_pretrained("openai/clip-vit-large-patch14")
133
- logger.info("✅ CLIPモデルのロード完了")
134
-
135
  if BASE_MODEL is None:
136
  logger.info("🧠 ベースLLMをロード中... (時間がかかります)")
137
  quantization_config = BitsAndBytesConfig(
@@ -145,8 +104,29 @@ def load_model_and_dependencies(person_name, progress=gr.Progress()):
145
  )
146
  logger.info("✅ ベースLLMのロード完了")
147
 
148
- # --- ペルソナモデルのロード ---
149
- progress(0.5, desc=f"🔄 AI人格「{person_name}」を適用中...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  if person_name == CURRENT_PERSONA and FINAL_MODEL is not None:
151
  logger.info(f"✅ AI人格「{person_name}」は既に準備完了です。")
152
  return True
@@ -185,7 +165,7 @@ def load_model_and_dependencies(person_name, progress=gr.Progress()):
185
  return True
186
 
187
  except Exception as e:
188
- logger.error(f"モデルロードおよび依存関係の初期化エラー: {e}")
189
  traceback.print_exc()
190
  return False
191
 
@@ -197,7 +177,7 @@ def predict(person_name, image, instruction, max_len, temp, top_p, progress=gr.P
197
  if image is None: return "❌ エラー: 画像をアップロードしてください。"
198
  if not instruction.strip(): return "❌ エラー: 指示(プロンプト)を入力してください。"
199
 
200
- if not load_model_and_dependencies(person_name, progress):
201
  return f"❌ エラー: AI人格「{person_name}」のロードに失敗しました。詳細はログを確認してくださ���。"
202
 
203
  progress(0.4, desc="🖼️ 顔の雰囲気を分析中...")
@@ -306,9 +286,9 @@ if __name__ == "__main__":
306
  logger.info("🌐 Gradioアプリケーションを起動します...")
307
  demo.launch(debug=False)
308
  else:
309
- # 初期化に失敗した場合、エラーUIを表示する
 
310
  with gr.Blocks(title="起動エラー") as error_demo:
311
  gr.Markdown("# ❌ 致命的なエラー: コアモデルの初期化に失敗しました。")
312
- gr.Markdown("ログを確認して、必要なライブラリがインストールされているか、モデルへのパスが正しいかを確認してください。")
313
- error_demo.launch(debug=False)
314
- logger.error("❌ コアモデルの初期化に失敗したため、アプリを起動できません。")
 
1
  # ===================================================================
2
  #
3
+ #   【最終完成版v4】AIペルソナ選択式 Gradioアプリ
4
  #
5
  # ===================================================================
6
 
7
  # ライブラリのインポート
 
8
  import torch
9
  import torch.nn as nn
10
  import warnings
 
17
  import gradio as gr
18
  from PIL import Image
19
 
20
+ # --- グローバル変数と基本設定 ---
21
  logging.basicConfig(level=logging.INFO)
22
  logger = logging.getLogger(__name__)
 
23
  warnings.filterwarnings("ignore")
24
 
 
25
  MODELS_CACHE = {}
26
  CURRENT_PERSONA = None
27
+ BASE_MODEL = None
28
  TOKENIZER = None
29
  CLIP_MODEL = None
30
  CLIP_PROCESSOR = None
31
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
32
 
33
+ # --- 環境判定とパス設定 ---
 
 
34
  if 'SPACE_ID' in os.environ:
35
+ logger.info("✅ Hugging Face Spaces環境で実行中")
 
36
  MODEL_BASE_PATH = '.'
37
  else:
38
  try:
39
  from google.colab import drive
40
+ logger.info("\n🔗 Googleドライブをマウントします...")
41
  drive.mount('/content/drive', force_remount=True)
42
  MODEL_BASE_PATH = '/content/drive/MyDrive'
43
+ logger.info("✅ Google Colab環境で実行中")
44
  except ImportError:
45
+ logger.warning("⚠️ ローカル環境として実行します。'./models'フォルダにモデルを配置してください。")
 
 
46
  MODEL_BASE_PATH = './models'
47
 
48
+ logger.info(f"🖥️ 使用デバイス: {DEVICE}")
49
+ logger.info(f"📂 モデルデータの検索パス: {MODEL_BASE_PATH}")
50
 
51
 
52
  # --- モデル定義 ---
53
  class MultimodalModel(nn.Module):
54
+ def __init__(self, peft_model, face_embedding_dim):
55
  super().__init__()
56
+ self.peft_model = peft_model
57
+ self.face_injector = nn.Linear(face_embedding_dim, self.peft_model.config.hidden_size)
58
 
59
  def forward(self, input_ids, attention_mask, face_embedding, **kwargs):
60
  try:
61
+ target_device = self.peft_model.device
62
+ target_dtype = self.peft_model.get_input_embeddings().weight.dtype
63
 
64
  self.face_injector.to(target_device, dtype=target_dtype)
65
+ inputs_embeds = self.peft_model.get_input_embeddings()(input_ids)
66
  injected_face_features = self.face_injector(face_embedding.to(target_device, dtype=target_dtype))
67
 
68
  conditioned_embeds = torch.cat([injected_face_features.unsqueeze(1), inputs_embeds], dim=1)
 
70
  torch.ones(attention_mask.shape[0], 1, device=target_device, dtype=attention_mask.dtype),
71
  attention_mask
72
  ], dim=1)
73
+
74
+ return self.peft_model.generate(
 
 
 
75
  inputs_embeds=conditioned_embeds,
76
  attention_mask=new_attention_mask,
77
  **kwargs
 
81
  traceback.print_exc()
82
  raise
83
 
84
+ # ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
85
+ # ★★★ エラー修正箇所 ★★★
86
+ # ★★★ モデルロードの仕組みを全面的に改善しました ★★★
87
+ # ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  @torch.no_grad()
90
+ def initialize_core_models():
91
+ """アプリ起動時に一度だけ、重いコアモデルをロードする"""
92
+ global BASE_MODEL, TOKENIZER, CLIP_MODEL, CLIP_PROCESSOR
 
93
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  if BASE_MODEL is None:
95
  logger.info("🧠 ベースLLMをロード中... (時間がかかります)")
96
  quantization_config = BitsAndBytesConfig(
 
104
  )
105
  logger.info("✅ ベースLLMのロード完了")
106
 
107
+ if TOKENIZER is None:
108
+ logger.info("📝 Tokenizerをロード中...")
109
+ TOKENIZER = AutoTokenizer.from_pretrained("rinna/nekomata-7b-instruction", trust_remote_code=True)
110
+ TOKENIZER.pad_token = TOKENIZER.eos_token
111
+ logger.info("✅ Tokenizerのロード完了")
112
+
113
+ if CLIP_MODEL is None or CLIP_PROCESSOR is None:
114
+ logger.info("📷 CLIP画像エンコーダーをロード中...")
115
+ CLIP_MODEL = CLIPModel.from_pretrained("openai/clip-vit-large-patch14").to(DEVICE)
116
+ CLIP_PROCESSOR = CLIPProcessor.from_pretrained("openai/clip-vit-large-patch14")
117
+ logger.info("✅ CLIPモデルのロード完了")
118
+ return True
119
+ except Exception as e:
120
+ logger.error(f"コアモデルの初期化エラー: {e}")
121
+ traceback.print_exc()
122
+ return False
123
+
124
+ @torch.no_grad()
125
+ def load_persona_model(person_name, progress):
126
+ """指定されたAI人格(アダプター)をロードする"""
127
+ global FINAL_MODEL, CURRENT_PERSONA
128
+ try:
129
+ progress(0.1, desc=f"🔄 AI人格「{person_name}」を準備中...")
130
  if person_name == CURRENT_PERSONA and FINAL_MODEL is not None:
131
  logger.info(f"✅ AI人格「{person_name}」は既に準備完了です。")
132
  return True
 
165
  return True
166
 
167
  except Exception as e:
168
+ logger.error(f"AI人格のロードエラー: {e}")
169
  traceback.print_exc()
170
  return False
171
 
 
177
  if image is None: return "❌ エラー: 画像をアップロードしてください。"
178
  if not instruction.strip(): return "❌ エラー: 指示(プロンプト)を入力してください。"
179
 
180
+ if not load_persona_model(person_name, progress):
181
  return f"❌ エラー: AI人格「{person_name}」のロードに失敗しました。詳細はログを確認してくださ���。"
182
 
183
  progress(0.4, desc="🖼️ 顔の雰囲気を分析中...")
 
286
  logger.info("🌐 Gradioアプリケーションを起動します...")
287
  demo.launch(debug=False)
288
  else:
289
+ logger.error("❌ コアモデルの初期化に失敗したため、アプリを起動できません。")
290
+ # エラーが発生した場合でも、簡単なエラー表示UIを起動する
291
  with gr.Blocks(title="起動エラー") as error_demo:
292
  gr.Markdown("# ❌ 致命的なエラー: コアモデルの初期化に失敗しました。")
293
+ gr.Markdown("アプリケーションのログを確認して、エラーの原因を特定してください。")
294
+ error_demo.launch(debug=False)