Upload a recording (audio, or video with the camera off), get a private Swedish transcript, and chat about it. - ADR-033: RLS-scoped private transcript store; ffprobe/ffmpeg intake; gateway transcription (iguana kb-whisper, berget fallback); in-process single-replica worker; chat over the transcript (local models only). - ADR-034: optional two-engine mode (pianissimo + kb-whisper) reconciled by a LOCAL model; off unless TAPIR_RECONCILE_BASE_MODEL is set. - ADR-035: real progress (phases, running/quiet/lost), phase logging, every judged spot stored, merged segments. - Hardening from four adversarial reviews: errors logged and stored as kinds never text; per-engine deadlines; converted-length check; bounded queue; client hang-ups are not errors; strict local-alias check. - Dockerfile: static ffmpeg/ffprobe 7.0.2 pinned by sha256 (#34). Built and inspected by hand; CI does not build the image on a PR, so its first CI build is this merge. Uploads stay OFF until TAPIR_UPLOADS_ENABLED is set in the deployment. Closes #33, #34, #42, #43, #44. Co-authored-by: Mathias <mthbqv@gmail.com>
This commit was merged in pull request #39.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A Request may carry its own transcript budget. The Service's cap (18,000 chars by
|
||||
// default) is sized for YouTube captions; an uploaded recording is much longer
|
||||
// (~50,000 chars an hour), and keeping only the head of it would answer questions
|
||||
// about the last two-thirds of a meeting from text that does not contain them
|
||||
// (ADR-033). The per-request value overrides; zero means "the service default".
|
||||
|
||||
func TestAnswerMaxCharsOverridesTheServiceCap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
serviceCap int
|
||||
requestCap int
|
||||
transcriptLen int
|
||||
wantKept int
|
||||
wantTruncated bool
|
||||
}{
|
||||
{"request cap above the service cap keeps the whole transcript", 10, 100, 50, 50, false},
|
||||
{"request cap below the service cap bounds tighter", 100, 10, 50, 10, true},
|
||||
{"zero request cap falls back to the service cap", 20, 0, 50, 20, true},
|
||||
{"negative request cap is treated as unset", 20, -1, 50, 20, true},
|
||||
{"request cap exceeded is reported as truncated", 10, 30, 50, 30, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
f := &factory{answer: "answer"}
|
||||
s := New(f.make, []string{"koala/phi4-mini"}, tt.serviceCap)
|
||||
|
||||
reply, err := s.Answer(context.Background(), Request{
|
||||
Model: "koala/phi4-mini",
|
||||
Transcript: strings.Repeat("x", tt.transcriptLen),
|
||||
Question: "what was decided?",
|
||||
MaxChars: tt.requestCap,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Answer: %v", err)
|
||||
}
|
||||
if got := strings.Count(f.used.lastSystem, "x"); got != tt.wantKept {
|
||||
t.Errorf("transcript chars sent = %d, want %d", got, tt.wantKept)
|
||||
}
|
||||
if reply.Truncated != tt.wantTruncated {
|
||||
t.Errorf("Truncated = %v, want %v", reply.Truncated, tt.wantTruncated)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user