feat: schema tracking, SHA256 integrity, identity UUID fix, 3-angle face match, cuts table, trace stranger_id
This commit is contained in:
@@ -106,7 +106,7 @@ pub struct IdentityFaceRecord {
|
||||
pub id: i64,
|
||||
pub file_uuid: String,
|
||||
pub frame_number: i64,
|
||||
pub timestamp_secs: f64,
|
||||
pub timestamp_secs: Option<f64>,
|
||||
pub face_id: Option<String>,
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
@@ -795,7 +795,7 @@ impl PostgresDb {
|
||||
.await?;
|
||||
|
||||
// Chunks
|
||||
sqlx::query("CREATE TABLE IF NOT EXISTS chunk (id SERIAL PRIMARY KEY, file_uuid VARCHAR(32) NOT NULL, chunk_id VARCHAR(64) NOT NULL, chunk_type VARCHAR(32) NOT NULL, start_time DOUBLE PRECISION NOT NULL, end_time DOUBLE PRECISION NOT NULL, fps DOUBLE PRECISION DEFAULT 24.0, start_frame BIGINT DEFAULT 0, end_frame BIGINT DEFAULT 0, content JSONB NOT NULL, metadata JSONB, vector_id VARCHAR(64), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(file_uuid, chunk_id))").execute(pool).await?;
|
||||
sqlx::query("CREATE TABLE IF NOT EXISTS chunk (id SERIAL PRIMARY KEY, file_uuid VARCHAR(32) NOT NULL, chunk_id VARCHAR(32) NOT NULL, chunk_type VARCHAR(32) NOT NULL, start_time DOUBLE PRECISION NOT NULL, end_time DOUBLE PRECISION NOT NULL, fps DOUBLE PRECISION DEFAULT 24.0, start_frame BIGINT DEFAULT 0, end_frame BIGINT DEFAULT 0, content JSONB NOT NULL, metadata JSONB, vector_id VARCHAR(64), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(file_uuid, chunk_id))").execute(pool).await?;
|
||||
sqlx::query("CREATE INDEX IF NOT EXISTS idx_chunk_file ON chunk(file_uuid)")
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -814,7 +814,7 @@ impl PostgresDb {
|
||||
|
||||
// Talents & Identity Bindings
|
||||
sqlx::query("CREATE TABLE IF NOT EXISTS talents (id BIGSERIAL PRIMARY KEY, real_name VARCHAR(255) NOT NULL UNIQUE, actor_name VARCHAR(255), voice_embedding TEXT, face_embedding TEXT, metadata JSONB DEFAULT '{}', created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP)").execute(pool).await?;
|
||||
sqlx::query("CREATE TABLE IF NOT EXISTS identity_bindings (id BIGSERIAL PRIMARY KEY, identity_id BIGINT REFERENCES talents(id) ON DELETE CASCADE, identity_type VARCHAR(20) NOT NULL, identity_value VARCHAR(100) NOT NULL, metadata JSONB DEFAULT '{}', confidence DOUBLE PRECISION DEFAULT 1.0, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, UNIQUE(identity_id, identity_type, identity_value))").execute(pool).await?;
|
||||
sqlx::query("CREATE TABLE IF NOT EXISTS identity_bindings (id BIGSERIAL PRIMARY KEY, identity_id BIGINT REFERENCES identities(id) ON DELETE CASCADE, identity_type VARCHAR(20) NOT NULL, identity_value VARCHAR(100) NOT NULL, metadata JSONB DEFAULT '{}', confidence DOUBLE PRECISION DEFAULT 1.0, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, UNIQUE(identity_id, identity_type, identity_value))").execute(pool).await?;
|
||||
|
||||
// API Keys
|
||||
sqlx::query("CREATE TABLE IF NOT EXISTS api_keys (id SERIAL PRIMARY KEY, key_id VARCHAR(48) UNIQUE NOT NULL, key_hash VARCHAR(64) NOT NULL, key_prefix VARCHAR(8) NOT NULL, name VARCHAR(128) NOT NULL, key_type VARCHAR(20) NOT NULL DEFAULT 'user', user_id BIGINT, service_name VARCHAR(64), permissions JSONB DEFAULT '[\"read\", \"write\"]', expires_at TIMESTAMP, last_used_at TIMESTAMP, last_used_ip VARCHAR(45), usage_count BIGINT DEFAULT 0, status VARCHAR(20) NOT NULL DEFAULT 'active', rotation_required BOOLEAN DEFAULT FALSE, rotation_reason TEXT, grace_period_end TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)").execute(pool).await?;
|
||||
@@ -2497,8 +2497,8 @@ impl PostgresDb {
|
||||
offset: i64,
|
||||
) -> Result<Vec<IdentityFaceRecord>> {
|
||||
let query = r#"
|
||||
SELECT fd.id, fd.file_uuid, fd.frame_number, fd.timestamp_secs,
|
||||
fd.face_id, fd.x, fd.y, fd.width, fd.height, fd.confidence
|
||||
SELECT fd.id::int8, fd.file_uuid, fd.frame_number::int8, fd.timestamp_secs,
|
||||
fd.face_id, fd.x::float8, fd.y::float8, fd.width::float8, fd.height::float8, fd.confidence::float8
|
||||
FROM face_detections fd
|
||||
JOIN identities i ON fd.identity_id = i.id
|
||||
WHERE i.uuid = $1
|
||||
|
||||
@@ -82,14 +82,14 @@ fn load_checksums(scripts_dir: &PathBuf) -> HashMap<String, String> {
|
||||
}
|
||||
|
||||
pub fn validate_python_env() -> Result<()> {
|
||||
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let venv_python = manifest.join("venv").join("bin").join("python");
|
||||
let python_path = std::env::var("MOMENTRY_PYTHON_PATH")
|
||||
.unwrap_or_else(|_| "/opt/homebrew/bin/python3.11".to_string());
|
||||
let venv_python = PathBuf::from(&python_path);
|
||||
|
||||
if !venv_python.exists() {
|
||||
anyhow::bail!(
|
||||
"Python venv not found at {:?}\n\
|
||||
Run: /opt/homebrew/bin/python3.11 -m venv venv",
|
||||
venv_python
|
||||
"Python not found at {} (set MOMENTRY_PYTHON_PATH env var)",
|
||||
python_path
|
||||
);
|
||||
}
|
||||
|
||||
@@ -109,9 +109,14 @@ pub fn validate_python_env() -> Result<()> {
|
||||
tracing::warn!("Expected Python 3.11, got: {}", version.trim());
|
||||
}
|
||||
|
||||
let script_path = manifest.join("scripts");
|
||||
let scripts_dir = std::env::var("MOMENTRY_SCRIPTS_DIR")
|
||||
.unwrap_or_else(|_| {
|
||||
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
manifest.join("scripts").to_string_lossy().to_string()
|
||||
});
|
||||
let script_path = PathBuf::from(&scripts_dir);
|
||||
if !script_path.exists() {
|
||||
anyhow::bail!("Scripts directory not found at {:?}", script_path);
|
||||
anyhow::bail!("Scripts directory not found at {}", scripts_dir);
|
||||
}
|
||||
|
||||
tracing::info!("Python environment validated successfully");
|
||||
@@ -126,27 +131,37 @@ pub struct PythonExecutor {
|
||||
|
||||
impl PythonExecutor {
|
||||
pub fn new() -> Result<Self> {
|
||||
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let venv_python = manifest.join("venv").join("bin").join("python");
|
||||
let scripts_dir = manifest.join("scripts");
|
||||
let python_path = std::env::var("MOMENTRY_PYTHON_PATH")
|
||||
.unwrap_or_else(|_| "/opt/homebrew/bin/python3.11".to_string());
|
||||
let scripts_dir = std::env::var("MOMENTRY_SCRIPTS_DIR")
|
||||
.unwrap_or_else(|_| {
|
||||
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
manifest.join("scripts").to_string_lossy().to_string()
|
||||
});
|
||||
|
||||
let venv_python = PathBuf::from(&python_path);
|
||||
let scripts_path = PathBuf::from(&scripts_dir);
|
||||
|
||||
if !venv_python.exists() {
|
||||
anyhow::bail!(
|
||||
"Python venv not found at {:?}. Run: /opt/homebrew/bin/python3.11 -m venv venv",
|
||||
venv_python
|
||||
"Python not found at {} (set MOMENTRY_PYTHON_PATH env var)",
|
||||
python_path
|
||||
);
|
||||
}
|
||||
|
||||
if !scripts_dir.exists() {
|
||||
anyhow::bail!("Scripts directory not found at {:?}", scripts_dir);
|
||||
if !scripts_path.exists() {
|
||||
anyhow::bail!(
|
||||
"Scripts directory not found at {} (set MOMENTRY_SCRIPTS_DIR env var)",
|
||||
scripts_dir
|
||||
);
|
||||
}
|
||||
|
||||
// Load SHA256 checksums manifest
|
||||
let checksums = load_checksums(&scripts_dir);
|
||||
let checksums = load_checksums(&scripts_path);
|
||||
|
||||
Ok(Self {
|
||||
venv_python,
|
||||
scripts_dir,
|
||||
scripts_dir: scripts_path,
|
||||
checksums,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user