Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,54 +1,375 @@
|
|
| 1 |
"""
|
| 2 |
-
|
| 3 |
-
Aula 9: Hugging Face Spaces
|
|
|
|
|
|
|
| 4 |
"""
|
| 5 |
|
| 6 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
"""
|
| 10 |
-
Função simples para testar o Gradio
|
| 11 |
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
"""
|
| 19 |
-
mensagem = f"""
|
| 20 |
-
🎉 Olá, {nome}!
|
| 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 |
# Lançar aplicação
|
| 53 |
if __name__ == "__main__":
|
| 54 |
-
|
|
|
|
| 1 |
"""
|
| 2 |
+
GERADOR DE POSTS PARA REDES SOCIAIS
|
| 3 |
+
Aula 9: Versão Web com Hugging Face Spaces + Gradio
|
| 4 |
+
|
| 5 |
+
Transforma o código da Aula 8 (Google Colab) em aplicação web
|
| 6 |
"""
|
| 7 |
|
| 8 |
import gradio as gr
|
| 9 |
+
import requests
|
| 10 |
+
import os
|
| 11 |
+
from datetime import datetime
|
| 12 |
+
from PIL import Image
|
| 13 |
+
from io import BytesIO
|
| 14 |
+
|
| 15 |
+
# API Key vem dos Secrets (configurado em Settings)
|
| 16 |
+
HUGGINGFACE_API_KEY = os.environ.get("HF_TOKEN")
|
| 17 |
+
|
| 18 |
+
# Verificar se API key existe
|
| 19 |
+
if not HUGGINGFACE_API_KEY:
|
| 20 |
+
raise ValueError("⚠️ API Key não configurada! Configure HF_TOKEN nos Secrets")
|
| 21 |
+
|
| 22 |
+
# URLs e modelos (SEM símbolos < >)
|
| 23 |
+
BASE_URL = "https://router.huggingface.co/v1"
|
| 24 |
+
MODELO_TEXTO = "meta-llama/Llama-3.1-8B-Instruct"
|
| 25 |
+
MODELO_IMAGEM = "black-forest-labs/FLUX.1-schnell"
|
| 26 |
+
|
| 27 |
+
# Headers para requisições
|
| 28 |
+
headers = {
|
| 29 |
+
"Authorization": f"Bearer {HUGGINGFACE_API_KEY}",
|
| 30 |
+
"Content-Type": "application/json"
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
# Opções da interface
|
| 34 |
+
NICHOS_DISPONIVEIS = [
|
| 35 |
+
"Fitness e Vida Saudável",
|
| 36 |
+
"Alimentação e Nutrição",
|
| 37 |
+
"Motivação e Desenvolvimento Pessoal",
|
| 38 |
+
"Negócios e Empreendedorismo",
|
| 39 |
+
"Viagens e Turismo",
|
| 40 |
+
"Tecnologia e Inovação"
|
| 41 |
+
]
|
| 42 |
+
|
| 43 |
+
ESTILOS_DISPONIVEIS = [
|
| 44 |
+
"Inspirador e motivacional",
|
| 45 |
+
"Educativo e informativo",
|
| 46 |
+
"Divertido e descontraído",
|
| 47 |
+
"Profissional e técnico"
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
|
| 51 |
+
# ============================================
|
| 52 |
+
# FUNÇÕES DE GERAÇÃO (adaptadas da Aula 8)
|
| 53 |
+
# ============================================
|
| 54 |
+
|
| 55 |
+
def gerar_texto(tema, nicho, estilo):
|
| 56 |
+
"""
|
| 57 |
+
Gera texto usando API do Hugging Face
|
| 58 |
+
|
| 59 |
+
Diferença da Aula 8:
|
| 60 |
+
- Aula 8: função imprimia no console
|
| 61 |
+
- Aula 9: função retorna string (para o Gradio)
|
| 62 |
"""
|
|
|
|
| 63 |
|
| 64 |
+
url = f"{BASE_URL}/chat/completions"
|
| 65 |
+
|
| 66 |
+
payload = {
|
| 67 |
+
"model": MODELO_TEXTO,
|
| 68 |
+
"messages": [
|
| 69 |
+
{
|
| 70 |
+
"role": "system",
|
| 71 |
+
"content": f"Você é um criador de conteúdo especializado em {nicho}."
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"role": "user",
|
| 75 |
+
"content": f"""Crie uma legenda criativa para Instagram sobre: {tema}
|
| 76 |
+
|
| 77 |
+
Requisitos:
|
| 78 |
+
- Estilo: {estilo}
|
| 79 |
+
- Tamanho: 100-150 palavras
|
| 80 |
+
- Estrutura: gancho inicial + desenvolvimento + call-to-action
|
| 81 |
+
- Incluir 4-5 hashtags relevantes no final
|
| 82 |
+
- Tom: próximo, empático e motivador
|
| 83 |
+
- Usar no máximo 3 emojis
|
| 84 |
+
|
| 85 |
+
Escreva apenas a legenda, sem introduções ou explicações."""
|
| 86 |
+
}
|
| 87 |
+
],
|
| 88 |
+
"max_tokens": 350,
|
| 89 |
+
"temperature": 0.7,
|
| 90 |
+
"stream": False
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
try:
|
| 94 |
+
response = requests.post(url, headers=headers, json=payload, timeout=60)
|
| 95 |
|
| 96 |
+
if response.status_code == 200:
|
| 97 |
+
resultado = response.json()
|
| 98 |
+
texto = resultado['choices'][0]['message']['content'].strip()
|
| 99 |
+
return texto
|
| 100 |
+
else:
|
| 101 |
+
return f"❌ Erro ao gerar texto: {response.status_code}\\n{response.text}"
|
| 102 |
+
|
| 103 |
+
except Exception as e:
|
| 104 |
+
return f"❌ Erro: {str(e)}"
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def gerar_imagem(descricao):
|
| 108 |
+
"""
|
| 109 |
+
Gera imagem usando API do Hugging Face
|
| 110 |
+
|
| 111 |
+
Diferença da Aula 8:
|
| 112 |
+
- Aula 8: salvava arquivo .png
|
| 113 |
+
- Aula 9: retorna objeto PIL Image (Gradio mostra automaticamente)
|
| 114 |
"""
|
|
|
|
|
|
|
| 115 |
|
| 116 |
+
try:
|
| 117 |
+
from huggingface_hub import InferenceClient
|
| 118 |
+
|
| 119 |
+
client = InferenceClient(api_key=HUGGINGFACE_API_KEY)
|
| 120 |
|
| 121 |
+
# Adicionar prompt engineering para melhor qualidade
|
| 122 |
+
prompt = f"{descricao}, professional photography, vibrant colors, high quality, 4k"
|
| 123 |
+
|
| 124 |
+
# Gerar imagem
|
| 125 |
+
image = client.text_to_image(
|
| 126 |
+
prompt=prompt,
|
| 127 |
+
model=MODELO_IMAGEM
|
| 128 |
+
)
|
| 129 |
|
| 130 |
+
return image # Retorna objeto PIL Image
|
| 131 |
+
|
| 132 |
+
except Exception as e:
|
| 133 |
+
print(f"Erro ao gerar imagem: {str(e)}")
|
| 134 |
+
return None
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
# ============================================
|
| 138 |
+
# FUNÇÃO PRINCIPAL PARA O GRADIO
|
| 139 |
+
# ============================================
|
| 140 |
+
|
| 141 |
+
def gerar_post_interface(tema, nicho, estilo, descricao_imagem, gerar_img):
|
| 142 |
"""
|
| 143 |
+
Função principal que o Gradio chama quando usuário clica no botão.
|
| 144 |
+
|
| 145 |
+
IMPORTANTE: Esta função é diferente da Aula 8!
|
| 146 |
+
|
| 147 |
+
Aula 8 (Colab):
|
| 148 |
+
- Função imprimia resultados
|
| 149 |
+
- Salvava arquivos
|
| 150 |
+
- Usávamos print()
|
| 151 |
+
|
| 152 |
+
Aula 9 (Spaces):
|
| 153 |
+
- Função RETORNA valores
|
| 154 |
+
- Gradio mostra automaticamente
|
| 155 |
+
- Usamos return
|
| 156 |
|
| 157 |
+
Parâmetros (vindos dos campos da interface):
|
| 158 |
+
tema: str - tema digitado pelo usuário
|
| 159 |
+
nicho: str - dropdown selecionado
|
| 160 |
+
estilo: str - radio button selecionado
|
| 161 |
+
descricao_imagem: str - descrição para imagem
|
| 162 |
+
gerar_img: bool - checkbox (True/False)
|
| 163 |
+
|
| 164 |
+
Retorna (para o Gradio mostrar):
|
| 165 |
+
texto: str - legenda gerada
|
| 166 |
+
imagem: PIL.Image ou None - imagem gerada
|
| 167 |
+
status: str - mensagem de status
|
| 168 |
+
"""
|
| 169 |
+
|
| 170 |
+
# Validação de entrada
|
| 171 |
+
if not tema or len(tema.strip()) < 3:
|
| 172 |
+
return (
|
| 173 |
+
"⚠️ Por favor, digite um tema válido (mínimo 3 caracteres).",
|
| 174 |
+
None,
|
| 175 |
+
"❌ Validação falhou"
|
| 176 |
)
|
| 177 |
+
|
| 178 |
+
# Etapa 1: Gerar texto
|
| 179 |
+
status_atual = "⏳ Gerando texto..."
|
| 180 |
+
texto = gerar_texto(tema, nicho, estilo)
|
| 181 |
+
|
| 182 |
+
# Verificar se houve erro
|
| 183 |
+
if texto.startswith("❌"):
|
| 184 |
+
return texto, None, "❌ Erro ao gerar texto"
|
| 185 |
+
|
| 186 |
+
# Etapa 2: Gerar imagem (se solicitado)
|
| 187 |
+
imagem = None
|
| 188 |
+
if gerar_img:
|
| 189 |
+
# Validar descrição da imagem
|
| 190 |
+
if not descricao_imagem or len(descricao_imagem.strip()) < 3:
|
| 191 |
+
descricao_imagem = f"{tema} related image, professional photography"
|
| 192 |
+
|
| 193 |
+
status_atual = "⏳ Gerando imagem..."
|
| 194 |
+
imagem = gerar_imagem(descricao_imagem)
|
| 195 |
+
|
| 196 |
+
if imagem is None:
|
| 197 |
+
status_final = "⚠️ Texto gerado, mas houve erro na imagem"
|
| 198 |
+
else:
|
| 199 |
+
status_final = "✅ Post completo gerado com sucesso!"
|
| 200 |
+
else:
|
| 201 |
+
status_final = "✅ Texto gerado com sucesso!"
|
| 202 |
+
|
| 203 |
+
# Retornar 3 valores (um para cada output do Gradio)
|
| 204 |
+
return texto, imagem, status_final
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
# ============================================
|
| 208 |
+
# INTERFACE GRADIO
|
| 209 |
+
# ============================================
|
| 210 |
+
|
| 211 |
+
# Usar gr.Blocks para layout customizado
|
| 212 |
+
with gr.Blocks(theme=gr.themes.Soft(), title="Gerador de Posts") as demo:
|
| 213 |
+
|
| 214 |
+
# Cabeçalho
|
| 215 |
+
gr.Markdown("""
|
| 216 |
+
# 🚀 Gerador de Posts para Redes Sociais
|
| 217 |
+
### Crie legendas profissionais e imagens com IA em segundos!
|
| 218 |
+
|
| 219 |
+
**Como usar:**
|
| 220 |
+
1. Escolha seu nicho e estilo
|
| 221 |
+
2. Digite o tema do post
|
| 222 |
+
3. (Opcional) Adicione descrição para imagem
|
| 223 |
+
4. Clique em **Gerar Post**
|
| 224 |
+
""")
|
| 225 |
+
|
| 226 |
+
# Dividir em 2 colunas
|
| 227 |
+
with gr.Row():
|
| 228 |
+
# COLUNA ESQUERDA: Inputs
|
| 229 |
+
with gr.Column(scale=1):
|
| 230 |
+
gr.Markdown("### ⚙️ Configurações do Post")
|
| 231 |
+
|
| 232 |
+
# Dropdown para nicho
|
| 233 |
+
nicho_input = gr.Dropdown(
|
| 234 |
+
choices=NICHOS_DISPONIVEIS,
|
| 235 |
+
value=NICHOS_DISPONIVEIS[0],
|
| 236 |
+
label="Nicho",
|
| 237 |
+
info="Escolha a área de atuação do seu conteúdo"
|
| 238 |
+
)
|
| 239 |
+
|
| 240 |
+
# Radio buttons para estilo
|
| 241 |
+
estilo_input = gr.Radio(
|
| 242 |
+
choices=ESTILOS_DISPONIVEIS,
|
| 243 |
+
value=ESTILOS_DISPONIVEIS[0],
|
| 244 |
+
label="Estilo de Escrita",
|
| 245 |
+
info="Tom e abordagem da sua legenda"
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
# Campo de texto para tema
|
| 249 |
+
tema_input = gr.Textbox(
|
| 250 |
+
label="Tema do Post",
|
| 251 |
+
placeholder="Ex: motivação para treinar no inverno",
|
| 252 |
+
lines=2,
|
| 253 |
+
info="Seja específico para melhores resultados"
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
gr.Markdown("### 🎨 Imagem (Opcional)")
|
| 257 |
+
|
| 258 |
+
# Checkbox para gerar imagem
|
| 259 |
+
gerar_img_checkbox = gr.Checkbox(
|
| 260 |
+
label="Gerar imagem junto com o texto",
|
| 261 |
+
value=True,
|
| 262 |
+
info="Desmarque para gerar apenas texto (mais rápido)"
|
| 263 |
+
)
|
| 264 |
+
|
| 265 |
+
# Campo para descrição da imagem
|
| 266 |
+
descricao_img_input = gr.Textbox(
|
| 267 |
+
label="Descrição da Imagem (em inglês)",
|
| 268 |
+
placeholder="Ex: person exercising at gym, motivated",
|
| 269 |
+
lines=2,
|
| 270 |
+
info="Descreva o que deve aparecer na imagem"
|
| 271 |
+
)
|
| 272 |
+
|
| 273 |
+
# Botão de gerar
|
| 274 |
+
gerar_btn = gr.Button(
|
| 275 |
+
"✨ Gerar Post",
|
| 276 |
+
variant="primary",
|
| 277 |
+
size="lg"
|
| 278 |
+
)
|
| 279 |
+
|
| 280 |
+
# COLUNA DIREITA: Outputs
|
| 281 |
+
with gr.Column(scale=1):
|
| 282 |
+
gr.Markdown("### 📋 Resultado")
|
| 283 |
+
|
| 284 |
+
# Status da geração
|
| 285 |
+
status_output = gr.Textbox(
|
| 286 |
+
label="Status",
|
| 287 |
+
value="Aguardando...",
|
| 288 |
+
interactive=False,
|
| 289 |
+
max_lines=1
|
| 290 |
+
)
|
| 291 |
+
|
| 292 |
+
# Texto gerado
|
| 293 |
+
texto_output = gr.Textbox(
|
| 294 |
+
label="Legenda Gerada",
|
| 295 |
+
lines=12,
|
| 296 |
+
show_copy_button=True,
|
| 297 |
+
info="Clique no ícone para copiar!"
|
| 298 |
+
)
|
| 299 |
+
|
| 300 |
+
# Imagem gerada
|
| 301 |
+
imagem_output = gr.Image(
|
| 302 |
+
label="Imagem Gerada",
|
| 303 |
+
type="pil",
|
| 304 |
+
height=400
|
| 305 |
+
)
|
| 306 |
+
|
| 307 |
+
# Exemplos prontos (aparecem abaixo)
|
| 308 |
+
gr.Markdown("### 💡 Experimente estes exemplos:")
|
| 309 |
+
gr.Examples(
|
| 310 |
+
examples=[
|
| 311 |
+
[
|
| 312 |
+
"motivação para treinar no frio",
|
| 313 |
+
"Fitness e Vida Saudável",
|
| 314 |
+
"Inspirador e motivacional",
|
| 315 |
+
"person exercising outdoors in winter, motivated, energetic",
|
| 316 |
+
True
|
| 317 |
+
],
|
| 318 |
+
[
|
| 319 |
+
"receita saudável de café da manhã",
|
| 320 |
+
"Alimentação e Nutrição",
|
| 321 |
+
"Educativo e informativo",
|
| 322 |
+
"healthy breakfast bowl, colorful fruits, wooden table",
|
| 323 |
+
True
|
| 324 |
+
],
|
| 325 |
+
[
|
| 326 |
+
"dicas de produtividade para empreendedores",
|
| 327 |
+
"Negócios e Empreendedorismo",
|
| 328 |
+
"Profissional e técnico",
|
| 329 |
+
"productive workspace, organized desk, laptop",
|
| 330 |
+
False
|
| 331 |
+
]
|
| 332 |
+
],
|
| 333 |
+
inputs=[
|
| 334 |
+
tema_input,
|
| 335 |
+
nicho_input,
|
| 336 |
+
estilo_input,
|
| 337 |
+
descricao_img_input,
|
| 338 |
+
gerar_img_checkbox
|
| 339 |
+
]
|
| 340 |
+
)
|
| 341 |
+
|
| 342 |
+
# Conectar botão com função
|
| 343 |
+
# Quando botão é clicado:
|
| 344 |
+
# 1. Gradio pega valores dos inputs
|
| 345 |
+
# 2. Chama gerar_post_interface()
|
| 346 |
+
# 3. Recebe os 3 retornos
|
| 347 |
+
# 4. Mostra nos outputs correspondentes
|
| 348 |
+
gerar_btn.click(
|
| 349 |
+
fn=gerar_post_interface,
|
| 350 |
+
inputs=[
|
| 351 |
+
tema_input,
|
| 352 |
+
nicho_input,
|
| 353 |
+
estilo_input,
|
| 354 |
+
descricao_img_input,
|
| 355 |
+
gerar_img_checkbox
|
| 356 |
+
],
|
| 357 |
+
outputs=[
|
| 358 |
+
texto_output,
|
| 359 |
+
imagem_output,
|
| 360 |
+
status_output
|
| 361 |
+
],
|
| 362 |
+
show_progress="full"
|
| 363 |
+
)
|
| 364 |
+
|
| 365 |
+
# Footer
|
| 366 |
+
gr.Markdown("""
|
| 367 |
+
---
|
| 368 |
+
**Desenvolvido no Curso de Python com IA** |
|
| 369 |
+
🤖 Powered by Llama 3.1 & FLUX |
|
| 370 |
+
⚡ Hugging Face Spaces + Gradio
|
| 371 |
+
""")
|
| 372 |
|
| 373 |
# Lançar aplicação
|
| 374 |
if __name__ == "__main__":
|
| 375 |
+
demo.launch()
|