59 lines
2.1 KiB
Rust
59 lines
2.1 KiB
Rust
|
|
use chrono::{DateTime, Utc};
|
||
|
|
use serde::{Deserialize, Serialize};
|
||
|
|
use uuid::Uuid;
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub struct Feed {
|
||
|
|
pub id: Uuid,
|
||
|
|
pub url: String,
|
||
|
|
pub title: String,
|
||
|
|
pub last_fetched_at: Option<DateTime<Utc>>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub struct Article {
|
||
|
|
pub id: Uuid,
|
||
|
|
pub feed_id: Uuid,
|
||
|
|
pub url: String,
|
||
|
|
pub title: String,
|
||
|
|
pub summary: String,
|
||
|
|
pub published_at: Option<DateTime<Utc>>,
|
||
|
|
/// Short canonical tags assigned at ingest time (e.g. by the LLM stage),
|
||
|
|
/// used both for display and as keys into `TopicAffinities`.
|
||
|
|
pub topics: Vec<String>,
|
||
|
|
/// Cosine similarity between the article embedding and the user's
|
||
|
|
/// preference-profile embedding. Cheap first-pass filter score.
|
||
|
|
pub embedding_score: Option<f32>,
|
||
|
|
/// 0.0-1.0 relevance judgment from the LLM stage, only computed for
|
||
|
|
/// articles that clear the embedding-score shortlist threshold.
|
||
|
|
pub llm_score: Option<f32>,
|
||
|
|
/// Final blended score actually used for ranking/surfacing, see
|
||
|
|
/// `scoring::score_article`.
|
||
|
|
pub final_score: Option<f32>,
|
||
|
|
pub estimated_read_seconds: Option<u32>,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A single recorded interaction between the user and an article. Every
|
||
|
|
/// event is appended to an immutable log (see `feedsignal-db`); affinities
|
||
|
|
/// are derived from replaying/aggregating these, never mutated in place,
|
||
|
|
/// so the scoring model can be recomputed or tuned retroactively.
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub struct ReadingEvent {
|
||
|
|
pub id: Uuid,
|
||
|
|
pub article_id: Uuid,
|
||
|
|
pub occurred_at: DateTime<Utc>,
|
||
|
|
pub outcome: ReadingOutcome,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub enum ReadingOutcome {
|
||
|
|
/// Shown in the feed list but no further interaction (yet).
|
||
|
|
Impression,
|
||
|
|
/// User opened the article. `dwell_seconds` is filled in later via an
|
||
|
|
/// update event (e.g. on tab close / navigation away) once known.
|
||
|
|
Opened { dwell_seconds: Option<u32> },
|
||
|
|
Starred,
|
||
|
|
/// Explicitly marked not relevant, independent of whether it was opened.
|
||
|
|
Dismissed,
|
||
|
|
}
|