File size: 8,337 Bytes
9a16e58 653a30c d64a646 653a30c 4faf3cd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
import os
ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "")
"""
🐾 BATUTO_encicloPromt🐾
Gestor de prompts con interfaz Gradio para Hugging Face Spaces
- Clasificación automática: Personajes / Fotografía profesional
- Modo admin protegido por contraseña (ADMIN_PASSWORD en Secrets)
- Modo cliente: solo visual, copiar y descargar categorías
"""
import os
import json
from datetime import datetime
from io import StringIO
import tempfile
import gradio as gr
admin_pass = gr.Textbox(label="Contraseña", type="password")
DATA_FILE = "prompts.json"
# ---------------------------
# Núcleo de datos y lógica
# ---------------------------
class GestorPrompts:
def __init__(self):
self.personajes = {}
self.fotografia = {}
self.keywords_personajes = [
"character", "personaje", "humanoid", "guardian", "portrait", "retrato",
"warrior", "creature", "avatar", "hero", "villain", "body", "full body",
"pose", "anatomy", "armor", "criatura"
]
self.keywords_fotografia = [
"photography", "foto", "bokeh", "macro", "studio", "dslr",
"aperture", "shutter", "lens", "professional", "portrait photography",
"product", "still life", "food", "fashion", "editorial"
]
def cargar(self, ruta=DATA_FILE):
if os.path.exists(ruta):
with open(ruta, "r", encoding="utf-8") as f:
data = json.load(f)
self.personajes = data.get("personajes", {})
self.fotografia = data.get("fotografia", {})
return self
def guardar(self, ruta=DATA_FILE):
data = {"personajes": self.personajes, "fotografia": self.fotografia}
with open(ruta, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def clasificar(self, texto: str) -> str:
t = texto.lower()
if any(k in t for k in self.keywords_personajes):
return "personajes"
if any(k in t for k in self.keywords_fotografia):
return "fotografia"
return "fotografia"
def agregar(self, nombre: str, texto: str, tags=None):
categoria = self.clasificar(texto)
entrada = {
"texto": texto.strip(),
"fecha": datetime.now().isoformat(timespec="seconds"),
"tags": tags or []
}
if categoria == "personajes":
self.personajes[nombre] = entrada
else:
self.fotografia[nombre] = entrada
return categoria
def agregar_lista(self, lista_textos):
resultados = []
for i, texto in enumerate(lista_textos, start=1):
if not texto.strip():
continue
nombre = f"Prompt_{i}"
cat = self.agregar(nombre, texto)
resultados.append((nombre, cat))
return resultados
def obtener_categoria(self, categoria: str):
return self.personajes if categoria == "personajes" else self.fotografia
def eliminar(self, categoria: str, nombre: str) -> bool:
coleccion = self.obtener_categoria(categoria)
if nombre in coleccion:
del coleccion[nombre]
return True
return False
def actualizar(self, categoria: str, nombre: str, nuevo_texto: str = None, nuevos_tags=None) -> bool:
coleccion = self.obtener_categoria(categoria)
if nombre not in coleccion:
return False
if nuevo_texto is not None:
coleccion[nombre]["texto"] = nuevo_texto.strip()
if nuevos_tags is not None:
coleccion[nombre]["tags"] = nuevos_tags
return True
def buscar(self, query: str, categoria: str = "todas"):
q = query.strip().lower()
res = []
cats = ["personajes", "fotografia"] if categoria == "todas" else [categoria]
for c in cats:
col = self.personajes if c == "personajes" else self.fotografia
for nombre, data in col.items():
if q in nombre.lower() or q in data["texto"].lower() or any(q in t.lower() for t in data.get("tags", [])):
res.append((c, nombre, data["texto"]))
return res
def exportar_categoria_json_bytes(self, categoria: str) -> bytes:
data = self.obtener_categoria(categoria)
si = StringIO()
json.dump(data, si, ensure_ascii=False, indent=2)
return si.getvalue().encode("utf-8")
def concatenar_prompts_categoria(self, categoria: str) -> str:
data = self.obtener_categoria(categoria)
bloques = [f"# {nombre}\n{info['texto']}" for nombre, info in data.items()]
return "\n\n---\n\n".join(bloques)
# ---------------------------
# App Gradio
# ---------------------------
ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "")
store = GestorPrompts().cargar()
def es_admin(pass_ingresado):
return bool(ADMIN_PASSWORD) and pass_ingresado == ADMIN_PASSWORD
def do_login(pass_ingresado):
ok = es_admin(pass_ingresado)
msg = "✅ Acceso admin concedido." if ok else "❌ Contraseña incorrecta."
return ok, gr.update(visible=ok), gr.update(visible=ok), gr.update(value=msg), gr.update(value="")
def refrescar_listas():
def to_table(dic):
return [[nombre, data["texto"]] for nombre, data in dic.items()]
tabla_personajes = to_table(store.personajes)
tabla_foto = to_table(store.fotografia)
concat_personajes = store.concatenar_prompts_categoria("personajes")
concat_foto = store.concatenar_prompts_categoria("fotografia")
nombres_personajes = list(store.personajes.keys())
nombres_foto = list(store.fotografia.keys())
return (tabla_personajes, tabla_foto, concat_personajes, concat_foto,
gr.update(choices=nombres_personajes), gr.update(choices=nombres_foto))
def admin_agregar(nombre, texto, lista_masiva):
if (not nombre or not texto) and not lista_masiva.strip():
return "⚠️ Provee un prompt o una lista.", *refrescar_listas()
msg = []
if nombre and texto:
cat = store.agregar(nombre, texto)
msg.append(f"Agregado '{nombre}' en {cat}.")
if lista_masiva.strip():
textos = [t.strip() for t in lista_masiva.split("\n") if t.strip()]
res = store.agregar_lista(textos)
if res:
msg.append(f"Lista agregada ({len(res)} prompts).")
store.guardar()
return " | ".join(msg) if msg else "Sin cambios.", *refrescar_listas()
def admin_actualizar(categoria, nombre, nuevo_texto):
if not nombre:
return "⚠️ Selecciona un prompt.", *refrescar_listas()
ok = store.actualizar(categoria, nombre, nuevo_texto=nuevo_texto)
store.guardar()
msg = "✏️ Actualizado." if ok else "⚠️ No existe."
return msg, *refrescar_listas()
def admin_eliminar(categoria, nombre):
if not nombre:
return "⚠️ Selecciona un prompt.", *refrescar_listas()
ok = store.eliminar(categoria, nombre)
store.guardar()
msg = "🗑️ Eliminado." if ok else "⚠️ No existe."
return msg, *refrescar_listas()
def buscar(query, categoria):
resultados = store.buscar(query, categoria)
if not resultados:
return [["-", "-", "Sin resultados"]]
return [[c, n, t] for c, n, t in resultados]
def preparar_descarga(categoria):
data = store.exportar_categoria_json_bytes(categoria)
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=f"_{categoria}.json")
tmp.write(data)
tmp.flush()
return tmp.name
with gr.Blocks(theme="soft", fill_height=True) as demo:
gr.Markdown("# 🐾 BATUTO_encicloPromt🐾")
gr.Markdown("Explora, copia y descarga categorías. Solo el admin puede agregar o editar.")
admin_state = gr.State(False)
with gr.Row():
with gr.Column():
gr.Markdown("### 🔍 Búsqueda")
in_query = gr.Textbox(label="Buscar texto o tag")
sel_cat = gr.Dropdown(choices=["todas", "personajes", "fotografia"], value="todas", label="Categoría")
btn_buscar = gr.Button("Buscar")
tabla_busqueda = gr.Dataframe(headers=["Categoría", "Nombre", "Texto"], interactive=False, wrap=True)
btn_buscar.click(
fn=buscar,
inputs=[in_query, sel_cat],
outputs=[tabla_busqueda]
)
if __name__ == "__main__":
demo.launch() |