syurein commited on
Commit
b42a7a4
·
1 Parent(s): 8851713
__pycache__/LLM_package.cpython-312.pyc CHANGED
Binary files a/__pycache__/LLM_package.cpython-312.pyc and b/__pycache__/LLM_package.cpython-312.pyc differ
 
__pycache__/search.cpython-312.pyc ADDED
Binary file (11.5 kB). View file
 
app.py CHANGED
@@ -244,6 +244,7 @@ def llm_to_process_image_simple(risk_level, image_path, point1, point2, threshol
244
  image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
245
  mask_llm = np.zeros(image.shape[:2], dtype=np.uint8)
246
  llm_results = Objectdetector.detect_objects(image_path)
 
247
  for result in llm_results:
248
  bbox=result['box_2d']
249
  x1, y1 = int(bbox[1]* image.shape[1]), int(bbox[0]* image.shape[0])
@@ -270,13 +271,15 @@ def llm_to_process_image_simple_auto(risk_level, image_path, point1, point2, thr
270
  Objectdetector = ObjectDetector(API_KEY=GEMINI_API_KEY)
271
  debug_image_path='/test_llm.jpg'
272
  response=Objectdetector.detect_auto(image_path)
 
273
  Objectdetector.prompt_objects=response["objects_to_remove"]
274
  # 画像の読み込みとRGB変換
275
-
276
  image = cv2.imread(image_path)
277
  image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
278
  mask_llm = np.zeros(image.shape[:2], dtype=np.uint8)
279
  llm_results = Objectdetector.detect_objects(image_path)
 
280
  for result in llm_results:
281
  bbox=result['box_2d']
282
  x1, y1 = int(bbox[1]* image.shape[1]), int(bbox[0]* image.shape[0])
 
244
  image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
245
  mask_llm = np.zeros(image.shape[:2], dtype=np.uint8)
246
  llm_results = Objectdetector.detect_objects(image_path)
247
+ print(f"LLM Results: {llm_results}")
248
  for result in llm_results:
249
  bbox=result['box_2d']
250
  x1, y1 = int(bbox[1]* image.shape[1]), int(bbox[0]* image.shape[0])
 
271
  Objectdetector = ObjectDetector(API_KEY=GEMINI_API_KEY)
272
  debug_image_path='/test_llm.jpg'
273
  response=Objectdetector.detect_auto(image_path)
274
+ print(response)
275
  Objectdetector.prompt_objects=response["objects_to_remove"]
276
  # 画像の読み込みとRGB変換
277
+ print(f"Objectdetector.prompt_objects: {Objectdetector.prompt_objects}")
278
  image = cv2.imread(image_path)
279
  image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
280
  mask_llm = np.zeros(image.shape[:2], dtype=np.uint8)
281
  llm_results = Objectdetector.detect_objects(image_path)
282
+ print(f"llm_results: {llm_results}")
283
  for result in llm_results:
284
  bbox=result['box_2d']
285
  x1, y1 = int(bbox[1]* image.shape[1]), int(bbox[0]* image.shape[0])
search.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ from playwright.async_api import async_playwright, Page, Browser
3
+ from bs4 import BeautifulSoup
4
+ from bs4.element import Comment # BeautifulSoupのコメント削除用
5
+ from urllib.parse import urlparse, parse_qs
6
+ from typing import List, Dict, Optional
7
+
8
+ class WebScraper:
9
+ """
10
+ DuckDuckGoでの検索、URLからのコンテンツ取得、HTMLクリーンアップを行うクラス。
11
+ """
12
+ def __init__(self, headless: bool = True, default_timeout: int = 30000):
13
+ """
14
+ WebScraperのインスタンスを初期化します。
15
+
16
+ Args:
17
+ headless (bool): Playwrightをヘッドレスモードで実行するかどうか (デフォルト: True)。
18
+ default_timeout (int): ページのロードタイムアウト (ミリ秒、デフォルト: 30000 = 30秒)。
19
+ """
20
+ self.headless = headless
21
+ self.default_timeout = default_timeout
22
+ self._browser: Optional[Browser] = None # Browserインスタンスを保持するため
23
+
24
+ async def _launch_browser(self) -> Browser:
25
+ """ブラウザを起動し、インスタンス変数に格納します。"""
26
+ if not self._browser or not self._browser.is_connected():
27
+ self._browser = await async_playwright().chromium.launch(headless=self.headless)
28
+ return self._browser
29
+
30
+ async def _close_browser(self):
31
+ """ブラウザを閉じます。"""
32
+ if self._browser and self._browser.is_connected():
33
+ await self._browser.close()
34
+ self._browser = None
35
+
36
+ async def _get_new_page(self) -> Page:
37
+ """新しいページ(タブ)を作成します。"""
38
+ browser = await self._launch_browser()
39
+ page = await browser.new_page()
40
+ page.set_default_timeout(self.default_timeout)
41
+ return page
42
+
43
+ async def search_duckduckgo(self, query: str, num_results: int = 3) -> List[Dict[str, str]]:
44
+ """
45
+ DuckDuckGoで指定されたクエリを検索し、上位N件の検索結果(タイトルとURL)を返します。
46
+ """
47
+ results = []
48
+ page: Optional[Page] = None # 明示的に型ヒントを追加
49
+ try:
50
+ page = await self._get_new_page()
51
+ print(f"DuckDuckGoで '{query}' を検索中...")
52
+ await page.goto("https://duckduckgo.com/")
53
+
54
+ await page.fill("#search_form_input_homepage", query)
55
+ await page.press("#search_form_input_homepage", "Enter")
56
+
57
+ await page.wait_for_selector("#links .result__a", timeout=10000)
58
+
59
+ search_elements = await page.query_selector_all("#links .result")
60
+
61
+ for i, element in enumerate(search_elements):
62
+ if i >= num_results:
63
+ break
64
+
65
+ title_element = await element.query_selector(".result__a")
66
+ url_element = await element.query_selector(".result__url")
67
+
68
+ title = await title_element.text_content() if title_element else "タイトルなし"
69
+ url = await url_element.get_attribute("href") if url_element else "URLなし"
70
+
71
+ # DuckDuckGoのURLのデコードとクリーンアップ
72
+ if url and url != "URLなし":
73
+ parsed_url = urlparse(url)
74
+ if parsed_url.path == '/l/':
75
+ decoded_url = parse_qs(parsed_url.query).get('uddg', [''])[0]
76
+ url = decoded_url
77
+
78
+ results.append({"title": title.strip(), "url": url.strip()})
79
+ except Exception as e:
80
+ print(f"DuckDuckGo検索中にエラーが発生しました: {e}")
81
+ finally:
82
+ if page:
83
+ await page.close() # ページを閉じる
84
+
85
+ print(f"検索が完了しました。{len(results)} 件の結果が見つかりました。")
86
+ return results
87
+
88
+ async def _get_raw_html_content(self, url: str) -> Optional[str]:
89
+ """指定されたURLから生のHTMLコンテンツを取得します。"""
90
+ page: Optional[Page] = None
91
+ try:
92
+ page = await self._get_new_page()
93
+ print(f" URL: {url} のコンテンツを取得中...")
94
+ await page.goto(url)
95
+ return await page.content()
96
+ except Exception as e:
97
+ print(f" URL: {url} のコンテンツ取得中にエラーが発生しました: {e}")
98
+ return None
99
+ finally:
100
+ if page:
101
+ await page.close()
102
+
103
+ def _clean_html_to_text(self, html_content: str) -> str:
104
+ """
105
+ HTMLコンテンツからJavaScript、スタイル、不要なリンクなどを除去し、整形されたテキストを返します。
106
+ """
107
+ soup = BeautifulSoup(html_content, 'html.parser')
108
+
109
+ # スクリプトタグとスタイルタグを削除
110
+ for script_or_style in soup(["script", "style"]):
111
+ script_or_style.decompose()
112
+
113
+ # headタグ内のリンクタグ(CSSなど)を削除
114
+ if soup.head:
115
+ for link_tag in soup.head.find_all('link'):
116
+ link_tag.decompose()
117
+
118
+ # HTMLコメントを削除
119
+ for comment in soup.find_all(string=lambda text: isinstance(text, Comment)):
120
+ comment.extract()
121
+
122
+ # 複数の連続する改行を1つに減らす
123
+ cleaned_text = soup.get_text(separator='\n', strip=True)
124
+ cleaned_text_lines = [line.strip() for line in cleaned_text.splitlines() if line.strip()]
125
+ return '\n'.join(cleaned_text_lines)
126
+
127
+ async def get_processed_documents(self, search_query: str, num_search_results: int = 2) -> List[Dict[str, str]]:
128
+ """
129
+ DuckDuckGoで検索し、上位N件の検索結果のURLからクリーンなHTMLコンテンツを取得します。
130
+
131
+ Args:
132
+ search_query (str): 検索クエリ。
133
+ num_search_results (int): 取得する検索結果の数。
134
+
135
+ Returns:
136
+ List[Dict[str, str]]: 処理されたドキュメントのリスト。
137
+ 各ドキュメントは 'title', 'original_url', 'cleaned_html_content' を含む。
138
+ """
139
+ processed_documents = []
140
+
141
+ # Playwrightの非同期コンテキストマネージャでブラウザインスタンスを管理
142
+ async with async_playwright() as p:
143
+ # ブラウザを一度だけ起動し、インスタンス変数に保持
144
+ self._browser = await p.chromium.launch(headless=self.headless)
145
+
146
+ top_results = await self.search_duckduckgo(search_query, num_search_results)
147
+
148
+ if top_results:
149
+ for i, result in enumerate(top_results):
150
+ print(f"\n--- 処理中の記事 {i+1} ---")
151
+ print(f"タイトル: {result['title']}")
152
+ print(f"元URL: {result['url']}")
153
+
154
+ # 個別のURLのコンテンツを取得・クリーンアップ
155
+ raw_html = await self._get_raw_html_content(result['url'])
156
+
157
+ if raw_html:
158
+ cleaned_content = self._clean_html_to_text(raw_html)
159
+ processed_documents.append({
160
+ "title": result['title'],
161
+ "original_url": result['url'],
162
+ "cleaned_html_content": cleaned_content
163
+ })
164
+ print(f" クリーンなコンテンツの長さ: {len(cleaned_content)} 文字")
165
+ print(f" クリーンなコンテンツ(一部):\n{cleaned_content[:500]}...")
166
+ else:
167
+ print(" クリーンなコンテンツを取得できませんでした。")
168
+ else:
169
+ print("検索結果が見つからなかったため、処理をスキップします。")
170
+
171
+ await self._close_browser() # 全ての処理後にブラウザを閉じる
172
+
173
+ return processed_documents
174
+
175
+ # クラスの使用例
templates/index.html CHANGED
@@ -185,6 +185,8 @@
185
  <option value="simple_lama">Simple Lamaインペイント</option>
186
  <option value="stamp">stampインペイント</option>
187
  <option value="mosaic">mosaicインペイント</option>
 
 
188
  </select>
189
  </div>
190
  <div class="slider-container">
@@ -440,6 +442,22 @@
440
  apiEndpoint = "/create-mask-and-inpaint-stamp";
441
  } else if (processingType === "mosaic") {
442
  apiEndpoint = "/create-mask-and-inpaint-mosaic";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  }
444
  processImageRequest(formData, "https://rein0421-aidentify.hf.space" + apiEndpoint);
445
  }
 
185
  <option value="simple_lama">Simple Lamaインペイント</option>
186
  <option value="stamp">stampインペイント</option>
187
  <option value="mosaic">mosaicインペイント</option>
188
+ <option value="llm-auto">llm-autoインペイント</option>
189
+ <option value="llm">llmインペイント</option>
190
  </select>
191
  </div>
192
  <div class="slider-container">
 
442
  apiEndpoint = "/create-mask-and-inpaint-stamp";
443
  } else if (processingType === "mosaic") {
444
  apiEndpoint = "/create-mask-and-inpaint-mosaic";
445
+ } else if (processingType === "llm-auto") {
446
+ apiEndpoint = "/create-mask-and-inpaint-sum-llm-auto";
447
+ formData.append('x1', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
448
+ formData.append('y1', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
449
+ formData.append('x2', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
450
+ formData.append('y2', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
451
+ } else if (processingType === "llm") {
452
+ apiEndpoint = "/create-mask-and-inpaint-sum-llm-auto";
453
+ formData.append('x1', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
454
+ formData.append('y1', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
455
+ formData.append('x2', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
456
+ formData.append('y2', 0.001); // FastAPIで使うデフォルト値と同じ値を設定
457
+ } else {
458
+ alert("無効な処理方法が選択されました。");
459
+ hideLoadingSpinner();
460
+ return;
461
  }
462
  processImageRequest(formData, "https://rein0421-aidentify.hf.space" + apiEndpoint);
463
  }
test.py CHANGED
@@ -4,36 +4,24 @@ from dotenv import load_dotenv
4
  import numpy as np
5
  import cv2
6
  from PIL import Image
 
7
  load_dotenv(dotenv_path='../.env')
8
- def llm_to_process_image(risk_level, image_path, point1, point2, thresholds=None):
9
- print(risk_level, image_path, point1, point2, thresholds)
10
- print('point1,point2', point1, point2)
11
- GEMINI_API_KEY=os.getenv('GEMINI_API_KEY')
12
- # 画像処理のロジックをここに追加
13
- Objectdetector = ObjectDetector(API_KEY=GEMINI_API_KEY)
14
- debug_image_path='/test_llm.jpg'
15
- Objectdetector.prompt_objects={'face', 'poster', 'Name tag', 'License plate', 'Digital screens',
16
- 'signboard', 'sign', 'logo', 'manhole', 'electricity pole', 'cardboard'}
17
- # 画像の読み込みとRGB変換
18
 
19
- image = cv2.imread(image_path)
20
- image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
21
- mask_llm = np.zeros(image.shape[:2], dtype=np.uint8)
22
- llm_results = Objectdetector.detect_objects(image_path)
23
- for result in llm_results:
24
- bbox=result['box_2d']
25
- x1, y1 = int(bbox[1]* image.shape[1]), int(bbox[0]* image.shape[0])
26
- x2, y2 = int(bbox[3]* image.shape[1]), int(bbox[2]* image.shape[0])
27
- mask_llm[y1:y2, x1:x2] = 255 # テキスト領域をマスク
28
- p1_x, p1_y = int(point1[0] * image.shape[1]), int(point1[1] * image.shape[0])
29
- p2_x, p2_y = int(point2[0] * image.shape[1]), int(point2[1] * image.shape[0])
30
- x_min, y_min = max(0, min(p1_x, p2_x)), max(0, min(p1_y, p2_y))
31
- x_max, y_max = min(image.shape[1], max(p1_x, p2_x)), min(image.shape[0], max(p1_y, p2_y))
32
- mask_llm[y_min:y_max, x_min:x_max] = 0 # 範囲を黒に設定
33
- save_dir = "./saved_images"
34
- os.makedirs(save_dir, exist_ok=True)
35
- debug_image_pil = Image.fromarray(mask_llm)
36
- debug_image_pil.save(save_dir + debug_image_path)
37
-
38
- llm_to_process_image(50, "../../16508.jpg", (0, 0), (0, 0), thresholds=None)
39
 
 
 
 
 
 
 
 
 
 
 
 
4
  import numpy as np
5
  import cv2
6
  from PIL import Image
7
+ from search import WebScraper
8
  load_dotenv(dotenv_path='../.env')
9
+ async def main():
10
+ scraper = WebScraper(headless=True) # UIなしで実行
 
 
 
 
 
 
 
 
11
 
12
+ # 個人情報流出に関する事例を検索し、上位2件のクリーンなコンテンツを取得
13
+ personal_breach_docs = await scraper.get_processed_documents(
14
+ search_query="個人情報流出 事例",
15
+ num_search_results=2
16
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ if personal_breach_docs:
19
+ print("\n--- 全ての処理済みドキュメントの概要 ---")
20
+ for doc in personal_breach_docs:
21
+ print(f"タイトル: {doc['title']}")
22
+ print(f"URL: {doc['original_url']}")
23
+ print(f"コンテンツサイズ: {len(doc['cleaned_html_content'])} 文字")
24
+ print("-" * 30)
25
+ else:
26
+ print("処理されたドキュメントはありませんでした。")
27
+ main()