rayochoajr commited on
Commit
2639964
Β·
verified Β·
1 Parent(s): f72e1d7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +887 -50
app.py CHANGED
@@ -1,78 +1,915 @@
1
- import gradio as gr
2
- import os
3
- import shutil
4
- import hashlib
5
- import subprocess
6
- import pandas as pd
7
  from PIL import Image
8
  from datetime import datetime
9
- import io
10
  import base64
11
  import requests
 
12
  import json
13
  import logging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- # Hardcoded Values
16
- API_KEY = "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"
17
- IMAGE_FOLDER = "./Images"
18
- THUMBS_UP_FOLDER = os.path.join(IMAGE_FOLDER, "Thumbs_Up")
19
- THUMBS_DOWN_FOLDER = os.path.join(IMAGE_FOLDER, "Thumbs_Down")
20
- BACKUP_FOLDER = "Backup_Scripts"
21
- ALLOWED_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']
22
- LOGGING_LEVEL = logging.INFO
23
- API_URL = "https://api.openai.com/v1/chat/completions"
24
 
25
- # Setup logging
26
- logging.basicConfig(level=LOGGING_LEVEL)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- # Ensure necessary directories exist
29
- os.makedirs(IMAGE_FOLDER, exist_ok=True)
30
- os.makedirs(THUMBS_UP_FOLDER, exist_ok=True)
31
- os.makedirs(THUMBS_DOWN_FOLDER, exist_ok=True)
32
- os.makedirs(BACKUP_FOLDER, exist_ok=True)
33
 
34
- def load_gallery(folder):
35
- return sorted([os.path.join(folder, f) for f in os.listdir(folder) if os.path.splitext(f)[1].lower() in ALLOWED_EXTENSIONS], key=lambda x: os.path.basename(x).lower())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  def get_image_description(image, custom_prompt):
 
 
 
 
 
 
 
 
 
38
  if not custom_prompt.strip():
39
  custom_prompt = "Describe this image"
40
- headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
41
- payload = json.dumps({
42
  "model": "gpt-4-vision-preview",
43
- "messages": [{
44
- "role": "user",
45
- "content": [{"type": "text", "text": custom_prompt},
46
- {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encode_image(image)}"}}
47
- ]
48
- }],
 
 
 
49
  "max_tokens": 300
50
- })
51
- response = requests.post(API_URL, headers=headers, data=payload)
52
- return json.loads(response.text).get('choices', [])[0].get('message', {}).get('content', '')
 
 
 
 
53
 
54
- def encode_image(image):
55
- with io.BytesIO() as image_bytes:
56
- image.convert('RGB').save(image_bytes, format='JPEG')
57
- return base64.b64encode(image_bytes.getvalue()).decode('utf-8')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
- def save_image_description(image_path, description):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  text_file_path = f"{os.path.splitext(image_path)[0]}.txt"
61
- with open(text_file_path, 'w') as file:
62
- file.write(description)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
  with gr.Blocks() as app:
65
  with gr.Row():
66
  upload_btn = gr.File(label="Upload Images", type="binary", file_count='multiple')
67
  gallery = gr.Gallery(label="Uploaded Images Gallery")
68
- upload_btn.change(fn=lambda files: [save_image_description(file.name, get_image_description(Image.open(io.BytesIO(file)), "")) for file in files if file.name.lower().endswith(tuple(ALLOWED_EXTENSIONS))], inputs=upload_btn, outputs=gallery)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
- with gr.Accordion("Training Data"):
71
- details_df = gr.Dataframe()
72
- thumbs_up_gallery = gr.Gallery(value=load_gallery(THUMBS_UP_FOLDER), label="Thumbs Up Gallery")
73
- thumbs_down_gallery = gr.Gallery(value=load_gallery(THUMBS_DOWN_FOLDER), label="Thumbs Down Gallery")
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  refresh_btn = gr.Button("Refresh")
76
- refresh_btn.click(lambda: details_df.update(load_gallery(IMAGE_FOLDER)), inputs=[], outputs=[details_df, thumbs_up_gallery, thumbs_down_gallery])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- app.launch()
 
1
+ project_index = 0 # Initialize project_index with a default value
2
+
3
+ import gradio as gr,os,shutil,numpy as np,hashlib,subprocess,pandas as pd
 
 
 
4
  from PIL import Image
5
  from datetime import datetime
 
6
  import base64
7
  import requests
8
+ import io
9
  import json
10
  import logging
11
+ import re
12
+
13
+ """
14
+ Gradio App Interface Specification:
15
+ Inputs:
16
+ - prompt: Text Input. Description: 'Enter a prompt for image generation.'
17
+ - steps: Slider. Range: [1, 32]. value: 16. Description: 'Number of steps for image generation.'
18
+ - model: Dropdown. Options: ['TurboAnime.saftensors', 'OtherModel']. value: 'TurboAnime.saftensors'. Description: 'Select the model for image generation.'
19
+ - styles: CheckboxGroup. Options: ['RayORender', 'OtherStyle']. value: ['RayORender']. Description: 'Select styles for image generation.'
20
+
21
+ Outputs:
22
+ - image: Image. Description: 'Generated image based on the prompt.'
23
+ - log: Text. Description: 'Log of the image generation process.'
24
+ """
25
+
26
+ import gradio as gr
27
+ import subprocess
28
+ import json
29
+ import base64
30
+ from PIL import Image
31
+ import io
32
+ import time
33
+
34
+ # πŸ•’ Start time for the entire script
35
+ start_time = time.time()
36
+ def analyze_all_images(custom_prompt):
37
+ global file_array
38
+ descriptions = []
39
+ for file_info in file_array:
40
+ file_path = find_file_by_hash(file_info["hash"])
41
+ if file_path:
42
+ with Image.open(file_path) as img:
43
+ description = get_image_description(img, custom_prompt)
44
+ save_text(file_info["hash"], description, "", "", True) # Save the description to the text file
45
+ descriptions.append(description)
46
+ return descriptions
47
+
48
+ def generate_status_message(index, total, file_name):
49
+ return f"Processing {index + 1}/{total}: {file_name}"
50
+
51
+ def analyze_thumbs_up_images(custom_prompt):
52
+ thumbs_up_images = load_thumbs_up_gallery() # Assuming this function returns full paths
53
+ total_images = len(thumbs_up_images)
54
+ descriptions = []
55
+ status_messages = []
56
+ for index, image_path in enumerate(thumbs_up_images):
57
+ with Image.open(image_path) as img:
58
+ description = get_image_description(img, custom_prompt)
59
+ descriptions.append((os.path.basename(image_path), description))
60
+ status_messages.append(generate_status_message(index, total_images, os.path.basename(image_path)))
61
+ save_text(file_info["hash"], description, "", "", True) # Save the description to the text file
62
+ return descriptions, status_messages
63
+
64
+ # πŸ“’ Log Status
65
+ def log_status(progress, message):
66
+ elapsed_time = time.time() - start_time
67
+ log_message = {"status": message, "progress": f"{progress}%", "time_elapsed": f"{elapsed_time:.2f} seconds"}
68
+ return json.dumps(log_message)
69
+ def process_files(file_info):
70
+ try:
71
+ if file_info:
72
+ return [_process_file(file_path) for file_path in file_info] if isinstance(file_info, list) else [_process_file(file_info)]
73
+ return []
74
+ except Exception as e:
75
+ print(f"Error processing files: {e}")
76
+ raise e
77
+
78
+ def clear_uploads_folder():
79
+ os.makedirs(recycle_bin_folder, exist_ok=True)
80
+ for file_name in os.listdir(_get_project_folder()):
81
+ dest_file_path = os.path.join(recycle_bin_folder, file_name)
82
+ if os.path.exists(dest_file_path):
83
+ base, extension = os.path.splitext(file_name)
84
+ i = 1
85
+ new_file_name = f"{base}_{i}{extension}"
86
+ new_dest_file_path = os.path.join(recycle_bin_folder, new_file_name)
87
+ while os.path.exists(new_dest_file_path):
88
+ i += 1
89
+ new_file_name = f"{base}_{i}{extension}"
90
+ new_dest_file_path = os.path.join(recycle_bin_folder, new_file_name)
91
+ dest_file_path = new_dest_file_path
92
+ shutil.move(os.path.join(_get_project_folder(), file_name), dest_file_path)
93
+ return "Uploads folder cleared!"
94
+
95
+ def undo_last_deletion():
96
+ file_list = os.listdir(recycle_bin_folder)
97
+ if file_list:
98
+ last_deleted_file = file_list[-1]
99
+ shutil.move(os.path.join(recycle_bin_folder, last_deleted_file), _get_project_folder())
100
+ return f"Restored: {last_deleted_file}"
101
+ return "No files to restore"
102
+
103
+ def next_session():
104
+ global project_index
105
+ project_index += 1
106
+ _init_project_directory()
107
+ return f"Switched to the next session! Current session index: {project_index}"
108
+
109
+ def previous_session():
110
+ global project_index
111
+ if project_index > 0: project_index -= 1
112
+ return f"Switched to the previous session! Current session index: {project_index}"
113
+
114
+ def get_next_image():
115
+ global current_image
116
+ images = get_images()
117
+ if images:
118
+ current_image = images[0] if current_image is None else images[(images.index(current_image) + 1) % len(images)]
119
+ else:
120
+ current_image = default_image
121
+ return current_image
122
+
123
+ def get_previous_image():
124
+ global current_image
125
+ images = get_images()
126
+ if images:
127
+ current_image = images[-1] if current_image is None else images[(images.index(current_image) - 1) % len(images)]
128
+ else:
129
+ current_image = default_image
130
+ return current_image
131
+
132
+ def process_all_zips():
133
+ for file_name in os.listdir(_get_project_folder()):
134
+ file_path = os.path.join(_get_project_folder(), file_name)
135
+ if zipfile.is_zipfile(file_path): _process_file(file_path)
136
+ return "All zip files processed!"
137
+
138
+ # 🌐 API Call
139
+ def make_api_call(url, payload):
140
+ try:
141
+ response = subprocess.run(["curl", "-X", "POST", url, "-H", "Content-Type: application/json", "--data", json.dumps(payload)], capture_output=True, text=True)
142
+ if response.returncode == 0:
143
+ return json.loads(response.stdout), None
144
+ else:
145
+ return None, log_status(progress, f"API call failed with return code: {response.returncode}")
146
+ except Exception as e:
147
+ return None, log_status(progress, f"API call failed with exception: {str(e)}")
148
 
149
+ # πŸ–ΌοΈ Save Image
150
+ def save_image(image_data):
151
+ image = Image.open(io.BytesIO(base64.b64decode(image_data)))
152
+ return image
 
 
 
 
 
153
 
154
+ # πŸš€ Main Execution Function
155
+ def generate_image(prompt, steps, model, styles):
156
+ base_url = "http://73.255.78.150:7909"
157
+ base_payload = {
158
+ "prompt": prompt,
159
+ "steps": steps,
160
+ "model": model,
161
+ "styles": styles,
162
+ "negative_prompt": "album, duplicate, crowded, multiple, stuff, messy, photo, collage, doll, caricature, render. mannequin.",
163
+ "seed": -1,
164
+ "height": 768,
165
+ "width": 1280,
166
+ "sampler_index": "DPM++ 2M SDE Karras",
167
+ "restore_faces": False,
168
+ "tiling": False,
169
+ "n_iter": 1,
170
+ "batch_size": 1,
171
+ "cfg_scale": 2.0,
172
+ "subseed": -1,
173
+ "subseed_strength": 0.0,
174
+ "seed_resize_from_h": -1,
175
+ "seed_resize_from_w": -1,
176
+ "seed_enable_extras": False,
177
+ "enable_hr": False,
178
+ "denoising_strength": 0.0,
179
+ "hr_scale": 2.0,
180
+ "hr_upscaler": "Latent",
181
+ "hr_second_pass_steps": 0,
182
+ "hr_resize_x": 0,
183
+ "hr_resize_y": 0,
184
+ "hr_sampler_index": "",
185
+ "hr_prompt": "",
186
+ "hr_negative_prompt": "",
187
+ "override_settings_texts": ""
188
+
189
+ }
190
 
191
+ progress = 0
192
+ log = log_status(progress, "Starting image generation...")
 
 
 
193
 
194
+ response, error_log = make_api_call(f"{base_url}/sdapi/v1/txt2img", base_payload)
195
+ if error_log:
196
+ return None, error_log
197
+
198
+ if response and 'images' in response:
199
+ image_data = response['images'][0]
200
+ image = save_image(image_data)
201
+ log = log_status(100, "Image generated successfully.")
202
+ return image, log
203
+ else:
204
+ log = log_status(progress, "Failed to generate image.")
205
+ return None, log
206
+
207
+ max_image_size = 768
208
+ image_folder = "/Users/gev7418/Library/CloudStorage/OneDrive-Personal/Gradio Script Building Blocks/HatchDuo-Gradio/Images"
209
+ thumbs_up_folder = os.path.join(image_folder, "Thumbs_Up")
210
+ thumbs_down_folder = os.path.join(image_folder, "Thumbs_Down")
211
+ allowed_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']
212
+ folders_cycle = [image_folder, thumbs_up_folder, thumbs_down_folder]
213
+ # Set up logging to print to the terminal
214
+ logging.basicConfig(level=logging.INFO)
215
+
216
+ # OpenAI API Key
217
+ api_key = "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" # Replace with your OpenAI API Key
218
+ import subprocess
219
+
220
+ def convert_and_rename_files_in_directory(directory, original_extension, new_extension, new_base_name):
221
+ """
222
+ Converts all files in the specified directory from the original extension to PNG, and renames them to a new base name followed by a number.
223
+ """
224
+ files = [f for f in os.listdir(directory) if f.endswith(original_extension)]
225
+ for index, file in enumerate(sorted(files)):
226
+ new_name = f"{new_base_name}_{index}{new_extension}"
227
+ original_file_path = os.path.join(directory, file)
228
+ new_file_path = os.path.join(directory, new_name)
229
+ # Convert to PNG using a subprocess call to a command line tool like ImageMagick
230
+ subprocess.run(['convert', original_file_path, new_file_path])
231
+ os.rename(new_file_path, os.path.join(directory, new_name))
232
+ logging.info(f"All {original_extension} files in {directory} have been converted to PNG and renamed to {new_base_name} format.")
233
+
234
+
235
+ def encode_image(image):
236
+ """
237
+ This function converts the image to bytes and returns the base64 encoding of the image file
238
+ """
239
+ logging.info("Encoding image to base64")
240
+ image_bytes = io.BytesIO()
241
+ if image.mode == 'RGBA':
242
+ # Convert RGBA to RGB
243
+ image = image.convert('RGB')
244
+ image.save(image_bytes, format='JPEG')
245
+ image_bytes = image_bytes.getvalue()
246
+ base64_image = base64.b64encode(image_bytes).decode('utf-8')
247
+
248
+ return base64_image
249
 
250
  def get_image_description(image, custom_prompt):
251
+ """
252
+ This function sends the image to the OpenAI API and returns the response.
253
+ It now checks if there's custom prompt content before sending it to the API.
254
+ """
255
+ logging.info("Getting image description from OpenAI API")
256
+ base64_image = encode_image(image)
257
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
258
+
259
+ # Check if custom_prompt is not empty, otherwise use a default prompt
260
  if not custom_prompt.strip():
261
  custom_prompt = "Describe this image"
262
+
263
+ payload = {
264
  "model": "gpt-4-vision-preview",
265
+ "messages": [
266
+ {
267
+ "role": "user",
268
+ "content": [
269
+ {"type": "text", "text": custom_prompt},
270
+ {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
271
+ ]
272
+ }
273
+ ],
274
  "max_tokens": 300
275
+ }
276
+ response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
277
+ response_payload = json.loads(response.text)
278
+ content = response_payload['choices'][0]['message']['content']
279
+
280
+ logging.info("Received response from OpenAI API")
281
+ return content
282
 
283
+ def create_directories():
284
+ print("Creating directories...")
285
+ os.makedirs(thumbs_up_folder, exist_ok=True)
286
+ os.makedirs(thumbs_down_folder, exist_ok=True)
287
+
288
+ create_directories()
289
+
290
+ def get_files(folder):
291
+ print(f"Getting files from {folder}...")
292
+ return [os.path.join(dp, f) for dp, dn, filenames in os.walk(folder) for f in filenames if os.path.splitext(f)[1].lower() in allowed_extensions]
293
+
294
+ def hash_image_pixels(file_path):
295
+ """
296
+ Generates a hash for an image based on its pixel content.
297
+ """
298
+ if os.path.splitext(file_path)[1].lower() in allowed_extensions:
299
+ with Image.open(file_path) as img:
300
+ # Convert the image to RGBA (to standardize if images are in different modes)
301
+ img_rgba = img.convert('RGBA')
302
+ # Calculate the new height and width to maintain aspect ratio
303
+ aspect_ratio = img_rgba.width / img_rgba.height
304
+ new_height = min(max_image_size, img_rgba.height)
305
+ new_width = int(aspect_ratio * new_height)
306
+ if img_rgba.height > max_image_size:
307
+ new_height = max_image_size
308
+ new_width = int(new_height * aspect_ratio)
309
+ # Use Image.Resampling.LANCZOS for better quality resizing
310
+ img_resized = img_rgba.resize((new_width, new_height), Image.Resampling.LANCZOS)
311
+ # Get the bytes of the resized image data
312
+ img_bytes = io.BytesIO()
313
+ img_resized.save(img_bytes, format='PNG') # PNG format to ensure consistency across platforms
314
+ img_bytes = img_bytes.getvalue()
315
+ # Generate a hash of the resized image bytes
316
+ hash_obj = hashlib.sha256(img_bytes)
317
+ return hash_obj.hexdigest()
318
+ else:
319
+ return None
320
+
321
+ # Global cache for hashes to file paths
322
+ hash_to_path_cache = {}
323
+
324
+ def update_hash_to_path_cache():
325
+ global hash_to_path_cache
326
+ hash_to_path_cache.clear()
327
+ for folder in folders_cycle:
328
+ for file_path in get_files(folder):
329
+ file_hash = hash_image_pixels(file_path)
330
+ hash_to_path_cache[file_hash] = file_path
331
+
332
+ def find_file_by_hash(file_hash):
333
+ # Use the cache to find the file path
334
+ file_path = hash_to_path_cache.get(file_hash, None)
335
+ if file_path and os.path.exists(file_path):
336
+ return file_path
337
+ # If the file was not found or doesn't exist at the cached location,
338
+ # search in the thumbs up and thumbs down folders
339
+ for folder in [thumbs_up_folder, thumbs_down_folder]:
340
+ for dp, dn, filenames in os.walk(folder):
341
+ for f in filenames:
342
+ potential_path = os.path.join(dp, f)
343
+ if os.path.splitext(f)[1].lower() in allowed_extensions:
344
+ if hash_image_pixels(potential_path) == file_hash:
345
+ # Update the cache with the new location
346
+ hash_to_path_cache[file_hash] = potential_path
347
+ return potential_path
348
+ # If the file is not found in any of the locations, return None
349
+ return None
350
+
351
+ def build_file_array():
352
+ print("Building file array...")
353
+ files = []
354
+ for folder in folders_cycle:
355
+ for file_path in get_files(folder):
356
+ file_hash = hash_image_pixels(file_path)
357
+ status = "πŸ‘ Rated Up" if folder == thumbs_up_folder else "πŸ‘Ž Rated Down" if folder == thumbs_down_folder else "⏳ Pending"
358
+ files.append({"path": file_path, "hash": file_hash, "status": status, "date_modified": os.path.getmtime(file_path)})
359
+
360
+ # Create text files for any images missing their text file counterpart
361
+ text_file_path = file_path.replace(os.path.splitext(file_path)[1], '.txt')
362
+ if not os.path.exists(text_file_path):
363
+ with open(text_file_path, 'w') as text_file:
364
+ text_file.write("") # Create an empty text file
365
+
366
+ files = sorted(files, key=lambda x: x["date_modified"], reverse=True)
367
+ return files
368
+
369
+ def refresh_file_array_and_hashes():
370
+ global file_array, hash_list
371
+ file_array = build_file_array()
372
+ hash_list = [file['hash'] for file in file_array]
373
+ print("File array and hash list updated.")
374
+
375
+ update_hash_to_path_cache()
376
+ refresh_file_array_and_hashes()
377
+ current_index = 0
378
+ def save_text(file_hash, text, prepend_text="", append_text="", save_and_overwrite_changes=True):
379
+ if not save_and_overwrite_changes:
380
+ print("Skipping saving due to user preference.")
381
+ return
382
+ file_path = find_file_by_hash(file_hash)
383
+ if file_path:
384
+ text_file_path = file_path.replace(os.path.splitext(file_path)[1], '.txt')
385
+ final_text = ""
386
+ if not save_and_overwrite_changes and os.path.exists(text_file_path):
387
+ with open(text_file_path, 'r') as existing_file:
388
+ existing_content = existing_file.read()
389
+ final_text = (prepend_text + ", " if prepend_text else "") + existing_content + (", " + append_text if append_text else "")
390
+ else:
391
+ final_text = (prepend_text + ", " if prepend_text else "") + text + (", " + append_text if append_text else "")
392
+ print(f"Saving text for file hash {file_hash} to {text_file_path}...")
393
+ with open(text_file_path, 'w') as text_file:
394
+ text_file.write(final_text)
395
+
396
+ def get_text(file_hash):
397
+ file_path = find_file_by_hash(file_hash)
398
+ if file_path:
399
+ text_file_path = file_path.replace(os.path.splitext(file_path)[1], '.txt')
400
+ if os.path.exists(text_file_path):
401
+ print(f"Getting text for file hash {file_hash} from {text_file_path}...")
402
+ with open(text_file_path) as text_file:
403
+ return text_file.read()
404
+ return ""
405
+
406
+ def update_index_for_navigation(current_text, prepend_text, append_text, navigate_forward=True, save_and_overwrite_changes=False):
407
+ global current_index, file_array, hash_list
408
+ if current_text or not save_and_overwrite_changes: # Save only if there's something to save or if saving changes is not required
409
+ file_hash = hash_list[current_index]
410
+ save_text(file_hash, current_text, prepend_text, append_text, save_and_overwrite_changes)
411
+ if navigate_forward:
412
+ current_index = (current_index + 1) % len(hash_list) # Cycle to the first item if at the end
413
+ else:
414
+ current_index = (current_index - 1) % len(hash_list) # Cycle to the last item if at the beginning
415
+ def get_file(navigate_forward, current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt):
416
+ global current_index, file_array, hash_list
417
+ print(f"Getting file, navigate_forward: {navigate_forward}...")
418
+ update_index_for_navigation(current_text, prepend_text, append_text, navigate_forward, save_and_overwrite_changes)
419
+ if current_index < len(hash_list):
420
+ current_hash = hash_list[current_index]
421
+ file_info = next((item for item in file_array if item["hash"] == current_hash), None)
422
+ if file_info:
423
+ file_path = find_file_by_hash(current_hash)
424
+ if file_path:
425
+ with Image.open(file_path) as img:
426
+ # Calculate the new height and width to maintain aspect ratio, with a max height of 768 for display in gradio
427
+ aspect_ratio = img.width / img.height
428
+ new_height = min(768, img.height) # Set max height to 768 for gradio display
429
+ new_width = int(aspect_ratio * new_height)
430
+ # Use Image.Resampling.LANCZOS for better quality resizing
431
+ img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
432
+ img_resized_bytes = io.BytesIO()
433
+ img_resized.save(img_resized_bytes, format='PNG')
434
+ img_resized_bytes = img_resized_bytes.getvalue()
435
+ text = get_text(current_hash) # Load text file contents into textbox
436
+ if not pause_api_call:
437
+ text = get_image_description(img, custom_prompt) # Get new description from OpenAI
438
+ save_text(current_hash, text, prepend_text, append_text, save_and_overwrite_changes) # Optionally save the new description
439
+ # Convert the resized image to a numpy array for display
440
+ img_resized_np = np.array(Image.open(io.BytesIO(img_resized_bytes)))
441
+ return img_resized_np, current_hash, file_info["status"], text, os.path.basename(file_path), file_path, os.path.relpath(file_path, start=image_folder), os.path.basename(file_path).replace(os.path.splitext(os.path.basename(file_path))[1], '.txt'), find_file_by_hash(current_hash).replace(os.path.splitext(find_file_by_hash(current_hash))[1], '.txt'), os.path.relpath(find_file_by_hash(current_hash).replace(os.path.splitext(find_file_by_hash(current_hash))[1], '.txt'), start=image_folder)
442
+ return None, "File not found", "⏳ Pending", "", "", "", "", "", "", ""
443
+ def move_file(direction, current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt):
444
+ global current_index, file_array, hash_list
445
+ print(f"Moving file in direction {direction}...")
446
+ if current_index < len(hash_list):
447
+ current_hash = hash_list[current_index]
448
+ file_info = next((item for item in file_array if item["hash"] == current_hash), None)
449
+ if file_info:
450
+ source_file = find_file_by_hash(current_hash)
451
+ if source_file:
452
+ destination = thumbs_up_folder if direction == "up" else thumbs_down_folder if direction == "down" else None
453
+ new_status = "πŸ‘ Rated Up" if direction == "up" else "πŸ‘Ž Rated Down" if direction == "down" else None
454
+ if destination:
455
+ shutil.move(source_file, os.path.join(destination, os.path.basename(source_file)))
456
+ file_info["status"] = new_status
457
+ # Get new description and save it
458
+ with Image.open(source_file) as img:
459
+ description = get_image_description(img, custom_prompt)
460
+ save_text(current_hash, description, prepend_text, append_text, save_and_overwrite_changes)
461
+ return get_file(True, current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt)
462
+ return None, "Invalid direction or file not found", "⏳ Pending", "", "", "", "", "", "", ""
463
+
464
+ def reset_files(current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt):
465
+ global file_array, current_index, hash_list
466
+ print("Resetting files and clearing text...")
467
+ for file_info in file_array:
468
+ source_file = find_file_by_hash(file_info["hash"])
469
+ if source_file and os.path.exists(source_file):
470
+ source_text = source_file.replace(os.path.splitext(source_file)[1], '.txt')
471
+ if os.path.exists(source_text):
472
+ shutil.move(source_text, os.path.join(image_folder, os.path.basename(source_text)))
473
+ shutil.move(source_file, os.path.join(image_folder, os.path.basename(source_file)))
474
+ with open(os.path.join(image_folder, os.path.basename(source_text)), 'w') as text_file:
475
+ text_file.write("")
476
+ file_info["status"] = "⏳ Pending"
477
+ file_array = build_file_array()
478
+ hash_list = [file['hash'] for file in file_array]
479
+ update_hash_to_path_cache()
480
+ return get_file(True, current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt)
481
+
482
+ def delete_file(current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt):
483
+ global current_index, file_array, hash_list
484
+ print("Deleting file...")
485
+ if current_index < len(hash_list):
486
+ current_hash = hash_list[current_index]
487
+ source_file = find_file_by_hash(current_hash)
488
+ if source_file:
489
+ source_text = source_file.replace(os.path.splitext(source_file)[1], '.txt')
490
+ os.remove(source_file)
491
+ os.remove(source_text)
492
+ hash_list.remove(current_hash) # Remove the hash from the hash_list
493
+ file_array = [file for file in file_array if file["hash"] != current_hash] # Rebuild file_array without the deleted file
494
+ if current_index >= len(hash_list): current_index = len(hash_list) - 1
495
+ update_hash_to_path_cache()
496
+ return get_file(True, current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt)
497
+
498
+ def load_image_details():
499
+ print("Loading image details...")
500
+ image_details = []
501
+ for folder in folders_cycle:
502
+ for file_path in get_files(folder):
503
+ file_hash = hash_image_pixels(file_path)
504
+ status = "πŸ‘ Rated Up" if folder == thumbs_up_folder else "πŸ‘Ž Rated Down" if folder == thumbs_down_folder else "⏳ Pending"
505
+ text_file_path = file_path.replace(os.path.splitext(file_path)[1], '.txt')
506
+ text_content = ""
507
+ if os.path.exists(text_file_path):
508
+ with open(text_file_path, 'r') as text_file:
509
+ text_content = text_file.read()
510
+ image_details.append({
511
+ "Text Content": text_content,
512
+ "Rating Status": status,
513
+ "File Hash": file_hash,
514
+ "Image Path": file_path,
515
+ "Text Path": text_file_path if os.path.exists(text_file_path) else "N/A"
516
+ })
517
+ return pd.DataFrame(image_details)
518
+
519
+ def load_text_files_as_df():
520
+ print("Loading text files into dataframe...")
521
+ text_files = []
522
+ for file in os.listdir(image_folder):
523
+ if file.endswith('.txt'):
524
+ file_path = os.path.join(image_folder, file)
525
+ with open(file_path, 'r') as text_file:
526
+ text_content = text_file.read()
527
+ text_files.append({
528
+ "File Name": file.replace('.txt', ''),
529
+ "Content": text_content,
530
+ "Date Modified": datetime.fromtimestamp(os.path.getmtime(file_path)).strftime('%Y-%m-%d %H:%M:%S')
531
+ })
532
+ return pd.DataFrame(text_files)
533
+
534
+ # Function to merge text_files_df and image_details_df into a single dataframe
535
+ def load_combined_details():
536
+ print("Loading text file details...")
537
+ text_df = load_text_files_as_df()
538
+ image_details_df = load_image_details()
539
+ # Ensure the 'File Name' column exists in image_details_df by extracting it from 'Image Path'
540
+ image_details_df['File Name'] = image_details_df['Image Path'].apply(lambda x: os.path.basename(x).replace(os.path.splitext(os.path.basename(x))[1], ''))
541
+ combined_df = pd.merge(text_df, image_details_df, on="File Name", how="outer")
542
+ # Reorder dataframe fields according to specified order: Date Modified, Rating Status, File Name, Text Content, File Hash, Text Path, Image Path
543
+ combined_df = combined_df[['Date Modified', 'Rating Status', 'File Name', 'Text Content', 'File Hash', 'Text Path', 'Image Path']]
544
+ return combined_df
545
+
546
+ def load_gallery():
547
+ print("Loading gallery...")
548
+ return sorted([os.path.join(image_folder, f) for f in os.listdir(image_folder) if os.path.splitext(f)[1].lower() in allowed_extensions], key=lambda x: os.path.basename(x).lower())
549
+
550
+ def load_thumbs_up_gallery():
551
+ print("Loading Thumbs Up gallery...")
552
+ return sorted([os.path.join(thumbs_up_folder, f) for f in os.listdir(thumbs_up_folder) if os.path.splitext(f)[1].lower() in allowed_extensions], key=lambda x: os.path.basename(x).lower())
553
 
554
+ def load_thumbs_down_gallery():
555
+ print("Loading Thumbs Down gallery...")
556
+ return sorted([os.path.join(thumbs_down_folder, f) for f in os.listdir(thumbs_down_folder) if os.path.splitext(f)[1].lower() in allowed_extensions], key=lambda x: os.path.basename(x).lower())
557
+
558
+ def load_all_folders_gallery():
559
+ print("Loading all folders gallery...")
560
+ all_images = []
561
+ for folder in folders_cycle:
562
+ all_images.extend(sorted([os.path.join(folder, f) for f in os.listdir(folder) if os.path.splitext(f)[1].lower() in allowed_extensions], key=lambda x: os.path.basename(x).lower()))
563
+ return all_images
564
+
565
+ def load_text_files():
566
+ print("Loading text files...")
567
+ return sorted([[file, open(os.path.join(image_folder, file),'r').read()] for file in os.listdir(image_folder) if file.endswith('.txt')], key=lambda x: x[0].lower())
568
+
569
+ def update_text_content(df):
570
+ global text_files_df
571
+ print("Updating text content...")
572
+ for row in df:
573
+ if len(row) == 3:
574
+ file_name, new_content, date_added = row
575
+ file_path = os.path.join(image_folder, file_name)
576
+ if os.path.exists(file_path):
577
+ file_hash = hash_file(file_path)
578
+ save_text(file_hash, new_content)
579
+ else:
580
+ print("Error: Unexpected number of values in row. Expected 3 values per row.")
581
+
582
+ # Step 1: Define a function to update the dataframe
583
+ def refresh_text_files():
584
+ print("Refreshing text files...")
585
+ updated_text_files = sorted([[file, open(os.path.join(image_folder, file),'r').read()] for file in os.listdir(image_folder) if file.endswith('.txt')], key=lambda x: x[0].lower())
586
+ return updated_text_files
587
+ def save_uploaded_image(image_file):
588
+ """
589
+ Attempts to save the uploaded image to the designated image folder. Returns the path of the saved image or None if an error occurs.
590
+ """
591
+ try:
592
+ os.makedirs(image_folder, exist_ok=True) # Ensure the image folder exists
593
+ image_path = os.path.join(image_folder, image_file.name)
594
+ with open(image_path, "wb") as file:
595
+ file.write(image_file.content) # Write the byte content of the file
596
+ print(f"Image saved successfully: {image_path}")
597
+ return image_path
598
+ except Exception as e:
599
+ print(f"Error saving image: {e}")
600
+ return None
601
+
602
+ def create_text_file_for_image(image_path):
603
+ """
604
+ Generates an empty text file corresponding to an uploaded image, using the same base name.
605
+ """
606
  text_file_path = f"{os.path.splitext(image_path)[0]}.txt"
607
+ open(text_file_path, 'w').close() # Efficiently create an empty text file
608
+ return text_file_path
609
+
610
+ def handle_image_upload(uploaded_files):
611
+ status_messages = []
612
+ for uploaded_file in uploaded_files:
613
+ file_extension = os.path.splitext(uploaded_file.name)[1].lower()
614
+ if file_extension in allowed_extensions:
615
+ # Ensure the image folder exists
616
+ os.makedirs(image_folder, exist_ok=True)
617
+ # Save the file with a unique name based on its hash
618
+ unique_name = hashlib.sha256(uploaded_file.name.encode()).hexdigest() + file_extension
619
+ save_path = os.path.join(image_folder, unique_name)
620
+ with open(save_path, "wb") as file:
621
+ file.write(uploaded_file.content)
622
+ # Optionally, create a corresponding text file
623
+ text_file_path = save_path + ".txt"
624
+ with open(text_file_path, "w") as text_file:
625
+ text_file.write(f"Image file: {unique_name} uploaded successfully.")
626
+ status_messages.append(f"Uploaded and saved {uploaded_file.name} successfully.")
627
+ else:
628
+ status_messages.append(f"File {uploaded_file.name} has an unsupported extension ({file_extension}) and was not uploaded.")
629
+ return "\n".join(status_messages)
630
+
631
+ def refresh_image_description(current_text, prepend_text, append_text, pause_api_call, save_and_overwrite_changes, custom_prompt):
632
+ global current_index, file_array
633
+ if not pause_api_call:
634
+ file_info = file_array[current_index]
635
+ file_path = find_file_by_hash(file_info["hash"])
636
+ if file_path:
637
+ with Image.open(file_path) as img:
638
+ # Use the custom_prompt parameter when calling get_image_description
639
+ text = get_image_description(img, custom_prompt)
640
+ save_text(file_info["hash"], text, prepend_text, append_text, save_and_overwrite_changes)
641
+ return np.array(img), file_info["hash"], file_info["status"], text, os.path.basename(file_path), file_path, os.path.relpath(file_path, start=image_folder), os.path.basename(file_path).replace(os.path.splitext(os.path.basename(file_path))[1], '.txt'), find_file_by_hash(file_info["hash"]).replace(os.path.splitext(find_file_by_hash(file_info["hash"]))[1], '.txt'), os.path.relpath(find_file_by_hash(file_info["hash"]).replace(os.path.splitext(find_file_by_hash(file_info["hash"]))[1], '.txt'), start=image_folder)
642
+ # If API call is paused or file not found, return current state without changes
643
+ return None, file_info["hash"], file_info["status"], current_text, os.path.basename(file_path), file_path, os.path.relpath(file_path, start=image_folder), os.path.basename(file_path).replace(os.path.splitext(os.path.basename(file_path))[1], '.txt'), find_file_by_hash(file_info["hash"]).replace(os.path.splitext(find_file_by_hash(file_info["hash"]))[1], '.txt'), os.path.relpath(find_file_by_hash(file_info["hash"]).replace(os.path.splitext(find_file_by_hash(file_info["hash"]))[1], '.txt'), start=image_folder)
644
+ # Backup functionality for successful app launches
645
+ backup_folder = "Backup_Scripts"
646
+ os.makedirs(backup_folder, exist_ok=True)
647
+
648
+ def backup_script():
649
+ """
650
+ This function creates a backup of the current script in the designated backup folder.
651
+ """
652
+ current_script_path = os.path.realpath(__file__)
653
+ backup_script_path = os.path.join(backup_folder, f"backup_{os.path.basename(current_script_path)}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.py")
654
+ shutil.copy2(current_script_path, backup_script_path)
655
+ print(f"Backup of the script created at {backup_script_path}")
656
+
657
+ def app_launch_success():
658
+ """
659
+ This function is called when the app successfully launches.
660
+ It triggers the backup of the current script.
661
+ """
662
+ print("App successfully launched. Creating a backup of the script...")
663
+ backup_script()
664
+
665
+ def refresh_all():
666
+ combined_details = load_combined_details()
667
+ image_gallery_content = load_gallery()
668
+ thumbs_up_gallery_content = load_thumbs_up_gallery()
669
+ # Reinitialize the hash array and the index for new images
670
+ update_hash_to_path_cache()
671
+ refresh_file_array_and_hashes()
672
+ current_index = 0 # Reset the index to start from the first image
673
+ return combined_details, image_gallery_content, thumbs_up_gallery_content
674
+
675
+ def combined_action(prompt, steps, model, styles, custom_prompt):
676
+ # Trigger the OpenAI API for description and wait for the response
677
+ description, status = trigger_openai_api(custom_prompt)
678
+ if status == "success":
679
+ # Once the response is received, generate the image based on the prompt and other parameters
680
+ generated_image, log = generate_image(prompt, steps, model, styles)
681
+ else:
682
+ generated_image, log = None, "Failed to generate image due to API call failure."
683
+ return generated_image, log, description
684
+
685
+
686
+ # πŸ“‚ Setup Environment πŸ“‚
687
+ import gradio as gr
688
+ import os
689
+ from pathlib import Path
690
+ import subprocess
691
+
692
+ # Define the directory to store uploaded images
693
+ image_folder = "./Images"
694
+ os.makedirs(image_folder, exist_ok=True) # Create the directory if it doesn't exist
695
+
696
+ # πŸ”„ Function Definitions πŸ”„
697
+ def save_and_show_images(uploaded_files):
698
+ images_to_display = []
699
+ # Process each uploaded file
700
+ for index, uploaded_file in enumerate(uploaded_files):
701
+ # Define a base file name with index
702
+ base_file_name = f"Img-{index}"
703
+ # Check for existing files and increment index to avoid overwriting
704
+ existing_files = [f for f in Path(image_folder).rglob('*') if f.is_file() and f.suffix in ['.jpg', '.png', '.txt']]
705
+ while any(base_file_name in file.name for file in existing_files):
706
+ index += 1
707
+ base_file_name = f"Img-{index}"
708
+
709
+ # Determine the file extension (jpg or png)
710
+ file_extension = "jpg" if uploaded_file[:3] == b'\xff\xd8\xff' else "png"
711
+ final_file_name = f"{base_file_name}.{file_extension}"
712
+ image_path = os.path.join(image_folder, final_file_name)
713
+
714
+ # Write the bytes to a new file in the specified directory
715
+ with open(image_path, "wb") as file:
716
+ file.write(uploaded_file)
717
+
718
+ # Create a corresponding text file for the image
719
+ text_file_path = os.path.join(image_folder, f"{base_file_name}.txt")
720
+ with open(text_file_path, "w") as text_file:
721
+ text_file.write(f"Image file: {final_file_name}")
722
+
723
+ # Add the path (or ideally, a URL to the file) to the list to display
724
+ images_to_display.append(image_path)
725
+
726
+ # Ensure all images have a corresponding text file
727
+ for image_file_path in Path(image_folder).rglob('*'):
728
+ if image_file_path.suffix in ['.jpg', '.png']:
729
+ base_name = os.path.splitext(image_file_path.name)[0]
730
+ text_file_path = os.path.join(image_folder, f"{base_name}.txt")
731
+ if not os.path.exists(text_file_path):
732
+ with open(text_file_path, "w") as text_file:
733
+ text_file.write(f"Image file: {image_file_path.name}")
734
+
735
+ return images_to_display
736
+
737
+
738
 
739
  with gr.Blocks() as app:
740
  with gr.Row():
741
  upload_btn = gr.File(label="Upload Images", type="binary", file_count='multiple')
742
  gallery = gr.Gallery(label="Uploaded Images Gallery")
743
+ upload_btn.change(fn=save_and_show_images, inputs=upload_btn, outputs=gallery)
744
+ with gr.Row():
745
+ with gr.Column():
746
+ gr.Markdown("## Image Viewer")
747
+ with gr.Column():
748
+ # Add an upload button for uploading files to the images folder
749
+
750
+ image = gr.Image(height=768, label="Current Image", image_mode="RGBA", width="max", elem_id="current_image", type="numpy")
751
+ with gr.Row():
752
+ thumbs_down_btn = gr.Button("πŸ‘Ž Rate Down")
753
+ thumbs_up_btn = gr.Button("πŸ‘ Rate Up")
754
+ with gr.Row():
755
+ prev_btn = gr.Button("β¬… Previous")
756
+ next_btn = gr.Button("Next ➑")
757
+ with gr.Row():
758
+ status_display = gr.Textbox(label="Rating Status", interactive=False)
759
+ image_path_display = gr.Textbox(label="Image Path", interactive=False)
760
+
761
+
762
+
763
+ with gr.Column():
764
+ # Existing setup for checkboxes
765
+ with gr.Row():
766
+ pause_api_call_checkbox = gr.Checkbox(label="Pause OpenAI API Calls", value=True)
767
+ save_and_overwrite_changes_checkbox = gr.Checkbox(label="Save and Overwrite Changes", value=True)
768
+
769
+ # New textbox for custom OpenAI API instructions
770
+ custom_instructions = gr.Textbox(label="Custom Instructions", value="Use the art of deduction and creativity to generate a persona profile and 3 inspiration words to describe the image without describing the subject. Wrap it up with a concise 1 sentence caption of the image with the subject in high detail. JSON Format needed: Futuristic Persona Profile: The subject exudes a sense of readiness and authority, dressed in attire that hints at a future dominated by advanced technology and interstellar travel. This character could be envisioned as a commander or a pioneer in a futuristic saga, marked by their composed nature and the streamlined design of their gear. Futuristic Caption: A resolute figure of tomorrow, standing firm with a serene resolve, garbed in a sleek, technologically superior suit that narrates tales of distant realms and adventures. Poised Persona Profile: The individual appears as a beacon of confidence and tactical acumen. Their outfit suggests a world of progressive technology and potential space conquests. This persona might be a strategist or a guardian in a speculative fiction setting, distinguished by their steady presence and the modernistic cut of their uniform. Poised Caption: A visionary sentinel of the cosmos, poised with a calm yet assertive demeanor, dressed in an advanced, form-enhancing suit that hints at the mysteries of the universe yet to unfold. Advanced Persona Profile: The figure stands as a symbol of assurance and innovation, clad in a costume that forecasts an era of sophisticated technology and cosmic exploration. This character could represent an expert or a defender in a futuristic tale, highlighted by their tranquil posture and the elegant configuration of their attire. Advanced Caption: An unwavering pioneer of the future, the individual poses with a composed assurance, enveloped in a cutting-edge suit that speaks of advanced civilizations and uncharted frontiers.", placeholder="Enter custom instructions...", lines=2, max_lines=5)
771
+ with gr.Accordion("πŸ‘ Thumbs Up Gallery", open=False):
772
+ thumbs_up_gallery = gr.Gallery(label="Thumbs Up Image Gallery", value=load_thumbs_up_gallery(), every=5, columns=3, rows=1, object_fit="contain", height="auto")
773
 
 
 
 
 
774
 
775
+ with gr.Row():
776
+ text_display = prompt = gr.Textbox(label="Image Analysis", lines=3, max_lines=10, interactive=True, placeholder="API call paused. Manually enter description.")
777
+ output_image = gr.Image(type="pil", label="Visual Analysis Analog")
778
+
779
+ with gr.Row():
780
+ trigger_api_btn = gr.Button("Analyze Aesthetic!")
781
+ combined_btn = gr.Button("Analyze & Generate") # New combined action button
782
+ generate_btn = gr.Button("Generate")
783
+
784
+ analyze_all_btn = gr.Button("Analyze All Thumbs Up")
785
+ descriptions_display = gr.Dataframe()
786
+ status_display = gr.Textbox(label="Status", lines=10, interactive=False)
787
+ analyze_all_btn.click(analyze_thumbs_up_images, inputs=[custom_instructions], outputs=[descriptions_display, status_display])
788
+
789
+ with gr.Row():
790
+ analyze_everything_btn = gr.Button("Analyze All Images")
791
+
792
+ analyze_all_btn.click(analyze_all_images, inputs=[custom_instructions], outputs=[descriptions_display, status_display])
793
+ analyze_everything_btn.click(analyze_all_images, inputs=[custom_instructions], outputs=[descriptions_display, status_display])
794
+
795
+
796
+ with gr.Row():
797
+ gr.Image(type="pil")
798
+ gr.Image(type="pil")
799
+ gr.Image(type="pil")
800
+
801
+ with gr.Accordion("Append / Prepend", open=False):
802
+ with gr.Row():
803
+ prepend_text = gr.Textbox(label="Prepend", lines=2, max_lines=5, placeholder="Enter text to prepend...")
804
+ append_text = gr.Textbox(label="Append", lines=2, max_lines=5, placeholder="Enter text to append...")
805
+
806
+
807
+ def trigger_openai_api(custom_prompt):
808
+ global current_index, file_array
809
+ if current_index < len(file_array):
810
+ file_info = file_array[current_index]
811
+ file_path = find_file_by_hash(file_info["hash"])
812
+ if file_path:
813
+ with Image.open(file_path) as img:
814
+ # Use the custom_prompt parameter when calling get_image_description
815
+ text = get_image_description(img, custom_prompt)
816
+ save_text(file_info["hash"], text, "", "", True) # Assuming you want to save and overwrite changes by default
817
+ return text, "Triggered OpenAI API successfully."
818
+ return "", "Failed to trigger OpenAI API."
819
+ trigger_api_btn.click(trigger_openai_api, inputs=[custom_instructions], outputs=[text_display, status_display])
820
+
821
+
822
+ with gr.Row():
823
+ delete_btn = gr.Button("πŸ—‘οΈ Delete")
824
+ reset_btn = gr.Button("πŸ”„ Reset All Ratings πŸ‘πŸ‘Ž")
825
+
826
+ with gr.Accordion(label="Edit Project", open=False):
827
+ with gr.Column(scale=0):
828
+ file_input = gr.File(file_count="multiple", type="binary", label="Upload Images or Zip Files")
829
+ with gr.Row():
830
+ previous_session_button = gr.Button("πŸ‘ˆ Previous Project")
831
+ next_session_button = gr.Button("Next ProjectπŸ‘‰")
832
+ with gr.Row():
833
+ next_img = gr.Button("πŸ–ΌοΈ Show Next Image")
834
+ prev_img = gr.Button("πŸ–ΌοΈ Show Previous Image")
835
+ with gr.Row():
836
+ with gr.Row():
837
+ clear_button = gr.Button("πŸ—‘οΈ Clear Uploads Folder")
838
+ undo_button = gr.Button("↩️ Undo Last Deletion")
839
+ process_zip_button = gr.Button("πŸ“‚ Process Zip Files")
840
+ with gr.Column():
841
+ randomize_checkbox = gr.Checkbox(label="πŸ”€ Randomize Every 2 Seconds", value=True)
842
+ refresh_time_input = gr.Number(label="⏱️ Refresh Time", value=2)
843
+ index_display = gr.Textbox(value=str(project_index), label="πŸ”’ Session Index", every=5)
844
+ file_input.change(process_files, inputs=[file_input], outputs=[])
845
+ clear_button.click(clear_uploads_folder, inputs=[], outputs=[])
846
+ undo_button.click(undo_last_deletion, inputs=[], outputs=[])
847
+ next_session_button.click(next_session, inputs=[], outputs=[index_display])
848
+ previous_session_button.click(previous_session, inputs=[], outputs=[index_display])
849
+ next_img.click(get_next_image, inputs=[], outputs=[gallery])
850
+ prev_img.click(get_previous_image, inputs=[], outputs=[gallery])
851
+ process_zip_button.click(process_all_zips, inputs=[], outputs=[])
852
+
853
+ with gr.Accordion("Advanced Generation Settings", open=False):
854
+ with gr.Column():
855
+ steps = gr.Slider(minimum=1, maximum=32, value=16, label="Steps")
856
+ model = gr.Dropdown(choices=['TurboAnime.saftensors', 'OtherModel'], value='TurboAnime.saftensors', label="Model")
857
+ styles = gr.CheckboxGroup(choices=['RayORender', 'OtherStyle'], value=['RayORender'], label="Styles")
858
+ output_log = gr.Textbox(label="Log")
859
+ # Step 2: Add a button to trigger the update
860
+
861
+ generate_btn.click(fn=generate_image, inputs=[prompt, steps, model, styles], outputs=[output_image, output_log])
862
+
863
+ # Set the click action for the combined button
864
+ combined_btn.click(combined_action, inputs=[prompt, steps, model, styles, custom_instructions], outputs=[output_image, output_log, text_display])
865
+
866
+
867
+ with gr.Accordion("Training Data", open=True):
868
  refresh_btn = gr.Button("Refresh")
869
+ with gr.Row():
870
+ combined_details_df = gr.Dataframe(label="Combined Text and Image Details", value=load_combined_details(), headers=["Date Modified", "Rating Status", "File Name", "Text Content", "File Hash", "Text Path", "Image Path"], datatype=["str", "str", "str", "str", "str", "str", "str"], every=5)
871
+ gallery = gr.Gallery(label="Image Gallery", value=load_gallery(), every=5)
872
+ with gr.Accordion("File Info", open=False):
873
+ file_hash_display = gr.Textbox(label="File Hash", interactive=False)
874
+ text_path_display = gr.Textbox(label="Text Path", interactive=False)
875
+ def delete_all_text_files_content():
876
+ text_files = [os.path.join(image_folder, f) for f in os.listdir(image_folder) if f.endswith('.txt')]
877
+ for file_path in text_files:
878
+ with open(file_path, 'w') as f:
879
+ f.write('') # Clear the content of the text file
880
+ return "All text files' content deleted."
881
+ with gr.Row():
882
+ # Add a button to manually trigger a backup of the script
883
+ backup_btn = gr.Button("Backup Script")
884
+ backup_btn.click(backup_script, inputs=[], outputs=[])
885
+
886
+ delete_all_text_btn = gr.Button("Delete All Text Files Content")
887
+ delete_all_text_btn.click(delete_all_text_files_content, inputs=[], outputs=status_display)
888
+
889
+ # Modify the button click actions to include the pause_api_call_checkbox state and the save_and_overwrite_changes_checkbox state as arguments
890
+ reset_btn.click(lambda t, pt, at, p, s, ci: reset_files(t, pt, at, p, s, ci), inputs=[text_display, prepend_text, append_text, pause_api_call_checkbox, save_and_overwrite_changes_checkbox, custom_instructions], outputs=[image, file_hash_display, status_display, text_display, image_path_display, text_path_display])
891
+ prev_btn.click(lambda t, pt, at, p, s, ci: get_file(False, t, pt, at, p, s, ci), inputs=[text_display, prepend_text, append_text, pause_api_call_checkbox, save_and_overwrite_changes_checkbox, custom_instructions], outputs=[image, file_hash_display, status_display, text_display, image_path_display, text_path_display])
892
+ next_btn.click(lambda t, pt, at, p, s, ci: get_file(True, t, pt, at, p, s, ci), inputs=[text_display, prepend_text, append_text, pause_api_call_checkbox, save_and_overwrite_changes_checkbox, custom_instructions], outputs=[image, file_hash_display, status_display, text_display, image_path_display, text_path_display])
893
+ thumbs_up_btn.click(lambda t, pt, at, p, s, ci: move_file("up", t, pt, at, p, s, ci), inputs=[text_display, prepend_text, append_text, pause_api_call_checkbox, save_and_overwrite_changes_checkbox, custom_instructions], outputs=[image, file_hash_display, status_display, text_display, image_path_display, text_path_display])
894
+ thumbs_down_btn.click(lambda t, pt, at, p, s, ci: move_file("down", t, pt, at, p, s, ci), inputs=[text_display, prepend_text, append_text, pause_api_call_checkbox, save_and_overwrite_changes_checkbox, custom_instructions], outputs=[image, file_hash_display, status_display, text_display, image_path_display, text_path_display])
895
+ delete_btn.click(lambda t, pt, at, p, s, ci: delete_file(t, pt, at, p, s, ci), inputs=[text_display, prepend_text, append_text, pause_api_call_checkbox, save_and_overwrite_changes_checkbox, custom_instructions], outputs=[image, file_hash_display, status_display, text_display, image_path_display, text_path_display])
896
+
897
+ refresh_btn.click(refresh_all, inputs=[], outputs=[combined_details_df, gallery, thumbs_up_gallery])
898
+
899
+
900
+ # Check for successful app launch and backup the script
901
+ try:
902
+ app.launch(share=True, server_port=7866, server_name="0.0.0.0")
903
+ app_launch_success()
904
+ except Exception as e:
905
+ print(f"Error launching the app: {e}")
906
+
907
+
908
+
909
+
910
+
911
+ ======
912
+
913
+ refactor using programmer golf. keep all hardcoded values, inputs, outputs, and features. Optimize for UI / UX intuitiveness. move all hardcoded values to the top of the script without breaking anything. refactor and simplify with the goal of brininging ui ux principles to coding
914
 
915
+ Use ui as guide