Implements persistent cross-photo knowledge memory so the agentic
insight loop can learn and recall facts about people, places, and
events across the photo collection.
Changes:
- photo_insights: drop UNIQUE(file_path) + INSERT OR REPLACE, replace
with append-only rows + is_current flag for insight history retention
- New tables: entities, entity_facts, entity_photo_links with FK
constraints and confidence scoring
- KnowledgeDao trait + SqliteKnowledgeDao with upsert, merge, and
corroboration (confidence +0.1 on duplicate fact detection)
- Four new agent tools: recall_entities, recall_facts_for_photo,
store_entity, store_fact (with object_entity_id FK support)
- Cameron entity auto-seeded with stable ID injected into system prompt
- Pre-run photo link clearing + post-loop source_insight_id backfill
- Audit REST API: GET/PATCH/DELETE /knowledge/entities/{id},
POST /knowledge/entities/merge, GET/PATCH/DELETE /knowledge/facts/{id},
GET /knowledge/recent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
229 lines
5.2 KiB
Rust
229 lines
5.2 KiB
Rust
// @generated automatically by Diesel CLI.
|
|
|
|
diesel::table! {
|
|
calendar_events (id) {
|
|
id -> Integer,
|
|
event_uid -> Nullable<Text>,
|
|
summary -> Text,
|
|
description -> Nullable<Text>,
|
|
location -> Nullable<Text>,
|
|
start_time -> BigInt,
|
|
end_time -> BigInt,
|
|
all_day -> Bool,
|
|
organizer -> Nullable<Text>,
|
|
attendees -> Nullable<Text>,
|
|
embedding -> Nullable<Binary>,
|
|
created_at -> BigInt,
|
|
source_file -> Nullable<Text>,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
daily_conversation_summaries (id) {
|
|
id -> Integer,
|
|
date -> Text,
|
|
contact -> Text,
|
|
summary -> Text,
|
|
message_count -> Integer,
|
|
embedding -> Binary,
|
|
created_at -> BigInt,
|
|
model_version -> Text,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
entities (id) {
|
|
id -> Integer,
|
|
name -> Text,
|
|
entity_type -> Text,
|
|
description -> Text,
|
|
embedding -> Nullable<Binary>,
|
|
confidence -> Float,
|
|
status -> Text,
|
|
created_at -> BigInt,
|
|
updated_at -> BigInt,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
entity_facts (id) {
|
|
id -> Integer,
|
|
subject_entity_id -> Integer,
|
|
predicate -> Text,
|
|
object_entity_id -> Nullable<Integer>,
|
|
object_value -> Nullable<Text>,
|
|
source_photo -> Nullable<Text>,
|
|
source_insight_id -> Nullable<Integer>,
|
|
confidence -> Float,
|
|
status -> Text,
|
|
created_at -> BigInt,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
entity_photo_links (id) {
|
|
id -> Integer,
|
|
entity_id -> Integer,
|
|
file_path -> Text,
|
|
role -> Text,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
favorites (id) {
|
|
id -> Integer,
|
|
userid -> Integer,
|
|
path -> Text,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
image_exif (id) {
|
|
id -> Integer,
|
|
file_path -> Text,
|
|
camera_make -> Nullable<Text>,
|
|
camera_model -> Nullable<Text>,
|
|
lens_model -> Nullable<Text>,
|
|
width -> Nullable<Integer>,
|
|
height -> Nullable<Integer>,
|
|
orientation -> Nullable<Integer>,
|
|
gps_latitude -> Nullable<Float>,
|
|
gps_longitude -> Nullable<Float>,
|
|
gps_altitude -> Nullable<Float>,
|
|
focal_length -> Nullable<Float>,
|
|
aperture -> Nullable<Float>,
|
|
shutter_speed -> Nullable<Text>,
|
|
iso -> Nullable<Integer>,
|
|
date_taken -> Nullable<BigInt>,
|
|
created_time -> BigInt,
|
|
last_modified -> BigInt,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
knowledge_embeddings (id) {
|
|
id -> Integer,
|
|
keyword -> Text,
|
|
description -> Text,
|
|
category -> Nullable<Text>,
|
|
embedding -> Binary,
|
|
created_at -> BigInt,
|
|
model_version -> Text,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
location_history (id) {
|
|
id -> Integer,
|
|
timestamp -> BigInt,
|
|
latitude -> Float,
|
|
longitude -> Float,
|
|
accuracy -> Nullable<Integer>,
|
|
activity -> Nullable<Text>,
|
|
activity_confidence -> Nullable<Integer>,
|
|
place_name -> Nullable<Text>,
|
|
place_category -> Nullable<Text>,
|
|
embedding -> Nullable<Binary>,
|
|
created_at -> BigInt,
|
|
source_file -> Nullable<Text>,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
message_embeddings (id) {
|
|
id -> Integer,
|
|
contact -> Text,
|
|
body -> Text,
|
|
timestamp -> BigInt,
|
|
is_sent -> Bool,
|
|
embedding -> Binary,
|
|
created_at -> BigInt,
|
|
model_version -> Text,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
photo_insights (id) {
|
|
id -> Integer,
|
|
file_path -> Text,
|
|
title -> Text,
|
|
summary -> Text,
|
|
generated_at -> BigInt,
|
|
model_version -> Text,
|
|
is_current -> Bool,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
search_history (id) {
|
|
id -> Integer,
|
|
timestamp -> BigInt,
|
|
query -> Text,
|
|
search_engine -> Nullable<Text>,
|
|
embedding -> Binary,
|
|
created_at -> BigInt,
|
|
source_file -> Nullable<Text>,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
tagged_photo (id) {
|
|
id -> Integer,
|
|
photo_name -> Text,
|
|
tag_id -> Integer,
|
|
created_time -> BigInt,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
tags (id) {
|
|
id -> Integer,
|
|
name -> Text,
|
|
created_time -> BigInt,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
users (id) {
|
|
id -> Integer,
|
|
username -> Text,
|
|
password -> Text,
|
|
}
|
|
}
|
|
|
|
diesel::table! {
|
|
video_preview_clips (id) {
|
|
id -> Integer,
|
|
file_path -> Text,
|
|
status -> Text,
|
|
duration_seconds -> Nullable<Float>,
|
|
file_size_bytes -> Nullable<Integer>,
|
|
error_message -> Nullable<Text>,
|
|
created_at -> Text,
|
|
updated_at -> Text,
|
|
}
|
|
}
|
|
|
|
diesel::joinable!(entity_facts -> photo_insights (source_insight_id));
|
|
diesel::joinable!(entity_photo_links -> entities (entity_id));
|
|
diesel::joinable!(tagged_photo -> tags (tag_id));
|
|
|
|
diesel::allow_tables_to_appear_in_same_query!(
|
|
calendar_events,
|
|
daily_conversation_summaries,
|
|
entities,
|
|
entity_facts,
|
|
entity_photo_links,
|
|
favorites,
|
|
image_exif,
|
|
knowledge_embeddings,
|
|
location_history,
|
|
message_embeddings,
|
|
photo_insights,
|
|
search_history,
|
|
tagged_photo,
|
|
tags,
|
|
users,
|
|
video_preview_clips,
|
|
);
|