Build Circleback

KINDAback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A local meeting notes pipeline whose hard problems are a speech model that invents text during silence, speaker labels that are wrong often enough to matter, and notes that must be traceable to audio because people act on them.

estimated effort multi-daythe files for this build are in the project pack

RuntimePython with a small local web interface and a background workerAudioFFmpeg to normalise everything to single-channel sixteen kilohertz before anything elseTranscriptionA local speech model with voice activity detection as a pre-passDiarisationA maintained open pipeline, with its labels treated as suggestionsNotesA model pass that must return segment identifiers with every claim

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the interface and the transcription worker.

    Get it python.org, or your package manager. open ↗

    Verify python3 --version prints 3.12 or higher

  2. installfree

    Why Every input is normalised to single-channel sixteen kilohertz before anything else touches it, and this is where half the format problems disappear.

    Get it Your package manager, or ffmpeg.org. open ↗

    Verify ffmpeg -version prints a version and a test file converts

  3. installfree, at the cost of disk and time

    Why Running it locally keeps recordings of colleagues on your machine, and the detection pre-pass is the mitigation for the documented failure mode.

    Get it A maintained local implementation with a bundled detector and per-segment scores exposed.

    Verify A file with silence in the middle produces no segments for it

  4. installfree, with an account for the model where required

    Why Attribution is a separate model from transcription, and the maintained pipelines publish their error rates so you can state them honestly.

    Get it A current open pipeline with published benchmark numbers, accepting its licence terms.

    Verify A two-speaker recording produces two labels with sensible boundaries

  5. decidefree

    Why Both are legal questions before they are product questions, and the build enforces whatever you write down here.

    Get it Decide what participants are told, how the telling is recorded, and how long audio and transcripts are kept.

    Verify Both appear in the README and are enforced by code rather than by intention

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- meetings(id, title, started_at, duration_s, source_path, normalised_path, consent_recorded_at, consent_note, retention_until, state)
- segments(id, meeting_id, start_ms, end_ms, text, avg_logprob, no_speech_prob, compression_ratio, flagged_reason) · one row per transcribed segment with the numbers that predict a bad one
- speech_regions(meeting_id, start_ms, end_ms) · from voice activity detection, before transcription touches the audio
- speakers(id, meeting_id, label, display_name, confirmed_by_user) · a guess until somebody confirms it
- segment_speakers(segment_id, speaker_id, overlap_ratio) · attribution kept separately from the words
- notes(id, meeting_id, kind, text, segment_ids_json, model_id, created_at) · kind is summary, decision or action; the segment list is mandatory
- actions(id, note_id, owner_speaker_id, due_text, confidence, accepted_by_user) · nothing is assigned to a person until a human accepts it
- Nothing in the notes table can exist without segment identifiers, and the schema enforces it rather than the prompt.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DATABASE_PATHrequired./data/meetings.dbMeetings, segments, speakers and notes. Contains what colleagues said, so treat it accordingly.
AUDIO_DIRrequired./data/audioNormalised audio. Deleted at the retention date along with the original.
RETENTION_DAYSrequired90Default retention set at import. Can be shortened per meeting, never silently extended.
ASR_MODELrequireda local speech model identifierStored per meeting, because a different model gives a different transcript.
NOTES_MODELrequireda local or hosted model identifierUsed only for the notes pass. If hosted, the transcript leaves the machine and the README must say so.
VAD_MIN_SILENCE_MSrequired2000Non-vocal stretches longer than this are cut before transcription.
FLAG_COMPRESSION_RATIOrequired2.4Above this a segment is flagged as probably repeating rather than transcribing.

The build, in order

  1. Consent first, audio second

    No audio is retained until a consent record exists, and every recording states its retention.

    1. Not a checkbox that can be added afterwards.

      Files src/meetings.pysrc/db/schema.sql

    2. One sample rate and one channel removes a category of later failures.

      Files src/audio.pytests/test_audio.py

    3. Recordings of colleagues should have an expiry date.

      Files src/retention.py

    done when · tick each as it passes
    watch out
    • Building capture first and consent as a checkbox later means the first real recordings in the database have no record of whether anyone was told, and the one meeting you later need to justify is one of those. Make the consent row a foreign key the audio path depends on, so the sequence cannot be done in the other order.
  2. A transcript that does not invent

    Silence produces nothing, repetition loops are caught, and doubtful segments are marked.

    1. The pre-pass removes the exact condition that produces invented text.

      Files src/vad.pytests/test_silence.py

    2. And state the trade-off in the README rather than hiding it.

      Files src/transcribe.py

    3. A doubtful segment should look doubtful in the interface.

      Files src/transcribe.pysrc/templates/transcript.html

    done when · tick each as it passes
    watch out
    • Feeding an hour of audio straight in and trusting the output puts plausible sentences into the transcript during the four minutes when somebody was screen sharing in silence, and they read exactly like the rest, which is why the published work found harms in over a third of the hallucinations it collected. Cut to speech regions first, keep the per-segment scores, and show flagged segments differently.
  3. Speaker labels that admit what they are

    Attribution is a suggestion the user confirms, and every label can be checked against the audio.

    1. A name is a claim about who said something.

      Files src/diarise.pysrc/templates/speakers.html

    2. People talk over each other and the transcript should show it.

      Files src/diarise.py

    3. Checking a line should take one click.

      Files src/templates/transcript.html

    done when · tick each as it passes
    watch out
    • Presenting diarisation output as names in the notes produces sentences like a named person committing to a deadline they never mentioned, and on distant-microphone meeting audio the best open pipelines still misattribute around a fifth of speech under a strict scoring protocol. Keep labels anonymous until confirmed, store the overlap ratio, and make every attributed line playable.
  4. Notes that cite the transcript

    Every summary line, decision and action item points at the segments it came from, or it is not shown.

    1. Verify they exist, because a model will invent an identifier too.

      Files src/notes.pytests/test_citations.py

    2. A caveat is read as confidence by the third reader.

      Files src/notes.py

    3. Assigning work from a guess about who spoke is how this goes wrong.

      Files src/actions.pysrc/templates/notes.html

    done when · tick each as it passes
    watch out
    • A summary produced from the whole transcript in one pass reads beautifully and contains a decision nobody made, because the model resolved an ambiguous exchange into a conclusion, and the person who reads the notes was not in the meeting and cannot tell. Require identifiers, verify they exist, and delete anything that arrives without them rather than showing it with a caveat.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more meeting notes.