A web app that lets a nonverbal person take part in a conversation by choosing from response options the AI generates, rather than speaking.
The verbal partner says something β an "AI ear" listens β it offers the person several ways to reply (agree, stay neutral, gently push back, ask a question, keep it light, or share an opinion) β the person (or a trusted person) taps the option that fits. That chosen reply is their voice.
Human talk is largely predictable moves β agreeing, staying neutral,
disagreeing, showing interest, keeping it light, steering. AIVoice turns each
of those moves into a selectable option, so a person who can't speak is
expressing the same conversational intent, just by choosing.
- Chat interface β verbal partner's words on the right, the person's chosen replies on the left (tagged with the direction they chose).
- Response options β 4-6 different conversational directions to pick from on every exchange.
- Typed replies β a trusted person can type a custom reply on their behalf.
- Speech-to-text π€ β the verbal partner can speak instead of typing (browser Web Speech API, no key).
- Text-to-speech π β every message can be read aloud, each option can be heard before choosing, and the chosen reply is spoken automatically β the person's voice.
- Profile β name, age, closeness, personality traits, likes, a long free-form "about this person" field (more detail = better responses), and which directions to offer.
- Age-appropriateness is enforced β it's written into the system prompt as a hard rule. A 20-year-old profile gets 20-year-old language; a 6-year-old profile never gets adult language, no matter what the conversation partner says.
- Multiple LLM providers β OpenAI, DeepSeek, OpenRouter, Ollama (local), Anthropic, and Gemini, plus a built-in no-key demo provider so you can try it instantly.
Live at https://aivoice.val.run β open the Profile & Setup tab first to describe the person (especially age), then use the Conversation tab.
Rendering mermaid diagram...
The demo provider works with no configuration. To use a real LLM provider, add the matching key in the val's environment settings β the provider then produces responses tailored to the person's profile:
| Provider | Env vars |
|---|---|
| OpenAI | OPENAI_API_KEY Β· OPENAI_MODEL (opt) |
| DeepSeek | DEEPSEEK_API_KEY Β· DEEPSEEK_MODEL (opt) |
| OpenRouter | OPENROUTER_API_KEY Β· OPENROUTER_MODEL (opt) |
| Ollama | OLLAMA_BASE_URL (point at a reachable/tunneled endpoint; http://localhost:11434/v1 is the default) Β· OLLAMA_MODEL (opt) |
| Anthropic | ANTHROPIC_API_KEY Β· ANTHROPIC_MODEL (opt) |
| Gemini | GEMINI_API_KEY Β· GEMINI_MODEL (opt) |
Pick the provider inside the Profile & Setup tab. If the chosen provider is unreachable or lacks a key, the app falls back to the demo provider so a conversation never hard-stops.
index.ts Hono server (frontend + JSON API)
store.ts Types + SQLite (profile, conversation, pending options)
llm.ts Multi-provider LLM abstraction + demo provider
prompts.ts Direction taxonomy + age-appropriate prompt building
frontend/
root.tsx HTML shell
index.tsx React entrypoint
components/App.tsx Chat + profile UI
Conversations and the profile are stored in the val's own project-scoped SQLite database, isolated to this val. To keep the VULNERABLE edge cases clear: a caregiver writing a child's profile should keep the age field accurate, since it is the strongest guard rail for language level.