OzoneAsai commited on
Commit
9d01b86
1 Parent(s): d6926f4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +219 -219
app.py CHANGED
@@ -1,219 +1,219 @@
1
- import os
2
- import re
3
- import streamlit as st
4
- import subprocess
5
- from zipfile import ZipFile
6
- from PIL import Image, ImageFilter, UnidentifiedImageError
7
- import pandas as pd
8
- import io
9
-
10
- # プレフィックスとParquetファイルのパス
11
- sth = "https___nhentai_net_g_" # 任意のプレフィックス
12
- parquet_file = "nsfw_classification_results.parquet" # Parquetファイルのパス
13
- log_file = "app_log.txt" # ログファイルのパス
14
-
15
- # ページ番号に基づいてファイル名をソートする関数
16
- def sort_files_by_page_number(file_list):
17
- def extract_page_number(filename):
18
- match = re.search(r'page_(\d+)\.(jpg|png)', filename)
19
- if match:
20
- return int(match.group(1))
21
- return 0
22
- return sorted(file_list, key=extract_page_number)
23
-
24
- # 画像フォルダを取得する関数(更新時間順にソート)
25
- def get_image_folders(base_folder='scraped_images'):
26
- if not os.path.exists(base_folder):
27
- os.makedirs(base_folder)
28
-
29
- folder_paths = [os.path.join(base_folder, f) for f in os.listdir(base_folder) if os.path.isdir(os.path.join(base_folder, f))]
30
-
31
- # フォルダの更新時間を取得し、タプルのリストを作成
32
- folder_info = []
33
- for folder_path in folder_paths:
34
- mtime = os.path.getmtime(folder_path)
35
- folder_name = os.path.basename(folder_path)
36
- # プレフィックスを取り除く
37
- if folder_name.startswith(sth):
38
- folder_name = folder_name.replace(sth, "")
39
- folder_info.append((folder_name, mtime, folder_path))
40
-
41
- # 更新時間でソート(新しい順)
42
- folder_info.sort(key=lambda x: x[1], reverse=True)
43
-
44
- # フォルダ名のリストを返す
45
- sorted_folders = [info[0] for info in folder_info]
46
-
47
- return sorted_folders
48
-
49
- # フォルダをZIP化する関数
50
- def create_zip_of_folder(folder_path, zip_name):
51
- with ZipFile(zip_name, 'w') as zipf:
52
- for root, dirs, files in os.walk(folder_path):
53
- for file in files:
54
- zipf.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), folder_path))
55
-
56
- # サブプロセスを実行し、ログをファイルから読み取る関数
57
- def run_subprocess(command):
58
- with open(log_file, 'a', encoding='shift_jis') as log_f:
59
- process = subprocess.Popen(
60
- command,
61
- stdout=log_f,
62
- stderr=log_f,
63
- text=True
64
- )
65
- process.wait()
66
- #
67
- # Parquetファイルをロードする関数
68
- def load_parquet_data(parquet_file):
69
- if os.path.exists(parquet_file):
70
- return pd.read_parquet(parquet_file)
71
- else:
72
- st.error(f"{parquet_file} が見つかりません。スクレイピング後にインデックスが作成される必要があります。")
73
- return None
74
-
75
- # Unsafe画像にブラーを適用する関数
76
- def apply_gaussian_blur_if_unsafe(image, label, show_unsafe):
77
- label = label.lower()
78
- if label == "unsafe" and not show_unsafe:
79
- blurred_image = image.filter(ImageFilter.GaussianBlur(18))
80
- img_byte_arr = io.BytesIO()
81
- blurred_image.save(img_byte_arr, format='PNG')
82
- img_byte_arr = img_byte_arr.getvalue()
83
- return img_byte_arr
84
- else:
85
- img_byte_arr = io.BytesIO()
86
- image.save(img_byte_arr, format='PNG')
87
- img_byte_arr = img_byte_arr.getvalue()
88
- return img_byte_arr
89
-
90
- # コールバック関数: フォルダを選択し、ビューを切り替える
91
- def open_folder(folder):
92
- st.session_state['selected_folder'] = folder
93
- st.session_state['current_view'] = 'Selected Folder'
94
-
95
- # StreamlitのUI
96
- st.title('画像ギャラリーとダウンロード')
97
-
98
- # show_unsafeのチェックボックスを作成し、その値をst.session_stateに保存
99
- if 'show_unsafe' not in st.session_state:
100
- st.session_state['show_unsafe'] = False
101
-
102
- st.session_state['show_unsafe'] = st.checkbox('Unsafe画像をブラーなしで表示', value=st.session_state['show_unsafe'])
103
-
104
- # Parquetファイルからデータをロード
105
- df = load_parquet_data(parquet_file)
106
-
107
- # URL入力
108
- url = st.text_input('スクレイピングするURLを入力してください', '')
109
-
110
- # ラジオボタンでビューを切り替える
111
- views = ["Gallery", "Logs", "Selected Folder"]
112
-
113
- # 初期ビュー設定
114
- if 'current_view' not in st.session_state:
115
- st.session_state['current_view'] = 'Gallery'
116
-
117
- # ラジオボタンを使用してビューを選択
118
- selected_view = st.radio("ビューを選択", views, index=views.index(st.session_state['current_view']))
119
-
120
- # ビューの更新
121
- if selected_view != st.session_state['current_view']:
122
- st.session_state['current_view'] = selected_view
123
-
124
- # "Gallery"ビュー
125
- if st.session_state['current_view'] == "Gallery":
126
- st.header("ギャラリー")
127
-
128
- if st.button('スクレイピングを開始'):
129
- if url:
130
- # ログファイルをクリア
131
- open(log_file, 'w').close()
132
- # スクレイピングとインデックス作成を順次実行
133
- run_subprocess(["python", "scrape_images_worker.py", url])
134
- run_subprocess(["python", "indexer.py"])
135
- st.success("スクレイピングとインデックス作成が完了しました。")
136
-
137
- # フォルダからギャラリーを表示
138
- folders = get_image_folders()
139
-
140
- if folders:
141
- col1, col2 = st.columns(2)
142
- if 'selected_folder' not in st.session_state:
143
- st.session_state['selected_folder'] = None
144
-
145
- for i, folder in enumerate(folders):
146
- if "http" in folder:
147
- folder_path = os.path.join('scraped_images', folder)
148
- else:
149
- folder_path = os.path.join('scraped_images', sth + folder)
150
- image_files = [f for f in os.listdir(folder_path) if f.endswith(('jpg', 'png'))]
151
- image_files = sort_files_by_page_number(image_files)
152
-
153
- if image_files:
154
- if i % 2 == 0:
155
- with col1:
156
- st.image(os.path.join(folder_path, image_files[0]), caption=f"{folder} - 1ページ目", use_column_width=True)
157
- st.button(f'{folder} を開く', key=f"open_{folder}_1", on_click=open_folder, args=(folder,))
158
- else:
159
- with col2:
160
- st.image(os.path.join(folder_path, image_files[0]), caption=f"{folder} - 1ページ目", use_column_width=True)
161
- st.button(f'{folder} を開く', key=f"open_{folder}_2", on_click=open_folder, args=(folder,))
162
- else:
163
- st.write('画像フォルダが見つかりません。')
164
-
165
- # "Logs"ビュー
166
- elif st.session_state['current_view'] == "Logs":
167
- st.header("ログ")
168
- if os.path.exists(log_file):
169
- with open(log_file, 'r', encoding='shift_jis') as f:
170
- log_text = f.read()
171
- st.text_area("ログ", value=log_text, height=400)
172
- else:
173
- st.write("ログがありません。スクレイピングを開始してください。")
174
-
175
- # "Selected Folder"ビュー
176
- elif st.session_state['current_view'] == "Selected Folder":
177
- st.header("選択されたフォルダ")
178
-
179
- if 'selected_folder' in st.session_state and st.session_state['selected_folder']:
180
- selected_folder = st.session_state['selected_folder']
181
-
182
- if "http" in selected_folder:
183
- folder_path = os.path.join('scraped_images', selected_folder)
184
- else:
185
- folder_path = os.path.join('scraped_images', sth + selected_folder)
186
-
187
- st.subheader(f"フォルダ: {selected_folder} の画像一覧")
188
-
189
- if df is not None:
190
- image_files = [f for f in os.listdir(folder_path) if f.endswith(('jpg', 'png'))]
191
- image_files = sort_files_by_page_number(image_files)
192
-
193
- if image_files:
194
- for image_file in image_files:
195
- image_path = os.path.join(folder_path, image_file)
196
- label_row = df[df['file_path'] == image_path]
197
-
198
- if not label_row.empty:
199
- label = label_row['label'].values[0]
200
- else:
201
- label = "Unknown"
202
-
203
- try:
204
- image = Image.open(image_path)
205
- img_byte_arr = apply_gaussian_blur_if_unsafe(image, label, st.session_state['show_unsafe'])
206
- st.image(img_byte_arr, caption=f"{image_file} - {label}", use_column_width=True)
207
- except UnidentifiedImageError:
208
- st.error(f"🚫 画像ファイルを識別できません: {image_file}")
209
- continue
210
- else:
211
- st.warning("選択されたフォルダに画像が存在しません。")
212
-
213
- zip_name = f'{selected_folder}.zip'
214
- if st.button('画像をダウンロード'):
215
- create_zip_of_folder(folder_path, zip_name)
216
- with open(zip_name, 'rb') as f:
217
- st.download_button('ダウンロード', f, file_name=zip_name)
218
- else:
219
- st.write('画像フォルダが選択されていません。Galleryビューでフォルダを選択してください。')
 
1
+ import os
2
+ import re
3
+ import streamlit as st
4
+ import subprocess
5
+ from zipfile import ZipFile
6
+ from PIL import Image, ImageFilter, UnidentifiedImageError
7
+ import pandas as pd
8
+ import io
9
+
10
+ # プレフィックスとParquetファイルのパス
11
+ sth = "https___nhentai_net_g_" # 任意のプレフィックス
12
+ parquet_file = "nsfw_classification_results.parquet" # Parquetファイルのパス
13
+ log_file = "app_log.txt" # ログファイルのパス
14
+
15
+ # ページ番号に基づいてファイル名をソートする関数
16
+ def sort_files_by_page_number(file_list):
17
+ def extract_page_number(filename):
18
+ match = re.search(r'page_(\d+)\.(jpg|png)', filename)
19
+ if match:
20
+ return int(match.group(1))
21
+ return 0
22
+ return sorted(file_list, key=extract_page_number)
23
+
24
+ # 画像フォルダを取得する関数(更新時間順にソート)
25
+ def get_image_folders(base_folder='scraped_images'):
26
+ if not os.path.exists(base_folder):
27
+ os.makedirs(base_folder)
28
+
29
+ folder_paths = [os.path.join(base_folder, f) for f in os.listdir(base_folder) if os.path.isdir(os.path.join(base_folder, f))]
30
+
31
+ # フォルダの更新時間を取得し、タプルのリストを作成
32
+ folder_info = []
33
+ for folder_path in folder_paths:
34
+ mtime = os.path.getmtime(folder_path)
35
+ folder_name = os.path.basename(folder_path)
36
+ # プレフィックスを取り除く
37
+ if folder_name.startswith(sth):
38
+ folder_name = folder_name.replace(sth, "")
39
+ folder_info.append((folder_name, mtime, folder_path))
40
+
41
+ # 更新時間でソート(新しい順)
42
+ folder_info.sort(key=lambda x: x[1], reverse=True)
43
+
44
+ # フォルダ名のリストを返す
45
+ sorted_folders = [info[0] for info in folder_info]
46
+
47
+ return sorted_folders
48
+
49
+ # フォルダをZIP化する関数
50
+ def create_zip_of_folder(folder_path, zip_name):
51
+ with ZipFile(zip_name, 'w') as zipf:
52
+ for root, dirs, files in os.walk(folder_path):
53
+ for file in files:
54
+ zipf.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), folder_path))
55
+
56
+ # サブプロセスを実行し、ログをファイルから読み取る関数
57
+ def run_subprocess(command):
58
+ process = subprocess.Popen(
59
+ command,
60
+ stdout=subprocess.PIPE,
61
+ stderr=subprocess.PIPE,
62
+ text=True
63
+ )
64
+ process.wait()
65
+
66
+ #
67
+ # Parquetファイルをロードする関数
68
+ def load_parquet_data(parquet_file):
69
+ if os.path.exists(parquet_file):
70
+ return pd.read_parquet(parquet_file)
71
+ else:
72
+ st.error(f"{parquet_file} が見つかりません。スクレイピング後にインデックスが作成される必要があります。")
73
+ return None
74
+
75
+ # Unsafe画像にブラーを適用する関数
76
+ def apply_gaussian_blur_if_unsafe(image, label, show_unsafe):
77
+ label = label.lower()
78
+ if label == "unsafe" and not show_unsafe:
79
+ blurred_image = image.filter(ImageFilter.GaussianBlur(18))
80
+ img_byte_arr = io.BytesIO()
81
+ blurred_image.save(img_byte_arr, format='PNG')
82
+ img_byte_arr = img_byte_arr.getvalue()
83
+ return img_byte_arr
84
+ else:
85
+ img_byte_arr = io.BytesIO()
86
+ image.save(img_byte_arr, format='PNG')
87
+ img_byte_arr = img_byte_arr.getvalue()
88
+ return img_byte_arr
89
+
90
+ # コールバック関数: フォルダを選択し、ビューを切り替える
91
+ def open_folder(folder):
92
+ st.session_state['selected_folder'] = folder
93
+ st.session_state['current_view'] = 'Selected Folder'
94
+
95
+ # StreamlitのUI
96
+ st.title('画像ギャラリーとダウンロード')
97
+
98
+ # show_unsafeのチェックボックスを作成し、その値をst.session_stateに保存
99
+ if 'show_unsafe' not in st.session_state:
100
+ st.session_state['show_unsafe'] = False
101
+
102
+ st.session_state['show_unsafe'] = st.checkbox('Unsafe画像をブラーなしで表示', value=st.session_state['show_unsafe'])
103
+
104
+ # Parquetファイルからデータをロード
105
+ df = load_parquet_data(parquet_file)
106
+
107
+ # URL入力
108
+ url = st.text_input('スクレイピングするURLを入力してください', '')
109
+
110
+ # ラジオボタンでビューを切り替える
111
+ views = ["Gallery", "Logs", "Selected Folder"]
112
+
113
+ # 初期ビュー設定
114
+ if 'current_view' not in st.session_state:
115
+ st.session_state['current_view'] = 'Gallery'
116
+
117
+ # ラジオボタンを使用してビューを選択
118
+ selected_view = st.radio("ビューを選択", views, index=views.index(st.session_state['current_view']))
119
+
120
+ # ビューの更新
121
+ if selected_view != st.session_state['current_view']:
122
+ st.session_state['current_view'] = selected_view
123
+
124
+ # "Gallery"ビュー
125
+ if st.session_state['current_view'] == "Gallery":
126
+ st.header("ギャラリー")
127
+
128
+ if st.button('スクレイピングを開始'):
129
+ if url:
130
+ # ログファイルをクリア
131
+ open(log_file, 'w').close()
132
+ # スクレイピングとインデックス作成を順次実行
133
+ run_subprocess(["python", "scrape_images_worker.py", url])
134
+ run_subprocess(["python", "indexer.py"])
135
+ st.success("スクレイピングとインデックス作成が完了しました。")
136
+
137
+ # フォルダからギャラリーを表示
138
+ folders = get_image_folders()
139
+
140
+ if folders:
141
+ col1, col2 = st.columns(2)
142
+ if 'selected_folder' not in st.session_state:
143
+ st.session_state['selected_folder'] = None
144
+
145
+ for i, folder in enumerate(folders):
146
+ if "http" in folder:
147
+ folder_path = os.path.join('scraped_images', folder)
148
+ else:
149
+ folder_path = os.path.join('scraped_images', sth + folder)
150
+ image_files = [f for f in os.listdir(folder_path) if f.endswith(('jpg', 'png'))]
151
+ image_files = sort_files_by_page_number(image_files)
152
+
153
+ if image_files:
154
+ if i % 2 == 0:
155
+ with col1:
156
+ st.image(os.path.join(folder_path, image_files[0]), caption=f"{folder} - 1ページ目", use_column_width=True)
157
+ st.button(f'{folder} を開く', key=f"open_{folder}_1", on_click=open_folder, args=(folder,))
158
+ else:
159
+ with col2:
160
+ st.image(os.path.join(folder_path, image_files[0]), caption=f"{folder} - 1ページ目", use_column_width=True)
161
+ st.button(f'{folder} を開く', key=f"open_{folder}_2", on_click=open_folder, args=(folder,))
162
+ else:
163
+ st.write('画像フォルダが見つかりません。')
164
+
165
+ # "Logs"ビュー
166
+ elif st.session_state['current_view'] == "Logs":
167
+ st.header("ログ")
168
+ if os.path.exists(log_file):
169
+ with open(log_file, 'r', encoding='shift_jis') as f:
170
+ log_text = f.read()
171
+ st.text_area("ログ", value=log_text, height=400)
172
+ else:
173
+ st.write("ログがありません。スクレイピングを開始してください。")
174
+
175
+ # "Selected Folder"ビュー
176
+ elif st.session_state['current_view'] == "Selected Folder":
177
+ st.header("選択されたフォルダ")
178
+
179
+ if 'selected_folder' in st.session_state and st.session_state['selected_folder']:
180
+ selected_folder = st.session_state['selected_folder']
181
+
182
+ if "http" in selected_folder:
183
+ folder_path = os.path.join('scraped_images', selected_folder)
184
+ else:
185
+ folder_path = os.path.join('scraped_images', sth + selected_folder)
186
+
187
+ st.subheader(f"フォルダ: {selected_folder} の画像一覧")
188
+
189
+ if df is not None:
190
+ image_files = [f for f in os.listdir(folder_path) if f.endswith(('jpg', 'png'))]
191
+ image_files = sort_files_by_page_number(image_files)
192
+
193
+ if image_files:
194
+ for image_file in image_files:
195
+ image_path = os.path.join(folder_path, image_file)
196
+ label_row = df[df['file_path'] == image_path]
197
+
198
+ if not label_row.empty:
199
+ label = label_row['label'].values[0]
200
+ else:
201
+ label = "Unknown"
202
+
203
+ try:
204
+ image = Image.open(image_path)
205
+ img_byte_arr = apply_gaussian_blur_if_unsafe(image, label, st.session_state['show_unsafe'])
206
+ st.image(img_byte_arr, caption=f"{image_file} - {label}", use_column_width=True)
207
+ except UnidentifiedImageError:
208
+ st.error(f"🚫 画像ファイルを識別できません: {image_file}")
209
+ continue
210
+ else:
211
+ st.warning("選択されたフォルダに画像が存在しません。")
212
+
213
+ zip_name = f'{selected_folder}.zip'
214
+ if st.button('画像をダウンロード'):
215
+ create_zip_of_folder(folder_path, zip_name)
216
+ with open(zip_name, 'rb') as f:
217
+ st.download_button('ダウンロード', f, file_name=zip_name)
218
+ else:
219
+ st.write('画像フォルダが選択されていません。Galleryビューでフォルダを選択してください。')