You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.0 KiB
5.0 KiB
🇮🇹 Italiano Vivo
App de italiano situacional-first com voz livre e scoring de inteligibilidade. Aprenda como uma criança: errando mas se comunicando.
Visão
- Scoring em 3 eixos: Sentido transmitido / Naturalidade / Precisão gramatical
- Tolerância estilo criança: erro gramatical que não impede entendimento = sucesso comunicativo
- Voz livre: grave, receba feedback estruturado, nunca "Errado"
- Salvavidas (Salvavita): treine estratégias de comunicação quando a palavra some
- SRS de chunks: revisão espaçada de frases, não palavras isoladas
- PWA offline: catálogo, áudio e SRS funcionam sem conexão
- CEFR can-do: badges baseados em competências reais ("você consegue reclamar de um item com defeito")
Como Rodar
Pré-requisitos
- Node.js ≥ 20
- LiteLLM proxy rodando (ou configure
LITELLM_BASE_URLpara outro endpoint OpenAI-compatible)
Instalação
# Instalar dependências do monorepo
npm install
# Configurar variáveis de ambiente
cp .env.example server/.env
# Edite server/.env com sua chave da API
Desenvolvimento
# Roda app + server simultaneamente
npm run dev
- App: http://localhost:5173
- Server: http://localhost:8787
- Health check: http://localhost:8787/health
Build
npm run build # Build server + app
npm run typecheck # Verificação de tipos
Endpoints do Server
| Método | Rota | Descrição |
|---|---|---|
| GET | /health |
Status do servidor |
| POST | /api/judge |
Avalia fala do aluno em 3 eixos (sentido, naturalidade, gramática) |
| POST | /api/transcribe |
Transcreve áudio via modelo omni (ASR tolerante a sotaque) |
| GET | /api/tts-proxy?text=...&voice=elsa|diego |
Serve áudio TTS pré-gerado do cache local |
POST /api/judge
Entrada:
{
"missionId": "bambino-m01",
"scenario": "Al bar",
"learnerGoalPt": "Pedir um café",
"expectedIt": "Vorrei un caffè, per favore",
"utteranceText": "io volere caffe",
"transcriptRaw": "io volere caffe",
"audioBase64": "..."
}
Saída:
{
"meaning_conveyed": "full",
"naturalness": 45,
"natural_version": "Vorrei un caffè, per favore",
"grammar": [
{
"it_said": "io volere",
"problem_pt": "Infinitivo em vez de conjugação",
"fix_it": "vorrei / voglio",
"severity": "minor"
}
],
"next_move": {
"italian": "Certo! Un caffè. Lo vuole al banco o al tavolo?",
"portuguese": "Claro! Um café. Quer no balcão ou na mesa?"
},
"praise_or_push": "Quase lá! Um italiano diria: Vorrei un caffè, per favore"
}
Estrutura de Pastas
cursoitaliano/
├── app/ # PWA React + Vite + TypeScript
│ ├── public/ # manifest.webmanifest, ícones
│ └── src/
│ ├── db/db.ts # IndexedDB via Dexie
│ ├── engine/srs.ts # SM-2 simplificado
│ ├── types/content.ts # Tipos do conteúdo JSON
│ ├── App.tsx # Componente principal
│ ├── main.tsx # Entry point
│ └── styles.css # Design system
├── server/ # Node + Express + TypeScript
│ ├── cache/audio/ # Áudios TTS pré-gerados (offline)
│ └── src/
│ ├── lib/llm.ts # Cliente LiteLLM singleton
│ ├── routes/
│ │ ├── judge.ts # Motor de feedback 3 eixos
│ │ ├── transcribe.ts # ASR via omni model
│ │ └── tts.ts # Proxy de áudio TTS
│ └── index.ts # Express app
├── content/ # JSONs versionados (gerados por pipeline)
├── audio/ # Assets de áudio por missão
├── SPEC.md # Especificação completa do produto
├── .env.example # Template de variáveis de ambiente
└── package.json # Monorepo root (npm workspaces)
Modelos Utilizados
| Modelo | Uso | Variável |
|---|---|---|
| qwen3.8-max | Juiz de feedback, geração de missões | CHAT_MODEL |
| qwen3.8-flash | Drills rápidos, fallback de quota | FAST_MODEL |
| qwen3-omni-flash | Transcrição de áudio (ASR) | OMNI_MODEL |
Todos acessados via LiteLLM proxy (LITELLM_BASE_URL).
Roadmap
- Esqueleto do monorepo (app PWA + server LiteLLM)
- Geração de conteúdo: Trilha Bambino (B1-B12) + Viaggio (V1-V6) = 18 missões
- Pipeline de geração de áudio TTS (edge-tts) — ~479 arquivos mp3
- Judge 3-eixos CEFR com tolerância estilo criança
- SRS de chunks com Dexie/IndexedDB
- Service Worker para modo offline completo
- Minijogo "descreva sem nomear" (circunlóquio)
- Modo carro/shadowing com medição de lag
- Trilhas restantes (Viaggio M7–M15, Vivere completa)
- Preparatório CILS/CELI B1 cidadania
- Wrapper Android (Capacitor)
- Calibração do judge com votos "isso estava certo"
Licença
Privado — uso pessoal.