AIdentify_LLM / app.py
rein0421's picture
Update app.py
86b2c3f verified
import json
import numpy as np
from PIL import Image
import subprocess
import sys
import logging
import gradio as gr
from typing import Tuple, Dict, Optional
import tempfile
import os
def install(package):
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
# 依存関係のインストール
install("opencv-python-headless")
install("moondream")
install("openai")
import cv2
import moondream as md
from openai import OpenAI
class PrivacyProtector:
def __init__(self, moondream_api_key, deepseek_api_key):
self.moon_model = md.vl(api_key=moondream_api_key)
self.deepseek_client = OpenAI(
api_key=deepseek_api_key,
base_url="https://api.deepseek.com"
)
def analyze_risk(self, image_path):
"""画像のリスク分析を行う"""
try:
pil_image = Image.open(image_path)
cv_image = cv2.imread(image_path)
if cv_image is None:
raise ValueError("画像の読み込みに失敗しました")
encoded_image = self.moon_model.encode_image(pil_image)
caption = self.moon_model.caption(encoded_image)["caption"]
analysis_prompt = f"""
以下の画像説明を基に個人情報漏洩リスクを分析し、厳密にJSON形式で返答してください:
{{
"risk_level": "high|medium|low",
"risk_reason": "リスクの具体的理由",
"objects_to_remove": ["消去すべきオブジェクトリスト"]
}}
画像説明: {caption}
"""
response = self.deepseek_client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "あなたは優秀なセキュリティ分析AIです。"},
{"role": "user", "content": analysis_prompt}
],
temperature=0.3,
response_format={"type": "json_object"}
)
result = json.loads(response.choices[0].message.content)
return pil_image, cv_image, result
except Exception as e:
logging.error(f"リスク分析エラー: {str(e)}")
raise
def remove_objects(self, pil_image, cv_image, objects_to_remove):
"""オブジェクト検出と消去処理"""
try:
mask = np.zeros(cv_image.shape[:2], dtype=np.uint8)
h, w = cv_image.shape[:2]
for obj_name in objects_to_remove:
detection = self.moon_model.detect(pil_image, obj_name)
for obj in detection["objects"]:
x_min = int(obj['x_min'] * w)
y_min = int(obj['y_min'] * h)
x_max = int(obj['x_max'] * w)
y_max = int(obj['y_max'] * h)
cv2.rectangle(mask, (x_min, y_min), (x_max, y_max), 255, -1)
inpainted = cv2.inpaint(cv_image, mask, 3, cv2.INPAINT_TELEA)
return inpainted
except Exception as e:
logging.error(f"オブジェクト削除エラー: {str(e)}")
raise
def process_image(self, image_path):
"""画像処理フロー全体"""
try:
pil_img, cv_img, result = self.analyze_risk(image_path)
if result['risk_level'] != 'low':
cleaned = self.remove_objects(pil_img, cv_img, result['objects_to_remove'])
return cleaned, result
return cv_img, result
except Exception as e:
logging.error(f"画像処理エラー: {str(e)}")
raise
def gradio_process(input_image):
try:
# 一時ファイルの処理
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_file:
input_path = tmp_file.name
cv2.imwrite(input_path, cv2.cvtColor(input_image, cv2.COLOR_RGB2BGR))
# 環境変数の安全な取得
protector = PrivacyProtector(
moondream_api_key=os.environ.get('MOONDREAM'),
deepseek_api_key=os.environ.get('DEEPSEEK')
)
# 画像処理実行
processed_image, result = protector.process_image(input_path)
# 結果の整形
output_image = cv2.cvtColor(processed_image, cv2.COLOR_BGR2RGB)
info_html = f"""
<div style="padding:20px; background:#f0f0f0; border-radius:10px;">
<h3>分析結果</h3>
<p><strong>生成キャプション:</strong> {result.get('caption', '')}</p>
<p><strong>リスクレベル:</strong> <span style="color:{'red' if result['risk_level'] == 'high' else 'orange' if result['risk_level'] == 'medium' else 'green'}">{result['risk_level'].upper()}</span></p>
<p><strong>理由:</strong> {result['risk_reason']}</p>
<p><strong>消去対象:</strong> {', '.join(result['objects_to_remove'])}</p>
</div>
"""
return input_image, output_image, info_html
except Exception as e:
error_msg = f"処理中にエラーが発生しました: {str(e)}"
return input_image, None, f'<div style="color:red;">{error_msg}</div>'
finally:
# 一時ファイルのクリーンアップ
if 'input_path' in locals() and os.path.exists(input_path):
os.remove(input_path)
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🛡️ プライバシー保護画像処理ツール")
with gr.Row():
with gr.Column(scale=2):
input_img = gr.Image(label="入力画像", type="numpy")
submit_btn = gr.Button("画像を分析・処理", variant="primary")
with gr.Column(scale=2):
output_img = gr.Image(label="処理後の画像")
info_output = gr.HTML(label="分析結果")
with gr.Accordion("処理の詳細", open=False):
gr.Markdown("""
**処理フロー:**
1. 画像キャプション生成 (Moondream)
2. リスク分析 (DeepSeek)
3. オブジェクト検出・消去 (Moondream + OpenCV)
""")
submit_btn.click(
fn=gradio_process,
inputs=input_img,
outputs=[input_img, output_img, info_output]
)
if __name__ == "__main__":
demo.launch()