The analyze recovery scan has been refactored to iterate through user
directories and enqueue pending analysis jobs more efficiently. The
`WorkerBusy` status has been introduced as an `Arc<AtomicBool>` to track
whether the analyze worker is currently processing a job.
This `WorkerBusy` flag is used in the `analyze::worker::run` function
and managed by a `BusyGuard` RAII struct, ensuring the flag is correctly
set and unset even in case of panics.
The `handle_my_cases` and `handle_case_detail` handlers in `user_web.rs`
now utilize the `WorkerBusy` flag to accurately display the "analyzing"
status and to trigger a self-heal of orphaned analysis inputs when the
worker is idle.
Additionally, the `WorkerBusy` type is now exported from
`server/src/lib.rs` to be accessible by other modules. The test cases
have been updated to include the `WorkerBusy` parameter when spawning
the analyze worker.
Introduces a new `/web/cases/bulk` endpoint to handle multiple case
actions simultaneously.
This change adds the following:
- A new `bulk` module for handling bulk operations.
- The `handle_bulk_action` function in `bulk.rs` to dispatch to specific
actions.
- `bulk_analyze` and `bulk_delete` functions to process the actions.
- Updates `Cargo.toml` and `Cargo.lock` to include necessary
dependencies: `form_urlencoded`, `serde_core`, `serde_html_form`, and
`serde_path_to_error`.
- Modified `axum-extra` features to include `form`.
- Adds checks for deleted cases in `collect_pending` for both analysis
and transcription recovery.
- Renames and modifies `handle_close_case` to `handle_analyze_case` in
`case_actions.rs` to better reflect its functionality.
- Adds a new `handle_delete_case` and `handle_undo_delete` to
`case_actions.rs`.
- Updates `my_cases.html` and `case_detail.html` to support bulk
actions, including checkboxes, a bulk action bar, and an "Undo last
delete" feature.
- Modifies `handle_audio` and `scan_cases` in `web.rs` to respect delete
markers.
- Updates `analyze_test.rs` with new request builders for analyze and
delete actions.
The distinction between `open/` and `done/` directories for cases has
been removed.
All cases for a user now reside directly under the user's directory
(e.g., `<data_path>/<slug>/<case_id>/`).
This simplifies path management and eliminates redundant directory
traversals.
Key changes include:
- Removed `open/` and `done/` subdirectories in path resolution.
- Introduced a `paths::case_dir` function as a single source of truth
for case directory layout.
- Updated various modules (`recovery`, `auth`, `routes`, `transcribe`,
`tests`) to use the new path structure.
- Adjusted templates to reflect the simplified case status
representation.
Introduce a new endpoint for reanalyzing cases. This feature allows
administrators
to rebuild analysis input files and enqueue new analysis jobs. The
system will
then generate a new document version, which will become the displayed
document.
This commit introduces a comprehensive suite of integration tests for
the case closing functionality.
These tests cover various scenarios including:
- Successful case closure with proper file writing and redirection.
- Handling of invalid inputs like non-UUIDs or cases without recordings.
- Authentication and authorization checks, ensuring only the case owner
can close it.
- Error handling for attempting to close a case twice or when the LLM
service is unavailable.
- Verification of the analysis worker's interaction with the mocked LLM.
- Testing the recovery mechanism for re-enqueuing pending analyses.
- Validating the document view displays the latest version.
Introduced a `test_default` method to `Config` to provide sane defaults
for integration tests. This refactors several test files to use this new
method, reducing boilerplate and improving maintainability.
Added `LLM_TIMEOUT_SECONDS` to the environment variables and `Config`
struct.
This commit introduces the foundation for web-based authentication and
user interface. It includes:
- **Session Management**: Securely handling user sessions using
cryptographically generated tokens, cookies with appropriate security
flags, and server-side storage.
- **Login/Logout Functionality**: Endpoints for users to log in with
their credentials and log out, clearing their session.
- **User Interface**: Basic templates for the login page, a list of
cases, and a detailed view of a single case, allowing users to
navigate and view their data.
- **Authorization**: An `AuthenticatedWebUser` extractor to ensure only
logged-in users can access protected web routes.
- **Configuration**: Added a `cookie_secure` option to the configuration
to control the `Secure` flag on session cookies, useful for local
development.
- **Dependencies**: Added necessary dependencies for password hashing,
time handling, and TOML file manipulation.
- **Helper Binary**: Included a `hash-password` binary to simplify
generating bcrypt hashes for user passwords.
Add a new `failed` field to `RecordingView` and corresponding logic in
the worker.
When FFmpeg remuxing or Whisper transcription fails, the worker now
renames the
original `.m4a` file to `.m4a.failed`. This prevents the recovery scan
from
reprocessing these files and signals to the UI that transcription
failed.
The UI displays a message indicating failure and suggests renaming the
file
back to `.m4a` to retry. A new integration test
`worker_renames_audio_to_failed_on_whisper_error`
is included to verify this behavior.
This commit introduces the capability to configure user-specific Whisper
settings, including language, hotwords, and initial prompts. These
settings are stored in `users.toml` and are passed to the Whisper
service for more tailored transcription results.
New unit tests have been added to verify that the `transcribe` function
correctly forwards these optional settings to the Whisper client and
omits them when they are not provided.
Additionally, a new directory `tests/fixtures/dictations` has been
created to store M4A audio files, their expected transcripts, and
associated hotword files. This serves as a regression corpus for the
Whisper pipeline. A README file explains the structure and conventions
for adding new fixtures. Several new fixtures have been added, covering
various medical domains and transcription scenarios.
Include per-user hotwords and initial prompts in the multipart form data
sent to the Whisper API. The language parameter is now dynamically set
based on user configuration, defaulting to "de" if not specified.
Introduce a new struct `WhisperUserSettings` to hold per-user
transcription settings. This allows users to customize Whisper
transcription for their specific needs directly in the `users.toml`
configuration file.
The changes include:
- Defining `WhisperUserSettings` with optional fields for `language`,
`hotwords`, and `initial_prompt`.
- Integrating `WhisperUserSettings` into the `User` struct, with
`#[serde(default)]` to ensure it defaults to
`WhisperUserSettings::default()` if not present in the TOML.
- Adding new unit tests to verify that users can be parsed correctly
with and without a `[user.whisper]` block.
- Updating existing tests in `auth_test.rs`, `upload_test.rs`, and
`web_test.rs` to include the new `whisper` field, ensuring backward
compatibility.
Introduce an `oneliner` field to the `CaseView` struct and update the
`scan_cases` function to read it from `oneliner.txt`. The `cases.html`
template is updated to display the oneliner if present. A new
integration test is added to verify the functionality.
This commit adds several unit tests for the `generate_oneliner`
function, which interacts with the Ollama API. These tests cover:
- Successful parsing of a chat response.
- Normalization of the response content to remove extra whitespace and
quotes.
- Handling of HTTP 500 errors from the server.
- Verification of sent request parameters like `keep_alive` and `model`.
- Parsing errors when the `content` field is missing in the response.
Introduces a dedicated function `validate_and_index_users` to
encapsulate the logic for validating user configurations, checking for
duplicate slugs and API keys. This function returns a `Result` to handle
errors gracefully, and its usage in `load_users` is updated to panic
with a more informative error message.
Additionally, this commit modifies the web routing to fetch and display
audio transcripts. When scanning recordings, it now attempts to read a
corresponding `.transcript.txt` file. If found, the transcript content
is included in the `RecordingView` and rendered in the `cases.html`
template. If the transcript file is not found, a "Transcription pending"
message is displayed.
The `transcribe` function in `whisper.rs` is updated to explicitly set
the language to German (`language=de`), which can improve transcription
accuracy by skipping language detection. The `encode=false` query
parameter has been removed, as the service is designed to handle encoded
audio.
Finally, tests have been added for the new `validate_and_index_users`
function to ensure duplicate slugs and API keys are correctly rejected.
Integration tests in `web_test.rs` have been updated to verify the
rendering of transcripts and the pending status.
This commit introduces a new module `transcribe::recovery` and a
function `scan_and_enqueue`.
This function is called at startup to find audio files that have not yet
been transcribed
and re-enqueues them for processing. This ensures that recordings are
not lost if the
server restarts before transcription is complete.
A new integration test `recovery_enqueues_only_pending_recordings` has
been added to
verify the functionality.
Introduces a new module for interacting with the Whisper ASR service.
This includes
an async function to POST audio files and retrieve transcripts. Error
handling
for network and HTTP status codes is also implemented.
New tests are added to cover successful transcription, HTTP error
responses,
and request timeouts.
Introduces a new web interface to list cases and play back audio
recordings. This includes:
- A new `web` module in `routes` to handle web requests.
- `handle_case_list` to scan and display available cases and their
recordings.
- `handle_audio` to serve audio files, with validation to prevent path
traversal and ensure correct file types.
- `AppError::NotFound` variant to handle missing resources gracefully.
- Updates to `projektplan.md` to document the change in STT container
and m4a preprocessing.
- New tests in `server/tests/web_test.rs` to ensure the web interface
functions correctly.
This commit introduces a new API endpoint `/api/upload` for handling
audio file uploads. It supports multipart form data, extracts `case_id`,
`recorded_at`, and `audio` fields. The audio data is saved to a
filesystem path determined by the user and case ID, within either the
`open/` or `done/` directories.
New features include:
- Integration with `axum`'s `Multipart` extractor for parsing form data.
- Validation of `case_id` as a UUID.
- Creation of case directories if they do not exist.
- Handling of late uploads to already closed cases by placing files in
the `done/` directory and removing any `.remove` marker.
- Logging of received recordings.
- Definition of `AckResponse` and `AckStatus` models for API responses.
- Addition of comprehensive unit tests for various upload scenarios,
including new case creation, invalid inputs, authentication, and late
uploads.
Refactor configuration loading to separate user credentials from server
settings.
Update dependencies to their latest compatible versions to leverage new
features
and security patches.
Key changes include:
- Moving user credentials (`api_key`, `web_password`, `role`) from
`.env`
to a dedicated `users.toml` file for better manageability and
security.
- Introducing an `AuthenticatedUser` struct and extractor for API
key-based
authentication.
- Updating `axum` and related crates to leverage Rust edition 2024
improvements.
- Adjusting configuration values and tests to reflect these changes.
Introduce a new health check endpoint at `/api/health`. This endpoint
returns a JSON response indicating the server's status and configuration
details, such as the port, data path, and configured URLs for external
services.
This change also refactors the application setup by:
- Creating a `lib.rs` file to house the `create_router` function, making
it
reusable for both the main application and integration tests.
- Moving configuration loading logic into `main.rs` and passing it as a
shared state (`Arc<Config>`) to the router.
- Adding a unit test (`health_test.rs`) to verify the functionality of
the
health check endpoint.
- Updating `Cargo.toml` and `Cargo.lock` to include the `tower`
dependency,
which is used for testing.