Spaces:
Sleeping
Sleeping
commit
Browse files- app.py +160 -47
- 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 |
-
|
20 |
-
|
|
|
|
|
21 |
|
|
|
22 |
try:
|
23 |
-
|
24 |
-
self.model = AutoModelForSeq2SeqLM.from_pretrained(model_name).to(self.device)
|
25 |
self.summarizer = pipeline(
|
26 |
"summarization",
|
27 |
-
model=
|
28 |
-
|
29 |
-
|
|
|
|
|
30 |
)
|
31 |
-
print("モデルの読み込みが完了しました")
|
32 |
except Exception as e:
|
33 |
-
print(f"
|
34 |
-
#
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
|
183 |
def process_pdf_input(pdf_file, max_length, min_length):
|
184 |
"""PDF��力の処理"""
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
|
195 |
def process_url_input(url, max_length, min_length):
|
196 |
"""URL入力の処理"""
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
3 |
-
transformers>=4.
|
4 |
-
tokenizers>=0.
|
|
|
5 |
|
6 |
# Web Interface
|
7 |
-
gradio>=
|
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 (
|
30 |
-
# torch
|
31 |
-
# torchvision>=0.
|
|
|
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
|