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/" ) # 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 # Definizione dello schema per la risposta contenente una lista di personaggi class CharactersResponse(BaseModel): personaggi: list[Character] def generate_story(character: Character): response = clientOpenAI.chat.completions.create( model=MODEL, n=1, stream=True, messages=[ {"role": "system", "content": "Tu sei un creatore di giochi di ruolo a CARTE. Crea un regolamento per un gioco di ruolo sul SACRO ROMANO IMPERO sulla base dei personaggi che ti fornirò"}, { "role": "user", "content": f"Ecco i personaggi del gioco di RUOLO a carte. Crea un regolamento!!! {character.model_dump_json()}" } ] ) 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): # Costruzione del prompt in italiano per generare i personaggi prompt = ( f"Genera {num_personaggi} personaggi per un gioco di ruolo a carte ambientato nel Sacro Romano Impero. " "Ogni personaggio deve avere i seguenti campi specificati nel modello. " "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": "Sei un assistente utile per la generazione di personaggi per un gioco di RUOLO sul SACRO ROMANO IMPERO."}, {"role": "user", "content": prompt}, ], response_format=CharactersResponse, ) characters_response = completion.choices[0].message.parsed print(characters_response) return characters_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: st.error(f"Errore durante la generazione delle immagini: {e}. Riprovo tra 10 secondi...") time.sleep(10) retries += 1 st.error("Numero massimo di tentativi raggiunto. Impossibile generare le immagini.") return None def generate_images(character: Character, stile_immagine, num_immagini): # Lista per salvare le immagini generate come tuple (nome_file, bytes) prompt = f"{character.english_description} {stile_immagine}" images_bytes_list = [] if character.nome != "": st.subheader(f"{character.nome} 🦸‍♂️") st.markdown(f"- **Classe:** {character.classe}\n- **Forza:** {character.forza}\n- **Destrezza:** {character.destrezza}\n- **Intelligenza:** {character.intelligenza}\n- **Descrizione:** {character.descrizione}", unsafe_allow_html=True) 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(5) return images_bytes_list def main(): st.title("Imperium AI 🏰") st.sidebar.header("Impostazioni") stile_default = ("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 ancient Roman mosaics, frescoes, " "and classical sculpture, with a balanced mix of realism and stylization. " "Elegant, decorative card borders with intricate engravings and antique flourishes. " "Designed for a tabletop card game, ensuring clarity, readability, and a visually immersive experience.") stile_immagine = st.sidebar.text_area("Stile Immagine", stile_default, disabled=False) auto = False prompt_input = st.sidebar.text_input("Prompt Immagine (in inglese)", value="Roman Soldier", disabled=auto) auto = st.sidebar.toggle(label= 'Generazione automatica') num_personaggi = st.sidebar.slider("Personaggi", min_value=1, max_value=30, value=5, disabled=not auto) num_immagini = st.sidebar.slider("Variazioni Immagini", min_value=1, max_value=6, value=2) 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 con nel più grande gioco di ruolo a carte generato dall'AI") if submit_button: if not prompt_input.strip() and not auto: st.error("Per favore, inserisci un prompt per l'immagine!") return if auto: with st.spinner('Generazione Personaggi'): characters = generate_ai(num_personaggi) 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) st.divider() generate_story(characters) st.divider() else: characters = CharactersResponse(personaggi=[Character(nome="", classe="Guerriero", forza=10, destrezza=8, intelligenza=6, descrizione="Un forte guerriero", english_description=prompt_input)]) with st.spinner('Generazione Immagini'): images = [] for character in characters.personaggi: images.extend(generate_images(character, 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()