70425939b2
Introduces a new module `auto_trigger` responsible for opportunistically initiating LLM analysis jobs. This mechanism scans case directories for new or updated recordings and transcripts, automatically creating and queuing analysis jobs when appropriate. Key components: - `evaluate_case`: Pure function to determine if a case is ready for analysis based on recording status, transcriptions, document modification times, and existing job/failure markers. - `try_enqueue`: Orchestrates the analysis job creation and queuing process if `evaluate_case` returns `AutoDecision::Enqueue`. - `try_enqueue_all_for_user`: Iterates through all user cases to trigger `try_enqueue` for eligible ones. - `write_failure_marker`/`remove_failure_marker`: Handles persistent recording of analysis failures and their cleanup. This feature aims to reduce manual intervention by automatically analyzing new or changed case data.
54 lines
1.9 KiB
Rust
54 lines
1.9 KiB
Rust
use axum::http::StatusCode;
|
|
use axum::response::{IntoResponse, Response};
|
|
use serde_json::json;
|
|
|
|
#[derive(Debug)]
|
|
pub enum AppError {
|
|
Unauthorized,
|
|
BadRequest(String),
|
|
NotFound(String),
|
|
/// 403 — authenticated but lacks permission (e.g. non-admin calling an
|
|
/// admin-only endpoint).
|
|
Forbidden(String),
|
|
/// 409 — request is valid but conflicts with current state (e.g. an
|
|
/// analysis is already running for this case).
|
|
Conflict(String),
|
|
/// 503 — the feature is unavailable right now (e.g. no LLM configured).
|
|
ServiceUnavailable(String),
|
|
Internal(String),
|
|
/// 302 redirect. Used by web auth to send unauthenticated users to login.
|
|
Redirect(String),
|
|
}
|
|
|
|
impl IntoResponse for AppError {
|
|
fn into_response(self) -> Response {
|
|
if let Self::Redirect(url) = &self {
|
|
return Response::builder()
|
|
.status(StatusCode::FOUND)
|
|
.header(axum::http::header::LOCATION, url)
|
|
.body(axum::body::Body::empty())
|
|
.unwrap();
|
|
}
|
|
|
|
let (status, message) = match &self {
|
|
Self::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized".to_owned()),
|
|
Self::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
|
|
Self::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
|
|
Self::Forbidden(msg) => (StatusCode::FORBIDDEN, msg.clone()),
|
|
Self::Conflict(msg) => (StatusCode::CONFLICT, msg.clone()),
|
|
Self::ServiceUnavailable(msg) => (StatusCode::SERVICE_UNAVAILABLE, msg.clone()),
|
|
Self::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()),
|
|
Self::Redirect(_) => unreachable!(),
|
|
};
|
|
|
|
let body = axum::Json(json!({ "error": message }));
|
|
(status, body).into_response()
|
|
}
|
|
}
|
|
|
|
impl From<std::io::Error> for AppError {
|
|
fn from(err: std::io::Error) -> Self {
|
|
Self::Internal(err.to_string())
|
|
}
|
|
}
|