The Problem
Many professionals need to capture meeting audio, obtain accurate transcripts, and generate concise summaries without sending any data to cloud services. Existing SaaS note‑taking tools either rely on third‑party APIs (exposing confidential content) or require heavyweight local installations that are hard to set up.
What This Does
StenoAI delivers a fully offline workflow for macOS meetings. The repository bundles four self‑contained projects:
| Project | Core purpose | Key files |
|---|---|---|
| app (desktop UI) | Electron‑based macOS client that records audio, shows transcripts and summaries | app/main.js, app/index.html, app/package.json |
| website (marketing & docs) | React‑Vite site that advertises the product and hosts the privacy policy | website/src/App.jsx, website/package.json |
| src (backend library) | Python modules that drive audio capture, Whisper transcription, Ollama summarization and file‑system organization | src/audio_recorder.py, src/transcriber.py, src/summarizer.py, src/ollama_manager.py, src/config.py |
| prompt_tests (prompt validation) | Small test harness for LLM prompt sanity checks | prompt_tests/test_prompts.py |
The desktop client invokes the Python library via a child process (see app/main.js), passing the recorded file path. The library writes transcripts, summaries and folder metadata under user‑controlled locations defined in src/config.py.
How It Is Wired
Execution starts at app/main.js (the Electron entry point). The script:
- Sets up the UI (HTML from
app/index.html). - When the user clicks “Record”, it calls the
simple_recordermodule (Python filesimple_recorder.py). This file imports six other modules, making it the most outward‑facing hub (Ca 0 Ce 6). simple_recorderlaunches the audio capture loop insrc/audio_recorder.py, which writes a raw.wavfile to the folder chosen insrc/config.py.- After recording,
src/transcriber.pyruns Whisper (whisper.cppbinary) on the file and returns a transcript. - The transcript is handed to
src/summarizer.py, which contacts the local Ollama server viasrc/ollama_manager.pyto obtain a summary. - Summaries and transcripts are persisted by
src/models.py(data‑model utilities) and organized bysrc/folders.py.
The import graph shows no cycles; the widest blast radius lies in simple_recorder (six downstream imports) and src/summarizer.py (deep nesting, 8‑level indentation). All filesystem writes are confined to paths resolved in src/config.py; no external network calls occur beyond the local Ollama HTTP endpoint.
The React front‑end (website/src/App.jsx) is independent of the desktop client; it consumes static assets and does not invoke the Python backend.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/stenoai
cd stenoai
# Install Python deps
python -m pip install -r requirements.txt
# Install desktop UI deps
cd app
npm ci # uses app/package-lock.json
# start the Electron app (script defined in app/package.json)
npm start
# (Optional) Build the marketing site
cd ../website
npm ci
npm run dev # Vite dev server, defined in website/package.json
Configuration lives in src/config.py; edit the constants there to change the default storage directory or Ollama endpoint. No environment variables are required out of the box.
Real‑World Use
A legal team installs the DMG release on each Mac. During a client call, the user clicks “Record” in the StenoAI window. The app writes meeting_2023‑08‑22.wav to a secure folder, runs Whisper locally, then invokes Ollama’s llama3.2:3b model to produce a 3‑sentence summary that is saved alongside the transcript. The team can later query the notes with the “Ask Steno” UI without any data ever leaving the device.
Code Health & Issues
- HIGH – GitHub Actions pinned to tags (
apple-actions/import-codesign-certs@v2,softprops/action-gh-release@v1). Replace with commit SHA to prevent supply‑chain drift. - HIGH –
eval/execover runtime value inapp/main.js. Replace with safe parsing (json.loadsorast.literal_eval). - MEDIUM – No Dependabot or Renovate config; add
.github/dependabot.ymlfor automatic version bumps. - MEDIUM – CI lacks a dependency‑vulnerability scan; integrate
dependency-review-actionorosv-scanner. - MEDIUM – Checkout step keeps the token; set
persist-credentials: falseand supply a token only where needed. - LOW – Workflows have no
timeout-minutes; add reasonable limits to avoid hung runs. - LOW – Repository lacks convention files (
.editorconfig,.gitattributes, formatter config); add them to enforce consistent style.
Measured static analysis also reported:
- Deep nesting (max depth 8) in
src/summarizer.py,simple_recorder.py,src/transcriber.py. Refactor with early returns or helper extraction. - Duplicated 6‑line blocks between
prompt_tests/test_prompts.pyandsrc/summarizer.py. Consolidate into a shared helper. - Bare
exceptclauses in several modules; narrow to specific exception types. - Oversized files:
app/main.js(≈1856 LOC) andsimple_recorder.py. Split into logical sub‑modules. - File opened without a context manager in
src/audio_recorder.py; usewith open(...).
The Bottom Line
StenoAI provides a functional, fully offline meeting‑note pipeline with a clear separation between UI (Electron/React) and processing (Python + Whisper + Ollama). The code works but suffers from maintainability concerns—large, deeply nested files and a few security‑related CI practices. It is suitable for teams that can tolerate some refactoring and want strict data privacy, but it is not ready for production‑grade deployment without addressing the highlighted high‑severity issues.