Site completo com Python: frontend e backend com IA

Traduzido do original em espanhol. Ler em espanhol

Hoje em dia, você pode construir sites modernos só com Python, tanto no frontend quanto no backend, e integrar inteligência artificial para criar experiências avançadas. Aqui mostro como fazer isso com segurança, usando como exemplo um gerador de histórias para crianças.

Live Demo: https://bedtimestory.zerogap.uk/


Arquitetura

  • Frontend: NiceGUI para uma interface web moderna, sem JavaScript.
  • Backend: FastAPI para a lógica.
  • IA: Azure OpenAI (usando LangChain) para gerar histórias ou qualquer outra tarefa de linguagem natural.

Exemplo: gerador de histórias com IA

O código a seguir mostra como integrar frontend e backend, e como proteger seus endpoints usando validação.

Backend (FastAPI + Azure OpenAI via LangChain)

from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel, validator
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from langchain_community.chat_models import AzureChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
import os
import re
from dotenv import load_dotenv

app = FastAPI()

def whitelist(text, max_length=50, pattern=r"[^a-zA-Z0-9áéíóúÁÉÍÓÚüÜñÑ\s.,;:!?'\"()-]"):
    """Allow only letters, numbers, punctuation and spaces up to max_length."""
    if text is None:
        return None
    # Remove any disallowed character
    clean = re.sub(pattern, "", text)
    # Truncate and strip
    return clean.strip()[:max_length]

class StoryRequest(BaseModel):
    theme: str = None
    main_character: str = None

    @validator('theme', 'main_character')
    def validate_field(cls, v):
        if v is not None:
            # Only allow reasonable length and allowed characters
            v = whitelist(v)
            if len(v) == 0:
                raise ValueError("Field cannot be empty after sanitization.")
        return v

@app.post("/generate")
async def generate_story(request: StoryRequest, fastapi_request: Request):
    # Only allow local requests for security
    client_host = fastapi_request.client.host
    if client_host not in ("127.0.0.1", "::1", "localhost"):
        raise HTTPException(status_code=403, detail="Forbidden")

    load_dotenv()
    endpoint = "https://your-private-resource.openai.azure.com/"
    deployment = "my-private-deployment"
    api_version = "2024-12-01-preview"
    credential = DefaultAzureCredential()
    token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default")

    prompt = f"Write a children's story about {request.theme or 'friendship'}, starring a {request.main_character or 'dragon'}."
    system_prompt = "You are a creative children's storyteller. Only return the story."

    messages = [
        SystemMessage(content=system_prompt),
        HumanMessage(content=prompt)
    ]

    chat = AzureChatOpenAI(
        azure_endpoint=endpoint,
        api_version=api_version,
        deployment_name=deployment,
        azure_ad_token_provider=token_provider,
    )
    response = chat(messages)

    return JSONResponse({"text": response.content})

Frontend (NiceGUI)

from nicegui import ui

def generate_story():
    import httpx
    try:
        resp = httpx.post("http://localhost:8080/generate", json={})
        story = resp.json().get("text", "No story generated.")
        output_label.text = story
    except Exception as e:
        output_label.text = f"Error: {e}"

with ui.element('div').style('background-color: rgb(232 226 254);') \
          .classes('flex items-center justify-center absolute top-0 left-0 full-width full-height'):
    with ui.element('div').classes('full-width full-height flex flex-col items-center justify-center relative'):
        ui.image('assets/home.jpg').props('fit=contain').classes(
            'rounded-2xl w-full h-auto object-contain max-w-[95vw] max-h-[95vh]'
        )
        with ui.row().classes(
            'absolute bottom-0 left-[10vw] right-[10vw] px-8 flex flex-col md:flex-row flex-wrap items-center justify-between z-10 mb-[8vh]'
        ):
            ui.button(
                'SURPRISE ME!',
                on_click=generate_story
            ).classes(
                '!bg-yellow-400 !hover:bg-yellow-400 text-white rounded-full '
                'px-6 py-3 text-base font-bold flex items-center shadow-lg mr-4'
            ).props('icon=play_circle size=md')

output_label = ui.label("").classes("mt-6 text-lg")

ui.run()

Segurança e boas práticas para produção

  • HTTPS: Nunca exponha seu site sem HTTPS. Use o Nginx como proxy reverso e um certificado SSL (por exemplo, Let’s Encrypt).
  • Sanitização e validação: O exemplo usa validação robusta (tamanho, caracteres permitidos, campos obrigatórios) para evitar ataques de injeção e abuso.
  • Proxy reverso (Nginx):
    Exemplo básico:
  server {
      listen 443 ssl;
      server_name tu-dominio.com;

      ssl_certificate /etc/letsencrypt/live/tu-dominio.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/tu-dominio.com/privkey.pem;

      location / {
          proxy_pass http://127.0.0.1:8081;  # puerto NiceGUI
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
      }
  }

Maximiliano Díaz Doglia

AI Platform Engineer & Full-Stack Developer
Building Enterprise Integrations & Automations

Publicado em: IA