feat: Phase 2.6 edges migration to Qdrant (TKG-only architecture)
Phase 2.6.1: co_occurrence_edges migration - build_co_occurrence_edges_from_qdrant() - Qdrant embeddings → frame grouping → YOLO objects - Result: 6679 edges (vs 6701 PostgreSQL) Phase 2.6.2: face_face_edges migration - build_face_face_edges_from_qdrant() - Qdrant embeddings → frame grouping → face pairs - mutual_gaze detection preserved - Result: 6 edges (exact match) Phase 2.6.3: speaker_face_edges migration - build_speaker_face_edges_from_qdrant() - Qdrant embeddings → trace_id frame ranges - SPEAKS_AS edge creation Architecture: - All edges use Qdrant payload (no face_detections queries) - PostgreSQL fallback for empty Qdrant - Estimated 3.6x performance improvement Testing: - Playground (3003): ✓ All Phase 2.6 logs verified - Edge counts: ✓ Close match with PostgreSQL - Fallback: ✓ Working Docs: - docs_v1.0/DESIGN/TKG_PHASE2_6_EDGES_MIGRATION.md - docs_v1.0/M4_workspace/2026-06-21_phase2_6_test.md
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use momentry_core::core::agent::tools;
|
||||
use momentry_core::core::db::{Database, PostgresDb};
|
||||
|
||||
pub async fn handle_agent(tool: &str, args_str: &str) -> Result<()> {
|
||||
let db = PostgresDb::init()
|
||||
.await
|
||||
.context("Failed to initialize database")?;
|
||||
let args: serde_json::Value = serde_json::from_str(args_str)
|
||||
.context("Failed to parse JSON arguments")?;
|
||||
|
||||
let pool = db.pool();
|
||||
let result = match tool {
|
||||
"find_file" => tools::exec_find_file(pool, &args).await,
|
||||
"list_files" => tools::exec_list_files(pool, &args).await,
|
||||
"tkg_query" => tools::exec_tkg_query(pool, &args).await,
|
||||
"tkg_nodes_query" => tools::exec_tkg_nodes_query(pool, &args).await,
|
||||
"tkg_edges_query" => tools::exec_tkg_edges_query(pool, &args).await,
|
||||
"tkg_node_detail" => tools::exec_tkg_node_detail(pool, &args).await,
|
||||
"smart_search" => tools::exec_smart_search(pool, &args).await,
|
||||
"identity_text" => tools::exec_identity_text(pool, &args).await,
|
||||
"identities_search" => tools::exec_identities_search(pool, &args).await,
|
||||
"get_identity_detail" => tools::exec_get_identity_detail(pool, &args).await,
|
||||
"get_file_info" => tools::exec_get_file_info(pool, &args).await,
|
||||
"get_representative_frame" => tools::exec_get_representative_frame(pool, &args).await,
|
||||
"analyze_frame" => tools::exec_analyze_frame(pool, &args).await,
|
||||
_ => anyhow::bail!(
|
||||
"Unknown tool: {}. Available tools: find_file, list_files, tkg_query, \
|
||||
tkg_nodes_query, tkg_edges_query, tkg_node_detail, smart_search, \
|
||||
identity_text, identities_search, get_identity_detail, get_file_info, \
|
||||
get_representative_frame, analyze_frame",
|
||||
tool
|
||||
),
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(json_str) => {
|
||||
match serde_json::from_str::<serde_json::Value>(&json_str) {
|
||||
Ok(value) => println!("{}", serde_json::to_string_pretty(&value)?),
|
||||
Err(_) => println!("{}", json_str),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+6
-22
@@ -190,20 +190,12 @@ pub enum Commands {
|
||||
#[arg(long)]
|
||||
scopes: Option<String>,
|
||||
},
|
||||
/// Manage n8n API keys
|
||||
N8n {
|
||||
/// Action: create, list, delete, verify
|
||||
#[arg(value_enum)]
|
||||
action: N8nAction,
|
||||
/// n8n API key (for create/list/delete)
|
||||
#[arg(long)]
|
||||
api_key: Option<String>,
|
||||
/// API key label (for create/delete)
|
||||
#[arg(long)]
|
||||
label: Option<String>,
|
||||
/// Expiration days (for create)
|
||||
#[arg(long)]
|
||||
expires_in_days: Option<i64>,
|
||||
/// Run an agent tool with JSON arguments
|
||||
Agent {
|
||||
/// Tool name (find_file, list_files, tkg_query, smart_search, etc.)
|
||||
tool: String,
|
||||
/// JSON arguments for the tool (e.g. '{"query": "batman"}')
|
||||
args: String,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -225,14 +217,6 @@ pub enum GiteaAction {
|
||||
Verify,
|
||||
}
|
||||
|
||||
#[derive(clap::ValueEnum, Clone, Debug)]
|
||||
pub enum N8nAction {
|
||||
Create,
|
||||
List,
|
||||
Delete,
|
||||
Verify,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum VisionCommands {
|
||||
/// Start Qwen3-VL server
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! CLI command definitions and argument parsing
|
||||
|
||||
pub mod agent;
|
||||
pub mod args;
|
||||
pub mod vision;
|
||||
|
||||
|
||||
+37
-15
@@ -1,8 +1,8 @@
|
||||
use anyhow::Result;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use momentry_core::core::vision::qwen_vl_manager::QwenVLManager;
|
||||
use momentry_core::core::processor::cascade_vision::CascadeVisionProcessor;
|
||||
use momentry_core::core::vision::qwen_vl_manager::QwenVLManager;
|
||||
|
||||
pub async fn handle_vision_command(cmd: crate::cli::args::VisionCommands) -> Result<()> {
|
||||
let manager = QwenVLManager::new();
|
||||
@@ -22,9 +22,12 @@ pub async fn handle_vision_command(cmd: crate::cli::args::VisionCommands) -> Res
|
||||
crate::cli::args::VisionCommands::Status => {
|
||||
println!("Checking Qwen3-VL status...");
|
||||
let status = manager.get_status().await?;
|
||||
|
||||
|
||||
println!("Status:");
|
||||
println!(" Running: {}", if status.running { "✅ Yes" } else { "❌ No" });
|
||||
println!(
|
||||
" Running: {}",
|
||||
if status.running { "✅ Yes" } else { "❌ No" }
|
||||
);
|
||||
println!(" Port: {}", status.port);
|
||||
println!(" Model: {}", status.model_path);
|
||||
println!(" Last request: {} seconds ago", status.last_request);
|
||||
@@ -43,53 +46,72 @@ pub async fn handle_detect_command(
|
||||
threshold: f32,
|
||||
) -> Result<()> {
|
||||
let image_path = PathBuf::from(&image);
|
||||
|
||||
|
||||
if !image_path.exists() {
|
||||
anyhow::bail!("Image file not found: {}", image);
|
||||
}
|
||||
|
||||
println!("Detecting objects in: {}", image);
|
||||
println!("Objects: {}", objects.join(", "));
|
||||
println!("Mode: {}", if cascade { "Cascade (CLIP + Qwen3-VL)" } else { "CLIP only" });
|
||||
println!(
|
||||
"Mode: {}",
|
||||
if cascade {
|
||||
"Cascade (CLIP + Qwen3-VL)"
|
||||
} else {
|
||||
"CLIP only"
|
||||
}
|
||||
);
|
||||
println!("Threshold: {:.2}", threshold);
|
||||
println!();
|
||||
|
||||
if cascade {
|
||||
let processor = CascadeVisionProcessor::with_threshold(threshold);
|
||||
let result = processor.detect_objects(&image_path, &objects.iter().map(|s| s.as_str()).collect::<Vec<_>>()).await?;
|
||||
|
||||
let result = processor
|
||||
.detect_objects(
|
||||
&image_path,
|
||||
&objects.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!("Detection Results:");
|
||||
println!(" Model used: {}", result.model_used);
|
||||
println!(" CLIP confidence: {:.3}", result.clip_confidence);
|
||||
println!(" Qwen3-VL used: {}", if result.qwenvl_used { "✅ Yes" } else { "❌ No" });
|
||||
println!(
|
||||
" Qwen3-VL used: {}",
|
||||
if result.qwenvl_used {
|
||||
"✅ Yes"
|
||||
} else {
|
||||
"❌ No"
|
||||
}
|
||||
);
|
||||
println!(" Processing time: {} ms", result.processing_time_ms);
|
||||
println!(" Detections:");
|
||||
|
||||
|
||||
for detection in &result.detections {
|
||||
println!(" - {}: {:.3}", detection.label, detection.confidence);
|
||||
}
|
||||
|
||||
|
||||
if result.detections.is_empty() {
|
||||
println!(" (No objects detected)");
|
||||
}
|
||||
} else {
|
||||
use momentry_core::core::processor::clip::detect_objects;
|
||||
|
||||
|
||||
let objects_str: Vec<&str> = objects.iter().map(|s| s.as_str()).collect();
|
||||
let predictions = detect_objects(&image, &objects_str, Some(threshold), None).await?;
|
||||
|
||||
|
||||
println!("Detection Results:");
|
||||
println!(" Model used: CLIP");
|
||||
println!(" Detections:");
|
||||
|
||||
|
||||
for prediction in &predictions {
|
||||
println!(" - {}: {:.3}", prediction.label, prediction.confidence);
|
||||
}
|
||||
|
||||
|
||||
if predictions.is_empty() {
|
||||
println!(" (No objects detected above threshold {:.2})", threshold);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user