Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -5,6 +5,7 @@ import random
|
|
5 |
from PIL import Image
|
6 |
import base64
|
7 |
import io
|
|
|
8 |
|
9 |
# Define categories at the top so they are accessible throughout the code
|
10 |
categories = [
|
@@ -124,35 +125,208 @@ class DataManager:
|
|
124 |
self.characters.append(character)
|
125 |
self.save_characters()
|
126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
def character_creation_app(data_manager):
|
128 |
with gr.Tab("Character Creation"):
|
129 |
with gr.Row():
|
130 |
name_input = gr.Textbox(label="Character Name")
|
131 |
traits_input = gr.Textbox(label="Traits/Appearance Tags (comma separated)")
|
132 |
-
image_input = gr.Image(label="Upload Character Image", type="
|
133 |
# New gender selection input
|
134 |
gender_input = gr.Radio(choices=["Boy", "Girl"], label="Gender")
|
135 |
save_button = gr.Button("Save Character")
|
136 |
output = gr.Textbox(label="Status", interactive=False)
|
137 |
|
138 |
-
def save_character(name, traits,
|
139 |
if not name or not traits or not gender:
|
140 |
return "Please enter all fields."
|
141 |
-
|
|
|
|
|
|
|
142 |
|
143 |
-
|
144 |
-
if image_path:
|
145 |
-
with open(image_path, "rb") as img_file:
|
146 |
-
image_data = base64.b64encode(img_file.read()).decode('utf-8')
|
147 |
-
character['image'] = f"data:image/png;base64,{image_data}"
|
148 |
-
else:
|
149 |
-
character['image'] = None
|
150 |
|
151 |
data_manager.add_character(character)
|
152 |
return f"Character '{name}' saved successfully."
|
153 |
|
154 |
save_button.click(save_character, inputs=[name_input, traits_input, image_input, gender_input], outputs=output)
|
155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
def prompt_generator_app(data_manager):
|
157 |
with gr.Tab("Prompt Generator"):
|
158 |
gr.Markdown("## Prompt Generator")
|
@@ -366,9 +540,10 @@ def tags_app(data_manager):
|
|
366 |
def main():
|
367 |
data_manager = DataManager(base_dir='/data')
|
368 |
with gr.Blocks() as demo:
|
369 |
-
|
370 |
-
|
371 |
-
|
|
|
372 |
|
373 |
demo.launch()
|
374 |
|
|
|
5 |
from PIL import Image
|
6 |
import base64
|
7 |
import io
|
8 |
+
from pathlib import Path
|
9 |
|
10 |
# Define categories at the top so they are accessible throughout the code
|
11 |
categories = [
|
|
|
125 |
self.characters.append(character)
|
126 |
self.save_characters()
|
127 |
|
128 |
+
def update_character(self, original_name, updated_character):
|
129 |
+
# Find the character by original_name
|
130 |
+
for idx, char in enumerate(self.characters):
|
131 |
+
if char['name'] == original_name:
|
132 |
+
# Handle image update
|
133 |
+
if updated_character['image']:
|
134 |
+
image_data = updated_character['image'] # base64 string
|
135 |
+
safe_name = "".join(c for c in updated_character['name'] if c.isalnum() or c in (' ', '_', '-')).rstrip()
|
136 |
+
image_filename = f"{safe_name}.png"
|
137 |
+
image_path = os.path.join(self.images_folder, image_filename)
|
138 |
+
|
139 |
+
# Decode and save the new image
|
140 |
+
image = Image.open(io.BytesIO(base64.b64decode(image_data.split(",")[1])))
|
141 |
+
image.save(image_path)
|
142 |
+
updated_character['image_path'] = image_path
|
143 |
+
else:
|
144 |
+
# If no new image provided, retain the old image_path
|
145 |
+
updated_character['image_path'] = char.get('image_path')
|
146 |
+
|
147 |
+
updated_character.pop('image', None)
|
148 |
+
|
149 |
+
# Process traits
|
150 |
+
if isinstance(updated_character['traits'], str):
|
151 |
+
updated_character['traits'] = updated_character['traits'].split(',')
|
152 |
+
updated_character['traits'] = [t.strip() for t in updated_character['traits']]
|
153 |
+
|
154 |
+
self.characters[idx] = updated_character
|
155 |
+
self.save_characters()
|
156 |
+
return True
|
157 |
+
return False
|
158 |
+
|
159 |
+
def delete_character(self, name):
|
160 |
+
# Find and remove the character
|
161 |
+
for idx, char in enumerate(self.characters):
|
162 |
+
if char['name'] == name:
|
163 |
+
image_path = char.get('image_path')
|
164 |
+
if image_path and os.path.exists(image_path):
|
165 |
+
os.remove(image_path)
|
166 |
+
del self.characters[idx]
|
167 |
+
self.save_characters()
|
168 |
+
return True
|
169 |
+
return False
|
170 |
+
|
171 |
def character_creation_app(data_manager):
|
172 |
with gr.Tab("Character Creation"):
|
173 |
with gr.Row():
|
174 |
name_input = gr.Textbox(label="Character Name")
|
175 |
traits_input = gr.Textbox(label="Traits/Appearance Tags (comma separated)")
|
176 |
+
image_input = gr.Image(label="Upload Character Image", type="base64")
|
177 |
# New gender selection input
|
178 |
gender_input = gr.Radio(choices=["Boy", "Girl"], label="Gender")
|
179 |
save_button = gr.Button("Save Character")
|
180 |
output = gr.Textbox(label="Status", interactive=False)
|
181 |
|
182 |
+
def save_character(name, traits, image_data, gender):
|
183 |
if not name or not traits or not gender:
|
184 |
return "Please enter all fields."
|
185 |
+
# Check for duplicate names
|
186 |
+
existing_names = [char['name'] for char in data_manager.get_characters()]
|
187 |
+
if name in existing_names:
|
188 |
+
return f"Character with name '{name}' already exists. Please choose a different name."
|
189 |
|
190 |
+
character = {'name': name, 'traits': traits, 'gender': gender, 'image': image_data}
|
|
|
|
|
|
|
|
|
|
|
|
|
191 |
|
192 |
data_manager.add_character(character)
|
193 |
return f"Character '{name}' saved successfully."
|
194 |
|
195 |
save_button.click(save_character, inputs=[name_input, traits_input, image_input, gender_input], outputs=output)
|
196 |
|
197 |
+
# Divider
|
198 |
+
gr.Markdown("---")
|
199 |
+
|
200 |
+
# Display Existing Characters
|
201 |
+
gr.Markdown("## Existing Characters")
|
202 |
+
|
203 |
+
# Container to hold the list of characters
|
204 |
+
characters_container = gr.Column()
|
205 |
+
|
206 |
+
def list_characters():
|
207 |
+
characters = data_manager.get_characters()
|
208 |
+
if not characters:
|
209 |
+
return "No characters created yet."
|
210 |
+
|
211 |
+
components = []
|
212 |
+
for char in characters:
|
213 |
+
with gr.AccordionItem(label=char['name']):
|
214 |
+
with gr.Row():
|
215 |
+
if char['image']:
|
216 |
+
image = Image.open(char['image'])
|
217 |
+
image_thumbnail = image.copy()
|
218 |
+
image_thumbnail.thumbnail((150, 150))
|
219 |
+
buffered = io.BytesIO()
|
220 |
+
image_thumbnail.save(buffered, format="PNG")
|
221 |
+
img_str = base64.b64encode(buffered.getvalue()).decode()
|
222 |
+
img_data = f"data:image/png;base64,{img_str}"
|
223 |
+
gr.Image(value=img_data, label="Character Image", width=150).render()
|
224 |
+
else:
|
225 |
+
gr.Markdown("**No Image Provided**").render()
|
226 |
+
with gr.Column():
|
227 |
+
gr.Markdown(f"**Name:** {char['name']}").render()
|
228 |
+
gr.Markdown(f"**Gender:** {char['gender']}").render()
|
229 |
+
gr.Markdown(f"**Traits:** {', '.join(char['traits'])}").render()
|
230 |
+
with gr.Row():
|
231 |
+
edit_btn = gr.Button("Edit", variant="primary")
|
232 |
+
delete_btn = gr.Button("Delete", variant="secondary")
|
233 |
+
edit_output = gr.Textbox(label="", interactive=False)
|
234 |
+
delete_output = gr.Textbox(label="", interactive=False)
|
235 |
+
|
236 |
+
# Define edit functionality
|
237 |
+
def initiate_edit(char_name):
|
238 |
+
return gr.update(visible=True), char_name
|
239 |
+
|
240 |
+
edit_interface = gr.Accordion(label=f"Edit {char['name']}", open=False, visible=False)
|
241 |
+
with edit_interface:
|
242 |
+
with gr.Row():
|
243 |
+
edit_name = gr.Textbox(label="Character Name", value=char['name'])
|
244 |
+
edit_traits = gr.Textbox(label="Traits/Appearance Tags (comma separated)", value=', '.join(char['traits']))
|
245 |
+
edit_image = gr.Image(label="Upload New Character Image", type="base64")
|
246 |
+
edit_gender = gr.Radio(choices=["Boy", "Girl"], label="Gender", value=char['gender'])
|
247 |
+
save_edit_btn = gr.Button("Save Changes")
|
248 |
+
save_edit_output = gr.Textbox(label="Edit Status", interactive=False)
|
249 |
+
|
250 |
+
def save_edit(original_name, new_name, new_traits, new_image, new_gender):
|
251 |
+
if not new_name or not new_traits or not new_gender:
|
252 |
+
return "Please enter all fields."
|
253 |
+
# If the name has changed, check for duplicates
|
254 |
+
if new_name != original_name:
|
255 |
+
existing_names = [c['name'] for c in data_manager.get_characters()]
|
256 |
+
if new_name in existing_names:
|
257 |
+
return f"Character with name '{new_name}' already exists. Please choose a different name."
|
258 |
+
updated_char = {
|
259 |
+
'name': new_name,
|
260 |
+
'traits': new_traits,
|
261 |
+
'gender': new_gender,
|
262 |
+
'image': new_image
|
263 |
+
}
|
264 |
+
success = data_manager.update_character(original_name, updated_char)
|
265 |
+
if success:
|
266 |
+
return f"Character '{new_name}' updated successfully."
|
267 |
+
else:
|
268 |
+
return "Failed to update character."
|
269 |
+
|
270 |
+
save_edit_btn.click(
|
271 |
+
save_edit,
|
272 |
+
inputs=[gr.State(char['name']), edit_name, edit_traits, edit_image, edit_gender],
|
273 |
+
outputs=save_edit_output
|
274 |
+
)
|
275 |
+
|
276 |
+
# Define delete functionality
|
277 |
+
def confirm_delete(char_name):
|
278 |
+
return f"Are you sure you want to delete '{char_name}'?"
|
279 |
+
|
280 |
+
def perform_delete(char_name):
|
281 |
+
success = data_manager.delete_character(char_name)
|
282 |
+
if success:
|
283 |
+
return f"Character '{char_name}' deleted successfully."
|
284 |
+
else:
|
285 |
+
return f"Failed to delete character '{char_name}'."
|
286 |
+
|
287 |
+
delete_btn.click(
|
288 |
+
lambda name: confirm_delete(name),
|
289 |
+
inputs=[char['name']],
|
290 |
+
outputs=delete_output
|
291 |
+
)
|
292 |
+
|
293 |
+
delete_confirm = gr.Button("Confirm Delete", visible=False)
|
294 |
+
delete_cancel = gr.Button("Cancel Delete", visible=False)
|
295 |
+
|
296 |
+
# Show confirmation buttons when delete is clicked
|
297 |
+
def show_delete_buttons(message):
|
298 |
+
if "Are you sure" in message:
|
299 |
+
return gr.update(visible=True), message
|
300 |
+
return gr.update(visible=False), message
|
301 |
+
|
302 |
+
delete_btn.click(
|
303 |
+
show_delete_buttons,
|
304 |
+
inputs=[delete_output],
|
305 |
+
outputs=[delete_confirm, delete_output]
|
306 |
+
)
|
307 |
+
|
308 |
+
# Handle delete confirmation
|
309 |
+
delete_confirm.click(
|
310 |
+
perform_delete,
|
311 |
+
inputs=[char['name']],
|
312 |
+
outputs=delete_output
|
313 |
+
)
|
314 |
+
|
315 |
+
delete_cancel.click(
|
316 |
+
lambda: "",
|
317 |
+
outputs=delete_output
|
318 |
+
)
|
319 |
+
|
320 |
+
components.append("") # Placeholder for spacing
|
321 |
+
|
322 |
+
return gr.Row(components)
|
323 |
+
|
324 |
+
characters_container.load(fn=list_characters, outputs=characters_container)
|
325 |
+
|
326 |
+
# Refresh Button to reload characters
|
327 |
+
refresh_button = gr.Button("Refresh Characters")
|
328 |
+
refresh_button.click(fn=list_characters, outputs=characters_container)
|
329 |
+
|
330 |
def prompt_generator_app(data_manager):
|
331 |
with gr.Tab("Prompt Generator"):
|
332 |
gr.Markdown("## Prompt Generator")
|
|
|
540 |
def main():
|
541 |
data_manager = DataManager(base_dir='/data')
|
542 |
with gr.Blocks() as demo:
|
543 |
+
with gr.Tabs():
|
544 |
+
prompt_generator_app(data_manager)
|
545 |
+
character_creation_app(data_manager)
|
546 |
+
tags_app(data_manager)
|
547 |
|
548 |
demo.launch()
|
549 |
|