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:
322
docs_v1.0/GUIDES/WordPress_Frontend_VideoPlayback_Guide.md
Normal file
322
docs_v1.0/GUIDES/WordPress_Frontend_VideoPlayback_Guide.md
Normal file
@@ -0,0 +1,322 @@
|
||||
---
|
||||
document_type: "guide"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "WordPress Frontend — Video Playback Integration Guide"
|
||||
version: "V1.0"
|
||||
date: "2026-06-07"
|
||||
author: "OpenCode"
|
||||
status: "draft"
|
||||
tags:
|
||||
- "wordpress"
|
||||
- "frontend"
|
||||
- "video-playback"
|
||||
- "thumbnail"
|
||||
- "integration"
|
||||
related_documents:
|
||||
- "DESIGN/VideoPlayback_Architecture_V1.0.md"
|
||||
---
|
||||
|
||||
# WordPress Frontend — Video Playback Integration Guide
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Scope | WordPress frontend (m5wp) video playback & thumbnail changes |
|
||||
| Status | Draft |
|
||||
| Backend | Momentry Core API (m5api.momentry.ddns.net) |
|
||||
| Caddy | Reverse proxy + file server on m5wp.momentry.ddns.net |
|
||||
| Target audience | WordPress frontend developer |
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Browser (search-chat @ m5wp.momentry.ddns.net)
|
||||
│
|
||||
├─ POST https://m5api.momentry.ddns.net/api/v1/search/smart?api_key=KEY
|
||||
│ └─ Response includes serve_url + file_name (already live)
|
||||
│
|
||||
├─ <video src="serve_url"> # Local: Caddy file_server, zero backend cost
|
||||
│ └─ https://m5wp.momentry.ddns.net/files/demo/Charade_YouTube_24fps.mp4
|
||||
│
|
||||
├─ <video src="/wp-json/.../media"> # Remote fallback: Caddy → Momentry streaming
|
||||
│ └─ /wp-json/momentry/v1/media?uuid=X&type=video&start_time=S&end_time=E
|
||||
│
|
||||
└─ <img src="/wp-json/.../media"> # Thumbnail: unchanged, already working
|
||||
└─ /wp-json/momentry/v1/media?type=thumbnail&uuid=X&frame=N
|
||||
```
|
||||
|
||||
**Traffic paths (all verified production)**:
|
||||
|
||||
| Resource | Path | Status |
|
||||
|----------|------|--------|
|
||||
| Search results | `m5api.momentry.ddns.net/api/v1/search/smart` | ✅ Returns serve_url |
|
||||
| Video (serve_url) | `m5wp.momentry.ddns.net/files/...` | ✅ 200, Accept-Ranges: bytes |
|
||||
| Video (streaming fallback) | `m5wp/.../media?type=video` | ✅ 200 video/mp4 |
|
||||
| Thumbnail | `m5wp/.../media?type=thumbnail` | ✅ 200 image/jpeg |
|
||||
|
||||
---
|
||||
|
||||
## 1. Search Endpoint Migration
|
||||
|
||||
### Before (being deprecated — drops serve_url / file_name)
|
||||
```
|
||||
POST /wp-json/momentry/v1/search-proxy
|
||||
→ WordPress PHP proxy → localhost:3002 → response
|
||||
|
||||
Critical problem: The search-proxy rebuilds the response envelope.
|
||||
Even though Momentry Core returns `serve_url` and `file_name`,
|
||||
these fields arrive as `null` in the proxy response because:
|
||||
1. Semantic mode (`/api/v1/search/llm-smart`) extracts only
|
||||
`$smart_data['results']` and wraps it in a new envelope
|
||||
with explicitly listed fields — unknown fields like
|
||||
`serve_url` / `file_name` are silently dropped.
|
||||
2. Keyword/universal mode passes through the raw response,
|
||||
but `serve_url` is computed post-search by Momentry Core's
|
||||
enricher — this enrichment path may not trigger when the
|
||||
request comes through a non-standard proxy route.
|
||||
|
||||
Net effect: The frontend never receives `serve_url` or `file_name`
|
||||
from the proxy, making direct Caddy file_server playback impossible.
|
||||
→ **Must call m5api directly to get these fields.**
|
||||
```
|
||||
|
||||
### After
|
||||
```javascript
|
||||
var SEARCH_URL = 'https://m5api.momentry.ddns.net/api/v1/search/smart';
|
||||
var API_KEY = 'muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69';
|
||||
```
|
||||
|
||||
CORS is open (`access-control-allow-origin: *`), so direct fetch works.
|
||||
|
||||
### API Key Transmission
|
||||
|
||||
**Method A: query parameter (recommended for simplicity)**
|
||||
```javascript
|
||||
fetch(SEARCH_URL + '?api_key=' + encodeURIComponent(API_KEY), { ... })
|
||||
```
|
||||
|
||||
**Method B: X-API-Key header**
|
||||
```javascript
|
||||
fetch(SEARCH_URL, {
|
||||
headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' }
|
||||
})
|
||||
```
|
||||
|
||||
**Method C (future): Caddy m5api block injects key**
|
||||
No frontend changes needed once configured.
|
||||
|
||||
---
|
||||
|
||||
## 2. Search Response Format
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "gun",
|
||||
"results": [
|
||||
{
|
||||
"file_uuid": "a6fb22eebefaef17e62af874997c5944",
|
||||
"file_name": "Charade_YouTube_24fps.mp4",
|
||||
"serve_url": "https://m5wp.momentry.ddns.net/files/demo/Charade_YouTube_24fps.mp4",
|
||||
"start_frame": 63445,
|
||||
"start_time": 2646.19,
|
||||
"end_time": 0.0,
|
||||
"fps": 23.976,
|
||||
"summary": "He has a gun, Mr. Bartholomew.",
|
||||
"similarity": 0.755
|
||||
}
|
||||
],
|
||||
"strategy": "hybrid_semantic+keyword"
|
||||
}
|
||||
```
|
||||
|
||||
### New Fields (both already live in backend)
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `file_name` | `string` | Original filename, e.g. `Charade_YouTube_24fps.mp4` |
|
||||
| `serve_url` | `string \| null` | Direct playable URL via Caddy file_server. `null` if file is not on local storage. |
|
||||
|
||||
---
|
||||
|
||||
## 3. Code Changes: `fetchSearchApi()`
|
||||
|
||||
### Before
|
||||
```javascript
|
||||
function fetchSearchApi(query) {
|
||||
return fetch('/wp-json/momentry/v1/search-proxy', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ query: query, mode: CURRENT_SEARCH_MODE })
|
||||
}).then(r => r.json());
|
||||
}
|
||||
```
|
||||
|
||||
### After
|
||||
```javascript
|
||||
var API_KEY = 'muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69';
|
||||
var SEARCH_BASE = 'https://m5api.momentry.ddns.net/api/v1/search/smart';
|
||||
var ID_SEARCH_BASE = 'https://m5api.momentry.ddns.net/api/v1/identities/search';
|
||||
|
||||
function fetchSearchApi(query) {
|
||||
// People mode → identities endpoint
|
||||
if (CURRENT_SEARCH_MODE === 'people') {
|
||||
var url = ID_SEARCH_BASE + '?q=' + encodeURIComponent(query)
|
||||
+ '&limit=20&page=1&page_size=20'
|
||||
+ '&api_key=' + encodeURIComponent(API_KEY);
|
||||
return fetch(url).then(checkStatus).then(r => r.json());
|
||||
}
|
||||
|
||||
// Keyword / Semantic → search/smart (unified)
|
||||
var url = SEARCH_BASE + '?api_key=' + encodeURIComponent(API_KEY);
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ query: query, limit: 30 })
|
||||
}).then(checkStatus).then(r => r.json());
|
||||
}
|
||||
|
||||
function checkStatus(r) {
|
||||
if (!r.ok) throw new Error('API error: ' + r.status + ' ' + r.statusText);
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
### Key Changes
|
||||
|
||||
| Item | Before | After |
|
||||
|------|--------|-------|
|
||||
| URL | WordPress search-proxy | m5api direct |
|
||||
| API Key | In PHP (hidden) | URL query param (exposed) |
|
||||
| Mode param | Sent to proxy | Only used for people vs smart routing |
|
||||
| limit | 20 | 30 |
|
||||
| Error handling | Silent failure | Explicit throw |
|
||||
|
||||
---
|
||||
|
||||
## 4. Code Changes: `mapMomentToCard()` — serve_url Support
|
||||
|
||||
### Before
|
||||
```javascript
|
||||
function mapMomentToCard(m) {
|
||||
var videoId = m.file_uuid;
|
||||
var tStart = m.start_time;
|
||||
var tEnd = m.end_time;
|
||||
var fps = m.fps;
|
||||
|
||||
return {
|
||||
id: m.id || m.file_uuid,
|
||||
url: '/wp-json/momentry/v1/media?uuid=' + encodeURIComponent(videoId)
|
||||
+ '&type=video&start_time=' + encodeURIComponent(tStart)
|
||||
+ '&end_time=' + encodeURIComponent(tEnd),
|
||||
thumbnailUrl: buildThumbUrl(videoId, m.start_frame || tStart),
|
||||
title: m.summary || 'Untitled',
|
||||
fileUuid: videoId,
|
||||
startTime: tStart,
|
||||
endTime: tEnd,
|
||||
fps: fps,
|
||||
momentId: m.id
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### After
|
||||
```javascript
|
||||
function mapMomentToCard(m) {
|
||||
var videoId = m.file_uuid;
|
||||
var tStart = m.start_time;
|
||||
var tEnd = m.end_time;
|
||||
var fps = m.fps;
|
||||
|
||||
// 1. Prefer serve_url (local file, Caddy direct serve)
|
||||
var videoUrl = m.serve_url || null;
|
||||
|
||||
// 2. Fall back to streaming endpoint
|
||||
if (!videoUrl) {
|
||||
videoUrl = '/wp-json/momentry/v1/media?uuid=' + encodeURIComponent(videoId)
|
||||
+ '&type=video&start_time=' + encodeURIComponent(tStart)
|
||||
+ '&end_time=' + encodeURIComponent(tEnd);
|
||||
}
|
||||
|
||||
return {
|
||||
id: m.id || m.file_uuid,
|
||||
url: videoUrl,
|
||||
thumbnailUrl: buildThumbUrl(videoId, m.start_frame || tStart),
|
||||
title: m.summary || 'Untitled',
|
||||
fileUuid: videoId,
|
||||
startTime: tStart,
|
||||
endTime: tEnd,
|
||||
fps: fps,
|
||||
momentId: m.id,
|
||||
serveUrl: m.serve_url
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Note: `openMM()` and `openVideo()` use `card.url` which is now already set to `serve_url` by `mapMomentToCard()`. No changes needed in those functions.
|
||||
|
||||
---
|
||||
|
||||
## 5. Thumbnails (No Change)
|
||||
|
||||
Thumbnail URL format stays the same:
|
||||
```
|
||||
/wp-json/momentry/v1/media?type=thumbnail&uuid={uuid}&frame={frame}
|
||||
```
|
||||
|
||||
Caddy proxy + Momentry Core `media-proxy` endpoint are deployed and verified (`200 image/jpeg`).
|
||||
|
||||
---
|
||||
|
||||
## 6. Implementation Summary
|
||||
|
||||
| # | Task | Location | Change | Depends On |
|
||||
|---|------|----------|--------|------------|
|
||||
| 1 | Update `fetchSearchApi()` | post_content ID=523 | Direct call to m5api, api_key query param | None |
|
||||
| 2 | Update `mapMomentToCard()` | post_content ID=523 | Read `m.serve_url`, use as `url` when present | Task 1 |
|
||||
| 3 | Add error handling | post_content ID=523 | `checkStatus()` helper | Task 1 |
|
||||
| 4 | Keep thumbnails | post_content ID=523 | No change needed | None |
|
||||
| 5 | Update `send()` | post_content ID=523 | Remove mode param for search/smart | Task 1 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Testing
|
||||
|
||||
Open the browser console on search-chat page:
|
||||
|
||||
```javascript
|
||||
// 1. Confirm search returns serve_url
|
||||
fetch('https://m5api.momentry.ddns.net/api/v1/search/smart?api_key=muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({query: 'gun', limit: 1})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(d => console.log('serve_url:', d.results[0]?.serve_url, 'file_name:', d.results[0]?.file_name));
|
||||
|
||||
// 2. Test serve_url direct playback
|
||||
var vid = document.createElement('video');
|
||||
vid.src = 'https://m5wp.momentry.ddns.net/files/demo/Charade_YouTube_24fps.mp4#t=10,20';
|
||||
vid.controls = true;
|
||||
document.body.appendChild(vid);
|
||||
|
||||
// 3. Test thumbnail (unchanged)
|
||||
var img = new Image();
|
||||
img.onload = () => console.log('Thumbnail OK');
|
||||
img.onerror = () => console.error('Thumbnail failed');
|
||||
img.src = '/wp-json/momentry/v1/media?uuid=a6fb22eebefaef17e62af874997c5944&type=thumbnail&frame=0';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture Reference
|
||||
|
||||
See `DESIGN/VideoPlayback_Architecture_V1.0.md` for Caddyfile configuration and `media-proxy` endpoint details.
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Date | Author | Changes |
|
||||
|---------|------|--------|---------|
|
||||
| V1.0 | 2026-06-07 | OpenCode | Initial version — search endpoint migration, serve_url support, thumbnail unchanged |
|
||||
Reference in New Issue
Block a user