iaflix / app.py
klawdyoss's picture
Update app.py
f38792f verified
import gradio as gr
import requests
import re
# --------------------------------------------
# Variáveis globais (poderíamos usar State)
# --------------------------------------------
groq_api_key = "" # será preenchido ao usuário inserir
groq_model = "llama3-groq-70b-8192-tool-use-preview"
huggingface_ti_endpoint = "https://huggingface.co/spaces/USER/YOUR_TEXT_TO_IMAGE/queue/predict"
# ^ Ajuste conforme seu Space de Text-to-Image.
# --------------------------------------------
# Funções auxiliares
# --------------------------------------------
def set_groq_key(key):
"""
Salva a chave do Groq informada pelo usuário.
"""
global groq_api_key
groq_api_key = key.strip()
return f"Chave Groq salva: {groq_api_key[:6]}******"
def ask_groq(prompt):
"""
Faz chamada à API Groq, retornando string com a resposta.
Necessita de groq_api_key global.
"""
if not groq_api_key:
return "ERRO: sem chave Groq. Insira primeiro."
# Monta body:
payload = {
"messages": [{"role": "user", "content": prompt}],
"model": groq_model,
"temperature": 1,
"max_tokens": 1024,
"top_p": 1,
"stream": False,
}
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {groq_api_key}"
}
try:
resp = requests.post("https://api.groq.com/openai/v1/chat/completions",
json=payload, headers=headers, timeout=60)
resp.raise_for_status()
data = resp.json()
content = data.get("choices",[{}])[0].get("message",{}).get("content","")
return content
except Exception as e:
return f"Erro ao chamar Groq: {e}"
def generate_suggestions(style, custom_theme):
"""
Gera 3 sugestões de histórias no estilo/style, usando Groq.
"""
if style == "Tema Personalizado":
if not custom_theme.strip():
return ["Digite algo em 'Tema Personalizado'..."]
tema = custom_theme
else:
tema = style
prompt = f"""
Gere 3 ideias de histórias no gênero/tema: '{tema}'.
Responda no formato:
1) ...
2) ...
3) ...
"""
resp = ask_groq(prompt)
# Faz parse simples para separar 3 linhas
# Caso a Groq retorne outro formato, ajuste aqui
lines = re.split(r"\d\)|\d\.", resp)
ideas = []
for line in lines:
line = line.strip()
if len(line) > 5:
ideas.append(line)
if not ideas:
ideas = [resp] # fallback: mostra a string toda
return ideas
def call_text_to_image_api(description):
"""
Chama seu endpoint Hugging Face (exemplo 'queue/predict') para gerar imagem com base no `description`.
Ajuste conforme a doc do seu Space.
"""
try:
# Exemplo de payload que alguns Spaces usam:
payload = {"data": [description]}
r = requests.post(huggingface_ti_endpoint, json=payload, timeout=120)
r.raise_for_status()
data = r.json()
# Exemplo: supor que a imagem retorne em data["data"][0] (base64)
# Precisaria ver doc exata do Space
base64_img = data["data"][0]
return f"data:image/png;base64,{base64_img}"
except Exception as e:
return None
def expand_story(idea):
"""
Gera uma história com várias cenas (CENA 1:, CENA 2:, etc.) dada uma ideia curta.
"""
if not idea or len(idea) < 5:
return "Nenhuma ideia selecionada."
prompt = f"""
Crie uma história detalhada a partir da seguinte ideia:
'{idea}'
Separe cada cena como 'CENA X:' e descreva cada cena em poucas frases.
"""
story_text = ask_groq(prompt)
# Quebrar a string pelas cenas
splitted = re.split(r"(CENA\s*\d+:)", story_text, flags=re.IGNORECASE)
# splitted vira algo como ["", "CENA 1:", "texto da cena1", "CENA 2:", "texto da cena2", ...]
# Precisamos remontar pares
scenes = []
buffer_title = ""
buffer_text = ""
for chunk in splitted:
chunk = chunk.strip()
if re.match(r"(?i)cena\s*\d+:", chunk):
# se já houver buffer_text e buffer_title, finaliza
if buffer_title and buffer_text:
scenes.append(f"{buffer_title}\n{buffer_text}")
buffer_title = chunk
buffer_text = ""
else:
# é corpo da cena
if buffer_text:
buffer_text += " " + chunk
else:
buffer_text = chunk
# Adiciona o último
if buffer_title and buffer_text:
scenes.append(f"{buffer_title}\n{buffer_text}")
if not scenes:
# fallback: sem 'CENA x:' => 1 bloco só
scenes = [story_text]
return scenes
def run_story(idea):
"""
Gera as cenas da história e para cada cena gera a imagem e retorna tudo.
Retorna uma lista de dicts: [{image, text}, ...].
"""
scenes = expand_story(idea)
output = []
for scene in scenes:
# Chama text2img
img_data = call_text_to_image_api(scene)
if not img_data:
# se falhar, placeholder
img_data = "https://via.placeholder.com/600x400?text=Falha+Gerar+Imagem"
output.append({"text": scene, "image": img_data})
return output
# --------------------------------------------
# Montando interface com Gradio
# --------------------------------------------
def ui_set_key(key):
return set_groq_key(key)
def ui_generate_suggs(style, custom_theme):
return generate_suggestions(style, custom_theme)
def ui_run_story(idea):
# Gera as cenas e retorna a lista
all_scenes = run_story(idea)
# Queremos exibir "carousel"? Ou gerar uma lista?
# No Gradio, podemos retornar algo como (list of images, ou HTML).
# Exemplo simples: retornamos uma tupla (primeira imagem, e todo o texto).
# Mas se quisermos exibir cada cena isoladamente, podemos usar "Gallery" etc.
# Para simplicidade, vamos juntar tudo em HTML:
html_content = ""
for i, sc in enumerate(all_scenes, start=1):
html_content += f"<h4> Cena {i} </h4>"
html_content += f"<p>{sc['text']}</p>"
html_content += f"<img src='{sc['image']}' alt='cena {i}' style='max-width:400px; margin-bottom:10px;'/>"
html_content += "<hr/>"
return html_content
import gradio as gr
with gr.Blocks() as demo:
gr.Markdown("# IAFlix: Exemplo em Gradio\nInsira a chave Groq, gere sugestões e expanda em cenas + imagens.")
with gr.Row():
groq_key_box = gr.Textbox(label="Sua Groq API Key", type="password", value="")
btn_save_key = gr.Button("Salvar Chave")
key_status = gr.Textbox(label="Status da Chave", interactive=False)
with gr.Accordion("Passo 1: Gerar sugestões", open=True):
style_dd = gr.Dropdown(
label="Estilo/Gênero",
choices=["Fantasia", "Ficção Científica", "Surreal", "Romance", "Tema Personalizado"],
value="Fantasia"
)
custom_theme_box = gr.Textbox(label="Tema Personalizado (se selecionado)")
btn_suggs = gr.Button("Gerar Sugestões")
suggestions_output = gr.State() # armazena array de sugestões
suggestions_display = gr.Radio(
label="Sugestões Geradas",
choices=[], # será populado dinâmicamente
interactive=True
)
with gr.Accordion("Passo 2: Expandir e gerar cenas", open=False):
btn_run_story = gr.Button("Iniciar História da Sugestão Selecionada")
story_html = gr.HTML(label="Resultado das Cenas")
# Lógica de Botões
btn_save_key.click(fn=ui_set_key, inputs=[groq_key_box], outputs=[key_status])
btn_suggs.click(fn=ui_generate_suggs,
inputs=[style_dd, custom_theme_box],
outputs=[suggestions_output]) # array de strings
# Quando suggestions_output mudar, atualizamos o Radio
suggestions_output.change(
fn=lambda arr: gr.update(choices=arr),
inputs=[suggestions_output],
outputs=[suggestions_display]
)
# Ao clicar em "Iniciar História", chamamos run_story com a ideia selecionada
btn_run_story.click(fn=ui_run_story,
inputs=[suggestions_display],
outputs=[story_html])
demo.launch(server_name="0.0.0.0", server_port=7860)