feat: async insight generation with SQLite job tracking
- Add insight_generation_jobs table migration and DAO - Implement job lifecycle: create_or_get_active, complete, fail, cancel - Refactor POST /insights/generate and /agentic to async spawn with timeout - Add GET /insights/generation/status endpoint with job_id and file_path lookup - Use String for enum fields in Diesel models to avoid private Bound type - Add from_str() helpers on InsightJobStatus and InsightGenerationType - Fix update_training_messages to return Result<usize, DbError> - 7/7 DAO unit tests passing
This commit is contained in:
1 parent
5a75d1a28c
commit
b87eb4e690
13 files changed
+1046
-174
No files matched your search
+101
-2
@@ -1,9 +1,81 @@
|
||||
use crate::database::schema::{
|
||||
entities, entity_facts, entity_photo_links, favorites, image_exif, libraries, personas,
|
||||
photo_insights, users, video_preview_clips,
|
||||
entities, entity_facts, entity_photo_links, favorites, image_exif, insight_generation_jobs,
|
||||
libraries, personas, photo_insights, users, video_preview_clips,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
/// Possible statuses for an insight generation job.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, FromSqlRow)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InsightJobStatus {
|
||||
Running,
|
||||
Completed,
|
||||
Failed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
impl InsightJobStatus {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Running => "running",
|
||||
Self::Completed => "completed",
|
||||
Self::Failed => "failed",
|
||||
Self::Cancelled => "cancelled",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for InsightJobStatus {
|
||||
fn to_string(&self) -> String {
|
||||
self.as_str().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl InsightJobStatus {
|
||||
pub fn from_str(s: &str) -> Self {
|
||||
match s {
|
||||
"running" => Self::Running,
|
||||
"completed" => Self::Completed,
|
||||
"failed" => Self::Failed,
|
||||
"cancelled" => Self::Cancelled,
|
||||
_ => Self::Failed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of insight generation (standard vs agentic).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InsightGenerationType {
|
||||
Standard,
|
||||
Agentic,
|
||||
}
|
||||
|
||||
impl InsightGenerationType {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Standard => "standard",
|
||||
Self::Agentic => "agentic",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for InsightGenerationType {
|
||||
fn to_string(&self) -> String {
|
||||
self.as_str().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl InsightGenerationType {
|
||||
pub fn from_str(s: &str) -> Self {
|
||||
match s {
|
||||
"standard" => Self::Standard,
|
||||
"agentic" => Self::Agentic,
|
||||
_ => Self::Standard,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = users)]
|
||||
pub struct InsertUser<'a> {
|
||||
@@ -394,3 +466,30 @@ pub struct VideoPreviewClip {
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = insight_generation_jobs)]
|
||||
pub struct InsertInsightGenerationJob {
|
||||
pub library_id: i32,
|
||||
#[diesel(column_name = file_path)]
|
||||
pub path: String,
|
||||
#[diesel(column_name = generation_type)]
|
||||
pub gen_type: String,
|
||||
pub status: String,
|
||||
pub started_at: i64,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Serialize, Clone, Debug)]
|
||||
pub struct InsightGenerationJob {
|
||||
pub id: i32,
|
||||
pub library_id: i32,
|
||||
#[diesel(column_name = file_path)]
|
||||
pub path: String,
|
||||
#[diesel(column_name = generation_type)]
|
||||
pub gen_type: String,
|
||||
pub status: String,
|
||||
pub started_at: i64,
|
||||
pub completed_at: Option<i64>,
|
||||
pub result_insight_id: Option<i32>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
Reference in new issue
Block a user