fix: face group name read consistency, sync_file_status fix, cleanup ghost records, identity_agent replaced with face_dedup

- get_face_groups_handler: COALESCE(tp.name, tn.label) for name consistency
- sync_file_status: compare JSON vs pre_chunks (not chunk table)
- face consistency: compare frames.len() not total_faces
- cleanup 2 ghost records with NULL file_name/file_path
- replace identity_agent with face_dedup in pipeline stages
- remove identity_agent_api.rs and all references
- update required_processors to match actual processors
- update AGENTS.md with team responsibilities
- add Studio pipeline changes documentation
This commit is contained in:
Accusys
2026-07-27 02:15:51 +08:00
parent fcdeab82e6
commit 39a2cbc65b
118 changed files with 19386 additions and 2964 deletions
+224 -37
View File
@@ -37,68 +37,154 @@ a { color: #0066cc; }
<h2>Temporal Knowledge Graph (TKG)</h2>
<p>TKG is a time-aligned knowledge graph built from multi-processor outputs (face, yolo, ocr, pose, asrx, gaze, lip, appearance). It produces 9 node types and 14 edge types stored in <code>dev.tkg_nodes</code> and <code>dev.tkg_edges</code>.</p>
<p><strong>Node naming convention:</strong> All trace types use <code>_track</code> suffix. Text uses <code>_region</code> (non-temporal).</p>
<p><strong>See also:</strong> <code>docs_v1.0/DESIGN/TKG_FORMATION_V1.0.md</code> for formation phases, flow diagrams, and query examples.</p>
<h3>Node Types</h3>
<table class="table">
<thead>
<tr>
<th>Node Type</th>
<th>External ID Format</th>
<th>Description</th>
<th>Key Properties</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>face_trace</code></td>
<td><code>face_track</code></td>
<td><code>trace_{trace_id}</code></td>
<td>A tracked face identity over time</td>
<td><code>trace_id</code>, <code>face_count</code>, <code>avg_confidence</code></td>
<td><code>trace_id</code>, <code>frame_count</code>, <code>status</code>, <code>avg_bbox</code>, <code>avg_yaw</code>, <code>avg_pitch</code>, <code>avg_roll</code>, <code>start_frame</code>, <code>end_frame</code>, <code>pose_count</code></td>
</tr>
<tr>
<td><code>gaze_trace</code></td>
<td><code>gaze_track</code></td>
<td><code>gaze_track_{id}</code></td>
<td>Gaze direction over time</td>
<td><code>direction</code> (frontal/left/right/up/down + diagonals)</td>
</tr>
<tr>
<td><code>lip_trace</code></td>
<td><code>lip_track</code></td>
<td><code>lip_track_{id}</code></td>
<td>Lip movement synced with speech</td>
<td><code>speaker_id</code>, <code>lip_area_range</code></td>
</tr>
<tr>
<td><code>text_trace</code></td>
<td><code>text_region</code></td>
<td><code>text_region_{id}</code></td>
<td>Spoken text aligned to time</td>
<td><code>speaker_id</code>, <code>text</code>, <code>start_time</code>, <code>end_time</code></td>
</tr>
<tr>
<td><code>appearance_trace</code></td>
<td><code>appearance_{trace_id}</code></td>
<td>Human appearance (clothing) over time</td>
<td><code>clothing_color</code>, <code>upper_cloth</code>, <code>lower_cloth</code></td>
</tr>
<tr>
<td><code>skin_tone_trace</code></td>
<td>Fitzpatrick skin tone classification</td>
<td><code>fitzpatrick_type</code> (I–VI)</td>
</tr>
<tr>
<td><code>accessory</code></td>
<td><code>accessory_{id}</code></td>
<td>Detected accessories</td>
<td><code>type</code> (glasses/hat/etc.), <code>confidence</code></td>
</tr>
<tr>
<td><code>object</code></td>
<td><code>object_{class}_{id}</code></td>
<td>YOLO-detected object</td>
<td><code>class</code>, <code>confidence</code>, <code>frame_count</code></td>
</tr>
<tr>
<td><code>speaker</code></td>
<td><code>speaker_{speaker_id}</code></td>
<td>ASRX speaker segment</td>
<td><code>speaker_id</code>, <code>segment_count</code>, <code>total_duration</code></td>
</tr>
</tbody>
</table>
<hr />
<h3>Identity Agent Integration (face_track nodes)</h3>
<p>Identity Agent marks face_track nodes with identity binding status.</p>
<h4>face_track Status Values</h4>
<table class="table">
<thead>
<tr>
<th>Status</th>
<th>Description</th>
<th>Properties</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pending</code></td>
<td>No identity suggestion</td>
<td>Default state</td>
</tr>
<tr>
<td><code>suggested</code></td>
<td>Identity Agent suggested</td>
<td><code>pending_identity_name</code>, <code>pending_identity_uuid</code>, <code>suggested_by</code>, <code>confidence</code></td>
</tr>
<tr>
<td><code>confirmed</code></td>
<td>User confirmed binding</td>
<td><code>identity_uuid</code>, <code>identity_id</code>, <code>identity_ref</code>, <code>identity_name</code></td>
</tr>
<tr>
<td><code>stranger</code></td>
<td>Stranger cluster member</td>
<td><code>stranger_id</code>, <code>stranger_ref</code></td>
</tr>
</tbody>
</table>
<h4>Suggested By Values</h4>
<table class="table">
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>tmdb</code></td>
<td>TMDb seed matched</td>
</tr>
<tr>
<td><code>propagation</code></td>
<td>Confirmed trace propagation</td>
</tr>
<tr>
<td><code>manual</code></td>
<td>User manual selection</td>
</tr>
</tbody>
</table>
<h4>Example face_track Node</h4>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;node_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_track&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;external_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_track_1&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;label&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Face Track 1&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;properties&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;trace_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;frame_count&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">45</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;start_frame&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;end_frame&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">300</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;avg_bbox&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="nt">&quot;x&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="nt">&quot;y&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">200</span><span class="p">,</span><span class="w"> </span><span class="nt">&quot;width&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">80</span><span class="p">,</span><span class="w"> </span><span class="nt">&quot;height&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">},</span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;suggested&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;pending_identity_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Tom Hanks&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;pending_identity_uuid&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;xxx-xxx&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;suggested_by&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;tmdb&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;confidence&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">0.91</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<h3>Edge Types</h3>
<table class="table">
<thead>
<tr>
<th>Edge Type</th>
<th>Storage Name</th>
<th>Source → Target</th>
<th>Description</th>
</tr>
@@ -106,39 +192,52 @@ a { color: #0066cc; }
<tbody>
<tr>
<td><code>co_occurs</code></td>
<td><code>CO_OCCURS_WITH</code></td>
<td>object ↔ object</td>
<td>Two objects appear together in same frame</td>
</tr>
<tr>
<td><code>speaker_face</code></td>
<td>speaker ↔ face_trace</td>
<td>Speaker matched to face trace via lip sync</td>
<td><code>SPEAKS_AS</code></td>
<td>speaker → face_track</td>
<td>Speaker matched to face track via lip sync</td>
</tr>
<tr>
<td><code>face_face</code></td>
<td>face_trace ↔ face_trace</td>
<td>Two face traces interact (mutual gaze)</td>
<td><code>INTERACTS_WITH</code></td>
<td>face_track ↔ face_track</td>
<td>Two face tracks interact (mutual gaze)</td>
</tr>
<tr>
<td><code>mutual_gaze</code></td>
<td>gaze_trace ↔ gaze_trace</td>
<td><code>MUTUAL_GAZE</code></td>
<td>gaze_track ↔ gaze_track</td>
<td>Two people looking at each other</td>
</tr>
<tr>
<td><code>lip_sync</code></td>
<td>lip_trace ↔ text_trace</td>
<td><code>LIP_SYNC</code></td>
<td>lip_track → text_region</td>
<td>Lip movement aligned with spoken text</td>
</tr>
<tr>
<td><code>has_appearance</code></td>
<td>face_trace ↔ appearance_trace</td>
<td><code>HAS_APPEARANCE</code></td>
<td>face_track → appearance_trace</td>
<td>Face has specific appearance</td>
</tr>
<tr>
<td><code>wears</code></td>
<td>face_trace ↔ accessory</td>
<td><code>WEARS</code></td>
<td>face_track → accessory</td>
<td>Face wears an accessory</td>
</tr>
<tr>
<td><code>hand_object</code></td>
<td><code>HOLDS</code></td>
<td>hand → object</td>
<td>Hand holding object</td>
</tr>
</tbody>
</table>
<hr />
@@ -156,10 +255,10 @@ a { color: #0066cc; }
<span class="w"> </span><span class="nt">&quot;success&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;file_uuid&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;d3f9ae8e471a1fc4d47022c66091b920&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;result&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;face_trace_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;gaze_trace_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;lip_trace_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;text_trace_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">24</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;face_track_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;gaze_track_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;lip_track_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;text_region_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">24</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;appearance_trace_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;skin_tone_trace_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;accessory_nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span>
@@ -230,7 +329,7 @@ a { color: #0066cc; }
<td>string</td>
<td>No</td>
<td>all</td>
<td>Filter by node type: <code>face_trace</code>, <code>gaze_trace</code>, <code>lip_trace</code>, <code>text_trace</code>, <code>appearance_trace</code>, <code>skin_tone_trace</code>, <code>accessory</code>, <code>object</code>, <code>speaker</code></td>
<td>Filter by node type: <code>face_track</code>, <code>gaze_track</code>, <code>lip_track</code>, <code>text_region</code>, <code>appearance_trace</code>, <code>skin_tone_trace</code>, <code>accessory</code>, <code>object</code>, <code>speaker</code></td>
</tr>
<tr>
<td><code>page</code></td>
@@ -249,11 +348,11 @@ a { color: #0066cc; }
</tbody>
</table>
<h4>Example</h4>
<div class="codehilite"><pre><span></span><code><span class="c1"># Get all face_trace nodes</span>
<div class="codehilite"><pre><span></span><code><span class="c1"># Get all face_track nodes</span>
curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/tkg/nodes&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;X-API-Key: </span><span class="nv">$KEY</span><span class="s2">&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;node_type&quot;: &quot;face_trace&quot;, &quot;page&quot;: 1, &quot;page_size&quot;: 50}&#39;</span>
<span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;node_type&quot;: &quot;face_track&quot;, &quot;page&quot;: 1, &quot;page_size&quot;: 50}&#39;</span>
<span class="c1"># Get all nodes</span>
curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/tkg/nodes&quot;</span><span class="w"> </span><span class="se">\</span>
@@ -272,12 +371,12 @@ curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>
<span class="w"> </span><span class="nt">&quot;nodes&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;node_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_trace&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;external_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;trace_0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;label&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Face Trace 0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;node_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_track&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;external_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_track_0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;label&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Face Track 0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;properties&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;trace_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;face_count&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">142</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;frame_count&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">142</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;avg_confidence&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">0.87</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
@@ -406,17 +505,17 @@ curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>
</tbody>
</table>
<h4>Example</h4>
<div class="codehilite"><pre><span></span><code><span class="c1"># Get all co_occurrence edges</span>
<div class="codehilite"><pre><span></span><code><span class="c1"># Get all co_occurs edges</span>
curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/tkg/edges&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;X-API-Key: </span><span class="nv">$KEY</span><span class="s2">&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;edge_type&quot;: &quot;co_occurs&quot;}&#39;</span>
<span class="c1"># Get edges between face_trace and speaker nodes</span>
<span class="c1"># Get edges between face_track and speaker nodes</span>
curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/tkg/edges&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;X-API-Key: </span><span class="nv">$KEY</span><span class="s2">&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;source_type&quot;: &quot;speaker&quot;, &quot;target_type&quot;: &quot;face_trace&quot;}&#39;</span>
<span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;source_type&quot;: &quot;speaker&quot;, &quot;target_type&quot;: &quot;face_track&quot;}&#39;</span>
</code></pre></div>
<h4>Response (200)</h4>
@@ -522,12 +621,12 @@ curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>
<span class="w"> </span><span class="nt">&quot;success&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;node&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;node_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_trace&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;external_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;trace_0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;label&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Face Trace 0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;node_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_track&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;external_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;face_track_0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;label&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Face Track 0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;properties&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;trace_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;face_count&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">142</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;frame_count&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">142</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;avg_confidence&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">0.87</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">},</span>
@@ -722,7 +821,95 @@ curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>
</tbody>
</table>
<hr />
<p><em>Updated: 2026-06-20 12:00:00</em></p>
<h3>Trace Management</h3>
<p>Endpoints for managing face traces: list, delete, restore, and merge.</p>
<h4><code>DELETE /api/v1/file/:file_uuid/trace/:trace_id</code></h4>
<p><strong>Auth</strong>: Required</p>
<p>Soft-delete a face trace (default) or hard-delete with <code>{"hard_delete": true}</code>.</p>
<p>Soft delete marks Qdrant points with <code>status: "deleted"</code> and TKG nodes with <code>status: "deleted"</code> in properties. Deleted traces are excluded from the traces list.</p>
<p>Hard delete permanently removes Qdrant points and TKG nodes.</p>
<p><strong>Request Body</strong> (optional):</p>
<table class="table">
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>hard_delete</code></td>
<td>boolean</td>
<td><code>false</code></td>
<td>Permanently delete instead of marking</td>
</tr>
</tbody>
</table>
<p><strong>Example</strong>:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># Soft delete</span>
curl<span class="w"> </span>-X<span class="w"> </span>DELETE<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/trace/8&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;X-API-Key: </span><span class="nv">$KEY</span><span class="s2">&quot;</span><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{}&#39;</span>
<span class="c1"># Hard delete</span>
curl<span class="w"> </span>-X<span class="w"> </span>DELETE<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/trace/8&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;X-API-Key: </span><span class="nv">$KEY</span><span class="s2">&quot;</span><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;hard_delete&quot;: true}&#39;</span>
</code></pre></div>
<p><strong>Response</strong>:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;success&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;file_uuid&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;9f6a9cd55a5809f977f5a6589b9045c5&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;trace_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;hard_delete&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;qdrant_marked&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;tkg_nodes_marked&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<h4><code>POST /api/v1/file/:file_uuid/trace/:trace_id/restore</code></h4>
<p><strong>Auth</strong>: Required</p>
<p>Undo a soft-deleted trace. Clears <code>status: "deleted"</code> from Qdrant points and TKG node properties.</p>
<p><strong>Example</strong>:</p>
<div class="codehilite"><pre><span></span><code>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/trace/8/restore&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;X-API-Key: </span><span class="nv">$KEY</span><span class="s2">&quot;</span>
</code></pre></div>
<p><strong>Response</strong>:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;success&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;file_uuid&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;9f6a9cd55a5809f977f5a6589b9045c5&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;trace_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;qdrant_restored&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;tkg_nodes_restored&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<h4><code>POST /api/v1/file/:file_uuid/trace/:source_trace_id/merge/:target_trace_id</code></h4>
<p><strong>Auth</strong>: Required</p>
<p>Merge all face points from source trace into target trace. Updates Qdrant <code>trace_id</code> and deletes source TKG node.</p>
<p><strong>Example</strong>:</p>
<div class="codehilite"><pre><span></span><code>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$API</span><span class="s2">/api/v1/file/</span><span class="nv">$FILE_UUID</span><span class="s2">/trace/16/merge/3&quot;</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;X-API-Key: </span><span class="nv">$KEY</span><span class="s2">&quot;</span>
</code></pre></div>
<p><strong>Response</strong>:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;success&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;file_uuid&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;9f6a9cd55a5809f977f5a6589b9045c5&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;source_trace_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;target_trace_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;points_moved&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">58</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;tkg_nodes_deleted&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<p><em>Updated: 2026-07-21 01:00:00</em></p>
</div>
</body>
</html>
+2 -1
View File
@@ -505,7 +505,8 @@ a { color: #0066cc; }
</tbody>
</table>
<hr />
<p><em>Updated: 2026-07-18 — New profile module: trace-profile (GET, PUT, PUT group) and file-profile (GET, PUT)</em></p>
<p><em>Updated: 2026-07-21 — Fixed external_id matching (trace_N + face_track_N formats), fixed parameter ordering in UPDATE query</em>
<em>Updated: 2026-07-18 — New profile module: trace-profile (GET, PUT, PUT group) and file-profile (GET, PUT)</em></p>
</div>
</body>
</html>
+1 -1
View File
@@ -29,7 +29,7 @@ a:hover td { background: #f8f8f8; border-radius: 4px; }
<a class="logout-btn" href="#" onclick="fetch('/api/v1/auth/logout',{method:'POST'}).then(()=>window.location.reload());return false">Logout</a>
</div>
<p class="subtitle">API 參考手冊 — 登入後可瀏覽各模組文件</p>
<table><tr onclick="window.location='11_error_codes.html'" style="cursor:pointer"><td class="cn">錯誤碼</td><td class="en">Error Codes</td></tr><tr onclick="window.location='14_identity_history.html'" style="cursor:pointer"><td class="cn">14 Identity History</td><td class="en"></td></tr><tr onclick="window.location='15_tkg.html'" style="cursor:pointer"><td class="cn">15 Tkg</td><td class="en"></td></tr><tr onclick="window.location='16_workspace.html'" style="cursor:pointer"><td class="cn">16 Workspace</td><td class="en"></td></tr><tr onclick="window.location='99_incomplete.html'" style="cursor:pointer"><td class="cn">99 Incomplete</td><td class="en"></td></tr></table>
<table><tr onclick="window.location='11_error_codes.html'" style="cursor:pointer"><td class="cn">錯誤碼</td><td class="en">Error Codes</td></tr><tr onclick="window.location='14_identity_history.html'" style="cursor:pointer"><td class="cn">14 Identity History</td><td class="en"></td></tr><tr onclick="window.location='15_tkg.html'" style="cursor:pointer"><td class="cn">15 Tkg</td><td class="en"></td></tr><tr onclick="window.location='16_workspace.html'" style="cursor:pointer"><td class="cn">16 Workspace</td><td class="en"></td></tr><tr onclick="window.location='17_progress.html'" style="cursor:pointer"><td class="cn">17 Progress</td><td class="en"></td></tr><tr onclick="window.location='18_profile.html'" style="cursor:pointer"><td class="cn">18 Profile</td><td class="en"></td></tr><tr onclick="window.location='99_incomplete.html'" style="cursor:pointer"><td class="cn">99 Incomplete</td><td class="en"></td></tr></table>
</div>
</body>
</html>