Files
fegger 2cf785746e M3c: meeting summaries and agenda coverage via Ollama
- meetrec-server: Ollama integration (chat API, gemma4:12b, num_ctx
  32768); German structured summary (topic/points/decisions/to-dos)
  written to summary.md; agenda coverage returns strict JSON (covered,
  time, evidence) parsed defensively; both run automatically in a
  background thread after upload plus manual trigger endpoints
  (POST /summary, POST /agenda) with status tracking in the index
- phone: agenda input on the Record tab (one item per line, persisted)
  is uploaded with the recording; Library detail shows the summary and
  a per-item agenda checklist with timestamps and evidence quotes,
  with polling while the server generates and manual re-trigger buttons
- validated end-to-end against the live Ollama server: crafted German
  test meeting produced a correct structured summary and perfect agenda
  discrimination (covered items with correct timestamps + quotes,
  undiscussed item correctly false)
2026-09-08 12:32:20 +02:00

113 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MeetRec for Android
Native Android app with the same functionality as the desktop meetrec:
record meetings and transcribe them on-device with Whisper. Nothing leaves
the phone — no cloud, no telemetry.
Status: **M2.5 (remote transcription)** — record on the phone while a
remote whisper.cpp server (GPU) provides live and final transcripts.
The phone's local whisper.cpp engine remains as the offline fallback.
## Transcription targets
**phone** — the app's local whisper.cpp engine (JNI/NEON): pick a model
(tiny/base for live, e.g. small for the final pass). Measured on the
Fairphone 6: ~0.60.8× realtime, so keep local models small.
**server** — a remote [whisper.cpp server](../whisper-server/)
(Docker Compose, Vulkan GPU) transcribes BOTH the live pass and the final
pass; the model lives on the server (e.g. large-v3). The phone only
records and displays. Set the server URL in the app (persisted; e.g.
`http://100.103.83.12:8085` over Tailscale — the phone needs Tailscale
too). Local model selection is greyed out in this mode.
## Recording library (meetrec-server)
Finished recordings (WAV + txt/srt/json) upload automatically to the
[meetrec-server](../meetrec-server/) storage service. Set the **Library
URL** in the app (`http://100.103.83.12:8090`, persisted) or leave it
empty to disable upload. Uploads run in the background after the final
pass; the status line reports the result.
The **Library** tab browses everything:
- *On this phone* — local recordings (with or without transcripts)
- *On the server* — stored bundles with date, duration, language
- Detail view: timestamped transcript, audio playback (streamed from
the server or from the local file), share, and delete with
confirmation. Refresh reloads both lists.
## Summaries and agenda (Ollama)
Enter **agenda items on the Record tab (one per line, persisted)** before
recording. After the recording uploads, meetrec-server automatically:
1. writes a German **summary** (gemma4:12b via your Ollama server):
topic, key points, decisions, to-dos — shown on the recording's
detail page
2. checks **which agenda items were actually discussed** — the detail
page shows a ✓/✗ checklist with the timestamp and a quote as evidence
Both can be re-triggered from the detail page ("Neu erstellen" /
"Agenda neu prüfen"). Note: very long meetings may exceed the LLM's
context window (the transcript is then truncated).
## Requirements
- Android Studio (or: SDK Platform 36, Build Tools 36, NDK 27.1, CMake 3.22.1)
- JDK 17+
- Device running Android 10+ (developed against a Fairphone 6 / Snapdragon
7s Gen 3, Android 15+)
## Build
```sh
cd android
./tools/fetch-whisper.sh # vendors whisper.cpp v1.9.3 into third_party/
./gradlew :app:assembleDebug # or open the android/ folder in Android Studio
adb install -r app/build/outputs/apk/debug/app-debug.apk
```
`third_party/whisper.cpp` is gitignored — the fetch script pins the exact
release tag so the JNI layer never breaks on upstream churn.
## Test on device
1. Pick **Transcribe on: phone or server**. For server: enter the URL
(needs Tailscale on the phone for a Tailscale-only server).
2. Phone mode: Download + Load engine first (tiny is fine for a start).
3. Tap **Record** — live transcript lines appear every few seconds.
4. Tap **Stop** — the final pass runs automatically and writes
`<stem>.txt/.srt/.json` next to the WAV.
5. Share the transcript via the share sheet. You can also pick any PCM WAV
file and transcribe it manually.
Expect roughly realtime transcription with `tiny`/`base` on the
Fairphone 6's CPU; `small` is noticeably slower — use it for final passes
only (the live/final split comes with the recorder milestones).
## Performance notes
- The engine runs on CPU via NEON, using up to 4 threads.
- GPU/NPU acceleration (e.g. Snapdragon NPU via the QNN backend) is a
stretch goal, not wired up yet.
## Module layout
```
app/ Compose UI + RecorderService (record → live pass → final pass)
core/recording/ MeetingRecorder, WavWriter/WavReader, RollingWindow,
linear resampler — pure Kotlin, unit tested on the JVM
core/whisper/ whisper.cpp JNI wrapper + WhisperEngine + TranscriptFiles
(txt/srt/json writers, desktop-compatible formats)
tools/ fetch-whisper.sh — vendor the pinned whisper.cpp release
```
Recording mirrors the desktop app: audio is captured at the input's native
rate (WAV on disk keeps it), while the 60 s rolling window is resampled to
Whisper's 16 kHz for the upcoming live pass. Recording continues while the
app is backgrounded via the microphone foreground service.
Models live in the app's private storage (`filesDir/models`), shared files
with the desktop app's `~/.cache/meetrec/whisper-cpp` naming
(ggml-tiny.bin … ggml-large-v3.bin).