File size: 8,354 Bytes
7687a98
f38792f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
762671d
f38792f
 
 
 
 
 
762671d
f38792f
e406699
f38792f
 
 
3c51c8e
f38792f
 
 
 
 
 
 
 
 
 
 
 
 
3c51c8e
f38792f
 
 
 
 
 
 
 
 
 
 
 
 
 
3c51c8e
f38792f
 
3c51c8e
f38792f
 
 
 
 
 
 
 
 
 
 
7687a98
f38792f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7687a98
f38792f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7687a98
f38792f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b4da423
f38792f
 
 
 
 
 
 
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
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)