Spaces:
Running
Running
File size: 19,808 Bytes
d60dac5 cebfd3c 293ffb8 c368803 c17cf76 293ffb8 c368803 ffafa9e 9301ad1 2f9c799 90c5698 2f9c799 90c5698 2f9c799 90c5698 2f9c799 90c5698 2f9c799 90c5698 2f9c799 90c5698 2f9c799 ffafa9e c368803 90c5698 c368803 90c5698 c368803 ffafa9e c368803 2f9c799 c368803 ffafa9e c368803 90c5698 c368803 2f9c799 c368803 90c5698 c368803 ffafa9e c368803 2f9c799 c368803 a6058bc 90c5698 293ffb8 c368803 293ffb8 c17cf76 293ffb8 90c5698 293ffb8 9301ad1 c368803 90c5698 9301ad1 90c5698 293ffb8 c368803 293ffb8 c368803 293ffb8 7376a17 293ffb8 90c5698 c368803 293ffb8 c368803 293ffb8 ffafa9e 293ffb8 c368803 90c5698 9301ad1 2f9c799 c368803 90c5698 c368803 293ffb8 90c5698 c368803 90c5698 ed5749a 90c5698 c368803 90c5698 9301ad1 90c5698 c368803 293ffb8 c368803 9301ad1 |
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 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
import streamlit as st
import time
import base64
import io
import zipfile
from PIL import Image
from together import Together
import os
from dotenv import load_dotenv
from pydantic import BaseModel
from openai import OpenAI
import pandas as pd
load_dotenv()
api_together = os.getenv("TOGETHER_API_KEY")
api_gemini = os.getenv("API_GEMINI")
MODEL = "gemini-2.0-flash-exp"
clientOpenAI = OpenAI(
api_key=api_gemini,
base_url="https://generativelanguage.googleapis.com/v1beta/openai/"
)
ambientazioni = {
"Roma Repubblicana": {
"nome": "Roma Repubblicana",
"stile_immagine": (
"A painterly, highly detailed visual narrative rich with graphic elements Roman Repubblic "
"Incorporate ornate Roman columns, laurel wreaths, engraved inscriptions, and intricate mosaic patterns. "
"Textures of weathered marble, aged frescoes, and tattered papyrus blend with a dramatic chiaroscuro effect. "
"A color palette of imperial red, bronze, and muted gold accentuates secretive senatorial silhouettes and subtle sigils. "
"Designed for a tabletop card game, this style captures clandestine intrigue and political tension with dynamic visual flair."
)
},
"Sacro Romano Impero": {
"nome": "Sacro Romano Impero",
"stile_immagine": (
"In the italian Holy Roman Empire, Highly detailed, painterly style with a historical yet stylized aesthetic. "
"Rich textures, ornate patterns, and a color palette dominated by imperial gold, "
"deep red, and aged marble tones. Inspired by medieval European art, "
"gothic illuminations, and the grandeur of cathedrals. "
"Designed for a tabletop card game, ensuring clarity, readability, "
"and a visually immersive experience."
)
},
"Antico Egitto": {
"nome": "Antico Egitto",
"stile_immagine": (
"A stylized Egyptian art style, reminiscent of ancient tomb paintings. "
"Use sandy, ochre and turquoise color palette, with hieroglyphic details. "
"Geometric shapes and patterns evoke the grandeur of pharaohs and pyramids. "
"Designed for a tabletop card game with clarity and distinct thematic flourishes."
)
},
"Dinastia Han Cinese": {
"nome": "Dinastia Han Cinese",
"stile_immagine": (
"Traditional Chinese art style, with ink wash influences, ornate calligraphy, "
"and vibrant silk robe patterns. Use subtle brush strokes and bold reds/golds. "
"Designed for clarity in a card game with a distinctly ancient Asian aesthetic."
)
},
"Impero Persiano": {
"nome": "Impero Persiano",
"stile_immagine": (
"Intricate Persian miniature style, lavish details, floral ornaments, "
"and strong jewel tones like turquoise, gold, and purple. Stylized silhouettes "
"in a rich, decorative composition suited for card art."
)
},
"Impero Ottomano": {
"nome": "Impero Ottomano",
"stile_immagine": (
"Ottoman illuminated manuscript style, featuring ornate arabesque borders, "
"rich gold leaf, and deep sapphire or emerald backgrounds. "
"Figures with flowing robes and turbans, capturing courtly splendor."
)
},
"Maya": {
"nome": "Maya",
"stile_immagine": (
"Mesoamerican style with stylized glyphs, stepped pyramids, and bright colors. "
"Incorporate traditional motifs of jaguars and feathers in a decorative, yet readable card layout."
)
},
"Vichinghi": {
"nome": "Vichinghi",
"stile_immagine": (
"Norse-inspired style, with knotwork borders, runic inscriptions, and rugged, "
"weathered textures. Use earthy colors and references to Viking longships, "
"mythology, and wooden carvings. Balanced for a legible card game design."
)
},
"Pirati": {
"nome": "Pirati",
"stile_immagine": (
"A dynamic and adventurous style inspired by leggende dei mari e pirati romantici. "
"Immagini di navi in tempesta, mappe del tesoro, e personaggi con bandane e cappelli tricorni. "
"Toni marinari, textures consumate dal sale e dall'acqua, e un'atmosfera ribelle ma affascinante, "
"perfetta per un gioco di carte che evoca il brivido dell'avventura sul mare."
)
},
"Cowboy del Far West": {
"nome": "Cowboy del Far West",
"stile_immagine": (
"Highly detailed, painterly style with a rugged yet cinematic aesthetic. "
"Rich textures, earthy tones, and a palette dominated by dusty browns, deep reds, and sunset golds. "
"Inspired by classic Western art, frontier landscapes, and vintage posters. "
"Iconic elements like cowboy hats, revolvers, and stagecoaches evoke the romance of the Wild West. "
"Designed for a tabletop card game, ensuring clarity, readability, and an immersive sense of adventure."
)
},
"Steampunk": {
"nome": "Steampunk",
"stile_immagine": (
"Highly detailed, painterly style with a fusion of Victorian elegance and mechanical ingenuity. "
"Brass gears, intricate machinery, steam-powered contraptions, and industrial backdrops "
"create a retro-futuristic atmosphere. "
"A color palette dominated by warm metallics, deep browns, and aged parchment tones. "
"Inspired by classic steampunk literature and art, ensuring a visually immersive experience "
"for a tabletop card game with a sense of mystery and innovation."
)
},
"Alieni": {
"nome": "Alieni",
"stile_immagine": (
"Highly detailed, painterly style with a futuristic and surreal aesthetic. "
"Glowing neon hues, organic and biomechanical forms, and impossible cosmic landscapes "
"blend to create an otherworldly atmosphere. "
"A color palette dominated by electric blues, deep purples, and iridescent greens. "
"Inspired by sci-fi concept art and space opera visuals, ensuring clarity, readability, "
"and a visually stunning experience for a tabletop card game set in a mysterious universe."
)
},
"Homo Sapiens": {
"nome": "Homo Sapiens",
"stile_immagine": (
"Highly detailed, painterly style with a blend of realism and symbolic representation. "
"Natural tones, textures inspired by organic matter, and visual elements reflecting "
"human evolution, history, and cultural development. "
"A fusion of prehistoric cave paintings, Renaissance anatomical studies, and modern artistic interpretations. "
"Designed for a tabletop card game, ensuring clarity, readability, and a thought-provoking visual narrative "
"that bridges the ancient past with the present."
)
}
}
# Definizione dello schema Pydantic per un personaggio
class Character(BaseModel):
nome: str
classe: str
forza: int
destrezza: int
intelligenza: int
descrizione: str
english_description:str
storia: str
# Definizione dello schema per la risposta contenente una lista di personaggi
class CharactersResponse(BaseModel):
personaggi: list[Character]
class ActionCard(BaseModel):
nome_azione: str
breve_descrizione: str
breve_descrizione_inglese: str
class ActionCardsResponse(BaseModel):
carte_azione: list[ActionCard]
def generate_story(character: Character, carte_azione: ActionCardsResponse, nome_ambientazione, creativita):
descrizione_carte_azione = ""
descrizione_personaggi = ""
if carte_azione:
descrizione_carte_azione = f"Ecco anche le CARTE AZIONE del gioco: {carte_azione.model_dump_json()}"
if character:
descrizione_personaggi = f"Ecco i personaggi del gioco di RUOLO a carte. {character.model_dump_json()}"
response = clientOpenAI.chat.completions.create(
model='gemini-2.0-flash-thinking-exp-01-21',
n=1,
stream=True,
temperature=creativita,
messages=[
{"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ò"},
{
"role": "user",
"content": f"Crea un regolamento!!! {descrizione_personaggi} \n\n {descrizione_carte_azione}"
}
]
)
story = ""
st.subheader('Regole 📜')
placeholder = st.empty()
for chunk in response:
if chunk.choices[0].delta.content is not None:
text_chunk = chunk.choices[0].delta.content
story += text_chunk
placeholder.markdown(story)
print(story)
return story
def generate_ai(num_personaggi, nome_ambientazione, creativita):
# Costruzione del prompt in italiano per generare i personaggi
prompt = (
f"Genera {num_personaggi} personaggi AMBIENTATI NELL'EPOCA {nome_ambientazione}, per un gioco di ruolo a carte."
"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) "
"nel campo STORIA, inventa la una BREVE storia di background del personaggio specificando aneddoti, e altre cose che rendono il personaggio unico. "
"Restituisci il risultato in formato JSON seguendo lo schema fornito")
# Esecuzione della chiamata all'API utilizzando il formato response_format
completion = clientOpenAI.beta.chat.completions.parse(
model=MODEL,
messages=[
{"role": "system", "content": f"Sei un assistente utile per la generazione di personaggi per un gioco di RUOLO sul {nome_ambientazione}."},
{"role": "user", "content": prompt},
],
temperature=creativita,
response_format=CharactersResponse,
)
characters_response = completion.choices[0].message.parsed
print(characters_response)
return characters_response
def generate_card_ai(num_carte_azione, nome_ambientazione, creativita):
prompt = (
f"Genera {num_carte_azione} CARTE AZIONE, per un gioco di ruolo ambientato in {nome_ambientazione}. "
"Attieniti allo schema formito e sii molto SINTETICO")
# Esecuzione della chiamata all'API utilizzando il formato response_format
completion = clientOpenAI.beta.chat.completions.parse(
model=MODEL,
messages=[
{"role": "system", "content": f"Sei un assistente utile per la generazione di CARTE AZIONE per un gioco di RUOLO sul {nome_ambientazione}."},
{"role": "user", "content": prompt},
],
temperature=creativita,
response_format=ActionCardsResponse,
)
action_card_response = completion.choices[0].message.parsed
return action_card_response
# Funzione per generare le immagini, con gestione errori e retry dopo 10 secondi
def generate_image(prompt, max_retries=5):
client = Together(api_key=api_together)
retries = 0
while retries < max_retries:
try:
response = client.images.generate(
prompt=prompt,
model="black-forest-labs/FLUX.1-schnell-Free",
width=960,
height=1440,
steps=4,
n=1,
response_format="b64_json"
)
return response.data # Una lista di oggetti con attributo b64_json
except Exception as e:
print(f"Errore durante la generazione delle immagini: {e}. Riprovo tra 10 secondi...")
time.sleep(9)
retries += 1
st.error("Numero massimo di tentativi raggiunto. Impossibile generare le immagini.")
return None
def generate_images(character: Character, carta_azione: ActionCard, stile_immagine, num_immagini, tipo_carta: str = None, nome_carta: str = None, colore_bordo: str = None):
# Lista per salvare le immagini generate come tuple (nome_file, bytes)
if character:
images_bytes_list = []
if character.nome == "":
if tipo_carta == "Personaggio":
prompt = f"{character.english_description} WITH THIS BOLD INSCRIPTION '{nome_carta}'. BORDER COLOR = {colore_bordo}). Use this Style: {stile_immagine}"
if tipo_carta == "Fronte":
prompt = f"FRONT OF CARD GAME (WITH THIS BOLD INSCRIPTION IN THE CENTER OF THE CARD = '{nome_carta}'. BORDER COLOR = {colore_bordo}). Use this Syle: {stile_immagine}"
if tipo_carta == "Retro":
prompt = ("Design an ornate playing card back with symmetrical filigree"
"At the center, prominently display the name '" + nome_carta + "' in an elegant, calligraphic style. ")
prompt += f"BACKGROUND COLOR = {colore_bordo}. Use this Syle: {stile_immagine}"
else:
prompt = f"{character.english_description} {stile_immagine}. (INSERT TEXT NAME = {character.nome})"
st.subheader(f"{character.nome} 🦸♂️")
st.write(
f"- **Classe:** {character.classe}\n"
f"- **Forza:** {character.forza}\n"
f"- **Destrezza:** {character.destrezza}\n"
f"- **Intelligenza:** {character.intelligenza}\n"
f"- **Descrizione:** {character.descrizione}\n",
f"- **Storia:** {character.storia}"
)
if carta_azione:
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}.)"
images_bytes_list = []
st.subheader(f"{carta_azione.nome_azione} 🃏")
st.write(f"- **Descrizione:** {carta_azione.breve_descrizione}")
print(prompt)
for numero in range(num_immagini):
images_data = generate_image(prompt)
if images_data is not None:
for i, img_obj in enumerate(images_data):
try:
image_bytes = base64.b64decode(img_obj.b64_json)
image = Image.open(io.BytesIO(image_bytes))
st.image(image, caption="")
img_byte_arr = io.BytesIO()
image.save(img_byte_arr, format='PNG')
images_bytes_list.append((f"image_{numero+1}_{i+1}.png", img_byte_arr.getvalue()))
except Exception as e:
st.error(f"Errore nella visualizzazione dell'immagine {i+1}: {e}")
else:
st.error("Non è stato possibile generare le immagini. Riprova più tardi.")
time.sleep(0.5)
return images_bytes_list
def main():
st.title("Imperium AI 🏰")
st.sidebar.header("Impostazioni")
selected_ambientazione = st.sidebar.selectbox("Ambientazione", list(ambientazioni.keys()), index=0)
stile_default = ambientazioni[selected_ambientazione]["stile_immagine"]
nome_ambientazione = ambientazioni[selected_ambientazione]["nome"]
stile_immagine = st.sidebar.text_area("Stile Immagine", stile_default, disabled=False)
auto = False
auto = st.sidebar.toggle(label= 'Generazione automatica', value = True)
prompt_input = ""
if auto == False:
tipo_carta = st.sidebar.selectbox("Tipo Carta",("Personaggio", "Fronte", "Retro"))
if tipo_carta == "Personaggio":
prompt_input = st.sidebar.text_input("Prompt Immagine (in inglese)", value="Soldier")
nome_carta = st.sidebar.text_input("Nome Carta", value="Carmine")
colore_bordo = st.sidebar.selectbox("Colore Bordo",("Blue", "Red", "Yellow", "Green", "Pink", "Black", "White"))
else:
num_personaggi = st.sidebar.slider("Personaggi", min_value=0, max_value=30, value=5, disabled=not auto)
num_carte_azione = st.sidebar.slider("Carte Azione", min_value=0, max_value=10, value=0, disabled=not auto)
genera_regolamento = st.sidebar.toggle(label= 'Regolamento', value = True, disabled=not auto)
tipo_carta = None
nome_carta = None
colore_bordo = None
num_immagini = st.sidebar.slider("Variazioni Immagini", min_value=1, max_value=6, value=2)
creativita = st.sidebar.slider("Creativita", min_value=0.1, max_value=1.0, value=0.8, step=0.1)
submit_button = st.sidebar.button(label="Genera Immagine", type="primary", use_container_width=True)
st.write("Forgia il tuo **destino nell'Impero**: crea, combatti e domina nel più grande gioco di ruolo a carte generato dall'AI")
if submit_button:
carte_azione = None
characters = None
if auto:
if num_personaggi > 0:
with st.spinner('Generazione Personaggi'):
characters = generate_ai(num_personaggi, nome_ambientazione, creativita)
st.subheader('Personaggi 🎭')
df = pd.DataFrame([{k: v for k, v in character.model_dump().items() if k != "english_description"} for character in characters.personaggi])
st.dataframe(df, hide_index=True, use_container_width=True)
st.divider()
if num_carte_azione > 0:
with st.spinner('Generazione Carte Azione'):
carte_azione = generate_card_ai(num_carte_azione, nome_ambientazione, creativita)
st.subheader('Carte Azione 📒')
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])
st.dataframe(df, hide_index=True, use_container_width=True)
st.divider()
if genera_regolamento:
with st.spinner('Generazione Regolamento'):
generate_story(characters, carte_azione, nome_ambientazione, creativita)
st.divider()
else:
characters = CharactersResponse(personaggi=[Character(nome="", classe="Guerriero", forza=10, destrezza=8, intelligenza=6, storia="", descrizione="Un forte guerriero", english_description=prompt_input)])
with st.spinner('Generazione Immagini'):
images = []
if characters:
for character in characters.personaggi:
images.extend(generate_images(character, None, stile_immagine, num_immagini, tipo_carta, nome_carta, colore_bordo))
if carte_azione:
for carta_azione in carte_azione.carte_azione:
images.extend(generate_images(None, carta_azione, stile_immagine, num_immagini))
if images:
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
for file_name, file_bytes in images:
zip_file.writestr(file_name, file_bytes)
zip_buffer.seek(0)
st.download_button(
label="Download All Images",
data=zip_buffer,
file_name="images.zip",
mime="application/zip",
type='primary'
)
st.success("Immagini generate con successo!")
if __name__ == "__main__":
st.set_page_config(page_title="Imperium AI", page_icon="🏰", layout="wide")
main()
|