ai newsMo., 26. Okt.
EilmeldungHugging Face libraries now run natively on TPUs via TorchTPU

MeetBrief AI : turns spoken discussions into structured, shareable meeting intelligence reports.

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady . Picture the twenty minutes after a 40-minute launch call. The call is over. The decisions are not. You open a blank document and try to remember what was actually agreed. The recording has the answer. It a

dev.toMontag 05:46 · 26.10.11 Min. Lesezeit
Bild: dev.to

Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady Submission 🦥

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady.

Picture the twenty minutes after a 40-minute launch call. The call is over. The decisions are not. You open a blank document and try to remember what was actually agreed.

The recording has the answer. It always does. The problem is that the recording is 40 minutes long, and you are tired.

That gap — between a conversation and the record of it — is where most meeting tools make things worse. They hand you a confident paragraph with no receipts. It reads well. It might even be right. But when someone asks who agreed to the 14-day trial, or why a task landed on their plate, the summary has nothing to show.

MeetBrief AI closes that gap. It turns a recording into a transcript, an evidence-linked report, assigned action items, and a spoken recap you can listen to on the way home.

The recap is the part I want to spend time on. Giving a meeting a voice is easy now. Giving it a voice that cannot invent things is the interesting problem.

![MeetBrief AI — Your meeting ended. Your recap can prove it.]

MeetBrief is a Next.js 15 PWA for the twenty minutes after a meeting.

Then you can rename the anonymous speakers, generate a spoken recap with ElevenLabs, share a read-only link, or export Markdown.

There is no attendee list and no manual participant entry. Diarization gives you Person 1, Person 2, and so on. A real name is applied only when a human confirms it. The AI may suggest a name, but only when that speaker explicitly introduced themselves in their own transcript line — and even then, it waits for a click.

The lazy payoff is simple: you leave the call and the first draft of the record already exists. Not a vibe summary. A document where every decision and task has a timestamp and a quote behind it.

The fastest way to see it is the /demo route. It is a complete interactive report — overview, transcript, decisions, actions, and recap — with no account, no recording, and no AI request.

git clone https://github.com/Ayush-Barai/MeetBrief cd MeetBrief npm install npm run dev # open http://localhost:3000/demo Enter fullscreen mode Exit fullscreen mode The demo data is fictional and labeled as such everywhere. The screenshots below come from a real production build with the integrations intentionally unconfigured, so the UI is showing the actual product, not a mockup.

There is no public deployment yet. The /demo route is deliberately credential-free, so you can see the whole UI without a database or an API key; the full pipeline is in DEPLOYMENT.md.

The overview keeps the executive summary separate from the evidence. Tabs for transcript, decisions, action items, and the audio recap sit above the report instead of hiding in a sidebar.

![Create a meeting without entering participants]

The speaker panel shows Person 1 through Person 4, their segment counts, when they first spoke, and any AI suggestion that still needs confirmation.

The suggestion is not a rename. It is a hint stored separately from the transcript. Nothing changes until a human clicks.

![Speaker panel with anonymous labels and AI suggestions]

The transcript keeps the same labels, timestamps, and the transcription metadata: whisper (demo) · large-v3-turbo · diarized speaker labels.

![Transcript with Person labels and timestamps]

A meeting record should not flatten “we agreed” and “we might agree” into the same sentence. Confirmed and tentative decisions look different, and each one carries the quote it came from.

Owners and deadlines appear only when the transcript supports them. Otherwise the item is unassigned or the date is absent. Status can be updated as work moves.

![Action items with owners, deadlines, and evidence]

Most AI meeting notes trust the model’s output. I don’t.

Gemma returns structured JSON with segment IDs and quotes. Before anything is saved, the server checks it:

That last rule matters. Deleting a questionable decision hides the disagreement. Keeping it with a warning tells you exactly where to look.

for ( const reference of evidence ) { let segment = byId. get ( reference. segmentId ); if (! segment && reference. quote. trim (). length > 12 ) { const needle = reference. quote. trim (). toLowerCase (). slice ( 0, 80 ); segment = segments. find (( candidate ) => candidate. text. toLowerCase (). includes ( needle ), ); } if (! segment ) { warnings. push ( ` ${ claimLabel }: a cited segment could not be verified and was removed.` ); continue; } const quoteIsExact = segment. text. toLowerCase (). includes ( reference. quote. trim (). toLowerCase ()); results. push ({ segmentId: segment. id, timestampSeconds: segment. startSeconds, quote: quoteIsExact? reference. quote. trim (): segment. text. slice ( 0, 277 ), }); } Enter fullscreen mode Exit fullscreen mode The result is a report that can be incomplete. It can say “a decision had no verifiable transcript evidence.” It cannot confidently invent a decision.

I think that trade is the whole product.

This is my entry for Best Use of ElevenLabs: the open-source agent gets a voice, and the voice is constrained by the same evidence rules as the text.

The recap is not text-to-speech over the transcript. It is a deterministic script built from the reconciled report:

That order is the design. The voice only says things that survived validation. If the report refuses a claim, the audio never speaks it.

Could I have used an open-source TTS model? Yes. I chose ElevenLabs because the recap is the one place where voice quality is the product, and a robotic read undermines the reason to listen. The trade-off is explicit: the intelligence and the evidence stay open and self-hostable; the last mile is a hosted service I can swap out without touching the pipeline.

![Audio recap script built from the edited report]

The integration is deliberately boring in the places that should be boring:

const response = await fetch ( `https://api.elevenlabs.io/v1/text-to-speech/ ${ voiceId }?output_format=mp3_44100_128`, { method: " POST ", headers: { " xi-api-key ": config. elevenLabsKey, " Content-Type ": " application/json ", Accept: " audio/mpeg ", }, body: JSON. stringify ({ text: script, model_id: " eleven_multilingual_v2 ", voice_settings: { stability: 0.45, similarity_boost: 0.75, style: 0.2, use_speaker_boost: true, }, }), signal: AbortSignal. timeout ( 120 _000 ), }, ); Enter fullscreen mode Exit fullscreen mode The script is capped at 4,900 characters so a long meeting doesn’t turn into a failed request. The MP3 is written to GridFS, not stuffed into the meeting document. Generation is on demand, not part of the transcription job.

Two details I care about more than the voice settings:

Failure is not data loss. If ElevenLabs fails, the script is saved with status failed. You can read it, fix the report, and retry. The app never pretends audio exists.

The voice can go stale, and it says so. Rename a speaker or edit the report and the existing recap is marked stale:

if ( recapScript && recapScript!== meeting. recap?. script ) { await db. collection ( COLLECTIONS. meetings ). updateOne ( { _id: meetingId }, { $set: { " recap.script ": recapScript,...( meeting. recap?. status === " ready " || meeting. recap?. status === " generating "? { " recap.status ": " stale " }: {}), }, }, ); } Enter fullscreen mode Exit fullscreen mode The old MP3 is still there, but the UI tells you it no longer matches the record. A spoken recap that silently disagrees with the written one is worse than no recap at all.

That is what “giving an open-source agent a voice” means here: the voice is the last mile of an auditable pipeline, not a layer on top of a black box.

The repository is public: https://github.com/Ayush-Barai/MeetBrief. It is a Next.js 15 / React 19 / TypeScript app with Zod validation, MongoDB 7, and Vitest. The files worth reading first:

The app talks to any OpenAI-compatible /audio/transcriptions endpoint. The recommended server is ScribeCrate (formerly docker-whisper, image hwdsl2/whisper-server ), which wraps open-source faster-whisper and supports local speaker diarization.

docker run -d --name whisper \ -p 9000:9000 \ -e WHISPER_MODEL = large-v3-turbo \ -e WHISPER_DIARIZATION = true \ -v whisper-data:/var/lib/whisper \ hwdsl2/whisper-server Enter fullscreen mode Exit fullscreen mode When the server returns a speaker field per segment, MeetBrief maps those labels to stable Person N labels in first-seen order. If the server does not diarize, every segment is Person 1 and the transcript metadata says diarized: false. The app never invents speakers.

Gemma is served through an OpenAI-compatible endpoint, so Ollama, vLLM, or a hosted Gemma endpoint all work:

GEMMA_API_URL=http://localhost:11434/v1 GEMMA_MODEL=gemma3:27b GEMMA_TIMEOUT_MS=180000 Enter fullscreen mode Exit fullscreen mode The prompt asks for JSON with evidence segment IDs. The response is validated with Zod, then reconciled against the transcript before anything is saved. The model’s owners, deadlines, and dates are never trusted blindly.

Atlas stores meeting metadata, ordered transcript segments, reports, action items, and share-token hashes. Recordings and recap MP3s live in the GridFS bucket meeting_files.

Covered above. The important part is not the API call. It is that the script is generated from the report that already passed validation.

/api/health returns 200 ok only when MongoDB is configured and reachable. It returns 503 degraded otherwise, and it never exposes secrets.

The full Atlas + Whisper + Gemma + ElevenLabs + Render walkthrough is in DEPLOYMENT.md.

Three reasons, in the order they mattered to me.

The audio doesn’t have to leave. Meeting recordings contain pricing, hiring plans, legal risk, customer names, and things people said without expecting a transcript. Whisper can run on your laptop or your own VPS. Gemma can too. The sensitive input stays inside infrastructure you control.

The rules are inspectable. The prompt, the Zod schema, the evidence reconciliation, and the speaker-rename rules are all in the repository. If you disagree with how a claim is accepted, you can read the code and change it. That is much harder with a hosted pipeline that returns a confident paragraph and no trail.

The model is replaceable. Whisper is an endpoint. Gemma is an endpoint. You can trade model size for hardware, swap providers, or run everything locally without rewriting the product. The open pieces are not decoration — remove them and MeetBrief stops working.

A closed pipeline gives you a paragraph. An open one gives you a paragraph you can argue with.

And the theme fits: slow and steady is fine when the machine does the slow part. A 40-minute call can take three minutes to transcribe. The human shouldn’t have to spend twenty minutes rebuilding the record afterward. Slowness is only a virtue if it buys accuracy. Otherwise it is just latency.

I used OpenCode during the build. I did not save a DevRelay session, so here is the short version.

The useful work was narrow and verifiable:

The most instructive bug is a regex problem: "I'm Maya" and "Maya's idea" look identical to a naive pattern. The self-introduction check needs a real word boundary after the name; the test now pins it.

The human decisions stayed human: removing a proprietary speech provider, deciding what “open source” should mean for this project, and what the demo is allowed to claim.

The payoff I designed for is the twenty minutes after a call: no scrubbing a recording for a timestamp, no guessing who owns a task, no retyping decisions into a document.

I am not going to claim a measured team time saving. The demo is fictional and I did not run this with a team this week. What I can show is the workflow it removes — and the fact that the first draft arrives with receipts.

The next automation I would add is a durable processing queue. Right now processing runs through Next.js after(), which is fine for a demo but can be interrupted by a Render restart. A worker with a heartbeat and lease would make long meetings reliable. After that: real multi-user auth, a retention and deletion job, and per-user storage quotas.

I want to be precise about the state of the project:

That distinction matters. A demo should show the product honestly, not borrow credibility from an AI call that never happened.

![Setup page showing which integrations are configured]

I would like this project considered for:

Repository: https://github.com/Ayush-Barai/MeetBrief

Start with /demo — no account, no recording, no API keys. If you want the real pipeline, DEPLOYMENT.md walks through Atlas, Whisper, Gemma, ElevenLabs, and Render.

If you have ever left a call unsure what was decided, I would love to know: what would your recap have to prove before you trusted it?

Quelle: dev.to (dev.to). Original öffnen