Skip to content

Latest commit

Β 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Pasithea

Plug in your dictaphone. Run one command. Every recording is transcribed, searchable, and taggable.


Pasithea is built around a simple daily ritual: carry a small USB dictaphone, record your thoughts throughout the day, and dock it when you're done. Plug it into your Mac, run the app, and everything new on the device is pulled in, transcribed via MacWhisper's command-line tool, and waiting for you on a local webpage β€” searchable, taggable, editable. No cloud, no accounts, no database. The entire catalog lives in one JSON file.

Manual drops still work too β€” anything you drag into recordings/ (an AirDropped voice memo, a Zoom recording) gets picked up the same way. But the primary workflow is the dock: dictaphone in, run the app, transcripts out.

Features

  • Dictaphone auto-import β€” on every launch (and on demand via the sidebar button), Pasithea looks for your dictaphone's USB volume and pulls any new recordings out of its RECORD folder into recordings/. Nothing is deleted from the device β€” recordings are copied, not moved.
  • Automatic transcription β€” anything that lands in recordings/, whether from the dictaphone or dropped in by hand, is transcribed via MacWhisper's mw CLI and appears on the page within seconds. No manual step.
  • Rename-safe, re-plug-safe β€” every file is identified by content, not filename or path. Renaming a file, or re-plugging a dictaphone that still has old recordings on it, is recognized as already known β€” never re-imported, never re-transcribed, never duplicated.
  • Full-text search β€” search across filenames and transcript text, with matches highlighted inline.
  • Tagging β€” organize recordings with tags (defaults: idea, rambling, todo). Add or remove tags from the sidebar at any time; each tag gets a consistent accent color. Click a tag in the sidebar to filter the list down to just that tag.
  • Editable transcripts, titles & timestamps β€” MacWhisper isn't always perfect, so every transcript is directly editable in place. Every entry also gets an editable title (separate from the underlying filename) and an editable "recorded at" date/time, in case the file's timestamp doesn't match when you actually recorded it.
  • Delete, safely β€” deleting an entry moves the underlying file to recordings/.trash/ instead of destroying it, and removes it from the catalog.
  • Four Catppuccin themes β€” Latte, FrappΓ©, Macchiato, and Mocha, switchable from a dropdown, remembered per-browser.
  • No database β€” the whole catalog is a single data.json file. Easy to back up, inspect, or edit by hand.

The dock: your daily workflow

  1. Record throughout the day on your dictaphone.
  2. At the end of the day, plug it into your Mac via USB.
  3. Run python3 app.py (or, if it's already running, click Import from dictaphone in the sidebar).
  4. Open http://127.0.0.1:5151 β€” your new recordings are already transcribed, or finishing up.
  5. Search, tag, rename, and edit as needed. The originals stay safely on the dictaphone.

How it works

Pasithea is a small Flask app (app.py) with background worker threads, plus a static HTML/CSS/JS frontend β€” no build step, no JavaScript framework.

  1. On startup (and whenever you click Import from dictaphone), Pasithea checks /Volumes/<dictaphone_volume_name>/<dictaphone_folder> (by default PASITHEA/RECORD). Any audio file found there whose content isn't already in the catalog gets copied into recordings/. The device itself is never modified.
  2. A background thread (watchdog) also watches recordings/ directly, for anything dropped in by hand.
  3. When a file shows up (from either path) and its size has stopped changing (so we don't grab a half-written file), it's checked against the catalog:
    • If a file at that exact path is already known, nothing happens.
    • If not, its content is hashed (SHA-1). A match against an existing entry means this is the same recording under a new name β€” renamed, re-imported, whatever β€” the catalog entry is updated in place, no re-transcription.
    • No match means it's genuinely new β€” a catalog entry is created and the file is queued for transcription.
  4. A single worker thread pulls jobs off the queue and runs mw transcribe <file> --format txt, MacWhisper's command-line tool, capturing the transcript from stdout.
  5. The result (or error, if mw isn't installed or transcription fails) is written back into data.json.
  6. The frontend polls the Flask API every few seconds and re-renders the list β€” no page refresh needed to see a new recording finish transcribing. (Polling pauses automatically while you're mid-edit on a title or transcript, so it never overwrites what you're typing.)

Everything β€” transcripts, titles, tags, timestamps, status β€” lives in data.json. There's no database server and no schema migrations; it's just a JSON file read and rewritten (atomically) on every change.

Folder structure

pasithea/
β”œβ”€β”€ app.py                     Flask server, dictaphone import, folder watcher, transcription worker, API
β”œβ”€β”€ config.json                Settings: dictaphone volume/folder, recordings path, tag list, host/port
β”œβ”€β”€ data.json                  The entire catalog (auto-created, do not edit while the server runs)
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ icon.svg                   Source app icon
β”œβ”€β”€ recordings/                Watched folder β€” dictaphone imports and manual drops both land here
β”‚   └── .trash/                Deleted recordings land here instead of being destroyed
└── static/                    Frontend (served directly by Flask, no build step)
    β”œβ”€β”€ index.html
    β”œβ”€β”€ style.css              Catppuccin theme definitions + all styling
    β”œβ”€β”€ app.js                 Search, tagging, theming, polling, all UI logic
    β”œβ”€β”€ favicon.svg
    └── pasithea-banner.png
  • recordings/ is the single working folder for the whole app β€” it's where dictaphone imports get copied to, and also where you can drop files by hand. Created automatically if it doesn't exist. Anything with an extension listed in config.json's audio_extensions gets picked up (.mp3, .wav, .m4a, .mp4, .mov, .flac, .aac, .ogg, .mkv, .webm, .caf by default).
  • recordings/.trash/ is where deleted recordings go. It's excluded from the watcher, from rescans, and from dictaphone re-import checks, so nothing in there gets picked back up. Files aren't permanently deleted by the app β€” clear this folder yourself if you want to reclaim disk space.
  • data.json is the entire database: an array of entries, each with an id, filename, title, tags, transcript, status, content hash, and timestamps. Safe to read, back up, or hand-edit while the server is stopped.
  • config.json holds the settings described below.

Nothing needs to exist on the dictaphone side beyond its own RECORD folder β€” Pasithea only ever reads from it and copies out, it never writes back to or deletes anything on the device.

Prerequisites

  • Python 3 with Flask and watchdog (see Setup).
  • MacWhisper installed, with its command-line tool enabled: open MacWhisper β†’ Settings β†’ Advanced β†’ Command-Line Tool β†’ Install. This installs the mw binary that Pasithea shells out to. Without it, new recordings will show a clear "MacWhisper CLI not found" error on the page instead of transcribing.
  • A USB dictaphone (optional, but this is the intended workflow). Any cheap USB flip-plug voice recorder works β€” Pasithea was built against a Liebssen digital voice recorder, which mounts as a plain USB drive with a RECORD folder containing timestamped .WAV files. Rename its USB volume (in Finder, like any drive) to match dictaphone_volume_name in config.json β€” PASITHEA by default.

Setup

pip3 install -r requirements.txt
python3 app.py

Then open http://127.0.0.1:5151. If your dictaphone is plugged in, its recordings are already imported and transcribing. Otherwise, drop a recording into recordings/ and watch it appear.

Configuration

Edit config.json (the server reads it fresh on relevant actions, so most changes just need a restart):

Key Description
dictaphone_volume_name The name of your dictaphone's USB volume, as it appears under /Volumes/. Matched case-insensitively. Set to null to disable dictaphone auto-import entirely.
dictaphone_folder The subfolder on the dictaphone containing recordings. Defaults to RECORD, matched case-insensitively.
recordings_path Folder to watch. Relative paths resolve from the project root; you can also point it at an absolute path elsewhere on disk.
tags The default/available tag list. Also editable live from the sidebar's "add tag" field.
audio_extensions File extensions the watcher (and dictaphone import) picks up.
host / port Where the local web server binds.

Notes

  • This is meant to run on your own Mac for personal use β€” the dev server (app.run(...)) is not intended to be exposed to the network.
  • Transcription is sequential (one file at a time) via a single worker thread, so dropping a batch of recordings at once β€” or importing a fresh dictaphone β€” will transcribe them one after another rather than all in parallel.
  • Dictaphone import only ever reads from RECORD/ and copies into recordings/. It never deletes or writes anything back to the device.

About

Pasithea 🧠 is an open-source voice journaling tool. the goddess of rest keeps your unfinished thoughts.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages