188 lines
6.5 KiB
Markdown
188 lines
6.5 KiB
Markdown
# Outbound Voice (demo)
|
|
|
|
> Build spec for Paperclip. **Status: last project.** Do not start until the Hub,
|
|
> the phone app, and Artemis work. Follow the phases in section 11 in order.
|
|
|
|
---
|
|
|
|
## 1. Purpose and outcome
|
|
|
|
A **demonstration of technology**. Show that the system can hold an artificial voice
|
|
conversation: MiniMax supplies the voice, an LLM supplies the words.
|
|
|
|
Sam sets a phone number, a topic, and a tone, then presses **Call now**.
|
|
|
|
**Outcome (the single success statement):**
|
|
> Sam enters a number, a topic, and a tone, presses Call now, and listens to a
|
|
> short, natural conversation driven by the LLM in a MiniMax voice.
|
|
|
|
## 2. Scope
|
|
|
|
**In scope**
|
|
- Set the target number, the topic, the tone, and the goal.
|
|
- Start a call on demand ("Call now").
|
|
- Speech to text the other person; the LLM decides the reply; MiniMax text to speech speaks.
|
|
- Keep the conversation on topic and in tone.
|
|
- End the call gracefully.
|
|
- Store and show the transcript.
|
|
|
|
**Out of scope**
|
|
- Inbound calls.
|
|
- Production or unattended use.
|
|
- Anything safety-critical.
|
|
- WhatsApp, unless it turns out to be simple. Decide in Phase 2.
|
|
|
|
## 3. Users and roles
|
|
|
|
- **Sam only.** This is an operator tool.
|
|
|
|
## 4. Functional requirements
|
|
|
|
| ID | Requirement |
|
|
|---|---|
|
|
| FR-1 | Set a target: phone number, topic, tone, and goal. **Choose the channel:** a phone call, WhatsApp, or Sam's Aussie Broadband service. |
|
|
| FR-2 | Start a call on demand ("Call now"). |
|
|
| FR-3 | Loop: STT the callee → LLM plans the reply → MiniMax TTS speaks it. |
|
|
| FR-4 | Keep the reply on topic and in the chosen tone. |
|
|
| FR-5 | Detect the end and close the call gracefully. |
|
|
| FR-6 | Store the transcript: each turn, who spoke, and the time. |
|
|
| FR-7 | Show a live transcript during the call. |
|
|
| FR-8 | A hard time limit per call. The demo never runs away. |
|
|
| FR-9 | Log the call: number, topic, tone, duration, result. |
|
|
|
|
## 5. Screens and UX flow
|
|
|
|
**Screen: control page**
|
|
1. Fields: target number, topic, tone, goal.
|
|
2. A **Call now** button.
|
|
3. A live transcript panel (speaker, text, time).
|
|
4. A **Hang up** button.
|
|
5. Call history with transcripts.
|
|
|
|
**Main flow**
|
|
```
|
|
Fill the form → Call now → watch the transcript → Hang up (or auto-end) → read the log
|
|
```
|
|
|
|
## 6. Look and feel
|
|
|
|
Reuse the Family Home Lab design system.
|
|
|
|
- Source: `/home/sam/Docker/Containers/family-home-lab/DESIGN.md`
|
|
- Tokens: `/home/sam/Docker/Containers/family-home-lab/portal/static/tokens.css`
|
|
- Copy `tokens.css` into this project.
|
|
|
|
Canvas `#f6f5f4`, one action blue `#0075de`, Inter, 8px grid, pill CTAs. Dark mode.
|
|
|
|
## 7. Data model
|
|
|
|
SQLite inside the service. Suggested:
|
|
|
|
| Table | Holds |
|
|
|---|---|
|
|
| `calls` | number, topic, tone, goal, started-at, ended-at, duration, result |
|
|
| `turns` | call id, speaker (`ai` or `human`), text, created-at |
|
|
| `recordings` | optional audio paths |
|
|
|
|
Retention: keep transcripts for a bounded period. Recordings only if Sam asks.
|
|
|
|
## 8. Integrations
|
|
|
|
| System | Use |
|
|
|---|---|
|
|
| **MiniMax** | Text to speech, and speech to text. Keys already in `environment.d`. |
|
|
| **OmniRoute** | The LLM that plans each reply. |
|
|
| **Telephony** | **To be decided** — see section 13. |
|
|
| **Hub** | Optional. `/ask` is not required. A `/notify` on call end is optional. |
|
|
|
|
## 9. Technology (locked)
|
|
|
|
| Item | Value |
|
|
|---|---|
|
|
| Backend | **Go** |
|
|
| UI | **HTMX** + server-rendered HTML |
|
|
| Database | **SQLite** |
|
|
| Voice | **MiniMax** T2A and STT |
|
|
| LLM | **OmniRoute** |
|
|
| Telephony | **Choose per call:** phone call, WhatsApp, or Aussie Broadband. Providers decided in Phase 2. |
|
|
| Host | `.13`, Docker |
|
|
| Container | **This project's own.** |
|
|
| Port | Allocate one (suggest **8794**). |
|
|
| URL | `voice.lab.audasmedia.com.au` via Caddy on `.35` |
|
|
| Auth | **Separate session login.** |
|
|
|
|
## 10. Rules and constraints
|
|
|
|
1. **It is a demo.** Keep calls short, and set a hard time limit.
|
|
2. **Never call a real person without Sam's explicit action.** No bulk, no cold lists.
|
|
3. Consider whether to disclose that the caller is an AI. Decide in section 13.
|
|
4. Models go through **OmniRoute**, except MiniMax voice.
|
|
5. Secrets come from `environment.d`.
|
|
6. Own folder, own container, own port.
|
|
7. This project writes its own docs.
|
|
|
|
## 11. Build order
|
|
|
|
**Phase 1 — Skeleton and control page**
|
|
Go service, SQLite, session login, the form, Docker, Caddy route.
|
|
*DoD:* the page runs on `.13` and the form saves.
|
|
|
|
**Phase 2 — Telephony (the risk phase)**
|
|
Prove that a call can be placed and that audio flows both ways. Decide the provider
|
|
here.
|
|
*DoD:* a real call connects and the app receives the other person's audio. **If this
|
|
fails, stop and report.**
|
|
|
|
**Phase 3 — The conversation loop**
|
|
STT → LLM → MiniMax TTS, turn by turn.
|
|
*DoD:* a short real conversation happens, with the LLM replying in a MiniMax voice.
|
|
|
|
**Phase 4 — Topic and tone**
|
|
Prompt the LLM from the form's topic, tone, and goal.
|
|
*DoD:* two different tones produce clearly different conversations.
|
|
|
|
**Phase 5 — Transcript**
|
|
Store and display each turn live.
|
|
*DoD:* the transcript is complete after a call.
|
|
|
|
**Phase 6 — Graceful end**
|
|
Detect the end, hang up, enforce the time limit.
|
|
*DoD:* the call ends cleanly at the limit.
|
|
|
|
**Phase 7 — Documentation**
|
|
*DoD:* project-docs run; docs updated.
|
|
|
|
## 12. Acceptance criteria
|
|
|
|
- Sam enters a number, topic, and tone, and presses Call now.
|
|
- A real call connects, and the LLM holds a short on-topic conversation.
|
|
- The tone setting measurably changes the conversation.
|
|
- The transcript is stored and readable.
|
|
- The call ends cleanly at the time limit.
|
|
- It runs in its own container on its own port.
|
|
|
|
## 13. Decisions and remaining questions
|
|
|
|
Resolved:
|
|
1. It is a **demo**, not production.
|
|
2. **Last project.** Do not start early.
|
|
3. MiniMax voice, OmniRoute for the LLM.
|
|
|
|
Resolved:
|
|
1. **Channel is chosen per call:** a phone call, WhatsApp, or Sam's Aussie Broadband
|
|
service.
|
|
|
|
Remaining:
|
|
1. **Telephony providers.** Three channels to prove in Phase 2:
|
|
- **Phone call** — a SIP/cloud provider (for example Twilio), or the Kotlin app
|
|
places the call and routes audio.
|
|
- **WhatsApp** — no public API. Options: WhatsApp Business Cloud API, or screen
|
|
control through `artemis_control`.
|
|
- **Aussie Broadband — mobile.** Confirmed as a mobile service. Confirm whether
|
|
it exposes an API, SIP, or only a SIM.
|
|
**Phase 2 proves at least one channel end to end.**
|
|
2. Which channel is the default?
|
|
3. One-way (speak a message) or two-way (hold a conversation)? The demo implies two-way.
|
|
4. Do we disclose that the caller is an AI? Recommend yes.
|
|
5. Which number does it call from, and who pays for it?
|