doropiza commited on
Commit
ddf4ee3
·
1 Parent(s): a1d9ef3
Files changed (2) hide show
  1. app.py +160 -47
  2. requirements.txt +14 -8
app.py CHANGED
@@ -13,26 +13,54 @@ class TextSummarizer:
13
  # GPUが利用可能かチェック
14
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
15
  print(f"使用デバイス: {self.device}")
 
16
 
17
- # 日本語対応の要約モデルを初期化
18
- # 軽量で高性能なモデルを使用
19
- model_name = "rinna/japanese-gpt2-medium" # 英語用
20
- # 日本語の場合は "rinna/japanese-gpt2-medium" "cyberagent/open-calm-7b" などを検討
 
 
21
 
 
22
  try:
23
- self.tokenizer = AutoTokenizer.from_pretrained(model_name)
24
- self.model = AutoModelForSeq2SeqLM.from_pretrained(model_name).to(self.device)
25
  self.summarizer = pipeline(
26
  "summarization",
27
- model=self.model,
28
- tokenizer=self.tokenizer,
29
- device=0 if self.device == "cuda" else -1
 
 
30
  )
31
- print("モデルの読み込みが完了しました")
32
  except Exception as e:
33
- print(f"モデル読み込みエラー: {e}")
34
- # フォールバック用の軽量モデル
35
- self.summarizer = pipeline("summarization", device=0 if self.device == "cuda" else -1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  def clean_text(self, text):
38
  """テキストの前処理"""
@@ -174,47 +202,98 @@ summarizer = TextSummarizer()
174
 
175
  def process_text_input(text, max_length, min_length):
176
  """テキスト入力の処理"""
177
- if not text.strip():
178
- return "テキストを入力してください。"
179
-
180
- summary = summarizer.summarize_text(text, max_length, min_length)
181
- return summarizer.structure_summary(summary)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
  def process_pdf_input(pdf_file, max_length, min_length):
184
  """PDF��力の処理"""
185
- if pdf_file is None:
186
- return "PDFファイルを選択してください。"
187
-
188
- text = summarizer.extract_text_from_pdf(pdf_file)
189
- if text.startswith("PDFの読み込みで"):
190
- return text
191
-
192
- summary = summarizer.summarize_text(text, max_length, min_length)
193
- return summarizer.structure_summary(summary)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
  def process_url_input(url, max_length, min_length):
196
  """URL入力の処理"""
197
- if not url.strip():
198
- return "URLを入力してください。"
199
-
200
- if not url.startswith(('http://', 'https://')):
201
- url = 'https://' + url
202
-
203
- text = summarizer.extract_text_from_url(url)
204
- if text.startswith("Webサイトの読み込みで"):
205
- return text
206
-
207
- summary = summarizer.summarize_text(text, max_length, min_length)
208
- return summarizer.structure_summary(summary)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
  # Gradioインターフェース作成
211
  def create_interface():
212
  with gr.Blocks(title="🤖 ローカルLLM テキスト要約ツール", theme=gr.themes.Soft()) as app:
213
  gr.Markdown("""
214
- # 🤖 ローカルLLM テキスト要約ツール
215
 
216
  このツールは、ローカルで動作するLLMを使用してテキストを要約し、構造化された形式で出力します。
217
 
 
 
 
 
 
218
  ## 📝 対応入力形式
219
  - **テキスト直接入力**
220
  - **PDFファイル**
@@ -249,9 +328,10 @@ def create_interface():
249
  text_output = gr.Markdown(label="要約結果")
250
 
251
  text_btn.click(
252
- process_text_input,
253
  inputs=[text_input, max_length, min_length],
254
- outputs=text_output
 
255
  )
256
 
257
  # PDF入力タブ
@@ -268,9 +348,10 @@ def create_interface():
268
  pdf_output = gr.Markdown(label="要約結果")
269
 
270
  pdf_btn.click(
271
- process_pdf_input,
272
  inputs=[pdf_input, max_length, min_length],
273
- outputs=pdf_output
 
274
  )
275
 
276
  # URL入力タブ
@@ -287,9 +368,10 @@ def create_interface():
287
  url_output = gr.Markdown(label="要約結果")
288
 
289
  url_btn.click(
290
- process_url_input,
291
  inputs=[url_input, max_length, min_length],
292
- outputs=url_output
 
293
  )
294
 
295
  # 使用方法
@@ -301,15 +383,46 @@ def create_interface():
301
  3. **実行**: 対応する実行ボタンをクリック
302
  4. **結果確認**: 構造化された要約結果を確認
303
 
304
- ## ⚙️ 技術仕様
305
  - **モデル**: Facebook BART (ローカル実行)
 
 
306
  - **GPU加速**: CUDA対応
307
  - **出力形式**: 構造化Markdown
 
 
 
 
 
308
  """)
309
 
310
  return app
311
 
312
  if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  # アプリケーション起動
314
  app = create_interface()
315
  app.launch(
 
13
  # GPUが利用可能かチェック
14
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
15
  print(f"使用デバイス: {self.device}")
16
+ print(f"PyTorch バージョン: {torch.__version__}")
17
 
18
+ # PyTorch v2.6未満の場合は警告
19
+ torch_version = torch.__version__.split('+')[0] # +cu121などを除去
20
+ major, minor = map(int, torch_version.split('.')[:2])
21
+ if major < 2 or (major == 2 and minor < 6):
22
+ print("⚠️ 警告: PyTorch v2.6未満です。セキュリティ脆弱性(CVE-2025-32434)のため、アップグレードを推奨します。")
23
+ print(" アップグレード: pip install torch>=2.6.0")
24
 
25
+ # safetensorsを優先したモデル読み込み
26
  try:
27
+ print("モデルを読み込み中...")
 
28
  self.summarizer = pipeline(
29
  "summarization",
30
+ model="facebook/bart-large-cnn",
31
+ device=0 if self.device == "cuda" else -1,
32
+ framework="pt",
33
+ use_safetensors=True, # safetensorsを優先
34
+ trust_remote_code=False # セキュリティ強化
35
  )
36
+ print("モデルの読み込みが完了しました (safetensors使用)")
37
  except Exception as e:
38
+ print(f" メインモデル読み込みエラー: {e}")
39
+ # より軽量なフォールバック(safetensors対応)
40
+ try:
41
+ print("フォールバックモデルを試行中...")
42
+ self.summarizer = pipeline(
43
+ "summarization",
44
+ model="sshleifer/distilbart-cnn-12-6",
45
+ device=0 if self.device == "cuda" else -1,
46
+ use_safetensors=True,
47
+ trust_remote_code=False
48
+ )
49
+ print("✅ フォールバックモデルの読み込みが完了しました")
50
+ except Exception as e2:
51
+ print(f"❌ フォールバックモデルもエラー: {e2}")
52
+ # 最終フォールバック(safetensorsなし)
53
+ try:
54
+ print("最終フォールバック(レガシーモード)...")
55
+ self.summarizer = pipeline(
56
+ "summarization",
57
+ model="sshleifer/distilbart-cnn-12-6",
58
+ device=0 if self.device == "cuda" else -1
59
+ )
60
+ print("⚠️ レガシーモードで読み込み完了(safetensorsなし)")
61
+ except Exception as e3:
62
+ print(f"❌ 全てのモデル読み込みに失敗: {e3}")
63
+ raise Exception("モデルの読み込みに失敗しました。requirements.txtを確認し、依存関係を更新してください。")
64
 
65
  def clean_text(self, text):
66
  """テキストの前処理"""
 
202
 
203
  def process_text_input(text, max_length, min_length):
204
  """テキスト入力の処理"""
205
+ try:
206
+ print(f"テキスト処理開始: {len(text) if text else 0}文字")
207
+
208
+ if not text or not text.strip():
209
+ return "## ⚠️ エラー\nテキストを入力してください。"
210
+
211
+ # プログレス表示
212
+ yield "## 🔄 処理中...\nテキストを要約しています..."
213
+
214
+ summary = summarizer.summarize_text(text, int(max_length), int(min_length))
215
+ result = summarizer.structure_summary(summary)
216
+
217
+ print("テキスト処理完了")
218
+ yield result
219
+
220
+ except Exception as e:
221
+ error_msg = f"## ❌ エラーが発生しました\n```\n{str(e)}\n```"
222
+ print(f"テキスト処理エラー: {e}")
223
+ yield error_msg
224
 
225
  def process_pdf_input(pdf_file, max_length, min_length):
226
  """PDF��力の処理"""
227
+ try:
228
+ print(f"PDF処理開始: {pdf_file}")
229
+
230
+ if pdf_file is None:
231
+ return "## ⚠️ エラー\nPDFファイルを選択してください。"
232
+
233
+ yield "## 🔄 処理中...\nPDFファイルを読み込んでいます..."
234
+
235
+ text = summarizer.extract_text_from_pdf(pdf_file)
236
+ if text.startswith("PDFの読み込みで"):
237
+ yield f"## ❌ エラー\n{text}"
238
+ return
239
+
240
+ yield "## 🔄 処理中...\nテキストを要約しています..."
241
+
242
+ summary = summarizer.summarize_text(text, int(max_length), int(min_length))
243
+ result = summarizer.structure_summary(summary)
244
+
245
+ print("PDF処理完了")
246
+ yield result
247
+
248
+ except Exception as e:
249
+ error_msg = f"## ❌ エラーが発生しました\n```\n{str(e)}\n```"
250
+ print(f"PDF処理エラー: {e}")
251
+ yield error_msg
252
 
253
  def process_url_input(url, max_length, min_length):
254
  """URL入力の処理"""
255
+ try:
256
+ print(f"URL処理開始: {url}")
257
+
258
+ if not url or not url.strip():
259
+ return "## ⚠️ エラー\nURLを入力してください。"
260
+
261
+ if not url.startswith(('http://', 'https://')):
262
+ url = 'https://' + url
263
+
264
+ yield "## 🔄 処理中...\nWebサイトを読み込んでいます..."
265
+
266
+ text = summarizer.extract_text_from_url(url)
267
+ if text.startswith("Webサイトの読み込みで"):
268
+ yield f"## ❌ エラー\n{text}"
269
+ return
270
+
271
+ yield "## 🔄 処理中...\nテキストを要約しています..."
272
+
273
+ summary = summarizer.summarize_text(text, int(max_length), int(min_length))
274
+ result = summarizer.structure_summary(summary)
275
+
276
+ print("URL処理完了")
277
+ yield result
278
+
279
+ except Exception as e:
280
+ error_msg = f"## ❌ エラーが発生しました\n```\n{str(e)}\n```"
281
+ print(f"URL処理エラー: {e}")
282
+ yield error_msg
283
 
284
  # Gradioインターフェース作成
285
  def create_interface():
286
  with gr.Blocks(title="🤖 ローカルLLM テキスト要約ツール", theme=gr.themes.Soft()) as app:
287
  gr.Markdown("""
288
+ # 🤖 ローカルLLM テキスト要約ツール (v5 Security Update)
289
 
290
  このツールは、ローカルで動作するLLMを使用してテキストを要約し、構造化された形式で出力します。
291
 
292
+ ## 🔒 セキュリティアップデート
293
+ - **PyTorch v2.6+** 対応(CVE-2025-32434 対策)
294
+ - **safetensors** 形式を優先使用
295
+ - **trust_remote_code=False** でセキュリティ強化
296
+
297
  ## 📝 対応入力形式
298
  - **テキスト直接入力**
299
  - **PDFファイル**
 
328
  text_output = gr.Markdown(label="要約結果")
329
 
330
  text_btn.click(
331
+ fn=process_text_input,
332
  inputs=[text_input, max_length, min_length],
333
+ outputs=text_output,
334
+ show_progress=True
335
  )
336
 
337
  # PDF入力タブ
 
348
  pdf_output = gr.Markdown(label="要約結果")
349
 
350
  pdf_btn.click(
351
+ fn=process_pdf_input,
352
  inputs=[pdf_input, max_length, min_length],
353
+ outputs=pdf_output,
354
+ show_progress=True
355
  )
356
 
357
  # URL入力タブ
 
368
  url_output = gr.Markdown(label="要約結果")
369
 
370
  url_btn.click(
371
+ fn=process_url_input,
372
  inputs=[url_input, max_length, min_length],
373
+ outputs=url_output,
374
+ show_progress=True
375
  )
376
 
377
  # 使用方法
 
383
  3. **実行**: 対応する実行ボタンをクリック
384
  4. **結果確認**: 構造化された要約結果を確認
385
 
386
+ ## ⚙️ 技術仕様 (v5 Security Update)
387
  - **モデル**: Facebook BART (ローカル実行)
388
+ - **セキュリティ**: PyTorch v2.6+ (CVE-2025-32434 対策)
389
+ - **フォーマット**: safetensors優先
390
  - **GPU加速**: CUDA対応
391
  - **出力形式**: 構造化Markdown
392
+
393
+ ## 🔒 セキュリティ機能
394
+ - safetensors形式での安全なモデル読み込み
395
+ - trust_remote_code=False設定
396
+ - 脆弱性対策済みPyTorchバージョン要求
397
  """)
398
 
399
  return app
400
 
401
  if __name__ == "__main__":
402
+ # セキュリティアップデート情報
403
+ print("""
404
+ 🔒 セキュリティアップデート v5 🔒
405
+
406
+ PyTorch脆弱性(CVE-2025-32434)対応のため、以下の更新が必要です:
407
+
408
+ pip install torch>=2.6.0 transformers>=4.40.0 safetensors>=0.4.0
409
+
410
+ または、requirements.txtを更新:
411
+ pip install -r requirements.txt
412
+
413
+ GPU使用の場合:
414
+ pip install torch>=2.6.0+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
415
+ """)
416
+
417
+ # PyTorchバージョンチェック
418
+ torch_version = torch.__version__.split('+')[0]
419
+ major, minor = map(int, torch_version.split('.')[:2])
420
+ if major < 2 or (major == 2 and minor < 6):
421
+ print(f"⚠️ 現在のPyTorchバージョン: {torch.__version__}")
422
+ print("🚨 セキュリティリスクあり - アップグレードを強く推奨します")
423
+ else:
424
+ print(f"✅ PyTorchバージョン: {torch.__version__} (セキュア)")
425
+
426
  # アプリケーション起動
427
  app = create_interface()
428
  app.launch(
requirements.txt CHANGED
@@ -1,10 +1,11 @@
1
- # Core ML Libraries
2
- torch>=2.0.0
3
- transformers>=4.30.0
4
- tokenizers>=0.13.0
 
5
 
6
  # Web Interface
7
- gradio>=3.35.0
8
 
9
  # PDF Processing
10
  PyPDF2>=3.0.0
@@ -21,14 +22,19 @@ pandas>=2.0.0
21
  nltk>=3.8.0
22
  regex>=2023.6.3
23
 
 
 
 
 
24
  # Optional: Japanese Text Processing
25
  # fugashi>=1.3.0
26
  # unidic-lite>=1.0.8
27
  # mecab-python3>=1.0.6
28
 
29
- # Optional: GPU Support (uncomment if using CUDA)
30
- # torch-audio>=2.0.0+cu118 --extra-index-url https://download.pytorch.org/whl/cu118
31
- # torchvision>=0.15.0+cu118 --extra-index-url https://download.pytorch.org/whl/cu118
 
32
 
33
  # Development Tools (optional)
34
  # jupyter>=1.0.0
 
1
+ # Core ML Libraries - Updated for security (CVE-2025-32434)
2
+ torch>=2.6.0
3
+ transformers>=4.40.0
4
+ tokenizers>=0.15.0
5
+ safetensors>=0.4.0
6
 
7
  # Web Interface
8
+ gradio>=4.0.0
9
 
10
  # PDF Processing
11
  PyPDF2>=3.0.0
 
22
  nltk>=3.8.0
23
  regex>=2023.6.3
24
 
25
+ # Security and Performance
26
+ accelerate>=0.25.0
27
+ huggingface-hub>=0.20.0
28
+
29
  # Optional: Japanese Text Processing
30
  # fugashi>=1.3.0
31
  # unidic-lite>=1.0.8
32
  # mecab-python3>=1.0.6
33
 
34
+ # Optional: GPU Support (CUDA 12.1+)
35
+ # torch>=2.6.0+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
36
+ # torchvision>=0.18.0+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
37
+ # torchaudio>=2.6.0+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
38
 
39
  # Development Tools (optional)
40
  # jupyter>=1.0.0