Refresh list status over Reverb with polling fallback, clarify queued vs processing, streamline upload empty states, and seed an admin login.
252 lines
7.4 KiB
Markdown
252 lines
7.4 KiB
Markdown
# AndyTranscribe
|
|
|
|
Upload pocket-recorder audio (MP3, WAV, OGG, and more), extract embedded metadata, and transcribe locally with [faster-whisper-server](https://github.com/fedirz/faster-whisper-server). Audio never leaves your machine.
|
|
|
|
Built with Laravel 13, Blade, Livewire, Flux UI, Alpine.js, Tailwind CSS 4, [Laravel Reverb](https://laravel.com/docs/reverb), FrankenPHP, and [Laravel AI](https://github.com/laravel/ai).
|
|
|
|
## Features
|
|
|
|
- User accounts with login and open registration (each user only sees their own recordings)
|
|
- Upload common audio formats (MP3, WAV, OGG, FLAC, M4A, AAC, WebM, WMA, AIFF — up to 2 GB)
|
|
- Automatic metadata extraction when tags are present (title, artist, album, duration, recorded date)
|
|
- Search recordings by title, artist, or transcript
|
|
- Queued local transcription (faster-whisper in Docker)
|
|
- Live transcription progress over WebSockets (Reverb) on the list and detail pages
|
|
- Stop or restart a run anytime
|
|
- Copy finished transcripts from the recording detail page
|
|
|
|
## Requirements
|
|
|
|
- [Docker](https://docs.docker.com/get-docker/) and Docker Compose
|
|
- About 2 GB free disk for the Whisper model cache (first run downloads the model)
|
|
|
|
Optional for native PHP development: PHP 8.3+ (8.5 recommended), Composer, Node.js & npm.
|
|
|
|
## Install
|
|
|
|
These steps run the full stack with Docker: web app, queue worker, Reverb WebSockets, and Whisper.
|
|
|
|
### 1. Clone the repository
|
|
|
|
```bash
|
|
git clone <your-repo-url> andyTranscibe
|
|
cd andyTranscibe
|
|
```
|
|
|
|
### 2. Create your environment file
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
### 3. Generate an application key
|
|
|
|
`APP_KEY` is required. Containers refuse to start if it is empty.
|
|
|
|
**Option A — PHP installed on the host**
|
|
|
|
```bash
|
|
php artisan key:generate
|
|
```
|
|
|
|
**Option B — Docker only**
|
|
|
|
Print a key:
|
|
|
|
```bash
|
|
docker run --rm php:8.5-cli php -r "echo 'base64:'.base64_encode(random_bytes(32)), PHP_EOL;"
|
|
```
|
|
|
|
Open `.env` and set:
|
|
|
|
```env
|
|
APP_KEY=base64:paste-the-value-here
|
|
```
|
|
|
|
On Linux you can write it in one step:
|
|
|
|
```bash
|
|
KEY=$(docker run --rm php:8.5-cli php -r "echo 'base64:'.base64_encode(random_bytes(32));")
|
|
sed -i "s|^APP_KEY=.*|APP_KEY=${KEY}|" .env
|
|
```
|
|
|
|
### 4. Start the stack
|
|
|
|
```bash
|
|
docker compose up --build -d
|
|
```
|
|
|
|
On first start the app container will:
|
|
|
|
- create `database/database.sqlite` if needed
|
|
- run migrations
|
|
- seed a demo user (see below)
|
|
- start FrankenPHP on port **8080**
|
|
|
|
Whisper may take a minute or two while the model downloads.
|
|
|
|
### Demo login
|
|
|
|
Every container start runs `db:seed`, which ensures these users exist:
|
|
|
|
| Email | Password |
|
|
| --- | --- |
|
|
| `demo@example.com` | `password` |
|
|
| `admin@example.com` | `password` |
|
|
|
|
Override the demo user with `SEED_USER_NAME`, `SEED_USER_EMAIL`, and `SEED_USER_PASSWORD` in `.env`.
|
|
|
|
### 5. Open the app
|
|
|
|
| URL | Purpose |
|
|
| --- | --- |
|
|
| [http://localhost:8080/recordings](http://localhost:8080/recordings) | App UI |
|
|
| [http://localhost:8080/up](http://localhost:8080/up) | Health check |
|
|
|
|
Live transcription status uses WebSockets on port **8081** (Reverb). Keep that port reachable from your browser.
|
|
|
|
### 6. Verify services (optional)
|
|
|
|
```bash
|
|
docker compose ps
|
|
docker compose logs -f app queue whisper reverb
|
|
```
|
|
|
|
You should see `app`, `queue`, `reverb`, and `whisper` running. Whisper becomes healthy after `/health` succeeds.
|
|
|
|
### Stop / restart
|
|
|
|
```bash
|
|
docker compose down
|
|
docker compose up -d
|
|
```
|
|
|
|
Data under `./database`, `./storage/app`, and `./storage/logs` is kept on the host.
|
|
|
|
### Live reload while developing
|
|
|
|
Default Compose uses the built image, so PHP/Blade/CSS/JS changes need a rebuild. For day-to-day work, use the dev overlay (bind-mounts the repo and runs Vite HMR):
|
|
|
|
```bash
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build -d
|
|
```
|
|
|
|
Or set once in `.env`:
|
|
|
|
```env
|
|
COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml
|
|
```
|
|
|
|
Then a normal `docker compose up -d` enables:
|
|
|
|
- host source mounted at `/app` (PHP, Blade, routes, etc. without rebuild)
|
|
- `vite` on port **5173** for CSS/JS hot reload and Blade refresh
|
|
- `queue:listen` so worker code picks up changes between jobs
|
|
|
|
Open [http://localhost:8080](http://localhost:8080) as usual. After changing Composer packages, run `docker compose exec app composer install`.
|
|
## Services and ports
|
|
|
|
| Service | Host port | Role |
|
|
| --- | --- | --- |
|
|
| `app` | `8080` | FrankenPHP (Laravel web UI) |
|
|
| `reverb` | `8081` | WebSockets for live transcription status |
|
|
| `whisper` | `8090` | faster-whisper HTTP API |
|
|
| `queue` | — | `php artisan queue:work` for transcription jobs |
|
|
| `vite` | `5173` | Vite HMR (dev overlay only) |
|
|
|
|
### Persistent data
|
|
|
|
| Host path | Container path | Contents |
|
|
| --- | --- | --- |
|
|
| `./database` | `/app/database` | SQLite database |
|
|
| `./storage/app` | `/app/storage/app` | Uploaded audio (`private/recordings`) |
|
|
| `./storage/logs` | `/app/storage/logs` | Application logs |
|
|
|
|
Whisper model cache uses the Docker volume `whisper-huggingface-cache`.
|
|
|
|
### Useful environment variables
|
|
|
|
Edit `.env` before `docker compose up` when you need different ports or models:
|
|
|
|
| Variable | Purpose | Default |
|
|
| --- | --- | --- |
|
|
| `APP_KEY` | Required Laravel encryption key | — |
|
|
| `APP_URL` | Public app URL | `http://localhost:8080` |
|
|
| `APP_HOST_PORT` | Host port for the web app | `8080` |
|
|
| `REVERB_HOST_PORT` | Host port for WebSockets | `8081` |
|
|
| `WHISPER_HOST_PORT` | Host port for Whisper | `8090` |
|
|
| `LOCAL_WHISPER_MODEL` | Whisper model id | `Systran/faster-whisper-base` |
|
|
| `TRANSCRIPTION_TIMEOUT` | Job/HTTP timeout (seconds) | `600` |
|
|
| `DB_QUEUE_RETRY_AFTER` | Must exceed `TRANSCRIPTION_TIMEOUT` | `660` |
|
|
|
|
Inside Compose, Laravel talks to Whisper at `http://whisper:8000/v1` and publishes broadcasts to the `reverb` service. The browser connects to Reverb on `localhost:8081`.
|
|
|
|
If you change `REVERB_APP_KEY` or browser-facing Reverb host/port settings, rebuild so Vite embeds the new values:
|
|
|
|
```bash
|
|
docker compose up --build -d
|
|
```
|
|
|
|
### GPU Whisper (optional)
|
|
|
|
```bash
|
|
docker compose --profile gpu up -d --build
|
|
```
|
|
|
|
Use the GPU Whisper service instead of the CPU `whisper` service when you have an NVIDIA GPU and the NVIDIA Container Toolkit installed.
|
|
|
|
## Usage
|
|
|
|
1. Open the app and **Log in** with `admin@example.com` / `password` (or `demo@example.com` / `password`), or **Register** a new account.
|
|
2. Open **Recordings → Upload** and drop one or many audio files.
|
|
3. Transcription starts automatically (the `queue` service must be running).
|
|
4. Watch live progress on the list or detail page; stop or restart anytime.
|
|
5. Search by title, artist, or transcript text.
|
|
6. For older uploads still **Queued** with no progress, use **Queue pending transcriptions** on the recordings list.
|
|
|
|
The demo user is re-seeded on every container start. Any recordings with no owner are assigned to that demo user. Later registered users only see their own uploads.
|
|
|
|
Finished transcripts are stored on each recording and are included in search.
|
|
|
|
## Native PHP development (optional)
|
|
|
|
For hacking on the Laravel app outside the FrankenPHP image:
|
|
|
|
```bash
|
|
composer setup
|
|
docker compose up -d whisper reverb
|
|
```
|
|
|
|
Then in separate terminals:
|
|
|
|
```bash
|
|
php artisan serve --port=8000
|
|
php artisan queue:work
|
|
php artisan reverb:start
|
|
npm run dev
|
|
```
|
|
|
|
Point `.env` at local services, for example:
|
|
|
|
```env
|
|
APP_URL=http://localhost:8000
|
|
LOCAL_WHISPER_URL=http://127.0.0.1:8090/v1
|
|
REVERB_HOST=localhost
|
|
REVERB_PORT=8080
|
|
VITE_REVERB_HOST=localhost
|
|
VITE_REVERB_PORT=8080
|
|
VITE_REVERB_SCHEME=http
|
|
```
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
composer test
|
|
# or
|
|
php artisan test
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|