Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -24,7 +24,7 @@ ambientazioni = {
|
|
| 24 |
"Sacro Romano Impero": {
|
| 25 |
"nome": "Sacro Romano Impero",
|
| 26 |
"stile_immagine": (
|
| 27 |
-
"Highly detailed, painterly style with a historical yet stylized aesthetic. "
|
| 28 |
"Rich textures, ornate patterns, and a color palette dominated by imperial gold, "
|
| 29 |
"deep red, and aged marble tones. Inspired by medieval European art, "
|
| 30 |
"gothic illuminations, and the grandeur of cathedrals. "
|
|
@@ -92,39 +92,46 @@ ambientazioni = {
|
|
| 92 |
"Cowboy del Far West": {
|
| 93 |
"nome": "Cowboy del Far West",
|
| 94 |
"stile_immagine": (
|
| 95 |
-
"
|
| 96 |
-
"
|
| 97 |
-
"
|
| 98 |
-
"
|
|
|
|
| 99 |
)
|
| 100 |
},
|
| 101 |
"Steampunk": {
|
| 102 |
"nome": "Steampunk",
|
| 103 |
"stile_immagine": (
|
| 104 |
-
"
|
| 105 |
-
"
|
| 106 |
-
"
|
| 107 |
-
"
|
|
|
|
|
|
|
| 108 |
)
|
| 109 |
},
|
| 110 |
"Alieni": {
|
| 111 |
"nome": "Alieni",
|
| 112 |
"stile_immagine": (
|
| 113 |
-
"
|
| 114 |
-
"
|
| 115 |
-
"
|
| 116 |
-
"
|
|
|
|
|
|
|
| 117 |
)
|
| 118 |
},
|
| 119 |
"Homo Sapiens": {
|
| 120 |
"nome": "Homo Sapiens",
|
| 121 |
"stile_immagine": (
|
| 122 |
-
"
|
| 123 |
-
"
|
| 124 |
-
"
|
| 125 |
-
"
|
|
|
|
|
|
|
| 126 |
)
|
| 127 |
-
}
|
| 128 |
}
|
| 129 |
|
| 130 |
|
|
@@ -137,12 +144,27 @@ class Character(BaseModel):
|
|
| 137 |
intelligenza: int
|
| 138 |
descrizione: str
|
| 139 |
english_description:str
|
|
|
|
| 140 |
|
| 141 |
# Definizione dello schema per la risposta contenente una lista di personaggi
|
| 142 |
class CharactersResponse(BaseModel):
|
| 143 |
personaggi: list[Character]
|
| 144 |
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
response = clientOpenAI.chat.completions.create(
|
| 147 |
model='gemini-2.0-flash-thinking-exp-01-21',
|
| 148 |
n=1,
|
|
@@ -152,7 +174,7 @@ def generate_story(character: Character, nome_ambientazione, creativita):
|
|
| 152 |
{"role": "system", "content": f"Tu sei un creatore di giochi di ruolo a CARTE. Crea un regolamento per un gioco di ruolo sul {nome_ambientazione} sulla base dei personaggi che ti fornirò"},
|
| 153 |
{
|
| 154 |
"role": "user",
|
| 155 |
-
"content": f"
|
| 156 |
}
|
| 157 |
]
|
| 158 |
)
|
|
@@ -170,8 +192,9 @@ def generate_story(character: Character, nome_ambientazione, creativita):
|
|
| 170 |
def generate_ai(num_personaggi, nome_ambientazione, creativita):
|
| 171 |
# Costruzione del prompt in italiano per generare i personaggi
|
| 172 |
prompt = (
|
| 173 |
-
f"Genera {num_personaggi} personaggi per un gioco di ruolo a carte
|
| 174 |
-
"Ogni personaggio deve avere i seguenti campi specificati nel modello
|
|
|
|
| 175 |
"Restituisci il risultato in formato JSON seguendo lo schema fornito")
|
| 176 |
|
| 177 |
# Esecuzione della chiamata all'API utilizzando il formato response_format
|
|
@@ -188,6 +211,24 @@ def generate_ai(num_personaggi, nome_ambientazione, creativita):
|
|
| 188 |
print(characters_response)
|
| 189 |
return characters_response
|
| 190 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
# Funzione per generare le immagini, con gestione errori e retry dopo 10 secondi
|
| 192 |
def generate_image(prompt, max_retries=5):
|
| 193 |
client = Together(api_key=api_together)
|
|
@@ -205,19 +246,33 @@ def generate_image(prompt, max_retries=5):
|
|
| 205 |
)
|
| 206 |
return response.data # Una lista di oggetti con attributo b64_json
|
| 207 |
except Exception as e:
|
| 208 |
-
|
| 209 |
-
time.sleep(
|
| 210 |
retries += 1
|
| 211 |
st.error("Numero massimo di tentativi raggiunto. Impossibile generare le immagini.")
|
| 212 |
return None
|
| 213 |
|
| 214 |
-
def generate_images(character: Character, stile_immagine, num_immagini):
|
| 215 |
# Lista per salvare le immagini generate come tuple (nome_file, bytes)
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
for numero in range(num_immagini):
|
| 222 |
images_data = generate_image(prompt)
|
| 223 |
if images_data is not None:
|
|
@@ -233,7 +288,7 @@ def generate_images(character: Character, stile_immagine, num_immagini):
|
|
| 233 |
st.error(f"Errore nella visualizzazione dell'immagine {i+1}: {e}")
|
| 234 |
else:
|
| 235 |
st.error("Non è stato possibile generare le immagini. Riprova più tardi.")
|
| 236 |
-
time.sleep(5)
|
| 237 |
return images_bytes_list
|
| 238 |
|
| 239 |
def main():
|
|
@@ -245,32 +300,50 @@ def main():
|
|
| 245 |
stile_immagine = st.sidebar.text_area("Stile Immagine", stile_default, disabled=False)
|
| 246 |
auto = False
|
| 247 |
prompt_input = st.sidebar.text_input("Prompt Immagine (in inglese)", value="Soldier", disabled=auto)
|
| 248 |
-
auto = st.sidebar.toggle(label= 'Generazione automatica', value = True)
|
| 249 |
-
num_personaggi = st.sidebar.slider("Personaggi", min_value=1, max_value=30, value=5, disabled=not auto)
|
| 250 |
num_immagini = st.sidebar.slider("Variazioni Immagini", min_value=1, max_value=6, value=2)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
creativita = st.sidebar.slider("Creativita", min_value=0.1, max_value=1.0, value=0.8, step=0.1)
|
| 252 |
submit_button = st.sidebar.button(label="Genera Immagine", type="primary", use_container_width=True)
|
| 253 |
-
st.write("Forgia il tuo **destino nell'Impero**: crea, combatti e domina
|
| 254 |
|
| 255 |
if submit_button:
|
| 256 |
if not prompt_input.strip() and not auto:
|
| 257 |
st.error("Per favore, inserisci un prompt per l'immagine!")
|
| 258 |
return
|
|
|
|
|
|
|
| 259 |
if auto:
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
else:
|
| 269 |
-
characters = CharactersResponse(personaggi=[Character(nome="", classe="Guerriero", forza=10, destrezza=8, intelligenza=6, descrizione="Un forte guerriero", english_description=prompt_input)])
|
| 270 |
with st.spinner('Generazione Immagini'):
|
| 271 |
images = []
|
| 272 |
-
|
| 273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
if images:
|
| 275 |
zip_buffer = io.BytesIO()
|
| 276 |
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
|
|
|
|
| 24 |
"Sacro Romano Impero": {
|
| 25 |
"nome": "Sacro Romano Impero",
|
| 26 |
"stile_immagine": (
|
| 27 |
+
"In the italian Holy Roman Empire, Highly detailed, painterly style with a historical yet stylized aesthetic. "
|
| 28 |
"Rich textures, ornate patterns, and a color palette dominated by imperial gold, "
|
| 29 |
"deep red, and aged marble tones. Inspired by medieval European art, "
|
| 30 |
"gothic illuminations, and the grandeur of cathedrals. "
|
|
|
|
| 92 |
"Cowboy del Far West": {
|
| 93 |
"nome": "Cowboy del Far West",
|
| 94 |
"stile_immagine": (
|
| 95 |
+
"Highly detailed, painterly style with a rugged yet cinematic aesthetic. "
|
| 96 |
+
"Rich textures, earthy tones, and a palette dominated by dusty browns, deep reds, and sunset golds. "
|
| 97 |
+
"Inspired by classic Western art, frontier landscapes, and vintage posters. "
|
| 98 |
+
"Iconic elements like cowboy hats, revolvers, and stagecoaches evoke the romance of the Wild West. "
|
| 99 |
+
"Designed for a tabletop card game, ensuring clarity, readability, and an immersive sense of adventure."
|
| 100 |
)
|
| 101 |
},
|
| 102 |
"Steampunk": {
|
| 103 |
"nome": "Steampunk",
|
| 104 |
"stile_immagine": (
|
| 105 |
+
"Highly detailed, painterly style with a fusion of Victorian elegance and mechanical ingenuity. "
|
| 106 |
+
"Brass gears, intricate machinery, steam-powered contraptions, and industrial backdrops "
|
| 107 |
+
"create a retro-futuristic atmosphere. "
|
| 108 |
+
"A color palette dominated by warm metallics, deep browns, and aged parchment tones. "
|
| 109 |
+
"Inspired by classic steampunk literature and art, ensuring a visually immersive experience "
|
| 110 |
+
"for a tabletop card game with a sense of mystery and innovation."
|
| 111 |
)
|
| 112 |
},
|
| 113 |
"Alieni": {
|
| 114 |
"nome": "Alieni",
|
| 115 |
"stile_immagine": (
|
| 116 |
+
"Highly detailed, painterly style with a futuristic and surreal aesthetic. "
|
| 117 |
+
"Glowing neon hues, organic and biomechanical forms, and impossible cosmic landscapes "
|
| 118 |
+
"blend to create an otherworldly atmosphere. "
|
| 119 |
+
"A color palette dominated by electric blues, deep purples, and iridescent greens. "
|
| 120 |
+
"Inspired by sci-fi concept art and space opera visuals, ensuring clarity, readability, "
|
| 121 |
+
"and a visually stunning experience for a tabletop card game set in a mysterious universe."
|
| 122 |
)
|
| 123 |
},
|
| 124 |
"Homo Sapiens": {
|
| 125 |
"nome": "Homo Sapiens",
|
| 126 |
"stile_immagine": (
|
| 127 |
+
"Highly detailed, painterly style with a blend of realism and symbolic representation. "
|
| 128 |
+
"Natural tones, textures inspired by organic matter, and visual elements reflecting "
|
| 129 |
+
"human evolution, history, and cultural development. "
|
| 130 |
+
"A fusion of prehistoric cave paintings, Renaissance anatomical studies, and modern artistic interpretations. "
|
| 131 |
+
"Designed for a tabletop card game, ensuring clarity, readability, and a thought-provoking visual narrative "
|
| 132 |
+
"that bridges the ancient past with the present."
|
| 133 |
)
|
| 134 |
+
}
|
| 135 |
}
|
| 136 |
|
| 137 |
|
|
|
|
| 144 |
intelligenza: int
|
| 145 |
descrizione: str
|
| 146 |
english_description:str
|
| 147 |
+
storia: str
|
| 148 |
|
| 149 |
# Definizione dello schema per la risposta contenente una lista di personaggi
|
| 150 |
class CharactersResponse(BaseModel):
|
| 151 |
personaggi: list[Character]
|
| 152 |
|
| 153 |
+
class ActionCard(BaseModel):
|
| 154 |
+
nome_azione: str
|
| 155 |
+
breve_descrizione: str
|
| 156 |
+
breve_descrizione_inglese: str
|
| 157 |
+
|
| 158 |
+
class ActionCardsResponse(BaseModel):
|
| 159 |
+
carte_azione: list[ActionCard]
|
| 160 |
+
|
| 161 |
+
def generate_story(character: Character, carte_azione: ActionCardsResponse, nome_ambientazione, creativita):
|
| 162 |
+
descrizione_carte_azione = ""
|
| 163 |
+
descrizione_personaggi = ""
|
| 164 |
+
if carte_azione:
|
| 165 |
+
descrizione_carte_azione = f"Ecco anche le CARTE AZIONE del gioco: {carte_azione.model_dump_json()}"
|
| 166 |
+
if character:
|
| 167 |
+
descrizione_personaggi = f"Ecco i personaggi del gioco di RUOLO a carte. {character.model_dump_json()}"
|
| 168 |
response = clientOpenAI.chat.completions.create(
|
| 169 |
model='gemini-2.0-flash-thinking-exp-01-21',
|
| 170 |
n=1,
|
|
|
|
| 174 |
{"role": "system", "content": f"Tu sei un creatore di giochi di ruolo a CARTE. Crea un regolamento per un gioco di ruolo sul {nome_ambientazione} sulla base dei personaggi che ti fornirò"},
|
| 175 |
{
|
| 176 |
"role": "user",
|
| 177 |
+
"content": f"Crea un regolamento!!! {descrizione_personaggi} \n\n {descrizione_carte_azione}"
|
| 178 |
}
|
| 179 |
]
|
| 180 |
)
|
|
|
|
| 192 |
def generate_ai(num_personaggi, nome_ambientazione, creativita):
|
| 193 |
# Costruzione del prompt in italiano per generare i personaggi
|
| 194 |
prompt = (
|
| 195 |
+
f"Genera {num_personaggi} personaggi AMBIENTATI NELL'EPOCA {nome_ambientazione}, per un gioco di ruolo a carte."
|
| 196 |
+
"Ogni personaggio deve avere i seguenti campi specificati nel modello ed devono essere COERENTI con l'epoca e l'ambientazione fornita (per esempio, se siamo nel Sacro Romano Impero devono essere nomi italiani) "
|
| 197 |
+
"nel campo STORIA, inventa la una BREVE storia di background del personaggio specificando aneddoti, e altre cose che rendono il personaggio unico. "
|
| 198 |
"Restituisci il risultato in formato JSON seguendo lo schema fornito")
|
| 199 |
|
| 200 |
# Esecuzione della chiamata all'API utilizzando il formato response_format
|
|
|
|
| 211 |
print(characters_response)
|
| 212 |
return characters_response
|
| 213 |
|
| 214 |
+
def generate_card_ai(num_carte_azione, nome_ambientazione, creativita):
|
| 215 |
+
prompt = (
|
| 216 |
+
f"Genera {num_carte_azione} CARTE AZIONE, per un gioco di ruolo ambientato in {nome_ambientazione}. "
|
| 217 |
+
"Attieniti allo schema formito e sii molto SINTETICO")
|
| 218 |
+
|
| 219 |
+
# Esecuzione della chiamata all'API utilizzando il formato response_format
|
| 220 |
+
completion = clientOpenAI.beta.chat.completions.parse(
|
| 221 |
+
model=MODEL,
|
| 222 |
+
messages=[
|
| 223 |
+
{"role": "system", "content": f"Sei un assistente utile per la generazione di CARTE AZIONE per un gioco di RUOLO sul {nome_ambientazione}."},
|
| 224 |
+
{"role": "user", "content": prompt},
|
| 225 |
+
],
|
| 226 |
+
temperature=creativita,
|
| 227 |
+
response_format=ActionCardsResponse,
|
| 228 |
+
)
|
| 229 |
+
action_card_response = completion.choices[0].message.parsed
|
| 230 |
+
return action_card_response
|
| 231 |
+
|
| 232 |
# Funzione per generare le immagini, con gestione errori e retry dopo 10 secondi
|
| 233 |
def generate_image(prompt, max_retries=5):
|
| 234 |
client = Together(api_key=api_together)
|
|
|
|
| 246 |
)
|
| 247 |
return response.data # Una lista di oggetti con attributo b64_json
|
| 248 |
except Exception as e:
|
| 249 |
+
print(f"Errore durante la generazione delle immagini: {e}. Riprovo tra 10 secondi...")
|
| 250 |
+
time.sleep(9)
|
| 251 |
retries += 1
|
| 252 |
st.error("Numero massimo di tentativi raggiunto. Impossibile generare le immagini.")
|
| 253 |
return None
|
| 254 |
|
| 255 |
+
def generate_images(character: Character, carta_azione: ActionCard, stile_immagine, num_immagini):
|
| 256 |
# Lista per salvare le immagini generate come tuple (nome_file, bytes)
|
| 257 |
+
if character:
|
| 258 |
+
prompt = f"{character.english_description} {stile_immagine}. (INSERT TEXT NAME = {character.nome})"
|
| 259 |
+
images_bytes_list = []
|
| 260 |
+
if character.nome != "":
|
| 261 |
+
st.subheader(f"{character.nome} 🦸♂️")
|
| 262 |
+
st.write(
|
| 263 |
+
f"- **Classe:** {character.classe}\n"
|
| 264 |
+
f"- **Forza:** {character.forza}\n"
|
| 265 |
+
f"- **Destrezza:** {character.destrezza}\n"
|
| 266 |
+
f"- **Intelligenza:** {character.intelligenza}\n"
|
| 267 |
+
f"- **Descrizione:** {character.descrizione}\n",
|
| 268 |
+
f"- **Storia:** {character.storia}"
|
| 269 |
+
)
|
| 270 |
+
if carta_azione:
|
| 271 |
+
prompt = f"PLAYING CARD FOR A CARD GAME WITHOUT CHARACTER WITH THIS BOLD INSCRIPTION IN THE CENTER OF THE CARD: '{carta_azione.nome_azione}'. USE THIS STYLE: {stile_immagine}.)"
|
| 272 |
+
images_bytes_list = []
|
| 273 |
+
st.subheader(f"{carta_azione.nome_azione} 🃏")
|
| 274 |
+
st.write(f"- **Descrizione:** {carta_azione.breve_descrizione}")
|
| 275 |
+
print(prompt)
|
| 276 |
for numero in range(num_immagini):
|
| 277 |
images_data = generate_image(prompt)
|
| 278 |
if images_data is not None:
|
|
|
|
| 288 |
st.error(f"Errore nella visualizzazione dell'immagine {i+1}: {e}")
|
| 289 |
else:
|
| 290 |
st.error("Non è stato possibile generare le immagini. Riprova più tardi.")
|
| 291 |
+
time.sleep(0.5)
|
| 292 |
return images_bytes_list
|
| 293 |
|
| 294 |
def main():
|
|
|
|
| 300 |
stile_immagine = st.sidebar.text_area("Stile Immagine", stile_default, disabled=False)
|
| 301 |
auto = False
|
| 302 |
prompt_input = st.sidebar.text_input("Prompt Immagine (in inglese)", value="Soldier", disabled=auto)
|
|
|
|
|
|
|
| 303 |
num_immagini = st.sidebar.slider("Variazioni Immagini", min_value=1, max_value=6, value=2)
|
| 304 |
+
auto = st.sidebar.toggle(label= 'Generazione automatica', value = True)
|
| 305 |
+
num_personaggi = st.sidebar.slider("Personaggi", min_value=0, max_value=30, value=5, disabled=not auto)
|
| 306 |
+
num_carte_azione = st.sidebar.slider("Carte Azione", min_value=0, max_value=10, value=0, disabled=not auto)
|
| 307 |
+
genera_regolamento = st.sidebar.toggle(label= 'Regolamento', value = True, disabled=not auto)
|
| 308 |
creativita = st.sidebar.slider("Creativita", min_value=0.1, max_value=1.0, value=0.8, step=0.1)
|
| 309 |
submit_button = st.sidebar.button(label="Genera Immagine", type="primary", use_container_width=True)
|
| 310 |
+
st.write("Forgia il tuo **destino nell'Impero**: crea, combatti e domina nel più grande gioco di ruolo a carte generato dall'AI")
|
| 311 |
|
| 312 |
if submit_button:
|
| 313 |
if not prompt_input.strip() and not auto:
|
| 314 |
st.error("Per favore, inserisci un prompt per l'immagine!")
|
| 315 |
return
|
| 316 |
+
carte_azione = None
|
| 317 |
+
characters = None
|
| 318 |
if auto:
|
| 319 |
+
if num_personaggi > 0:
|
| 320 |
+
with st.spinner('Generazione Personaggi'):
|
| 321 |
+
characters = generate_ai(num_personaggi, nome_ambientazione, creativita)
|
| 322 |
+
st.subheader('Personaggi 🎭')
|
| 323 |
+
df = pd.DataFrame([{k: v for k, v in character.model_dump().items() if k != "english_description"} for character in characters.personaggi])
|
| 324 |
+
st.dataframe(df, hide_index=True, use_container_width=True)
|
| 325 |
+
st.divider()
|
| 326 |
+
if num_carte_azione > 0:
|
| 327 |
+
with st.spinner('Generazione Carte Azione'):
|
| 328 |
+
carte_azione = generate_card_ai(num_carte_azione, nome_ambientazione, creativita)
|
| 329 |
+
st.subheader('Carte Azione 📒')
|
| 330 |
+
df = pd.DataFrame([{k: v for k, v in carta_azione.model_dump().items() if k != "breve_descrizione_inglese"} for carta_azione in carte_azione.carte_azione])
|
| 331 |
+
st.dataframe(df, hide_index=True, use_container_width=True)
|
| 332 |
+
st.divider()
|
| 333 |
+
if genera_regolamento:
|
| 334 |
+
with st.spinner('Generazione Regolamento'):
|
| 335 |
+
generate_story(characters, carte_azione, nome_ambientazione, creativita)
|
| 336 |
+
st.divider()
|
| 337 |
else:
|
| 338 |
+
characters = CharactersResponse(personaggi=[Character(nome="", classe="Guerriero", forza=10, destrezza=8, intelligenza=6, storia="", descrizione="Un forte guerriero", english_description=prompt_input)])
|
| 339 |
with st.spinner('Generazione Immagini'):
|
| 340 |
images = []
|
| 341 |
+
if characters:
|
| 342 |
+
for character in characters.personaggi:
|
| 343 |
+
images.extend(generate_images(character, None, stile_immagine, num_immagini))
|
| 344 |
+
if carte_azione:
|
| 345 |
+
for carta_azione in carte_azione.carte_azione:
|
| 346 |
+
images.extend(generate_images(None, carta_azione, stile_immagine, num_immagini))
|
| 347 |
if images:
|
| 348 |
zip_buffer = io.BytesIO()
|
| 349 |
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
|