No backend configuration UI — API key, endpoint URL, and backend priority are invisible to the user #5

Closed
opened 2026-05-13 05:38:15 +00:00 by Mark · 1 comment
Owner

Problem

BackendConfig is persisted to SharedPreferences (key transcriber_backend, field backend_order) but there is no UI to configure it. The ManageScreen only handles Speakers and Subjects. A user who wants to:

  • Set their OpenAI API key for cloud transcription
  • Change the STT endpoint URL
  • Reorder backend priority (e.g., prefer cloud over Android)
  • Select a Whisper model path

Has no way to do this from within the app. The cloud transcription path is therefore unusable without manually editing SharedPreferences via ADB.

Revised Implementation Spec

What to Build

Add a Backend Settings panel to the existing ManageScreen, accessible via a new "Backends" row:

UI Layout

ManageScreen (modified)

├── Speakers (existing)
├── Subjects (existing)
├── Subjects to Record (existing)
├── Speakers to Record (existing)
├── ─────────────────────
└── ⚙ Backends                     ← NEW row, navigates to BackendSettingsScreen

BackendSettingsScreen (new)

┌──────────────────────────────────────┐
│  Backend Priority                    │
│  ┌────────────────────────────────┐  │
│  │ ☰ Cloud                    ⚙  │  │  ← drag handle, tap ⚙ for per-backend config
│  │ ☰ Android                  ⚙  │  │
│  │ ☰ Local Whisper            ⚙  │  │
│  │ ☰ FireOS                   ⚙  │  │
│  └────────────────────────────────┘  │
│                                      │
│  ── Cloud Settings ──               │
│  API Key:    [•••••••••••••••] 👁   │
│  Endpoint:   [https://api.open... ] │
│  Model:      [whisper-1        ▼]  │
│  Language:   [auto             ▼]  │
│                                      │
│  ── Local Whisper Settings ──       │
│  Model Path: [/filesDir/models/...] │
│  Threads:    [4]                     │
│                                      │
│  ── Connection Test ──              │
│  [ Test Cloud Backend ]             │
│  ✓ Connected (120ms)               │  ← result label, green/red
└──────────────────────────────────────┘

Files Changed

File Action
app/.../ui/screens/MainScreen.kt MODIFY — add "Backends" row to ManageScreen
app/.../ui/screens/BackendSettingsScreen.kt NEW — Compose screen for all backend config
app/.../ui/viewmodels/BackendSettingsViewModel.kt NEW — manages state, persists to SharedPreferences
app/.../service/SpeechBackend.kt MODIFY — expose BackendConfig fields for read/write

Validation & Security

  • API key: mask by default, toggle visibility via 👁 button
  • API key: validate format (starts with sk- for OpenAI) on save
  • Endpoint URL: must be valid HTTPS URL
  • Test Connection: POST a short audio clip to verify, show latency
  • Persist immediately on change (no save button — auto-save)

Data Model

data class BackendConfig(
    val priorityOrder: List<SpeechBackendType>,
    val cloudEndpoint: String = "https://api.openai.com/v1/audio/transcriptions",
    val cloudApiKey: String = "",
    val cloudModel: String = "whisper-1",
    val cloudLanguage: String = "auto",
    val localWhisperModelPath: String = "",
    val localWhisperThreads: Int = 4,
)
## Problem `BackendConfig` is persisted to `SharedPreferences` (key `transcriber_backend`, field `backend_order`) but there is no UI to configure it. The `ManageScreen` only handles Speakers and Subjects. A user who wants to: - Set their OpenAI API key for cloud transcription - Change the STT endpoint URL - Reorder backend priority (e.g., prefer cloud over Android) - Select a Whisper model path Has no way to do this from within the app. The cloud transcription path is therefore unusable without manually editing SharedPreferences via ADB. ## Revised Implementation Spec ### What to Build Add a **Backend Settings panel** to the existing `ManageScreen`, accessible via a new "Backends" row: ### UI Layout **ManageScreen** (modified) ``` ├── Speakers (existing) ├── Subjects (existing) ├── Subjects to Record (existing) ├── Speakers to Record (existing) ├── ───────────────────── └── ⚙ Backends ← NEW row, navigates to BackendSettingsScreen ``` **BackendSettingsScreen** (new) ``` ┌──────────────────────────────────────┐ │ Backend Priority │ │ ┌────────────────────────────────┐ │ │ │ ☰ Cloud ⚙ │ │ ← drag handle, tap ⚙ for per-backend config │ │ ☰ Android ⚙ │ │ │ │ ☰ Local Whisper ⚙ │ │ │ │ ☰ FireOS ⚙ │ │ │ └────────────────────────────────┘ │ │ │ │ ── Cloud Settings ── │ │ API Key: [•••••••••••••••] 👁 │ │ Endpoint: [https://api.open... ] │ │ Model: [whisper-1 ▼] │ │ Language: [auto ▼] │ │ │ │ ── Local Whisper Settings ── │ │ Model Path: [/filesDir/models/...] │ │ Threads: [4] │ │ │ │ ── Connection Test ── │ │ [ Test Cloud Backend ] │ │ ✓ Connected (120ms) │ ← result label, green/red └──────────────────────────────────────┘ ``` ### Files Changed | File | Action | |------|--------| | `app/.../ui/screens/MainScreen.kt` | **MODIFY** — add "Backends" row to ManageScreen | | `app/.../ui/screens/BackendSettingsScreen.kt` | **NEW** — Compose screen for all backend config | | `app/.../ui/viewmodels/BackendSettingsViewModel.kt` | **NEW** — manages state, persists to SharedPreferences | | `app/.../service/SpeechBackend.kt` | **MODIFY** — expose `BackendConfig` fields for read/write | ### Validation & Security - API key: mask by default, toggle visibility via 👁 button - API key: validate format (starts with `sk-` for OpenAI) on save - Endpoint URL: must be valid HTTPS URL - Test Connection: POST a short audio clip to verify, show latency - Persist immediately on change (no save button — auto-save) ### Data Model ```kotlin data class BackendConfig( val priorityOrder: List<SpeechBackendType>, val cloudEndpoint: String = "https://api.openai.com/v1/audio/transcriptions", val cloudApiKey: String = "", val cloudModel: String = "whisper-1", val cloudLanguage: String = "auto", val localWhisperModelPath: String = "", val localWhisperThreads: Int = 4, ) ```
Author
Owner

Fixed in commit. Closing.

Fixed in commit. Closing.
Mark closed this issue 2026-05-14 03:31:25 +00:00
Sign in to join this conversation.
No description provided.