generated from john/python-template
smoothed readme and startup
This commit is contained in:
Vendored
+4
-8
@@ -8,14 +8,10 @@
|
||||
"module": "debugpy",
|
||||
"args": [
|
||||
"-m",
|
||||
"uvicorn",
|
||||
"transcription.app:create_app",
|
||||
"--factory",
|
||||
"--host",
|
||||
// "127.0.0.1",
|
||||
"0.0.0.0",
|
||||
"--port",
|
||||
"8080"
|
||||
"transcription",
|
||||
"--host", "127.0.0.1",
|
||||
"--port", "9999",
|
||||
"--database.driver", "sqlite"
|
||||
],
|
||||
"justMyCode": true,
|
||||
"console": "integratedTerminal",
|
||||
|
||||
@@ -22,18 +22,80 @@ uv sync
|
||||
|
||||
### 2) Configure environment
|
||||
|
||||
Create a `.env` file in the project root (minimum required setting shown):
|
||||
Create a `.env` file in the project root with the required OpenRouter API key:
|
||||
|
||||
```env
|
||||
OPENROUTER_API_KEY=your_openrouter_api_key
|
||||
```
|
||||
|
||||
Optional settings (defaults shown):
|
||||
Settings are read from CLI arguments first, then environment variables, then `.env`, then the defaults below.
|
||||
|
||||
### Configuration Source Precedence
|
||||
|
||||
When the same setting is provided in multiple places, the value is chosen in this order (highest priority first):
|
||||
|
||||
1. CLI arguments (for example `--port 9999`)
|
||||
2. Settings constructor arguments (used mainly in tests)
|
||||
3. Environment variables
|
||||
4. `.env` file values
|
||||
5. Model defaults in code
|
||||
|
||||
Practical examples:
|
||||
|
||||
- `--port 9999` overrides both `PORT=8000` in the shell and `PORT=7000` in `.env`.
|
||||
- `DATABASE__PATH=prod.db` in the shell overrides `DATABASE__PATH=dev.db` in `.env`.
|
||||
|
||||
#### Server and runtime
|
||||
|
||||
| Environment variable | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `HOST` | `0.0.0.0` | Address on which the server listens. |
|
||||
| `PORT` | `8000` | Server port. |
|
||||
| `LOG_LEVEL` | `info` | Uvicorn and application log level. |
|
||||
| `RELOAD` | `false` | Restart the development server when source files change. |
|
||||
| `ENVIRONMENT` | `development` | Runtime environment: `development`, `test`, or `production`. |
|
||||
|
||||
#### Provider
|
||||
|
||||
| Environment variable | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `PROVIDER` | `openrouter` | Transcription provider. |
|
||||
| `OPENROUTER_API_KEY` | Required | OpenRouter API key. |
|
||||
| `PROVIDER_MODEL` | Provider default | Optional model override. |
|
||||
| `OPENROUTER_HTTP_REFERER` | Unset | Optional OpenRouter attribution URL. |
|
||||
| `OPENROUTER_APP_TITLE` | Unset | Optional OpenRouter attribution title. |
|
||||
|
||||
#### Database and files
|
||||
|
||||
Use nested env vars for database settings (recommended):
|
||||
|
||||
```env
|
||||
DATABASE_URL=sqlite:///./transcription.db
|
||||
DATABASE__DRIVER=sqlite
|
||||
DATABASE__PATH=app.db
|
||||
# BOOTSTRAP_SCHEMA_ON_STARTUP=true
|
||||
SQLITE_CHECK_SAME_THREAD=false
|
||||
UPLOAD_DIR=./uploads
|
||||
PROMPT_DIR=./prompts
|
||||
```
|
||||
|
||||
For PostgreSQL:
|
||||
|
||||
```env
|
||||
DATABASE__DRIVER=postgres
|
||||
DATABASE__HOST=localhost
|
||||
DATABASE__PORT=5432
|
||||
DATABASE__DATABASE=transcription
|
||||
DATABASE__USER=postgres
|
||||
DATABASE__PASSWORD=change-me
|
||||
```
|
||||
|
||||
This uses Pydantic nested settings (`env_nested_delimiter='__'`) and avoids JSON blobs in `.env`. A top-level `DATABASE={...}` JSON value is still supported as a fallback, and nested keys such as `DATABASE__PATH` take precedence over conflicting JSON keys.
|
||||
|
||||
`BOOTSTRAP_SCHEMA_ON_STARTUP` creates missing tables when the app starts. When unset, it is enabled in `development` and `test`, and disabled in `production`; set it explicitly to override that policy. `SQLITE_CHECK_SAME_THREAD` defaults to `false`.
|
||||
|
||||
#### Worker
|
||||
|
||||
```env
|
||||
WORKER_MAX_RETRIES=0
|
||||
WORKER_RETRY_BACKOFF_SECONDS=0
|
||||
WORKER_PROVIDER_TIMEOUT_SECONDS=20
|
||||
@@ -45,13 +107,17 @@ WORKER_FAIL_ON_FINISH_REASON_LENGTH=false
|
||||
### 3) Run the app
|
||||
|
||||
```bash
|
||||
uv run uvicorn transcription.app:create_app --factory --reload
|
||||
uv run python -m transcription --port 9999 --reload --database.driver sqlite --bootstrap-schema-on-startup
|
||||
```
|
||||
|
||||
This starts the development server with SQLite, creates missing tables, and enables automatic reload. Run `uv run python -m transcription --help` for all CLI options; CLI names use kebab case and nested database options use dot notation, such as `--database.path ./data/transcription.db`.
|
||||
|
||||
### 4) Open in browser
|
||||
|
||||
- GUI: [http://[IP_ADDRESS]:8000/ui](http://[IP_ADDRESS]:8000/ui)
|
||||
- Health check: [http://[IP_ADDRESS]:8000/healthz](http://[IP_ADDRESS]:8000/healthz)
|
||||
- GUI: [http://localhost:9999/ui](http://localhost:9999/ui)
|
||||
- Health check: [http://localhost:9999/healthz](http://localhost:9999/healthz)
|
||||
|
||||
Replace `localhost` with the server's hostname or IP address when connecting from another machine.
|
||||
|
||||
## How to navigate the GUI
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ class Settings(BaseSettings):
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
env_nested_delimiter="__",
|
||||
cli_implicit_flags=True,
|
||||
cli_kebab_case=True,
|
||||
)
|
||||
@@ -92,7 +93,7 @@ class Settings(BaseSettings):
|
||||
@property
|
||||
def should_bootstrap_schema(self) -> bool:
|
||||
"""Return whether startup should auto-create schema for this environment."""
|
||||
if self.bootstrap_schema_on_startup is not None:
|
||||
if "bootstrap_schema_on_startup" in self.model_fields_set:
|
||||
return self.bootstrap_schema_on_startup
|
||||
return self.environment in {"development", "test"}
|
||||
|
||||
@@ -100,13 +101,13 @@ class Settings(BaseSettings):
|
||||
@cache
|
||||
def get_settings(**kwargs: Any) -> Settings:
|
||||
"""Load cached settings without reading process CLI arguments."""
|
||||
return Settings(_cli_parse_args=False, **kwargs)
|
||||
return Settings(_cli_parse_args=False, **kwargs) # pyright: ignore[reportCallIssue]
|
||||
|
||||
|
||||
def parse_cli_settings(args: Sequence[str] | None = None) -> Settings:
|
||||
"""Load settings with CLI arguments at the executable boundary."""
|
||||
cli_args = True if args is None else list(args)
|
||||
return Settings(_cli_parse_args=cli_args)
|
||||
return Settings(_cli_parse_args=cli_args) # pyright: ignore[reportCallIssue]
|
||||
|
||||
|
||||
LOGGING_CONFIG: dict[str, Any] = {
|
||||
|
||||
@@ -31,8 +31,9 @@ def resolve_session_factory(
|
||||
*,
|
||||
settings: Settings | None = None,
|
||||
) -> SessionFactory:
|
||||
active_settings = settings or get_settings()
|
||||
return get_session_factory(database_url or get_database_url(active_settings))
|
||||
if database_url is not None:
|
||||
return get_session_factory(database_url)
|
||||
return get_session_factory(get_database_url(settings or get_settings()))
|
||||
|
||||
|
||||
type SessionFactoryDep = Annotated[SessionFactory, Depends(resolve_session_factory)]
|
||||
@@ -92,4 +93,7 @@ async def transaction_scope(
|
||||
yield owned_session
|
||||
|
||||
|
||||
type TransactionScopeDep = Annotated[AsyncSessionTransaction, Depends(transaction_scope)]
|
||||
type TransactionScopeDep = Annotated[
|
||||
AsyncSession | AsyncSessionTransaction,
|
||||
Depends(transaction_scope),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user