docs: reorganize documentation structure and fix word highlight behavior

This commit is contained in:
Richard R 2026-02-11 06:03:51 -07:00
parent 63483e055e
commit 852092c558
30 changed files with 528 additions and 263 deletions

View file

@ -12,8 +12,9 @@ This page covers application-level configuration for provider access and authent
## Related docs
- For the complete variable reference: [Environment Variables](../reference/environment-variables)
- For auth environment variables: [Environment Variables](../reference/environment-variables#auth-and-identity)
- For TTS character limits and quota behavior: [TTS Rate Limiting](./tts-rate-limiting)
- For provider-specific guidance: [TTS Providers](./tts-providers)
- For storage/S3/SeaweedFS behavior: [Object / Blob Storage](./object-blob-storage)
- For database mode and migration commands: [Database and Migrations](./database-and-migrations)
- For database mode: [Database](./database)
- For migration behavior and commands: [Migrations](./migrations)

View file

@ -0,0 +1,26 @@
---
title: Database
---
This page covers database mode selection for OpenReader WebUI.
## Database mode
- SQLite (default): embedded DB at `docstore/sqlite3.db`; good for local/self-host single-instance setups.
- Postgres: enabled when `POSTGRES_URL` is set; recommended for production/distributed deployments.
## What the database stores
- Document and audiobook metadata/state used by server routes.
- Auth/session tables when auth is enabled.
## Related variables
- `POSTGRES_URL`
For database variable behavior, see [Environment Variables](../reference/environment-variables#database-and-object-blob-storage).
## Related docs
- [Migrations](./migrations)
- [Object / Blob Storage](./object-blob-storage)

View file

@ -1,16 +1,11 @@
---
title: Database and Migrations
title: Migrations
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
This page covers database mode selection and migration behavior for OpenReader WebUI.
## Database mode
- SQLite (default): embedded DB at `docstore/sqlite3.db`; good for local/self-host single-instance setups.
- Postgres: enabled when `POSTGRES_URL` is set; recommended for production/distributed deployments.
This page covers migration behavior for both database schema and storage data in OpenReader WebUI.
## Startup migration behavior
@ -34,17 +29,28 @@ To skip automatic startup migrations:
- Set `RUN_DRIZZLE_MIGRATIONS=false`
- Set `RUN_FS_MIGRATIONS=false`
Database variables are documented in [Environment Variables](../reference/environment-variables).
:::warning
If you disable startup migrations, ensure your deployment process runs migrations before serving traffic.
:::
## Common project commands
## Apply migrations
In most cases, you do not need manual migration commands because startup runs migrations automatically.
<Tabs groupId="migration-commands">
`pnpm migrate` applies migrations for one database target:
- Postgres when `POSTGRES_URL` is set
- SQLite when `POSTGRES_URL` is unset
You can always override the target explicitly with `--config`.
<Tabs groupId="apply-migration-commands">
<TabItem value="project-scripts" label="Project Scripts" default>
```bash
# Run pending migrations (uses Postgres config when POSTGRES_URL is set, otherwise SQLite)
# Run pending migrations for one target:
# - Postgres if POSTGRES_URL is set
# - SQLite if POSTGRES_URL is unset
pnpm migrate
# Run storage migration (filesystem -> S3 + DB)
@ -52,13 +58,10 @@ pnpm migrate-fs
# Dry-run storage migration without uploading/deleting
pnpm migrate-fs:dry-run
# Generate new migration files for both SQLite and Postgres outputs
pnpm generate
```
</TabItem>
<TabItem value="drizzle-direct" label="Drizzle Direct (Advanced)">
<TabItem value="drizzle-direct" label="Manual Drizzle Cmd">
```bash
# Migrate SQLite
@ -66,7 +69,34 @@ pnpm exec drizzle-kit migrate --config drizzle.config.sqlite.ts
# Migrate Postgres
pnpm exec drizzle-kit migrate --config drizzle.config.pg.ts
```
</TabItem>
</Tabs>
## Generate migrations
`pnpm generate` creates migration files for both configs in one run:
- `drizzle.config.sqlite.ts`
- `drizzle.config.pg.ts`
:::note
Most users do not need to run `pnpm generate`. Use it when contributing or when you have changed Drizzle schema files and need new migration files.
:::
<Tabs groupId="generate-migration-commands">
<TabItem value="project-script" label="Project Script" default>
```bash
# Generate migration files for both SQLite and Postgres outputs
pnpm generate
```
</TabItem>
<TabItem value="drizzle-direct" label="Manual Drizzle Cmd">
```bash
# Generate SQLite migrations
pnpm exec drizzle-kit generate --config drizzle.config.sqlite.ts
@ -77,6 +107,8 @@ pnpm exec drizzle-kit generate --config drizzle.config.pg.ts
</TabItem>
</Tabs>
:::warning
If you disable startup migrations, ensure your deployment process runs migrations before serving traffic.
:::
## Related docs
- [Database](./database)
- [Object / Blob Storage](./object-blob-storage)
- [Migration Environment Variables](../reference/environment-variables#migration-controls)

View file

@ -2,6 +2,9 @@
title: Object / Blob Storage
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
This page documents storage backends, blob upload routing, and core Docker mount behavior.
## Storage backends
@ -9,7 +12,7 @@ This page documents storage backends, blob upload routing, and core Docker mount
- Embedded (default): SQLite metadata + embedded SeaweedFS (`weed mini`) blobs.
- External: Postgres + external S3-compatible object storage.
Storage variables are documented in [Environment Variables](../reference/environment-variables) under the storage sections.
Storage variables are documented in [Environment Variables](../reference/environment-variables#database-and-object-blob-storage).
## Ports
@ -26,13 +29,22 @@ Storage variables are documented in [Environment Variables](../reference/environ
- Fallback path: `/api/documents/blob/upload/fallback` when direct upload fails/unreachable.
- Read/download path: blob/content serving route `/api/documents/blob` (not the upload fallback route).
## Recommended Docker mounts
## FS / Volume Mounts
| Mount | Type | Recommended | Purpose | Example |
| --- | --- | --- | --- | --- |
| `/app/docstore` | Docker named volume | Yes (for persistence) | Persists SeaweedFS blob data, SQLite metadata DB, migrations, and local runtime temp state | `-v openreader_docstore:/app/docstore` |
### App data mount
For server library mounts/import behavior, see [Server Library Import](./server-library-import).
- Target: `/app/docstore`
- Recommended: yes, for persistence
- Purpose: persists SeaweedFS blob data, SQLite metadata DB, migrations, and local runtime temp state
- Mount string: `-v openreader_docstore:/app/docstore`
### Library source mount (optional)
- Target: `/app/docstore/library`
- Recommended: optional, use read-only (`:ro`)
- Purpose: exposes host files as a source for server library import
- Mount string: `-v /path/to/your/library:/app/docstore/library:ro`
- Details: [Server Library Import](./server-library-import)
## Private blob endpoint mode
@ -46,7 +58,39 @@ If `8333` is not published externally:
Without `8333`, expect higher app-server traffic because uploads/downloads go through API routes instead of direct object endpoint access.
:::
## Audiobook storage note
## Audiobook Storage Debug Commands
- In current versions, audiobook assets live in object storage (`audiobooks_v1` keyspace), not as durable files under `/app/docstore`.
- Local filesystem usage for audiobook routes is temporary processing only.
Audiobook assets are stored in object storage under the `audiobooks_v1` keyspace. Use these commands to inspect and download objects for debugging.
<Tabs groupId="audiobook-storage-access-cli">
<TabItem value="aws-s3" label="AWS S3" default>
```bash
# List all audiobook objects
aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive
# Filter to one book id (replace <book-id>)
aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive | grep "<book-id>-audiobook/"
# Download one object by full key
aws s3 cp "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/<path>/<file>.m4b" "./audiobook.m4b"
```
</TabItem>
<TabItem value="s3-compatible" label="Embedded / MinIO / R2 / etc">
```bash
# List all audiobook objects
aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive --endpoint-url "$S3_ENDPOINT"
# Filter to one book id (replace <book-id>)
aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive --endpoint-url "$S3_ENDPOINT" | grep "<book-id>-audiobook/"
# Download one object by full key
aws s3 cp "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/<path>/<file>.m4b" "./audiobook.m4b" --endpoint-url "$S3_ENDPOINT"
```
Embedded default example: `S3_ENDPOINT=http://127.0.0.1:8333` (or your mapped host/port).
</TabItem>
</Tabs>

View file

@ -12,30 +12,21 @@ Server library import lets you browse files from one or more server directories
- Only selected files are imported
- Imported files become normal OpenReader documents
## Configure library roots
## FS / Volume Mounts
Library roots are resolved from environment variables:
### App data mount
- `IMPORT_LIBRARY_DIRS` (takes precedence): multiple roots separated by comma, colon, or semicolon
- `IMPORT_LIBRARY_DIR`: single root
- Fallback when neither is set: `docstore/library`
- Target: `/app/docstore`
- Recommended: yes, for persistence
- Purpose: stores app runtime data, metadata DB, and embedded storage state
- Mount string: `-v openreader_docstore:/app/docstore`
See [Environment Variables](../reference/environment-variables#import_library_dir) for details.
### Library source mount
## Docker mount example
Mount a host folder to the default library path:
```bash
docker run --name openreader-webui \
--restart unless-stopped \
-p 3003:3003 \
-v openreader_docstore:/app/docstore \
-v /path/to/your/library:/app/docstore/library:ro \
ghcr.io/richardr1126/openreader-webui:latest
```
Using `:ro` is recommended so the app treats the library as a read-only source.
- Target: `/app/docstore/library`
- Recommended: yes for this feature, use read-only (`:ro`)
- Purpose: exposes host files as import candidates in Server Library Import
- Mount string: `-v /path/to/your/library:/app/docstore/library:ro`
## Import flow
@ -59,6 +50,17 @@ Imported documents are still saved to the importing user's document scope.
- `.txt`
- `.md`, `.mdown`, `.markdown`
## Optional: Configure Library Roots
You only need this when the default mounted path is not what you want.
By default, OpenReader uses `docstore/library` as the import root. You can override that with environment variables:
- `IMPORT_LIBRARY_DIRS` (takes precedence): multiple roots separated by comma, colon, or semicolon
- `IMPORT_LIBRARY_DIR`: single root
See [Environment Variables](../reference/environment-variables#library-import) for variable details.
## Notes
- Library listing is capped per request (up to 10,000 files).

View file

@ -0,0 +1,40 @@
---
title: Custom OpenAI
---
Use any custom OpenAI-compatible TTS service with OpenReader.
Use this integration when your endpoint is not directly covered by built-in dropdown defaults.
## Provider
- Provider: `Custom OpenAI-Like`
- `API_BASE`: required (your service base URL)
- `API_KEY`: set if required by your service
Custom providers should expose:
- `GET /v1/audio/voices`
- `POST /v1/audio/speech`
## OpenReader setup
1. In OpenReader Settings, choose provider `Custom OpenAI-Like`.
2. Set `API_BASE` to your service base URL (typically ending with `/v1`).
3. Set `API_KEY` if your service requires authentication.
4. Choose a model and voice supported by your backend.
## Notes
:::warning Compatibility required
Custom providers must implement OpenAI-compatible TTS endpoints, including `GET /v1/audio/voices` and `POST /v1/audio/speech`.
:::
:::info Voice troubleshooting
If voices do not load, verify the `/v1/audio/voices` response shape and that the endpoint is reachable from the OpenReader server.
:::
## References
- [TTS Providers](../tts-providers)
- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior)

View file

@ -0,0 +1,33 @@
---
title: Deepinfra
---
Use Deepinfra as a hosted OpenAI-compatible TTS provider.
## Provider
- Provider: `Deepinfra`
- Default endpoint: `https://api.deepinfra.com/v1/openai` (auto-filled)
- `API_KEY`: required for authenticated DeepInfra usage
## OpenReader setup
1. In OpenReader Settings, choose provider `Deepinfra`.
2. Keep the default `API_BASE`.
3. Set `API_KEY`.
4. Choose your model and voice.
## Notes
:::tip Built-in endpoint
`Deepinfra` is a built-in provider, so OpenReader auto-fills the default `API_BASE`.
:::
:::info Model support
DeepInfra exposes multiple TTS models, including Kokoro-family options.
:::
## References
- [TTS Providers](../tts-providers)
- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior)

View file

@ -0,0 +1,68 @@
---
title: Kokoro-FastAPI
---
You can run the Kokoro TTS API server directly with Docker.
:::warning
For Kokoro issues and support, use the upstream repository: [remsky/Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI).
:::
## Provider
- Provider: `Custom OpenAI-Like`
- Typical model: `Kokoro`
- `API_BASE`: required (typically your Kokoro URL ending with `/v1`)
- `API_KEY`: set only if your deployment requires one
## Run Kokoro (CPU)
```bash
docker run -d \
--name kokoro-tts \
--restart unless-stopped \
-p 8880:8880 \
-e ONNX_NUM_THREADS=8 \
-e ONNX_INTER_OP_THREADS=4 \
-e ONNX_EXECUTION_MODE=parallel \
-e ONNX_OPTIMIZATION_LEVEL=all \
-e ONNX_MEMORY_PATTERN=true \
-e ONNX_ARENA_EXTEND_STRATEGY=kNextPowerOfTwo \
-e API_LOG_LEVEL=DEBUG \
ghcr.io/remsky/kokoro-fastapi-cpu:v0.2.4
```
## Run Kokoro (GPU)
```bash
docker run -d \
--name kokoro-tts \
--gpus all \
--user 1001:1001 \
--restart unless-stopped \
-p 8880:8880 \
-e USE_GPU=true \
-e PYTHONUNBUFFERED=1 \
-e API_LOG_LEVEL=DEBUG \
ghcr.io/remsky/kokoro-fastapi-gpu:v0.2.4
```
## OpenReader setup
1. Start Kokoro using either the CPU or GPU image.
2. In OpenReader Settings, choose provider `Custom OpenAI-Like`.
3. Set `API_BASE` to your Kokoro endpoint (for Docker Compose, commonly `http://kokoro-tts:8880/v1`).
4. Set `API_KEY` only if your deployment requires one.
5. Choose model `Kokoro`.
## Notes
:::tip Runtime guidance
GPU mode requires NVIDIA Docker support and is best on NVIDIA hardware. CPU mode is a good default on Apple Silicon and modern x86 CPUs.
:::
## References
- [remsky/Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI)
- [TTS Providers](../tts-providers)
- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior)

View file

@ -0,0 +1,33 @@
---
title: OpenAI
---
Use OpenAI directly as an OpenAI-compatible TTS provider.
## Provider
- Provider: `OpenAI`
- Default endpoint: `https://api.openai.com/v1` (auto-filled)
- `API_KEY`: required for OpenAI access
## OpenReader setup
1. In OpenReader Settings, choose provider `OpenAI`.
2. Keep the default `API_BASE`.
3. Set `API_KEY`.
4. Choose your model and voice.
## Notes
:::tip Built-in endpoint
`OpenAI` is a built-in provider, so OpenReader auto-fills the default `API_BASE`.
:::
:::info Server-side requests
OpenReader sends TTS requests from the server runtime, not directly from the browser.
:::
## References
- [TTS Providers](../tts-providers)
- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior)

View file

@ -0,0 +1,36 @@
---
title: Orpheus-FastAPI
---
Use Orpheus-FastAPI as an OpenAI-compatible TTS backend for OpenReader.
## Provider
- Provider: `Custom OpenAI-Like`
- Typical model: `Orpheus`
- `API_BASE`: required (usually your Orpheus URL ending with `/v1`)
- `API_KEY`: set only if your deployment requires one
## OpenReader setup
1. Start your Orpheus-FastAPI server.
2. In OpenReader Settings, choose provider `Custom OpenAI-Like`.
3. Set `API_BASE` to your Orpheus base URL (typically ending with `/v1`).
4. Set `API_KEY` only if your Orpheus deployment requires one.
5. Choose model `Orpheus` (or another model exposed by your deployment).
## Notes
:::info OpenAI-compatible API
OpenReader expects OpenAI-compatible audio endpoints when using Orpheus through `Custom OpenAI-Like`.
:::
:::tip Endpoint shape
Use an `API_BASE` that points at the Orpheus API root (typically ending with `/v1`).
:::
## References
- [Lex-au/Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI)
- [TTS Providers](../tts-providers)
- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior)

View file

@ -64,13 +64,16 @@ Custom providers should expose:
TTS requests are sent from the Next.js server, not directly from the browser. `API_BASE` must be reachable from the server runtime.
:::
## Related Guides
## Provider Guides
- [Environment Variables](../reference/environment-variables)
- [Kokoro-FastAPI](./tts-provider-guides/kokoro-fastapi)
- [Orpheus-FastAPI](./tts-provider-guides/orpheus-fastapi)
- [DeepInfra](./tts-provider-guides/deepinfra)
- [OpenAI](./tts-provider-guides/openai)
- [Custom OpenAI-Like](./tts-provider-guides/custom-openai)
## Related Configuration
- [TTS Environment Variables](../reference/environment-variables#tts-provider-and-request-behavior)
- [TTS Rate Limiting](./tts-rate-limiting)
- [Auth](./auth)
- [Kokoro-FastAPI](../integrations/kokoro-fastapi)
- [Orpheus-FastAPI](../integrations/orpheus-fastapi)
- [Deepinfra](../integrations/deepinfra)
- [OpenAI](../integrations/openai)
- [Custom OpenAI](../integrations/custom-openai)

View file

@ -46,6 +46,6 @@ IP backstop daily limits:
## Related docs
- Full variable list: [Environment Variables](../reference/environment-variables)
- TTS/rate-limit environment variables: [Environment Variables](../reference/environment-variables#tts-provider-and-request-behavior)
- Auth configuration: [Auth](./auth)
- Provider setup: [TTS Providers](./tts-providers)

View file

@ -95,7 +95,8 @@ For all environment variables, see [Environment Variables](../reference/environm
For app/auth behavior, see [Auth](../configure/auth).
For storage configuration, see [Object / Blob Storage](../configure/object-blob-storage).
For database mode and migrations, see [Database and Migrations](../configure/database-and-migrations).
For database mode, see [Database](../configure/database).
For migration behavior and commands, see [Migrations](../configure/migrations).
4. Run DB migrations.

View file

@ -2,9 +2,6 @@
title: Vercel Deployment
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
This guide covers deploying OpenReader WebUI to Vercel with external Postgres and S3-compatible object storage.
## What works on Vercel
@ -18,8 +15,7 @@ This guide covers deploying OpenReader WebUI to Vercel with external Postgres an
## 1. Environment Variables
<Tabs groupId="vercel-env-setup">
<TabItem value="required" label="Required" default>
Recommended production setup (auth enabled):
```bash
POSTGRES_URL=postgres://...
@ -28,24 +24,42 @@ S3_ACCESS_KEY_ID=...
S3_SECRET_ACCESS_KEY=...
S3_BUCKET=...
S3_REGION=us-east-1
S3_ENDPOINT=https://...
S3_FORCE_PATH_STYLE=true
S3_PREFIX=openreader
```
</TabItem>
<TabItem value="common" label="Common Optional">
```bash
BASE_URL=https://your-app.vercel.app
AUTH_SECRET=...
NEXT_PUBLIC_NODE_ENV=production
NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT=true
NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT=true
# Optional client/runtime feature overrides:
# NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT=false
# NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT=true
# Optional (non-AWS S3-compatible providers):
# S3_ENDPOINT=https://...
# S3_FORCE_PATH_STYLE=true
```
</TabItem>
</Tabs>
:::info `NEXT_PUBLIC_*` feature flags
- `NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT=false`: hides audiobook export UI entry points.
- `NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT=true`: enables word-highlight UI and timestamp alignment requests.
:::
:::warning `NEXT_PUBLIC_NODE_ENV` behavior
Use `NEXT_PUBLIC_NODE_ENV=production` on Vercel unless you explicitly want dev-oriented client behavior.
With `production`:
- Footer is shown in the app shell
- DOCX upload/conversion option is hidden
- Default provider/model behavior is production-oriented
- DeepInfra model picker is restricted without an API key
- Privacy modal shows hosted-service/operator wording
- Dev-only destructive document actions are hidden
With unset/non-`production`, the inverse dev behavior applies.
Full details: [Environment Variables](../reference/environment-variables#next_public_node_env).
:::
:::warning Auth recommendation
For internet-exposed Vercel deployments, set both `BASE_URL` and `AUTH_SECRET`. Running without auth is possible, but not recommended for public environments.
:::
:::tip
For all variables and defaults, see [Environment Variables](../reference/environment-variables).

View file

@ -11,7 +11,7 @@ import TabItem from '@theme/TabItem';
- A TTS API server that OpenReader can reach (Kokoro-FastAPI, Orpheus-FastAPI, DeepInfra, OpenAI, or equivalent)
:::note
If you have suitable hardware, you can run Kokoro locally with Docker. See [Kokoro-FastAPI](../integrations/kokoro-fastapi).
If you have suitable hardware, you can run Kokoro locally with Docker. See [Kokoro-FastAPI](./configure/tts-provider-guides/kokoro-fastapi).
:::
## 1. Start the Docker container
@ -75,10 +75,11 @@ If `8333` is not reachable from the browser, direct presigned access is unavaila
:::
:::info Related Docs
- [Environment Variables](../reference/environment-variables)
- [Auth](../configure/auth)
- [Database and Migrations](../configure/database-and-migrations)
- [Object / Blob Storage](../configure/object-blob-storage)
- [Environment Variables](./reference/environment-variables)
- [Auth](./configure/auth)
- [Database](./configure/database)
- [Object / Blob Storage](./configure/object-blob-storage)
- [Migrations](./configure/migrations)
:::
## 2. Configure settings in the app UI

View file

@ -1,28 +0,0 @@
---
title: Custom OpenAI
---
Use any custom OpenAI-compatible TTS service with OpenReader.
Use this integration when your endpoint is not directly covered by built-in dropdown defaults.
## Compatibility requirements
Your provider should expose:
- `GET /v1/audio/voices`
- `POST /v1/audio/speech`
## OpenReader setup
1. In OpenReader settings, choose provider `Custom OpenAI-Like`.
2. Pick model `Kokoro`, `Orpheus`, or `Other` as appropriate.
3. Set `API_BASE` to your service base URL.
4. Set `API_KEY` if required by your service.
5. Choose voice.
## Notes
- `API_BASE` is required for this provider path because OpenReader cannot infer your custom host.
- If voices do not load, verify the `/v1/audio/voices` response format.
- For variable details, see [Environment Variables](../reference/environment-variables).

View file

@ -1,19 +0,0 @@
---
title: Deepinfra
---
Use Deepinfra as a hosted OpenAI-compatible TTS provider.
## OpenReader setup
1. In OpenReader settings, choose provider `Deepinfra`.
2. Leave `API_BASE` unset unless you want to override the default endpoint.
- Default value: `https://api.deepinfra.com/v1/openai`
3. Set `API_KEY` to your Deepinfra API key if needed.
4. Choose model and voice.
## Notes
- `Deepinfra` is a built-in provider in the dropdown, so `API_BASE` is usually not required.
- Deepinfra supports multiple TTS models, including Kokoro-family options.
- For variable details, see [Environment Variables](../reference/environment-variables).

View file

@ -1,49 +0,0 @@
---
title: Kokoro-FastAPI
---
You can run the Kokoro TTS API server directly with Docker.
:::warning
For Kokoro issues and support, use the upstream repository: [remsky/Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI).
:::
## CPU image
```bash
docker run -d \
--name kokoro-tts \
--restart unless-stopped \
-p 8880:8880 \
-e ONNX_NUM_THREADS=8 \
-e ONNX_INTER_OP_THREADS=4 \
-e ONNX_EXECUTION_MODE=parallel \
-e ONNX_OPTIMIZATION_LEVEL=all \
-e ONNX_MEMORY_PATTERN=true \
-e ONNX_ARENA_EXTEND_STRATEGY=kNextPowerOfTwo \
-e API_LOG_LEVEL=DEBUG \
ghcr.io/remsky/kokoro-fastapi-cpu:v0.2.4
```
## GPU image
```bash
docker run -d \
--name kokoro-tts \
--gpus all \
--user 1001:1001 \
--restart unless-stopped \
-p 8880:8880 \
-e USE_GPU=true \
-e PYTHONUNBUFFERED=1 \
-e API_LOG_LEVEL=DEBUG \
ghcr.io/remsky/kokoro-fastapi-gpu:v0.2.4
```
## OpenReader integration notes
- In OpenReader settings, choose provider `Custom OpenAI-Like` and model `Kokoro`.
- Set OpenReader `API_BASE` to your Kokoro endpoint (for Docker Compose, commonly `http://kokoro-tts:8880/v1`).
- `API_BASE` is needed here because Kokoro is used via the custom provider path, not a built-in provider endpoint.
- GPU mode requires NVIDIA Docker support and is best on NVIDIA hardware.
- CPU mode works best on Apple Silicon or modern x86 CPUs.

View file

@ -1,18 +0,0 @@
---
title: OpenAI
---
Use OpenAI directly as an OpenAI-compatible TTS provider.
## OpenReader setup
1. In OpenReader settings, choose provider `OpenAI`.
2. Leave `API_BASE` unset unless you want to override the default `https://api.openai.com/v1`.
3. Set `API_KEY` to your OpenAI API key.
4. Choose model and voice.
## Notes
- `OpenAI` is a built-in provider in the dropdown, so `API_BASE` is usually not required.
- OpenReader routes TTS calls through its server API.
- For variable details, see [Environment Variables](../reference/environment-variables).

View file

@ -1,23 +0,0 @@
---
title: Orpheus-FastAPI
---
Use Orpheus-FastAPI as an OpenAI-compatible TTS backend for OpenReader.
## Upstream project
- [Lex-au/Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI)
## OpenReader setup
1. Start your Orpheus-FastAPI server.
2. In OpenReader settings, choose provider `Custom OpenAI-Like` and model `Orpheus`.
3. Set OpenReader `API_BASE` to your Orpheus base URL (typically ending with `/v1`).
4. Set `API_KEY` if your Orpheus deployment requires one.
5. Choose voice.
## Notes
- `API_BASE` is needed here because Orpheus is configured through the custom provider path.
- OpenReader expects OpenAI-compatible audio endpoints.
- For variable details, see [Environment Variables](../reference/environment-variables).

View file

@ -31,15 +31,16 @@ It supports multiple TTS providers including OpenAI, DeepInfra, and custom OpenA
- 🎨 **Customizable Experience**
- Theme, TTS, and document handling controls
## 🚀 Start Here
## 🧭 Key Docs
- [Docker Quick Start](./start-here/docker-quick-start)
- [Vercel Deployment](./start-here/vercel-deployment)
- [Local Development](./start-here/local-development)
- [Docker Quick Start](./docker-quick-start)
- [Local Development](./deploy/local-development)
- [Vercel Deployment](./deploy/vercel-deployment)
- [Environment Variables](./reference/environment-variables)
- [Auth](./configure/auth)
- [Database and Migrations](./configure/database-and-migrations)
- [Database](./configure/database)
- [Object / Blob Storage](./configure/object-blob-storage)
- [Migrations](./configure/migrations)
- [Server Library Import](./configure/server-library-import)
- [TTS Providers](./configure/tts-providers)

View file

@ -9,9 +9,9 @@ This is the single reference page for OpenReader WebUI environment variables.
| Variable | Area | Default | When to set |
| --- | --- | --- | --- |
| `NEXT_PUBLIC_NODE_ENV` | Runtime mode | `development` | Set `production` for production builds |
| `NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT` | Client feature flags | `true` unless set to `false` | Disable audiobook export UI in any environment |
| `NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT` | Client feature flags | `true` in dev, `false` in production | Force-enable word highlight UI in production |
| `NEXT_PUBLIC_NODE_ENV` | Runtime mode | treated as `development` unless `production` | Set `production` for production client behavior |
| `NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT` | Client feature flags | `true` unless set to `false` | Set `false` to hide audiobook export UI |
| `NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT` | Client feature flags | `false` unless set to `true` | Set `true` to enable word highlight + alignment |
| `API_BASE` | TTS provider | none | Point to your OpenAI-compatible TTS base URL |
| `API_KEY` | TTS provider | `none` fallback in TTS route | Set when provider requires auth |
| `TTS_CACHE_MAX_SIZE_BYTES` | TTS caching | `268435456` (256 MB) | Tune in-memory TTS cache size |
@ -52,12 +52,23 @@ This is the single reference page for OpenReader WebUI environment variables.
## Detailed Reference
## Client Runtime and Feature Flags
### NEXT_PUBLIC_NODE_ENV
Controls development vs production behavior in client/server code paths.
- Typical values: `development`, `production`
- In production builds, set `production`
- OpenReader `isDev` checks rely on this variable directly
- If this is not `production`, OpenReader treats the client as development mode
- In deployed environments, set `NEXT_PUBLIC_NODE_ENV=production` explicitly for predictable production behavior
- Affects:
- Footer visibility in the app shell
- DOCX upload/conversion availability in upload UI
- Default provider/model behavior for first-run TTS config
- DeepInfra model picker restrictions when no API key is set
- Privacy modal wording (hosted-service vs local/dev wording)
- Dev-only destructive document actions in settings
### NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT
@ -65,14 +76,20 @@ Controls whether audiobook export UI/actions are shown in the client.
- Default behavior: enabled unless explicitly set to `false`
- Applies in both development and production
- Affects export entry points in PDF/EPUB pages and document settings UI
### NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT
Controls word-by-word highlighting UI in production builds.
Controls word-by-word highlighting UI and timestamp-alignment behavior.
- Development default: enabled
- Production default: disabled unless set to `true`
- Default behavior: disabled unless set to `true`
- Applies in both development and production
- Requires working timestamp generation (for example `WHISPER_CPP_BIN`)
- Affects:
- Word-highlight toggles in document settings
- Alignment requests during TTS playback
## TTS Provider and Request Behavior
### API_BASE
@ -80,6 +97,7 @@ Base URL for OpenAI-compatible TTS API requests.
- Example: `http://host.docker.internal:8880/v1`
- Can be overridden per request from UI settings
- Related docs: [TTS Providers](../configure/tts-providers)
### API_KEY
@ -87,6 +105,7 @@ Default API key for TTS provider requests.
- Example: `none` or your provider token
- Can be overridden by request headers from app settings
- Related docs: [TTS Providers](../configure/tts-providers)
### TTS_CACHE_MAX_SIZE_BYTES
@ -156,12 +175,15 @@ Authenticated IP backstop daily character limit.
- Default: `1000000`
## Auth and Identity
### BASE_URL
External base URL for this OpenReader instance.
- Required with `AUTH_SECRET` to enable auth
- Example: `http://localhost:3003` or `https://reader.example.com`
- Related docs: [Auth](../configure/auth)
### AUTH_SECRET
@ -169,6 +191,7 @@ Secret key used by auth/session handling.
- Required with `BASE_URL` to enable auth
- Generate with `openssl rand -base64 32`
- Related docs: [Auth](../configure/auth)
### AUTH_TRUSTED_ORIGINS
@ -176,6 +199,7 @@ Additional allowed origins for auth requests.
- Comma-separated list
- `BASE_URL` origin is always trusted automatically
- Related docs: [Auth](../configure/auth)
### GITHUB_CLIENT_ID
@ -196,6 +220,9 @@ Controls Better Auth rate limiting.
- Default behavior: auth-layer rate limiting enabled
- Set to `true` to disable auth-layer rate limiting
- This does not affect TTS character rate limiting
- Related docs: [Auth](../configure/auth)
## Database and Object Blob Storage
### POSTGRES_URL
@ -203,6 +230,7 @@ Switches metadata/auth storage from SQLite to Postgres.
- Unset: SQLite at `docstore/sqlite3.db`
- Set: Postgres mode
- Related docs: [Database](../configure/database)
### USE_EMBEDDED_WEED_MINI
@ -210,18 +238,21 @@ Controls embedded SeaweedFS startup.
- Default behavior: treated as enabled when unset
- Set `false` to rely on external S3-compatible storage
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### WEED_MINI_DIR
Data directory for embedded SeaweedFS (`weed mini`).
- Default: `docstore/seaweedfs`
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### WEED_MINI_WAIT_SEC
Maximum seconds to wait for embedded SeaweedFS startup.
- Default: `20`
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### S3_ACCESS_KEY_ID
@ -229,6 +260,7 @@ Access key for S3-compatible storage.
- Auto-generated in embedded mode if unset
- Set explicitly for stable credentials or external providers
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### S3_SECRET_ACCESS_KEY
@ -236,6 +268,7 @@ Secret key for S3-compatible storage.
- Auto-generated in embedded mode if unset
- Set explicitly for stable credentials or external providers
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### S3_BUCKET
@ -243,12 +276,14 @@ Bucket name used for document blobs.
- Default in embedded mode: `openreader-documents`
- Required for external S3-compatible storage
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### S3_REGION
Region used by the S3 client.
- Default in embedded mode: `us-east-1`
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### S3_ENDPOINT
@ -257,6 +292,7 @@ Endpoint URL for S3-compatible storage.
- In embedded mode, defaults to `http://<BASE_URL host>:8333` (or detected host)
- For AWS S3, usually leave unset
- For MinIO/SeaweedFS/R2/B2-style APIs, typically set explicitly
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### S3_FORCE_PATH_STYLE
@ -264,12 +300,16 @@ Path-style S3 addressing toggle.
- Default in embedded mode: `true`
- Set according to provider requirements
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
### S3_PREFIX
Prefix prepended to stored object keys.
- Default: `openreader`
- Related docs: [Object / Blob Storage](../configure/object-blob-storage)
## Migration Controls
### RUN_DRIZZLE_MIGRATIONS
@ -277,6 +317,7 @@ Controls startup migration execution in shared entrypoint.
- Default: `true`
- Set `false` to skip automatic startup Drizzle schema migrations
- Related docs: [Migrations](../configure/migrations), [Database](../configure/database)
### RUN_FS_MIGRATIONS
@ -285,6 +326,9 @@ Controls startup filesystem-to-object-store migration execution in shared entryp
- Default: `true`
- Runs `scripts/migrate-fs-v2.mjs` at startup after DB migrations
- Set `false` to skip automatic storage migration pass
- Related docs: [Migrations](../configure/migrations), [Database](../configure/database), [Object / Blob Storage](../configure/object-blob-storage)
## Library Import
### IMPORT_LIBRARY_DIR
@ -292,6 +336,7 @@ Single directory root for server library import.
- Used when `IMPORT_LIBRARY_DIRS` is unset
- Default fallback root: `docstore/library`
- Related docs: [Server Library Import](../configure/server-library-import)
### IMPORT_LIBRARY_DIRS
@ -299,6 +344,9 @@ Multiple library roots for server library import.
- Separator: comma, colon, or semicolon
- Takes precedence over `IMPORT_LIBRARY_DIR`
- Related docs: [Server Library Import](../configure/server-library-import)
## Audio Tooling and Alignment
### WHISPER_CPP_BIN

View file

@ -98,7 +98,7 @@ const config: Config = {
{
title: 'Community',
items: [
{ label: 'Support', to: '/project/support-and-contributing' },
{ label: 'Support', to: '/about/support-and-contributing' },
{ label: 'GitHub Discussions', href: 'https://github.com/richardr1126/OpenReader-WebUI/discussions' },
{ label: 'Issues', href: 'https://github.com/richardr1126/OpenReader-WebUI/issues' },
],

View file

@ -3,10 +3,50 @@ import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';
const sidebars: SidebarsConfig = {
tutorialSidebar: [
'intro',
{
type: 'doc',
id: 'docker-quick-start',
label: '🐳 Docker Quick Start',
},
{
type: 'category',
label: 'Start Here',
items: ['start-here/docker-quick-start', 'start-here/vercel-deployment', 'start-here/local-development'],
label: '⚙️ Configure',
items: [
{
type: 'category',
label: '🔊 TTS Providers',
link: {
type: 'doc',
id: 'configure/tts-providers',
},
items: [
'configure/tts-provider-guides/kokoro-fastapi',
'configure/tts-provider-guides/orpheus-fastapi',
'configure/tts-provider-guides/deepinfra',
'configure/tts-provider-guides/openai',
'configure/tts-provider-guides/custom-openai',
],
},
{
type: 'doc',
id: 'configure/auth',
label: '🔐 Auth',
},
{
type: 'doc',
id: 'configure/server-library-import',
label: '📥 Server Library Import',
},
'configure/tts-rate-limiting',
'configure/database',
'configure/object-blob-storage',
'configure/migrations',
],
},
{
type: 'category',
label: '🚀 Deploy',
items: ['deploy/local-development', 'deploy/vercel-deployment'],
},
{
type: 'category',
@ -18,31 +58,8 @@ const sidebars: SidebarsConfig = {
},
{
type: 'category',
label: 'Configure',
items: [
'configure/tts-providers',
'configure/auth',
'configure/tts-rate-limiting',
'configure/database-and-migrations',
'configure/object-blob-storage',
'configure/server-library-import',
],
},
{
type: 'category',
label: 'Integrations',
items: [
'integrations/kokoro-fastapi',
'integrations/orpheus-fastapi',
'integrations/deepinfra',
'integrations/openai',
'integrations/custom-openai',
],
},
{
type: 'category',
label: 'Project',
items: ['project/support-and-contributing', 'project/acknowledgements', 'project/license'],
label: 'About',
items: ['about/support-and-contributing', 'about/acknowledgements', 'about/license'],
},
],
};

View file

@ -11,9 +11,8 @@ import { useParams } from 'next/navigation';
import type { TTSAudiobookChapter } from '@/types/tts';
import type { AudiobookGenerationSettings } from '@/types/client';
const isDev = process.env.NEXT_PUBLIC_NODE_ENV !== 'production' || process.env.NODE_ENV == null;
const canExportAudiobook = process.env.NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT !== 'false';
const canWordHighlight = isDev || process.env.NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT === 'true';
const canWordHighlight = process.env.NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT === 'true';
const viewTypeTextMapping = [
{ id: 'single', name: 'Single Page' },

View file

@ -99,6 +99,7 @@ interface SetTextOptions {
const CONTINUATION_LOOKAHEAD = 600;
const SENTENCE_ENDING = /[.?!…]["'”’)\]]*\s*$/;
const wordHighlightFeatureEnabled = process.env.NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT === 'true';
// Tiny silent WAV used to unlock HTML5 audio on iOS/Safari.
const SILENT_WAV_DATA_URI =
@ -857,8 +858,9 @@ export function TTSProvider({ children }: { children: ReactNode }): ReactElement
*/
const getAudio = useCallback(async (sentence: string, preload = false): Promise<TTSAudioBuffer | undefined> => {
const alignmentEnabledForCurrentDoc =
(!isEPUB && pdfHighlightEnabled && pdfWordHighlightEnabled) ||
(isEPUB && epubHighlightEnabled && epubWordHighlightEnabled);
wordHighlightFeatureEnabled &&
((!isEPUB && pdfHighlightEnabled && pdfWordHighlightEnabled) ||
(isEPUB && epubHighlightEnabled && epubWordHighlightEnabled));
// Helper to ensure we have an alignment for a given
// sentence/audio pair, even when the audio itself is
// served from the local cache.

View file

@ -1,6 +1,7 @@
import type { DocumentListState } from '@/types/documents';
const isDev = process.env.NEXT_PUBLIC_NODE_ENV !== 'production' || process.env.NODE_ENV == null;
const wordHighlightEnabledByDefault = process.env.NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT === 'true';
export type ViewType = 'single' | 'dual' | 'scroll';
@ -53,9 +54,9 @@ export const APP_CONFIG_DEFAULTS: AppConfigValues = {
savedVoices: {},
smartSentenceSplitting: true,
pdfHighlightEnabled: true,
pdfWordHighlightEnabled: isDev,
pdfWordHighlightEnabled: wordHighlightEnabledByDefault,
epubHighlightEnabled: true,
epubWordHighlightEnabled: isDev,
epubWordHighlightEnabled: wordHighlightEnabledByDefault,
firstVisit: false,
documentListState: {
sortBy: 'name',