diff --git a/.env.development b/.env.development index eb0822b..b457003 100644 --- a/.env.development +++ b/.env.development @@ -10,7 +10,7 @@ MOMENTRY_REDIS_PREFIX=momentry_dev: # Worker Configuration (enabled for development) MOMENTRY_WORKER_ENABLED=true -MOMENTRY_MAX_CONCURRENT=1 +MOMENTRY_MAX_CONCURRENT=6 MOMENTRY_POLL_INTERVAL=10 MOMENTRY_WORKER_BATCH_SIZE=5 diff --git a/.gitignore b/.gitignore index f38c930..20904b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,92 +1,79 @@ -# Environment - Local configs (NEVER commit these) -.env -.env.local -.env.*.local -# Build artifacts -target/ -venv/ - -# Generated files -thumbnails/ -*.asr.json -*.probe.json -test_asr.json - -# Local output (machine learning results) -output/ -*.pt - -# Cache -.ruff_cache/ - -# OS files -.DS_Store -.Spotlight-V100 -.Trashes - -# Logs -*.log - -# SSH keys (NEVER commit) -id_* -!id_*.pub - -# IDE and editor -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# Documentation backups -# docs_v1.0/ (Moved to active tracking) - -# Frontend dependencies -node_modules/ -portal/src-tauri/target/ - -# Python cache __pycache__/ -*.pyc -*.pyo - -# Test artifacts -test_output/ -test_output_simple/ -test_output_v2/ -*.mp4 -*.pt -server.pid -server.pid.* - -# Backup files -*.bak -*.backup -*.bak[0-9] - -# Model files -models/ -model_checkpoints/ -pretrained_models/ - -# Desktop app -momentry_desktop/ - -# Release artifacts (track docs, ignore binaries) -release/*.zip -release/momentry_v* -release/*.sql -release/dev_data_*.sql -release/public_schema_*.sql -release/migrate_*.sql - -# But track release documentation +!id_*.pub !release/*.md !release/*.txt - +.DS_Store +.env +.env.*.local +.env.local +.idea/ +.ruff_cache/ +.Spotlight-V100 +.Trashes +.vscode/ +*.asr.json +*.backup +*.bak +*.bak[0-9] +*.log +*.mp4 +*.probe.json +*.pt +*.pyc +*.pyo +*.swo +*.swp +*~ +# Backup files +# Build artifacts +# But track release documentation +# Cache # Data directories -data/ - +# Desktop app +# docs_v1.0/ (Moved to active tracking) +# Documentation backups +# Environment - Local configs (NEVER commit these) +# Frontend dependencies +# Generated files +# IDE and editor +# Local output (machine learning results) +# Logs +# Model files +# OS files +# Portal build artifacts +# Python cache +# Release and output directories +# Release artifacts (track docs, ignore binaries) +# SSH keys (NEVER commit) # System status +# Test artifacts +data/ +id_* +model_checkpoints/ +models/ +momentry_desktop/ +momentry_runtime/ +node_modules/ +output/ +portal/dist/ +portal/node_modules/ +portal/src-tauri/target/ +pretrained_models/ +release/ +release/*.sql +release/*.zip +release/dev_data_*.sql +release/migrate_*.sql +release/momentry_v* +release/public_schema_*.sql +server.pid +server.pid.* system_status_*.md +target/ +test_asr.json +test_output_simple/ +test_output_v2/ +test_output/ +thumbnails/ +venv/ diff --git a/AGENTS.md b/AGENTS.md index 921102a..30d7872 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,10 +29,16 @@ Rust-based digital asset management system with video analysis and RAG capabilit | Production | 3002 | ❌ 禁止修改 | `cargo run -- server` (僅 release 時) | | Portal (Tauri) | 1420 | 前端開發 | `npm run tauri dev` | +### ⛔ 嚴格測試隔離規則 (Strict Test Isolation) +- **所有測試 (Test) 必須在 Dev (3003) 進行**。 +- **絕對禁止 (ABSOLUTELY FORBIDDEN)** 在任何測試指令、Demo 流程或 API 檢查中使用 `localhost:3002`。 +- 即使是「測試 Unregister」或「檢查版本」,若未明確標示為 "Production Deployment",一律視為違規。 +- **預設行為**: 所有 curl, CLI, 或程式碼測試指令,預設 URL 必須為 `http://localhost:3003`。 + ### 違反後果 - 修改 WordPress/n8n 可能影響 marcom 團隊工作與生產環境 - 修改 WordPress/n8n 資料庫 table 可能破壞自動化流程與資料完整性 -- 修改 port 3002 可能中斷正在使用的服務 +- 修改 port 3002 可能中斷正在使用的服務 (這是非常嚴重的錯誤) - 所有 dev 測試必須在 playground (3003) 進行 --- diff --git a/Cargo.lock b/Cargo.lock index c5abea1..293490d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2369,6 +2369,7 @@ dependencies = [ "qdrant-client", "ratatui", "redis", + "regex", "reqwest", "sdl2", "serde", diff --git a/Cargo.toml b/Cargo.toml index 7a57be3..f7be791 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ futures-util = "0.3" # Serialization serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +regex = "1" chrono = { version = "0.4", features = ["serde"] } # UUID @@ -98,6 +99,10 @@ optional = true name = "momentry" path = "src/main.rs" +[[bin]] +name = "momentry-cli" +path = "src/bin/cli.rs" + [[bin]] name = "momentry_player" path = "src/player/main.rs" diff --git a/a1b10138a6bbb0cd.cut.json b/a1b10138a6bbb0cd.cut.json deleted file mode 120000 index 31c7e3c..0000000 --- a/a1b10138a6bbb0cd.cut.json +++ /dev/null @@ -1 +0,0 @@ -/Users/accusys/momentry_core_0.1/output/a1b10138a6bbb0cd.cut.json \ No newline at end of file diff --git a/a1b10138a6bbb0cd.face.json b/a1b10138a6bbb0cd.face.json deleted file mode 120000 index e481d5e..0000000 --- a/a1b10138a6bbb0cd.face.json +++ /dev/null @@ -1 +0,0 @@ -/Users/accusys/momentry_core_0.1/output/a1b10138a6bbb0cd.face.json \ No newline at end of file diff --git a/a1b10138a6bbb0cd.ocr.json b/a1b10138a6bbb0cd.ocr.json deleted file mode 120000 index edfdb5a..0000000 --- a/a1b10138a6bbb0cd.ocr.json +++ /dev/null @@ -1 +0,0 @@ -/Users/accusys/momentry_core_0.1/output/a1b10138a6bbb0cd.ocr.json \ No newline at end of file diff --git a/a1b10138a6bbb0cd.pose.json b/a1b10138a6bbb0cd.pose.json deleted file mode 120000 index fb33446..0000000 --- a/a1b10138a6bbb0cd.pose.json +++ /dev/null @@ -1 +0,0 @@ -/Users/accusys/momentry_core_0.1/output/a1b10138a6bbb0cd.pose.json \ No newline at end of file diff --git a/a1b10138a6bbb0cd.story.json b/a1b10138a6bbb0cd.story.json deleted file mode 120000 index 392fd81..0000000 --- a/a1b10138a6bbb0cd.story.json +++ /dev/null @@ -1 +0,0 @@ -/Users/accusys/momentry_core_0.1/output/a1b10138a6bbb0cd.story.json \ No newline at end of file diff --git a/a1b10138a6bbb0cd.yolo.json b/a1b10138a6bbb0cd.yolo.json deleted file mode 120000 index 2423006..0000000 --- a/a1b10138a6bbb0cd.yolo.json +++ /dev/null @@ -1 +0,0 @@ -/Users/accusys/momentry_core_0.1/output/a1b10138a6bbb0cd.yolo.json \ No newline at end of file diff --git a/benchmark_asr.py b/benchmark_asr.py deleted file mode 100644 index ceab604..0000000 --- a/benchmark_asr.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python3 -"""Benchmark ASR processor direct vs chunked transcription overhead.""" - -import sys -import os -import subprocess -import json -import tempfile -import time -import shutil -import statistics - -# Use a small video clip for consistent benchmarking -VIDEO_SOURCE = "../test_video/BigBuckBunny_320x180.mp4" # 10 minutes, 62MB -if not os.path.exists(VIDEO_SOURCE): - print(f"Video not found: {VIDEO_SOURCE}") - sys.exit(1) - -# Create temporary directory for all test runs -temp_dir = tempfile.mkdtemp(prefix="asr_bench_") -print(f"Benchmark directory: {temp_dir}") - - -def run_asr_mode(mode_name, max_direct_duration, chunk_duration=600): - """Run ASR processor with given parameters, return timing and resource stats.""" - clip_path = os.path.join(temp_dir, f"clip_{mode_name}.mp4") - output_path = os.path.join(temp_dir, f"output_{mode_name}.json") - - # Copy source video to clip path (no transcoding) - shutil.copy2(VIDEO_SOURCE, clip_path) - - env = os.environ.copy() - env["MOMENTRY_ASR_MAX_DIRECT_DURATION"] = str(max_direct_duration) - env["MOMENTRY_ASR_CHUNK_DURATION"] = str(chunk_duration) - env["MOMENTRY_ASR_MODEL_SIZE"] = "tiny" - env["MOMENTRY_ASR_COMPUTE_TYPE"] = "int8" - - cmd = [ - "/opt/homebrew/bin/python3.11", - "scripts/asr_processor.py", - clip_path, - output_path, - "--uuid", - f"bench_{mode_name}", - ] - - # Start monitoring (external) - import psutil - - start_time = time.time() - proc = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env - ) - - # Monitor CPU and memory of child process - cpu_percents = [] - memory_mbs = [] - - while True: - try: - p = psutil.Process(proc.pid) - cpu = p.cpu_percent(interval=0.1) - mem = p.memory_info().rss / (1024 * 1024) - cpu_percents.append(cpu) - memory_mbs.append(mem) - except (psutil.NoSuchProcess, psutil.AccessDenied): - break - if proc.poll() is not None: - # Process ended, wait a bit for final stats - time.sleep(0.1) - break - - stdout, stderr = proc.communicate(timeout=1) - elapsed = time.time() - start_time - returncode = proc.returncode - - # Read output - segments = [] - if os.path.exists(output_path): - with open(output_path, "r") as f: - data = json.load(f) - segments = data.get("segments", []) - - # Clean up temporary files - try: - os.unlink(clip_path) - os.unlink(output_path) - except: - pass - - return { - "mode": mode_name, - "elapsed": elapsed, - "returncode": returncode, - "segments": len(segments), - "cpu_avg": statistics.mean(cpu_percents) if cpu_percents else 0, - "cpu_max": max(cpu_percents) if cpu_percents else 0, - "memory_avg": statistics.mean(memory_mbs) if memory_mbs else 0, - "memory_max": max(memory_mbs) if memory_mbs else 0, - "stderr": stderr.decode() if stderr else "", - } - - -try: - # Run direct transcription (clip duration ~600s, max_direct=1800) - print("Running direct transcription benchmark...") - direct = run_asr_mode("direct", max_direct_duration=1800, chunk_duration=600) - - # Run chunked transcription (force chunked with max_direct=300, chunk=120) - print("Running chunked transcription benchmark...") - chunked = run_asr_mode("chunked", max_direct_duration=300, chunk_duration=120) - - # Calculate overhead - overhead = (chunked["elapsed"] - direct["elapsed"]) / direct["elapsed"] * 100 - - # Print results - print("\n" + "=" * 60) - print("ASR PROCESSOR BENCHMARK RESULTS") - print("=" * 60) - print(f"Test video: {VIDEO_SOURCE}") - print(f"Video duration: ~10 minutes (600 seconds)") - print() - print("Direct Transcription:") - print(f" Time: {direct['elapsed']:.1f}s") - print(f" Segments: {direct['segments']}") - print(f" CPU avg/max: {direct['cpu_avg']:.1f}% / {direct['cpu_max']:.1f}%") - print( - f" Memory avg/max: {direct['memory_avg']:.1f} MB / {direct['memory_max']:.1f} MB" - ) - print() - print("Chunked Transcription:") - print(f" Time: {chunked['elapsed']:.1f}s") - print(f" Segments: {chunked['segments']}") - print(f" CPU avg/max: {chunked['cpu_avg']:.1f}% / {chunked['cpu_max']:.1f}%") - print( - f" Memory avg/max: {chunked['memory_avg']:.1f} MB / {chunked['memory_max']:.1f} MB" - ) - print() - print("OVERHEAD ANALYSIS:") - print(f" Time overhead: {overhead:.2f}%") - if overhead <= 5: - print(f" ✅ PASS: Overhead ≤5% requirement") - else: - print(f" ❌ FAIL: Overhead exceeds 5% limit") - print() - - # Check for errors - if direct["returncode"] != 0: - print(f"WARNING: Direct transcription returned {direct['returncode']}") - if chunked["returncode"] != 0: - print(f"WARNING: Chunked transcription returned {chunked['returncode']}") - -except Exception as e: - print(f"Benchmark failed: {e}") - import traceback - - traceback.print_exc() -finally: - # Clean up directory - shutil.rmtree(temp_dir, ignore_errors=True) - print(f"Cleaned up {temp_dir}") diff --git a/benchmark_realistic.py b/benchmark_realistic.py deleted file mode 100644 index 6884a6d..0000000 --- a/benchmark_realistic.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python3 -"""Benchmark ASR with realistic chunk sizes.""" - -import sys -import os -import subprocess -import json -import tempfile -import time -import shutil -import statistics - -VIDEO_SOURCE = "../test_video/BigBuckBunny_320x180.mp4" # 10 minutes, 62MB -if not os.path.exists(VIDEO_SOURCE): - print(f"Video not found: {VIDEO_SOURCE}") - sys.exit(1) - - -def run_asr_mode(mode_name, max_direct_duration, chunk_duration, description): - """Run ASR processor with given parameters, return timing.""" - clip_path = os.path.join(temp_dir, f"clip_{mode_name}.mp4") - output_path = os.path.join(temp_dir, f"output_{mode_name}.json") - - # Copy source video to clip path - shutil.copy2(VIDEO_SOURCE, clip_path) - - env = os.environ.copy() - env["MOMENTRY_ASR_MAX_DIRECT_DURATION"] = str(max_direct_duration) - env["MOMENTRY_ASR_CHUNK_DURATION"] = str(chunk_duration) - env["MOMENTRY_ASR_MODEL_SIZE"] = "tiny" - env["MOMENTRY_ASR_COMPUTE_TYPE"] = "int8" - - cmd = [ - "/opt/homebrew/bin/python3.11", - "scripts/asr_processor.py", - clip_path, - output_path, - "--uuid", - f"bench_{mode_name}", - ] - - start_time = time.time() - proc = subprocess.run(cmd, capture_output=True, env=env, text=True) - elapsed = time.time() - start_time - returncode = proc.returncode - - # Read output - segments = [] - language = "" - if os.path.exists(output_path): - with open(output_path, "r") as f: - data = json.load(f) - segments = data.get("segments", []) - language = data.get("language", "") - - # Clean up - try: - os.unlink(clip_path) - os.unlink(output_path) - except: - pass - - return { - "mode": mode_name, - "description": description, - "elapsed": elapsed, - "returncode": returncode, - "segments": len(segments), - "language": language, - "stderr": proc.stderr[:200] if proc.stderr else "", - } - - -# Create temporary directory -temp_dir = tempfile.mkdtemp(prefix="asr_bench_real_") -print(f"Benchmark directory: {temp_dir}") - -try: - # Test 1: Direct transcription (video is 10 min, max_direct=30 min) - print("\n1. Direct transcription (max_direct=1800s, chunk=600s):") - direct = run_asr_mode( - "direct", - max_direct_duration=1800, - chunk_duration=600, - description="Direct (video < 30min threshold)", - ) - print(f" Time: {direct['elapsed']:.1f}s, Segments: {direct['segments']}") - - # Test 2: Chunked with 1 chunk (force chunked but chunk size = video duration) - print("\n2. Chunked with 1 chunk (max_direct=300s, chunk=600s):") - chunked1 = run_asr_mode( - "chunked1", - max_direct_duration=300, - chunk_duration=600, - description="Chunked with 1 chunk (10 min)", - ) - print(f" Time: {chunked1['elapsed']:.1f}s, Segments: {chunked1['segments']}") - - # Test 3: Chunked with 2 chunks (5 min each) - print("\n3. Chunked with 2 chunks (max_direct=300s, chunk=300s):") - chunked2 = run_asr_mode( - "chunked2", - max_direct_duration=300, - chunk_duration=300, - description="Chunked with 2 chunks (5 min each)", - ) - print(f" Time: {chunked2['elapsed']:.1f}s, Segments: {chunked2['segments']}") - - # Test 4: Chunked with 5 chunks (2 min each) - worst case - print("\n4. Chunked with 5 chunks (max_direct=300s, chunk=120s):") - chunked5 = run_asr_mode( - "chunked5", - max_direct_duration=300, - chunk_duration=120, - description="Chunked with 5 chunks (2 min each)", - ) - print(f" Time: {chunked5['elapsed']:.1f}s, Segments: {chunked5['segments']}") - - # Calculate overheads - print("\n" + "=" * 60) - print("OVERHEAD ANALYSIS (compared to direct transcription)") - print("=" * 60) - - for test in [chunked1, chunked2, chunked5]: - if direct["elapsed"] > 0: - overhead = (test["elapsed"] - direct["elapsed"]) / direct["elapsed"] * 100 - status = "✅ ≤5%" if overhead <= 5 else "❌ >5%" - print(f"\n{test['description']}:") - print(f" Time: {test['elapsed']:.1f}s (direct: {direct['elapsed']:.1f}s)") - print(f" Overhead: {overhead:.2f}% {status}") - print(f" Segments: {test['segments']} (direct: {direct['segments']})") - if test["segments"] != direct["segments"]: - print(f" ⚠️ Segment count mismatch!") - - # Summary - print("\n" + "=" * 60) - print("SUMMARY") - print("=" * 60) - print(f"Video: {os.path.basename(VIDEO_SOURCE)} (~10 minutes)") - print(f"\nKey finding: Overhead depends heavily on chunk count.") - print(f"With realistic chunk sizes (10 min), overhead should be minimal.") - -except Exception as e: - print(f"Benchmark failed: {e}") - import traceback - - traceback.print_exc() -finally: - # Clean up directory - shutil.rmtree(temp_dir, ignore_errors=True) - print(f"\nCleaned up {temp_dir}") diff --git a/build.rs b/build.rs index 83882e8..43fd11b 100644 --- a/build.rs +++ b/build.rs @@ -1,19 +1,4 @@ -use chrono::Local; -use std::env; - fn main() { - let now = Local::now(); - let build_time = now.format("%Y-%m-%d %H:%M:%S").to_string(); - - // Get version from Cargo.toml - let version = env!("CARGO_PKG_VERSION"); - let full_version = format!("{} (build: {})", version, build_time); - - // Set build-time environment variables - println!("cargo:rustc-env=BUILD_VERSION={}", full_version); - println!("cargo:rustc-env=BUILD_TIME={}", build_time); - println!("cargo:rustc-env=VERSION={}", version); - - // Also print for debugging - println!("cargo:warning=Building version: {}", full_version); + let version = std::env::var("CARGO_PKG_VERSION").unwrap_or_else(|_| "unknown".to_string()); + println!("cargo:rustc-env=BUILD_VERSION={}", version); } diff --git a/check_whisper.py b/check_whisper.py deleted file mode 100644 index 4d03213..0000000 --- a/check_whisper.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/opt/homebrew/bin/python3.11 -try: - import whisper - - print("whisper available") -except ImportError as e: - print(f"whisper not available: {e}") diff --git a/chunked_transcribe.py b/chunked_transcribe.py deleted file mode 100644 index 2044b40..0000000 --- a/chunked_transcribe.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python3 -""" -Chunked transcription to handle large audio files. -""" - -import sys -import time -import tempfile -import json -import subprocess -from pathlib import Path -import numpy as np - - -def split_audio(input_path, chunk_duration=1800, output_dir=None): - """Split audio into chunks using ffmpeg.""" - if output_dir is None: - output_dir = Path(tempfile.mkdtemp(prefix="audio_chunks_")) - else: - output_dir = Path(output_dir) - output_dir.mkdir(exist_ok=True, parents=True) - - # Get total duration - cmd = [ - "ffprobe", - "-v", - "error", - "-show_entries", - "format=duration", - "-of", - "csv=p=0", - str(input_path), - ] - result = subprocess.run(cmd, capture_output=True, text=True) - total_duration = float(result.stdout.strip()) - - print( - f"Total audio duration: {total_duration:.1f}s ({total_duration / 3600:.1f} hrs)" - ) - print(f"Splitting into {chunk_duration}s chunks...") - - chunks = [] - start = 0 - chunk_idx = 0 - while start < total_duration: - chunk_path = output_dir / f"chunk_{chunk_idx:04d}.wav" - cmd = [ - "ffmpeg", - "-i", - str(input_path), - "-ss", - str(start), - "-t", - str(chunk_duration), - "-acodec", - "pcm_s16le", - "-ar", - "16000", - "-ac", - "1", - "-y", - str(chunk_path), - ] - subprocess.run(cmd, capture_output=True) - if chunk_path.exists() and chunk_path.stat().st_size > 0: - chunks.append( - { - "path": chunk_path, - "start_time": start, - "end_time": min(start + chunk_duration, total_duration), - } - ) - else: - print(f"Warning: Chunk {chunk_idx} may be empty") - start += chunk_duration - chunk_idx += 1 - - print(f"Created {len(chunks)} chunks in {output_dir}") - return chunks, output_dir - - -def transcribe_chunk(chunk_info, model, chunk_idx, total_chunks): - """Transcribe a single chunk.""" - print( - f"[{chunk_idx + 1}/{total_chunks}] Transcribing chunk {chunk_info['start_time']:.1f}-{chunk_info['end_time']:.1f}" - ) - start_time = time.time() - - segments, info = model.transcribe(str(chunk_info["path"]), beam_size=5) - results = [] - for segment in segments: - # Adjust timestamps by chunk start time - results.append( - { - "start": segment.start + chunk_info["start_time"], - "end": segment.end + chunk_info["start_time"], - "text": segment.text.strip(), - } - ) - - elapsed = time.time() - start_time - print(f" → {len(results)} segments in {elapsed:.1f}s") - return results, info - - -def main(): - import argparse - - parser = argparse.ArgumentParser(description="Chunked transcription") - parser.add_argument("audio_path", help="Audio file path") - parser.add_argument( - "--chunk-duration", - type=int, - default=1800, - help="Chunk duration in seconds (default: 1800 = 30 min)", - ) - parser.add_argument("--model-size", default="tiny", help="Whisper model size") - parser.add_argument("--compute-type", default="int8", help="Compute type") - parser.add_argument( - "--output", "-o", default="chunked_transcription.json", help="Output JSON path" - ) - args = parser.parse_args() - - audio_path = Path(args.audio_path) - if not audio_path.exists(): - print(f"Error: File not found: {audio_path}") - sys.exit(1) - - print(f"Chunked Transcription for {audio_path}") - print(f"Model: {args.model_size}, Compute: {args.compute_type}") - print( - f"Chunk duration: {args.chunk_duration}s ({args.chunk_duration / 60:.1f} min)" - ) - - # Split audio - chunks, temp_dir = split_audio(audio_path, chunk_duration=args.chunk_duration) - if not chunks: - print("No chunks created") - sys.exit(1) - - # Load model once - print("Loading Whisper model...") - from faster_whisper import WhisperModel - - model_start = time.time() - model = WhisperModel(args.model_size, device="cpu", compute_type=args.compute_type) - print(f"Model loaded in {time.time() - model_start:.1f}s") - - # Process each chunk - all_segments = [] - language = None - language_prob = None - - for i, chunk in enumerate(chunks): - try: - segments, info = transcribe_chunk(chunk, model, i, len(chunks)) - all_segments.extend(segments) - if language is None: - language = info.language - language_prob = info.language_probability - except Exception as e: - print(f"Error transcribing chunk {i}: {e}") - import traceback - - traceback.print_exc() - # Continue with next chunk - - # Sort segments by start time - all_segments.sort(key=lambda x: x["start"]) - - # Save results - output = { - "language": language or "unknown", - "language_probability": language_prob or 0.0, - "segments": all_segments, - "chunk_count": len(chunks), - "chunk_duration": args.chunk_duration, - "total_segments": len(all_segments), - } - - output_path = Path(args.output) - output_path.parent.mkdir(exist_ok=True, parents=True) - with open(output_path, "w") as f: - json.dump(output, f, indent=2) - - print(f"\nTranscription completed:") - print(f" Total segments: {len(all_segments)}") - print( - f" Language: {output['language']} (prob {output['language_probability']:.2f})" - ) - print(f" Results saved to: {output_path}") - - # Cleanup temp directory - import shutil - - shutil.rmtree(temp_dir, ignore_errors=True) - - -if __name__ == "__main__": - main() diff --git a/com.momentry.api.updated.plist b/com.momentry.api.updated.plist deleted file mode 100644 index 341fbd2..0000000 --- a/com.momentry.api.updated.plist +++ /dev/null @@ -1,64 +0,0 @@ - - - - - Label - com.momentry.api - - UserName - accusys - - GroupName - staff - - WorkingDirectory - /Users/accusys/momentry_core_0.1 - - ProgramArguments - - /Users/accusys/momentry_core_0.1/target/release/momentry - server - --port - 3002 - - - EnvironmentVariables - - PATH - /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin - - DATABASE_URL - postgres://accusys@localhost:5432/momentry - - DB_MAX_CONNECTIONS - 50 - - DB_ACQUIRE_TIMEOUT - 30 - - REDIS_URL - redis://:accusys@localhost:6379 - - REDIS_PASSWORD - accusys - - OLLAMA_HOST - http://localhost:11434 - - QDRANT_URL - http://127.0.0.1:6333 - - - RunAtLoad - - - KeepAlive - - - StandardOutPath - /Users/accusys/momentry/log/momentry_api.log - - StandardErrorPath - /Users/accusys/momentry/log/momentry_api.error.log - - \ No newline at end of file diff --git a/create_job.rs b/create_job.rs deleted file mode 100644 index fa3f0ec..0000000 --- a/create_job.rs +++ /dev/null @@ -1,98 +0,0 @@ -use anyhow::Result; -use sqlx::postgres::PgPoolOptions; - -#[tokio::main] -async fn main() -> Result<()> { - // Database connection - let pool = PgPoolOptions::new() - .max_connections(5) - .connect("postgres://accusys@localhost:5432/momentry") - .await?; - - let video_uuid = "9760d0820f0cf9a7"; - let video_id = 28; - let video_path = "/Users/accusys/momentry/var/sftpgo/data/demo/ExaSAN PCIe series - Director Ou Yu-Zhi Shares His Experience.mp4"; - - println!("Creating monitor job for video:"); - println!(" UUID: {}", video_uuid); - println!(" ID: {}", video_id); - println!(" Path: {}", video_path); - - // 1. Create monitor job - let job_row = sqlx::query( - r#" - INSERT INTO monitor_jobs (uuid, video_path, status) - VALUES ($1, $2, 'pending') - RETURNING id, uuid, video_path, status - "# - ) - .bind(video_uuid) - .bind(video_path) - .fetch_one(&pool) - .await?; - - let job_id: i32 = job_row.get(0); - let job_uuid: String = job_row.get(1); - let job_status: String = job_row.get(3); - - println!("\nCreated monitor job:"); - println!(" Job ID: {}", job_id); - println!(" Job UUID: {}", job_uuid); - println!(" Status: {}", job_status); - - // 2. Update video with job_id - sqlx::query( - r#" - UPDATE videos - SET job_id = $1, updated_at = CURRENT_TIMESTAMP - WHERE id = $2 - "# - ) - .bind(job_id) - .bind(video_id) - .execute(&pool) - .await?; - - println!("Updated video {} with job_id {}", video_id, job_id); - - // 3. Update monitor_jobs with video_id - sqlx::query( - r#" - UPDATE monitor_jobs - SET video_id = $1, updated_at = CURRENT_TIMESTAMP - WHERE id = $2 - "# - ) - .bind(video_id) - .bind(job_id) - .execute(&pool) - .await?; - - println!("Updated monitor_jobs {} with video_id {}", job_id, video_id); - - // 4. Create processor results for this job - let processors = vec!["asr", "cut", "yolo", "ocr", "face", "pose", "asrx"]; - - for processor in processors { - sqlx::query( - r#" - INSERT INTO processor_results (job_id, video_id, processor, status) - VALUES ($1, $2, $3, 'pending') - ON CONFLICT (job_id, processor) DO NOTHING - "# - ) - .bind(job_id) - .bind(video_id) - .bind(processor) - .execute(&pool) - .await?; - - println!("Created processor result for {}: {}", processor, job_id); - } - - println!("\n✅ Job creation completed successfully!"); - println!("Job ID: {}", job_id); - println!("The worker should now pick up this job and start processing."); - - Ok(()) -} diff --git a/create_job.sql b/create_job.sql deleted file mode 100644 index f345734..0000000 --- a/create_job.sql +++ /dev/null @@ -1,7 +0,0 @@ --- 1. Create monitor job -INSERT INTO monitor_jobs (uuid, video_path, status) -VALUES ('9760d0820f0cf9a7', '/Users/accusys/momentry/var/sftpgo/data/demo/ExaSAN PCIe series - Director Ou Yu-Zhi Shares His Experience.mp4', 'pending') -RETURNING id; - --- Note: The job_id will be returned. Let's assume it's 18 for now. --- We'll run these commands step by step. diff --git a/debug_asr.py b/debug_asr.py deleted file mode 100644 index 1cfd581..0000000 --- a/debug_asr.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python3 -""" -Debug ASR processing stages for large video. -""" - -import os -import sys -import time -import subprocess -import tempfile -import json -from pathlib import Path - - -def run_ffmpeg_extract(video_path, audio_path): - """Extract audio using ffmpeg.""" - cmd = [ - "ffmpeg", - "-i", - str(video_path), - "-vn", - "-acodec", - "pcm_s16le", - "-ar", - "16000", - "-ac", - "1", - "-y", - str(audio_path), - ] - print(f"Running ffmpeg: {' '.join(cmd)}") - start = time.time() - proc = subprocess.run(cmd, capture_output=True, text=True) - elapsed = time.time() - start - print(f"ffmpeg completed in {elapsed:.1f}s, return code: {proc.returncode}") - if proc.returncode != 0: - print(f"stderr: {proc.stderr[:500]}") - return proc.returncode == 0, elapsed - - -def test_asr_stages(video_path): - """Test ASR stages step by step.""" - video_path = Path(video_path) - print(f"Testing video: {video_path}") - print(f"Size: {video_path.stat().st_size / 1024 / 1024:.1f} MB") - - # Stage 1: Check audio streams - print("\n=== Stage 1: Check audio streams ===") - cmd = [ - "ffprobe", - "-v", - "error", - "-select_streams", - "a", - "-show_entries", - "stream=codec_name,channels,sample_rate,duration", - "-of", - "csv=p=0", - str(video_path), - ] - proc = subprocess.run(cmd, capture_output=True, text=True) - print(f"Audio streams: {proc.stdout.strip()}") - - # Stage 2: Extract audio - print("\n=== Stage 2: Extract audio ===") - with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f: - audio_path = f.name - try: - success, extract_time = run_ffmpeg_extract(video_path, audio_path) - if success: - print(f"Audio extracted to {audio_path}") - print(f"Audio size: {Path(audio_path).stat().st_size / 1024 / 1024:.1f} MB") - else: - print("Audio extraction failed") - os.unlink(audio_path) - return - except Exception as e: - print(f"Error extracting audio: {e}") - return - - # Stage 3: Load faster_whisper model (just import) - print("\n=== Stage 3: Test faster_whisper import ===") - try: - start = time.time() - from faster_whisper import WhisperModel - - elapsed = time.time() - start - print(f"Import faster_whisper: {elapsed:.1f}s") - except Exception as e: - print(f"Import failed: {e}") - os.unlink(audio_path) - return - - # Stage 4: Transcribe a small segment (first 30 seconds) - print("\n=== Stage 4: Transcribe first 30 seconds ===") - try: - # Trim audio to first 30 seconds - trim_path = audio_path + ".trim.wav" - cmd = [ - "ffmpeg", - "-i", - audio_path, - "-t", - "30", - "-acodec", - "pcm_s16le", - "-ar", - "16000", - "-ac", - "1", - "-y", - trim_path, - ] - subprocess.run(cmd, capture_output=True) - - # Load model with small model - start = time.time() - model = WhisperModel("tiny", device="cpu", compute_type="int8") - load_time = time.time() - start - print(f"Model loaded in {load_time:.1f}s") - - # Transcribe - start = time.time() - segments, info = model.transcribe(trim_path, beam_size=5) - segments = list(segments) # Force processing - transcribe_time = time.time() - start - print(f"Transcription of 30s audio: {transcribe_time:.1f}s") - print( - f"Detected language: {info.language} with probability {info.language_probability}" - ) - print(f"Segments found: {len(segments)}") - - # Cleanup - os.unlink(trim_path) - except Exception as e: - print(f"Transcription test failed: {e}") - import traceback - - traceback.print_exc() - finally: - os.unlink(audio_path) - - print("\n=== Debug complete ===") - - -if __name__ == "__main__": - if len(sys.argv) != 2: - print(f"Usage: {sys.argv[0]} ") - sys.exit(1) - test_asr_stages(sys.argv[1]) diff --git a/debug_chunked_hang.py b/debug_chunked_hang.py deleted file mode 100644 index 7b617ad..0000000 --- a/debug_chunked_hang.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 -import sys -import time - -print("Start") -print("Importing faster_whisper...") -try: - from faster_whisper import WhisperModel - - print("Import successful") -except Exception as e: - print(f"Import failed: {e}") - sys.exit(1) - -print("Loading model...") -try: - model = WhisperModel("tiny", device="cpu", compute_type="int8") - print("Model loaded") -except Exception as e: - print(f"Model load failed: {e}") - sys.exit(1) - -import subprocess - -print("Getting duration...") -cmd = [ - "ffprobe", - "-v", - "error", - "-show_entries", - "format=duration", - "-of", - "csv=p=0", - "/tmp/test_audio.wav", -] -result = subprocess.run(cmd, capture_output=True, text=True) -print(f"ffprobe output: {result.stdout}") -duration = float(result.stdout.strip()) -print(f"Duration: {duration}") - -# Extract first chunk -print("Extracting first chunk...") -chunk_path = "/tmp/debug_chunk.wav" -cmd = [ - "ffmpeg", - "-i", - "/tmp/test_audio.wav", - "-t", - "60", - "-acodec", - "pcm_s16le", - "-ar", - "16000", - "-ac", - "1", - "-y", - chunk_path, -] -result = subprocess.run(cmd, capture_output=True, text=True) -print(f"ffmpeg return code: {result.returncode}") -if result.returncode != 0: - print(f"stderr: {result.stderr[:200]}") - -import os - -print(f"Chunk exists: {os.path.exists(chunk_path)}") -if os.path.exists(chunk_path): - print(f"Chunk size: {os.path.getsize(chunk_path)}") - - print("Transcribing chunk...") - start = time.time() - try: - segments, info = model.transcribe(chunk_path, beam_size=5) - segments = list(segments) - elapsed = time.time() - start - print(f"Transcription succeeded in {elapsed}s, segments: {len(segments)}") - except Exception as e: - print(f"Transcription failed: {e}") - import traceback - - traceback.print_exc() -else: - print("Chunk not created") - -print("Script finished") diff --git a/docs_v1.0/API/PEOPLE_API_MARCOM_MAPPING.md b/docs_v1.0/API/PEOPLE_API_MARCOM_MAPPING.md deleted file mode 100644 index 2625833..0000000 --- a/docs_v1.0/API/PEOPLE_API_MARCOM_MAPPING.md +++ /dev/null @@ -1,442 +0,0 @@ -# People API 设计方案 (marcom 需求等效映射) - -**日期**: 2026-04-28 -**状态**: 设计阶段 -**目的**: 根据 marcom 团队需求,在符合现有架构的前提下提供等效 API - ---- - -## 设计原则 - -1. **遵循 RESTful 规范**: 使用标准 HTTP 方法 (GET, POST, PATCH, DELETE) -2. **统一路径前缀**: `/api/v1/people` -3. **响应格式统一**: `{ success: bool, message: string, data: any }` -4. **向后兼容**: 现有 API 保持不变,新 API 扩展功能 -5. **符合 Identity 系统**: 与 `identities` 表和 `identity_bindings` 表集成 - ---- - -## API 对照表 - -### 1. GET /people/candidates (候选人物) - -**marcom 需求**: 获取待确认的人物候选列表 - -**等效 API**: -``` -GET /api/v1/people/candidates?file_uuid={uuid}&limit={n} -``` - -**功能**: -- 返回待确认的人物身份候选 -- 包含 face cluster、speaker cluster 的匹配建议 -- 状态: `pending`, `suggested`, `unmatched` - -**响应示例**: -```json -{ - "success": true, - "message": "Found 15 candidates", - "data": { - "candidates": [ - { - "candidate_id": "face_cluster_1", - "type": "face", - "suggested_identity": { - "id": 123, - "name": "张曼玉", - "confidence": 0.92 - }, - "appearance_count": 45, - "status": "pending" - } - ], - "total": 15 - } -} -``` - -**实现**: 扩展现有 `/api/v1/people/suggest` - ---- - -### 2. GET /people (人物列表) - -**marcom 需求**: 获取所有人物列表 - -**等效 API**: -``` -GET /api/v1/people?file_uuid={uuid}&limit={n}&offset={n}&status={status} -``` - -**功能**: -- 返回人物身份列表 -- 支持按 file_uuid 筛选 -- 支持分页 -- 支持按状态筛选 (confirmed, pending, all) - -**响应示例**: -```json -{ - "success": true, - "message": "Found 8 persons", - "data": { - "persons": [ - { - "identity_id": "Person_17", - "name": "张曼玉", - "appearance_count": 45, - "total_duration": 350.2, - "is_confirmed": true - } - ], - "total": 8 - } -} -``` - -**实现**: 现有 `/api/v1/people/list` 已支持 - ---- - -### 3. GET /people/{identity_id} (人物详情) - -**marcom 需求**: 获取人物详情 - -**等效 API**: -``` -GET /api/v1/people/{identity_id}?file_uuid={uuid} -``` - -**功能**: -- 返回人物详细信息 -- 包含出场时间线 -- 包含关联的 face/speaker -- 包含缩略图 - -**响应示例**: -```json -{ - "success": true, - "data": { - "identity_id": "Person_17", - "name": "张曼玉", - "face_identity_id": 123, - "speaker_id": "SPEAKER_00", - "appearance_count": 45, - "total_duration": 350.2, - "first_appearance_time": 10.5, - "last_appearance_time": 360.2, - "timeline": [...], - "thumbnails": [...] - } -} -``` - -**实现**: 现有 `/api/v1/people/:person_id` 已支持 - ---- - -### 4. POST /people (创建人物) - -**marcom 需求**: 手动创建新人物 - -**等效 API**: -``` -POST /api/v1/people -Body: { "name": "张曼玉", "file_uuid": "xxx", "metadata": {...} } -``` - -**功能**: -- 创建新人物身份 -- 关联到指定视频 -- 支持添加 metadata (角色名、演员名等) - -**响应示例**: -```json -{ - "success": true, - "message": "Person created", - "data": { - "identity_id": "Person_99", - "name": "张曼玉", - "file_uuid": "xxx" - } -} -``` - -**实现**: 需新增,参考 `CreatePersonIdentityRequest` - ---- - -### 5. PATCH /people/{identity_id} (更新人物) - -**marcom 需求**: 更新人物信息 - -**等效 API**: -``` -PATCH /api/v1/people/{identity_id} -Body: { "name": "新名字", "is_confirmed": true, "metadata": {...} } -``` - -**功能**: -- 更新人物名称 -- 确认人物身份 -- 更新 metadata - -**实现**: 现有 `/api/v1/people/:person_id` (PATCH) 已支持 - ---- - -### 6. POST /people/merge (合并人物) - -**marcom 需求**: 合并多个人物为一个 - -**等效 API**: -``` -POST /api/v1/people/merge -Body: { - "target_identity_id": "Person_17", - "source_identity_ids": ["Person_18", "Person_19"] -} -``` - -**功能**: -- 合并多个人物身份 -- 转移所有出场记录 -- 更新统计数据 - -**实现**: 现有 `/api/v1/people/merge` 已支持 - ---- - -### 7. POST /people/skip (跳过人物) - -**marcom 需求**: 跳过某个候选人物(不处理) - -**等效 API**: -``` -POST /api/v1/people/skip -Body: { "candidate_id": "face_cluster_2", "reason": "非人物" } -``` - -**功能**: -- 标记候选为"已跳过" -- 记录跳过原因 -- 不创建人物身份 - -**响应示例**: -```json -{ - "success": true, - "message": "Candidate skipped", - "data": { - "candidate_id": "face_cluster_2", - "status": "skipped", - "reason": "非人物" - } -} -``` - -**实现**: 需新增,扩展候选管理功能 - ---- - -### 8. POST /people/{identity_id}/remove-face (移除人脸) - -**marcom 需求**: 从人物身份中移除特定人脸绑定 - -**等效 API**: -``` -POST /api/v1/people/{identity_id}/unbind -Body: { "binding_type": "face", "binding_value": "face_123" } -``` - -**功能**: -- 解绑人脸与人物身份的关联 -- 人脸回到候选状态 -- 更新人物出场统计 - -**响应示例**: -```json -{ - "success": true, - "message": "Face unbound", - "data": { - "identity_id": "Person_17", - "unbound_face": "face_123", - "updated_appearance_count": 42 - } -} -``` - -**实现**: 需新增,参考现有 `UnbindIdentityRequest` - ---- - -### 9. POST /people/split-face (分离人脸) - -**marcom 需求**: 将人脸从现有人物分离为新人物 - -**等效 API**: -``` -POST /api/v1/people/split -Body: { - "source_identity_id": "Person_17", - "face_ids": ["face_123", "face_124"], - "new_identity_name": "新人物" -} -``` - -**功能**: -- 从现有人物分离指定人脸 -- 创建新人物身份 -- 转移出场记录 - -**实现**: 现有 `/api/v1/people/:person_id/split` 部分支持 - ---- - -### 10. GET /people/{identity_id}/resolve (解决冲突) - -**marcom 需求**: 获取人物的冲突/歧义信息 - -**等效 API**: -``` -GET /api/v1/people/{identity_id}/conflicts -``` - -**功能**: -- 返回人物身份的潜在冲突 -- 显示相似人脸/声音的匹配 -- 提供解决方案建议 - -**响应示例**: -```json -{ - "success": true, - "data": { - "identity_id": "Person_17", - "conflicts": [ - { - "type": "similar_face", - "conflicting_identity": "Person_18", - "similarity": 0.85, - "suggestion": "merge" - } - ], - "resolution_options": ["merge", "keep_separate", "skip"] - } -} -``` - -**实现**: 需新增 - ---- - -### 11. POST /search (搜索) - -**marcom 需求**: 搜索人物 - -**等效 API**: -``` -POST /api/v1/people/search -Body: { - "query": "张", - "filters": { "type": "people", "file_uuid": "xxx" }, - "limit": 20 -} -``` - -**功能**: -- 搜索人物身份 -- 支持按名称、类型、视频筛选 -- 返回匹配结果 - -**实现**: 现有 `/api/v1/identities/search` 已支持,建议扩展 - ---- - -### 12. GET /people/status (人物状态) - -**marcom 需求**: 获取人物处理状态统计 - -**等效 API**: -``` -GET /api/v1/people/status?file_uuid={uuid} -``` - -**功能**: -- 返回人物处理统计 -- 待确认数量、已确认数量、跳过数量 -- 合并历史 - -**响应示例**: -```json -{ - "success": true, - "data": { - "file_uuid": "xxx", - "total_candidates": 15, - "confirmed": 8, - "pending": 5, - "skipped": 2, - "merge_count": 3, - "split_count": 1 - } -} -``` - -**实现**: 需新增 - ---- - -## 实现优先级 - -| 优先级 | API | 状态 | 预估工时 | -|--------|-----|------|----------| -| **P0** | GET /people | ✅ 已有 | 0h | -| **P0** | GET /people/{identity_id} | ✅ 已有 | 0h | -| **P0** | PATCH /people/{identity_id} | ✅ 已有 | 0h | -| **P0** | POST /people/merge | ✅ 已有 | 0h | -| **P1** | GET /people/candidates | ⚠️ 扩展 | 2h | -| **P1** | POST /people | ❌ 新增 | 2h | -| **P1** | POST /people/search | ⚠️ 扩展 | 1h | -| **P2** | POST /people/skip | ❌ 新增 | 2h | -| **P2** | POST /people/{identity_id}/unbind | ❌ 新增 | 2h | -| **P2** | POST /people/split | ⚠️ 扩展 | 1h | -| **P2** | GET /people/{identity_id}/conflicts | ❌ 新增 | 3h | -| **P2** | GET /people/status | ❌ 新增 | 2h | - -**总预估**: ~13h (P1+P2) - ---- - -## 数据库表需求 - -现有表结构支持大部分需求,可能需要扩展: - -```sql --- 建议新增: candidates 表 (候选管理) -CREATE TABLE person_candidates ( - id BIGSERIAL PRIMARY KEY, - file_uuid VARCHAR(36) NOT NULL, - candidate_type VARCHAR(20), -- 'face', 'speaker' - candidate_id VARCHAR(50), -- 'face_cluster_1', 'speaker_2' - suggested_identity_id BIGINT, - confidence FLOAT, - status VARCHAR(20), -- 'pending', 'confirmed', 'skipped' - skip_reason TEXT, - created_at TIMESTAMP, - updated_at TIMESTAMP -); -``` - ---- - -## 参考文档 - -- `docs_v1.0/ARCHITECTURE/MOMENTRY_CORE_ARCHITECTURE_V2.md` - Identity 系统设计 -- `docs_v1.0/ARCHITECTURE/PERSON_IDENTITY_INTEGRATION.md` - Person Identity 整合 -- `src/api/person_identity.rs` - 现有 API 实现 -- `src/api/identity_binding.rs` - 身份绑定 API diff --git a/docs_v1.0/API_DOCUMENTATION.md b/docs_v1.0/API_DOCUMENTATION.md deleted file mode 100644 index 7306170..0000000 --- a/docs_v1.0/API_DOCUMENTATION.md +++ /dev/null @@ -1,699 +0,0 @@ -# Momentry Core API Documentation v1.0.0 - -## Overview -Momentry Core is a digital asset management system with video analysis, RAG, and face recognition capabilities. This document covers all API endpoints available in v1.0.0. - -**Base URL**: `http://:` -- Production: Port 3002 -- Development (Playground): Port 3003 - -**Authentication**: All protected routes require API key validation via `X-API-Key` header. - ---- - -## API Classification - -The API is organized into 7 categories: - -| Category | Prefix | Description | -|----------|--------|-------------| -| **Health & Auth** | `/health`, `/api/v1/auth` | System health, authentication | -| **Asset Management** | `/api/v1/register`, `/api/v1/files`, `/api/v1/assets` | File registration, probing, processing | -| **Search** | `/api/v1/search`, `/api/v1/n8n` | Text, hybrid, visual, and n8n search | -| **Video Details** | `/api/v1/videos`, `/api/v1/progress` | Video listing, details, chunks | -| **Identity & Binding** | `/api/v1/identities`, `/api/v1/signals` | Face/speaker identity management | -| **Jobs & Rules** | `/api/v1/jobs`, `/api/v1/rules` | Processing job monitoring | -| **Stats & Config** | `/api/v1/stats`, `/api/v1/config` | System statistics, configuration | - ---- - -## 1. Health & Authentication - -### `GET /health` -Basic health check. - -**Response**: -```json -{ - "status": "ok", - "version": "v1.0.0", - "uptime_ms": 12345 -} -``` - -### `GET /health/detailed` -Detailed health check with service status (PostgreSQL, Redis, Qdrant, MongoDB). - -**Response**: -```json -{ - "status": "ok", - "version": "v1.0.0", - "uptime_ms": 12345, - "services": { - "postgres": { "status": "ok", "latency_ms": 5 }, - "redis": { "status": "ok", "latency_ms": 2 }, - "qdrant": { "status": "ok", "latency_ms": 10 }, - "mongodb": { "status": "ok", "latency_ms": 8 } - } -} -``` - -### `POST /api/v1/auth/login` -Authenticate and obtain API key. - -**Request**: -```json -{ - "username": "demo", - "password": "demo" -} -``` - -**Response**: -```json -{ - "success": true, - "message": "Login successful", - "api_key": "muser_test_001", - "user": { "username": "demo" } -} -``` - -### `POST /api/v1/auth/logout` -Logout session. - -**Response**: -```json -{ "success": true } -``` - ---- - -## 2. Asset Management - -### `POST /api/v1/register` -Register a video file (legacy path-based). - -**Request**: -```json -{ "path": "./demo/video.mp4" } -``` - -**Response**: -```json -{ - "file_uuid": "384b0ff44aaaa1f1", - "file_id": 1, - "job_id": 1, - "file_name": "video.mp4", - "duration": 120.5, - "width": 1920, - "height": 1080, - "already_exists": false -} -``` - -### `POST /api/v1/files/register` -Register a file with full metadata (recommended). Supports move detection. - -**Request**: -```json -{ - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4", - "user_id": null -} -``` - -**Response**: -```json -{ - "success": true, - "file_uuid": "384b0ff44aaaa1f1", - "file_name": "video.mp4", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4", - "file_type": "video", - "duration": 120.5, - "width": 1920, - "height": 1080, - "fps": 30.0, - "total_frames": 3615, - "registration_time": null, - "already_exists": false, - "message": "File registered successfully" -} -``` - -### `GET /api/v1/files/scan` -Scan filesystem for unregistered files. - -### `POST /api/v1/unregister` -Unregister a video file. - -**Request**: -```json -{ "uuid": "384b0ff44aaaa1f1" } -``` - -### `POST /api/v1/probe` -Probe a video file for metadata. - -**Request**: -```json -{ "path": "./demo/video.mp4" } -``` - -**Response**: -```json -{ - "uuid": "384b0ff44aaaa1f1", - "file_name": "video.mp4", - "duration": 120.5, - "width": 1920, - "height": 1080, - "fps": 30.0, - "cached": true, - "format": { ... }, - "streams": [ ... ] -} -``` - -### `GET /api/v1/assets/:uuid/probe` -Probe a video by UUID. - -### `POST /api/v1/assets/:uuid/process` -Trigger processing pipeline for an asset. - -**Request**: -```json -{ - "processors": ["asr", "cut", "yolo", "ocr", "face", "pose", "asrx", "visual_chunk"] -} -``` - -**Response**: -```json -{ - "job_id": 1, - "asset_uuid": "384b0ff44aaaa1f1", - "status": "PENDING", - "message": "Processing triggered for video.mp4" -} -``` - -### `GET /api/v1/assets/:uuid/status` -Get asset processing status with frame progress. - -**Response**: -```json -{ - "uuid": "384b0ff44aaaa1f1", - "file_name": "video.mp4", - "registration_time": "2026-04-30T10:00:00Z", - "processing_status": "processing", - "current_job_id": "abc-123", - "frame_progress": { - "total_frames": 3615, - "processed_frames": 1200, - "progress_percent": 33.2 - } -} -``` - ---- - -## 3. Search - -### `POST /api/v1/search` -Vector/smart search across chunks. - -**Request**: -```json -{ - "query": "person talking about AI", - "mode": "smart", - "uuid": "384b0ff44aaaa1f1", - "limit": 10 -} -``` - -**Response**: -```json -{ - "results": [ - { - "uuid": "384b0ff44aaaa1f1", - "chunk_id": "chunk_1", - "chunk_type": "sentence", - "start_time": 10.5, - "end_time": 15.2, - "text": "AI is transforming...", - "score": 0.85 - } - ], - "query": "person talking about AI" -} -``` - -### `POST /api/v1/search/hybrid` -Hybrid search (vector + BM25). - -**Request**: -```json -{ - "query": "search term", - "limit": 10, - "uuid": "384b0ff44aaaa1f1", - "vector_weight": 0.7, - "bm25_weight": 0.3 -} -``` - -### `POST /api/v1/search/bm25` -BM25 full-text search. - -### `POST /api/v1/search/visual` -Search visual chunks by criteria. - -**Request**: -```json -{ - "uuid": "384b0ff44aaaa1f1", - "criteria": { - "object_class": "person", - "min_count": 1 - } -} -``` - -### `POST /api/v1/search/visual/class` -Search by object class. - -**Request**: -```json -{ - "uuid": "384b0ff44aaaa1f1", - "object_class": "person", - "min_count": 1, - "max_count": null -} -``` - -### `POST /api/v1/search/visual/density` -Search by object density. - -**Request**: -```json -{ - "uuid": "384b0ff44aaaa1f1", - "min_density": 0.5, - "max_density": null -} -``` - -### `POST /api/v1/search/visual/combination` -Search by object combination. - -**Request**: -```json -{ - "uuid": "384b0ff44aaaa1f1", - "combination": [["person", 2], ["car", 1]] -} -``` - -### `POST /api/v1/search/visual/stats` -Get visual chunk statistics. - -**Request**: -```json -{ "uuid": "384b0ff44aaaa1f1" } -``` - -### `POST /api/v1/n8n/search` -Search via n8n integration. - -### `POST /api/v1/n8n/search/bm25` -BM25 search via n8n. - -### `POST /api/v1/n8n/search/hybrid` -Hybrid search via n8n. - -### `POST /api/v1/n8n/search/smart` -Smart search via n8n. - ---- - -## 4. Video Details - -### `GET /api/v1/videos` -List all registered videos with pagination. - -**Query Parameters**: -- `page`: Page number (default: 1) -- `page_size`: Items per page (default: 20) -- `status`: Filter by status -- `q`: Search query -- `uuid`: Filter by UUID - -**Response**: -```json -{ - "files": [ - { - "file_uuid": "384b0ff44aaaa1f1", - "file_path": "/path/to/video.mp4", - "file_name": "video.mp4", - "file_type": "video", - "duration": 120.5, - "width": 1920, - "height": 1080, - "status": "completed", - "created_at": "2026-04-30T10:00:00Z", - "file_size": 52428800, - "total_frames": 3615 - } - ], - "count": 1, - "page": 1, - "page_size": 20 -} -``` - -### `DELETE /api/v1/videos/:uuid` -Delete a video and all associated data (faces, chunks, processor results). - -**Response**: -```json -{ - "success": true, - "message": "File 384b0ff44aaaa1f1 unregistered successfully...", - "file_uuid": "384b0ff44aaaa1f1", - "deleted_face_detections": 150, - "deleted_processor_results": 8, - "deleted_chunks": 45 -} -``` - -### `GET /api/v1/videos/:uuid/details` -Get detailed chunk information. - -**Query Parameters**: -- `chunk_id`: Specific chunk ID (required) -- `parent_id`: Parent chunk ID - -**Response**: -```json -{ - "uuid": "384b0ff44aaaa1f1", - "chunk_id": "chunk_1", - "chunk_type": "sentence", - "frame_range": { - "start_frame": 315, - "end_frame": 456, - "duration_frames": 141, - "fps": 30.0 - }, - "reference_time": { - "start": 10.5, - "end": 15.2 - }, - "text_content": "AI is transforming...", - "summary_text": "Discussion about AI impact", - "speaker_ids": ["SPEAKER_0"], - "person_ids": ["face_100"] -} -``` - -### `GET /api/v1/videos/:uuid/pre_chunks` -List pre-processor chunks. - -**Query Parameters**: -- `processor_type`: Filter by processor (asr, yolo, face, etc.) -- `page`: Page number -- `page_size`: Items per page - -### `GET /api/v1/progress/:uuid` -Get processing progress for a video. - ---- - -## 5. Identity & Binding - -### `POST /api/v1/identities/from-face` -Register a global identity from face.json with multi-angle reference vectors. - -**Request**: -```json -{ - "face_json_path": "/path/to/face.json", - "identity_name": "John Doe", - "schema": "dev" -} -``` - -### `POST /api/v1/identities/from-person` -Register identity from a person in a video. - -**Request**: -```json -{ - "file_uuid": "384b0ff44aaaa1f1", - "person_id": "person_1", - "identity_name": "John Doe" -} -``` - -### `GET /api/v1/identities` -List all global identities. - -**Query Parameters**: -- `page`: Page number -- `page_size`: Items per page - -### `GET /api/v1/faces/candidates` -List unbound face candidates. - -**Query Parameters**: -- `file_uuid`: Filter by file -- `min_confidence`: Minimum confidence (default: 0.5) -- `page`, `page_size`: Pagination - -### `GET /api/v1/identities/:identity_id/faces` -Get all faces for an identity. - -### `GET /api/v1/faces/:face_id/thumbnail` -Get face thumbnail image (JPEG). - -### `POST /api/v1/identities/bind` -Bind a face/speaker to an identity. - -**Request**: -```json -{ - "identity_id": 1, - "binding_type": "face", - "binding_value": "face_100", - "source": "manual" -} -``` - -### `POST /api/v1/identities/unbind` -Unbind an identity. - -**Request**: -```json -{ - "binding_type": "face", - "binding_value": "face_100" -} -``` - -### `GET /api/v1/identity/:binding_type/:binding_value` -Get identity info by binding. - -### `GET /api/v1/signals/unbound` -List unbound signals. - -**Query Parameters**: -- `uuid`: File UUID -- `binding_type`: "face" or "speaker" - -### `GET /api/v1/signals/:uuid/:binding_type/:binding_value/timeline` -Get signal timeline (all chunks for a face/speaker). - -### `POST /api/v1/identities/suggest-av` -Suggest audio-visual bindings based on temporal overlap. - -**Request**: -```json -{ - "file_uuid": "384b0ff44aaaa1f1", - "overlap_threshold": 0.6 -} -``` - ---- - -## 6. Jobs & Rules - -### `GET /api/v1/jobs` -List all monitor jobs. - -**Query Parameters**: -- `page`, `page_size`: Pagination -- `status`: Filter by status - -### `GET /api/v1/jobs/:job_id` -Get job details with processor information. - -**Response**: -```json -{ - "job_id": "1", - "asset_uuid": "384b0ff44aaaa1f1", - "rule": "default", - "status": "RUNNING", - "current_processor_id": "asr", - "frame_progress": { - "total_frames": 3615, - "processed_frames": 1200, - "progress_percent": 33.2 - } -} -``` - -### `GET /api/v1/rules/:rule/status` -Get rule status with active jobs. - ---- - -## 7. Stats & Configuration - -### `GET /api/v1/stats/ingest` -Get ingestion statistics. - -**Response**: -```json -{ - "total_videos": 50, - "total_chunks": 1200, - "sentence_chunks": 800, - "cut_chunks": 300, - "time_chunks": 100, - "searchable_chunks": 1150, - "chunks_with_visual": 450, - "chunks_with_summary": 200, - "pending_videos": 5 -} -``` - -### `GET /api/v1/stats/sftpgo` -Get SFTPGo status and registered videos. - -### `GET /api/v1/stats/inference` -Check inference engine health (Ollama, llama-server). - -**Response**: -```json -{ - "ollama": { - "engine": "Ollama", - "model": "nomic-embed-text", - "status": "ok", - "latency_ms": 15 - }, - "llama_server": { - "engine": "llama-server", - "model": "gemma4_e4b_q5", - "status": "ok", - "latency_ms": 25 - } -} -``` - -### `POST /api/v1/config/cache` -Toggle MongoDB cache. - -**Request**: -```json -{ "enabled": false } -``` - -**Response**: -```json -{ - "success": true, - "cache_enabled": false, - "message": "Cache disabled" -} -``` - ---- - -## API Usage Patterns - -### 1. List Pattern -``` -GET /api/v1/videos?page=1&page_size=20 -``` -- Supports pagination -- Optional filters via query parameters -- Returns `{ items: [...], count, page, page_size }` - -### 2. Detail Pattern -``` -GET /api/v1/videos/:uuid/details?chunk_id=chunk_1 -``` -- Path parameter for resource identifier -- Query parameters for sub-resource selection -- Returns detailed object with nested structures - -### 3. Operation Pattern -``` -POST /api/v1/assets/:uuid/process -``` -- Action-oriented endpoint -- Request body contains operation parameters -- Returns operation status and job ID - -### 4. Application Pattern -``` -POST /api/v1/identities/bind -POST /api/v1/identities/suggest-av -``` -- Complex workflows with multiple steps -- Often involve external services (Python scripts, FFmpeg) -- Return comprehensive results with metadata - ---- - -## Error Responses - -| Status Code | Description | -|-------------|-------------| -| `400` | Bad Request - Invalid parameters | -| `404` | Not Found - Resource doesn't exist | -| `500` | Internal Server Error - Database/service failure | - ---- - -## V4.0 Architecture Notes - -### Key Changes from V3.x -- `video_uuid` → `file_uuid` (terminology update) -- `person_identities` table **removed** -- Face → Identity direct binding (no intermediate person_id) -- 28 person_id APIs removed (except register/bind) -- Chunk binding auto via time alignment - -### Identity Model -``` -Face Detection → Identity (direct binding) -Speaker Detection → Identity (direct binding) -``` - -### Processing Pipeline -``` -Register → Probe → ASR → CUT → YOLO → OCR → Face → Pose → ASRX → Visual Chunk -``` diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/API_DICTIONARY_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/API_DICTIONARY_V1.0.0.md new file mode 100644 index 0000000..5f5be85 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/API_DICTIONARY_V1.0.0.md @@ -0,0 +1,183 @@ +--- +document_type: "reference_doc" +service: "MOMENTRY_CORE" +title: "Momentry Core API 字典 V1.0.0" +date: "2026-05-01" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "momentry" + - "core" + - "api" + - "dictionary" + - "v1.0.0" +ai_query_hints: + - "Momentry Core API 字典查詢" + - "API 端點與參數說明" + - "API 回應格式定義" + - "查詢所有 Public/Internal/Admin API 端點列表" + - "API 端點的 HTTP 方法與路徑結構" + - "搜尋 API 有哪些端點(search/bm25/hybrid/visual)" + - "API 端點的狀態分類(Public/Internal/Admin)" +related_documents: + - "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md" + - "API_V1.0.0/API_USAGE_DEMO_V1.0.0.md" + - "API_V1.0.0/API_REFERENCE_v1.0.0.20260501md.md" + - "API_V1.0.0/CHUNK_DEFINITION_V1.0.0.md" + - "API_V1.0.0/VECTOR_SPEC_V1.0.0.md" +--- + +# Momentry Core API 字典級全量文件 V1.0.0 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Public API | 供前端與外部系統使用的標準介面(58 個端點) | +| Internal API | 系統內部流程或狀態查詢用(5 個端點) | +| Admin API | 管理員專用(5 個端點) | +| file_uuid | 32 碼 SHA256 檔案識別碼 | +| RESTful | 以資源為中心的 API 設計風格 | + +## 📊 端點統計 (Endpoint Statistics) + +| 分類 | 數量 | 說明 | +|---|---|---| +| ✅ **Public** | 58 | 供前端與外部系統使用的標準介面 | +| ⚠️ **Internal** | 5 | 系統內部流程或狀態查詢 (如 Probe, SFTPGo) | +| 🔒 **Admin** | 5 | 管理員專用 (如 Resources, Config Cache) | +| **總計** | **67** | 所有已註冊路由 (`gen-traces` 已移除) | + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-01 | +| 端點總數 | **68** | +| 文件版本 | V1.1 (Route Fixes + Arch Notes) | + +--- + +## 🚀 設計原則 (Design Principles) + +### 1. Clear API (介面清晰化) +* **去蕪存菁**: 嚴格區分 **Public** (公開) 與 **Internal** (內部) 端點。舊版冗餘路徑(如 `/api/v1/videos`, `/api/v1/probe`)已全面移除或合併。 +* **標準化回應**: 所有列表型 API 均回傳統一結構 `{ "success": true, "data": [...], "total": N }`。 +* **命名規範**: 採用 RESTful 風格,資源以複數名詞或明確動作命名(如 `files`, `identities`)。 + +### 2. File-Centric (以檔案為核心) +* **唯一識別**: 每個媒體檔案(影片/圖片/音訊)均由 **32 碼 UUID** (`file_uuid`) 唯一標識。 +* **生命週期**: `File` 是所有資料的根節點。所有的 `Chunk` (片段), `Snapshot` (快照), `Jobs` (任務) 皆隸屬於特定的 `File`。 +* **操作模式**: 前端應優先呼叫 `GET /api/v1/files` 取得清單,再透過 `POST /api/v1/files/:uuid/snapshots/migrate` 載入詳細資源。 + +### 4. Trace Aggregation (軌跡聚合獨立化) +* **架構**: `trace_face` 聚合由獨立 Python 腳本 `scripts/trace_face_aggregator.py` 處理,**不**內嵌於 Rust DB 層。 +* **流程**: Face Processor (Python) 輸出離散幀級資料到 `face_detections` 表 → Rust Worker 排程 `trace_face_aggregator.py` → 該腳本讀取 DB、按 `face_id` 分組聚合、寫入 `pre_chunks` (source_type=`trace_face`)。 +* **設計理由**: 保持 Rust 排程層輕量化,軌跡聚合邏輯留在 Python 層統一維護,便於未來調整聚合演算法 (如 IOU 門檻、時間間隔合併等) 而無需重新編譯 Rust。 + +### 5. Global Identity (全域身份識別) +* **跨檔案關聯**: `Identity` 代表一個獨立的人物或角色,不受單一檔案限制。 +* **綁定機制 (Binding)**: 透過 `POST /api/v1/identities/bind`,我們可以將多個檔案中偵測到的臉部 (`face`) 或聲音 (`speaker`) 聚合到同一個 `Identity` 下。 +* **資料聚合**: 查詢某個 `Identity` 即可看到該人物在所有歷史檔案中的軌跡 (`/api/v1/identities/:uuid/files`)。 + +--- + +## 1. 系統與認證 (System & Auth) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `GET` | `/health` | ✅ Public | +| `GET` | `/health/detailed` | ✅ Public | +| `POST` | `/api/v1/auth/login` | ✅ Public | +| `POST` | `/api/v1/auth/logout` | ✅ Public | + +## 2. 檔案管理 (Files & Assets) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `GET` | `/api/v1/files` | ✅ Public | +| `GET` | `/api/v1/files/scan` | ✅ Public | +| `POST` | `/api/v1/files/register` | ✅ Public | +| `POST` | `/api/v1/unregister` | ✅ Public | +| `GET` | `/api/v1/files/:file_uuid` | ✅ Public | +| `GET` | `/api/v1/files/:file_uuid/identities` | ✅ Public | +| `GET` | `/api/v1/files/:file_uuid/snapshots` | ✅ Public | +| `GET` | `/api/v1/files/:file_uuid/snapshots/status` | ✅ Public | +| `POST` | `/api/v1/files/:file_uuid/snapshots/migrate` | ✅ Public | +| `POST` | `/api/v1/files/:file_uuid/snapshots/teardown` | ✅ Public | + +## 3. 影片與任務 (Videos & Jobs) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `DELETE` | `/api/v1/videos/:file_uuid` | ✅ Public | +| `GET` | `/api/v1/videos/:file_uuid/details` | ✅ Public | +| `GET` | `/api/v1/videos/:file_uuid/pre_chunks` | ✅ Public | +| `GET` | `/api/v1/progress/:file_uuid` | ✅ Public | +| `GET` | `/api/v1/jobs` | ✅ Public | +| `GET` | `/api/v1/jobs/:job_id` | ✅ Public | +| `GET` | `/api/v1/rules/:rule/status` | ✅ Public | +| `GET` | `/api/v1/files/:file_uuid/probe` | ✅ Public | +| `POST` | `/api/v1/files/:file_uuid/process` | ✅ Public | +| `GET` | `/api/v1/assets/:uuid/status` | ⚠️ Internal | +| `POST` | `/api/v1/resources/register` | 🔒 Internal | +| `POST` | `/api/v1/resources/heartbeat` | 🔒 Internal | +| `GET` | `/api/v1/resources` | 🔒 Internal | + +## 4. 搜尋 (Search) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `POST` | `/api/v1/search` | ✅ Public | +| `POST` | `/api/v1/search/bm25` | ✅ Public | +| `POST` | `/api/v1/search/hybrid` | ✅ Public | +| `POST` | `/api/v1/search/visual` | ✅ Public | +| `POST` | `/api/v1/search/visual/class` | ✅ Public | +| `POST` | `/api/v1/search/visual/density` | ✅ Public | +| `POST` | `/api/v1/search/visual/combination` | ✅ Public | +| `POST` | `/api/v1/search/visual/stats` | ✅ Public | + +## 5. 身份與綁定 (Identity & Binding) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `GET` | `/api/v1/identities` | ✅ Public | +| `GET` | `/api/v1/identities/:uuid` | ✅ Public | +| `GET` | `/api/v1/identities/:uuid/files` | ✅ Public | +| `GET` | `/api/v1/identities/:uuid/chunks` | ✅ Public | +| `GET` | `/api/v1/identities/:identity_id/faces` | ✅ Public | +| `POST` | `/api/v1/identities/from-person` | ✅ Public | +| `POST` | `/api/v1/identities/from-face` | ✅ Public | +| `POST` | `/api/v1/identities/bind` | ✅ Public | +| `POST` | `/api/v1/identities/unbind` | ✅ Public | + +## 6. 臉部 (Face) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `GET` | `/api/v1/face/list` | ✅ Public | +| `GET` | `/api/v1/face/:face_id` | ✅ Public | +| `DELETE` | `/api/v1/face/:face_id` | ✅ Public | +| `POST` | `/api/v1/face/recognize` | ✅ Public | +| `POST` | `/api/v1/face/register` | ✅ Public | +| `POST` | `/api/v1/face/search` | ✅ Public | +| `GET` | `/api/v1/faces/candidates` | ✅ Public | +| `GET` | `/api/v1/files/:file_uuid/faces/:face_id/thumbnail` | ✅ Public | +| `GET` | `/api/v1/signals/unbound` | ✅ Public | +| `GET` | `/api/v1/signals/:uuid/:binding_type/:binding_value/timeline` | ✅ Public | + +## 7. 代理人 (Agents) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `POST` | `/api/v1/agents/translate` | ✅ Public | +| `POST` | `/api/v1/agents/5w1h/analyze` | ✅ Public | +| `POST` | `/api/v1/agents/5w1h/batch` | ✅ Public | +| `GET` | `/api/v1/agents/5w1h/status` | ✅ Public | +| `POST` | `/api/v1/agents/identity/analyze` | ✅ Public | +| `POST` | `/api/v1/agents/identity/suggest` | ✅ Public | +| `GET` | `/api/v1/agents/identity/status` | ✅ Public | +| `POST` | `/api/v1/agents/suggest/merge` | ✅ Public | + +## 8. 狀態與統計 (Stats) +| 方法 | 路徑 | 狀態 | +|---|---|---| +| `GET` | `/api/v1/stats/ingest` | ✅ Public | +| `GET` | `/api/v1/stats/sftpgo` | ⚠️ Internal | +| `GET` | `/api/v1/stats/inference` | ⚠️ Internal | +| `POST` | `/api/v1/config/cache` | 🔒 Internal | +| `GET` | `/api/v1/lookup` | ✅ Public | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/API_REFERENCE_v1.0.0.20260501md.md b/docs_v1.0/API_V1.0.0/INTERNAL/API_REFERENCE_v1.0.0.20260501md.md new file mode 100644 index 0000000..0ccd574 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/API_REFERENCE_v1.0.0.20260501md.md @@ -0,0 +1,310 @@ +--- +document_type: "reference_doc" +service: "MOMENTRY_CORE" +title: "Momentry Core API 參考文件 V1.0.0 (Demo 完整指南)" +date: "2026-05-01" +version: "V3.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "api" + - "reference" + - "v1.0.0" + - "demo" + - "marcom" +ai_query_hints: + - "查詢 V1.0.0 Demo 所需 API 列表" + - "Momentry Core Demo 流程如何使用 API?" + - "API 的檔案註冊、處理、臉部綁定流程" + - "Demo 流程中 Scan → Unregister → Register → Probe → Process → Faces → Bind 的完整步驟" + - "API 的 curl 範例與回應格式" + - "Process 回傳 400 Bad Request 的常見原因與解決方法" + - "臉部查詢回傳空結果的疑難排解步驟" +related_documents: + - "STANDARDS/DOCS_STANDARD.md" + - "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md" + - "TEST_REPORT_CLI.md" +--- + +# Momentry Core API 參考文件 V1.0.0 (Demo 完整指南) + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| file_uuid | 32 碼 SHA256 檔案識別碼 | +| X-API-Key | API 認證方式,透過 HTTP Header 傳遞 | +| Scan | 掃描檔案系統,列出所有檔案及當前狀態 | +| Register | 將檔案加入資料庫系統 | +| Probe | 讀取檔案 metadata(時長、解析度、幀率) | +| Bind | 將臉部綁定到指定身份 | +| Progress | 獲取處理進度與目前階段 | + +## 📊 文件統計 (Document Statistics) + +| 項目 | 數值 | +|---|---| +| **收錄端點** | 15+ (Demo 核心流程) | +| **涵蓋率** | Demo 流程 100% | +| **測試狀態** | ✅ CLI Verified | + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-01 | +| 文件版本 | V3.0 | + +--- + +## 1. Demo 流程總覽 (Demo Workflow) + +本文件專注於 **Demo 測試計畫** 所需的 API。以下是完整流程與對應 API: + +``` +1. 掃描狀態 (Scan) → GET /api/v1/files/scan +2. 檔案重置 (Unregister) → POST /api/v1/unregister +3. 檔案註冊 (Register) → POST /api/v1/files/register +4. 檔案探測 (Probe) → GET /api/v1/files/:file_uuid/probe +5. 開始處理 (Process) → POST /api/v1/files/:file_uuid/process +6. 監控進度 (Progress) → GET /api/v1/progress/:file_uuid** +7. 查詢臉部 (Faces) → GET /api/v1/faces/candidates +8. 綁定身份 (Bind) → POST /api/v1/identities/bind +``` + +--- + +## 2. 快速資訊 + +- **Base URL (Dev)**: `http://localhost:3003` +- **Base URL (Prod)**: `http://localhost:3002` +- **認證方式**: Header `X-API-Key: muser_test_001` +- **測試 Key**: `muser_test_001` + +--- + +## 3. API 詳細說明 (依 Demo 順序) + +### 3.1 掃描檔案系統 (Scan Files) +**路徑**: `GET /api/v1/files/scan` + +**用途**: 列出檔案系統中所有檔案及當前狀態,**是 Demo 流程的第一步**。 + +**Response**: +```json +{ + "files": [ + { + "file_name": "A12T3-Share-User Experience of Thunderbolt 3 Shareable Storage.mp4", + "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/A12T3-Share-User Experience of Thunderbolt 3 Shareable Storage.mp4", + "file_uuid": "7ab7e25f48b58675e33aca44d15c1ecc", + "is_registered": true, + "status": "processing" + } + ], + "total": 20, + "registered_count": 20, + "unregistered_count": 0 +} +``` + +--- + +### 3.2 取消註冊 (Unregister File) +**路徑**: `POST /api/v1/unregister` + +**用途**: 從 Scan 結果中選取 `file_uuid`,對該檔案執行取消註冊。 + +**Request**: +```json +{ + "uuid": "53e3a229bf68878b7a799e811e097f9c" +} +``` + +**Response**: +```json +{ + "success": true, + "uuid": "53e3a229bf68878b7a799e811e097f9c", + "message": "File unregistered successfully" +} +``` + +--- + +### 3.3 註冊檔案 (Register File) +**路徑**: `POST /api/v1/files/register` + +**用途**: 從 Scan 結果中選取 `file_path`,將檔案加入資料庫系統。 + +**Request**: +```json +{ + "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/view15.mp4" +} +``` + +**Response**: +```json +{ + "success": true, + "file_uuid": "53e3a229bf68878b7a799e811e097f9c", + "file_name": "view15.mp4", + "file_path": "/Users/.../demo/view15.mp4", + "already_exists": false +} +``` + +--- + +### 3.4 檔案探測 (Probe File) +**路徑**: `GET /api/v1/files/:file_uuid/probe` + +**用途**: 讀取檔案的 metadata (時長、解析度、幀率)。**必須在 Process 前執行**。 + +**Response**: +```json +{ + "file_uuid": "7ab7e25f48b58675e33aca44d15c1ecc", + "file_name": "A12T3-Share-User Experience of Thunderbolt 3 Shareable Storage.mp4", + "duration": 621.55, + "width": 1920, + "height": 1080, + "fps": 29.97, + "cached": true +} +``` + +--- + +### 3.5 觸發處理 (Process File) +**路徑**: `POST /api/v1/files/:file_uuid/process` + +**用途**: 啟動後端 Worker 進行分析 (ASR, Face, YOLO, 等)。 + +**Request**: +```json +{} +``` + +**Response**: +```json +{ + "success": true, + "message": "Processing started" +} +``` + +--- + +### 3.6 查詢進度 (Progress) +**路徑**: `GET /api/v1/progress/:file_uuid` + +**用途**: 獲取處理進度與目前階段。 + +**Response**: +```json +{ + "file_uuid": "53e3a229bf68878b7a799e811e097f9c", + "overall_progress": 65, + "current_processor": "face", + "status": "running", + "processors": [ + { "name": "probe", "status": "completed" }, + { "name": "asr", "status": "completed" }, + { "name": "face", "status": "running" } + ] +} +``` + +--- + +### 3.6 查詢未綁定臉部 (List Face Candidates) +**路徑**: `GET /api/v1/faces/candidates` + +**用途**: 列出檔案中尚未綁定身份的臉部。 + +**Query Parameters**: +- `file_uuid` (必填): 檔案 UUID +- `min_confidence` (選填): 最低信心值 (預設 0.5) +- `page_size` (選填): 每頁數量 (預設 20) + +**Response**: +```json +{ + "candidates": [ + { + "id": 123, + "face_id": "123_RoleA", + "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", + "frame_number": 115, + "confidence": 0.98, + "bbox": { "x": 50, "y": 50, "w": 100, "h": 100 } + } + ], + "total": 1, + "page": 1, + "page_size": 20 +} +``` + +--- + +### 3.7 綁定身份 (Bind Identity) +**路徑**: `POST /api/v1/identities/bind` + +**用途**: 將臉部綁定到指定身份 (或建立新身份)。 + +**Request**: +```json +{ + "identity_id": 22, + "binding_type": "face", + "binding_value": "123_RoleA" +} +``` + +**Response**: +```json +{ + "success": true, + "message": "Bound face '123_RoleA' to Identity 'Cary Grant'" +} +``` + +--- + +## 4. 補充 API (Demo 選用) + +### 4.1 列出身份 (List Identities) +**路徑**: `GET /api/v1/identities` + +**用途**: 列出系統中所有已建立的身份。 + +--- + +## 5. 常見問題 (FAQ) + +### Q1: 為什麼 Process 回傳 400 Bad Request? +**Ans**: 必須先執行 **Probe** (`GET /api/v1/files/:file_uuid/probe`),確保系統已知曉檔案的幀數資訊。 + +### Q2: 為什麼 Unregister 回傳 404? +**Ans**: 確認伺服器是否已更新至最新版本。舊版可能尚未包含此路由。 + +### Q3: 臉部查詢回傳空結果? +**Ans**: +1. 確認檔案已**處理完成** (Progress = 100%)。 +2. 嘗試降低 `min_confidence` 參數 (例如設為 0.0)。 +3. 確認該檔案內容確實包含可辨識的臉部。 + +--- + +## 6. 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | +|------|------|------|--------| +| V1.0 | 2026-04-30 | 初始 API 列表 | OpenCode | +| V2.0 | 2026-05-01 | 基於 Production 測試結果補足文件 | OpenCode | +| V3.0 | 2026-05-01 | 重構為 Demo 流程導向,補齊 Probe/Unregister 說明 | OpenCode | +| V3.1 | 2026-05-01 | 修正 `:uuid`→`:file_uuid`,修正 port 3002→3003,移除重複 Scan 章節 | OpenCode | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/API_USAGE_DEMO_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/API_USAGE_DEMO_V1.0.0.md new file mode 100644 index 0000000..35fa355 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/API_USAGE_DEMO_V1.0.0.md @@ -0,0 +1,376 @@ +--- +document_type: "develop_guide" +service: "MOMENTRY_CORE" +title: "Momentry Core V1.0.0 API 示範與整合指南" +date: "2026-05-01" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "momentry" + - "core" + - "api-usage" + - "demo" + - "n8n" + - "wordpress" +ai_query_hints: + - "查詢 V1.0.0 API 示範與整合指南的內容" + - "如何使用 n8n 呼叫 V1.0.0 API?" + - "如何整合 V1.0.0 API 到 WordPress?" + - "V1.0.0 API 的 curl 範例" + - "PHP 整合 V1.0.0 API 的方式(wp_remote_request)" + - "n8n 工作流如何串接 V1.0.0 API" + - "Face 綁定錯誤修正的 API 操作步驟" + - "前端 Face Interpolation 的實作方式" +related_documents: + - "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md" + - "API_V1.0.0/API_DICTIONARY_V1.0.0.md" + - "API_V1.0.0/API_REFERENCE_v1.0.0.20260501md.md" + - "API_V1.0.0/CHUNK_DEFINITION_V1.0.0.md" + - "API_V1.0.0/PROCESSOR_SELECTION_V1.0.0.md" +--- + +# Momentry Core V1.0.0 API 示範與整合指南 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-01 | +| 文件版本 | V1.0 | +| 適用版本 | Momentry Core V1.0.0+ | + +--- + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| file_uuid | 32 碼 SHA256 檔案識別碼 | +| X-API-Key | API 認證方式,透過 HTTP Header 傳遞 | +| face_id | 單一幀中的人臉偵測 ID,格式為 `<檢測ID>_<角色後綴>` | +| Identity | 全域人物身份,跨檔案關聯同一人物 | +| Face Interpolation | 前端線性插值,補足非逐幀臉部標記的顯示 | +| Scan | 掃描檔案系統,列出所有檔案及當前狀態 | + +## 1. 快速開始 (Quick Start) + +### 1.1 環境 URL + +| 環境 | URL | 用途 | +|------|-----|------| +| **對外 URL** | `https://api.momentry.ddns.net` | 外部存取 | +| **Dev Server** | `http://localhost:3003` | **開發環境,所有測試用** | +| **Local Server** | `http://localhost:3002` | Production,僅 release 用 | + +### 1.2 測試連線 + +```bash +curl http://localhost:3003/health +``` + +```json +{ + "status": "ok", + "version": "1.0.0 (build: ...)", + "uptime_ms": 64880 +} +``` + +--- + +## 2. 核心 API 工作流 (Workflows) + +### 2.1 掃描檔案系統 (Scan Files) +**入口 API**: `GET /api/v1/files/scan` — 所有 Demo 流程從這裡開始。 + +**掃描檔案**: +```bash +curl -s "http://localhost:3003/api/v1/files/scan" \ + -H "X-API-Key: " +``` + +**列出檔案 (分頁)**: +```bash +curl -s "http://localhost:3003/api/v1/files?page=1&page_size=10" \ + -H "X-API-Key: " +``` + +**取得單一檔案詳情**: +```bash +curl -s "http://localhost:3003/api/v1/files/" \ + -H "X-API-Key: " +``` + +### 2.2 搜尋 (Search) +支援語意搜尋、混合搜尋與視覺搜尋。 + +```bash +curl -X POST "http://localhost:3003/api/v1/search" \ + -H "X-API-Key: " \ + -H "Content-Type: application/json" \ + -d '{"query": "尋找紅色信封", "uuid": ""}' +``` + +### 2.3 單獨 Face 綁定流程 (Single Face Binding Workflow) + +此流程適用於手動將特定臉部關聯到已知人物或建立新人物的場景。系統支援**一人分飾多角**,透過 `face_id` 加上角色後綴來區分。 + +#### 步驟 1: 選定 Face (Input Format) +使用者需提供一個 **`file_uuid`** 搭配 **`face_id`** 來鎖定目標。 +選定的意思是輸入 **`:`** 的組合。 + +* **命名規則**: `face_id` 格式通常為 `<原始檢測 ID>_<後綴>`,用於區分同一人的不同臉部實體或角色。 + * **有角色名稱**: 使用角色名 (如 `123_PeterJoshua`)。 + * **無角色名稱**: 使用通用代號 (如 `123_RoleA`, `123_RoleB`)。 + +#### 步驟 2: 列出 Identities 或新增 Identity +使用者決定將該 Face 綁定到系統中已存在的全域人物 (Identity),或是建立一個新人物。 +* **Identity 特性**: 代表現實世界中的真實人物,具備**全域唯一性** (如 "Cary Grant")。 + +- **選項 A: 列出人物清單** + ```bash + curl -s "http://localhost:3003/api/v1/identities?page=1&page_size=20" \ + -H "X-API-Key: " + ``` + +- **選項 B: 決定新增人物名稱** + 若列表中沒有對應人物,使用者需準備一個新名稱(如 "Cary Grant")。 + +#### 步驟 3: 確認綁定 +透過 `POST /api/v1/identities/bind` 完成綁定。 +* **若提供 `identity_id`**: 將帶有後綴的 `face_id` 綁定至該人物。 +* **若提供 `name`**: 系統自動建立新人物 (Identity),並將該臉部綁定上去。 + +- **綁定至現有身份 (範例)**: + 假設我們要綁定的目標是檔案 `file_uuid_abc` 中的臉部 `123_PeterJoshua`。 + ```bash + curl -X POST "http://localhost:3003/api/v1/identities/bind" \ + -H "X-API-Key: " \ + -H "Content-Type: application/json" \ + -d '{ + "identity_id": 101, + "binding_type": "face", + "binding_value": "123_PeterJoshua" + }' + ``` + *註: 雖然 API 接收的是 `binding_value`,但系統內部會根據選定的 `file_uuid` 與 `face_id` 組合來精確鎖定目標。* + +#### 步驟 4: 循環 +完成綁定後,返回列表處理下一個未綁定的 Face。 + +--- + +### 2.4 取得 Face 截圖 (Retrieve Face Snapshots) + +在確認綁定前,通常需要檢視臉部截圖。根據使用場景,取得截圖有兩種方式: + +#### 1. Local Path / Filename (本地路徑) +* **適用**: Tauri 桌面應用、本機腳本。 +* **說明**: 直接從硬碟讀取圖片檔案,速度最快,無需經過網路層。 +* **路徑**: `//snapshots/faces/.jpg` + +#### 2. URL (網路存取) +* **適用**: Web 前端、外部系統。 +* **說明**: 透過 HTTP GET 請求取得影像串流。 +* **API Endpoint**: `GET /api/v1/files//faces//thumbnail` +* **範例**: + ```bash + curl -s -o face.jpg \ + "http://localhost:3003/api/v1/files//faces//thumbnail" \ + -H "X-API-Key: " + ``` + +--- + +### 2.4.1 前端動態辨識與插值 (Face Interpolation Logic) + +由於系統對臉部標記並非逐幀 (Frame-by-Frame) 進行(為節省運算資源或受限於取樣率),在 Client 端進行**逐幀播放**或**時間軸拖曳**時,若直接顯示會導致臉部框選忽閃忽滅。 + +#### 運作邏輯 +前端需實作**線性插值 (Linear Interpolation)** 機制: + +1. **取得資料**:從 API 取得該 `face_id` 在所有 `frame_number` 的座標列表(例如:Frame 10, Frame 15 有資料)。 +2. **插值計算**: + * 當使用者停在 **Frame 12** 時,系統無直接資料。 + * 前端應找出前後最近的有資料幀(Frame 10 與 Frame 15)。 + * 根據時間差比例,動態計算出 Frame 12 的座標 `x, y, w, h`。 + +#### 實作範例 (JavaScript/TypeScript) + +```typescript +// 假設 API 回傳該 Face 的軌跡點 +const detections = [ + { frame: 10, bbox: { x: 100, y: 100, w: 50, h: 60 } }, + { frame: 15, bbox: { x: 110, y: 105, w: 50, h: 60 } }, +]; + +// 計算 Frame 12 的預測框選 +function getInterpolatedBBox(frameIndex: number, detections) { + // 找到前一幀與後一幀 + const prev = detections.find(d => d.frame <= frameIndex); // Frame 10 + const next = detections.find(d => d.frame > frameIndex); // Frame 15 + + if (!prev) return null; // 還沒開始出現 + if (!next) return prev.bbox; // 結束了,維持最後位置 + + // 計算比例 (0.0 - 1.0) + const ratio = (frameIndex - prev.frame) / (next.frame - prev.frame); + + return { + x: prev.bbox.x + (next.bbox.x - prev.bbox.x) * ratio, + y: prev.bbox.y + (next.bbox.y - prev.bbox.y) * ratio, + // w, h 亦可依此邏輯進行縮放插值 + w: prev.bbox.w, + h: prev.bbox.h, + }; +} +``` + +--- + +### 2.5 Face 綁定錯誤修正 (Face Binding Error Correction) + +此流程適用於移除錯誤綁定的臉部資料,使其恢復為未綁定狀態。 + +1. **選定 Face**: 確認需要解除綁定的臉部 `face_id` 以及所屬的 `file_uuid`。 +2. **解除綁定 (Unbind)**: + ```bash + curl -X POST "http://localhost:3003/api/v1/identities/unbind" \ + -H "X-API-Key: " \ + -H "Content-Type: application/json" \ + -d '{ + "binding_type": "face", + "binding_value": "" + }' + ``` + +--- + +## 3. n8n 整合範例 + +### 3.1 HTTP Request 設定 + +| 欄位 | 值 | +|---|---| +| Method | `GET` 或 `POST` | +| URL | `http://localhost:3003/api/v1/files` (Dev) 或 `https://` (Prod) | +| Header `X-API-Key` | `` | + +### 3.2 列出檔案 Workflow (JSON) +使用 `GET /api/v1/files/scan` 作為入口。 + +```json +{ + "nodes": [ + { + "name": "Get Files", + "type": "n8n-nodes-base.httpRequest", + "parameters": { + "method": "GET", + "url": "http://localhost:3003/api/v1/files/scan", + "sendHeaders": true, + "headerParameters": { + "parameters": [{ "name": "X-API-Key", "value": "{{ $env.API_KEY }}" }] + }, + "options": { "qs": { "page": 1, "page_size": 10 } } + }, + "position": [450, 300] + }, + { + "name": "Extract List", + "type": "n8n-nodes-base.code", + "parameters": { + "jsCode": "return $input.first().json.data.map(f => ({\n json: {\n uuid: f.file_uuid,\n name: f.file_name,\n status: f.status\n }\n}));" + }, + "position": [650, 300] + } + ] +} +``` + +--- + +## 4. WordPress / PHP 整合範例 + +### 4.1 PHP Client Library (V1.0.0 相容) + +```php +'; + + private function request(string $endpoint, array $data = [], string $method = 'GET'): array { + $url = self::API_URL . $endpoint; + $args = [ + 'headers' => [ + 'X-API-Key' => self::API_KEY, + 'Content-Type' => 'application/json', + ], + 'timeout' => 30, + ]; + + if ($method === 'POST') { + $args['method'] = 'POST'; + $args['body'] = json_encode($data); + } + + $response = wp_remote_request($url, $args); + if (is_wp_error($response)) { + throw new Exception($response->get_error_message()); + } + return json_decode(wp_remote_retrieve_body($response), true); + } + + // 掃描檔案 + public function scan_files(): array { + return $this->request('/api/v1/files/scan'); + } + + // 列出檔案 + public function list_files(): array { + return $this->request('/api/v1/files'); + } + + // 搜尋 + public function search(string $query): array { + return $this->request('/api/v1/search', ['query' => $query], 'POST'); + } +} +?> +``` + +--- + +## 5. 疑難排解 + +| 錯誤 | 原因 | 解決方案 | +|------|------|----------| +| `401 Unauthorized` | API Key 無效 | 檢查 Key 格式與權限 | +| `404 Not Found` | 端點不存在 | 確認是否使用了舊版 `/api/v1/videos`,應改為 `/api/v1/files` | +| `400 Bad Request on Process` | 缺少 Probe 資料 | 先執行 `GET /api/v1/files/:file_uuid/probe` | +| `500 Error` | 伺服器錯誤 | 檢查資料庫連線與 Schema 版本 | + +--- + +## 6. 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-01 | 初始版本 | OpenCode | deepseek-chat | +| V1.1 | 2026-05-01 | 修正 port 為 Dev(3003),更新 API 路徑與掃描入口 | OpenCode | deepseek-chat | + +--- + +## 7. 附錄:UUID 格式說明 + +V1.0.0 使用 **32 碼 SHA256** 作為 `file_uuid`。 + +``` +/Users/.../demo/video.mp4 + ↓ +SHA256 Hash (前 32 字元) + ↓ +53e3a229bf68878b7a799e811e097f9c +``` diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/CHUNK_DEFINITION_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/CHUNK_DEFINITION_V1.0.0.md new file mode 100644 index 0000000..fa8ec73 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/CHUNK_DEFINITION_V1.0.0.md @@ -0,0 +1,198 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Chunk 定義 V1.0.0" +date: "2026-05-01" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "momentry" + - "core" + - "chunk" + - "v1.0.0" + - "chunk-type" + - "pre-chunk" + - "parent-child" + - "data-structure" +ai_query_hints: + - "chunk 的定義與結構" + - "pre_chunk 與 chunk 的關係" + - "parent_chunk 與 child_chunk 的關係" + - "ChunkType 包含哪些類型(Sentence/Cut/Visual/Trace/Story)" + - "chunk 的巢狀結構與 Rule 組合規則" + - "chunk 如何對應到 file_uuid 與幀區間" + - "chunk 的搜尋用途與向量儲存方式" + - "chunk 與 pre_chunk 的雙層資料架構" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "VECTOR_SPEC_V1.0.0.md" + - "PROCESSORS/ASR_V1.0.0.md" + - "PROCESSORS/CUT_V1.0.0.md" + - "PROCESSORS/FACE_V1.0.0.md" +--- + +# Chunk 定義 V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-01 | +| 文件版本 | V1.0 | + +## 名詞定義 + +| 名詞 | 定義 | 範例 | +|------|------|------| +| **Processor JSON** | Processor 腳本的第一層產出檔案 | `384b0ff44aaaa1f14cb2cd63b3fea966.face.json` | +| **pre_chunk** | 從 Processor JSON 匯入 DB 的最低層元件(`pre_chunks` 表) | 單幀 face detection、單句 ASR text | +| **chunk** | 可搜尋單位(`chunks` 表),由 Rule 組合 pre_chunks 產出,`start_frame` ~ `end_frame` 定義區間 | sentence chunk, visual chunk, scene chunk | +| **parent_chunk** | chunk 的一種,包含 `child_chunk_ids`,其區間涵蓋多個 child_chunks,由 Summary Agent 產出統整描述 | scene chunk, story chunk | +| **child_chunk** | chunk 的一種,被 parent_chunk 參照為子元素 | sentence chunk, visual chunk | + +--- + +## Chunk 結構 + +```rust +Chunk { + uuid: String, // file_uuid (32-char hex) + chunk_id: String, // "{uuid}_{chunk_index}" + chunk_index: u32, // 0-based 序號 + chunk_type: ChunkType, // Sentence | Cut | Visual | Trace | Story + rule: ChunkRule, // Rule1 (直接組合) | Rule2 (聚合) + start_frame: i64, // 起始幀(0-based,唯一時間參考) + end_frame: i64, // 結束幀(exclusive) + fps: f64, // 該區間的 fps + content: JSON, // 主要內容 + text_content: Option, // 純文字內容(供搜尋用) + metadata: Option, // speaker, face_ids, yolo_objects 等 + pre_chunk_ids: Vec, // 來源 pre_chunks(原始元件追溯) + parent_chunk_id: Option, // 父 chunk ID(如存在) + child_chunk_ids: Vec, // 子 chunk IDs(如為 parent_chunk) + vector_id: Option, // 向量儲存參考 +} +``` + +--- + +## ChunkType + +| 類型 | 說明 | 範例 | +|------|------|------| +| `Sentence` | ASR 句子 chunk | 一句話對應一個 chunk | +| `Cut` | 場景切換 chunk | PySceneDetect 輸出的場景邊界 | +| `Visual` | 視覺物件 chunk | YOLO/OCR/Face/Pose 聚合 | +| `Trace` | 追蹤 chunk | face_trace / yolo_trace | +| `Story` | 敘事 chunk(parent) | 5W1H Agent 產出的統整描述 | + +--- + +## Chunk 特性 + +- **區間定義**: `start_frame` / `end_frame`(frames 為唯一時間座標) +- **可重疊**: 不同類型的 chunk 可以覆蓋相同區間 +- **可不連續**: chunk 之間不需要連續 +- **巢狀**: parent_chunk 包含 child_chunk_ids,子區間不須填滿父區間 +- **單幀 chunk**: `start_frame == end_frame`(如 frame-level detection) + +--- + +## 資料流 + +``` +Processor JSON ({file_uuid}.{type}.json) + │ + ▼ 匯入 +pre_chunks (原始元件, start_frame / end_frame / data) + │ + ▼ Rule 組合 (Rule1 / Rule2 / Rule3) +chunks (可搜尋單位) + ├── child_chunk (基礎搜尋單位) + │ └── 5W1H: 該 chunk 的摘要描述(3~5 句話) + │ + └── parent_chunk (較大區間, Summary Agent 產出) + ├── child_chunk_ids: [內含的所有 child_chunks] + └── summary: (child_chunks 的 5W1H + parent_chunk 補充描述) + via Summary Agent (如 5W1H Agent) + summary 為 3~5 句話,統整區間內所有內容 + 用於 embedding 成向量,確保搜尋時涵蓋足夠語意 +``` + +--- + +## 與 pre_chunk 的關係 + +| 層級 | 產生方式 | 目的 | +|------|----------|------| +| pre_chunk | 直接從 Processor JSON 匯入 | 保留原始資料,供 Rule 加工 | +| chunk | Rule 組合 pre_chunks | 成為可搜尋單位 | +| child_chunk | chunk 的一種 | 基礎搜尋目標 | +| parent_chunk | Summary Agent 產出 | 補足單一 child_chunk 資訊量不足 | + +--- + +## 範例 + +### Sentence Chunk (child_chunk) + +```json +{ + "chunk_id": "384b0ff44aaaa1f14cb2cd63b3fea966_42", + "chunk_index": 42, + "chunk_type": "sentence", + "rule": "rule_1", + "start_frame": 1260, + "end_frame": 1350, + "fps": 29.97, + "content": { + "text": "今天天氣很好,我們決定去公園走走。", + "speaker": "SPEAKER_00" + }, + "text_content": "今天天氣很好,我們決定去公園走走。", + "metadata": { + "speaker": "SPEAKER_00", + "face_ids": ["face_42", "face_43"], + "5w1h": "講者 SPEAKER_00 在室內提到今天天氣很好。他建議大家一起到公園散步。同伴們同意這個提議。大家開始準備出發。整個對話顯示團隊氣氛融洽。" + }, + "pre_chunk_ids": [101, 102, 103], + "parent_chunk_id": "384b0ff44aaaa1f14cb2cd63b3fea966_scene_3" +} +``` + +### Scene Chunk (parent_chunk) + +```json +{ + "chunk_id": "384b0ff44aaaa1f14cb2cd63b3fea966_scene_3", + "chunk_index": 3, + "chunk_type": "cut", + "rule": "rule_3", + "start_frame": 1200, + "end_frame": 1800, + "fps": 29.97, + "content": { + "scene_number": 3, + "scene_type": "dialogue" + }, + "text_content": "今天天氣很好,我們決定去公園走走。之後我們在公園裡散步,看到很多花。", + "metadata": { + "summary": "講者和同伴在室內討論天氣狀況,提到今天陽光明媚。他們決定到附近的公園散步享受好天氣。抵達公園後,他們沿著步道行走,觀察到許多盛開的花朵。其中一人用手機拍攝了花朵的照片。整個對話氣氛輕鬆愉快。" + }, + "pre_chunk_ids": [98, 99, 100], + "child_chunk_ids": [ + "384b0ff44aaaa1f14cb2cd63b3fea966_42", + "384b0ff44aaaa1f14cb2cd63b3fea966_43", + "384b0ff44aaaa1f14cb2cd63b3fea966_44" + ] +} +``` + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-01 | 初始版本 | OpenCode | deepseek-chat | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/MOMENTRY_CORE_API_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/MOMENTRY_CORE_API_V1.0.0.md new file mode 100644 index 0000000..94118a0 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/MOMENTRY_CORE_API_V1.0.0.md @@ -0,0 +1,240 @@ +--- +document_type: "reference_doc" +service: "MOMENTRY_CORE" +title: "Momentry Core V1.0.0 API 參考文件" +date: "2026-04-30" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "api" + - "reference" + - "v1.0.0" + - "marcom" + - "restful" + - "endpoint" + - "file-centric" +ai_query_hints: + - "Momentry Core V1.0.0 API 參考文件的主要內容是什麼?" + - "查詢 V1.0.0 API 列表包含哪些端點?" + - "Marcom 團隊如何使用 API Reference?" + - "API 的 Progressive Workflow 範例" + - "Momentry API 的檔案管理與搜尋功能" + - "API 的 Progressive Workflow 操作步驟" + - "API 的檔案管理與搜尋功能" +related_documents: + - "STANDARDS/DOCS_STANDARD.md" + - "DEV_API_V1.0/API_REFERENCE_v1.0.0.md" + - "API_DICTIONARY_V1.0.0.md" + - "API_USAGE_DEMO_V1.0.0.md" + - "PRODUCTION_VERIFICATION_V1.0.0.md" +--- + +# Momentry Core V1.0.0 API 參考文件 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-04-30 | +| 文件版本 | V1.0 | + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-04-30 | 創建 V1.0.0 API 列表,移除過時端點 | OpenCode | OpenCode | + +--- + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| file_uuid | 媒體檔案(影片/圖片/音訊)的唯一 32 碼 SHA256 識別碼 | +| identity_uuid | 全域人物身份識別碼,跨檔案關聯同一人物 | +| Chunk | 可搜尋單位,由 Rule 組合 pre_chunks 產出 | +| Snapshot | 臉部或場景的快取快照,需 migrate 後供 UI 使用 | +| API Key | 認證方式,透過 Header `X-API-Key` 傳遞 | + +## 概述 + +本文檔定義 Momentry Core **V1.0.0** 版本供 **Marcom 團隊** 使用的 API 列表與開發範例。此列表已移除舊版、冗餘及內部使用的端點,確保前端開發使用的是標準且穩定的介面。 + +--- + +## 🚀 設計原則 (Design Principles) + +### 1. Clear API (介面清晰化) +* **去蕪存菁**: 嚴格區分 **Public** (公開) 與 **Internal** (內部) 端點。舊版冗餘路徑(如 `/api/v1/videos`, `/api/v1/probe`)已全面移除或合併。 +* **標準化回應**: 所有列表型 API 均回傳統一結構 `{ "success": true, "data": [...], "total": N }`。 +* **命名規範**: 採用 RESTful 風格,資源以複數名詞或明確動作命名(如 `files`, `identities`)。 + +### 2. File-Centric (以檔案為核心) +* **唯一識別**: 每個媒體檔案(影片/圖片/音訊)均由 **32 碼 UUID** (`file_uuid`) 唯一標識。 +* **生命週期**: `File` 是所有資料的根節點。所有的 `Chunk` (片段), `Snapshot` (快照), `Jobs` (任務) 皆隸屬於特定的 `File`。 +* **操作模式**: 前端應優先呼叫 `GET /api/v1/files` 取得清單,再透過 `POST /api/v1/files/:uuid/snapshots/migrate` 載入詳細資源。 + +### 3. Global Identity (全域身份識別) +* **跨檔案關聯**: `Identity` 代表一個獨立的人物或角色,不受單一檔案限制。 +* **綁定機制 (Binding)**: 透過 `POST /api/v1/identities/bind`,我們可以將多個檔案中偵測到的臉部 (`face`) 或聲音 (`speaker`) 聚合到同一個 `Identity` 下。 +* **資料聚合**: 查詢某個 `Identity` 即可看到該人物在所有歷史檔案中的軌跡 (`/api/v1/identities/:uuid/files`)。 + +--- + +## 當前狀態 + +| 項目 | 狀態 | +|------|------| +| API 版本 | V1.0.0 | +| 開發環境 Port | 3003 | +| 正式環境 Port | 3002 | +| 認證方式 | Header `X-API-Key` | + +--- + +## 1. API Dictionary (端點清單) + +### 1.1 系統與認證 (System & Auth) +| Method | Endpoint | 說明 | +| :--- | :--- | :--- | +| `GET` | `/health` | 基本健康檢查 | +| `POST` | `/api/v1/auth/login` | 登入以取得 API Key | + +### 1.2 檔案管理 (File Management) +*主要入口:瀏覽與管理資產* +| Method | Endpoint | 說明 | +| :--- | :--- | :--- | +| `GET` | `/api/v1/files` | **列出所有檔案** (支援分頁) | +| `GET` | `/api/v1/files/:uuid` | 取得檔案詳情 (包含 probe_json, metadata) | +| `POST` | `/api/v1/files/register` | 從磁碟註冊新檔案 | +| `DELETE`| `/api/v1/videos/:uuid` | **刪除影片** 及其關聯資料 | + +### 1.3 搜尋與檢索 (Search & Retrieval) +| Method | Endpoint | 說明 | +| :--- | :--- | :--- | +| `POST` | `/api/v1/search` | **語意搜尋** (Text-based, 使用 Embedding) | +| `POST` | `/api/v1/search/hybrid` | 混合搜尋 (Vector + BM25 關鍵字) | +| `POST` | `/api/v1/search/visual` | 視覺搜尋 (尋找物件/形狀) | +| `POST` | `/api/v1/search/visual/class`| 依物件類別過濾 (如 "person", "car") | + +### 1.4 身份與人物管理 (Identity Management) +*跨影片的人物/角色關聯* +| Method | Endpoint | 說明 | +| :--- | :--- | :--- | +| `GET` | `/api/v1/identities` | **列出所有身份** (人物/角色) | +| `GET` | `/api/v1/identities/:uuid` | 取得身份詳情 (名稱, 品質, 來源) | +| `GET` | `/api/v1/identities/:uuid/files`| 列出該身份出現的所有檔案 | +| `GET` | `/api/v1/identities/:uuid/chunks`| 列出特定的時間軸片段 (Chunks) | +| `POST` | `/api/v1/identities/bind` | 將臉部/聲音訊號綁定至身份 | + +### 1.5 臉部與快照 (Face & Snapshots) +| Method | Endpoint | 說明 | +| :--- | :--- | :--- | +| `GET` | `/api/v1/face/list` | 列出特定影片中偵測到的所有臉部 | +| `POST` | `/api/v1/face/recognize` | 對指定影片觸發臉部辨識流程 | +| `GET` | `/api/v1/files/:uuid/snapshots` | 檢查快照快取狀態 (Hot/Cold) | +| `POST` | `/api/v1/files/:uuid/snapshots/migrate`| **載入快照至記憶體** (UI 顯示快圖前需呼叫) | + +### 1.6 任務與代理人 (Jobs & Agents) +| Method | Endpoint | 說明 | +| :--- | :--- | :--- | +| `GET` | `/api/v1/progress/:uuid` | 檢查即時處理進度 | +| `POST` | `/api/v1/assets/:uuid/process` | 觸發處理流程 (ASR, YOLO, 等) | +| `POST` | `/api/v1/agents/identity/analyze` | AI Agent: 分析身份重複情況 | + +--- + +## 2. Progressive Workflow Examples (操作範例) + +此章節展示典型的使用者操作情境:**尋找影片 → 處理 → 搜尋 → 人物綁定**。 + +### Phase 1: 瀏覽與檢視 +*使用者瀏覽檔案庫以尋找目標影片。* + +**Step 1: 登入** +```bash +curl -s -X POST http://localhost:3003/api/v1/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username": "demo", "password": "demo"}' +# 回應範例: { "api_key": "muser_test_001..." } +``` + +**Step 2: 列出檔案** +```bash +curl -s "http://localhost:3003/api/v1/files?page=1&page_size=5" \ + -H "X-API-Key: muser_test_001" +# 回應範例: { "success": true, "data": [ { "file_uuid": "...", "file_name": "Demo.mp4" ... } ] } +``` + +### Phase 2: 處理與監控 +*使用者決定分析該影片的臉部與語音內容。* + +**Step 3: 觸發處理** +```bash +curl -s -X POST "http://localhost:3003/api/v1/assets/{file_uuid}/process" \ + -H "X-API-Key: muser_test_001" \ + -H "Content-Type: application/json" \ + -d '{}' +# 啟動 ASR, 臉部偵測等處理器 +``` + +**Step 4: 檢查進度** +```bash +curl -s "http://localhost:3003/api/v1/progress/{file_uuid}" \ + -H "X-API-Key: muser_test_001" +# 回應範例: { "overall_progress": 50, "processors": [...] } +``` + +### Phase 3: 搜尋內容 +*使用者搜尋影片中的特定內容。* + +**Step 5: 語意搜尋 (文字描述)** +```bash +curl -s -X POST "http://localhost:3003/api/v1/search" \ + -H "X-API-Key: muser_test_001" \ + -H "Content-Type: application/json" \ + -d '{"query": "一個人拿著紅色的信封", "uuid": "{file_uuid}"}' +# 回應範例: 符合文字描述的片段列表 +``` + +### Phase 4: 身份管理 (GUI 開發重點) +*使用者發現了一張臉,確認該人物,並將其綁定到已知身份。* + +**Step 6: 載入快照 (Migrate Snapshots)** +*在 GUI 渲染大量臉部縮圖前,必須先將快取載入記憶體以加速讀取。* +```bash +curl -s -X POST "http://localhost:3003/api/v1/files/{file_uuid}/snapshots/migrate" \ + -H "X-API-Key: muser_test_001" \ + -H "Content-Type: application/json" \ + -d '{"parent_uuid": "{file_uuid}"}' +# 回應範例: { "success": true, "migrated_types": ["faces", ...] } +``` + +**Step 7: 綁定臉部到身份 (Bind Face)** +*假設偵測到臉部 `face_123`,欲綁定至身份 `uuid_identity`。* +```bash +curl -s -X POST "http://localhost:3003/api/v1/identities/bind" \ + -H "X-API-Key: muser_test_001" \ + -H "Content-Type: application/json" \ + -d '{ + "identity_id": null, + "name": "Cary Grant", + "binding_type": "face", + "binding_value": "face_123" + }' +``` + +--- + +## 3. 棄用聲明 (Deprecation Notices) + +以下端點已在 V1.0.0 移除或棄用,**請勿**在新的開發中使用。 + +* `GET /api/v1/videos` (列表) → 已取代為 `GET /api/v1/files` +* `POST /api/v1/register` → 已取代為 `POST /api/v1/files/register` +* `POST /api/v1/probe` → 已取代為 `GET /api/v1/files/:uuid` +* `GET /api/v1/people/...` → 已合併為 `GET /api/v1/identities/...` +* `/api/v1/n8n/search/...` → 僅供內部 n8n 工作流使用 (請使用標準 `/api/v1/search`) diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/ASRX_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/ASRX_V1.0.0.md new file mode 100644 index 0000000..c46c5bf --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/ASRX_V1.0.0.md @@ -0,0 +1,102 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "ASRX Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "asrx" + - "speaker-diarization" + - "speechbrain" + - "v1.0.0" +ai_query_hints: + - "ASRX 使用 SpeechBrain ECAPA-TDNN 進行說話者日誌化" + - "ASRX 從 Pyannote 遷移至自定義 SpeechBrain,快 6 倍" + - "ASRX 不需要 HuggingFace token(相較 Pyannote)" + - "ASRX Charade 6879s 長片輸出 1118 segments, 8 說話人" + - "ASRX 依賴 ASR processor 的轉錄結果" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../ASR_V1.0.0.md" + - "../CUT_V1.0.0.md" + - "../VOICE_EMBEDDING_FLOW_V1.0.0.md" + - "../VECTOR_SPEC_V1.0.0.md" +--- + +# ASRX Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ⚠️ 80% | **模型**: SpeechBrain ECAPA-TDNN | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| ASRX | 進階語音處理,包含說話者日誌化(Speaker Diarization) | +| Speaker Diarization | 說話者日誌化,區分「誰在什麼時候說話」 | +| ECAPA-TDNN | SpeechBrain 提供的說話人辨識模型,產出 192-D embedding | +| VAD | Voice Activity Detection,語音活動檢測(使用 Silero) | +| Spectral Clustering | 頻譜聚類,將 embedding 分群以區分不同說話人 | + +--- + +## 選型過程 + +| 指標 | Pyannote-based(原始) | Custom SpeechBrain(新) | +|------|----------------------|------------------------| +| Pipeline | VAD → Whisper → Align → Diarize | VAD (Silero) → ECAPA-TDNN → Spectral Clustering | +| 處理時間 | 4.79s(輸出為空) | **1.66s** (96.25x) | +| 比 Pyannote 快 | 基準 | **6x 更快** | +| HuggingFace token | ✅ **需要** | ❌ **不需要** | +| 重疊語音 | ✅ 支援 | ❌ 不支援 | + +**決策**: 因 pyannote.audio 需要 HuggingFace token、import 錯誤頻繁、輸出為空,已改為自定義 SpeechBrain 實作。 + +--- + +## 處理時間分解(Custom SpeechBrain) + +| 步驟 | 時間 | 佔比 | +|------|------|------| +| VAD (Silero) | 0.41s | 24.7% | +| Speaker embedding (ECAPA-TDNN) | 1.15s | 69.3% | +| Spectral clustering | 0.10s | 6.0% | + +--- + +## Charade 長片(6879s) + +| 指標 | 值 | +|------|-----| +| Segments | 1118 | +| 說話人數 | 8 | +| 匹配率 | 99.82% | + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.8 | +| 記憶體 | 2048 MB | +| GPU | 不使用 | +| 依賴 | ASR | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/ASR_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/ASR_V1.0.0.md new file mode 100644 index 0000000..098f0f0 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/ASR_V1.0.0.md @@ -0,0 +1,117 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "ASR Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "asr" + - "whisper" + - "speech-recognition" + - "v1.0.0" +ai_query_hints: + - "ASR 使用 faster-whisper/small 模型及 INT8 CPU 量化" + - "ASR 以 CUT 場景邊界為基礎分段處理長片" + - "ASR 每個 segment 記錄 scene_number 對應 CUT 場景序號" + - "ASR 處理 159.6s 影片約 12.68s,即時倍率 12.6x" + - "ASR 依賴 CUT processor 的場景邊界輸出" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../CUT_V1.0.0.md" + - "../ASRX_V1.0.0.md" + - "../STORY_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" +--- + +# ASR Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: faster-whisper/small | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| ASR | Automatic Speech Recognition,自動語音辨識 | +| faster-whisper | 基於 OpenAI Whisper 的優化版本,支援 INT8 CPU 量化 | +| segment | Whisper 輸出的語音片段,包含 start/end/time/text | +| scene_number | CUT 場景序號(1-based),標示 segment 所屬場景 | +| real-time factor | 即時倍率,處理時間與影片時長的比值 | + +--- + +## 選型過程 + +| 模型 | 參數 | 大小 | English WER | Chinese CER | 速度 | +|------|------|------|-------------|-------------|------| +| tiny | 39M | ~40MB | 9.5% | 15.0% | ~1x RT | +| base | 74M | ~75MB | 7.3% | 11.2% | ~1.5x RT | +| **small** | **244M** | **~250MB** | **5.5%** | **8.4%** | **~2x RT** | +| medium | 769M | ~800MB | 4.3% | 6.4% | ~3x RT | +| large-v3 | 1.5B | ~1.5GB | 3.5% | 4.9% | ~5x RT | + +**決策**: small 在準確率與速度間取得最佳平衡,經實驗驗證最少要使用 small 才能較好處理多語種及台灣腔國語。 + +--- + +## 效能實測(ExaSAN 159.6s 影片) + +| 指標 | 值 | +|------|-----| +| 處理時間 | 12.68s | +| 即時倍率 | 12.6x | +| 輸出 | 78~79 segments, ~15KB | + +--- + +## 長片分段處理 + +對於長片(如 Charade 6879s),ASR 以 CUT processor 產出的場景邊界為基礎分段處理: + +1. CUT 先產出 `{file_uuid}.cut.json`(含 `scenes[]`,每個有 `start_time`/`end_time`) +2. ASR 讀取 CUT JSON,依 `scene_number` 順序對每個場景萃取音訊 +3. 每個場景分別用 Whisper 轉錄 +4. 合併結果,每個 segment 記錄所屬的 `scene_number` + +每個 segment 的 JSON 格式: +```json +{ + "start": 12.5, + "end": 15.3, + "text": "Hello world", + "scene_number": 42 +} +``` + +`scene_number` 是在該 `file_uuid` 下的 CUT 場景序號(1-based)。 + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +--- + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 1.0(一個完整核心) | +| 記憶體 | 2048 MB(長片因分段處理,實際低於此值) | +| GPU | 不使用(INT8 CPU 量化) | +| 依賴 | 無 | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/CAPTION_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/CAPTION_V1.0.0.md new file mode 100644 index 0000000..d2f51a1 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/CAPTION_V1.0.0.md @@ -0,0 +1,80 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Caption Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "caption" + - "moondream2" + - "image-captioning" + - "v1.0.0" +ai_query_hints: + - "Caption 使用 Moondream2 進行本地圖像描述生成" + - "Caption 已從 GPT-4o 雲端 API 本地化為 Moondream2" + - "Caption Moondream2 模型約 1.8GB,完全本地執行" + - "Caption 處理速度約 5s/frame" + - "Caption 備援方案為 YOLO + OCR + Scene 串接" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../SCENE_V1.0.0.md" + - "../STORY_V1.0.0.md" + - "../YOLO_V1.0.0.md" + - "../OCR_V1.0.0.md" +--- + +# Caption Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: Moondream2 | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Caption | 圖像描述生成,為每個場景產出文字敘述 | +| Moondream2 | HuggingFace transformers 提供的本地圖像描述模型 | +| GPT-4o | (已移除)先前使用的雲端 API 方案 | +| local deployment | 完全本地執行,不依賴任何雲端 API | +| fallback | 備援方案:YOLO + OCR + Scene 結果串接 | + +--- + +## 選型過程 + +| 指標 | GPT-4o(已移除) | Moondream2(新) | +|------|-----------------|-----------------| +| 速度 | 2s/frame | 5s/frame | +| 品質 | 高 | 良好 | +| 依賴 | ✅ 雲端 API Key | ❌ 完全本地 | + +**決策**: 已從 GPT-4o 雲端 API 本地化為 Moondream2(HuggingFace transformers, ~1.8GB)。備援方案為 YOLO + OCR + Scene 結果串接。 + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | - | +| 記憶體 | ~1.8 GB(模型載入後) | +| GPU | 不使用 | +| 依賴 | Scene | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/CUT_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/CUT_V1.0.0.md new file mode 100644 index 0000000..c17e3af --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/CUT_V1.0.0.md @@ -0,0 +1,135 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "CUT Processor (Scene Cut Detection) V1.0.0" +date: "2026-05-03" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "cut" + - "scene-detection" + - "pyscenedetect" + - "v1.0.0" +ai_query_hints: + - "CUT 場景檢測的輸出結構與檔案後綴規則" + - "CUT 的 cut_count 與 cut_max_duration 用途" + - "長影片動態調度如何將 Face 移到 ASR 前" + - "CUT 與 Scene 的執行階段(register 同步)" + - "CUT 輸出 JSON 結構(start_time/end_time)" +related_documents: + - "PROCESSORS/SCENE_V1.0.0.md" + - "PROCESSOR_SELECTION_V1.0.0.md" + - "PROCESSORS/ASR_V1.0.0.md" + - "PROCESSORS/FACE_V1.0.0.md" + - "CHUNK_DEFINITION_V1.0.0.md" +--- + +# CUT Processor (Scene Cut Detection) V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-03 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: PySceneDetect (ContentDetector) | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| CUT | 場景切換檢測,使用 PySceneDetect ContentDetector | +| scene boundary | 場景邊界,以 start_time/end_time 定義 | +| cut_count | 場景數量,register 階段寫入 DB | +| cut_max_duration | 最長場景秒數,用於長影片動態調度 | +| ContentDetector | 基於幀差異的場景切換檢測演算法 | + +--- + +## 選型過程 + +無 ML 模型,基於幀差異的場景切換檢測。門檻值 threshold=27 為實驗最佳值。 + +--- + +## 輸出結構 + +CUT 產出 `{file_uuid}.cut.json`,結構如下: + +```json +{ + "scenes": [ + { "start_time": 0.0, "end_time": 120.5 }, + { "start_time": 120.5, "end_time": 245.0 } + ] +} +``` + +--- + +## 執行階段 + +CUT 在 **register 階段同步執行**(`register_single_file`),不做 worker pipeline 排程。完成後寫入 DB 欄位: +- `cut_done: bool` — 是否完成 +- `cut_count: i32` — 場景數量 +- `cut_max_duration: f64` — 最長場景秒數 + +--- + +## 狀態後綴 + +| 後綴 | 意義 | 行為 | +|------|------|------| +| `.cut.json` | 完成 | 直接載入使用 | +| `.cut.json.tmp` | 執行中 | 跳過、等待 | +| `.cut.json.err` | 失敗 | 跳過、不重試 | + +--- + +## 長影片動態調度 + +當 `cut_count ≤ 3 && cut_max_duration > 600s`(如會議紀錄長鏡頭),Worker 自動調整 pipeline 順序: +- **Face 移到 ASR 前面**,先用 face detection 找出人物進出點 +- 後續可用 face 分佈切分長 scene,輔助 ASR 分段 + +--- + +## 效能實測 + +**ExaSAN 159.6s 影片**: +| 指標 | 值 | +|------|-----| +| 處理時間 | 0.08s | +| 即時倍率 | 2036.5x(最快的 processor) | +| 輸出 | 52 bytes | + +**Charade 長片(6879s, 412343 幀)**: +| 指標 | 值 | +|------|-----| +| 場景數 | 1331 | +| 輸出 | 217 KB | + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-03 | 初始版本 | OpenCode | deepseek-chat | + +--- + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.5 | +| 記憶體 | 512 MB | +| GPU | 不使用 | +| 依賴 | 無 | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/FACE_EMBEDDING_FLOW_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/FACE_EMBEDDING_FLOW_V1.0.0.md new file mode 100644 index 0000000..a4e1b25 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/FACE_EMBEDDING_FLOW_V1.0.0.md @@ -0,0 +1,133 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Face Embedding 產出流程 V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "momentry" + - "core" + - "face" + - "embedding" + - "qdrant" + - "v1.0.0" +ai_query_hints: + - "Face Embedding 的完整處理流程(Frame → InsightFace → Qdrant)" + - "Face processor 的輸出結構與 embedding 欄位說明" + - "Worker store_face_chunks 與 store_face_embeddings_to_qdrant 的步驟" + - "Qdrant face collection 的 payload 結構與點位 ID 規則" + - "Face embedding 的 512-D ArcFace w600k_r50 向量規格" + - "Face embedding 使用 Cosine 距離計算" + - "InsightFace buffalo_l 的資源預估與 GPU 加速資訊" + - "face_detections 表與 Qdrant 的資料同步方式" +related_documents: + - "../VECTOR_SPEC_V1.0.0.md" + - "../PROCESSORS/FACE_V1.0.0.md" + - "../PROCESSOR_SELECTION_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" + - "../MOMENTRY_CORE_API_V1.0.0.md" +--- + +# Face Embedding 產出流程 V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Face Embedding | 人臉向量嵌入,由 InsightFace ArcFace 產出 512-D 向量 | +| SCRFD-10G | InsightFace 的人臉檢測模型 | +| ArcFace w600k_r50 | InsightFace 的人臉辨識模型,產出 512-D embedding | +| point_id | Qdrant 中向量的唯一 ID,使用幀編號 (frame number) | +| Cosine distance | 餘弦距離,用於向量相似度計算 | +| payload | Qdrant 向量的附帶 metadata 欄位 | + +## 處理流程 + +``` +1. Video Frame (取樣) + │ + ▼ +2. Face Processor (face_processor.py) + ├── InsightFace buffalo_l + │ ├── SCRFD-10G 人臉檢測 + │ ├── ArcFace w600k_r50 512-D embedding + │ ├── 年齡/性別預測 + │ └── 2D106 landmarks + │ + ├── 輸出: job_{id}_face_{ts}.json → {file_uuid}.face.json + │ └── FaceResult { frame_count, fps, frames: [FaceFrame] } + │ + ▼ +3. Worker store_face_chunks() + ├── 解析 FaceResult + ├── 寫入 pre_chunks 表 (file_uuid, processor_type='face', data) + └── 寫入 face_detections 表 + │ + ▼ +4. Worker store_face_embeddings_to_qdrant() + ├── 對每個 face frame 的每個 face + │ └── 若有 embedding (512-D): + │ ├── point_id = frame number (u64) + │ ├── vector = 512-D float array + │ └── payload (見下方) + └── 寫入 Qdrant collection `momentry_dev_face` +``` + +## Qdrant Payload 結構 + +```json +{ + "file_uuid": "dd61fda85fee441fdd00ab5528213ff7", + "face_id": null, + "frame": 15, + "timestamp": 0.68, + "x": 328, + "y": 88, + "width": 63, + "height": 75, + "confidence": 0.83 +} +``` + +| 欄位 | 型別 | 說明 | +|------|------|------| +| `file_uuid` | string | 來源影片識別碼 | +| `face_id` | string|null | 臉部追蹤 ID(尚未分配時為 null) | +| `frame` | integer | 幀編號 | +| `timestamp` | float | 時間戳(秒) | +| `x, y, width, height` | integer | 人臉邊界框 | +| `confidence` | float | 檢測信心度 (0~1) | + +## Vector 規格 + +| 屬性 | 值 | +|------|-----| +| 模型 | InsightFace ArcFace w600k_r50 | +| 維度 | 512 | +| 距離計算 | Cosine | +| 歸一化 | 否 (raw output) | + +## 來源 Processor 資源預估 + +| 資源 | 值 | +|------|-----| +| 模型 | InsightFace buffalo_l (~150MB) | +| CPU | 0.6 | +| 記憶體 | 1536 MB | +| GPU | 支援(CoreML 50-80 FPS, CUDA 80-120 FPS) | +| 處理速度 | 130.5x real-time (M4 Mac Mini) | + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/FACE_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/FACE_V1.0.0.md new file mode 100644 index 0000000..8dc02e7 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/FACE_V1.0.0.md @@ -0,0 +1,104 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Face Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "face" + - "insightface" + - "face-detection" + - "v1.0.0" +ai_query_hints: + - "Face 使用 InsightFace buffalo_l 進行人臉偵測與辨識" + - "Face 在 ExaSAN 159.6s 影片上僅需 1.22s,即時倍率 130.5x" + - "Face 支援 GPU 加速,CoreML 可達 50~80 FPS" + - "Face 輸出 512-D embedding 用於比對" + - "Face 不再使用 Haar Cascade fallback,強制使用 InsightFace" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../FACE_EMBEDDING_FLOW_V1.0.0.md" + - "../CUT_V1.0.0.md" + - "../VECTOR_SPEC_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" +--- + +# Face Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: InsightFace buffalo_l | **GPU**: 是 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Face Detection | 人臉偵測,使用 InsightFace SCRFD-10G | +| Face Recognition | 人臉辨識,使用 ArcFace w600k_r50 產出 512-D embedding | +| embedding | 向量嵌入,用於人臉比對與搜尋 | +| CoreML | Apple Silicon 上的 GPU 加速方案 | +| LFW | Labeled Faces in the Wild,人臉辨識基準資料集 | + +--- + +## 選型過程 + +| 模型 | 類型 | 大小 | 檢測率 | 辨識率 | Embedding | +|------|------|------|--------|--------|-----------| +| **InsightFace Buffalo_l** | **完整套件** | **~150MB** | **97.3% mAP** | **99.77% (LFW)** | **512-D ✅** | +| MediaPipe BlazeFace | 輕量檢測 | 1~2MB | 95.2% mAP | 無 | ❌ | +| OpenCV Haar Cascade | 傳統 ML | 900KB | 70~85% | 無 | ❌ | + +**關鍵決策**: 舊版 Haar Cascade fallback 會產生全鏈路失敗(0 embeddings),已改為強制使用 InsightFace。 + +--- + +## 效能實測(ExaSAN 159.6s 影片) + +| 指標 | 值 | +|------|-----| +| 處理時間 | 1.22s | +| 即時倍率 | 130.5x | +| 輸出 | 49 frames, 67 faces | + +--- + +## GPU 加速 + +| 平台 | FPS | +|------|-----| +| CoreML (Apple Silicon) | 50~80 FPS | +| CUDA (NVIDIA) | 80~120 FPS | +| CPU | 15~20 FPS | + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +--- + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.6 | +| 記憶體 | 1536 MB | +| GPU | 支援(`uses_gpu = true`) | +| 依賴 | 無 | + +--- diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/OCR_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/OCR_V1.0.0.md new file mode 100644 index 0000000..00d208a --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/OCR_V1.0.0.md @@ -0,0 +1,87 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "OCR Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "ocr" + - "paddleocr" + - "optical-character-recognition" + - "v1.0.0" +ai_query_hints: + - "OCR 使用 PaddleOCR PP-OCRv4 模型支援 80+ 語言" + - "OCR 處理 159.6s 影片全幀約 36.87s,即時倍率 4.3x" + - "OCR 輸出 102 frames, 234 texts, 65KB" + - "OCR 不使用 GPU,CPU 使用率 0.8" + - "OCR 精度 > 95%,支援繁體中文" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../YOLO_V1.0.0.md" + - "../CAPTION_V1.0.0.md" + - "../VISUAL_CHUNK_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" +--- + +# OCR Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: PaddleOCR PP-OCRv4 | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| OCR | Optical Character Recognition,光學字元辨識 | +| PaddleOCR | 百度開發的 OCR 引擎,PP-OCRv4 為最新版本 | +| PP-OCRv4 | PaddleOCR 第四代模型,支援 80+ 語言 | +| real-time factor | 即時倍率,處理時間與影片時長的比值 | +| full-frame processing | 全幀處理模式,對影片每一幀進行 OCR | + +--- + +## 選型過程 + +選擇 PaddleOCR 原因: +- 支援 80+ 語言(含繁體中文) +- 精度 > 95% +- EasyOCR 經測試不如 PaddleOCR + +--- + +## 效能實測(ExaSAN 159.6s 影片, 全幀處理) + +| 指標 | 值 | +|------|-----| +| 處理時間 | 36.87s | +| 即時倍率 | 4.3x | +| 輸出 | 102 frames, 234 texts, 65KB | + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.8 | +| 記憶體 | 1024 MB | +| GPU | 不使用 | +| 依賴 | 無 | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/POSE_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/POSE_V1.0.0.md new file mode 100644 index 0000000..9e76a0d --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/POSE_V1.0.0.md @@ -0,0 +1,84 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Pose Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "pose" + - "mediapipe" + - "pose-estimation" + - "v1.0.0" +ai_query_hints: + - "Pose 使用 MediaPipe Pose (pose_landmarker_heavy, 33 keypoints)" + - "Pose 處理 159.6s 影片全幀約 65.87s,即時倍率 2.4x" + - "Pose 輸出 1853 frames, 2341 persons, 603KB" + - "Pose 支援 GPU 加速(uses_gpu = true)" + - "Pose 與 YOLO 同為處理瓶頸之一" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../YOLO_V1.0.0.md" + - "../FACE_V1.0.0.md" + - "../CUT_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" +--- + +# Pose Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: MediaPipe Pose | **GPU**: 是 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Pose Estimation | 姿態估計,偵測人體關鍵點位置 | +| MediaPipe | Google 開發的跨平台 ML 解決方案 | +| keypoint | 關鍵點,pose_landmarker_heavy 輸出 33 個關鍵點 | +| landmarker_heavy | MediaPipe 的精確模式,準確度最高但速度較慢 | +| bottleneck | 處理瓶頸,Pose 與 YOLO 同為最耗時的 processor | + +--- + +## 選型過程 + +使用 MediaPipe Pose(pose_landmarker_heavy, 33 keypoints)。 + +--- + +## 效能實測(ExaSAN 159.6s 影片, 全幀處理) + +| 指標 | 值 | +|------|-----| +| 處理時間 | 65.87s | +| 即時倍率 | 2.4x(瓶頸之一,與 YOLO 相當) | +| 輸出 | 1853 frames, 2341 persons, 603KB | + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.4 | +| 記憶體 | 1024 MB | +| GPU | 支援(`uses_gpu = true`) | +| 依賴 | 無 | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/SCENE_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/SCENE_V1.0.0.md new file mode 100644 index 0000000..3cbaa6e --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/SCENE_V1.0.0.md @@ -0,0 +1,95 @@ +--- +document_type: "processor-spec" +service: "MOMENTRY_CORE" +title: "Scene Processor (Scene Classification) V1.0.0" +date: "2026-05-03" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "scene" + - "places365" + - "scene-classification" + - "v1.0.0" +ai_query_hints: + - "Scene 分類的模型選型與效能實測" + - "Scene 的執行階段與檔案後綴檢查規則" + - "Scene 與 CUT 的依賴關係(已移除 ASR)" + - "Scene 輸出為 pre_chunks 供 Rule 3 parent chunk 使用" + - "load_scene_from_file 直接載入 JSON 不入庫" +related_documents: + - "PROCESSORS/CUT_V1.0.0.md" + - "PROCESSOR_SELECTION_V1.0.0.md" + - "PROCESSORS/CAPTION_V1.0.0.md" + - "PROCESSORS/STORY_V1.0.0.md" + - "CHUNK_DEFINITION_V1.0.0.md" +--- + +# Scene Processor (Scene Classification) V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-03 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: MIT Places365 (ResNet18) | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Scene Classification | 場景分類,辨識影片畫面的場景類型 | +| Places365 | MIT 開發的場景辨識資料集與模型(365 個場景類別) | +| ResNet18 | 殘差網路架構,輕量級分類模型 | +| pre_chunks | 原始元件的資料表,Scene 輸出供 Rule 3 使用 | +| parent chunk | 聚合多個 child chunks 的上層 chunk,由 Rule 3 產出 | + +## 選型過程 + +初始使用 ImageNet(產生 scene_XXX 類別索引),後升級至 Places365 以獲得具名場景類別(如 living_room, beach, airport),準確率 85~90%。 + +## 執行階段 + +Scene 在 **register 階段同步執行**(`register_single_file`)。Worker 中重入時檢查後綴: +- `.scene.json` → 從檔案載入(不入庫 pre_chunks) +- `.scene.json.tmp` → 跳過(回傳空結果) +- `.scene.json.err` → 跳過(回傳空結果) + +載入函數:`load_scene_from_file(path: &str) -> SceneClassificationResult` + +## 與 CUT 的關係 + +Scene 與 ASR 無關(純視覺分類),已移除對 ASR 的依賴。CUT 為 Scene 的唯一前置依賴。 + +## 輸出用途 + +Scene 為 **pre_chunks**(scene boundary),供 Rule 3 產生 parent chunk。Rule 3 需要 CUT + Scene 的 boundary 來產生複合 parent chunk。 + +## 效能實測(ExaSAN 159.6s 影片, 取樣間隔=2s) + +| 指標 | 值 | +|------|-----| +| 處理時間 | 4.09s | +| 即時倍率 | 39.0x | +| 取樣數 | 79 samples | + +## Charade 長片(6879s) + +| 指標 | 值 | +|------|-----| +| 處理時間 | 313.3s(5.2 分鐘) | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.3 | +| 記憶體 | 512 MB | +| GPU | 不使用 | +| 依賴 | CUT, ASR | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/STORY_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/STORY_V1.0.0.md new file mode 100644 index 0000000..a8edd6f --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/STORY_V1.0.0.md @@ -0,0 +1,80 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Story Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "story" + - "template-aggregator" + - "narrative" + - "v1.0.0" +ai_query_hints: + - "Story 使用模板聚合從 ASR+YOLO+Scene 產生結構化敘述" + - "Story 已從 GPT-4 雲端 API 本地化為模板聚合" + - "Story 處理速度 <0.1s/chunk,極快" + - "Story 完全不依賴雲端 API,完全本地執行" + - "Story 依賴 Scene 和 Caption processor 的輸出" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../SCENE_V1.0.0.md" + - "../CAPTION_V1.0.0.md" + - "../ASR_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" +--- + +# Story Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: 模板聚合 | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Story Processor | 從 ASR + YOLO + Scene 結果產生結構化敘述的處理器 | +| Template Aggregation | 使用預定義模板組合資料,非 LLM 生成 | +| GPT-4 | (已移除)先前使用的雲端 API 方案 | +| local deployment | 完全本地執行,不依賴任何雲端 API | +| structured narrative | 結構化敘述,以固定格式組織的故事描述 | + +--- + +## 選型過程 + +| 指標 | GPT-4(已移除) | 模板(新) | +|------|----------------|------------| +| 速度 | 3s/chunk | **<0.1s/chunk** | +| 品質 | 自然語言 | 結構化格式 | +| 依賴 | ✅ 雲端 API Key | ❌ 完全本地 | + +**決策**: 已從 GPT-4 雲端 API 本地化為模板聚合,從 ASR + YOLO + Scene 結果產生結構化敘述。 + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | - | +| 記憶體 | - | +| GPU | 不使用 | +| 依賴 | Scene, Caption | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/VISUAL_CHUNK_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/VISUAL_CHUNK_V1.0.0.md new file mode 100644 index 0000000..103d4bb --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/VISUAL_CHUNK_V1.0.0.md @@ -0,0 +1,74 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "VisualChunk Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "visual-chunk" + - "rule-aggregator" + - "yolo" + - "v1.0.0" +ai_query_hints: + - "VisualChunk 是規則驅動的聚合器,非 ML 模型" + - "VisualChunk 將 YOLO 結果組合成視覺分片" + - "VisualChunk 依賴 YOLO processor 的偵測結果" + - "VisualChunk CPU 使用率低(0.3),記憶體 512 MB" + - "VisualChunk 是 Scene 和 Story processor 的前置依賴" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../YOLO_V1.0.0.md" + - "../SCENE_V1.0.0.md" + - "../STORY_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" +--- + +# VisualChunk Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 整合 | **模型**: 無(規則聚合) | **GPU**: 否 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| VisualChunk | 規則驅動的聚合器,將 YOLO 結果組合成視覺分片 | +| Rule Aggregation | 使用預設規則而非 ML 模型進行資料組合 | +| Visual Chunk | 視覺分片,包含 YOLO 偵測物件的時間區間 | +| pre_chunks | 原始元件表,VisualChunk 的輸出會寫入此表 | +| dependency chain | 依賴鏈:YOLO → VisualChunk → Scene → Story | + +--- + +## 說明 + +非 ML 模型,是規則驅動的聚合器,將 YOLO 結果組合成視覺分片。 + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.3 | +| 記憶體 | 512 MB | +| GPU | 不使用 | +| 依賴 | YOLO | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/VOICE_EMBEDDING_FLOW_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/VOICE_EMBEDDING_FLOW_V1.0.0.md new file mode 100644 index 0000000..18ba79e --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/VOICE_EMBEDDING_FLOW_V1.0.0.md @@ -0,0 +1,139 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Voice Embedding 產出流程 V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "momentry" + - "core" + - "voice" + - "embedding" + - "asrx" + - "qdrant" + - "v1.0.0" +ai_query_hints: + - "Voice Embedding 的完整處理流程(音軌 → ECAPA-TDNN → Qdrant)" + - "ASRX Processor 的三階段處理:音軌預處理 → ASR segments 載入 → Speaker Diarization" + - "Worker store_asrx_chunks 的步驟與 pre_chunks 寫入規則" + - "Qdrant voice collection 的 payload 結構與欄位定義" + - "Voice embedding 的 192-D ECAPA-TDNN 向量規格(L2 normalize)" + - "Voice embedding 使用 Cosine 距離計算與 L2 歸一化" + - "SpeechBrain ECAPA-TDNN 的資源預估與處理速度" + - "Voice embedding 與 ASR 處理器的依賴關係" +related_documents: + - "../VECTOR_SPEC_V1.0.0.md" + - "../PROCESSORS/ASRX_V1.0.0.md" + - "../PROCESSORS/ASR_V1.0.0.md" + - "../PROCESSOR_SELECTION_V1.0.0.md" + - "../MOMENTRY_CORE_API_V1.0.0.md" +--- + +# Voice Embedding 產出流程 V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Voice Embedding | 語音向量嵌入,由 ECAPA-TDNN 產出 192-D 向量 | +| ECAPA-TDNN | SpeechBrain 提供的說話人辨識模型 | +| L2 normalize | 向量歸一化,確保所有向量單位長度 | +| Spectral Clustering | 頻譜聚類,將語音 embedding 分群以區分說話人 | +| segment_index | 在 asrx 輸出 segments 中的索引編號 | +| speaker_id | 說話人標籤(如 SPEAKER_0, SPEAKER_1) | + +## 處理流程 + +``` +1. Video → ffmpeg 萃取音軌 → 16kHz mono WAV + │ + ▼ +2. ASRX Processor (asrx_processor_custom.py) + │ + ├── Stage 1: 音軌預處理 + │ ├── ffprobe 列出所有音軌 + │ ├── 選擇最佳音軌(優先英語) + │ └── ffmpeg 轉為 16kHz mono WAV + │ + ├── Stage 2: 載入 ASR segments + │ └── 從 {file_uuid}.asr.json 讀取 segments + │ + ├── Stage 3: Speaker Diarization (SelfASRXFixed.process_with_segments) + │ ├── 對每個 ASR segment 取出音訊片段 + │ ├── ECAPA-TDNN 產出 192-D embedding + │ ├── 正規化 embeddings + │ └── 譜聚類 → speaker label + │ + ├── 輸出: {file_uuid}.asrx.json + │ ├── segments: [start_time, end_time, speaker_id] + │ └── embeddings: [[192-D float array], ...] + │ + ▼ +3. Worker store_asrx_chunks() + ├── 解析 AsrxResult + ├── 寫入 pre_chunks 表 + └── 寫入 voice embeddings 到 Qdrant + │ + ▼ +4. Qdrant `momentry_dev_voice` + └── 每個 segment 一個 vector +``` + +## Qdrant Payload 結構 + +```json +{ + "file_uuid": "dd61fda85fee441fdd00ab5528213ff7", + "speaker_id": "SPEAKER_0", + "segment_index": 0, + "start_frame": 9, + "end_frame": 441, + "start_time": 0.3, + "end_time": 14.7 +} +``` + +| 欄位 | 型別 | 說明 | +|------|------|------| +| `file_uuid` | string | 來源影片識別碼 | +| `speaker_id` | string | 說話人標籤(如 SPEAKER_0) | +| `segment_index` | integer | 在 segments 中的索引 | +| `start_frame` | integer | 起始幀 | +| `end_frame` | integer | 結束幀 | +| `start_time` | float | 起始時間(秒) | +| `end_time` | float | 結束時間(秒) | + +## Vector 規格 + +| 屬性 | 值 | +|------|-----| +| 模型 | SpeechBrain ECAPA-TDNN | +| 維度 | 192 | +| 距離計算 | Cosine | +| 歸一化 | 是(L2 normalize) | + +## 來源 Processor 資源預估 + +| 資源 | 值 | +|------|-----| +| 模型 | SpeechBrain ECAPA-TDNN (~80MB) | +| CPU | 0.8 | +| 記憶體 | 2048 MB | +| GPU | 不使用 | +| 處理速度 | 57x real-time (M4 Mac Mini) | +| 依賴 | ASR(需 ASR JSON 完成後才能啟動) | + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/YOLO_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/YOLO_V1.0.0.md new file mode 100644 index 0000000..2cb088b --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSORS/YOLO_V1.0.0.md @@ -0,0 +1,92 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "YOLO Processor V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +parent: "PROCESSOR_SELECTION_V1.0.0.md" +tags: + - "momentry" + - "core" + - "processor" + - "yolo" + - "object-detection" + - "yolov8" + - "v1.0.0" +ai_query_hints: + - "YOLO 使用 yolov8n (nano) 模型進行物件偵測" + - "YOLO 在 M4 Mac Mini 上可達 100~200 FPS" + - "YOLO 支援 GPU 加速(MPS),可快 2~5 倍" + - "YOLO 輸出 4.3 MB 含偵測結果" + - "YOLO 是 VisualChunk 和 Scene 的依賴" +related_documents: + - "PROCESSOR_SELECTION_V1.0.0.md" + - "../VISUAL_CHUNK_V1.0.0.md" + - "../POSE_V1.0.0.md" + - "../OCR_V1.0.0.md" + - "../CHUNK_DEFINITION_V1.0.0.md" +--- + +# YOLO Processor V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +**狀態**: ✅ 100% | **模型**: YOLOv8n (nano) | **GPU**: 是 + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| YOLO | You Only Look Once,即時物件偵測演算法 | +| YOLOv8n | Ultralytics YOLO 第八代 nano 版本,最小最快 | +| object detection | 物件偵測,辨識影像中的物體類別與位置 | +| MPS | Metal Performance Shaders,Apple Silicon GPU 加速 | +| bottleneck | 處理瓶頸,YOLO 與 Pose 同為最耗時的 processor | + +--- + +## 選型過程 + +| 模型 | 參數 | 大小 | 速度 | 精度 | +|------|------|------|------|------| +| **yolov8n (nano)** | **3.2M** | **6.2MB** | **最快** | **較低** | +| yolov8s (small) | 11.2M | - | 快 | 中等 | +| yolov8m (medium) | 25.9M | - | 中 | 高 | +| yolov8l (large) | 43.7M | - | 慢 | 很高 | +| yolov8x (x-large) | 68.2M | - | 最慢 | 最高 | + +**決策**: 預設使用 `yolov8n.pt`(nano),在 M4 Mac Mini 上可達 100~200 FPS。可透過配置檔切換至更大模型。 + +--- + +## 效能實測(ExaSAN 159.6s 影片, 全幀處理) + +| 指標 | 值 | +|------|-----| +| 處理時間 | 65.72s | +| 即時倍率 | 2.4x(瓶頸之一) | +| 輸出 | 4.3 MB | + +--- + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | + +## 資源預估 + +| 資源 | 值 | +|------|-----| +| CPU | 0.3 | +| 記憶體 | 1024 MB | +| GPU | 支援(`yolo_processor_mps.py` 可使用 MPS,快 2~5 倍) | +| 依賴 | 無 | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSOR_SELECTION_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSOR_SELECTION_V1.0.0.md new file mode 100644 index 0000000..67e7f93 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/PROCESSOR_SELECTION_V1.0.0.md @@ -0,0 +1,108 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "Processor 選型與資源預估 V1.0.0" +date: "2026-05-02" +version: "V1.1" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "momentry" + - "core" + - "processor" + - "model-selection" + - "resource-estimation" + - "v1.0.0" +ai_query_hints: + - "processor 的選型原因與實驗報告" + - "各 processor 的資源預估與模型資訊" + - "processor 之間的依賴關係" + - "模型選擇的比較與決策" + - "processor 檔案狀態後綴規則(json/tmp/err)" + - "Job 完成條件與必要 processor 定義" +related_documents: + - "PROCESSORS/ASR_V1.0.0.md" + - "PROCESSORS/FACE_V1.0.0.md" + - "PROCESSORS/YOLO_V1.0.0.md" + - "PROCESSORS/CUT_V1.0.0.md" + - "CHUNK_DEFINITION_V1.0.0.md" +--- + +# Processor 選型與資源預估 V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.1 | + +--- + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| Processor | 處理器,負責特定類型媒體分析的 Python 腳本 | +| Pipeline | 處理管線,定義 processor 的執行順序與依賴關係 | +| PythonExecutor | 統一執行 Python 腳本的 Rust 封裝層 | +| real-time factor | 即時倍率,處理時間與影片時長的比值 | +| resource estimation | 資源預估,包含 CPU/記憶體/GPU 的使用量 | +| Job | 處理任務,包含多個 processor 的執行與狀態管理 | + +## 總覽 + +| Processor | 狀態 | 模型 | 依賴 | GPU | CPU | 記憶體 | 文件 | +|-----------|------|------|------|-----|-----|--------|------| +| ASR | ✅ 100% | faster-whisper (small) | 無 | 否 | 1.0 | 2048 MB | [詳細](./PROCESSORS/ASR_V1.0.0.md) | +| CUT | ✅ 100% | PySceneDetect | 無 | 否 | 0.5 | 512 MB | [詳細](./PROCESSORS/CUT_V1.0.0.md) | +| YOLO | ✅ 100% | YOLOv8n | 無 | 是 | 0.3 | 1024 MB | [詳細](./PROCESSORS/YOLO_V1.0.0.md) | +| OCR | ✅ 100% | PaddleOCR PP-OCRv4 | 無 | 否 | 0.8 | 1024 MB | [詳細](./PROCESSORS/OCR_V1.0.0.md) | +| Face | ✅ 100% | InsightFace buffalo_l | 無 | 是 | 0.6 | 1536 MB | [詳細](./PROCESSORS/FACE_V1.0.0.md) | +| Pose | ✅ 100% | MediaPipe Pose | 無 | 是 | 0.4 | 1024 MB | [詳細](./PROCESSORS/POSE_V1.0.0.md) | +| ASRX | ⚠️ 80% | SpeechBrain ECAPA-TDNN | ASR | 否 | 0.8 | 2048 MB | [詳細](./PROCESSORS/ASRX_V1.0.0.md) | +| Scene | ✅ 100% | MIT Places365 | CUT | 否 | 0.3 | 512 MB | [詳細](./PROCESSORS/SCENE_V1.0.0.md) | +| VisualChunk | ✅ 整合 | 規則聚合(無模型) | YOLO | 否 | 0.3 | 512 MB | [詳細](./PROCESSORS/VISUAL_CHUNK_V1.0.0.md) | +| Caption | ✅ 100% (本地化) | Moondream2 | Scene | 否 | - | - | [詳細](./PROCESSORS/CAPTION_V1.0.0.md) | +| Story | ✅ 100% (本地化) | 模板聚合 | Scene, Caption | 否 | - | - | [詳細](./PROCESSORS/STORY_V1.0.0.md) | + +--- + +## Processor 依賴關係圖 (V4.1) + +``` +CUT ───→ Scene + │ +ASR ───→ ASRX + │ +YOLO ─→ VisualChunk +``` + +> **註(V4.1)**:CUT 和 Scene 在 register 階段同步執行,Worker pipeline 中 Scene 依賴僅 CUT(已移除 ASR)。長影片(scene ≤ 3, max > 600s)時 Face 動態移到 ASR 前。 + +## 檔案狀態後綴 + +所有 processor 輸出檔案使用統一的後綴規則: + +| 後綴 | 意義 | 行為 | +|------|------|------| +| `.json` | 完成 | 直接載入使用 | +| `.json.tmp` | 執行中 | 跳過、等待 | +| `.json.err` | 失敗 | 跳過、不重試 | + +此規則由 `PythonExecutor` 統一處理(`executor.rs:150-279`)。 + +## Job 完成條件(V4.1) + +| 條件 | 結果 | +|------|------| +| 所有 processor 完成 | ✅ Job completed | +| 必要 processor (cut/asr/yolo) 完成,其餘失敗 | ✅ Job completed(非必要失敗不卡住) | +| 必要 processor 任一失敗 | ❌ Job failed | + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本,含選型實驗報告與資源預估 | OpenCode | deepseek-chat | +| V1.1 | 2026-05-03 | CUT 新增 cut_count/cut_max_duration;Scene 移除 ASR 依賴;長影片 Face 動態調度;Job 完成條件放寬 | OpenCode | deepseek-chat | diff --git a/docs_v1.0/API_V1.0.0/INTERNAL/VECTOR_SPEC_V1.0.0.md b/docs_v1.0/API_V1.0.0/INTERNAL/VECTOR_SPEC_V1.0.0.md new file mode 100644 index 0000000..fe23a11 --- /dev/null +++ b/docs_v1.0/API_V1.0.0/INTERNAL/VECTOR_SPEC_V1.0.0.md @@ -0,0 +1,129 @@ +--- +document_type: "spec" +service: "MOMENTRY_CORE" +title: "向量化規範 V1.0.0" +date: "2026-05-02" +version: "V1.0" +status: "active" +owner: "Warren" +created_by: "OpenCode" +tags: + - "momentry" + - "core" + - "vector-embedding" + - "qdrant" + - "v1.0.0" + - "face-embedding" + - "voice-embedding" + - "text-embedding" +ai_query_hints: + - "向量化規範的向量類型與維度說明" + - "Face/Voice/Text 三種 embedding 的處理流程" + - "Qdrant collection 的名稱與 payload 結構" + - "Face embedding 的 512-D 向量規格(InsightFace ArcFace)" + - "Voice embedding 的 192-D 向量規格(ECAPA-TDNN)" + - "Text embedding 的 768-D 向量規格(nomic-embed-text-v2-moe)" + - "Qdrant Payload 中 face 與 voice 的欄位定義" + - "向量化流程中 child chunk 與 parent chunk 的 collection 區別" +related_documents: + - "PROCESSORS/FACE_EMBEDDING_FLOW_V1.0.0.md" + - "PROCESSORS/VOICE_EMBEDDING_FLOW_V1.0.0.md" + - "CHUNK_DEFINITION_V1.0.0.md" + - "PROCESSORS/FACE_V1.0.0.md" + - "PROCESSORS/ASRX_V1.0.0.md" +--- + +# 向量化規範 V1.0.0 + +| 項目 | 內容 | +|------|------| +| 建立者 | OpenCode | +| 建立時間 | 2026-05-02 | +| 文件版本 | V1.0 | + +## 關鍵術語定義 + +| 術語 | 定義 | +|------|------| +| embedding | 向量嵌入,將非結構化資料轉換為數值向量 | +| Qdrant | 向量資料庫,用於儲存與檢索 embedding | +| collection | Qdrant 中的向量集合,類似資料庫中的資料表 | +| 768-D | Text embedding 的維度,由 nomic-embed-text-v2-moe 產出 | +| 512-D | Face embedding 的維度,由 InsightFace ArcFace 產出 | +| 192-D | Voice embedding 的維度,由 SpeechBrain ECAPA-TDNN 產出 | + +## 向量類型 + +| 類型 | 來源 | 維度 | Collection | 用途 | +|------|------|------|------------|------| +| Text (child) | sentence chunk | 768-D | `momentry_dev_rule1` | 語意搜尋 | +| Text (parent) | scene chunk summary | 768-D | `momentry_dev_chunk_summaries` | 場景語意搜尋 | +| **Face** | Face processor (InsightFace) | **512-D** | `momentry_dev_face` | 人臉比對 | +| **Voice** | ASRX processor (ECAPA-TDNN) | **192-D** | `momentry_dev_voice` | 說話人比對 | + +## 向量化流程 + +### Text Embedding + +``` +chunk (sentence / scene) + → text_content / summary_text + → nomic-embed-text-v2-moe (Ollama) + → 768-D vector + → Qdrant momentry_dev_rule1 / momentry_dev_chunk_summaries +``` + +### Face Embedding + +``` +Face processor (InsightFace buffalo_l) + → face_detections.embedding (512-D) + → Qdrant momentry_dev_face + → 用於 1:N 人臉比對 +``` + +### Voice Embedding + +``` +ASRX processor (ECAPA-TDNN) + → speaker embedding (192-D) + → Qdrant momentry_dev_voice + → 用於跨影片說話人辨識 +``` + +## Qdrant Payload 結構 + +### Face Payload + +```json +{ + "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", + "face_id": "face_42", + "frame": 1260, + "timestamp": 42.0, + "x": 328, + "y": 88, + "width": 63, + "height": 75, + "confidence": 0.83 +} +``` + +### Voice Payload + +```json +{ + "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", + "speaker_id": "SPEAKER_0", + "start_frame": 9, + "end_frame": 441, + "start_time": 0.3, + "end_time": 14.7 +} +``` + +## 版本歷史 + +| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | +|------|------|------|--------|-----------| +| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat | diff --git a/docs_v1.0/ARCHITECTURE/DOCUMENT_EMBEDDING_STRATEGY.md b/docs_v1.0/ARCHITECTURE/DOCUMENT_EMBEDDING_STRATEGY.md deleted file mode 100644 index 4d6597d..0000000 --- a/docs_v1.0/ARCHITECTURE/DOCUMENT_EMBEDDING_STRATEGY.md +++ /dev/null @@ -1,167 +0,0 @@ -# Document Embedding Strategy - Parent-Child Chunks - -| Item | Content | -|------|---------| -| Author | Warren | -| Created | 2026-03-23 | -| Document Version | V1.0 | - ---- - -## Version History - -| Version | Date | Purpose | Operator | Tool/Model | -|---------|------|---------|----------|------------| -| V1.0 | 2026-03-23 | Create document embedding strategy | Warren | OpenCode | - ---- - -## Overview - -Momentry uses a **parent-child chunk hierarchy** for improved RAG retrieval. This document describes the embedding strategy for this hierarchy. - -## Chunk Structure - -### Parent Chunk -- **Purpose**: Summarize multiple child chunks with narrative description -- **Content**: High-level description of multiple scenes/segments -- **Example**: -```json -{ - "chunk_id": "story_asr_0000", - "chunk_type": "story", - "text_content": "[0s-125s] A man enters a building. He walks down a hallway.", - "child_chunk_ids": ["asr_0001", "asr_0002", "asr_0003", "asr_0004", "asr_0005"] -} -``` - -### Child Chunk -- **Purpose**: Individual segments from ASR, scenes from CUT, etc. -- **Content**: Raw transcription or detection results -- **Example**: -```json -{ - "chunk_id": "asr_0001", - "chunk_type": "sentence", - "text_content": "Hello world", - "parent_chunk_id": "story_asr_0000" -} -``` - -## Embedding Strategy - -### For Vector Search - -When embedding chunks for vector search, we combine **parent description + child content** to provide both context and detail. - -#### Parent Chunk Embedding -``` -embedding_text = f"Summary: {parent.text_content} -Children: {child_text_1}. {child_text_2}. {child_text_3}..." -``` - -**Prefix**: `search_document:` (for documents in Qdrant) - -**Example**: -``` -search_document: Summary: A man enters a building. He walks down a hallway. -Children: Hello, how are you? I'm fine thank you. The weather is nice today. -``` - -#### Child Chunk Embedding -``` -embedding_text = f"[{child.chunk_type}] {child.text_content} -Parent: {parent.description}" -``` - -**Prefix**: `search_document:` - -**Example**: -``` -search_document: [sentence] Hello, how are you? -Parent: A man enters a building. He walks down a hallway. -``` - -### For BM25 Text Search - -BM25 operates on raw text with PostgreSQL full-text search. - -- **Index**: `search_vector` (TSVECTOR) on `chunks.text_content` -- **Search**: Uses `ts_rank_cd()` for ranking - -## Hybrid Search Ranking - -Combined score = `(vector_score * 0.7) + (bm25_score * 0.3)` - -### Why 0.7/0.3? - -| Weight | Vector | BM25 | -|--------|--------|------| -| Pros | Semantic similarity | Exact keyword match | -| Cons | May miss specific terms | No semantic understanding | -| Best for | Thematic queries | Fact lookup | - -## Query Patterns - -### Thematic Query ("What are the main themes?") -- Use higher `vector_weight` (0.8-0.9) -- Vector search finds semantically similar content - -### Fact Lookup ("Who said X?") -- Use higher `bm25_weight` (0.5-0.7) -- BM25 finds exact matches - -### Balanced ("Tell me about scene 5") -- Use default 0.7/0.3 - -## Implementation - -### Embedding Generation -```rust -fn build_embedding_text(chunk: &Chunk, parent_text: Option<&str>) -> String { - match chunk.chunk_type { - ChunkType::Story => { - format!( - "Summary: {}\nChildren: {}", - chunk.text_content, - get_children_text(chunk) - ) - } - _ => { - format!( - "[{}] {}\nParent: {}", - chunk.chunk_type.as_str(), - chunk.text_content, - parent_text.unwrap_or("N/A") - ) - } - } -} -``` - -### Storage -- Parent chunks stored with their `child_chunk_ids` -- Child chunks reference `parent_chunk_id` -- Both stored in PostgreSQL with full-text index -- Vectors stored in Qdrant - -## Example Flow - -1. **Story Processing** generates parent-child hierarchy -2. **Embedding** creates vector for each chunk -3. **Storage** saves to PostgreSQL + Qdrant -4. **Search** retrieves using hybrid search -5. **Results** include both parent context and child details - -## Best Practices - -1. **Chunk Size**: 5 child chunks per parent (configurable) -2. **Text Length**: Keep embeddings under 512 tokens -3. **Parent Description**: Include temporal markers (timestamps) -4. **Child Content**: Preserve original transcription - -## Future Enhancements - -- [ ] GraphRAG integration for relationship traversal -- [ ] Cross-chunk entity linking -- [ ] Temporal graph building diff --git a/docs_v1.0/ARCHITECTURE/PLAYGROUND_BINARY_IMPLEMENTATION.md b/docs_v1.0/ARCHITECTURE/PLAYGROUND_BINARY_IMPLEMENTATION.md deleted file mode 100644 index 4f0bc2c..0000000 --- a/docs_v1.0/ARCHITECTURE/PLAYGROUND_BINARY_IMPLEMENTATION.md +++ /dev/null @@ -1,392 +0,0 @@ -# Playground Binary Implementation Plan - -| Item | Content | -|------|---------| -| Author | Warren | -| Created | 2026-03-23 | -| Document Version | V1.0 | - ---- - -## Version History - -| Version | Date | Purpose | Operator | Tool/Model | -|---------|------|---------|----------|------------| -| V1.0 | 2026-03-23 | Create implementation plan | Warren | OpenCode | - ---- - -## Overview - -Create separate `momentry_playground` binary with distinct configuration from `momentry` (production). - -| Aspect | Production (`momentry`) | Development (`momentry_playground`) | -|--------|------------------------|-------------------------------------| -| **Port** | 3002 | 3003 | -| **Redis Prefix** | `momentry:` | `momentry_dev:` | -| **Worker** | Enabled | Disabled | -| **Purpose** | Production deployment | Testing/Development | - ---- - -## Files to Modify - -``` -Files Changed: 6 files (+1 new) -├── src/core/config.rs ← Add server_port(), redis_key_prefix() -├── src/core/db/redis_client.rs ← Replace hardcoded prefixes -├── src/core/cache/redis_cache.rs ← Use configurable prefix -├── src/main.rs ← Update CLI defaults -├── src/playground.rs ← NEW: Development binary -├── Cargo.toml ← Add new binary -└── .env.development ← NEW: Dev environment config -``` - ---- - -## Implementation Steps - -### Step 1: Update `src/core/config.rs` - -Add after line 51 (after `MEDIA_BASE_URL`): - -```rust -pub static SERVER_PORT: Lazy = Lazy::new(|| { - env::var("MOMENTRY_SERVER_PORT") - .unwrap_or_else(|_| "3002".to_string()) - .parse() - .unwrap_or(3002) -}); - -pub static REDIS_KEY_PREFIX: Lazy = Lazy::new(|| { - env::var("MOMENTRY_REDIS_PREFIX") - .unwrap_or_else(|_| "momentry:".to_string()) -}); -``` - ---- - -### Step 2: Update `src/core/db/redis_client.rs` - -Replace all hardcoded `momentry:` prefixes with configurable prefix. - -**Import at top:** -```rust -use crate::core::config::REDIS_KEY_PREFIX; -``` - -**Pattern for each method:** -```rust -let prefix = REDIS_KEY_PREFIX.as_str(); -let key = format!("{}job:{}", prefix, uuid); -``` - -**Affected lines:** - -| Line | Key Pattern | -|------|-------------| -| 47 | `job:{uuid}` | -| 81, 109 | `job:{uuid}:processor:{processor}` | -| 136, 146 | `progress:{uuid}` | -| 172 | `jobs:active` | -| 179 | `jobs:active` → `jobs:completed` | -| 187 | `jobs:active` → `jobs:failed` | -| 194 | `jobs:active` | -| 201, 208 | `health:momentry_core` | -| 214 | `monitor:job:{uuid}` | -| 242, 300 | `errors:{uuid}` | -| 258, 281 | `anomaly:alerts`, `anomaly:key:{key_id}` | -| 317, 346, 364, 392, 397 | `worker:job:{uuid}...` | -| 406, 410 | `worker:job:*` | - ---- - -### Step 3: Update `src/core/cache/redis_cache.rs` - -**Import:** -```rust -use crate::core::config::REDIS_KEY_PREFIX; -``` - -**Replace line 10:** -```rust -// Remove: const KEY_PREFIX: &str = "momentry:cache:"; -``` - -**Update `prefixed_key` method (line 24):** -```rust -fn prefixed_key(&self, key: &str) -> String { - format!("{}cache:{}", REDIS_KEY_PREFIX.as_str(), key) -} -``` - -**Update tests (lines 161-162):** -```rust -#[test] -fn test_prefixed_key() { - // Note: This test will use the configured prefix - let cache = RedisCache::new().unwrap(); - // With default prefix "momentry:" - assert_eq!(cache.prefixed_key("test"), "momentry:cache:test"); - assert_eq!(cache.prefixed_key("video:abc"), "momentry:cache:video:abc"); -} -``` - ---- - -### Step 4: Update `src/main.rs` - -**Change CLI defaults (Lines 691-695):** - -```rust -// Before: -#[arg(long, default_value = "3000")] -port: u16, - -// After: -#[arg(long)] -port: Option, -``` - -**Update Server match arm (around line 2398):** - -```rust -Commands::Server { host, port } => { - let port = port.unwrap_or_else(|| *crate::core::config::SERVER_PORT); - momentry_core::api::start_server(&host, port).await?; - Ok(()) -} -``` - -**Update Redis key usage (Line 1098):** - -```rust -// Before: -let key = format!("momentry:job:{}:processor:{}", uuid, processor); - -// After: -let key = format!( - "{}job:{}:processor:{}", - crate::core::config::REDIS_KEY_PREFIX.as_str(), - uuid, - processor -); -``` - ---- - -### Step 5: Create `src/playground.rs` - -```rust -use anyhow::{Context, Result}; -use clap::{Parser, Subcommand}; -// ... same imports as main.rs ... - -fn main() -> Result<()> { - // Load development environment first - dotenv::from_filename(".env.development").ok(); - - tracing_subscriber::fmt::init(); - tracing::info!("Starting momentry_playground (development binary)"); - tracing::info!("Port: {}", *momentry_core::core::config::SERVER_PORT); - tracing::info!("Redis prefix: {}", *momentry_core::core::config::REDIS_KEY_PREFIX); - - let cli = Cli::parse(); - // ... rest identical to main.rs ... -} -``` - ---- - -### Step 6: Update `Cargo.toml` - -**Add after line 90:** - -```toml -[[bin]] -name = "momentry_playground" -path = "src/playground.rs" -``` - -**Add dependency (if not present):** - -```toml -dotenv = "0.15" -``` - ---- - -### Step 7: Create `.env.development` - -```bash -# Development Environment Configuration -# Used by: momentry_playground binary - -# Server Configuration -MOMENTRY_SERVER_PORT=3003 -MOMENTRY_REDIS_PREFIX=momentry_dev: - -# Worker Configuration (disabled for development) -MOMENTRY_WORKER_ENABLED=false -MOMENTRY_MAX_CONCURRENT=1 -MOMENTRY_POLL_INTERVAL=10 - -# Database (can use separate dev database) -DATABASE_URL=postgres://accusys@localhost:5432/momentry -MONGODB_URL=mongodb://accusys:Test3200Test3200@localhost:27017/admin - -# Redis -REDIS_URL=redis://:accusys@localhost:6379 -``` - ---- - -### Step 8: Update `.env` (Production) - -Add these lines: - -```bash -# Production Environment Configuration -# Used by: momentry binary - -# Server Configuration -MOMENTRY_SERVER_PORT=3002 -MOMENTRY_REDIS_PREFIX=momentry: - -# Worker Configuration -MOMENTRY_WORKER_ENABLED=true -MOMENTRY_MAX_CONCURRENT=2 -MOMENTRY_POLL_INTERVAL=5 -``` - ---- - -## Testing Checklist - -### 1. Build and Run Production Binary - -```bash -cargo build --release --bin momentry -cargo run --bin momentry -- server -# Expected: Listening on http://127.0.0.1:3002 - -cargo run --bin momentry -- worker -# Expected: Worker started with momentry: prefix -``` - -### 2. Build and Run Development Binary - -```bash -cargo build --bin momentry_playground -cargo run --bin momentry_playground -- server -# Expected: Listening on http://127.0.0.1:3003 -``` - -### 3. Verify Redis Key Isolation - -```bash -# Production data -redis-cli KEYS "momentry:*" -# Development data -redis-cli KEYS "momentry_dev:*" -# Should be separate -``` - -### 4. Run Both Simultaneously - -```bash -# Terminal 1: Production -cargo run --bin momentry -- server - -# Terminal 2: Development -cargo run --bin momentry_playground -- server - -# Both should run without port conflicts -``` - -### 5. Unit Tests - -```bash -cargo test --lib -# All tests should pass -``` - ---- - -## Redis Key Structure - -### Production (`momentry:`) - -``` -momentry:job:{uuid} # Job status -momentry:job:{uuid}:processor:{name} # Processor progress -momentry:progress:{uuid} # Progress pub/sub -momentry:jobs:active # Active job set -momentry:jobs:completed # Completed job set -momentry:jobs:failed # Failed job set -momentry:health:momentry_core # Health status -momentry:cache:{key} # Cache entries -momentry:worker:job:{uuid} # Worker job -momentry:worker:job:{uuid}:processor:{name} -``` - -### Development (`momentry_dev:`) - -``` -momentry_dev:job:{uuid} -momentry_dev:job:{uuid}:processor:{name} -momentry_dev:progress:{uuid} -momentry_dev:jobs:active -momentry_dev:jobs:completed -momentry_dev:jobs:failed -momentry_dev:health:momentry_core -momentry_dev:cache:{key} -momentry_dev:worker:job:{uuid} -momentry_dev:worker:job:{uuid}:processor:{name} -``` - ---- - -## Potential Issues & Solutions - -| Issue | Solution | -|-------|----------| -| `dotenv` crate not in dependencies | Add to Cargo.toml | -| Tests use hardcoded prefix | Update tests to use config, or use `#[cfg(test)]` defaults | -| Worker starts in playground | Check `MOMENTRY_WORKER_ENABLED=false` in `.env.development` | -| Port already in use | Graceful error message with suggestion to use `--port` flag | -| Mixed data in Redis | Ensure prefix is loaded before any Redis operations | - ---- - -## Files Summary - -| File | Lines Changed | Purpose | -|------|---------------|---------| -| `src/core/config.rs` | +15 | Add SERVER_PORT and REDIS_KEY_PREFIX | -| `src/core/db/redis_client.rs` | ~50 | Replace hardcoded prefixes | -| `src/core/cache/redis_cache.rs` | ~10 | Use configurable prefix | -| `src/main.rs` | ~15 | Update CLI defaults, Redis key usage | -| `src/playground.rs` | NEW (~2800) | Development binary | -| `Cargo.toml` | +4 | Add binary definition | -| `.env.development` | NEW (~20) | Development environment | - -**Total**: ~60 lines modified + ~2800 lines new file - ---- - -## Reference Documents - -| Document | Purpose | -|----------|---------| -| `docs/SERVICES.md` | Port allocations | -| `docs/MOMENTRY_CORE_REDIS_KEYS.md` | Redis key design | -| `AGENTS.md` | Code style and conventions | - ---- - -## Version History - -| Version | Date | Author | Changes | -|---------|------|--------|---------| -| 1.0 | 2025-03-25 | OpenCode | Initial implementation plan | diff --git a/docs_v1.0/ARCHITECTURE/ROOT_API_KEY_ARCHITECTURE.md b/docs_v1.0/ARCHITECTURE/ROOT_API_KEY_ARCHITECTURE.md deleted file mode 100644 index ff0a4d1..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_API_KEY_ARCHITECTURE.md +++ /dev/null @@ -1,195 +0,0 @@ -# API Key Management System Architecture - -## System Overview - -``` -┌─────────────────────────────────────────────────────────────────────────────────┐ -│ API Key Management System │ -├─────────────────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ CLI │ │ HTTP API │ │ Service │ │ External │ │ -│ │ Layer │────▶│ Layer │────▶│ Layer │────▶│ Services │ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ -│ │ │ │ │ │ -│ │ │ │ │ │ -│ ▼ ▼ ▼ ▼ │ -│ ┌─────────────────────────────────────────────────────────────────────────┐ │ -│ │ Core Modules │ │ -│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ -│ │ │ Service │ │Validator│ │ Anomaly │ │Rotation │ │ Cleanup │ │ │ -│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ -│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ -│ │ │ Webhook │ │Encrypt │ │Blacklist│ │ Report │ │ Error │ │ │ -│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ -│ └─────────────────────────────────────────────────────────────────────────┘ │ -│ │ │ │ │ -│ ▼ ▼ ▼ │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ PostgreSQL │ │ Redis │ │ External │ │ -│ │ (Storage) │ │ (Cache) │ │ (Gitea/n8n)│ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────────────────┘ -``` - -## Module Dependencies - -``` - ┌──────────────┐ - │ models.rs │ - │ (Types) │ - └──────┬───────┘ - │ - ┌──────────────────┼──────────────────┐ - │ │ │ - ▼ ▼ ▼ -┌───────────────┐ ┌───────────────┐ ┌───────────────┐ -│ service.rs │ │ error.rs │ │ validator.rs │ -│ (Core CRUD) │ │ (Errors) │ │ (Cache+Rate) │ -└───────┬───────┘ └───────────────┘ └───────────────┘ - │ - │ ┌───────────────────────────────┐ - │ │ │ - ▼ ▼ ▼ -┌───────────────┐ ┌───────────────┐ ┌───────────────┐ -│ anomaly.rs │ │ rotation.rs │ │ blacklist.rs │ -│ (Detection) │ │ (Rotation) │ │ (IP Block) │ -└───────────────┘ └───────────────┘ └───────────────┘ -``` - -## Request Flow - -``` -Client Request - │ - ▼ -┌─────────────┐ -│ CLI/API │ -└──────┬──────┘ - │ - ▼ -┌─────────────┐ ┌─────────────┐ -│ Rate Limit │────▶│ IP Blacklist│ -│ Check │ │ Check │ -└──────┬──────┘ └──────┬──────┘ - │ │ - └─────────┬─────────┘ - │ - ▼ - ┌───────────────┐ - │ Hash API Key │ - └───────┬───────┘ - │ - ▼ - ┌───────────────┐ ┌───────────────┐ - │ Cache Lookup │────▶│ PostgreSQL │ - └───────┬───────┘ │ Lookup │ - │ └───────┬───────┘ - │ │ - └──────────┬──────────┘ - │ - ▼ - ┌───────────────┐ - │ Validate │ - │ (Status, │ - │ Expiry) │ - └───────┬───────┘ - │ - ┌─────────────┼─────────────┐ - │ │ │ - ▼ ▼ ▼ - ┌──────────┐ ┌──────────┐ ┌──────────┐ - │ Valid │ │ Invalid │ │ Error │ - │ Response│ │ Response │ │ Response │ - └──────────┘ └──────────┘ └──────────┘ -``` - -## Database Schema - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ PostgreSQL │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ api_keys │ │ api_key_audit_ │ │ -│ ├─────────────────┤ │ log │ │ -│ │ id │ ├─────────────────┤ │ -│ │ key_id │─────▶│ id │ │ -│ │ key_hash │ │ key_id (FK) │ │ -│ │ name │ │ action │ │ -│ │ key_type │ │ ip_address │ │ -│ │ status │ │ details │ │ -│ │ expires_at │ └─────────────────┘ │ -│ │ ... │ │ -│ └─────────────────┘ ┌─────────────────┐ │ -│ │ api_key_anomalies│ │ -│ ┌─────────────────┐ ├─────────────────┤ │ -│ │ gitea_tokens │ │ id │ │ -│ ├─────────────────┤ │ key_id (FK) │ │ -│ │ id │ │ anomaly_type │ │ -│ │ gitea_token_id │ │ severity │ │ -│ │ token_name │ │ details │ │ -│ │ scopes │ └─────────────────┘ │ -│ └─────────────────┘ │ -│ │ -│ ┌─────────────────┐ │ -│ │ n8n_api_keys │ │ -│ ├─────────────────┤ │ -│ │ id │ │ -│ │ n8n_key_id │ │ -│ │ label │ │ -│ └─────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## External Integrations - -``` -┌─────────────────────────────────────────────────────────────────────────────────┐ -│ External Integrations │ -├─────────────────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ Gitea │ │ n8n │ │ Webhook │ │ -│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │ -│ │ • Create Token │ │ • Create API Key│ │ • Key Created │ │ -│ │ • List Tokens │ │ • List API Keys │ │ • Key Revoked │ │ -│ │ • Delete Token │ │ • Delete API Key│ │ • Anomaly │ │ -│ │ • Verify Token │ │ • Verify │ │ • Rate Limited │ │ -│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────────────────┘ -``` - -## Security Layers - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Security Layers │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ Layer 1: Network │ -│ ┌─────────────────────────────────────────────────────────┐ │ -│ │ • IP Blacklist │ │ -│ │ • Rate Limiting │ │ -│ └─────────────────────────────────────────────────────────┘ │ -│ │ -│ Layer 2: Authentication │ -│ ┌─────────────────────────────────────────────────────────┐ │ -│ │ • API Key Hash (SHA256) │ │ -│ │ • Constant-time Comparison │ │ -│ │ • Key Validation (Status, Expiry) │ │ -│ └─────────────────────────────────────────────────────────┘ │ -│ │ -│ Layer 3: Monitoring │ -│ ┌─────────────────────────────────────────────────────────┐ │ -│ │ • Anomaly Detection │ │ -│ │ • Audit Logging (Encrypted) │ │ -│ │ • Webhook Notifications │ │ -│ └─────────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` diff --git a/docs_v1.0/ARCHITECTURE/ROOT_API_WORKFLOW_WORDPRESS_N8N.md b/docs_v1.0/ARCHITECTURE/ROOT_API_WORKFLOW_WORDPRESS_N8N.md deleted file mode 100644 index 44d40e4..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_API_WORKFLOW_WORDPRESS_N8N.md +++ /dev/null @@ -1,461 +0,0 @@ -# Momentry API 使用流程 - -> **目標**: 從影片上傳到搜尋的完整流程 -> **適用**: WordPress / n8n 整合 -> **版本**: V1.0 | **日期**: 2026-03-25 - ---- - -## 流程總覽 - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ 1. 上傳 │ → │ 2. 註冊 │ → │ 3. 確認 │ → │ 4. 處理 │ → │ 5. 搜尋 │ -│ SFTPGo │ │ 自動完成 │ │ UUID │ │ 查詢進度 │ │ 測試 │ -└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ -``` - ---- - -## Step 1: 上傳影片 - -### 方式 A: SFTP 上傳(推薦) - -```bash -# 連線資訊 -主機: sftpgo.momentry.ddns.net -連接埠: 2022 -用戶名: demo -密碼: demopassword123 -``` - -使用 FileZilla 或 SFTP 客戶端上傳到 `/` 目錄 - -### 方式 B: SFTP 命令列 - -```bash -sshpass -p "demopassword123" sftp -P 2022 demo@sftpgo.momentry.ddns.net -``` - -上傳後確認檔案在 SFTPGo 中的位置 - ---- - -## Step 2: 自動註冊 - -上傳後,系統會自動: -1. 偵測新檔案 -2. 計算 UUID(SHA256) -3. 建立資料庫記錄 - -**無需手動操作** - ---- - -## Step 3: 確認註冊成功 - -### 查詢所有影片 - -```bash -curl -s -H "X-API-Key: YOUR_API_KEY" \ - "https://api.momentry.ddns.net/api/v1/videos" | jq '.videos | length' -``` - -### 查詢特定檔案 - -```bash -curl -s -H "X-API-Key: YOUR_API_KEY" \ - "https://api.momentry.ddns.net/api/v1/videos" | jq '.videos[] | select(.file_name | contains("你的檔案名"))' -``` - -### 預期回應 - -```json -{ - "uuid": "952f5854b9febad1", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/你的檔案.mp4", - "file_name": "你的檔案.mp4", - "duration": 123.45, - "width": 1920, - "height": 1080 -} -``` - -**確認要點**: -- ✅ UUID 已產生(16位 hex) -- ✅ `file_path` 正確 -- ✅ `duration` > 0 - ---- - -## Step 4: 查詢處理進度 - -### 取得任務 UUID - -```bash -# 從影片資訊取得 job_id -curl -s -H "X-API-Key: YOUR_API_KEY" \ - "https://api.momentry.ddns.net/api/v1/videos" | \ - jq '.videos[] | select(.file_name == "你的檔案.mp4") | {uuid, job_id}' -``` - -### 查詢任務狀態 - -```bash -curl -s -H "X-API-Key: YOUR_API_KEY" \ - "https://api.momentry.ddns.net/api/v1/jobs/{uuid}" -``` - -### 任務狀態說明 - -| status | 說明 | 動作 | -|--------|------|------| -| `pending` | 等待處理 | 等待中 | -| `processing` | 處理中 | 繼續輪詢 | -| `completed` | 已完成 | 可進入 Step 5 | -| `failed` | 處理失敗 | 檢查錯誤 | - -### n8n 輪詢範例 - -```javascript -// n8n Workflow: 檢查處理狀態 -const jobUuid = $input.item.json.job_uuid; - -const response = await fetch( - `https://api.momentry.ddns.net/api/v1/jobs/${jobUuid}`, - { - headers: { - "X-API-Key": "YOUR_API_KEY" - } - } -); - -const job = await response.json(); - -// 狀態檢查 -if (job.status === 'completed') { - return [{ json: { done: true, file_uuid: job.file_uuid } }]; -} else { - return [{ json: { done: false, status: job.status } }]; -} -``` - ---- - -## Step 5: 搜尋測試 - -處理完成後,資料會入庫到向量資料庫,可進行搜尋測試。 - -### 測試向量搜尋 - -```bash -curl -s -X POST "https://api.momentry.ddns.net/api/v1/search" \ - -H "X-API-Key: YOUR_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "query": "測試關鍵字", - "limit": 5 - }' -``` - -### 取得分段(Chunk)內容 - -搜尋結果會返回影片分段(Chunk),包含可播放的時間軸資訊: - -```json -{ - "results": [ - { - "uuid": "39567a0eb16f39fd", - "chunk_id": "sentence_1471", - "chunk_type": "sentence", - "start_time": 5309.08, - "end_time": 5311.08, - "text": "influenced by a vital way,", - "score": 0.68 - } - ] -} -``` - -**Chunk 欄位說明**: -| 欄位 | 說明 | -|------|------| -| `uuid` | 影片 UUID(用於取得影片網址) | -| `chunk_id` | 分段 ID | -| `chunk_type` | 分段類型(sentence/cut/time/trace/story) | -| `start_time` | 開始時間(秒) | -| `end_time` | 結束時間(秒) | -| `text` | 語音內容文字 | -| `score` | 相似度分數(0-1) | - -### 播放分段 - -取得 Chunk 後可組合成播放網址: - -``` -影片網址?start={start_time}&end={end_time} -``` - -範例: -``` -https://wp.momentry.ddns.net/video.mp4?start=5309.08&end=5311.08 -``` - ---- - -## 完整 n8n Workflow 範例 - -``` -┌──────────────┐ -│ 觸發 (定時) │ -└──────┬───────┘ - ▼ -┌──────────────┐ ┌──────────────┐ -│ 查詢影片 │────►│ 比對新檔案 │ -│ /videos │ │ │ -└──────┬───────┘ └──────────────┘ - │ │ - ▼ ▼ -┌──────────────┐ ┌──────────────┐ -│ 等待處理 │◄────│ 輪詢任務狀態 │ -│ /jobs/:uuid │ │ /jobs/:uuid │ -└──────┬───────┘ └──────────────┘ - │ - ▼ (completed) -┌──────────────┐ -│ 搜尋測試 │ -│ /search │ -└──────────────┘ -``` - ---- - -## 快速參考 - -| 步驟 | API | 用途 | -|------|-----|------| -| 查詢影片 | `GET /api/v1/videos` | 確認上傳成功 | -| 查詢任務 | `GET /api/v1/jobs/:uuid` | 查看處理進度 | -| 搜尋內容 | `POST /api/v1/search` | 測試搜尋功能 | - ---- - -## WordPress PHP 範例 - -### 基本設定 - -```php - $method, - 'headers' => [ - 'X-API-Key' => self::API_KEY, - 'Content-Type' => 'application/json', - ], - 'timeout' => 30, - ]; - - if ($data !== null) { - $args['body'] = json_encode($data); - } - - $response = wp_remote_request($url, $args); - - if (is_wp_error($response)) { - throw new Exception($response->get_error_message()); - } - - return json_decode(wp_remote_retrieve_body($response), true); - } - - public static function getVideos(): array { - return self::request('GET', '/api/v1/videos'); - } - - public static function getVideo(string $uuid): array { - return self::request('GET', "/api/v1/videos/{$uuid}"); - } - - public static function getJob(string $uuid): array { - return self::request('GET', "/api/v1/jobs/{$uuid}"); - } - - public static function search(string $query, int $topK = 5): array { - return self::request('POST', '/api/v1/search', [ - 'query' => $query, - 'top_k' => $topK, - ]); - } -} -``` - -### Step 3: 確認註冊成功 - -```php - '', - 'limit' => 10, - ], $atts); - - if (empty($atts['query'])) { - return '

請輸入搜尋關鍵字

'; - } - - try { - $results = Momentry_API::search($atts['query'], $atts['limit']); - - if (empty($results['results'])) { - return '

找不到相關結果

'; - } - - $html = '
'; - $html .= '

搜尋結果: ' . esc_html($atts['query']) . '

'; - $html .= '
    '; - - foreach ($results['results'] as $result) { - $file_uuid = $result['uuid']; - $start = $result['start_time'] ?? 0; - $end = $result['end_time'] ?? 0; - $text = $result['text'] ?? '無文字描述'; - - $html .= '
  • '; - $html .= ''; - $html .= '播放 ' . $start . 's - ' . $end . 's'; - $html .= ''; - $html .= '
    '; - $html .= '相似度: ' . round($result['score'] * 100) . '%'; - $html .= '
    '; - $html .= esc_html($text); - $html .= '
  • '; - } - - $html .= '
'; - return $html; - - } catch (Exception $e) { - return '

搜尋服務暫時無法使用

'; - } -}); -``` - -**使用方式**: -```html -[momentry_search query="關鍵字" limit="5"] -``` - ---- - -## 完整 n8n Workflow 範例 - -``` -┌──────────────┐ -│ 觸發 (定時) │ -└──────┬───────┘ - ▼ -┌──────────────┐ ┌──────────────┐ -│ 查詢影片 │────►│ 比對新檔案 │ -│ /videos │ │ │ -└──────┬───────┘ └──────────────┘ - │ │ - ▼ ▼ -┌──────────────┐ ┌──────────────┐ -│ 等待處理 │◄────│ 輪詢任務狀態 │ -│ /jobs/:uuid │ │ /jobs/:uuid │ -└──────┬───────┘ └──────────────┘ - │ - ▼ (completed) -┌──────────────┐ -│ 搜尋測試 │ -│ /search │ -└──────────────┘ -``` - ---- - -**注意**: -- 處理時間視影片長度而定(1分鐘影片約需 2-5 分鐘處理) -- 大量影片時建議分批上傳 - ---- - -## 附錄:版本歷史 - -| 版本 | 日期 | 內容 | 操作人 | -|------|------|------|--------| -| V1.0 | 2026-03-25 | 初版建立 | OpenCode | -| V1.1 | 2026-03-25 | 新增 Chunk 取得與播放說明、Shortcode 範例 | OpenCode | -| V1.2 | 2026-03-25 | 修正 SFTPGo 主機名稱為 sftpgo.momentry.ddns.net | OpenCode | diff --git a/docs_v1.0/ARCHITECTURE/ROOT_ARCHITECTURE_EVALUATION.md b/docs_v1.0/ARCHITECTURE/ROOT_ARCHITECTURE_EVALUATION.md deleted file mode 100644 index ca95826..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_ARCHITECTURE_EVALUATION.md +++ /dev/null @@ -1,331 +0,0 @@ -# 架構優化待評估事項 - -| 項目 | 內容 | -|------|------| -| 建立者 | OpenCode | -| 建立時間 | 2026-03-21 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | -|------|------|------|--------| -| V1.0 | 2026-03-21 | 創建文件 | OpenCode | -| V1.1 | 2026-03-22 | 新增 TigerGraph/GraphRAG 說故事評估 | OpenCode | - ---- - -## 架構優化項目 - -### 1. PostgreSQL → Redis 故障轉移 - -**說明**: 當 PostgreSQL 不可用時,降級到 Redis 作為臨時存儲 - -**複雜度**: 中 - -**影響範圍**: -- `src/core/db/postgres_db.rs` -- `src/core/db/redis_client.rs` - -**風險**: -- 數據一致性問題 -- 需要定義轉移策略 - -**優先級**: 待評估 - ---- - -### 2. 連接池監控 - -**說明**: 添加 PostgreSQL 和 Redis 連接池指標到 Prometheus - -**複雜度**: 低 - -**影響範圍**: -- `src/core/db/postgres_db.rs` -- `src/core/db/redis_client.rs` -- `src/api/` (新增 metrics endpoint) - -**風險**: 低 - -**優先級**: 待評估 - ---- - -### 3. Processor 重試機制 - -**說明**: 當 processor 失敗時自動重試 - -**複雜度**: 中 - -**影響範圍**: -- `src/core/processor/executor.rs` (新增 `run_with_retry` 方法) -- `src/core/processor/mod.rs` (導出 `RetryConfig`) - -**風險**: -- 無限重試風險 → 已通過 `max_attempts` 控制 -- 需要指數退避 → 已實現 - -**優先級**: ✅ 已完成 (2026-03-21) - -**實作內容**: -- `RetryConfig` 結構體 (可配置重試次數、初始延遲、最大延遲、退避倍數) -- `run_with_retry()` 方法 (自動重試 + 指數退避) -- 單元測試覆蓋 - -**使用範例**: -```rust -use crate::core::processor::{PythonExecutor, RetryConfig}; - -let executor = PythonExecutor::new()?; -let config = RetryConfig::new(3).with_delay(1000).with_max_delay(30000); - -executor.run_with_retry( - "asr_processor.py", - &["--input", "/path/to/video"], - Some(&uuid), - "asr", - Some(Duration::from_secs(3600)), - Some(config), -).await?; -``` - ---- - -### 4. PyO3 整合 - -**說明**: Python/Rust 直接調用,移除子進程調用 - -**複雜度**: 高 - -**影響範圍**: -- `src/core/processor/executor.rs` (重寫) -- Python 模組 (修改為可直接 import) - -**風險**: -- Python GIL 問題 -- 依賴版本兼容性 -- 需要大量重寫 - -**優先級**: 低 (長期目標) - ---- - -### 5. HTTP 健康端點 - -**說明**: 添加 `/health` API 用於外部監控 - -**複雜度**: 低 - -**影響範圍**: -- `src/api/server.rs` (新增路由) - -**風險**: 低 - -**優先級**: ✅ 已完成 (2026-03-21) - -**實作內容**: -- `GET /health` - 基本健康檢查 (status, version, uptime) -- `GET /health/detailed` - 詳細健康檢查 (PostgreSQL, Redis, Qdrant 狀態和延遲) - ---- - -### 6. Gitea Actions CI/CD - -**說明**: 配置 Gitea Actions 自動化 CI/CD,在合併前執行檢查 - -**複雜度**: 中 - -**影響範圍**: -- `.gitea/workflows/` (新增 workflow 文件) - -**優點**: -- 強制執行檢查,無法跳過 -- 跨設備一致 -- PR 審查前自動檢查 - -**風險**: 低 - -**優先級**: 待評估 - ---- - -### 7. Commit Message Lint - -**說明**: 規範化提交訊息格式 (Conventional Commits) - -**複雜度**: 低 - -**影響範圍**: -- `.git/hooks/commit-msg` (新增 hook) -- `~/dotfiles/hooks/commit-msg` - -**風險**: 低 - -**優先級**: ✅ 已完成 (2026-03-21) - -**實作內容**: -- 驗證格式: `(): ` -- 有效類型: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert -- 警告: 第一行超過 72 字符 - -**範例**: -``` -feat(api): add health check endpoint -fix(db): resolve connection pool issue -docs: update README -``` - ---- - -### 8. 自動化安裝腳本 - -**說明**: 創建腳本一次安裝所有開發工具 - -**複雜度**: 低 - -**影響範圍**: -- `scripts/install-dev-tools.sh` (新增) - -**風險**: 低 - -**優先級**: 待評估 - ---- - -## 評估標準 - -| 標準 | 說明 | -|------|------| -| 業務價值 | 對用戶有何幫助 | -| 技術風險 | 實現難度和潛在問題 | -| 維護成本 | 未來維護負擔 | -| 依賴性 | 對其他系統的影響 | - ---- - -## 評估記錄 - -| 項目 | 評估日期 | 決策 | 原因 | -|------|----------|------|------| -| PostgreSQL → Redis 故障轉移 | 待評估 | - | - | -| 連接池監控 | 待評估 | - | - | -| Processor 重試機制 | 2026-03-21 | 已完成 | - | -| PyO3 整合 | 待評估 | - | - | -| HTTP 健康端點 | 2026-03-21 | 已完成 | - | -| Gitea Actions CI/CD | 待評估 | - | - | -| Commit Message Lint | 2026-03-21 | 已完成 | - | -| 自動化安裝腳本 | 待評估 | - | - | - ---- - -## 9. TigerGraph / Knowledge Graph 圖譜說故事 - -**說明**: 使用知識圖譜 (Knowledge Graph) 增強視頻敘事 (Storytelling) 和 RAG 檢索 - -**複雜度**: 高 - -**研究來源**: -- [TigerGraph Agentic GraphRAG](https://www.tigergraph.com/blog/agentic-graphrag-gives-ai-a-playbook-for-smarter-retrieval/) (2025-12-15) -- [TigerGraph GraphRAG GitHub](https://github.com/tigergraph/graphrag) (v1.2.0, 2026-03-11) -- [GraphRAG in 2026: Practitioner's Guide](https://medium.com/graph-praxis/graph-rag-in-2026-a-practitioners-guide-to-what-actually-works-dca4962e7517) (2026-02-22) -- [GraphRAG Complete Guide](https://medium.com/@brian-curry-research/graphrag-the-complete-guide-to-graph-powered-retrieval-augmented-generation-eeb58a6bb4d1) (2026-02-11) - -### 核心概念 - -| 概念 | 說明 | -|------|------| -| **GraphRAG** | 結合知識圖譜與 RAG,比傳統向量檢索更智能 | -| **知識圖譜** | 實體 (Entity) + 關係 (Relationship) 的結構化表示 | -| **多跳推理** | Multi-hop traversal,可連接多個相關節點 | -| **混合檢索** | Graph traversal + Vector similarity 結合 | - -### 對 Momentry 的潛在應用 - -``` -視頻場景 → 實體識別 → 關係建立 → 故事圖譜 - ↓ ↓ ↓ ↓ - CUT [人物, 物品, 動作] [誰做了什麼, 什麼導致什麼] [敘事鏈] -``` - -**1. 敘事圖譜構建 (Narrative Graph)** -- 從 Story/Chunks 模組提取實體 -- 建立場景之間的因果關係 -- 追蹤角色互動和情節發展 - -**2. 故事檢索增強** -```python -# 現有: Parent-child chunks -parent_chunk: "場景描述" -child_chunks: [詳細內容] - -# 加入圖譜: -場景A --led_to--> 場景B -角色X --interacted_with--> 角色Y -主題Y --related_to--> 主題Z -``` - -**3. 查詢模式** - -| 查詢類型 | 傳統 RAG | GraphRAG | -|----------|----------|----------| -| 事實查找 | ✅ "這個場景在說什麼" | ✅ | -| 主題推理 | ❌ "這個視頻的主要情節" | ✅ Global search | -| 多跳關係 | ❌ | ✅ "A導致B,B導致C" | -| 可解釋性 | ❌ | ✅ 關係路徑可追溯 | - -### 實作方案 - -**方案 A: TigerGraph Cloud (推薦)** -- ✅ 原生 Graph + Vector 混合查詢 -- ✅ GraphRAG 官方支援 -- ✅ 200GB 免費額度 -- ❌ 雲端依賴,延遲敏感場景需考慮 - -**方案 B: Neo4j + Qdrant** -- ✅ 成熟開源生態 -- ✅ LangChain/LlamaIndex 整合 -- ❌ 需要維護兩個系統 - -**方案 C: 自建混合架構** -- PostgreSQL + Neo4j (或Typesense) -- 利用現有 BM25 + 向量檢索基礎 -- ❌ 開發成本高 - -### 技術棧整合建議 - -```rust -// 現有架構 -Vector Search (Qdrant) ← BM25 (PostgreSQL) - -// 加入 GraphRAG -Knowledge Graph (TigerGraph/Neo4j) - ↓ - 混合檢索 ← Vector + Graph traversal -``` - -### 優先級: 待評估 - -**考慮因素**: -- 用戶是否需要複雜的故事情節查詢? -- 實體識別 (NER) 成本是否可以接受? -- 與現有 BM25 + Vector 混合搜索的比較優勢? - ---- - -## 10. LazyGraphRAG / FastGraphRAG 成本優化 - -**說明**: GraphRAG 索引成本高昂,LazyGraphRAG 推遲圖譜構建到查詢時 - -**來源**: [GraphRAG in 2026](https://medium.com/graph-praxis/graph-rag-in-2026-a-practitioners-guide-to-what-actually-works-dca4962e7517) - -**Microsoft GraphRAG 問題**: $33K 索引大型數據集 - -**替代方案**: -- **LazyGraphRAG**: 按需構建,查詢時再建立子圖 -- **FastGraphRAG**: 優化索引管道,10-90% 成本節省 -- **HippoRAG**: 使用 Personalised PageRank 優化遍歷 - -**優先級**: 待評估 (作為 GraphRAG 的一部分) diff --git a/docs_v1.0/ARCHITECTURE/ROOT_CACHE_ARCHITECTURE_PLAN.md b/docs_v1.0/ARCHITECTURE/ROOT_CACHE_ARCHITECTURE_PLAN.md deleted file mode 100644 index 7d9001e..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_CACHE_ARCHITECTURE_PLAN.md +++ /dev/null @@ -1,1106 +0,0 @@ -# Momentry Core 分層緩存架構開發計劃 - -**版本**: V1.0 -**日期**: 2026-03-24 -**目標**: 實現 Redis + MongoDB 分層緩存架構 - ---- - -## 1. 概述 - -### 1.1 目標 - -在 Momentry Core 中實現分層緩存架構: -- **小型、高頻存取** → Redis -- **中型、查詢導向** → MongoDB - -### 1.2 現有架構 - -| 組件 | 現況 | 用途 | -|------|------|------| -| Redis | ✅ 已實現 | Job 進度、Pub/Sub、健康檢查、API Key(Moka) | -| MongoDB | ⚠️ HTTP 驅動 | 僅用於存儲 chunks | -| 內存緩存 | Moka + RwLock | API Key、視頻記錄 | - -### 1.3 目標架構 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Layer 1: Redis Cache │ -│ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ Job Progress │ │ Health Status │ │ -│ │ (已有) │ │ (新增) │ │ -│ └─────────────────┘ └─────────────────┘ │ -│ ┌─────────────────┐ │ -│ │ Video Meta 熱讀 │ │ -│ │ (新增) │ │ -│ └─────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ Cache Miss - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Layer 2: MongoDB Cache │ -│ Collection: momento.cache │ -│ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ Videos List │ │ Search Results │ │ -│ │ (新增) │ │ (新增) │ │ -│ └─────────────────┘ └─────────────────┘ │ -│ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ Hybrid Search │ │ N8n Search │ │ -│ │ (新增) │ │ (新增) │ │ -│ └─────────────────┘ └─────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ Cache Miss - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ PostgreSQL / Qdrant │ -└─────────────────────────────────────────────────────────────┘ -``` - ---- - -## 2. 技術棧變更 - -### 2.1 Cargo.toml 變更 - -```toml -# 現有 -mongodb = { version = "2", features = ["tokio-sync"] } - -# 變更為 -mongodb = { version = "2", features = ["tokio-comp", "bson"] } -``` - -**說明**: -- `tokio-comp`: 啟用 async tokio runtime 支持 -- `bson`: BSON 序列化/反序列化支持 - ---- - -## 3. 新增模組結構 - -### 3.1 目錄結構 - -``` -src/core/ -├── cache/ # 新增目錄 -│ ├── mod.rs # 模組入口 -│ ├── mongo_cache.rs # MongoDB 緩存實現 -│ ├── redis_cache.rs # Redis 緩存封裝 -│ ├── keys.rs # Cache Key 工具函數 -│ └── config.rs # 緩存配置 -├── db/ -│ ├── mod.rs # 新增 cache 導出 -│ ├── mongodb_db.rs # 重構為原生驅動 -│ └── ... -└── ... -``` - -### 3.2 文件清單 - -| 操作 | 文件路徑 | 說明 | -|------|----------|------| -| 新增 | `src/core/cache/mod.rs` | Cache 模組入口 | -| 新增 | `src/core/cache/mongo_cache.rs` | MongoDB 緩存實現 | -| 新增 | `src/core/cache/redis_cache.rs` | Redis 緩存封裝 | -| 新增 | `src/core/cache/keys.rs` | Cache Key 工具函數 | -| 新增 | `src/core/cache/config.rs` | 緩存配置 | -| 修改 | `src/core/db/mongodb_db.rs` | 改用原生 `mongodb` crate | -| 修改 | `src/core/db/mod.rs` | 導出新增模組 | -| 修改 | `src/api/server.rs` | 整合緩存到 API handlers | -| 修改 | `src/core/config.rs` | 添加 MongoDB 緩存配置 | -| 修改 | `Cargo.toml` | 更新 mongodb feature | - ---- - -## 4. 配置設計 - -### 4.1 環境變數 - -```bash -# MongoDB Cache 配置 (新增) -MONGODB_URL=mongodb://localhost:27017 -MONGODB_CACHE_ENABLED=true -MONGODB_CACHE_TTL_VIDEOS=300 # 5 分鐘 -MONGODB_CACHE_TTL_SEARCH=300 # 5 分鐘 -MONGODB_CACHE_TTL_HYBRID_SEARCH=600 # 10 分鐘 -MONGODB_CACHE_TTL_VIDEO_META=3600 # 60 分鐘 - -# Redis Cache 配置 (新增) -REDIS_CACHE_TTL_HEALTH=30 # 30 秒 -REDIS_CACHE_TTL_VIDEO_META=3600 # 60 分鐘 -``` - -### 4.2 config.rs 結構 - -```rust -// src/core/config.rs - -pub mod cache { - use super::*; - - pub static MONGODB_URL: Lazy = Lazy::new(|| { - env::var("MONGODB_URL") - .unwrap_or_else(|_| "mongodb://localhost:27017".to_string()) - }); - - pub static MONGODB_CACHE_ENABLED: Lazy = Lazy::new(|| { - env::var("MONGODB_CACHE_ENABLED") - .unwrap_or_else(|_| "true".to_string()) - .parse() - .unwrap_or(true) - }); - - pub static MONGODB_CACHE_TTL_VIDEOS: Lazy = Lazy::new(|| { - env::var("MONGODB_CACHE_TTL_VIDEOS") - .unwrap_or_else(|_| "300".to_string()) - .parse() - .unwrap_or(300) - }); - - pub static MONGODB_CACHE_TTL_SEARCH: Lazy = Lazy::new(|| { - env::var("MONGODB_CACHE_TTL_SEARCH") - .unwrap_or_else(|_| "300".to_string()) - .parse() - .unwrap_or(300) - }); - - pub static MONGODB_CACHE_TTL_HYBRID_SEARCH: Lazy = Lazy::new(|| { - env::var("MONGODB_CACHE_TTL_HYBRID_SEARCH") - .unwrap_or_else(|_| "600".to_string()) - .parse() - .unwrap_or(600) - }); - - pub static MONGODB_CACHE_TTL_VIDEO_META: Lazy = Lazy::new(|| { - env::var("MONGODB_CACHE_TTL_VIDEO_META") - .unwrap_or_else(|_| "3600".to_string()) - .parse() - .unwrap_or(3600) - }); - - pub static REDIS_CACHE_TTL_HEALTH: Lazy = Lazy::new(|| { - env::var("REDIS_CACHE_TTL_HEALTH") - .unwrap_or_else(|_| "30".to_string()) - .parse() - .unwrap_or(30) - }); -} -``` - ---- - -## 5. MongoDB Cache 設計 - -### 5.1 Collection 結構 - -```javascript -// Collection: momento.cache -// Database: momento - -{ - "_id": ObjectId("..."), - "key": "videos:list:page=1:limit=20", - "value": { - "videos": [ - { - "uuid": "xxx", - "file_path": "/path/to/video.mp4", - "file_name": "video.mp4", - "duration": 120.5, - "width": 1920, - "height": 1080 - } - ] - }, - "category": "videos", - "created_at": ISODate("2026-03-24T08:00:00Z"), - "expires_at": ISODate("2026-03-24T08:05:00Z"), - "hit_count": 0, - "last_access": ISODate("2026-03-24T08:00:00Z") -} -``` - -### 5.2 索引設計 - -```javascript -// TTL Index - 自動刪除過期文檔 -db.momento.cache.createIndex( - { "expires_at": 1 }, - { expireAfterSeconds: 0 } -) - -// 唯一索引 - 防止重複 key -db.momento.cache.createIndex( - { "key": 1 }, - { unique: true } -) - -// 分類索引 - 批量失效用 -db.momento.cache.createIndex({ "category": 1 }) -``` - -### 5.3 CacheEntry 結構 - -```rust -// src/core/cache/mongo_cache.rs - -use serde::{Deserialize, Serialize}; -use bson::oid::ObjectId; -use chrono::{DateTime, Utc}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CacheEntry { - #[serde(rename = "_id", skip_serializing_if = "Option::is_none")] - pub id: Option, - - pub key: String, - pub value: serde_json::Value, - pub category: String, - - pub created_at: DateTime, - pub expires_at: DateTime, - - #[serde(default)] - pub hit_count: i64, - - #[serde(default)] - pub last_access: DateTime, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CacheConfig { - pub enabled: bool, - pub ttl_videos: u64, - pub ttl_search: u64, - pub ttl_hybrid_search: u64, - pub ttl_video_meta: u64, -} -``` - ---- - -## 6. API 緩存策略 - -### 6.1 緩存矩陣 - -| API | Cache Layer | Key Pattern | TTL | 失效時機 | -|-----|-------------|-------------|-----|----------| -| `GET /api/v1/videos` | MongoDB | `videos:list:page={p}:limit={l}` | 5min | register/delete | -| `GET /api/v1/lookup` | Redis | `momentry:cache:video:{uuid}` | 60min | update/delete | -| `POST /api/v1/search` | MongoDB | `search:{hash}` | 5min | vectorize | -| `POST /api/v1/search/hybrid` | MongoDB | `search:hybrid:{hash}` | 10min | vectorize | -| `POST /api/v1/n8n/search` | MongoDB | `search:n8n:{hash}` | 5min | vectorize | -| `GET /health` | Redis | `momentry:cache:health` | 30s | - | - -### 6.2 Cache Key 命名規範 - -```rust -// src/core/cache/keys.rs - -pub mod keys { - pub const CATEGORY_VIDEOS: &str = "videos"; - pub const CATEGORY_SEARCH: &str = "search"; - pub const CATEGORY_HYBRID_SEARCH: &str = "hybrid_search"; - pub const CATEGORY_N8N_SEARCH: &str = "n8n_search"; - pub const CATEGORY_VIDEO_META: &str = "video_meta"; - pub const CATEGORY_HEALTH: &str = "health"; - - pub fn videos_list(page: usize, limit: usize) -> String { - format!("videos:list:page={}:limit={}", page, limit) - } - - pub fn video_meta(uuid: &str) -> String { - format!("video:{}", uuid) - } - - pub fn search(query_hash: &str) -> String { - format!("search:{}", query_hash) - } - - pub fn hybrid_search(query_hash: &str) -> String { - format!("search:hybrid:{}", query_hash) - } - - pub fn n8n_search(query_hash: &str) -> String { - format!("search:n8n:{}", query_hash) - } - - pub fn health() -> String { - "health:basic".to_string() - } -} -``` - ---- - -## 7. 實現細節 - -### 7.1 MongoCache 實現 - -```rust -// src/core/cache/mongo_cache.rs - -use anyhow::Result; -use bson::{doc, oid::ObjectId}; -use chrono::{Duration, Utc}; -use mongodb::{Client, Collection, Database}; -use serde::{de::DeserializeOwned, Serialize}; -use std::sync::Arc; - -use super::keys; -use super::config::CacheConfig; -use crate::core::config::cache as cache_config; - -#[derive(Clone)] -pub struct MongoCache { - client: Client, - db: Database, - collection: Collection, - config: CacheConfig, -} - -impl MongoCache { - pub async fn init() -> Result { - let uri = cache_config::MONGODB_URL.as_str(); - let client = Client::uri(uri).await?; - let db = client.database("momento"); - let collection = db.collection::("cache"); - - let config = CacheConfig { - enabled: *cache_config::MONGODB_CACHE_ENABLED, - ttl_videos: *cache_config::MONGODB_CACHE_TTL_VIDEOS, - ttl_search: *cache_config::MONGODB_CACHE_TTL_SEARCH, - ttl_hybrid_search: *cache_config::MONGODB_CACHE_TTL_HYBRID_SEARCH, - ttl_video_meta: *cache_config::MONGODB_CACHE_TTL_VIDEO_META, - }; - - // Ensure indexes exist - Self::ensure_indexes(&collection).await?; - - Ok(Self { - client, - db, - collection, - config, - }) - } - - async fn ensure_indexes(collection: &Collection) -> Result<()> { - use mongodb::IndexModel; - - // TTL Index - let ttl_index = IndexModel::builder() - .keys(doc! { "expires_at": 1 }) - .options( - mongodb::options::IndexOptions::builder() - .expire_after(std::time::Duration::from_secs(0)) - .build() - ) - .build(); - - // Unique key index - let key_index = IndexModel::builder() - .keys(doc! { "key": 1 }) - .options( - mongodb::options::IndexOptions::builder() - .unique(true) - .build() - ) - .build(); - - collection.create_indexes([ttl_index, key_index]).await?; - Ok(()) - } - - pub async fn get(&self, key: &str) -> Result> { - if !self.config.enabled { - return Ok(None); - } - - let filter = doc! { "key": key }; - let result = self.collection.find_one(filter).await?; - - if let Some(entry) = result { - // Update hit count and last_access - let update = doc! { - "$inc": { "hit_count": 1 }, - "$set": { "last_access": Utc::now() } - }; - self.collection.update_one(doc! { "_id": entry.id }, update).await?; - - // Deserialize value - let value = serde_json::from_value(entry.value)?; - Ok(Some(value)) - } else { - Ok(None) - } - } - - pub async fn set(&self, key: &str, value: &T, ttl_secs: u64, category: &str) -> Result<()> { - if !self.config.enabled { - return Ok(()); - } - - let now = Utc::now(); - let expires_at = now + Duration::seconds(ttl_secs as i64); - let json_value = serde_json::to_value(value)?; - - let entry = CacheEntry { - id: None, - key: key.to_string(), - value: json_value, - category: category.to_string(), - created_at: now, - expires_at, - hit_count: 0, - last_access: now, - }; - - let filter = doc! { "key": key }; - let update = doc! { - "$set": { - "value": &entry.value, - "category": &entry.category, - "expires_at": entry.expires_at, - "last_access": entry.last_access, - }, - "$setOnInsert": { - "key": &entry.key, - "created_at": entry.created_at, - "hit_count": 0i64, - } - }; - - self.collection.update_one(filter, update).await?; - Ok(()) - } - - pub async fn invalidate_category(&self, category: &str) -> Result { - if !self.config.enabled { - return Ok(0); - } - - let result = self.collection.delete_many(doc! { "category": category }).await?; - Ok(result.deleted_count) - } - - pub async fn invalidate_prefix(&self, prefix: &str) -> Result { - if !self.config.enabled { - return Ok(0); - } - - let filter = doc! { "key": { "$regex": &format!("^{}", prefix) } }; - let result = self.collection.delete_many(filter).await?; - Ok(result.deleted_count) - } - - pub async fn get_or_fetch(&self, key: &str, ttl_secs: u64, category: &str, fetcher: F) -> Result - where - F: FnOnce() -> Fut, - Fut: std::future::Future>, - T: DeserializeOwned + Serialize, - { - // Try cache first - if let Some(cached) = self.get::(key).await? { - tracing::debug!("Cache hit for key: {}", key); - return Ok(cached); - } - - // Cache miss - fetch from source - tracing::debug!("Cache miss for key: {}", key); - let value = fetcher().await?; - - // Store in cache - self.set(key, &value, ttl_secs, category).await?; - - Ok(value) - } -} -``` - -### 7.2 RedisCache 實現 - -```rust -// src/core/cache/redis_cache.rs - -use anyhow::Result; -use redis::AsyncCommands; -use serde::{de::DeserializeOwned, Serialize}; -use std::time::Duration; - -use crate::core::config::cache as cache_config; - -#[derive(Clone)] -pub struct RedisCache { - client: crate::core::db::RedisClient, -} - -impl RedisCache { - pub fn new() -> Result { - let client = crate::core::db::RedisClient::new()?; - Ok(Self { client }) - } - - pub async fn get(&self, key: &str) -> Result> { - let mut conn = self.client.get_conn_internal().await?; - let value: Option = conn.get(key).await?; - - match value { - Some(json) => { - let result = serde_json::from_str(&json)?; - Ok(Some(result)) - } - None => Ok(None), - } - } - - pub async fn set(&self, key: &str, value: &T, ttl_secs: u64) -> Result<()> { - let mut conn = self.client.get_conn_internal().await?; - let json = serde_json::to_string(value)?; - let _: String = conn.set_ex(key, json, ttl_secs).await?; - Ok(()) - } - - pub async fn delete(&self, key: &str) -> Result<()> { - let mut conn = self.client.get_conn_internal().await?; - let _: () = conn.del(key).await?; - Ok(()) - } - - pub async fn invalidate_pattern(&self, pattern: &str) -> Result { - let mut conn = self.client.get_conn_internal().await?; - let keys: Vec = conn.keys(pattern).await?; - let count = keys.len() as u64; - - if !keys.is_empty() { - let _: () = conn.del(keys).await?; - } - - Ok(count) - } - - pub async fn get_or_fetch(&self, key: &str, ttl_secs: u64, fetcher: F) -> Result - where - F: FnOnce() -> Fut, - Fut: std::future::Future>, - T: DeserializeOwned + Serialize, - { - // Try cache first - if let Some(cached) = self.get::(key).await? { - return Ok(cached); - } - - // Cache miss - let value = fetcher().await?; - self.set(key, &value, ttl_secs).await?; - Ok(value) - } - - pub async fn get_health(&self) -> Result> { - let mut conn = self.client.get_conn_internal().await?; - let key = "momentry:cache:health"; - let value: Option = conn.get(key).await?; - Ok(value) - } - - pub async fn set_health(&self, status: &str) -> Result<()> { - let ttl = *cache_config::REDIS_CACHE_TTL_HEALTH; - let mut conn = self.client.get_conn_internal().await?; - let key = "momentry:cache:health"; - let _: String = conn.set_ex(key, status, ttl).await?; - Ok(()) - } -} -``` - ---- - -## 8. API Handler 整合 - -### 8.1 AppState 擴展 - -```rust -// src/api/server.rs - -#[derive(Clone)] -struct AppState { - embedder: Arc, - embedder_model: String, - mongo_cache: Arc, // 新增 - redis_cache: Arc, // 新增 -} -``` - -### 8.2 Videos List Handler - -```rust -// src/api/server.rs - -use crate::core::cache::{MongoCache, RedisCache, keys}; - -async fn list_videos( - State(state): State, - Query(params): Query, -) -> Result, StatusCode> { - let page = params.page.unwrap_or(1); - let limit = params.limit.unwrap_or(20); - let cache_key = keys::videos_list(page, limit); - - // Try cache first - let video_infos = state.mongo_cache - .get_or_fetch::<_, _, VideosResponse>( - &cache_key, - 300, // 5 min TTL - keys::CATEGORY_VIDEOS, - || async { - let db = PostgresDb::init().await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - - let videos = db.list_videos().await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - - let video_infos: Vec = videos - .into_iter() - .map(|v| VideoInfoResponse { - uuid: v.uuid, - file_path: v.file_path, - file_name: v.file_name, - duration: v.duration, - width: v.width, - height: v.height, - }) - .collect(); - - Ok(VideosResponse { videos: video_infos }) - }, - ) - .await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - - Ok(Json(video_infos)) -} -``` - -### 8.3 Lookup Handler - -```rust -// src/api/server.rs - -async fn lookup( - State(state): State, - Query(query): Query, -) -> Result, StatusCode> { - if let Some(path) = query.path { - let uuid = crate::uuid::compute_uuid_from_path(&path); - return Ok(Json(LookupResponse { - uuid, - file_path: None, - file_name: None, - duration: None, - })); - } - - if let Some(uuid) = query.uuid { - let cache_key = keys::video_meta(&uuid); - - // Try Redis cache first, fallback to DB - let video = state.redis_cache - .get_or_fetch::<_, _, Option>( - &cache_key, - 3600, // 60 min TTL - || async { - let db = PostgresDb::init().await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - db.get_video_by_uuid(&uuid).await - .map_err(|e| anyhow::anyhow!(e)) - }, - ) - .await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - - if let Some(v) = video { - return Ok(Json(LookupResponse { - uuid: v.uuid, - file_path: Some(v.file_path), - file_name: Some(v.file_name), - duration: Some(v.duration), - })); - } - } - - Err(StatusCode::NOT_FOUND) -} -``` - -### 8.4 Search Handler - -```rust -// src/api/server.rs - -use sha2::{Sha256, Digest}; - -async fn search( - State(state): State, - Json(req): Json, -) -> Result, StatusCode> { - let limit = req.limit.unwrap_or(10); - - // Generate cache key from query hash - let query_for_hash = serde_json::json!({ - "query": req.query, - "limit": limit, - "uuid": req.uuid, - }); - let query_hash = format!("{:x}", Sha256::digest(&serde_json::to_string(&query_for_hash).unwrap())); - let cache_key = keys::search(&query_hash); - - let response = state.mongo_cache - .get_or_fetch::<_, _, SearchResponse>( - &cache_key, - 300, // 5 min TTL - keys::CATEGORY_SEARCH, - || async { - // Original search logic here - let query_vector = state.embedder.embed_query(&req.query).await - .map_err(|e| anyhow::anyhow!("Embedding failed: {}", e))?; - - let qdrant = QdrantDb::init().await - .map_err(|e| anyhow::anyhow!("Qdrant init failed: {}", e))?; - let pg = PostgresDb::init().await - .map_err(|e| anyhow::anyhow!("PG init failed: {}", e))?; - - let search_results = if let Some(ref uuid) = req.uuid { - let query_f64: Vec = query_vector.iter().map(|&x| x as f64).collect(); - qdrant.search_in_uuid(&query_f64, uuid, limit).await? - } else { - let query_f64: Vec = query_vector.iter().map(|&x| x as f64).collect(); - qdrant.search(&query_f64, limit).await? - }; - - let mut results = Vec::new(); - for r in search_results { - if let Some(chunk) = pg.get_chunk_by_chunk_id(&r.chunk_id).await.ok().flatten() { - let text = chunk.content.get("text") - .and_then(|v| v.as_str()) - .unwrap_or("") - .to_string(); - - results.push(SearchResult { - uuid: chunk.uuid, - chunk_id: chunk.chunk_id, - chunk_type: chunk.chunk_type.as_str().to_string(), - start_time: chunk.start_time, - end_time: chunk.end_time, - text, - score: r.score, - }); - } - } - - Ok(SearchResponse { results, query: req.query }) - }, - ) - .await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - - Ok(Json(response)) -} -``` - -### 8.5 Health Handler - -```rust -// src/api/server.rs - -async fn health(State(state): State) -> Json { - // Try Redis cache first - if let Some(status) = state.redis_cache.get_health().await.ok().flatten() { - return Json(HealthResponse { - status, - version: env!("CARGO_PKG_VERSION").to_string(), - uptime_ms: get_uptime_ms(), - }); - } - - // Cache miss - compute and cache - let status = "ok".to_string(); - state.redis_cache.set_health(&status).await.ok(); - - Json(HealthResponse { - status, - version: env!("CARGO_PKG_VERSION").to_string(), - uptime_ms: get_uptime_ms(), - }) -} -``` - -### 8.6 Register Handler (緩存失效) - -```rust -// src/api/server.rs - -async fn register( - State(state): State, - Json(req): Json, -) -> Result, StatusCode> { - // ... existing registration logic ... - - let video_id = db.register_video(&record).await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - - // Invalidate videos list cache - state.mongo_cache.invalidate_prefix("videos:list:").await.ok(); - - Ok(Json(RegisterResponse { - uuid, - video_id, - file_name, - duration, - width, - height, - })) -} -``` - ---- - -## 9. 失效策略 - -### 9.1 寫操作觸發失效 - -| 操作 | 失效範圍 | -|------|----------| -| `POST /api/v1/register` | `videos:*` | -| 刪除視頻 | `video:{uuid}`, `videos:*` | -| 更新視頻 | `video:{uuid}` | -| 向量更新 | `search:*`, `search:hybrid:*`, `search:n8n:*` | - -### 9.2 失效實現 - -```rust -// Invalidation helper methods - -impl MongoCache { - pub async fn invalidate_videos_list(&self) -> Result { - self.invalidate_category(keys::CATEGORY_VIDEOS).await - } - - pub async fn invalidate_video(&self, uuid: &str) -> Result { - let key = keys::video_meta(uuid); - let count = self.invalidate_prefix(&key).await?; - Ok(count + self.invalidate_videos_list().await?) - } - - pub async fn invalidate_all_search(&self) -> Result { - let count = self.invalidate_category(keys::CATEGORY_SEARCH).await?; - let count2 = self.invalidate_category(keys::CATEGORY_HYBRID_SEARCH).await?; - let count3 = self.invalidate_category(keys::CATEGORY_N8N_SEARCH).await?; - Ok(count + count2 + count3) - } -} -``` - ---- - -## 10. 實現步驟 - -### Phase 1: 基礎設施 - -| 步驟 | 任務 | 檔案 | -|------|------|------| -| 1.1 | 更新 Cargo.toml mongodb feature | `Cargo.toml` | -| 1.2 | 添加 MongoDB 配置到 config.rs | `src/core/config.rs` | -| 1.3 | 創建 cache 模組目錄 | `src/core/cache/` | -| 1.4 | 實現 CacheEntry 和 keys 工具 | `src/core/cache/keys.rs` | -| 1.5 | 實現 CacheConfig | `src/core/cache/config.rs` | -| 1.6 | 重構 MongoDb 使用原生驅動 | `src/core/db/mongodb_db.rs` | -| 1.7 | 實現 MongoCache | `src/core/cache/mongo_cache.rs` | -| 1.8 | 實現 RedisCache | `src/core/cache/redis_cache.rs` | -| 1.9 | 更新 db/mod.rs 導出 | `src/core/db/mod.rs` | - -### Phase 2: API 整合 - -| 步驟 | 任務 | 檔案 | -|------|------|------| -| 2.1 | 擴展 AppState | `src/api/server.rs` | -| 2.2 | 整合 list_videos 緩存 | `src/api/server.rs` | -| 2.3 | 整合 lookup 緩存 | `src/api/server.rs` | -| 2.4 | 整合 search 緩存 | `src/api/server.rs` | -| 2.5 | 整合 hybrid_search 緩存 | `src/api/server.rs` | -| 2.6 | 整合 n8n_search 緩存 | `src/api/server.rs` | -| 2.7 | 整合 health 緩存 | `src/api/server.rs` | -| 2.8 | 添加 register 緩存失效 | `src/api/server.rs` | - -### Phase 3: 測試驗證 - -| 步驟 | 任務 | -|------|------| -| 3.1 | cargo check | -| 3.2 | cargo build | -| 3.3 | cargo clippy | -| 3.4 | cargo fmt | -| 3.5 | cargo test | -| 3.6 | 手動 API 測試 | - ---- - -## 11. 測試策略 - -### 11.1 單元測試 - -```rust -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_cache_key_generation() { - assert_eq!( - keys::videos_list(1, 20), - "videos:list:page=1:limit=20" - ); - assert_eq!( - keys::video_meta("abc123"), - "video:abc123" - ); - } - - #[tokio::test] - async fn test_cache_hit_miss() { - let cache = MongoCache::init().await.unwrap(); - - // Set value - cache.set("test_key", &"test_value".to_string(), 60, "test").await.unwrap(); - - // Get value - let value: Option = cache.get("test_key").await.unwrap(); - assert_eq!(value, Some("test_value".to_string())); - - // Invalidate - cache.invalidate_category("test").await.unwrap(); - - // Get again - let value: Option = cache.get("test_key").await.unwrap(); - assert_eq!(value, None); - } -} -``` - -### 11.2 API 測試腳本 - -```bash -# Test cache hit -curl -s http://localhost:8080/api/v1/videos | jq .videos | wc -l -# Should return cached count - -# Force cache miss (wait for TTL or invalidate) -curl -s -X POST http://localhost:8080/api/v1/register \ - -H "Content-Type: application/json" \ - -d '{"path": "/path/to/new/video.mp4"}' - -# Verify cache was invalidated -curl -s http://localhost:8080/api/v1/videos | jq .videos | wc -l -# Should trigger fresh query -``` - ---- - -## 12. 監控指標 - -### 12.1 日誌 - -```rust -// 在 cache 命中/未命中時記錄 -tracing::debug!("Cache hit for key: {}", key); -tracing::debug!("Cache miss for key: {}", key); - -// 在失效時記錄 -tracing::info!("Invalidated {} entries in category: {}", count, category); -``` - -### 12.2 可選指標 - -| 指標 | 描述 | -|------|------| -| `cache_hit_total` | Cache 命中總數 | -| `cache_miss_total` | Cache 未命中總數 | -| `cache_invalidations_total` | 緩存失效總數 | -| `cache_operation_duration_seconds` | 緩存操作延遲 | - ---- - -## 13. 風險與緩解 - -| 風險 | 影響 | 緩解措施 | -|------|------|----------| -| MongoDB 連接失敗 | 降級到無緩存 | 緩存操作添加 `.ok()` 錯誤處理 | -| 緩存數據過期不一致 | 用戶看到舊數據 | 合理的 TTL 值 + 寫時失效 | -| 緩存 key 衝突 | 返回錯誤數據 | 使用 SHA256 hash 確保唯一性 | -| 緩存空間膨脹 | 記憶體/磁碟佔用過大 | TTL 自動過期 + 最大條目限制 | - ---- - -## 14. 預期效益 - -| 指標 | 改善前 | 預期改善後 | -|------|--------|------------| -| `GET /api/v1/videos` 延遲 | ~200ms | ~20ms (Cache Hit) | -| `GET /api/v1/lookup` 延遲 | ~50ms | ~5ms (Cache Hit) | -| `POST /api/v1/search` 延遲 | ~500ms | ~50ms (Cache Hit) | -| 資料庫負載 | 100% | ~30% | -| API 吞吐量 | 100 RPS | ~300 RPS | - ---- - -## 15. 附錄 - -### A. MongoDB 初始化腳本 - -```javascript -// 初始化 momento.cache collection 和索引 -use momento; - -db.cache.drop(); - -db.cache.insertOne({ - key: "init", - value: { initialized: true }, - category: "system", - created_at: new Date(), - expires_at: new Date(Date.now() + 86400000), - hit_count: 0, - last_access: new Date() -}); - -db.cache.createIndex( - { "expires_at": 1 }, - { expireAfterSeconds: 0 } -); - -db.cache.createIndex( - { "key": 1 }, - { unique: true } -); - -db.cache.createIndex({ "category": 1 }); - -db.cache.deleteOne({ key: "init" }); - -print("Cache collection initialized successfully"); -``` - -### B. 環境變數參考 - -```bash -# .env 或 shell 環境 -MONGODB_URL=mongodb://localhost:27017 -MONGODB_CACHE_ENABLED=true -MONGODB_CACHE_TTL_VIDEOS=300 -MONGODB_CACHE_TTL_SEARCH=300 -MONGODB_CACHE_TTL_HYBRID_SEARCH=600 -MONGODB_CACHE_TTL_VIDEO_META=3600 - -REDIS_CACHE_TTL_HEALTH=30 -REDIS_CACHE_TTL_VIDEO_META=3600 -``` diff --git a/docs_v1.0/ARCHITECTURE/ROOT_JOB_WORKER_IMPLEMENTATION_PLAN.md b/docs_v1.0/ARCHITECTURE/ROOT_JOB_WORKER_IMPLEMENTATION_PLAN.md deleted file mode 100644 index ff61911..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_JOB_WORKER_IMPLEMENTATION_PLAN.md +++ /dev/null @@ -1,682 +0,0 @@ -# Job Worker 實作計畫 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren / OpenCode | -| 建立時間 | 2026-03-24 | -| 文件版本 | V1.1 | -| 狀態 | ✅ 已實作 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | -|------|------|------|--------| -| V1.0 | 2026-03-24 | 建立實作計畫 | OpenCode | -| V1.1 | 2026-03-25 | 實作完成,更新狀態 | OpenCode | - ---- - -## 實作狀態 - -### ✅ 已完成 - -| 元件 | 檔案 | 狀態 | -|------|------|------| -| MonitorJob 結構 | `src/core/db/postgres_db.rs` | ✅ | -| ProcessorResult 結構 | `src/core/db/postgres_db.rs` | ✅ | -| Worker 配置 | `src/worker/config.rs` | ✅ | -| Job Worker | `src/worker/job_worker.rs` | ✅ | -| Processor Pool | `src/worker/processor.rs` | ✅ | -| Worker 模組 | `src/worker/mod.rs` | ✅ | -| PostgreSQL 表格 | `monitor_jobs`, `processor_results` | ✅ | -| 類型修復 | `i32`, `NaiveDateTime` | ✅ | - -### 待整合 - -| 項目 | 說明 | -|------|------| -| Worker 服務啟動 | 需要加入 launchd plist | -| 監控整合 | 需要加入 MOMENTRY_CORE_MONITORING.md | -| 備份涵蓋 | 需要確認備份包含新表格 | - ---- - -## 1. 設計決策 - -### 1.1 確認的設計決策 - -| 項目 | 決策 | 理由 | -|------|------|------| -| 觸發方式 | 輪詢(Job Worker) | 暫無可靠的 API 觸發機制 | -| 並行處理 | 最多 2 個 | 可根據 CPU/GPU 能力調整 | -| 失敗處理 | 獨立模組,部分完成可接續 | 任何模組失敗都產出狀態記錄 | -| Worker 啟動 | 獨立進程 | 隔離、易管理 | -| 並行上限調整 | 環境變數 + 預設值 | 靈活、可調整 | -| 狀態同步 | PostgreSQL + Redis | 可靠 + 即時 | - -### 1.2 環境變數 - -| 變數 | 預設值 | 說明 | -|------|--------|------| -| `MOMENTRY_MAX_CONCURRENT` | 2 | 最大並行 processor 數 | -| `MOMENTRY_POLL_INTERVAL` | 5 | 輪詢間隔(秒) | -| `MOMENTRY_WORKER_ENABLED` | true | 是否啟用 worker | - ---- - -## 2. 系統架構 - -### 2.1 完整流程圖 - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ 檔案註冊觸發處理流程 │ -├─────────────────────────────────────────────────────────────────────────┤ -│ │ -│ 1. SFTPGo 上傳 │ -│ │ │ -│ ▼ │ -│ 2. Hook 呼叫 Register API │ -│ │ │ -│ ▼ │ -│ 3. Register API │ -│ ├─► ffprobe 提取 metadata │ -│ ├─► 寫入 videos 表 │ -│ └─► 建立 monitor_jobs 記錄 (status=pending) │ -│ │ │ -│ ▼ │ -│ 4. Job Worker (獨立進程,輪詢機制) │ -│ ├─► 輪詢 pending jobs │ -│ ├─► 檢查 videos 表 fs_json 決定需要處理什麼 │ -│ ├─► 並行執行 processors (最多 2 個) │ -│ └─► 更新 videos, monitor_jobs, processor_results 表 │ -│ │ │ -│ ▼ │ -│ 5. 處理結果 │ -│ ├─► 更新 videos 表 (fs_json, psql_chunk, qvector_chunk) │ -│ ├─► 更新 monitor_jobs 表 (status, progress) │ -│ ├─► 更新 processor_results 表 (每個模組狀態) │ -│ └─► Redis Pub/Sub 即時進度 │ -│ │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - -### 2.2 Job Worker 架構 - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ Job Worker 架構 │ -├─────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ PostgreSQL │ ───▶ │ Worker │ ───▶ │ Processor │ │ -│ │ Job Queue │ │ Loop │ │ Pool │ │ -│ └─────────────┘ └──────┬──────┘ └──────┬──────┘ │ -│ │ │ │ -│ ▼ ▼ │ -│ ┌─────────────┐ ┌─────────────┐ │ -│ │ Video State │ │ Processor 1 │ │ -│ │ Check │ │ (ASR/YOLO) │ │ -│ └─────────────┘ ├─────────────┤ │ -│ │ Processor 2 │ │ -│ │ (CUT/OCR) │ │ -│ └─────────────┘ │ -│ │ -│ Redis ──── Pub/Sub ──── 即時進度 │ -│ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - ---- - -## 3. 資料庫結構 - -### 3.1 Migration 檔案 - -**檔案**: `migrations/003_job_worker.sql` - -```sql --- ================================================================ --- Migration 003: Job Worker System --- ================================================================ - --- 3.1.1 更新 videos 表 -ALTER TABLE videos ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'pending'; -ALTER TABLE videos ADD COLUMN IF NOT EXISTS user_id BIGINT; -ALTER TABLE videos ADD COLUMN IF NOT EXISTS job_id INTEGER REFERENCES monitor_jobs(id); - -COMMENT ON COLUMN videos.status IS 'pending, processing, completed, failed'; -COMMENT ON COLUMN videos.user_id IS 'WordPress user ID'; -COMMENT ON COLUMN videos.job_id IS 'Associated monitor_jobs ID'; - --- 3.1.2 更新 monitor_jobs 表 -ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS video_id BIGINT REFERENCES videos(id); -ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS user_id BIGINT; -ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS processors VARCHAR(20)[]; -ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS completed_processors VARCHAR(20)[]; -ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS failed_processors VARCHAR(20)[]; - -COMMENT ON COLUMN monitor_jobs.processors IS 'Processors to run: asr, cut, yolo, ocr, face, pose, asrx'; -COMMENT ON COLUMN monitor_jobs.completed_processors IS 'Successfully completed processors'; -COMMENT ON COLUMN monitor_jobs.failed_processors IS 'Failed processors'; - --- 3.1.3 新增 processor_results 表 -CREATE TABLE IF NOT EXISTS processor_results ( - id SERIAL PRIMARY KEY, - job_id INTEGER REFERENCES monitor_jobs(id) ON DELETE CASCADE, - video_id BIGINT REFERENCES videos(id) ON DELETE CASCADE, - processor VARCHAR(20) NOT NULL, - status VARCHAR(20) NOT NULL DEFAULT 'pending', - output_path TEXT, - started_at TIMESTAMP, - completed_at TIMESTAMP, - error_message TEXT, - progress_total INT DEFAULT 0, - progress_current INT DEFAULT 0, - last_checkpoint JSONB, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - - UNIQUE(job_id, processor) -); - -CREATE INDEX IF NOT EXISTS idx_processor_results_job ON processor_results(job_id); -CREATE INDEX IF NOT EXISTS idx_processor_results_video ON processor_results(video_id); -CREATE INDEX IF NOT EXISTS idx_processor_results_status ON processor_results(status); - -COMMENT ON TABLE processor_results IS 'Tracks individual processor execution status'; -COMMENT ON COLUMN processor_results.status IS 'pending, running, completed, failed, skipped'; - --- 3.1.4 更新 videos 表標記欄位用途 -COMMENT ON COLUMN videos.fs_video IS 'Video file exists on filesystem'; -COMMENT ON COLUMN videos.fs_json IS 'All processor JSON files generated'; -COMMENT ON COLUMN videos.fs_chunks IS 'Chunk files generated'; -COMMENT ON COLUMN videos.fs_vectors IS 'Vector files generated'; -COMMENT ON COLUMN videos.psql_chunk IS 'Chunks stored in PostgreSQL'; -COMMENT ON COLUMN videos.pvector_chunk IS 'Vectors stored in PostgreSQL'; -COMMENT ON COLUMN videos.qvector_chunk IS 'Vectors stored in Qdrant'; -``` - -### 3.2 表關係圖 - -``` -videos monitor_jobs -┌──────────────────────┐ ┌──────────────────────┐ -│ id (PK) │◄────────│ video_id (FK) │ -│ uuid │ │ user_id │ -│ status │ │ processors[] │ -│ fs_video │ │ completed_processors[]│ -│ fs_json │ │ failed_processors[] │ -│ job_id (FK)─────────┼────────►│ status │ -│ user_id │ │ id (PK) │ -└──────────────────────┘ └──────────────────────┘ - │ - │ - processor_results - ┌──────────────────────┐ - │ job_id (FK) │ - │ video_id (FK) │ - │ processor │ - │ status │ - │ progress_current │ - │ last_checkpoint │ - │ id (PK) │ - └──────────────────────┘ -``` - ---- - -## 4. 模組並行策略 - -### 4.1 模組分類 - -| 模組 | 資源需求 | 獨立性 | 建議並行 | -|------|----------|--------|----------| -| ASR | GPU/CPU | 高 | ✅ 可並行 | -| CUT | CPU | 高 | ✅ 可並行 | -| YOLO | GPU | 中 | ✅ 可並行 | -| OCR | GPU/CPU | 高 | ✅ 可並行 | -| Face | GPU | 中 | ✅ 可並行 | -| Pose | GPU | 中 | ✅ 可並行 | -| ASRX | GPU/CPU | 高 | ✅ 可並行 | - -### 4.2 建議並行組合 - -| 組合 | 模組 1 | 模組 2 | 說明 | -|------|---------|---------|------| -| GPU+CPU | YOLO/Pose/Face | ASR/CUT/OCR | 平衡負載 | -| 雙GPU | YOLO | Pose | 雙 GPU 卡片 | -| 雙CPU | ASR | CUT/OCR | 無 GPU 時 | - -### 4.3 Worker 配置 - -```rust -// src/worker/config.rs - -#[derive(Debug, Clone)] -pub struct WorkerConfig { - pub max_concurrent: usize, // 預設 2 - pub poll_interval_secs: u64, // 預設 5 - pub enabled: bool, // 預設 true -} - -impl Default for WorkerConfig { - fn default() -> Self { - Self { - max_concurrent: 2, - poll_interval_secs: 5, - enabled: true, - } - } -} - -impl WorkerConfig { - pub fn from_env() -> Self { - Self { - max_concurrent: std::env::var("MOMENTRY_MAX_CONCURRENT") - .ok() - .and_then(|v| v.parse().ok()) - .unwrap_or(2), - poll_interval_secs: std::env::var("MOMENTRY_POLL_INTERVAL") - .ok() - .and_then(|v| v.parse().ok()) - .unwrap_or(5), - enabled: std::env::var("MOMENTRY_WORKER_ENABLED") - .ok() - .map(|v| v != "false") - .unwrap_or(true), - } - } -} -``` - ---- - -## 5. 失敗處理機制 - -### 5.1 設計原則 - -``` -每個模組獨立處理: -- 成功 → 產出完整 .json,status=completed -- 失敗 → 產出 .json 包含 error 狀態,status=failed -- 部分完成 → 可從 checkpoint 繼續,status=running -``` - -### 5.2 Processor 輸出格式 - -```json -{ - "processor": "asr", - "status": "completed|failed|partial", - "completed_at": "2026-03-24T12:00:00Z", - "result": { ... }, - "error": null, - "last_checkpoint": { - "frame": 5000, - "timestamp": 180.5 - } -} -``` - -### 5.3 失敗處理流程 - -```rust -async fn run_processor(&self, module: &str, video: &Video) -> Result<()> { - let output_path = self.get_output_path(video, module); - - match self.execute_processor(module, video, &output_path).await { - Ok(result) => { - // 成功:更新狀態 - self.db.update_processor_status(job_id, module, "completed").await?; - self.publish_progress(job_id, module, 100).await?; - } - Err(e) => { - // 失敗:仍然保存部分結果 - let partial_result = self.get_partial_result(&output_path); - self.db.update_processor_status(job_id, module, "failed").await?; - self.db.save_error_message(job_id, module, &e.to_string()).await?; - - // 記錄錯誤但不中斷其他模組 - tracing::warn!("Processor {} failed: {}", module, e); - } - } - - Ok(()) -} -``` - ---- - -## 6. 實作結構 - -### 6.1 目錄結構 - -``` -src/ -├── worker/ -│ ├── mod.rs # Worker 模組導出 -│ ├── config.rs # Worker 配置 -│ ├── worker.rs # Worker 主邏輯 -│ ├── processor.rs # Processor 執行器 -│ ├── queue.rs # Job 佇列管理 -│ └── progress.rs # 進度追蹤 -├── api/ -│ └── server.rs # 更新 Register API -└── main.rs # 新增 worker 命令 -``` - -### 6.2 核心模組 - -#### 6.2.1 Worker Config (`src/worker/config.rs`) - -```rust -pub struct WorkerConfig { - pub max_concurrent: usize, - pub poll_interval_secs: u64, - pub enabled: bool, -} - -impl WorkerConfig { - pub fn from_env() -> Self { ... } -} -``` - -#### 6.2.2 Worker Loop (`src/worker/worker.rs`) - -```rust -pub struct JobWorker { - db: PostgresDb, - redis: RedisCache, - config: WorkerConfig, - semaphore: Arc, -} - -impl JobWorker { - pub async fn run(&self) -> Result<()> { - loop { - if self.config.enabled { - self.process_pending_jobs().await?; - } - tokio::time::sleep(Duration::from_secs(self.config.poll_interval_secs)).await; - } - } - - async fn process_pending_jobs(&self) -> Result<()> { - // 1. 檢查並發數 - // 2. 取得 pending jobs - // 3. 分配給 worker pool - // 4. 並行執行 processors - } -} -``` - -#### 6.2.3 Processor Pool (`src/worker/processor.rs`) - -```rust -pub struct ProcessorPool { - max_concurrent: usize, -} - -impl ProcessorPool { - pub async fn execute(&self, job: &Job, video: &Video) -> Result { - // 根據 videos 表決定需要執行哪些 processor - // 並行執行最多 2 個 - // 處理失敗但不中斷其他 processor - } -} -``` - ---- - -## 7. API 端點設計 - -### 7.1 新增端點 - -| 端點 | 方法 | 說明 | -|------|------|------| -| `/api/v1/jobs` | GET | 列出所有 jobs | -| `/api/v1/jobs/:uuid` | GET | 取得特定 job 詳細 | -| `/api/v1/jobs/:uuid/retry` | POST | 重試失敗的 processor | -| `/api/v1/jobs/:uuid/cancel` | POST | 取消 job | - -### 7.2 端點詳情 - -#### GET /api/v1/jobs - -```json -Response: -{ - "jobs": [ - { - "id": 1, - "uuid": "abc123def456", - "status": "running", - "progress": 60, - "processors": ["asr", "cut", "yolo", "ocr", "face", "pose"], - "completed": ["asr", "cut", "yolo"], - "failed": [] - } - ] -} -``` - -#### GET /api/v1/jobs/:uuid - -```json -Response: -{ - "id": 1, - "uuid": "abc123def456", - "video_id": 10, - "status": "running", - "processors": { - "asr": {"status": "completed", "progress": 100}, - "cut": {"status": "completed", "progress": 100}, - "yolo": {"status": "running", "progress": 45, "current": 5000, "total": 11000}, - "ocr": {"status": "pending"}, - "face": {"status": "pending"}, - "pose": {"status": "pending"} - }, - "created_at": "2026-03-24T12:00:00Z", - "started_at": "2026-03-24T12:01:00Z" -} -``` - ---- - -## 8. Redis Key 設計 - -### 8.1 現有 Key 保持 - -```bash -momentry:job:{uuid} # Job Hash -momentry:job:{uuid}:processor:{name} # Processor Hash -momentry:progress:{uuid} # Pub/Sub Channel -momentry:jobs:active # Set: 運行中 UUIDs -momentry:jobs:completed # Set: 完成 UUIDs -momentry:jobs:failed # Set: 失敗 UUIDs -``` - -### 8.2 進度更新時序 - -``` -Processor 執行 - │ - ├─► 每秒更新 Redis Hash (即時) - │ - ├─► 每 10% 或完成時更新 PostgreSQL (持久) - │ - └─► 失敗時立即更新 PostgreSQL (錯誤記錄) -``` - ---- - -## 9. 實作順序 - -### Phase 1: 資料庫遷移 - -| 任務 | 說明 | -|------|------| -| 1.1 | 建立 `migrations/003_job_worker.sql` | -| 1.2 | 更新 `postgres_db.rs` 對應的 struct | -| 1.3 | 執行 migration 驗證 | - -### Phase 2: Worker 框架 - -| 任務 | 說明 | -|------|------| -| 2.1 | 建立 `src/worker/mod.rs` | -| 2.2 | 建立 `src/worker/config.rs` | -| 2.3 | 建立 `src/worker/worker.rs` | -| 2.4 | 建立 `src/worker/processor.rs` | - -### Phase 3: Register API 整合 - -| 任務 | 說明 | -|------|------| -| 3.1 | 修改 `src/api/server.rs` 的 register 函數 | -| 3.2 | 加入建立 monitor_jobs 的邏輯 | -| 3.3 | 更新 videos 表 status 欄位 | - -### Phase 4: Processor 執行 - -| 任務 | 說明 | -|------|------| -| 4.1 | 實作 processor 並行執行(最多 2 個) | -| 4.2 | 實作失敗處理(保存部分結果) | -| 4.3 | 實作 checkpoint 恢復 | - -### Phase 5: 進度追蹤 - -| 任務 | 說明 | -|------|------| -| 5.1 | Redis Pub/Sub 整合 | -| 5.2 | PostgreSQL 定期同步 | -| 5.3 | API 進度端點更新 | - -### Phase 6: API 端點 - -| 任務 | 說明 | -|------|------| -| 6.1 | GET /api/v1/jobs | -| 6.2 | GET /api/v1/jobs/:uuid | -| 6.3 | POST /api/v1/jobs/:uuid/retry | -| 6.4 | POST /api/v1/jobs/:uuid/cancel | - -### Phase 7: CLI 命令 - -| 任務 | 說明 | -|------|------| -| 7.1 | `cargo run -- worker` 命令 | -| 7.2 | Worker 啟動/停止/狀態顯示 | -| 7.3 | launchd plist 設定 | - -### Phase 8: 測試 - -| 任務 | 說明 | -|------|------| -| 8.1 | 單元測試 | -| 8.2 | 端到端測試 | -| 8.3 | 失敗處理測試 | -| 8.4 | 並行執行測試 | - ---- - -## 10. CLI 命令 - -### 10.1 Worker 命令 - -```bash -# 啟動 worker -cargo run -- worker - -# 顯示 worker 幫助 -cargo run -- worker --help -``` - -### 10.2 環境變數 - -```bash -# Worker 配置 -export MOMENTRY_MAX_CONCURRENT=2 -export MOMENTRY_POLL_INTERVAL=5 -export MOMENTRY_WORKER_ENABLED=true - -# 現有環境變數 -export DATABASE_URL=postgres://accusys@localhost:5432/momentry -export REDIS_URL=redis://:accusys@localhost:6379 -``` - ---- - -## 11. 預估工時 - -| Phase | 任務 | 預估工時 | -|-------|------|----------| -| 1 | 資料庫遷移 | 2h | -| 2 | Worker 框架 | 4h | -| 3 | Register API 整合 | 2h | -| 4 | Processor 執行 | 4h | -| 5 | 進度追蹤 | 2h | -| 6 | API 端點 | 3h | -| 7 | CLI 命令 | 2h | -| 8 | 測試 | 4h | -| **總計** | | **23h** | - ---- - -## 12. 參考文件 - -| 文件 | 用途 | -|------|------| -| `docs/MOMENTRY_CORE_MONITORING.md` | 監控系統規範 | -| `docs/MOMENTRY_CORE_REDIS_KEYS.md` | Redis Key 設計 | -| `docs/PROCESSING_PIPELINE.md` | 處理流程 | -| `docs/CHUNK_DESIGN.md` | 資料庫設計 | -| `docs/API_REFERENCE.md` | API 參考 | - ---- - -## 13. 附錄 - -### A. 狀態機 - -``` - ┌──────────────┐ - │ PENDING │ - └──────┬───────┘ - │ register 後 - ▼ - ┌──────────────┐ - ┌─────▶│ PROCESSING │◀──────┐ - │ └──────┬───────┘ │ - │ │ │ - 部分失敗 all completed 全部失敗 - │ │ │ - ▼ ▼ ▼ - ┌──────────┐ ┌──────────┐ ┌──────────┐ - │ PARTIAL │ │COMPLETED │ │ FAILED │ - └──────────┘ └──────────┘ └──────────┘ -``` - -### B. videos 表 status 欄位 - -| 值 | 說明 | -|------|------| -| `pending` | 已註冊,等待處理 | -| `processing` | 處理中 | -| `completed` | 所有處理完成 | -| `failed` | 處理失敗 | - -### C. processor_results 表 status 欄位 - -| 值 | 說明 | -|------|------| -| `pending` | 等待執行 | -| `running` | 執行中 | -| `completed` | 執行成功 | -| `failed` | 執行失敗 | -| `skipped` | 跳過(如檔案已存在) | diff --git a/docs_v1.0/ARCHITECTURE/ROOT_MAC_INSTALLATION_PLAN.md b/docs_v1.0/ARCHITECTURE/ROOT_MAC_INSTALLATION_PLAN.md deleted file mode 100644 index e179de4..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_MAC_INSTALLATION_PLAN.md +++ /dev/null @@ -1,782 +0,0 @@ -# Momentry 系統自動化安裝計劃 - -> **計劃階段** - 僅供討論,尚未執行 -> **建立時間**: 2026-03-23 -> **目標**: Thunderbolt NVMe 外開機完整安裝 - ---- - -## 系統概述 - -### 當前環境 -| 項目 | 內容 | -|------|------| -| **主控機** | Mac mini (M4, 16GB RAM) | -| **作業系統** | macOS 26.3.1 (Tahoe) | -| **儲存** | Thunderbolt NVMe (2TB) | -| **用途** | 開機碟 + 完整 Momentry 系統 | - -### 目標環境 -| 項目 | 內容 | -|------|------| -| **目標主機** | 其他 Mac (Intel 或 Apple Silicon) | -| **安裝方式** | Thunderbolt NVMe 外接開機 | -| **連接方式** | Thunderbolt 3/4 | -| **控制方式** | SSH 遠端管理 | - ---- - -## 系統架構 - -### 服務列表 - -| 服務 | 版本 | 用途 | Port | -|------|------|------|------| -| **PostgreSQL** | 18.1 | 主資料庫、n8n 資料庫 | 5432 | -| **MongoDB** | 8.0 | 文件資料庫 | 27017 | -| **MariaDB** | 11.4 | WordPress 資料庫 | 3306 | -| **Redis** | 7.x | 快取、佇列 | 6379 | -| **Qdrant** | 1.7.x | 向量資料庫 | 6333 | -| **Ollama** | 0.13.5 | 本地 LLM | 11434 | -| **Caddy** | 2.x | 反向代理 | 80/443 | -| **Gitea** | 1.21 | Git 服務 | 3000 | -| **PHP-FPM** | 8.5 | WordPress | 9000 | -| **n8n** | 2.3.5 | 工作流程自動化 | 5678 | -| **RustDesk** | hbbs/hbbr | 遠端桌面 | 21115-21119 | -| **SFTPGo** | 2.x | SFTP 服務 | 2022 | -| **Momentry Core** | 0.1.0 | 影片處理核心 | 3002 | -| **Prometheus** | 3.9.1 | 監控 | 9090 | - -### 目錄結構 - -``` -/Volumes/Momentry/ -├── System/ -│ └── macOS/ # macOS 系統 -├── Applications/ -│ └── Homebrew/ # Homebrew 應用程式 -├── momentry/ -│ ├── var/ # 資料目錄 -│ │ ├── postgresql/ # PostgreSQL 資料 -│ │ ├── mongodb/ # MongoDB 資料 -│ │ ├── mariadb/ # MariaDB 資料 -│ │ ├── redis/ # Redis 資料 -│ │ ├── qdrant/ # Qdrant 資料 -│ │ ├── n8n/ # n8n 資料 -│ │ ├── ollama/ # Ollama 模型 -│ │ └── ... -│ ├── etc/ # 配置檔案 -│ │ ├── Caddyfile -│ │ ├── gitea/ -│ │ ├── php/ -│ │ └── ... -│ ├── log/ # 日誌 -│ ├── scripts/ # 管理腳本 -│ └── backup/ # 備份 -├── momentry_core/ # Rust 原始碼 -└── momentry_dashboard/ # Web Dashboard -``` - ---- - -## 階段一:前置準備 - -### 1.1 收集目標主機資訊 - -```bash -# 需要收集的資訊 -- Mac 型號 (Intel/Apple Silicon) -- macOS 版本 -- Thunderbolt 版本 (3/4) -- 可用記憶體 -- 目標磁碟代號 (diskX) -- 網路配置 (DHCP/固定 IP) -``` - -### 1.2 準備 Thunderbolt NVMe - -```bash -# 檢查 Thunderbolt NVMe -diskutil list external - -# 預期輸出: -# /dev/diskX (external, physical): -# NAME TYPE SIZE -# Thunderbolt NVMe ... -``` - -### 1.3 準備主控機腳本 - -```bash -# 主控機需要準備的腳本 -~/momentry/setup/ -├── 01_prepare_disk.sh -├── 02_install_macos.sh -├── 03_install_homebrew.sh -├── 04_install_dependencies.sh -├── 05_install_services.sh -├── 06_install_momentry.sh -├── 07_configure_network.sh -├── 08_start_services.sh -└── utils/ - ├── common.sh - ├── backup.sh - └── monitor.sh -``` - ---- - -## 階段二:Thunderbolt NVMe 準備 - -### 2.1 分割磁碟方案 A(推薦) - -```bash -# 磁碟分割配置 -diskutil partitionDisk /dev/diskX \ - GPT \ - "APFS System" APFS "Momentry System" 200G \ - "APFS Data" APFS "Momentry Data" 1.8T -``` - -### 2.2 分割磁碟方案 B(最小化) - -```bash -# 統一 APFS 容器 -diskutil partitionDisk /dev/diskX \ - GPT \ - APFS "Momentry" 100% -``` - ---- - -## 階段三:安裝 macOS - -### 3.1 建立 macOS 安裝碟 - -```bash -# 下載 macOS Sonoma (或最新版本) -softwareupdate --fetch-full-installer --full-installer-version 14.0 - -# 建立可開機安裝碟 -sudo /Applications/Install\ macOS\ Sonoma.app/Contents/Resources/createinstallinstmedi \ - --volume /Volumes/Momentry \ - --nointeraction -``` - -### 3.2 安裝 macOS 到 Thunderbolt NVMe - -**兩種方法:** - -#### 方法 A: 復原模式安裝 -1. 連接 Thunderbolt NVMe -2. 重啟目標主機,按住Option鍵 -3. 選擇 Thunderbolt NVMe 開機 -4. 進入 Recovery Mode (Command+R) -5. 使用 Disk Utility 格式化目標磁碟 -6. 安裝 macOS - -#### 方法 B: ASR 複製(建議) -```bash -# 從主控機執行 -# 將現有系統複製到目標磁碟 -sudo asr restore \ - --source /Volumes/Macintosh\ HD \ - --target /Volumes/Momentry \ - --erase --noprompt -``` - -### 3.3 設定 macOS - -```bash -# 自動化設定腳本 -./setup/scripts/03_install_homebrew.sh -``` - -**設定項目:** -- 電腦名稱:`momentry-` -- 使用者帳號:`momentry` (管理員) -- SSH 遠端登入:啟用 -- 螢幕鎖定:關閉 -- 節能設定:永不休眠 - ---- - -## 階段四:安裝 Homebrew - -### 4.1 安裝 Homebrew - -```bash -#!/bin/bash -# 04_install_homebrew.sh - -# 檢查架構 -ARCH=$(uname -m) - -if [ "$ARCH" = "arm64" ]; then - # Apple Silicon - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile - eval "$(/opt/homebrew/bin/brew shellenv)" -elif [ "$ARCH" = "x86_64" ]; then - # Intel - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile - eval "$(/usr/local/bin/brew shellenv)" -fi - -# 驗證 -brew --version -``` - -### 4.2 安裝基礎工具 - -```bash -# 基礎開發工具 -brew install \ - git \ - curl \ - wget \ - jq \ - yq \ - tree \ - htop \ - tmux \ - zsh \ - zsh-completions -``` - ---- - -## 階段五:安裝服務 - -### 5.1 安裝資料庫服務 - -```bash -#!/bin/bash -# 05_install_services.sh - -# PostgreSQL -brew install postgresql@18 -brew services start postgresql@18 - -# MongoDB -brew tap mongodb/brew -brew install mongodb-community -brew services start mongodb-community - -# MariaDB -brew install mariadb -brew services start mariadb - -# Redis -brew install redis -brew services start redis - -# Qdrant (需要 Cargo) -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -cargo install qdrant -``` - -### 5.2 安裝應用服務 - -```bash -# Ollama -brew install ollama -brew services start ollama - -# Caddy -brew install caddy -brew services start caddy - -# Gitea -brew install gitea -brew services start gitea - -# PHP -brew install php -brew services start php - -# n8n -brew install n8n -brew services start n8n -``` - -### 5.3 Launchd 服務配置 - -```xml - - - - - - Label - com.momentry.postgresql - UserName - momentry - ProgramArguments - - /opt/homebrew/opt/postgresql@18/bin/postgres - -D - /Volumes/Momentry/momentry/var/postgresql - - RunAtLoad - - KeepAlive - - StandardOutPath - /Volumes/Momentry/momentry/log/postgresql.log - StandardErrorPath - /Volumes/Momentry/momentry/log/postgresql.error.log - - -``` - ---- - -## 階段六:安裝 Momentry Core - -### 6.1 複製原始碼 - -```bash -#!/bin/bash -# 06_install_momentry.sh - -# 建立 Momentry 目錄 -mkdir -p /Volumes/Momentry/momentry/{var,etc,log,scripts,backup} -mkdir -p /Volumes/Momentry/momentry_core - -# 複製原始碼 -rsync -av \ - --exclude 'target' \ - --exclude '.git' \ - --exclude 'node_modules' \ - /Users/accusys/momentry_core_0.1/ \ - /Volumes/Momentry/momentry_core/ - -# 編譯 Rust 專案 -cd /Volumes/Momentry/momentry_core -cargo build --release -``` - -### 6.2 初始化資料庫 - -```bash -# 建立 PostgreSQL 資料庫 -psql -U postgres < "$BACKUP_DIR/momentry.sql" -pg_dump -U n8n n8n > "$BACKUP_DIR/n8n.sql" - -# 2. MongoDB 備份 -mongodump --out "$BACKUP_DIR/mongodb" - -# 3. Redis 備份 -redis-cli BGSAVE -cp /Volumes/Momentry/var/redis/dump.rdb "$BACKUP_DIR/redis.rdb" - -# 4. Qdrant 備份 -curl -X POST http://localhost:6333/collections/accusysdb/snapshots - -# 5. 配置檔案備份 -tar -czf "$BACKUP_DIR/config.tar.gz" \ - /Volumes/Momentry/momentry/etc/ -``` - -### 9.2 自動備份 Cron - -```bash -# crontab -e -0 2 * * * /Volumes/Momentry/scripts/backup.sh -0 3 * * 0 /Volumes/Momentry/scripts/backup_full.sh -``` - ---- - -## 階段十:監控與維護 - -### 10.1 健康檢查腳本 - -```bash -#!/bin/bash -# health_check.sh - -# 檢查所有服務 -check_postgresql() { - pg_isready -q && echo "✅ PostgreSQL" || echo "❌ PostgreSQL" -} - -check_mongodb() { - mongosh --eval "db.stats()" > /dev/null 2>&1 && echo "✅ MongoDB" || echo "❌ MongoDB" -} - -check_redis() { - redis-cli ping > /dev/null 2>&1 && echo "✅ Redis" || echo "❌ Redis" -} - -check_qdrant() { - curl -s http://localhost:6333/health && echo "✅ Qdrant" || echo "❌ Qdrant" -} - -check_n8n() { - curl -s http://localhost:5678/api/v1/workflows > /dev/null 2>&1 && echo "✅ n8n" || echo "❌ n8n" -} - -check_momentry() { - curl -s http://localhost:3002/api/v1/videos > /dev/null 2>&1 && echo "✅ Momentry" || echo "❌ Momentry" -} -``` - -### 10.2 日誌輪替 - -```bash -# 新聞日誌配置 -/Volumes/Momentry/momentry/log/*.log { - daily - rotate 7 - compress - missingok - notifempty - create 644 momentry staff -} -``` - ---- - -## 自動化腳本架構 - -### 主控腳本:部署控制器 - -```bash -#!/bin/bash -# deploy_controller.sh -# 用於從主控機部署到目標主機 - -set -e - -# 配置 -TARGET_HOST="momentry@192.168.1.100" -TARGET_DISK="/dev/disk2" - -# 顏色定義 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -function log_info() { - echo -e "${GREEN}[INFO]${NC} $1" -} - -function log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} - -function log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# 階段執行 -function run_stage() { - local stage=$1 - local script=$2 - - log_info "執行階段: $stage..." - ssh "$TARGET_HOST" "bash /Volumes/Momentry/scripts/$script" - - if [ $? -eq 0 ]; then - log_info "✅ 階段完成: $stage" - else - log_error "❌ 階段失敗: $stage" - exit 1 - fi -} - -# 主程序 -log_info "開始 Momentry 系統部署..." - -# 執行各階段 -run_stage "磁碟準備" "01_prepare_disk.sh" -run_stage "macOS 安裝" "02_install_macos.sh" -run_stage "Homebrew 安裝" "03_install_homebrew.sh" -run_stage "依賴安裝" "04_install_dependencies.sh" -run_stage "服務安裝" "05_install_services.sh" -run_stage "Momentry 安裝" "06_install_momentry.sh" -run_stage "網路配置" "07_configure_network.sh" -run_stage "啟動服務" "08_start_services.sh" - -log_info "✅ 部署完成!" -``` - ---- - -## 待確認事項 - -### 需要與使用者確認 - -1. **目標主機型號** - - Intel Mac 或 Apple Silicon? - - Thunderbolt 版本 (3/4)? - -2. **網路配置** - - DHCP 或固定 IP? - - 目標 IP 網段? - -3. **磁碟配置** - - 分割方案 A (200G 系統 + 1.8T 資料)? - - 分割方案 B (統一磁碟區)? - -4. **服務需求** - - 需要安裝全部服務? - - 還是選擇性安裝? - -5. **備份策略** - - 本地備份? - - 遠端備份? - - 備份頻率? - -6. **監控需求** - - Prometheus + Grafana? - - 簡單腳本監控? - ---- - -## 預估時間 - -| 階段 | 預估時間 | 備註 | -|------|---------|------| -| 前置準備 | 30 分鐘 | 收集資訊、準備腳本 | -| 磁碟準備 | 10 分鐘 | 分割格式化 | -| macOS 安裝 | 30-60 分鐘 | 視 USB 速度 | -| Homebrew 安裝 | 15 分鐘 | 下載速度 | -| 服務安裝 | 60-90 分鐘 | 多個服務 | -| Momentry 安裝 | 20 分鐘 | 編譯 Rust | -| 網路配置 | 10 分鐘 | 固定 IP | -| 服務啟動 | 15 分鐘 | 依序啟動 | -| 驗證測試 | 30 分鐘 | 完整測試 | -| **總計** | **3-4 小時** | 自動化後可縮短 | - ---- - -## 風險與應對 - -| 風險 | 機率 | 影響 | 應對措施 | -|------|------|------|---------| -| Thunderbolt 不相容 | 低 | 高 | 準備多種驅動 | -| macOS 安裝失敗 | 低 | 高 | 準備還原方案 | -| 服務啟動失敗 | 中 | 中 | 日誌診斷腳本 | -| 網路連線問題 | 中 | 中 | 有線網路備援 | -| 儲存空間不足 | 低 | 高 | 磁碟空間檢查 | - ---- - -## 下一步行動 - -1. ✅ 確認目標主機規格 -2. ✅ 確認 Thunderbolt NVMe 容量 -3. ✅ 確認網路配置 -4. ✅ 選擇服務清單 -5. ✅ 準備安裝腳本 -6. ✅ 測試腳本執行 -7. ✅ 正式部署 - ---- - -## 附錄 - -### A. 服務端口對照表 - -| 服務 | Port | 協議 | -|------|------|------| -| PostgreSQL | 5432 | TCP | -| MongoDB | 27017 | TCP | -| MariaDB | 3306 | TCP | -| Redis | 6379 | TCP | -| Qdrant API | 6333 | HTTP | -| Qdrant gRPC | 6334 | gRPC | -| Ollama | 11434 | HTTP | -| Caddy HTTP | 80 | HTTP | -| Caddy HTTPS | 443 | HTTPS | -| Gitea | 3000 | HTTP | -| PHP-FPM | 9000 | FastCGI | -| n8n | 5678 | HTTP | -| SFTPGo | 2022 | SFTP | -| RustDesk hbbs | 21115 | TCP | -| RustDesk hbbr | 21117 | TCP | -| Momentry | 3002 | HTTP | -| Prometheus | 9090 | HTTP | - -### B. 環境變數清單 - -見 `.env` 範例檔案或 `docs/MOMENTRY_CORE_MONITORING.md` - -### C. 疑難排解 - -見 `docs/PENDING_ISSUES.md` - ---- - -**計劃狀態**: 📝 草稿 - 等待使用者確認後執行 - -**負責人**: OpenCode AI Assistant - -**最後更新**: 2026-03-23 diff --git a/docs_v1.0/ARCHITECTURE/ROOT_N8N_WORKFLOW_VIDEO_RAG_MCP.md b/docs_v1.0/ARCHITECTURE/ROOT_N8N_WORKFLOW_VIDEO_RAG_MCP.md deleted file mode 100644 index e869249..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_N8N_WORKFLOW_VIDEO_RAG_MCP.md +++ /dev/null @@ -1,169 +0,0 @@ -# Momentry Video RAG MCP Workflow - -## 工作流程資訊 - -- **名稱**: Momentry Video RAG MCP -- **ID**: WlVvpX2OeKK83QOK -- **Webhook Path**: `video-rag-mcp` -- **狀態**: ✅ Active (已啟動) -- **建立時間**: 2026-03-22 - -## 工作流程架構 - -``` -┌─────────────────┐ ┌──────────────────────┐ ┌───────────────────┐ ┌─────────────────┐ -│ Webhook │────▶│ Search Momentry │────▶│ Process RAG │────▶│ Respond to │ -│ Trigger │ │ Core │ │ Results │ │ Webhook │ -└─────────────────┘ └──────────────────────┘ └───────────────────┘ └─────────────────┘ - │ - │ POST http://localhost:5678/webhook/video-rag-mcp - │ - ▼ -{ - "query": "搜尋關鍵字", - "limit": 5, - "uuid": "可選的影片UUID" -} -``` - -## Node 說明 - -### 1. Webhook Trigger -- **類型**: Webhook -- **Method**: POST -- **Path**: `video-rag-mcp` -- **Response Mode**: Last Node (等待最後一個節點完成後回應) - -### 2. Search Momentry Core -- **類型**: HTTP Request -- **URL**: `http://localhost:3002/api/v1/n8n/search` -- **Method**: POST -- **Body**: - ```json - { - "query": "搜尋關鍵字", - "limit": 5, - "uuid": "可選的影片UUID" - } - ``` -- **Timeout**: 30秒 - -### 3. Process RAG Results -- **類型**: Code (JavaScript) -- **功能**: - - 處理 Momentry Core 搜尋結果 - - 格式化 hits 為結構化資料 - - 建立 RAG context(用於 LLM 問答) - - 計算相關度百分比 - -**輸出格式**: -```json -{ - "success": true, - "query": "搜尋關鍵字", - "totalFound": 5, - "context": "[1] 文本內容... (Video: 影片標題, Time: 10s-20s)\n\n[2] ...", - "results": [ - { - "index": 1, - "id": "chunk_id", - "title": "影片標題", - "text": "文本內容", - "startTime": 10, - "endTime": 20, - "relevance": "85%", - "videoUuid": "uuid", - "mediaUrl": "影片URL", - "deepLink": "影片URL#t=10,20" - } - ] -} -``` - -### 4. Respond to Webhook -- **類型**: Respond to Webhook -- **Response**: JSON 格式結果 -- **Status Code**: 200 - -## 使用方式 - -### 直接呼叫 Webhook - -```bash -curl -X POST http://localhost:5678/webhook/video-rag-mcp \ - -H "Content-Type: application/json" \ - -d '{ - "query": "charade", - "limit": 5 - }' -``` - -### 指定特定影片搜尋 - -```bash -curl -X POST http://localhost:5678/webhook/video-rag-mcp \ - -H "Content-Type: application/json" \ - -d '{ - "query": "audrey hepburn", - "limit": 3, - "uuid": "a1b10138a6bbb0cd" - }' -``` - -### 在 n8n 工作流程中使用 - -可以將此 Webhook 作為子工作流程觸發器,或使用 HTTP Request Node 呼叫: - -```json -{ - "name": "Call Video RAG", - "type": "n8n-nodes-base.httpRequest", - "parameters": { - "url": "http://localhost:5678/webhook/video-rag-mcp", - "method": "POST", - "body": { - "query": "={{ $json.searchTerm }}", - "limit": 5 - } - } -} -``` - -## RAG Context 用途 - -工作流程產生的 `context` 欄位可直接用於 LLM 提示: - -```javascript -// Example: 使用 context 進行問答 -const prompt = ` -基於以下影片片段資訊回答問題: - -${context} - -問題:${userQuestion} - -請根據上述內容提供準確的答案。 -`; -``` - -## 相關文件 - -- [Momentry Core API 文件](./API_ACCESS.md) -- [n8n MCP 測試報告](./N8N_MCP_TEST_REPORT.md) -- [N8N_DEMO_WORKFLOW.md](./N8N_DEMO_WORKFLOW.md) - 完整工作流程設計 - -## MCP 建立指令 - -此工作流程是透過 MCP 工具建立的: - -```bash -# 使用 MCP 建立工作流程 -node create_workflow.js | mcp-n8n - -# 使用 MCP 啟動工作流程 -echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"n8n_activate_workflow","arguments":{"workflowId":"WlVvpX2OeKK83QOK"}}}' | mcp-n8n -``` - -## 工作流程檔案 - -- 原始檔案: `docs/n8n_workflow_video_rag_mcp.json` diff --git a/docs_v1.0/ARCHITECTURE/ROOT_PROCESSING_PIPELINE.md b/docs_v1.0/ARCHITECTURE/ROOT_PROCESSING_PIPELINE.md deleted file mode 100644 index 3ebd733..0000000 --- a/docs_v1.0/ARCHITECTURE/ROOT_PROCESSING_PIPELINE.md +++ /dev/null @@ -1,292 +0,0 @@ -# Video Processing Pipeline - 處理流程 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-22 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode | -| V1.1 | 2026-03-26 | 更新流程圖文字 (media_url→file_path) | OpenCode | deepseek-reasoner | - ---- - -## 處理流程架構 - -``` -┌─────────────────────────────────────────────────────────────────────────────┐ -│ Video Processing Pipeline │ -├─────────────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 1: JSON 生成 (Process) │ │ -│ │ │ │ -│ │ video.mp4 ──→ [ASR] ──→ asr.json (語音辨識) │ │ -│ │ ──→ [CUT] ──→ cut.json (場景偵測) │ │ -│ │ ──→ [ASRX] ──→ asrx.json (說話者分離) │ │ -│ │ ──→ [YOLO] ──→ yolo.json (物體偵測) │ │ -│ │ ──→ [OCR] ──→ ocr.json (文字辨識) │ │ -│ │ ──→ [Face] ──→ face.json (人臉偵測) │ │ -│ │ ──→ [Pose] ──→ pose.json (姿態估計) │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 2: 入庫 (Import) │ │ -│ │ │ │ -│ │ .json files ──→ PostgreSQL (fs_json = true) │ │ -│ │ ↓ │ │ -│ │ pre_chunks 表 (from ASR, CUT) │ │ -│ │ frames 表 (from YOLO, OCR, Face, Pose) │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 3: Chunk 生成 (Chunk) │ │ -│ │ │ │ -│ │ pre_chunks ──→ [Chunk Rule] ──→ chunks 表 │ │ -│ │ ↓ │ │ -│ │ 清洗 → 純文字 │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 4: 向量化 (Vectorize) │ │ -│ │ │ │ -│ │ chunks ──→ [Embedding Model] ──→ vectors │ │ -│ │ ↓ │ │ -│ │ Qdrant (主要向量庫) │ │ -│ │ PGVector (備份向量庫) │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 5: 搜尋 (Search) │ │ -│ │ │ │ -│ │ Natural Language Query ──→ [Embedding] ──→ [Qdrant Search] │ │ -│ │ ↓ │ │ -│ │ 返回結果含 file_path │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────────────┘ -``` - ---- - -## CLI 命令 - -### Stage 1: JSON 生成 (Process) - -```bash -# 基本用法 -cargo run --bin momentry -- process - -# 只處理特定模組 -cargo run --bin momentry -- process --modules asr,cut - -# 強制重新處理(忽略完整性檢查) -cargo run --bin momentry -- process --force - -# 從中斷點續傳 -cargo run --bin momentry -- process --resume - -# 模組使用雲端處理 -cargo run --bin momentry -- process --modules yolo,face --cloud yolo - -# 完整範例 -cargo run --bin momentry -- process /path/to/video.mp4 \ - --modules asr,cut,yolo,ocr \ - --cloud yolo -``` - -### Stage 2: 入庫 (Import) - -```bash -# 目前入庫在 process 完成後自動執行 -# 計劃新增獨立的 import 命令 -# cargo run --bin momentry -- import -``` - -### Stage 3: Chunk 生成 - -```bash -# 生成 chunks -cargo run --bin momentry -- chunk -``` - -### Stage 4: 向量化 - -```bash -# 向量化 chunks(使用預設模型 nomic-embed-text-v2-moe:latest) -cargo run --bin momentry -- vectorize - -# 明確指定模型 -cargo run --bin momentry -- vectorize --model nomic-embed-text-v2-moe:latest -``` - ---- - -## 處理模式選項 - -### --force (強制重新處理) - -- 刪除現有的 JSON 檔案 -- 從頭開始處理 -- 適用於:處理失敗、模型更新、需要重新處理 - -```bash -# 強制重新處理 YOLO -cargo run --bin momentry -- process --modules yolo --force -``` - -### --resume (續傳) - -- 檢查現有 JSON 的進度 -- 從中斷點繼續處理 -- 適用於:處理中斷、系統崩潰後恢復 - -```bash -# 從上次中斷點繼續 -cargo run --bin momentry -- process --resume -``` - -### 預設行為 (Smart Mode) - -- 如果 JSON 完全:跳過 -- 如果 JSON 不完整:警告 + 跳過(需要 --resume 或 --force) -- 如果 JSON 不存在:處理 - -``` -Output: -ASR: ✓ Already complete, skipping - -⚠️ Found incomplete JSON file: /path/to/yolo.json - Progress: 73800/412343 (17.9%) - Use --resume to continue from checkpoint - Use --force to reprocess from scratch -YOLO: ✓ Already complete, skipping -``` - ---- - -## 可用模組 - -| 模組 | 功能 | 輸出 | 用途 | -|------|------|------|------| -| asr | 自動語音辨識 | asr.json | 語音轉文字 | -| cut | 場景偵測 | cut.json | 影片分段 | -| asrx | 說話者分離 | asrx.json | 多人對話分析 | -| yolo | 物體偵測 | yolo.json | 物體辨識 | -| ocr | 文字辨識 | ocr.json | 畫面文字 | -| face | 人臉偵測 | face.json | 人臉辨識 | -| pose | 姿態估計 | pose.json | 人體姿態 | - ---- - -## 向量化模型選擇 - -### 統一嵌入模型 -Momentry Core 統一使用 **`nomic-embed-text-v2-moe:latest`** 作為所有規則的嵌入模型: - -```bash -# 統一模型(所有 Rule 1/2/3 使用) ---model nomic-embed-text-v2-moe:latest -``` - -### 模型特性 -| 特性 | 說明 | -|------|------| -| **模型名稱** | `nomic-embed-text-v2-moe:latest` | -| **向量維度** | 768 維 | -| **多語言支持** | ✅ 完整支持(英語、中文、日語、韓語等) | -| **模型架構** | Mixture of Experts (MoE) | -| **推理速度** | 快速,適合實時應用 | - -### 使用方式 -```bash -# 向量化命令 -cargo run --bin momentry -- vectorize --model nomic-embed-text-v2-moe:latest -``` - ---- - -## 資料庫儲存 - -### PostgreSQL (主要關聯式資料庫) - -- 影片資訊 -- Chunks 資料 -- Pre-chunks 資料 -- Frames 資料 -- 使用者資料 - -### Qdrant (主要向量資料庫) - -- Chunk 向量 -- 相似度搜尋 - -### PGVector (備份向量資料庫) - -- Chunk 向量副本 -- 備援機制 - ---- - -## Pipeline 狀態追蹤 - -### PostgreSQL 狀態欄位 - -```sql --- 影片處理狀態 -videos.status: 'pending' | 'processing' | 'completed' | 'failed' - --- 檔案處理狀態 -videos.fs_json: true/false -videos.fs_chunks: true/false -videos.fs_vectors: true/false - --- pre_chunks 狀態 -pre_chunks.imported: true/false - --- frames 狀態 -frames.imported: true/false - --- chunks 狀態 -chunks.cleaned: true/false -chunks.vectorized: true/false -``` - -### 進度查詢 API - -```bash -# 查詢處理進度 -curl http://localhost:3002/api/v1/progress/{uuid} - -# 回應範例 -{ - "uuid": "a1b10138a6bbb0cd", - "file_name": "video.mp4", - "overall_progress": 65, - "cpu_percent": 45.2, - "gpu_percent": 98.5, - "memory_mb": 8500, - "processors": [ - {"name": "asr", "status": "complete", "progress": 100}, - {"name": "cut", "status": "complete", "progress": 100}, - {"name": "yolo", "status": "progress", "progress": 45}, - {"name": "ocr", "status": "pending", "progress": 0} - ] -} -``` - ---- - -## 下一步 - -1. **API 端點** - 支援 --modules 和 --cloud 參數 -2. **獨立 Import 命令** - 分離入庫流程 -3. **獨立 Chunk 命令** - 分離 chunk 生成 -4. **獨立 Vectorize 命令** - 分離向量化流程 -5. **模型管理** - 新增、選擇、預覽模型 diff --git a/docs_v1.0/DEV_API_V1.0/API_REFERENCE_v1.0.0 draft.md b/docs_v1.0/DEV_API_V1.0/API_REFERENCE_v1.0.0 draft.md deleted file mode 100644 index f534207..0000000 --- a/docs_v1.0/DEV_API_V1.0/API_REFERENCE_v1.0.0 draft.md +++ /dev/null @@ -1,464 +0,0 @@ -# Momentry Core API Documentation v1.0.0 - -## 快速資訊 -- **Base URL**: `http://:3003` (開發環境) -- **Production**: `http://:3002` -- **認證方式**: Header `X-API-Key: ` -- **測試 Key**: `muser_test_001` - ---- - -## API 分類原則 - -| 分類 | 用途 | 代表端點 | -|------|------|----------| -| **健康檢查** | 系統狀態確認 | `/health` | -| **檔案管理 (Files)** | 列出、查詢檔案 | `/api/v1/files` | -| **人物管理 (People)** | Identity 搜尋、候選 | `/api/v1/people` | -| **Identity 管理** | 人物詳細資訊 | `/api/v1/identities/:uuid` | -| **搜尋 (Search)** | 文字、BM25、混合搜尋 | `/api/v1/search/*` | -| **人臉 (Face)** | 人臉辨識、列表 | `/api/v1/face/*` | -| **任務 (Jobs)** | 處理任務狀態 | `/api/v1/jobs` | -| **統計 (Stats)** | 系統統計 | `/api/v1/stats/ingest` | - -### 設計概念 -1. **Files 是核心資源**:所有影片/圖片都是 File,用 32 碼 `file_uuid` 識別 -2. **Identity 是跨檔案的人物**:一個 Identity 可出現在多個 Files -3. **People = Identity 的別名路由**:`/api/v1/people` 和 `/api/v1/identities` 指向相同資料 -4. **所有列表 API 支援分頁**:`page`, `page_size` 參數 -5. **所有操作 API 回傳統一格式**:`{ success, data, total, page, page_size }` - ---- - -## 1. 健康檢查 - -### `GET /health` -檢查系統是否運作。 - -**回應**: -```json -{ - "status": "ok", - "version": "1.0.0 (build: 2026-04-30 15:40:04)", - "uptime_ms": 348240 -} -``` - ---- - -## 2. 檔案管理 (Files) - -> **測試日期**: 2026-04-30 | **環境**: Playground (Port 3003) | **Schema**: dev - -### `GET /api/v1/files` — 列出所有檔案 - -**參數**: `page` (預設 1), `page_size` (預設 20) - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files?page=1&page_size=2" \ - -H "X-API-Key: muser_test_001" -``` - -**實際回應**: -```json -{ - "success": true, - "total": 21, - "page": 1, - "page_size": 2, - "data": [ - { - "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", - "file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "status": "ready" - } - ] -} -``` - -### `GET /api/v1/files/:uuid` — 取得檔案詳情 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files/384b0ff44aaaa1f14cb2cd63b3fea966" \ - -H "X-API-Key: muser_test_001" -``` - -**實際回應**: -```json -{ - "success": true, - "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", - "file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "metadata": { - "format": { - "duration": "6879.329524", - "width": 1920, - "height": 1080 - }, - "streams": [ - { - "codec_name": "h264", - "codec_type": "video", - "width": 1920, - "height": 1080, - "r_frame_rate": "60000/1001" - }, - { - "codec_name": "aac", - "codec_type": "audio", - "sample_rate": "44100", - "channels": 2 - } - ] - } -} -``` - -### `GET /api/v1/files/scan` — 掃描檔案系統 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files/scan" \ - -H "X-API-Key: muser_test_001" -``` - -**實際回應**: -```json -{ - "files": [ - { - "file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_size": 2361629896, - "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", - "status": "pending", - "is_registered": true, - "registration_time": "2026-04-28 18:25:14.010351+00" - } - ], - "total": 20, - "registered_count": 20, - "unregistered_count": 0 -} -``` - -### `POST /api/v1/files/register` — 註冊新檔案 - -> **⚠️ 已知問題**: 此 endpoint 在 dev 環境有 SQLx 型別綁定問題 (probe_json text vs jsonb)。不影響 marcom 團隊的 GUI 設計。 - -**Request**: -```json -{ - "file_path": "/path/to/video.mp4" -} -``` - ---- - -## 3. 人物管理 (People) - -### `GET /api/v1/people` — 列出所有人物 - -**參數**: `page`, `page_size` - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/people?page=1&page_size=3" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "total": 100, - "page": 1, - "page_size": 3, - "data": [ - { - "identity_id": "a9a90105-6d6b-46ff-92da-0c3c1a57dff4", - "name": "Trace 2 Fixed Format", - "metadata": {}, - "created_at": "2026-04-28T06:10:14.582062Z" - } - ] -} -``` - -### `POST /api/v1/people/search` — 搜尋人物 - -**Request**: -```json -{ - "query": "Trace", - "limit": 3 -} -``` - -**curl**: -```bash -curl -s -X POST "http://localhost:3003/api/v1/people/search" \ - -H "X-API-Key: muser_test_001" \ - -H "Content-Type: application/json" \ - -d '{"query":"Trace","limit":3}' -``` - -**回應**: -```json -{ - "success": true, - "total": 3, - "page": 1, - "page_size": 20, - "data": [ - { - "identity_id": "a9a90105-6d6b-46ff-92da-0c3c1a57dff4", - "name": "Trace 2 Fixed Format", - "metadata": {}, - "created_at": "2026-04-28T06:10:14.582062Z" - } - ] -} -``` - -### `GET /api/v1/people/candidates` — 列出未命名人物候選 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/people/candidates" \ - -H "X-API-Key: muser_test_001" -``` - ---- - -## 4. Identity 詳細資訊 - -### `GET /api/v1/identities/:uuid` — 取得人物詳情 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/identities/a9a90105-6d6b-46ff-92da-0c3c1a57dff4" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "uuid": "a9a90105-6d6b-46ff-92da-0c3c1a57dff4", - "name": "Trace 2 Fixed Format", - "identity_type": "people", - "source": "auto_trace", - "status": "active", - "metadata": {}, - "reference_data": { - "trace_id": 2, - "quality_avg": 0.8748, - "trace_stats": { - "start_frame": 155, - "end_frame": 297, - "avg_confidence": 0.8624, - "duration_seconds": 6.5, - "total_appearances": 143 - }, - "angles_covered": ["profile_right", "three_quarter"] - } -} -``` - -### `GET /api/v1/identities/:uuid/files` — 取得人物出現的檔案列表 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/identities/a9a90105-6d6b-46ff-92da-0c3c1a57dff4/files" \ - -H "X-API-Key: muser_test_001" -``` - ---- - -## 5. 搜尋 (Search) - -### `POST /api/v1/search` — 向量搜尋 - -**Request**: -```json -{ - "query": "person talking", - "limit": 5 -} -``` - -**回應**: -```json -{ - "results": [], - "query": "person talking" -} -``` - -### `POST /api/v1/search/bm25` — BM25 全文搜尋 - -**Request**: -```json -{ - "query": "test", - "limit": 3 -} -``` - -**回應**: -```json -{ - "results": [ - { - "uuid": "a1b10138a6bbb0cd", - "chunk_id": "sentence_1006", - "text": "...", - "bm25_score": 5.23 - } - ], - "query": "test" -} -``` - -### `POST /api/v1/search/hybrid` — 混合搜尋 (向量 + BM25) - -**Request**: -```json -{ - "query": "test", - "limit": 3 -} -``` - ---- - -## 6. 人臉 (Face) - -### `GET /api/v1/face/list` — 列出人臉 - -**必填參數**: `file_uuid` - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/face/list?file_uuid=384b0ff44aaaa1f14cb2cd63b3fea966&page=1&page_size=3" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "message": "Found 2 faces", - "faces": [ - { - "face_id": "identity_8d7c22e3a6794a8c93b4a3655f106944", - "name": "Cary Grant", - "created_at": "2026-04-18T10:44:48.571407+00:00", - "is_active": true - }, - { - "face_id": "identity_9c5d1e8965eb49ae83d9b88db12fbb18", - "name": "Audrey Hepburn", - "created_at": "2026-04-18T10:44:31.536039+00:00", - "is_active": true - } - ], - "count": 2, - "page": 1, - "page_size": 3 -} -``` - ---- - -## 7. 任務 (Jobs) - -### `GET /api/v1/jobs` — 列出處理任務 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/jobs?page=1&page_size=2" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "jobs": [ - { - "id": 32, - "uuid": "942d0bdf5d6fb6ac18b47deb031e60c3", - "status": "running", - "current_processor": null, - "progress_current": 0, - "progress_total": 0, - "created_at": "2026-04-28 15:55:47.911654", - "started_at": null - } - ], - "count": 19, - "page": 1, - "page_size": 2 -} -``` - -### `GET /api/v1/rules/:rule/status` — 取得規則狀態 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/rules/default/status" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "rule": "default", - "supported_processor_ids": [], - "active_jobs": [] -} -``` - ---- - -## 8. 統計 (Stats) - -### `GET /api/v1/stats/ingest` — 取得匯入統計 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/stats/ingest" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "total_videos": 21, - "total_chunks": 0, - "sentence_chunks": 0, - "cut_chunks": 0, - "time_chunks": 0, - "searchable_chunks": 0, - "chunks_with_visual": 0, - "chunks_with_summary": 0, - "pending_videos": 12 -} -``` - ---- - -## 錯誤回應 - -| HTTP Code | 說明 | -|-----------|------| -| `400` | 請求參數錯誤 (例如缺少必填欄位) | -| `401` | API Key 無效或缺失 | -| `404` | 資源不存在 | -| `422` | 請求格式錯誤 (JSON 解析失敗) | -| `500` | 伺服器內部錯誤 | diff --git a/docs_v1.0/DEV_API_V1.0/API_REFERENCE_v1.0.0.md b/docs_v1.0/DEV_API_V1.0/API_REFERENCE_v1.0.0.md deleted file mode 100644 index 68cbb6d..0000000 --- a/docs_v1.0/DEV_API_V1.0/API_REFERENCE_v1.0.0.md +++ /dev/null @@ -1,904 +0,0 @@ -# Momentry Core API Documentation v1.0.0 - -## 快速資訊 -- **Base URL**: `http://:3003` (開發環境) -- **Production**: `http://:3002` -- **認證方式**: Header `X-API-Key: ` -- **測試 Key**: `muser_test_001` - ---- - -## API 分類原則 - -| 分類 | 用途 | 代表端點 | -|------|------|----------| -| **健康檢查** | 系統狀態確認 | `/health` | -| **檔案管理 (Files)** | 列出、查詢檔案 | `/api/v1/files` | -| **人物管理 (People)** | Identity 搜尋、候選 | `/api/v1/people` | -| **Identity 管理** | 人物詳細資訊 | `/api/v1/identities/:uuid` | -| **搜尋 (Search)** | 文字、BM25、混合搜尋 | `/api/v1/search/*` | -| **人臉 (Face)** | 人臉辨識、列表 | `/api/v1/face/*` | -| **任務 (Jobs)** | 處理任務狀態 | `/api/v1/jobs` | -| **統計 (Stats)** | 系統統計 | `/api/v1/stats/ingest` | - -### 設計概念 -1. **Files 是核心資源**:所有影片/圖片都是 File,用 32 碼 `file_uuid` 識別 -2. **Identity 是跨檔案的人物**:一個 Identity 可出現在多個 Files -3. **People = Identity 的別名路由**:`/api/v1/people` 和 `/api/v1/identities` 指向相同資料 -4. **所有列表 API 支援分頁**:`page`, `page_size` 參數 -5. **所有操作 API 回傳統一格式**:`{ success, data, total, page, page_size }` - ---- - -## 1. 健康檢查 - -### `GET /health` -檢查系統是否運作。 - -**回應**: -```json -{ - "status": "ok", - "version": "1.0.0 (build: 2026-04-30 15:40:04)", - "uptime_ms": 348240 -} -``` - ---- - -## 2. 檔案管理 (Files) - -> **測試日期**: 2026-04-30 | **環境**: Playground (Port 3003) | **Schema**: dev - -### `GET /api/v1/files` — 列出所有檔案 - -**參數**: `page` (預設 1), `page_size` (預設 20) - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files?page=1&page_size=2" \ - -H "X-API-Key: muser_test_001" -``` - -**實際回應**: -```json -{ - "success": true, - "total": 21, - "page": 1, - "page_size": 2, - "data": [ - { - "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", - "file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "status": "ready" - } - ] -} -``` - -### `GET /api/v1/files/:uuid` — 取得檔案詳情 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files/384b0ff44aaaa1f14cb2cd63b3fea966" \ - -H "X-API-Key: muser_test_001" -``` - -**實際回應**: -```json -{ - "success": true, - "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", - "file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "metadata": { - "format": { - "duration": "6879.329524", - "width": 1920, - "height": 1080 - }, - "streams": [ - { - "codec_name": "h264", - "codec_type": "video", - "width": 1920, - "height": 1080, - "r_frame_rate": "60000/1001" - }, - { - "codec_name": "aac", - "codec_type": "audio", - "sample_rate": "44100", - "channels": 2 - } - ] - } -} -``` - -### `GET /api/v1/files/scan` — 掃描檔案系統 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files/scan" \ - -H "X-API-Key: muser_test_001" -``` - -**實際回應**: -```json -{ - "files": [ - { - "file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "file_size": 2361629896, - "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", - "status": "pending", - "is_registered": true, - "registration_time": "2026-04-28 18:25:14.010351+00" - } - ], - "total": 20, - "registered_count": 20, - "unregistered_count": 0 -} -``` - -### `POST /api/v1/files/register` — 註冊新檔案 - -> **⚠️ 已知問題**: 此 endpoint 在 dev 環境有 SQLx 型別綁定問題 (probe_json text vs jsonb)。不影響 marcom 團隊的 GUI 設計。 - -**Request**: -```json -{ - "file_path": "/path/to/video.mp4" -} -``` - ---- - -## 3. 人物管理 (People) - -### `GET /api/v1/people` — 列出所有人物 - -**參數**: `page`, `page_size` - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/people?page=1&page_size=3" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "total": 100, - "page": 1, - "page_size": 3, - "data": [ - { - "identity_id": "a9a90105-6d6b-46ff-92da-0c3c1a57dff4", - "name": "Trace 2 Fixed Format", - "metadata": {}, - "created_at": "2026-04-28T06:10:14.582062Z" - } - ] -} -``` - -### `POST /api/v1/people/search` — 搜尋人物 - -**Request**: -```json -{ - "query": "Trace", - "limit": 3 -} -``` - -**curl**: -```bash -curl -s -X POST "http://localhost:3003/api/v1/people/search" \ - -H "X-API-Key: muser_test_001" \ - -H "Content-Type: application/json" \ - -d '{"query":"Trace","limit":3}' -``` - -**回應**: -```json -{ - "success": true, - "total": 3, - "page": 1, - "page_size": 20, - "data": [ - { - "identity_id": "a9a90105-6d6b-46ff-92da-0c3c1a57dff4", - "name": "Trace 2 Fixed Format", - "metadata": {}, - "created_at": "2026-04-28T06:10:14.582062Z" - } - ] -} -``` - -### `GET /api/v1/people/candidates` — 列出未命名人物候選 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/people/candidates" \ - -H "X-API-Key: muser_test_001" -``` - ---- - -## 4. Identity 詳細資訊 - -### `GET /api/v1/identities/:uuid` — 取得人物詳情 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/identities/a9a90105-6d6b-46ff-92da-0c3c1a57dff4" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "uuid": "a9a90105-6d6b-46ff-92da-0c3c1a57dff4", - "name": "Trace 2 Fixed Format", - "identity_type": "people", - "source": "auto_trace", - "status": "active", - "metadata": {}, - "reference_data": { - "trace_id": 2, - "quality_avg": 0.8748, - "trace_stats": { - "start_frame": 155, - "end_frame": 297, - "avg_confidence": 0.8624, - "duration_seconds": 6.5, - "total_appearances": 143 - }, - "angles_covered": ["profile_right", "three_quarter"] - } -} -``` - -### `GET /api/v1/identities/:uuid/files` — 取得人物出現的檔案列表 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/identities/a9a90105-6d6b-46ff-92da-0c3c1a57dff4/files" \ - -H "X-API-Key: muser_test_001" -``` - ---- - -## 5. 搜尋 (Search) - -### `POST /api/v1/search` — 向量搜尋 - -**Request**: -```json -{ - "query": "person talking", - "limit": 5 -} -``` - -**回應**: -```json -{ - "results": [], - "query": "person talking" -} -``` - -### `POST /api/v1/search/bm25` — BM25 全文搜尋 - -**Request**: -```json -{ - "query": "test", - "limit": 3 -} -``` - -**回應**: -```json -{ - "results": [ - { - "uuid": "a1b10138a6bbb0cd", - "chunk_id": "sentence_1006", - "text": "...", - "bm25_score": 5.23 - } - ], - "query": "test" -} -``` - -### `POST /api/v1/search/hybrid` — 混合搜尋 (向量 + BM25) - -**Request**: -```json -{ - "query": "test", - "limit": 3 -} -``` - ---- - -## 6. 人臉 (Face) - -### `GET /api/v1/face/list` — 列出人臉 - -**必填參數**: `file_uuid` - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/face/list?file_uuid=384b0ff44aaaa1f14cb2cd63b3fea966&page=1&page_size=3" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "message": "Found 2 faces", - "faces": [ - { - "face_id": "identity_8d7c22e3a6794a8c93b4a3655f106944", - "name": "Cary Grant", - "created_at": "2026-04-18T10:44:48.571407+00:00", - "is_active": true - }, - { - "face_id": "identity_9c5d1e8965eb49ae83d9b88db12fbb18", - "name": "Audrey Hepburn", - "created_at": "2026-04-18T10:44:31.536039+00:00", - "is_active": true - } - ], - "count": 2, - "page": 1, - "page_size": 3 -} -``` - ---- - -## 7. 任務 (Jobs) - -### `GET /api/v1/jobs` — 列出處理任務 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/jobs?page=1&page_size=2" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "jobs": [ - { - "id": 32, - "uuid": "942d0bdf5d6fb6ac18b47deb031e60c3", - "status": "running", - "current_processor": null, - "progress_current": 0, - "progress_total": 0, - "created_at": "2026-04-28 15:55:47.911654", - "started_at": null - } - ], - "count": 19, - "page": 1, - "page_size": 2 -} -``` - -### `GET /api/v1/rules/:rule/status` — 取得規則狀態 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/rules/default/status" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "rule": "default", - "supported_processor_ids": [], - "active_jobs": [] -} -``` - ---- - -## 8. 統計 (Stats) - -### `GET /api/v1/stats/ingest` — 取得匯入統計 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/stats/ingest" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "total_videos": 21, - "total_chunks": 0, - "sentence_chunks": 0, - "cut_chunks": 0, - "time_chunks": 0, - "searchable_chunks": 0, - "chunks_with_visual": 0, - "chunks_with_summary": 0, - "pending_videos": 12 -} -``` - ---- - -## 9. 影片管理 (Videos) - -> **注意**: `/api/v1/videos` 主要用於後端列表與詳細資料查詢。前端常用 `/api/v1/files` 作為主要資源入口。 - -### `GET /api/v1/videos` — 列出影片 - -**參數**: `page`, `page_size` - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/videos?page=1&page_size=1" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "files": [ - { - "file_uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/view7.mp4", - "file_name": "view7.mp4", - "file_type": null, - "duration": 11.066667, - "width": 1920, - "height": 1080, - "status": "pending", - "processing_status": {}, - "birth_registration": {}, - "created_at": "2026-04-30 18:17:46.161312+00", - "registration_time": "2026-04-30 18:17:46.161312+00", - "file_size": null, - "probe_json": "...", - "total_frames": 332 - } - ], - "count": 22, - "page": 1, - "page_size": 1 -} -``` - -### `DELETE /api/v1/videos/:uuid` — 刪除影片 - -刪除影片及其所有關聯資料 (faces, chunks, etc.)。 - -**curl**: -```bash -curl -s -X DELETE "http://localhost:3003/api/v1/videos/" \ - -H "X-API-Key: muser_test_001" -``` - -### `GET /api/v1/progress/:uuid` — 取得處理進度 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/progress/e79890f13e2e0bebf6c67b436f2c4279" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "file_name": "view7.mp4", - "duration": 11.066667, - "overall_progress": 0, - "cpu_percent": 0.0, - "gpu_percent": null, - "memory_percent": 0.2, - "memory_mb": 29504, - "processors": [ - { - "name": "asr", - "status": "pending", - "current": 0, - "total": 0, - "progress": 0, - "message": "" - } - ] -} -``` - ---- - -## 10. 其他工具 (Utilities) - -### `GET /api/v1/lookup` — 查詢檔案資訊 - -可透過 `uuid` 或 `path` 查詢。 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/lookup?uuid=e79890f13e2e0bebf6c67b436f2c4279" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "file_uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/view7.mp4", - "file_name": "view7.mp4", - "duration": 11.066667 -} -``` - ---- - -## 11. 人臉 (Face) - -### `GET /api/v1/face/list` — 列出人臉 - -**必填參數**: `file_uuid` - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/face/list?file_uuid=e79890f13e2e0bebf6c67b436f2c4279&page=1&page_size=2" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "faces": [ - { - "face_id": "identity_8d7c22e3a6794a8c93b4a3655f106944", - "name": "Cary Grant", - "is_active": true - } - ], - "count": 2 -} -``` - -### `GET /api/v1/face/:face_id` — 取得人臉詳情 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/face/identity_8d7c22e3a6794a8c93b4a3655f106944" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "face_id": "identity_8d7c22e3a6794a8c93b4a3655f106944", - "name": "Cary Grant", - "has_embedding": false, - "is_active": true -} -``` - -### `POST /api/v1/face/recognize` — 進行人臉辨識 - -> **注意**: 此端點會掃描影片並返回逐幀結果。若影片過大可能耗時較長。 - -**Request**: -```json -{ - "file_uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "image_path": "/tmp/test.jpg" -} -``` - -**回應**: -```json -{ - "success": true, - "result": { - "frame_count": 332, - "fps": 30.0, - "faces": [ ... ] - } -} -``` - ---- - -## 12. 快照與截圖管理 (Snapshots) - -> **設計概念**: 快照分為「熱 (hot)」與「冷 (cold)」。冷快照需遷移至記憶體 (migrate) 後才能進行高效存取。 - -### `GET /api/v1/files/:uuid/snapshots` — 列出快照狀態 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files/e79890f13e2e0bebf6c67b436f2c4279/snapshots" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "file_uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "tier": "cold", - "hits": 0, - "types": [ - "products", "ocr", "logos", "faces" - ] -} -``` - -### `GET /api/v1/files/:uuid/snapshots/status` — 檢查詳細狀態 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files/e79890f13e2e0bebf6c67b436f2c4279/snapshots/status" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "status": "cold" -} -``` - -### `POST /api/v1/files/:uuid/snapshots/migrate` — 載入快照至記憶體 - -將冷快照載入記憶體以加速讀取。 - -**Request**: -```json -{ - "parent_uuid": "e79890f13e2e0bebf6c67b436f2c4279" -} -``` - -**回應**: -```json -{ - "success": true, - "message": "Migrated 4 snapshot types", - "migrated_types": ["products", "ocr", "logos", "faces"] -} -``` - -### `POST /api/v1/files/:uuid/snapshots/teardown` — 釋放記憶體 - -釋放已載入的快照資源。 - ---- - -## 13. 身份綁定與訊號 (Identity Binding) - -### `POST /api/v1/identities/bind` — 綁定人臉/聲音至身份 - -將特定的人臉或聲音訊號綁定到全域身份。若身份不存在,需提供 `name` 自動建立。 - -**Request**: -```json -{ - "name": "John Doe", - "binding_type": "face", - "binding_value": "identity_xxx" -} -``` - -### `POST /api/v1/identities/unbind` — 解綁身份 - -**Request**: -```json -{ - "binding_type": "face", - "binding_value": "identity_xxx" -} -``` - -### `GET /api/v1/signals/unbound` — 列出未綁定訊號 - -列出檔案中尚未被綁定的臉部或聲音訊號。 - -**參數**: `uuid`, `binding_type` (face/speaker) - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/signals/unbound?uuid=e79890f13e2e0bebf6c67b436f2c4279&binding_type=face" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "message": "Found 0 unbound face signals", - "data": [] -} -``` - ---- - -## 14. 身份來源與詳細 (Identity Sources) - -### `GET /api/v1/identities/:uuid` — 取得身份詳情 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/identities/a9a90105-6d6b-46ff-92da-0c3c1a57dff4" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "uuid": "a9a90105-6d6b-46ff-92da-0c3c1a57dff4", - "name": "Trace 2 Fixed Format", - "identity_type": "people", - "source": "auto_trace", - "status": "active", - "reference_data": { - "trace_id": 2, - "quality_avg": 0.8748 - } -} -``` - -### `GET /api/v1/identities/:identity_id/faces` — 取得身份下的所有臉部 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/identities/22/faces?page=1&page_size=5" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "identity_id": 22, - "faces": [], - "total": 0 -} -``` - -### `GET /api/v1/files/:uuid/identities` — 取得檔案中出現的身份 - -**curl**: -```bash -curl -s "http://localhost:3003/api/v1/files/e79890f13e2e0bebf6c67b436f2c4279/identities" \ - -H "X-API-Key: muser_test_001" -``` - -**回應**: -```json -{ - "success": true, - "file_uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "total": 0, - "data": [] -} -``` - ---- - -## 15. 進階視覺搜尋 (Visual Search Variants) - -### `POST /api/v1/search/visual/class` — 依物件類別搜尋 - -**Request**: -```json -{ - "uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "object_class": "person" -} -``` - -### `POST /api/v1/search/visual/density` — 依物件密度搜尋 - -**Request**: -```json -{ - "uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "min_density": 0.1 -} -``` - -### `POST /api/v1/search/visual/combination` — 依物件組合搜尋 - -**Request**: -```json -{ - "uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "combination": [["person", 1]] -} -``` - ---- - -## 16. 代理人 (Agents) - -### `POST /api/v1/agents/identity/analyze` — 分析身份重複 - -分析檔案中的身份是否重複,提供合併建議。 - -**Request**: -```json -{ - "file_uuid": "e79890f13e2e0bebf6c67b436f2c4279" -} -``` - -### `POST /api/v1/agents/5w1h/analyze` — 分析 5W1H 摘要 - -**Request**: -```json -{ - "file_uuid": "e79890f13e2e0bebf6c67b436f2c4279", - "chunk_id": "chunk_1" -} -``` - ---- - -## 17. 資產操作 (Assets) - -### `POST /api/v1/assets/:uuid/process` — 觸發處理流程 - -**Request**: -```json -{ - "processors": ["asr", "cut", "face"] -} -``` - -### `POST /api/v1/unregister` — 解除註冊檔案 - -**Request**: -```json -{ - "uuid": "e79890f13e2e0bebf6c67b436f2c4279" -} -``` - ---- - -## 錯誤回應 - -| HTTP Code | 說明 | -|-----------|------| -| `400` | 請求參數錯誤 (例如缺少必填欄位) | -| `401` | API Key 無效或缺失 | -| `404` | 資源不存在 | -| `422` | 請求格式錯誤 (JSON 解析失敗) | -| `500` | 伺服器內部錯誤 | diff --git a/docs_v1.0/IMPLEMENTATION/API_TRAINING_MARCOM.md b/docs_v1.0/IMPLEMENTATION/API_TRAINING_MARCOM.md deleted file mode 100644 index 8a9aa0f..0000000 --- a/docs_v1.0/IMPLEMENTATION/API_TRAINING_MARCOM.md +++ /dev/null @@ -1,391 +0,0 @@ -# Momentry Core API 教育訓練手冊 - -> **對象**: marcom 團隊 -> **版本**: V1.4 | **日期**: 2026-03-25 - ---- - -## 1. 快速開始 - -### 基本資訊 - -| 項目 | 值 | -|------|-----| -| API 網址 | `https://api.momentry.ddns.net` | -| 認證方式 | Header `X-API-Key` | -| 格式 | JSON | - -### Demo 測試帳號 - -#### API Key(用於 API 認證) - -``` -X-API-Key: muser_68600856036340bcafc01930eb4bd839 -``` - -#### SFTPGo(用於影片上傳) - -| 項目 | 值 | -|------|-----| -| SFTP 主機 | `sftpgo.momentry.ddns.net` | -| SFTP 連接埠 | `2022` | -| 用戶名 | `demo` | -| 密碼 | `demopassword123` | -| Web 管理介面 | `https://sftpgo.momentry.ddns.net` | - -**使用方式**:透過 SFTP 上傳影片,系統會自動註冊並處理。 - ---- - -## 2. 快速範例 - -### 查詢所有影片 - -```bash -curl -s -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - "https://api.momentry.ddns.net/api/v1/videos" -``` - -### 查詢單一影片 - -```bash -curl -s -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - "https://api.momentry.ddns.net/api/v1/videos/{uuid}" -``` - -### 查詢處理任務狀態 - -```bash -curl -s -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - "https://api.momentry.ddns.net/api/v1/jobs/{uuid}" -``` - ---- - -## 3. API 端點說明 - -### 3.1 影片相關 - -#### GET /api/v1/videos -取得所有影片列表 - -**回應範例**: -```json -{ - "videos": [ - { - "uuid": "5dea6618a606e7c7", - "filename": "demo_video.mp4", - "duration": 123.45, - "status": "ready", - "created_at": "2026-03-25T10:00:00Z" - } - ] -} -``` - -#### GET /api/v1/videos/:uuid -取得單一影片詳情 - -### 3.2 搜尋與分段查詢 - -#### POST /api/v1/search -向量搜尋,查詢分段(Chunk)詳情 - -**請求參數**: -| 參數 | 類型 | 必填 | 說明 | -|------|------|------|------| -| `query` | string | 是 | 搜尋關鍵字 | -| `limit` | number | 否 | 回傳數量(預設 10) | -| `uuid` | string | 否 | 只搜尋指定影片 | - -**請求範例**: -```json -{ - "query": "天氣", - "limit": 10, - "uuid": "5dea6618a606e7c7" -} -``` - -**回應範例**: -```json -{ - "results": [ - { - "uuid": "39567a0eb16f39fd", - "chunk_id": "sentence_1471", - "chunk_type": "sentence", - "start_time": 5309.08, - "end_time": 5311.08, - "text": "influenced by a vital way,", - "score": 0.68 - } - ], - "query": "天氣" -} -``` - -**Chunk 欄位說明**: -| 欄位 | 說明 | 範例 | -|------|------|------| -| `uuid` | 影片唯一識別碼 | `39567a0eb16f39fd` | -| `chunk_id` | 分段識別碼 | `sentence_1471` | -| `chunk_type` | 分段類型 | `sentence` / `cut` / `time` / `trace` / `story` | -| `start_time` | 開始時間(秒) | `5309.08` | -| `end_time` | 結束時間(秒) | `5311.08` | -| `text` | 內容文字 | `influenced by a vital way` | -| `score` | 相似度分數(0-1) | `0.68` | - -**Chunk 類型說明**: -| 類型 | 說明 | 來源 | -|------|------|------| -| `sentence` | 語音轉文字片段 | ASR 處理 | -| `cut` | 場景變化片段 | CUT 處理 | -| `time` | 固定時間分段 | 系統自動切割 | -| `trace` | 軌跡追蹤片段 | YOLO 追蹤 | -| `story` | 故事線片段(父子關係) | Story 分析 | - -#### POST /api/v1/n8n/search -n8n 專用搜尋(包含完整影片檔案路徑 file_path) - -**請求參數**: 與 `/search` 相同 - -**回應範例**: -```json -{ - "query": "天氣", - "count": 2, - "hits": [ - { - "id": "sentence_1471", - "vid": "39567a0eb16f39fd", - "chunk_type": "sentence", - "start_frame": 318545, - "end_frame": 318665, - "fps": 59.94, - "start_time": 5314.31, - "end_time": 5316.32, - "text": "influenced by a vital way,", - "score": 0.68 - } - ] -} -``` - -**與 /search 的差異**: -| 欄位 | `/search` | `/n8n/search` | -|------|-----------|----------------| -| 影片 UUID | `uuid` | `vid` | -| Chunk ID | `chunk_id` | `id` | -| 開始時間 | `start_time` | `start_time` | -| 結束時間 | `end_time` | `end_time` | -| 相似度分數 | `score` | `score` | -| **檔案路徑** | ❌ | ✅ `file_path` | - -> **注意**: `file_path` 是影片的實際路徑,可用於本地播放。 - -### 3.3 任務相關 - -### 3.4 任務相關 - -#### GET /api/v1/jobs/:uuid -查詢處理任務狀態 - -**回應範例**: -```json -{ - "uuid": "9760d0820f0cf9a7", - "file_uuid": "5dea6618a606e7c7", - "status": "completed", - "progress": 100, - "created_at": "2026-03-25T10:00:00Z", - "completed_at": "2026-03-25T10:05:00Z" -} -``` - -#### GET /api/v1/jobs -查詢所有任務 - -**查詢參數**: -| 參數 | 說明 | 範例 | -|------|------|------| -| `status` | 篩選狀態 | `pending`, `processing`, `completed`, `failed` | -| `limit` | 回傳數量 | `10` | - -**範例**: -```bash -curl -s -H "X-API-Key: ..." \ - "https://api.momentry.ddns.net/api/v1/jobs?status=completed&limit=5" -``` - -### 3.5 系統管理 - -#### POST /api/v1/config/cache -切換快取功能(管理員專用) - -**請求範例**: -```json -{ - "enabled": true -} -``` - -**回應範例**: -```json -{ - "cache_enabled": true, - "message": "Cache toggled successfully" -} -``` - -#### POST /api/v1/unregister -刪除影片及其所有關聯資料(管理員專用) - -**請求範例**: -```json -{ - "uuid": "5dea6618a606e7c7" -} -``` - -**回應範例**: -```json -{ - "success": true, - "message": "Video unregistered successfully", - "uuid": "5dea6618a606e7c7" -} -``` - -**注意**: 此操作會刪除影片及其所有分段、處理結果、縮圖等關聯資料,**無法復原**。 - -### 3.6 健康檢查 - -#### GET /health -服務健康狀態(**無需認證**) - -**回應**: -```json -{ - "status": "ok", - "version": "0.9.20260325_144654" -} -``` - ---- - -## 4. n8n Workflow 範例 - -### 4.1 基本設定 - -在 n8n workflow 中使用 HTTP Request 節點: - -``` -┌─────────────────┐ -│ HTTP Request │ -├─────────────────┤ -│ Method: GET │ -│ URL: https://api.momentry.ddns.net/api/v1/videos -│ Headers: │ -│ X-API-Key: │ -│ [YOUR_KEY] │ -└────────┬────────┘ - │ - ▼ -┌─────────────────┐ -│ 處理回應資料 │ -└─────────────────┘ -``` - -### 4.2 範例:檢查任務狀態 - -```javascript -// n8n Function Node 範例 -const jobUuid = $input.item.json.uuid; - -return [{ - json: { - method: "GET", - url: `https://api.momentry.ddns.net/api/v1/jobs/${jobUuid}`, - headers: { - "X-API-Key": "YOUR_API_KEY" - } - } -}]; -``` - ---- - -## 5. 常見問題 - -### Q: 返回 401 錯誤怎麼辦? -確認 Header 中有正確的 `X-API-Key` 值 - -### Q: 如何確認影片處理完成? -``` -GET /api/v1/jobs/{uuid} -``` -檢查 `status` 是否為 `completed` - -### Q: 查不到資料? -確認 UUID 格式正確(16碼 hex 字串) - ---- - -## 6. 快速參考卡 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Momentry API 速查 │ -├─────────────────────────────────────────────────────────────┤ -│ 查詢所有影片 GET /api/v1/videos │ -│ 查詢單一影片 GET /api/v1/videos/:uuid │ -│ 向量搜尋 POST /api/v1/search │ -│ n8n 搜尋 POST /api/v1/n8n/search │ -│ 查詢任務狀態 GET /api/v1/jobs/:uuid │ -│ 查詢所有任務 GET /api/v1/jobs │ -│ 快取設定 POST /api/v1/config/cache (管理員) │ -│ 刪除影片 POST /api/v1/unregister (管理員) │ -│ 健康檢查 GET /health (免認證) │ -├─────────────────────────────────────────────────────────────┤ -│ Header: X-API-Key: [YOUR_KEY] │ -│ URL: https://api.momentry.ddns.net │ -└─────────────────────────────────────────────────────────────┘ -``` - ---- - -## 附錄:回應狀態說明 - -### 任務狀態 (status) - -| 狀態 | 說明 | -|------|------| -| `pending` | 等待處理 | -| `processing` | 處理中 | -| `completed` | 已完成 | -| `failed` | 處理失敗 | - -### 影片狀態 (status) - -| 狀態 | 說明 | -|------|------| -| `uploading` | 上傳中 | -| `pending` | 等待處理 | -| `processing` | 處理中 | -| `ready` | 已就緒 | -| `error` | 錯誤 | - ---- - -## 附錄:版本歷史 - -| 版本 | 日期 | 內容 | 操作人 | -|------|------|------|--------| -| V1.0 | 2026-03-25 | 初版建立 | OpenCode | -| V1.1 | 2026-03-25 | 新增快取/刪除 API、搜尋端點文件 | OpenCode | -| V1.2 | 2026-03-25 | 新增 Chunk 欄位說明、類型、播放方式 | OpenCode | -| V1.3 | 2026-03-25 | 新增 Demo 測試帳號(SFTPGo)| OpenCode | -| V1.4 | 2026-03-25 | 更新 n8n 搜尋回傳欄位說明 (media_url→file_path) | OpenCode | -| V1.5 | 2026-04-17 | 修正 API Key 格式、統一 n8n/search 欄位名稱 (start/end → start_time/end_time) | OpenCode | diff --git a/docs_v1.0/IMPLEMENTATION/CONTINUOUS_DEMO_GUIDE.md b/docs_v1.0/IMPLEMENTATION/CONTINUOUS_DEMO_GUIDE.md deleted file mode 100644 index 5ee7de3..0000000 --- a/docs_v1.0/IMPLEMENTATION/CONTINUOUS_DEMO_GUIDE.md +++ /dev/null @@ -1,371 +0,0 @@ -# 🎬 連續演示模式使用指南 - -## 功能特點 - -### 1️⃣ 從頭到尾連續播放 -- 按 ASR 片段順序播放 -- 不跳躍、不間斷 -- 完整呈現所有內容 - -### 2️⃣ 顯示所有識別信息 -每個片段顯示: -- **ASR**: 文字內容 -- **Speaker**: 說話人 + 演員名 + 角色名 -- **Face**: 人臉位置和置信度 -- **Pose**: 嘴部關鍵點 -- **更多**: 未來可擴展 OCR、場景等 - -### 3️⃣ 鍵盤控制 -- **SPACE**: 暫停/恢復 -- **Q**: 停止並退出 - ---- - -## 快速開始 - -### 基本用法 - -```bash -./run_demo.sh --continuous -``` - -### 顯示視頻 - -```bash -./run_demo.sh --continuous --video -``` - ---- - -## 使用範例 - -### 1. 音頻連續播放(默認) - -```bash -./run_demo.sh --continuous -``` - -**輸出示例**: -``` -🎬 Continuous Demo Mode -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -📺 Playing from beginning to end -⏸️ Press SPACE to pause/resume -⏹️ Press Q to quit -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -[1/1118] Segment -================================================================================ -⏱ Time: 14.20s - 21.50s -🎤 Speaker: SPEAKER_4 → James Coburn (Tex Panthollow) -================================================================================ -▶️ Playing: 14.20s - 21.50s (7.30s) - -[2/1118] Segment -================================================================================ -⏱ Time: 22.40s - 58.30s -🎤 Speaker: SPEAKER_4 → James Coburn (Tex Panthollow) -================================================================================ -▶️ Playing: 22.40s - 58.30s (35.90s) -``` - -### 2. 視頻連續播放 - -```bash -./run_demo.sh --continuous --video -``` - -**特點**: -- 📺 彈出視頻窗口 -- 🎬 視聽同步 -- 💯 完整體驗 - -### 3. 自定義窗口大小 - -```bash -./target/debug/integrated_player \ - --video /tmp/charade_audio.wav \ - --asrx /tmp/asrx_charade_optimized.json \ - --continuous-demo \ - --show-video \ - --video-width 1600 \ - --video-height 900 -``` - ---- - -## 鍵盤控制詳解 - -### ⏸️ 暫停(SPACE) - -**何時使用**: -- 想仔細看某個片段 -- 需要暫停分析 -- 想跳過某些內容 - -**操作**: -``` -⏸️ Paused - Press SPACE to resume -``` - -再次按 SPACE 恢復播放。 - -### ⏹️ 退出(Q) - -**何時使用**: -- 演示完成 -- 想提前結束 -- 切換到其他任務 - -**操作**: -``` -⏹️ Stopped by user -``` - -立即停止並退出。 - ---- - -## 演示流程 - -### 完整流程圖 - -``` -開始 - ↓ -載入數據(ASR, ASRX, Face, Pose) - ↓ -逐句播放 ASR 片段 - ├─ 顯示文字 - ├─ 顯示說話人 - ├─ 顯示人臉 - ├─ 顯示嘴部動作 - └─ 播放音頻/視頻 - ↓ -用戶可隨時: - ├─ SPACE 暫停/恢復 - └─ Q 退出 - ↓ -播放完成 -``` - ---- - -## 信息顯示格式 - -### 標準格式 - -``` -[片段序號/總數] Segment -================================================================================ -⏱ Time: 起始時間 - 結束時間 -📝 Text: 文字內容(如果有) -🎤 Speaker: 說話人ID → 演員名 (角色名) -👤 Face: 位置、大小、置信度(如果有) -👄 Mouth landmarks: 嘴部關鍵點(如果有) -================================================================================ -▶️ Playing: 起始時間 - 結束時間 (時長) -``` - -### 實際範例 - -``` -[234/1118] Segment -================================================================================ -⏱ Time: 299.50s - 303.10s -🎤 Speaker: SPEAKER_1 → Audrey Hepburn (Regina Lampert) -👤 Face: bbox=(1250,178) 147x206, confidence=0.88 -================================================================================ -▶️ Playing: 299.50s - 303.10s (3.60s) -``` - ---- - -## 與其他模式對比 - -| 特性 | 連續模式 | 說話人演示 | 交互模式 | -|------|----------|-----------|----------| -| **播放方式** | 從頭到尾 | 按說話人 | 手動控制 | -| **自動化** | ✅ 全自動 | ✅ 半自動 | ❌ 手動 | -| **信息展示** | ✅ 完整 | ✅ 完整 | ✅ 按需 | -| **暫停控制** | ✅ 支持 | ❌ 不支持 | N/A | -| **適用場景** | 完整演示 | 說話人分析 | 深度分析 | - ---- - -## 使用場景 - -### 1. 完整功能演示 - -```bash -# 展示所有識別功能 -./run_demo.sh --continuous --video -``` - -適用於: -- 向客戶演示 -- 團隊內部展示 -- 功能驗收 - -### 2. 內容審核 - -```bash -# 快速瀏覽所有內容 -./run_demo.sh --continuous -``` - -適用於: -- 檢查 ASR 準確度 -- 驗證說話人識別 -- 確認人臉檢測 - -### 3. 數據驗證 - -```bash -# 驗證處理結果 -./target/debug/integrated_player \ - --video video.mp4 \ - --asr asr.json \ - --asrx asrx.json \ - --face face.json \ - --continuous-demo -``` - -適用於: -- 檢查處理質量 -- 發現問題片段 -- 優化處理參數 - ---- - -## 高級用法 - -### 1. 慢速播放 - -```bash -# 慢速觀看細節 -./target/debug/integrated_player \ - --video video.mp4 \ - --asrx asrx.json \ - --continuous-demo \ - --show-video -``` - -按 SPACE 暫停查看細節。 - -### 2. 快速瀏覽 - -```bash -# 音頻模式快速瀏覽 -./run_demo.sh --continuous -``` - -適合快速了解內容。 - -### 3. 特定時間段 - -結合交互模式: - -```bash -# 1. 先用交互模式找到起始時間 -./target/debug/integrated_player --video video.mp4 --asrx asrx.json - -# 2. 輸入時間跳轉 -> 300 - -# 3. 改用連續模式從該時間開始 -# (需要修改代碼支持 --start 參數) -``` - ---- - -## 性能優化 - -### 1. 音頻模式 - -```bash -# 最快、最輕量 -./run_demo.sh --continuous -``` - -### 2. 視頻模式 - -```bash -# 較慢、更完整 -./run_demo.sh --continuous --video -``` - -### 3. 自定義窗口 - -```bash -# 小窗口更快 ---video-width 640 --video-height 480 -``` - ---- - -## 常見問題 - -### Q1: 播放速度太快? - -A: 按 SPACE 暫停,仔細查看信息。 - -### Q2: 想跳過某些片段? - -A: 按 Q 退出,使用交互模式手動選擇。 - -### Q3: 沒有 ASR 數據? - -A: 連續模式需要 ASR 數據。請確保提供 `--asr` 參數。 - -### Q4: 某些片段沒有信息? - -A: 正常現象。不是每個片段都有所有信息(Face、Pose等)。 - -### Q5: 可以調整播放速度嗎? - -A: 連續模式按實際時長播放。需要快進請使用 `--demo` 模式。 - ---- - -## 命令速查 - -```bash -# 連續音頻演示 -./run_demo.sh --continuous - -# 連續視頻演示 -./run_demo.sh --continuous --video - -# 自定義窗口 -./target/debug/integrated_player \ - --video video.mp4 \ - --asrx asrx.json \ - --continuous-demo \ - --show-video \ - --video-width 1600 \ - --video-height 900 - -# 鍵盤控制 -SPACE - 暫停/恢復 -Q - 退出 -``` - ---- - -## 未來擴展 - -### 計劃功能 - -1. **進度條**: 顯示當前播放進度 -2. **時間跳轉**: 支持從指定時間開始 -3. **字幕疊加**: 在視頻上顯示 ASR 文字 -4. **人臉標註**: 在視頻上畫出人臉框 -5. **OCR 整合**: 顯示文字識別結果 -6. **場景識別**: 顯示場景類型 - ---- - -**更新日期**: 2026-04-02 -**版本**: 2.0.0 -**作者**: Momentry Team diff --git a/docs_v1.0/IMPLEMENTATION/DEMO_GUIDE.md b/docs_v1.0/IMPLEMENTATION/DEMO_GUIDE.md deleted file mode 100644 index ecfae1a..0000000 --- a/docs_v1.0/IMPLEMENTATION/DEMO_GUIDE.md +++ /dev/null @@ -1,397 +0,0 @@ -# 整合播放器演示功能指南 - -## 🎬 自動演示模式 - -整合播放器支持自動演示功能,可以自動播放所有說話人的片段,展示各項功能。 - ---- - -## 快速開始 - -### 1. 快速演示(推薦初次使用) - -```bash -./run_demo.sh --quick -``` - -- 每個說話人演示 1 個片段 -- 3 倍速播放 -- 適合快速了解功能 - -### 2. 標準演示 - -```bash -./run_demo.sh -``` - -- 每個說話人演示 3 個片段 -- 2 倍速播放 -- 完整展示所有功能 - -### 3. 自定義演示 - -```bash -./target/debug/integrated_player \ - --video /tmp/charade_audio.wav \ - --asrx /tmp/asrx_charade_optimized.json \ - --demo \ - --demo-segments-per-speaker 5 \ - --demo-speed 1.5 -``` - ---- - -## 演示參數 - -| 參數 | 說明 | 默認值 | -|------|------|--------| -| `--demo` | 啟用自動演示模式 | false | -| `--demo-segments-per-speaker` | 每個說話人演示的片段數 | 3 | -| `--demo-speed` | 演示速度(倍速) | 2.0 | - ---- - -## 演示流程 - -演示模式會自動執行以下步驟: - -1. **載入數據** - - ASRX 說話人分離結果 - - Face 人臉檢測結果(如果提供) - - Pose 姿態估計結果(如果提供) - -2. **列出說話人** - ``` - 📊 Speaker Statistics: - ──────────────────────────────────────────────────────────────────────────────── - Speaker ID Actor Character Segments Duration - ──────────────────────────────────────────────────────────────────────────────── - SPEAKER_0 Cary Grant Peter Joshua 654 1764.4s - SPEAKER_1 Audrey Hepburn Regina Lampert 403 1119.4s - SPEAKER_2 Walter Matthau Hamilton Bartholomew 49 65.7s - SPEAKER_4 James Coburn Tex Panthollow 3 44.1s - ──────────────────────────────────────────────────────────────────────────────── - ``` - -3. **逐一演示每個說話人** - - 對每個說話人: - - 顯示說話人信息(ID → 演員 → 角色) - - 播放指定數量的片段 - - 顯示整合信息(文字、人臉、嘴部動作) - - 暫停 2 秒後切換到下一個說話人 - -4. **演示示例輸出** - - ``` - ================================================================================ - 🎭 Demo: SPEAKER_1 → Audrey Hepburn (Regina Lampert) - ================================================================================ - - [Segment 1/3] - - ================================================================================ - ⏱ Time: 299.50s - 303.10s - 🎤 Speaker: SPEAKER_1 → Audrey Hepburn (Regina Lampert) - 👤 Face: bbox=(1250,178) 147x206, confidence=0.88 - ================================================================================ - - ⏳ Playing audio (1.8s)... - ``` - ---- - -## 演示模式特點 - -### 1. 自動化播放 -- 無需手動輸入命令 -- 自動播放所有說話人 -- 適合展示和測試 - -### 2. 速度控制 -- 可調整播放速度 -- 支持快速瀏覽(3x) -- 支持正常速度(1x) - -### 3. 完整展示 -- ASR 文字 -- 人臉檢測 -- 說話人識別 -- 演員/角色映射 -- 嘴部動作(如果有 Pose 數據) - ---- - -## 使用場景 - -### 1. 功能演示 -```bash -# 展示給團隊或客戶 -./run_demo.sh -``` - -### 2. 快速測試 -```bash -# 開發過程中的快速測試 -./run_demo.sh --quick -``` - -### 3. 數據驗證 -```bash -# 驗證 ASRX 結果的正確性 -./target/debug/integrated_player \ - --video video.mp4 \ - --asrx asrx.json \ - --demo \ - --demo-speed 1.0 # 原速播放 -``` - -### 4. 說話人分析 -```bash -# 分析特定說話人的表現 -./target/debug/integrated_player \ - --video video.mp4 \ - --asrx asrx.json \ - --demo \ - --demo-segments-per-speaker 10 # 更多片段 -``` - ---- - -## 演示時間估算 - -以 Charade (114.7 分鐘) 為例: - -| 模式 | 片段數/說話人 | 速度 | 總時間 | -|------|---------------|------|--------| -| 快速 | 1 | 3x | ~2 分鐘 | -| 標準 | 3 | 2x | ~5 分鐘 | -| 完整 | 5 | 1x | ~15 分鐘 | - -計算公式: -``` -總時間 = 說話人數 × 片段數 × 平均片段時長 / 速度 -``` - ---- - -## 演示腳本詳解 - -### run_demo.sh - -```bash -#!/bin/bash -# 主要邏輯: - -# 1. 檢查編譯 -if [ ! -f ./target/debug/integrated_player ]; then - cargo build --bin integrated_player -fi - -# 2. 檢查數據 -if [ ! -f "$VIDEO" ]; then - python3 scripts/asrx_self/test_long_movie.py -fi - -# 3. 運行演示 -if [ "$1" = "--quick" ]; then - # 快速模式 - ./target/debug/integrated_player \ - --demo \ - --demo-segments-per-speaker 1 \ - --demo-speed 3.0 -else - # 標準模式 - ./target/debug/integrated_player \ - --demo \ - --demo-segments-per-speaker 3 \ - --demo-speed 2.0 -fi -``` - ---- - -## 高級用法 - -### 1. 演示特定說話人 - -```bash -# 只演示主要說話人 -./target/debug/integrated_player \ - --video video.mp4 \ - --asrx asrx.json \ - --auto-play-speaker \ - --speaker-name SPEAKER_0 -``` - -### 2. 演示整合 Face 數據 - -```bash -./target/debug/integrated_player \ - --video video.mp4 \ - --asrx asrx.json \ - --face face.json \ - --demo \ - --demo-segments-per-speaker 3 -``` - -### 3. 完整演示(所有數據) - -```bash -./target/debug/integrated_player \ - --video video.mp4 \ - --asr asr.json \ - --face face.json \ - --asrx asrx.json \ - --pose pose.json \ - --demo \ - --demo-segments-per-speaker 5 \ - --demo-speed 1.5 -``` - ---- - -## 輸出說明 - -### 演示輸出結構 - -``` -🎬 Auto Demo Mode -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Segments per speaker: 3 -Demo speed: 2.0x - -================================================================================ -🎭 Demo: SPEAKER_0 → Cary Grant (Peter Joshua) -================================================================================ - -[Segment 1/3] - -================================================================================ -⏱ Time: 14.20s - 21.50s -🎤 Speaker: SPEAKER_0 → Cary Grant (Peter Joshua) -👤 Face: bbox=(1250,178) 147x206, confidence=0.88 -================================================================================ - -⏳ Playing audio (3.6s)... - -[Segment 2/3] -... - -⏸️ Pausing 2 seconds before next speaker... - -================================================================================ -🎭 Demo: SPEAKER_1 → Audrey Hepburn (Regina Lampert) -================================================================================ -... - -================================================================================ -✅ Demo completed! -================================================================================ -``` - -### 信息解讀 - -- **🎭 Demo**: 說話人演示標題 -- **⏱ Time**: 片段時間範圍 -- **🎤 Speaker**: 說話人 → 演員 → 角色 -- **👤 Face**: 人臉位置和置信度 -- **👄 Mouth**: 嘴部關鍵點(如果有) -- **⏳ Playing**: 正在播放音頻 -- **⏸️ Pausing**: 說話人切換暫停 - ---- - -## 故障排查 - -### 問題 1: 找不到測試數據 - -```bash -# 解決方案:生成測試數據 -cd scripts/asrx_self -python3 test_long_movie.py -cd ../.. -``` - -### 問題 2: 播放失敗 - -```bash -# 檢查 ffplay -which ffplay - -# 安裝 ffmpeg -brew install ffmpeg -``` - -### 問題 3: 演示太快/太慢 - -```bash -# 調整速度參數 ---demo-speed 1.0 # 原速 ---demo-speed 2.0 # 2 倍速(默認) ---demo-speed 3.0 # 3 倍速 -``` - ---- - -## 性能優化 - -### 減少片段數 - -```bash ---demo-segments-per-speaker 1 # 每個說話人只演示 1 個片段 -``` - -### 提高速度 - -```bash ---demo-speed 4.0 # 4 倍速快速瀏覽 -``` - -### 演示主要說話人 - -```bash -# 只演示片段數最多的說話人 ---auto-play-speaker --speaker-name SPEAKER_0 -``` - ---- - -## 比較:演示模式 vs 交互模式 - -| 特性 | 演示模式 | 交互模式 | -|------|----------|----------| -| 自動化 | ✅ 全自動 | ❌ 需手動輸入 | -| 速度控制 | ✅ 可調整 | ❌ 固定速度 | -| 說話人選擇 | ❌ 按順序 | ✅ 自由選擇 | -| 時間跳轉 | ❌ 不支持 | ✅ 支持 | -| 適用場景 | 展示、測試 | 分析、開發 | - ---- - -## 相關命令 - -```bash -# 查看幫助 -./target/debug/integrated_player --help - -# 快速測試 -./run_demo.sh --quick - -# 標準演示 -./run_demo.sh - -# 自定義演示 -./target/debug/integrated_player \ - --video video.mp4 \ - --asrx asrx.json \ - --demo \ - --demo-segments-per-speaker 5 \ - --demo-speed 1.5 -``` - ---- - -**創建日期**: 2026-04-02 -**版本**: 1.1.0 -**作者**: Momentry Team diff --git a/docs_v1.0/IMPLEMENTATION/DEMO_MANUAL.md b/docs_v1.0/IMPLEMENTATION/DEMO_MANUAL.md deleted file mode 100644 index cd4304e..0000000 --- a/docs_v1.0/IMPLEMENTATION/DEMO_MANUAL.md +++ /dev/null @@ -1,705 +0,0 @@ ---- -document_type: "implementation_guide" -service: "MOMENTRY_CORE" -title: "Momentry Core API 示範手冊" -date: "2026-03-25" -version: "V1.0" -status: "active" -owner: "Warren" -created_by: "OpenCode" -tags: - - "momentry" - - "core" - - "示範手冊" -ai_query_hints: - - "查詢 Momentry Core API 示範手冊 的內容" - - "Momentry Core API 示範手冊 的主要目的是什麼?" - - "如何操作或實施 Momentry Core API 示範手冊?" ---- - -# Momentry Core API 示範手冊 - -| 項目 | 內容 | -|------|------| -| 建立者 | OpenCode | -| 建立時間 | 2026-03-25 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-25 | 創建示範手冊,包含 Demo API Key 與完整範例 | OpenCode | deepseek-reasoner | - ---- - -**狀態**: 完成 - ---- - -## 快速開始 - -### Demo API Key - -``` -API Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69 -Key ID: muser_68600856036340bcafc01930eb4bd839 -過期日: 2027-03-25 -``` - -### 測試連線 - -```bash -curl http://localhost:3002/health -``` - -```json -{"status":"ok","version":"0.1.0","uptime_ms":456464} -``` - -### 測試認證 - -```bash -curl -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - http://localhost:3002/api/v1/videos | jq '.videos | length' -``` - -```json -13 -``` - ---- - -## 環境 URL - -| 環境 | URL | 用途 | -|------|-----|------| -| **本地開發** | `http://localhost:3002` | 本機開發測試 | -| **外部訪問** | `https://api.momentry.ddns.net` | n8n/WordPress/curl 生產環境 | - ---- - -## 端點總覽 - -| 方法 | 端點 | 說明 | 認證 | -|------|------|------|------| -| GET | `/health` | 健康檢查 | 公開 | -| GET | `/health/detailed` | 詳細健康檢查 | 公開 | -| POST | `/api/v1/register` | 註冊影片 | 需要 | -| POST | `/api/v1/probe` | 探測影片資訊 | 需要 | -| POST | `/api/v1/search` | 語意搜尋 | 需要 | -| POST | `/api/v1/n8n/search` | n8n 格式搜尋 | 需要 | -| POST | `/api/v1/search/hybrid` | 混合搜尋 | 需要 | -| GET | `/api/v1/videos` | 列出所有影片 | 需要 | -| GET | `/api/v1/lookup` | 查詢影片 UUID | 需要 | -| GET | `/api/v1/progress/:uuid` | 處理進度 | 需要 | -| GET | `/api/v1/jobs` | 任務列表 | 需要 | -| GET | `/api/v1/jobs/:uuid` | 任務詳情 | 需要 | - ---- - -## 1. curl 範例 - -### 基本格式 - -```bash -curl -H "X-API-Key: YOUR_API_KEY" \ - -H "Content-Type: application/json" \ - URL -``` - -### 1.1 健康檢查(公開) - -```bash -# 基本健康檢查 -curl http://localhost:3002/health - -# 詳細健康檢查(含服務狀態) -curl http://localhost:3002/health/detailed -``` - -### 1.2 列出影片 - -```bash -curl -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - http://localhost:3002/api/v1/videos | jq '.' -``` - -```json -{ - "videos": [ - { - "uuid": "952f5854b9febad1", - "file_name": "ExaSAN PCIe series - Director Ou Yu-Zhi Shares His Experience.mp4", - "duration": 159.637188, - "width": 640, - "height": 360 - }, - ... - ] -} -``` - -### 1.3 搜尋影片 - -```bash -curl -X POST \ - -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - -H "Content-Type: application/json" \ - -d '{"query": "ExaSAN", "limit": 5}' \ - http://localhost:3002/api/v1/search | jq '.' -``` - -```json -{ - "results": [ - { - "uuid": "952f5854b9febad1", - "chunk_id": "...", - "text": "...", - "score": 0.85, - "start_time": 0.0, - "end_time": 5.0 - } - ], - "total": 1, - "query": "ExaSAN", - "took_ms": 123 -} -``` - -### 1.4 查詢進度 - -```bash -curl -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - http://localhost:3002/api/v1/progress/952f5854b9febad1 | jq '.' -``` - -```json -{ - "uuid": "952f5854b9febad1", - "overall_progress": 67, - "current_processor": "yolo", - "processors": [ - {"name": "asr", "status": "completed"}, - {"name": "cut", "status": "completed"}, - {"name": "yolo", "status": "running"} - ] -} -``` - ---- - -## 2. n8n 範例 - -### 2.1 HTTP Request 節點設定 - -``` -Method: POST -URL: https://api.momentry.ddns.net/api/v1/search -Authentication: None (使用 Header) - -Headers: -┌─────────────────────┬──────────────────────────────────────────────────┐ -│ Name │ Value │ -├─────────────────────┼──────────────────────────────────────────────────┤ -│ X-API-Key │ muser_68600856036340bcafc01930eb4bd839_... │ -│ Content-Type │ application/json │ -└─────────────────────┴──────────────────────────────────────────────────┘ - -Body Content (JSON): -{ - "query": "{{ $json.search_term }}", - "limit": 5 -} -``` - -### 2.2 n8n 搜尋 Workflow - -```json -{ - "nodes": [ - { - "name": "Manual Trigger", - "type": "n8n-nodes-base.manualTrigger", - "position": [250, 300] - }, - { - "name": "Set Search Term", - "type": "n8n-nodes-base.set", - "parameters": { - "values": { - "json": { - "search_term": "ExaSAN" - } - } - }, - "position": [450, 300] - }, - { - "name": "Search Videos", - "type": "n8n-nodes-base.httpRequest", - "parameters": { - "method": "POST", - "url": "https://api.momentry.ddns.net/api/v1/search", - "authentication": "genericCredentialType", - "genericAuthType": "httpHeaderAuth", - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "X-API-Key", - "value": "muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" - } - ] - }, - "sendBody": true, - "bodyContentType": "json", - "specifyBody": "json", - "jsonBody": "={{ { \"query\": $json.search_term, \"limit\": 5 } }}" - }, - "position": [650, 300] - }, - { - "name": "Process Results", - "type": "n8n-nodes-base.code", - "parameters": { - "jsCode": "// Extract video results\nconst results = $input.first().json.results;\nreturn results.map(r => ({\n uuid: r.uuid,\n text: r.text,\n score: r.score,\n time: `${r.start_time}s - ${r.end_time}s`\n}));" - }, - "position": [850, 300] - } - ], - "connections": { - "Manual Trigger": { - "main": [[{"node": "Set Search Term"}]] - }, - "Set Search Term": { - "main": [[{"node": "Search Videos"}]] - }, - "Search Videos": { - "main": [[{"node": "Process Results"}]] - } - } -} -``` - -### 2.3 n8n 列出影片 Workflow - -```json -{ - "nodes": [ - { - "name": "Get Videos", - "type": "n8n-nodes-base.httpRequest", - "parameters": { - "method": "GET", - "url": "https://api.momentry.ddns.net/api/v1/videos", - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "X-API-Key", - "value": "muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" - } - ] - } - }, - "position": [450, 300] - }, - { - "name": "Extract Video List", - "type": "n8n-nodes-base.code", - "parameters": { - "jsCode": "const videos = $input.first().json.videos;\nreturn videos.map(v => ({\n json: {\n uuid: v.uuid,\n name: v.file_name,\n duration: Math.round(v.duration) + 's',\n resolution: `${v.width}x${v.height}`\n }\n}));" - }, - "position": [650, 300] - }, - { - "name": "Slack Notification", - "type": "n8n-nodes-base.slack", - "parameters": { - "channel": "#momentry", - "text": "=Found {{ $json.length }} videos:\n{{ $json.map(v => `• ${v.name} (${v.duration})`).join(`\n`) }}" - }, - "position": [850, 300] - } - ] -} -``` - -### 2.4 n8n 定時同步 Workflow - -```json -{ - "nodes": [ - { - "name": "Schedule Trigger", - "type": "n8n-nodes-base.scheduleTrigger", - "parameters": { - "rule": { - "interval": [{"field": "hours", "hours": 1}] - } - }, - "position": [250, 300] - }, - { - "name": "Get Pending Videos", - "type": "n8n-nodes-base.httpRequest", - "parameters": { - "method": "GET", - "url": "https://api.momentry.ddns.net/api/v1/videos" - }, - "position": [450, 300] - }, - { - "name": "Filter Processing", - "type": "n8n-nodes-base.filter", - "parameters": { - "conditions": { - "options": {"caseSensitive": true}, - "conditions": [ - {"id": "status", "leftValue": "{{ $json.status }}", "rightValue": "processing"} - ] - } - }, - "position": [650, 300] - } - ] -} -``` - ---- - -## 3. WordPress 範例 - -### 3.1 PHP 函數庫 - -```php - [ - 'X-API-Key' => self::API_KEY, - 'Content-Type' => 'application/json', - ], - 'timeout' => 30, - ]; - - if ($method === 'POST') { - $args['method'] = 'POST'; - $args['body'] = json_encode($data); - } - - $response = wp_remote_request($url, $args); - - if (is_wp_error($response)) { - throw new Exception($response->get_error_message()); - } - - return json_decode(wp_remote_retrieve_body($response), true); - } - - /** - * 列出所有影片 - */ - public function list_videos(): array { - return $this->request('/api/v1/videos'); - } - - /** - * 搜尋影片內容 - */ - public function search(string $query, int $limit = 10): array { - return $this->request('/api/v1/search', [ - 'query' => $query, - 'limit' => $limit, - ], 'POST'); - } - - /** - * 取得影片進度 - */ - public function get_progress(string $uuid): array { - return $this->request("/api/v1/progress/{$uuid}"); - } - - /** - * 檢查健康狀態 - */ - public function health_check(): array { - return $this->request('/health'); - } -} -``` - -### 3.2 短代碼 (Shortcode) - -```php - 10, - ], $atts); - - $api = new Momentry_API(); - - try { - $result = $api->list_videos(); - $videos = array_slice($result['videos'], 0, $atts['limit']); - - ob_start(); - ?> -
-

影片列表

-
    - -
  • - -
    - - UUID: - | 時長: - -
  • - -
-
- 載入失敗: ' . esc_html($e->getMessage()) . '

'; - } -}); - -// 搜尋短代碼 -add_shortcode('momentry_search', function($atts, $content = '') { - $query = sanitize_text_field($content); - - if (empty($query)) { - return '

請提供搜尋關鍵字

'; - } - - $api = new Momentry_API(); - - try { - $result = $api->search($query); - - ob_start(); - ?> -
-

」搜尋結果

- -

沒有找到相關結果

- -
    - -
  • - - - -
    - 相似度: % -
  • - -
- -
- 搜尋失敗: ' . esc_html($e->getMessage()) . '

'; - } -}); -``` - -### 3.3 使用方式 - -在 WordPress 頁面或文章中: - -``` -[momentry_videos limit="5"] - -[momentry_search]ExaSAN[/momentry_search] -``` - -### 3.4 REST API 整合 - -```php - 'GET', - 'callback' => function(WP_REST_Request $request) { - $query = sanitize_text_field($request->get_param('q')); - - if (empty($query)) { - return new WP_Error('missing_query', '需要搜尋關鍵字', ['status' => 400]); - } - - $api = new Momentry_API(); - $result = $api->search($query); - - return new WP_REST_Response($result, 200); - }, - 'permission_callback' => '__return_true', - ]); -}); - -// 使用方式: GET /wp-json/momentry/v1/search?q=ExaSAN -``` - ---- - -## 4. 疑難排解 - -### 4.1 常見錯誤 - -| 錯誤 | 原因 | 解決方案 | -|------|------|----------| -| `401 Unauthorized` | API Key 無效或過期 | 檢查 API Key 是否正確 | -| `500 Internal Server Error` | 伺服器錯誤 | 檢查 `/health/detailed` 服務狀態 | -| `Connection Timeout` | 網路問題 | 確認 `api.momentry.ddns.net` 可達 | - -### 4.2 測試腳本 - -```bash -#!/bin/bash -# test_api.sh - Momentry API 測試腳本 - -API_KEY="muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" -BASE_URL="http://localhost:3002" - -echo "=== 1. 健康檢查 ===" -curl -s "$BASE_URL/health" | jq . -echo "" - -echo "=== 2. 列出影片 ===" -curl -s -H "X-API-Key: $API_KEY" "$BASE_URL/api/v1/videos" | jq '.videos | length' -echo "" - -echo "=== 3. 搜尋測試 ===" -curl -s -X POST -H "X-API-Key: $API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"query": "test", "limit": 3}' \ - "$BASE_URL/api/v1/search" | jq '.results | length' -echo "" - -echo "=== 完成 ===" -``` - -### 4.3 驗證腳本 - -```bash -#!/bin/bash -# verify_auth.sh - 驗證 API Key - -API_KEY="muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" -BASE_URL="http://localhost:3002" - -# 測試 1: 無 API Key -echo "測試 1: 無 API Key" -RESULT=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/api/v1/videos") -[ "$RESULT" = "401" ] && echo "✅ 正確拒絕 (401)" || echo "❌ 預期 401,實際 $RESULT" - -# 測試 2: 有 API Key -echo "測試 2: 有 API Key" -RESULT=$(curl -s -H "X-API-Key: $API_KEY" "$BASE_URL/api/v1/videos") -echo "$RESULT" | jq -e '.videos' > /dev/null && echo "✅ 成功取得資料" || echo "❌ 取得資料失敗" - -# 測試 3: 無效 API Key -echo "測試 3: 無效 API Key" -RESULT=$(curl -s -o /dev/null -w "%{http_code}" -H "X-API-Key: invalid_key" "$BASE_URL/api/v1/videos") -[ "$RESULT" = "401" ] && echo "✅ 正確拒絕 (401)" || echo "❌ 預期 401,實際 $RESULT" -``` - ---- - -## 5. API Key 管理 - -### 5.1 建立新 API Key - -```bash -# 本地建立 -./target/release/momentry api-key create "My App" --key-type user --ttl 90 -``` - -### 5.2 列出 API Keys - -```bash -./target/release/momentry api-key list -``` - -### 5.3 驗證 API Key - -```bash -./target/release/momentry api-key validate --key "YOUR_API_KEY" -``` - -### 5.4 撤銷 API Key - -```bash -./target/release/momentry api-key revoke --key "YOUR_API_KEY" -``` - ---- - -## 附錄 - -### A. 影片 UUID 說明 - -UUID 是基於檔案路徑的 SHA256 哈希前 16 位: - -``` -/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4 - ↓ -SHA256 Hash - ↓ -9760d0820f0cf9a7 -``` - -### B. 處理器狀態 - -| 狀態 | 說明 | -|------|------| -| `pending` | 等待處理 | -| `running` | 處理中 | -| `completed` | 已完成 | -| `failed` | 失敗 | - -### C. 支援的處理器 - -- **ASR**: 語音識別 -- **CUT**: 場景剪切 -- **YOLO**: 物件偵測 - -### D. 聯絡支援 - -- Email: support@momentry.ddns.net -- 文件: https://docs.momentry.ddns.net -- GitHub: https://github.com/anomalyco/momentry diff --git a/docs_v1.0/IMPLEMENTATION/DEMO_MODES.md b/docs_v1.0/IMPLEMENTATION/DEMO_MODES.md deleted file mode 100644 index f111782..0000000 --- a/docs_v1.0/IMPLEMENTATION/DEMO_MODES.md +++ /dev/null @@ -1,222 +0,0 @@ -# 🎬 演示功能總結 - -## 當前可用的演示模式 - -### 1️⃣ 說話人演示模式(已實現) - -```bash -# 快速演示(每個說話人 1 個片段) -./run_demo.sh --quick - -# 標準演示(每個說話人 3 個片段) -./run_demo.sh - -# 視頻演示 -./run_demo.sh --video -``` - -**特點**: -- ✅ 按 ASRX 數據播放 -- ✅ 顯示說話人統計 -- ✅ 顯示演員名和角色名 -- ✅ 支持音頻/視頻模式 - ---- - -### 2️⃣ 連續播放模式(簡化版) - -```bash -# 音頻模式 -./play_continuous.sh - -# 視頻模式 -./play_continuous.sh --video -``` - -**特點**: -- ✅ 從頭到尾連續播放 -- ✅ 顯示說話人和時間信息 -- ✅ 支持視頻顯示 -- ⚠️ 不能暫停(按 Ctrl+C 停止) - -**實現原理**: -- 使用 `jq` 解析 ASRX JSON -- 循環調用 `ffplay` 播放每個片段 -- 簡單高效 - ---- - -## 演示效果 - -### 說話人演示 - -``` -🎬 Integrated Player for ASR/Face/ASRX/Pose -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Video: "/tmp/charade_audio.wav" -✓ Loaded 1118 ASRX segments, 8 speakers - -📊 Speaker Statistics: --------------------------------------------------------------------------------- -Speaker ID Actor Character Segments Duration --------------------------------------------------------------------------------- -SPEAKER_0 Cary Grant Peter Joshua 654 1764.4s -SPEAKER_1 Audrey Hepburn Regina Lampert 403 1119.4s -SPEAKER_2 Walter Matthau Hamilton Bartholomew 49 65.7s -SPEAKER_4 James Coburn Tex Panthollow 3 44.1s --------------------------------------------------------------------------------- - -🎭 Demo: SPEAKER_0 → Cary Grant (Peter Joshua) -================================================================================ -⏱ Time: 374.80s - 375.90s -🎤 Speaker: SPEAKER_0 → Cary Grant (Peter Joshua) -================================================================================ -⏳ Playing audio... -``` - -### 連續播放 - -``` -🎬 连续演示模式 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -📺 从头到尾播放所有 ASRX 片段 -⏸️ 按 Ctrl+C 停止 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -📊 总片段数: 1118 - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -[1/1118] 🎤 SPEAKER_5 -⏱ 1.8s - 2.6s (0.8s) -🔊 播放中... - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -[2/1118] 🎤 SPEAKER_4 -⏱ 14.2s - 21.5s (7.3s) -🔊 播放中... -``` - ---- - -## 使用建議 - -### 適用場景 - -| 模式 | 適用場景 | 優點 | 缺點 | -|------|----------|------|------| -| **說話人演示** | 展示、分析 | 按說話人跳躍、完整信息 | 不連續 | -| **連續播放** | 完整體驗 | 從頭到尾、不間斷 | 不能暫停 | - -### 推薦用法 - -#### 1. 快速了解內容 -```bash -./run_demo.sh --quick -``` - -#### 2. 說話人分析 -```bash -./run_demo.sh -``` - -#### 3. 完整觀看 -```bash -./play_continuous.sh --video -``` - ---- - -## 技術實現 - -### 說話人演示 -- **語言**: Rust -- **實現**: `integrated_player` binary -- **數據源**: ASRX JSON -- **控制**: 預設片段數 - -### 連續播放 -- **語言**: Bash -- **實現**: `play_continuous.sh` 腳本 -- **數據源**: ASRX JSON -- **控制**: Ctrl+C 停止 -- **工具**: jq, ffplay - ---- - -## 未來改進 - -### 計劃功能 - -1. **暫停控制** - - 使用 Rust 實現 - - 支持鍵盤交互 - - 空格鍵暫停 - -2. **進度條** - - 顯示當前進度 - - 剩餘時間估算 - -3. **字幕疊加** - - 在視頻上顯示 ASR 文字 - - 支持多語言 - -4. **人臉標註** - - 在視頻上畫出人臉框 - - 實時顯示檢測結果 - -5. **完整信息展示** - - ASR 文字 - - 人臉檢測 - - 嘴部動作 - - OCR 文字 - - 場景識別 - ---- - -## 常見問題 - -### Q: 為什麼連續模式不能暫停? - -A: 簡化版使用 Bash 腳本實現,沒有鍵盤監聽功能。完整版需要 Rust 實現,目前開發中。 - -### Q: 說話人演示為什麼會跳躍? - -A: 說話人演示按說話人分組播放,會跳過其他說話人的片段。連續模式才會完整播放。 - -### Q: 如何查看所有片段? - -A: 使用連續播放模式: -```bash -./play_continuous.sh -``` - -### Q: 播放速度如何? - -A: 兩種模式都按實際時長播放。說話人演示有 2 秒暫停。 - ---- - -## 快速命令參考 - -```bash -# 說話人演示(音頻) -./run_demo.sh - -# 說話人演示(視頻) -./run_demo.sh --video - -# 快速演示 -./run_demo.sh --quick - -# 連續播放(音頻) -./play_continuous.sh - -# 連續播放(視頻) -./play_continuous.sh --video -``` - ---- - -**更新日期**: 2026-04-02 -**版本**: 2.1.0 -**作者**: Momentry Team diff --git a/docs_v1.0/IMPLEMENTATION/DEMO_VIDEO_MODE.md b/docs_v1.0/IMPLEMENTATION/DEMO_VIDEO_MODE.md deleted file mode 100644 index f76e8d6..0000000 --- a/docs_v1.0/IMPLEMENTATION/DEMO_VIDEO_MODE.md +++ /dev/null @@ -1,222 +0,0 @@ -# 🎬 演示功能使用說明 - -## 問題:只聽到聲音? - -您遇到的情況是正常的!默認情況下,演示模式只播放音頻,不顯示視頻畫面。這樣可以: -- 快速瀏覽所有說話人 -- 專注於語音內容 -- 不受視頻窗口干擾 - ---- - -## 解決方案:顯示視頻畫面 - -### 方法 1: 使用演示腳本(推薦) - -```bash -# 快速演示 + 顯示視頻 -./run_demo.sh --quick --video - -# 標準演示 + 顯示視頻 -./run_demo.sh --video - -# 完整演示 + 顯示視頻 -./run_demo.sh --video -``` - -### 方法 2: 直接使用播放器 - -```bash -# 啟用視頻顯示 -./target/debug/integrated_player \ - --video /tmp/charade_audio.wav \ - --asrx /tmp/asrx_charade_optimized.json \ - --demo \ - --show-video - -# 自定義視頻窗口大小 -./target/debug/integrated_player \ - --video /tmp/charade_audio.wav \ - --asrx /tmp/asrx_charade_optimized.json \ - --demo \ - --show-video \ - --video-width 1200 \ - --video-height 800 -``` - ---- - -## 完整參數說明 - -### 視頻相關參數 - -| 參數 | 說明 | 默認值 | -|------|------|--------| -| `--show-video` | 顯示視頻畫面 | false(僅音頻) | -| `--video-width` | 視頻窗口寬度 | 800 | -| `--video-height` | 視頻窗口高度 | 600 | - -### 演示相關參數 - -| 參數 | 說明 | 默認值 | -|------|------|--------| -| `--demo` | 啟用自動演示模式 | false | -| `--demo-segments-per-speaker` | 每個說話人的片段數 | 3 | -| `--demo-speed` | 演示速度倍數 | 2.0 | - ---- - -## 使用範例 - -### 1. 音頻模式(默認) - -```bash -# 僅播放音頻,不顯示視頻 -./run_demo.sh --quick -``` - -**優點**: -- ✅ 快速瀏覽 -- ✅ 專注語音 -- ✅ 不受干擾 - -**適用場景**: -- 快速測試 -- 語音內容分析 -- 後台播放 - -### 2. 視頻模式 - -```bash -# 顯示視頻畫面 -./run_demo.sh --video -``` - -**優點**: -- ✅ 視聽結合 -- ✅ 更直觀 -- ✅ 完整體驗 - -**適用場景**: -- 功能演示 -- 內容展示 -- 完整測試 - -### 3. 自定義模式 - -```bash -# 慢速演示 + 大窗口 -./target/debug/integrated_player \ - --video /tmp/charade_audio.wav \ - --asrx /tmp/asrx_charade_optimized.json \ - --demo \ - --show-video \ - --demo-speed 1.0 \ - --video-width 1600 \ - --video-height 900 \ - --demo-segments-per-speaker 5 -``` - ---- - -## 對比:音頻模式 vs 視頻模式 - -| 特性 | 音頻模式 | 視頻模式 | -|------|----------|----------| -| **播放速度** | 快 | 慢 | -| **資源占用** | 低 | 高 | -| **窗口干擾** | 無 | 有 | -| **體驗完整度** | 70% | 100% | -| **適用場景** | 測試、分析 | 演示、展示 | - ---- - -## 推薦使用方式 - -### 開發測試 -```bash -# 快速音頻測試 -./run_demo.sh --quick -``` - -### 功能演示 -```bash -# 視頻演示 -./run_demo.sh --video -``` - -### 完整體驗 -```bash -# 慢速視頻演示 -./target/debug/integrated_player \ - --video /tmp/charade_audio.wav \ - --asrx /tmp/asrx_charade_optimized.json \ - --face /tmp/face_long.json \ - --demo \ - --show-video \ - --demo-speed 1.0 \ - --demo-segments-per-speaker 5 -``` - ---- - -## 常見問題 - -### Q: 為什麼默認不顯示視頻? - -A: -1. **性能考慮**:音頻模式更快、更輕量 -2. **專注內容**:不受視覺干擾 -3. **測試效率**:快速瀏覽所有說話人 - -### Q: 如何調整視頻窗口大小? - -A: -```bash ---video-width 1200 --video-height 800 -``` - -### Q: 可以同時顯示字幕嗎? - -A: 目前終端會顯示 ASR 文字,未來可以考慮在視頻上疊加字幕。 - -### Q: 視頻播放卡頓? - -A: -1. 使用較低的 `--demo-speed`(如 1.5) -2. 減少 `--demo-segments-per-speaker` -3. 確保系統性能足夠 - ---- - -## 完整演示命令集合 - -```bash -# 1. 快速音頻演示 -./run_demo.sh --quick - -# 2. 快速視頻演示 -./run_demo.sh --quick --video - -# 3. 標準音頻演示 -./run_demo.sh - -# 4. 標準視頻演示 -./run_demo.sh --video - -# 5. 完整視頻演示(慢速 + 大窗口) -./target/debug/integrated_player \ - --video /tmp/charade_audio.wav \ - --asrx /tmp/asrx_charade_optimized.json \ - --demo \ - --show-video \ - --demo-speed 1.0 \ - --video-width 1600 \ - --video-height 900 -``` - ---- - -**更新日期**: 2026-04-02 -**版本**: 1.2.0 -**作者**: Momentry Team diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_API_CURL_EXAMPLES.md b/docs_v1.0/IMPLEMENTATION/ROOT_API_CURL_EXAMPLES.md deleted file mode 100644 index e6a6388..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_API_CURL_EXAMPLES.md +++ /dev/null @@ -1,586 +0,0 @@ -# Momentry API 使用說明 (curl 範例) - -| 項目 | 內容 | -|------|------| -| 版本 | V1.4 | -| 日期 | 2026-03-26 | -| Base URL | `http://localhost:3002` | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.4 | 2026-03-26 | 新增: 任務管理端點 (`/api/v1/jobs`, `/api/v1/jobs/:uuid`),更新註冊端點回應格式 | OpenCode | deepseek-reasoner | -| V1.3 | 2026-03-25 | 更新: n8n 搜尋回傳 `file_path` 取代 `media_url`,新增 API Key 驗證說明 | OpenCode | deepseek-reasoner | -| V1.2 | 2026-03-23 | 建立 curl 範例文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-18 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -> **狀態說明**: -> - ✅ **已實作**: 健康檢查、搜尋、影片管理端點 -> - ⚠️ **規劃中**: API Key 管理功能 -> - 🔧 **CLI**: 部分功能需使用命令列工具 - ---- - -## 目錄 - -1. [已實作端點](#1-已實作端點) -2. [API Key 管理](#2-api-key-管理-規劃中) -3. [影片管理](#3-影片管理) -4. [查詢與搜索](#4-查詢與搜索) -5. [系統狀態](#5-系統狀態) - ---- - -## URL 選擇指南 - -### 兩種 URL 的使用情境 - -| 環境 | URL | 說明 | -|------|-----|------| -| **本地開發** | `http://localhost:3002` | 直接訪問 API,繞過反向代理 | -| **外部訪問** | `https://api.momentry.ddns.net` | 通過 Caddy 反向代理訪問,需網路可達 | - -### 何時使用 localhost:3002 - -- ✅ 開發/測試環境 -- ✅ 直接在伺服器上操作 -- ✅ 當 Caddy/反向代理有問題時 -- ✅ 需要快速除錯時 - -### 何時使用 api.momentry.ddns.net - -- ✅ n8n workflow 中呼叫 API -- ✅ 外部系統整合 -- ✅ 生產環境 -- ✅ 從其他機器訪問 - -### 快速切換範例 - -```bash -# 本地測試 -curl http://localhost:3002/health - -# 外部測試(功能相同) -curl https://api.momentry.ddns.net/health -``` - -### 常見問題 - -**Q: 為什麼有兩個 URL?** -A: `localhost:3002` 是直接訪問,`api.momentry.ddns.net` 通過 Caddy 反向代理。 - -**Q: 兩者功能相同嗎?** -A: 是的,所有端點和功能完全相同。 - -**Q: 502 錯誤時怎麼辦?** -A: 如果 `api.momentry.ddns.net` 返回 502,檢查 Momentry API 服務是否運行: -```bash -launchctl list | grep momentry.api -# 如果未運行 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist -``` - ---- - -## API 認證 - -所有 `/api/v1/*` 端點(除了健康檢查)都需要 API Key 認證。請在請求標頭中加入: - -``` --H "X-API-Key: YOUR_API_KEY" -``` - -**目前示範使用的 API Key**: `demo_api_key_12345` - -> **注意**: 正式環境請使用安全的 API Key 管理機制。 - ---- - -## 1. 已實作端點 - -### 健康檢查 - -```bash -curl http://localhost:3002/health -``` - -**回應**: -```json -{"status":"ok","version":"0.1.0","uptime_ms":123456} -``` - -### 詳細健康檢查 - -```bash -curl http://localhost:3002/health/detailed -``` - ---- - -## 2. API Key 管理 *(規劃中)* - -> ⚠️ **此功能尚未實作**。以下為規劃中的 API 說明,僅供參考。 - -### 2.1 建立 API Key - -```bash -curl -X POST http://localhost:3002/api/v1/api-keys \ - -H "Content-Type: application/json" \ - -H "X-API-Key: your-admin-key" \ - -d '{ - "name": "my-service-key", - "key_type": "service", - "permissions": ["read", "write"], - "ttl_days": 90 - }' -``` - -### 2.2 列出所有 API Keys - -```bash -curl -X GET http://localhost:3002/api/v1/api-keys \ - -H "X-API-Key: your-admin-key" -``` - -### 2.3 驗證 API Key - -```bash -curl -X GET http://localhost:3002/api/v1/api-keys/validate \ - -H "X-API-Key: key-to-validate" -``` - -### 2.4 撤銷 API Key - -```bash -curl -X DELETE http://localhost:3002/api/v1/api-keys/msvc_a1b2c3d4_... \ - -H "X-API-Key: your-admin-key" -``` - -### 2.5 請求 Key 輪換 - -```bash -curl -X POST http://localhost:3002/api/v1/api-keys/msvc_a1b2c3d4_.../rotate \ - -H "X-API-Key: your-admin-key" \ - -H "Content-Type: application/json" \ - -d '{"reason": "scheduled_rotation"}' -``` - -### 2.6 取得統計資訊 - -```bash -curl -X GET http://localhost:3002/api/v1/api-keys/stats \ - -H "X-API-Key: your-admin-key" -``` - ---- - -## 3. 影片管理 - -### 3.1 註冊影片 ✅ - -```bash -curl -X POST http://localhost:3002/api/v1/register \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"path": "/path/to/video.mp4"}' -``` - -**回應範例**: - -```json -{ - "uuid": "a1b2c3d4e5f6g7h8", - "video_id": 1, - "job_id": 123, - "file_name": "video.mp4", - "duration": 120.5, - "width": 1920, - "height": 1080, - "already_exists": false -} -``` - -### 3.2 列出所有影片 ✅ - -```bash -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos -``` - -### 3.3 查詢影片 ✅ - -```bash -# 依 UUID 查詢 -curl -H "X-API-Key: YOUR_API_KEY" "http://localhost:3002/api/v1/lookup?uuid=a1b2c3d4e5f6g7h8" - -# 依路徑查詢 -curl -H "X-API-Key: YOUR_API_KEY" "http://localhost:3002/api/v1/lookup?path=/path/to/video.mp4" -``` - -### 3.4 處理影片 🔧 *(CLI - 非 API)* - -影片處理需要使用 CLI 命令: - -```bash -# 處理影片(生成 ASR, CUT, YOLO, OCR, Face, Pose 資料) -cargo run --bin momentry -- process - -# 或處理多個影片 -cargo run --bin momentry -- process -``` - -### 3.5 取得處理進度 ✅ - -```bash -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/progress/ -``` - -**回應範例**: - -```json -{ - "uuid": "a1b2c3d4e5f6g7h8", - "overall_progress": 75, - "processors": [ - { - "name": "asr", - "status": "complete", - "current": 100, - "total": 100, - "progress": 100, - "message": "7 segments" - }, - { - "name": "cut", - "status": "complete", - "current": 134, - "total": 134, - "progress": 100, - "message": "134 scenes" - }, - { - "name": "yolo", - "status": "progress", - "current": 5000, - "total": 14315, - "progress": 35, - "message": "frame 5000" - } - ] -} -``` - -### 3.6 任務管理 ✅ - -```bash -# 列出所有任務 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/jobs - -# 取得特定任務詳情 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/jobs/ -``` - -**任務列表回應範例**: -```json -{ - "jobs": [ - { - "id": 123, - "uuid": "a1b2c3d4e5f6g7h8", - "status": "pending", - "current_processor": null, - "progress_current": 0, - "progress_total": 100, - "created_at": "2026-03-26 10:30:00", - "started_at": null - } - ] -} -``` - -**任務詳情回應範例**: -```json -{ - "id": 123, - "uuid": "a1b2c3d4e5f6g7h8", - "status": "processing", - "current_processor": "asr", - "progress_current": 50, - "progress_total": 100, - "processors": [ - { - "processor_type": "asr", - "status": "complete", - "started_at": "2026-03-26 10:30:00", - "completed_at": "2026-03-26 10:35:00", - "duration_secs": 300.5, - "error_message": null - }, - { - "processor_type": "cut", - "status": "pending", - "started_at": null, - "completed_at": null, - "duration_secs": null, - "error_message": null - } - ], - "created_at": "2026-03-26 10:30:00", - "started_at": "2026-03-26 10:30:00", - "updated_at": "2026-03-26 10:35:00" -} -``` - ---- - -## 4. 查詢與搜索 - -### 4.1 語意搜尋 ✅ - -```bash -curl -X POST http://localhost:3002/api/v1/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{ - "query": "測試關鍵字", - "limit": 5 - }' -``` - -**回應範例**: - -```json -{ - "results": [ - { - "uuid": "a1b2c3d4e5f6g7h8", - "chunk_id": "sentence_0006", - "chunk_type": "sentence", - "start_time": 48.8, - "end_time": 55.44, - "text": "fun plot twists...", - "score": 0.526 - } - ], - "query": "測試關鍵字" -} -``` - -### 4.2 n8n 格式搜尋 ✅ - -```bash -curl -X POST http://localhost:3002/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{ - "query": "測試關鍵字", - "limit": 5 - }' -``` - -**回應範例**: - -```json -{ - "query": "測試關鍵字", - "count": 2, - "hits": [ - { - "id": "c_001", - "vid": "a1b2c3d4e5f6g7h8", - "start": 48.8, - "end": 55.44, - "title": "Chunk sentence_0006", - "text": "fun plot twists...", - "score": 0.92, - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4" - } - ] -} -``` - -### 4.3 混合搜尋 ✅ - -```bash -curl -X POST http://localhost:3002/api/v1/search/hybrid \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{ - "query": "測試關鍵字", - "limit": 5 - }' -``` - ---- - -## 5. 系統狀態 - -### 5.1 健康檢查 ✅ - -```bash -curl http://localhost:3002/health -``` - -**回應**: -```json -{"status":"ok","version":"0.1.0","uptime_ms":123456} -``` - -### 5.2 詳細健康檢查 ✅ - -```bash -curl http://localhost:3002/health/detailed -``` - -**回應範例**: - -```json -{ - "status":"ok", - "version":"0.1.0", - "uptime_ms":123456, - "services":{ - "postgres":{"status":"ok","latency_ms":42,"error":null}, - "redis":{"status":"ok","latency_ms":0,"error":null}, - "qdrant":{"status":"ok","latency_ms":15,"error":null} - } -} -``` - ---- - -## 6. n8n Webhook 測試 - -### 測試 n8n Workflow - -**重要**: 測試前請先在 n8n UI 中點擊 "Execute workflow" 按鈕 - -```bash -# 測試 Video RAG Workflow (Test Mode) -curl -X POST http://localhost:5678/webhook-test/video-rag-mcp \ - -H "Content-Type: application/json" \ - -d '{"query":"charade","limit":3}' - -# 帶有 UUID 過濾的搜尋 -curl -X POST http://localhost:5678/webhook-test/video-rag-mcp \ - -H "Content-Type: application/json" \ - -d '{"query":"woody","limit":5,"uuid":"a1b10138a6bbb0cd"}' -``` - -### 生產環境 Webhook - -**注意**: 工作流程必須處於 Active 狀態 - -```bash -curl -X POST http://localhost:5678/webhook/video-rag-mcp \ - -H "Content-Type: application/json" \ - -d '{"query":"charade","limit":3}' -``` - -### n8n Webhook 常見問題 - -**Q: webhook-test 返回 404** -A: 需要在 n8n UI 中點擊 "Execute workflow" 按鈕後才能使用 test webhook - -**Q: webhook (生產環境) 返回 404** -A: 需要將工作流程切換為 Active 狀態 (右上角開關) - ---- - -## 附錄 - -### A. 服務 URL 列表 - -| 服務 | URL | -|------|-----| -| Momentry API (本地) | `http://localhost:3002` | -| Momentry API (外部) | `https://api.momentry.ddns.net` | -| n8n Web UI | `https://n8n.momentry.ddns.net` | -| n8n Webhook Test | `http://localhost:5678/webhook-test/{workflow-name}` | -| n8n Webhook Prod | `http://localhost:5678/webhook/{workflow-name}` | - -### B. 所有可用端點 - -| 端點 | 方法 | 狀態 | 說明 | -|------|------|------|------| -| `/health` | GET | ✅ | 健康檢查 | -| `/health/detailed` | GET | ✅ | 詳細健康檢查 | -| `/api/v1/register` | POST | ✅ | 註冊影片 | -| `/api/v1/search` | POST | ✅ | 語意搜尋 | -| `/api/v1/n8n/search` | POST | ✅ | n8n 格式搜尋 | -| `/api/v1/search/hybrid` | POST | ✅ | 混合搜尋 | -| `/api/v1/lookup` | GET | ✅ | 查詢影片 | -| `/api/v1/videos` | GET | ✅ | 列出所有影片 | -| `/api/v1/progress/:uuid` | GET | ✅ | 處理進度 | -| `/api/v1/jobs` | GET | ✅ | 任務列表 | -| `/api/v1/jobs/:uuid` | GET | ✅ | 任務詳情 | -| `/api/v1/api-keys` | * | ⚠️ | API Key 管理 (規劃中) | - -### C. 常見錯誤 - -| HTTP 狀態 | 說明 | 解決方式 | -|-----------|------|----------| -| 200 | 成功 | - | -| 400 | 請求格式錯誤 | 檢查 JSON 格式 | -| 404 | 端點不存在或資源未找到 | 確認端點 URL 正確 | -| 500 | 伺服器內部錯誤 | 檢查 API 服務日誌 | -| **502** | **Bad Gateway** | **API 服務未啟動,見下方說明** | - -#### 502 Bad Gateway 錯誤 - -**問題**: 外部 URL `https://api.momentry.ddns.net` 返回 502 - -**原因**: Momentry Core API 服務未啟動 - -**解決方式**: - -```bash -# 1. 檢查服務狀態 -launchctl list | grep momentry.api - -# 2. 如果未啟動,手動啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 3. 或使用本地測試(繞過反向代理) -curl http://localhost:3002/health - -# 4. 檢查日誌 -tail -50 /Users/accusys/momentry/log/momentry_api.error.log -``` - -### D. 範例腳本 - -```bash -#!/bin/bash -# api_test.sh - API 測試腳本 - -API_URL="http://localhost:3002" - -# 健康檢查 -echo "=== Health Check ===" -curl -s "$API_URL/health" | jq . - -# 搜尋 -echo -e "\n=== Search ===" -curl -s -X POST "$API_URL/api/v1/search" \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "test", "limit": 3}' | jq . - -# 列出影片 -echo -e "\n=== Videos ===" -curl -s -H "X-API-Key: YOUR_API_KEY" "$API_URL/api/v1/videos" | jq '.videos | length' -``` - ---- - -## 相關文件 - -- [API_INDEX.md](./API_INDEX.md) - 文件總覽(起點) -- [API_ENDPOINTS.md](./API_ENDPOINTS.md) - 端點完整說明 -- [API_N8N_GUIDE.md](./API_N8N_GUIDE.md) - n8n 使用範例 -- [API_WORDPRESS_GUIDE.md](./API_WORDPRESS_GUIDE.md) - WordPress 使用範例 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_API_EXAMPLES.md b/docs_v1.0/IMPLEMENTATION/ROOT_API_EXAMPLES.md deleted file mode 100644 index b1ac92d..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_API_EXAMPLES.md +++ /dev/null @@ -1,771 +0,0 @@ -# Momentry Core API 使用範例總覽 - -| 項目 | 內容 | -|------|------| -| 版本 | V2.1 | -| 日期 | 2026-03-26 | -| Base URL (本地) | `http://localhost:3002` | -| Base URL (外部) | `https://api.momentry.ddns.net` | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | -|------|------|------|--------| -| V2.0 | 2026-03-25 | 創建完整範例總覽 | OpenCode | -| V2.1 | 2026-03-26 | 更新API回應格式 (media_url→file_path) 與認證標頭 | OpenCode | - ---- - -## 快速參考 - -### 環境 URL 選擇 - -| 環境 | URL | 用途 | -|------|-----|------| -| **本地開發** | `http://localhost:3002` | 開發/測試,直接訪問 API | -| **外部訪問** | `https://api.momentry.ddns.net` | n8n、WordPress、curl 生產環境 | - -### 所有可用端點 - -| 方法 | 端點 | 說明 | -|------|------|------| -| GET | `/health` | 健康檢查 | -| GET | `/health/detailed` | 詳細健康檢查 | -| POST | `/api/v1/search` | 語意搜尋(標準格式) | -| POST | `/api/v1/n8n/search` | 語意搜尋(n8n 格式) | -| POST | `/api/v1/search/hybrid` | 混合搜尋 | -| POST | `/api/v1/register` | 註冊影片 | -| POST | `/api/v1/probe` | 探測影片資訊 | -| GET | `/api/v1/videos` | 列出所有影片 | -| GET | `/api/v1/lookup` | 查詢影片 | -| GET | `/api/v1/progress/:uuid` | 處理進度 | -| GET | `/api/v1/jobs` | 任務列表 | -| GET | `/api/v1/jobs/:uuid` | 任務詳情 | - ---- - -## 認證 - -### API Key - -所有 `/api/v1/*` 端點需要 API Key 認證。 - -```bash -# 添加 API Key Header -curl -H "X-API-Key: your-api-key" http://localhost:3002/api/v1/videos - -# 範例 -curl -H "X-API-Key: muser_f08e13ba967e4d8ea8fc542ad9f99ac8_1774416728_90472a35" \ - http://localhost:3002/api/v1/videos -``` - -### 響應狀態 - -| 狀態碼 | 說明 | -|--------|------| -| 200 | 成功 | -| 401 | 未授權(缺少或無效 API Key) | -| 500 | 伺服器錯誤 | - -### 建立 API Key - -```bash -./target/release/momentry api-key create "My Key" --key-type user -``` - ---- - -## 1. curl 範例 - -### 基本語法 - -```bash -# 格式 -curl [OPTIONS] URL - -# 常用選項 --X METHOD # HTTP 方法 (GET, POST, etc.) --H HEADER # 添加 HTTP 標頭 --d DATA # POST 請求體 --s # 靜默模式 --w FORMAT # 輸出額外信息 -``` - -### 1.1 健康檢查 - -```bash -# 基本健康檢查 -curl http://localhost:3002/health - -# 詳細健康檢查 -curl http://localhost:3002/health/detailed -``` - -**回應**: -```json -{"status":"ok","version":"0.1.0","uptime_ms":123456} -``` - -### 1.2 語意搜尋 - -```bash -# 標準格式搜尋 -curl -X POST http://localhost:3002/api/v1/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 5}' - -# n8n 格式搜尋(推薦) -curl -X POST http://localhost:3002/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 5}' - -# 混合搜尋 -curl -X POST http://localhost:3002/api/v1/search/hybrid \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 5}' -``` - -**標準格式回應**: -```json -{ - "results": [ - { - "uuid": "a1b10138a6bbb0cd", - "chunk_id": "sentence_0001", - "chunk_type": "sentence", - "start_time": 48.8, - "end_time": 55.44, - "text": "fun plot twists...", - "score": 0.92 - } - ], - "query": "charade" -} -``` - -**n8n 格式回應**: -```json -{ - "query": "charade", - "count": 1, - "hits": [ - { - "id": "sentence_0001", - "vid": "a1b10138a6bbb0cd", - "start": 48.8, - "end": 55.44, - "title": "Chunk sentence_0001", - "text": "fun plot twists...", - "score": 0.92, - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4" - } - ] -} -``` - -### 1.3 影片管理 - -```bash -# 列出所有影片 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos - -# 查詢特定影片(依 UUID) -curl -H "X-API-Key: YOUR_API_KEY" "http://localhost:3002/api/v1/lookup?uuid=a1b10138a6bbb0cd" - -# 查詢特定影片(依路徑) -curl -H "X-API-Key: YOUR_API_KEY" "http://localhost:3002/api/v1/lookup?path=/path/to/video.mp4" - -# 取得處理進度 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/progress/a1b10138a6bbb0cd - -# 探測影片(不註冊) -curl -X POST http://localhost:3002/api/v1/probe \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"path": "/path/to/video.mp4"}' - -# 註冊影片 -curl -X POST http://localhost:3002/api/v1/register \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"path": "/path/to/video.mp4"}' -``` - -### 1.4 批次測試腳本 - -```bash -#!/bin/bash -# api_test.sh - API 測試腳本 - -API_URL="http://localhost:3002" - -echo "=== 健康檢查 ===" -curl -s "$API_URL/health" | jq . - -echo -e "\n=== 語意搜尋 ===" -curl -s -X POST "$API_URL/api/v1/search" \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 3}' | jq . - -echo -e "\n=== 影片列表 ===" -curl -s -H "X-API-Key: YOUR_API_KEY" "$API_URL/api/v1/videos" | jq '.videos | length' -``` - -### 1.5 外部 URL 範例 - -```bash -# 使用外部 URL(需網路可達) -curl https://api.momentry.ddns.net/health - -# 外部搜尋 -curl -X POST https://api.momentry.ddns.net/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 5}' -``` - ---- - -## 2. n8n 範例 - -### 2.1 HTTP Request Node 設定 - -``` -Node: HTTP Request -├── URL: https://api.momentry.ddns.net/api/v1/n8n/search -├── Method: POST -├── Authentication: None -├── Send Body: ✓ (checked) -├── Content Type: JSON -├── Body: -│ { -│ "query": "={{ $json.query }}", -│ "limit": "={{ $json.limit || 10 }}" -│ } -├── Send Headers: ✓ (checked) -└── Header Parameters: - └── X-API-Key: {{ $env.MOMENTRY_API_KEY }} -``` - -### 2.2 基本搜尋 Workflow - -```json -{ - "name": "Momentry Video Search", - "nodes": [ - { - "parameters": {}, - "name": "Manual Trigger", - "type": "n8n-nodes-base.manualTrigger", - "position": [250, 300] - }, - { - "parameters": { - "url": "https://api.momentry.ddns.net/api/v1/n8n/search", - "method": "POST", - "sendBody": true, - "contentType": "json", - "body": { - "query": "charade", - "limit": 3 - } - }, - "name": "Search Video API", - "type": "n8n-nodes-base.httpRequest", - "position": [450, 300] - } - ], - "connections": { - "Manual Trigger": { - "main": [[{"node": "Search Video API"}]] - } - } -} -``` - -### 2.3 Webhook 動態搜尋 - -```json -{ - "name": "Momentry Dynamic Search", - "nodes": [ - { - "parameters": { - "httpMethod": "POST", - "path": "search", - "responseMode": "lastNode" - }, - "name": "Webhook", - "type": "n8n-nodes-base.webhook", - "position": [250, 300] - }, - { - "parameters": { - "url": "https://api.momentry.ddns.net/api/v1/n8n/search", - "method": "POST", - "sendBody": true, - "contentType": "json", - "body": { - "query": "={{ JSON.stringify($json.body.query) }}", - "limit": "={{ $json.body.limit || 5 }}" - } - }, - "name": "Search API", - "type": "n8n-nodes-base.httpRequest", - "position": [450, 300] - } - ], - "connections": { - "Webhook": { - "main": [[{"node": "Search API"}]] - } - } -} -``` - -### 2.4 測試 Webhook - -```bash -# 測試模式(需先在 n8n UI 點擊 Execute) -curl -X POST http://localhost:5678/webhook-test/video-rag-mcp \ - -H "Content-Type: application/json" \ - -d '{"query":"charade","limit":3}' - -# 生產環境(需 workflow 為 Active 狀態) -curl -X POST http://localhost:5678/webhook/video-rag-mcp \ - -H "Content-Type: application/json" \ - -d '{"query":"charade","limit":3}' -``` - -### 2.5 健康檢查 Workflow - -```json -{ - "name": "Momentry Health Check", - "nodes": [ - { - "parameters": {}, - "name": "Manual Trigger", - "type": "n8n-nodes-base.manualTrigger", - "position": [250, 300] - }, - { - "parameters": { - "url": "https://api.momentry.ddns.net/health", - "method": "GET" - }, - "name": "Health Check", - "type": "n8n-nodes-base.httpRequest", - "position": [450, 300] - } - ], - "connections": { - "Manual Trigger": { - "main": [[{"node": "Health Check"}]] - } - } -} -``` - -### 2.6 錯誤處理 - -| 錯誤 | 原因 | 解決 | -|------|------|------| -| 502 Bad Gateway | API 服務未啟動 | `sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist` | -| "Your request is invalid" | Body 格式設定錯誤 | 確認 Content Type: JSON,Body 為有效 JSON | -| 404 on webhook-test | 未執行 workflow | 在 n8n UI 點擊 "Execute workflow" | - ---- - -## 3. WordPress 範例 - -### 3.1 PHP 基本用法 - -```php - 'charade', - 'limit' => 10 -]; - -$response = wp_remote_post($api_url, [ - 'headers' => ['Content-Type' => 'application/json'], - 'body' => json_encode($data), - 'timeout' => 30 -]); - -if (is_wp_error($response)) { - echo '錯誤: ' . $response->get_error_message(); -} else { - $body = json_decode(wp_remote_retrieve_body($response), true); - print_r($body['hits']); -} -?> -``` - -### 3.2 列出影片 - -```php - 30]); - -if (!is_wp_error($response)) { - $body = json_decode(wp_remote_retrieve_body($response), true); - foreach ($body['videos'] as $video) { - echo $video['file_name'] . "\n"; - } -} -?> -``` - -### 3.3 查詢特定影片 - -```php - 30]); - -if (!is_wp_error($response)) { - $video = json_decode(wp_remote_retrieve_body($response), true); - echo '檔案: ' . $video['file_name'] . "\n"; - echo '時長: ' . $video['duration'] . ' 秒'; -} -?> -``` - -### 3.4 JavaScript fetch - -```javascript -// 搜尋影片 -async function searchVideos(query, limit = 10) { - const response = await fetch('https://api.momentry.ddns.net/api/v1/n8n/search', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query, limit }) - }); - - if (!response.ok) { - throw new Error('API 請求失敗'); - } - - return await response.json(); -} - -// 使用範例 -searchVideos('charade', 5) - .then(data => { - data.hits.forEach(hit => { - console.log(`${hit.text} (score: ${hit.score})`); - }); - }); -``` - -### 3.5 WordPress Shortcode - -在 `functions.php` 中註冊短碼: - -```php - '', - 'limit' => '10' - ], $atts); - - if (empty($atts['query'])) { - return '

請提供搜尋關鍵字

'; - } - - $response = wp_remote_post('https://api.momentry.ddns.net/api/v1/n8n/search', [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'X-API-Key' => 'YOUR_API_KEY' // 替換為實際的 API Key - ], - 'body' => json_encode([ - 'query' => $atts['query'], - 'limit' => (int)$atts['limit'] - ]), - 'timeout' => 30 - ]); - - if (is_wp_error($response)) { - return '

搜尋服務暫時無法使用

'; - } - - $data = json_decode(wp_remote_retrieve_body($response), true); - - if (empty($data['hits'])) { - return '

找不到相關結果

'; - } - - $output = '
    '; - foreach ($data['hits'] as $hit) { - // 注意: API 現在返回 file_path 而非 media_url - // 需要將文件路徑轉換為可訪問的 URL - $file_path = $hit['file_path']; - $video_url = convert_file_path_to_url($file_path); // 需要實作此函數 - - $output .= sprintf( - '
  • %s 播放
  • ', - esc_html($hit['text']), - $video_url, - $hit['start'] - ); - } - $output .= '
'; - - return $output; -}); -?> -``` - -**使用方式**: -``` -[momentry_search query="charade" limit="5"] -``` - -### 3.6 WordPress REST API Endpoint - -在 WordPress REST API 中註冊自定義端點: - -```php - 'POST', - 'callback' => function($request) { - $response = wp_remote_post( - 'https://api.momentry.ddns.net/api/v1/n8n/search', - [ - 'headers' => ['Content-Type' => 'application/json'], - 'body' => json_encode([ - 'query' => $request->get_param('query'), - 'limit' => $request->get_param('limit', 10) - ]) - ] - ); - - if (is_wp_error($response)) { - return new WP_Error('api_error', 'API 請求失敗'); - } - - return json_decode(wp_remote_retrieve_body($response)); - } - ]); -}); -?> -``` - -**呼叫方式**: -``` -POST /wp-json/momentry/v1/search -Body: {"query": "charade", "limit": 5} -``` - ---- - -## 4. 回應格式說明 - -### 4.1 n8n 格式 (`/api/v1/n8n/search`) - -```json -{ - "query": "charade", - "count": 10, - "hits": [ - { - "id": "sentence_0001", - "vid": "a1b10138a6bbb0cd", - "start": 48.8, - "end": 55.44, - "title": "Chunk sentence_0001", - "text": "fun plot twists...", - "score": 0.92, - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4" - } - ] -} -``` - -### 4.2 標準格式 (`/api/v1/search`) - -```json -{ - "results": [ - { - "uuid": "a1b10138a6bbb0cd", - "chunk_id": "sentence_0001", - "chunk_type": "sentence", - "start_time": 48.8, - "end_time": 55.44, - "text": "fun plot twists...", - "score": 0.92 - } - ], - "query": "charade" -} -``` - -### 4.3 健康檢查 - -```json -{ - "status": "ok", - "version": "0.1.0", - "uptime_ms": 123456 -} -``` - -### 4.4 詳細健康檢查 - -```json -{ - "status": "ok", - "version": "0.1.0", - "uptime_ms": 123456, - "services": { - "postgres": {"status": "ok", "latency_ms": 42, "error": null}, - "redis": {"status": "ok", "latency_ms": 0, "error": null}, - "qdrant": {"status": "ok", "latency_ms": 15, "error": null}, - "mongodb": {"status": "ok", "latency_ms": 0, "error": null} - } -} -``` - -### 4.5 處理進度 - -```json -{ - "uuid": "a1b10138a6bbb0cd", - "file_name": "video.mp4", - "duration": 120.5, - "overall_progress": 75, - "processors": [ - {"name": "asr", "status": "complete", "progress": 100}, - {"name": "cut", "status": "complete", "progress": 100}, - {"name": "yolo", "status": "progress", "progress": 35} - ] -} -``` - -### 4.6 Probe 回應 - -```json -{ - "uuid": "a1b10138a6bbb0cd", - "file_name": "video.mp4", - "duration": 120.5, - "width": 1920, - "height": 1080, - "fps": 30.0, - "cached": false, - "format": { - "filename": "/path/to/video.mp4", - "format_name": "mov,mp4,m4a,3gp,3g2,mj2", - "duration": "120.5", - "size": "12345678", - "bit_rate": "819200" - }, - "streams": [ - { - "index": 0, - "codec_name": "h264", - "codec_type": "video", - "width": 1920, - "height": 1080, - "r_frame_rate": "30/1", - "duration": "120.5" - } - ] -} -``` - ---- - -## 5. HTTP 狀態碼 - -| 狀態 | 說明 | 解決 | -|------|------|------| -| 200 | 成功 | - | -| 400 | 請求格式錯誤 | 檢查 JSON 格式 | -| 404 | 端點或資源不存在 | 確認 URL 正確 | -| 500 | 伺服器內部錯誤 | 檢查 API 服務日誌 | -| 502 | API 服務未啟動 | 見下方說明 | - -### 502 Bad Gateway 解決 - -```bash -# 檢查服務狀態 -launchctl list | grep momentry.api - -# 啟動服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 或使用本地測試 -curl http://localhost:3002/health -``` - ---- - -## 6. 常見問題 - -### Q: 為什麼有兩個 URL? - -| URL | 用途 | -|-----|------| -| `localhost:3002` | 直接訪問,繞過反向代理 | -| `api.momentry.ddns.net` | 通過 Caddy 反向代理 | - -### Q: 兩者功能相同嗎? - -是的,所有端點和功能完全相同。 - -### Q: n8n webhook-test 返回 404? - -需在 n8n UI 中點擊 "Execute workflow" 按鈕後才能使用測試 Webhook。 - -### Q: 生產環境 webhook 返回 404? - -需將 workflow 切換為 Active 狀態(右上角開關)。 - ---- - -## 相關文件 - -- [API_INDEX.md](./API_INDEX.md) - 文件總覽 -- [API_ENDPOINTS.md](./API_ENDPOINTS.md) - 端點完整說明 -- [API_N8N_GUIDE.md](./API_N8N_GUIDE.md) - n8n 詳細指南 -- [API_WORDPRESS_GUIDE.md](./API_WORDPRESS_GUIDE.md) - WordPress 詳細指南 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_API_KEY_INTEGRATION_TESTS.md b/docs_v1.0/IMPLEMENTATION/ROOT_API_KEY_INTEGRATION_TESTS.md deleted file mode 100644 index 366610c..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_API_KEY_INTEGRATION_TESTS.md +++ /dev/null @@ -1,236 +0,0 @@ -# API Key Management Integration Tests - -## Test Environment Setup - -### Prerequisites - -```bash -# Start services -sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.redis.plist - -# Set environment variables -export DATABASE_URL="postgres://accusys@localhost:5432/momentry" -export REDIS_URL="redis://:accusys@localhost:6379" -export GITEA_URL="http://localhost:3000" -export N8N_URL="https://n8n.momentry.ddns.net" -``` - -### Run Tests - -```bash -# Run all unit tests -cargo test --lib - -# Run API key specific tests -cargo test --lib api_key - -# Run with output -cargo test --lib -- --nocapture -``` - ---- - -## Test Cases - -### 1. API Key Creation - -```bash -# Test: Create a service key -momentry api-key create test-key --key-type service --ttl 90 - -# Expected Output: -# ✅ API Key created successfully! -# Key ID: msvc_... -# API Key: msvc_... -# Expires: 2026-06-19 -``` - -### 2. API Key Validation - -```bash -# Test: Validate the created key -momentry api-key validate --key "msvc_..." - -# Expected Output: -# ✅ API Key is valid -# Key ID: msvc_... -# Name: test-key -# Type: service -``` - -### 3. API Key Listing - -```bash -# Test: List all keys -momentry api-key list - -# Expected Output: -# 📋 API Key List -# ┌────────────────────────────────────────────────────────────────────────────┐ -# │ Status │ Name │ Type │ Usage │ Last Used │ -# ├────────────────────────────────────────────────────────────────────────────┤ -# │ ✓ active │ test-key │ "service" │ 0 │ never │ -# └────────────────────────────────────────────────────────────────────────────┘ -``` - -### 4. API Key Statistics - -```bash -# Test: Show statistics -momentry api-key stats - -# Expected Output: -# 📊 API Key Statistics -# ┌─────────────────────────────────────────┐ -# │ Total Keys: 1 │ -# │ Active Keys: 1 │ -# │ Expired Keys: 0 │ -# └─────────────────────────────────────────┘ -``` - -### 5. Gitea Token Creation - -```bash -# Test: Create Gitea token -momentry gitea create \ - --username admin \ - --password "Test3200Test3200Test3200" \ - --token-name "test-token" \ - --scopes "read:repository,write:repository" - -# Expected Output: -# ✅ Gitea Token created successfully! -# Token ID: ... -# SHA1: ... -``` - -### 6. n8n API Key Creation - -```bash -# Test: Create n8n API key -momentry n8n create \ - --api-key "existing-n8n-key" \ - --label "test-key" \ - --expires-in-days 90 - -# Expected Output: -# ✅ n8n API Key created successfully! -# Key ID: ... -# API Key: ... -``` - ---- - -## Automated Test Script - -```bash -#!/bin/bash -# integration_test.sh - -set -e - -echo "=== API Key Integration Tests ===" - -# 1. Create API key -echo "1. Testing API key creation..." -momentry api-key create integration-test --key-type service --ttl 30 -echo "✅ API key created" - -# 2. List keys -echo "2. Testing API key listing..." -momentry api-key list -echo "✅ API key list OK" - -# 3. Show stats -echo "3. Testing statistics..." -momentry api-key stats -echo "✅ Statistics OK" - -# 4. Test Gitea integration -echo "4. Testing Gitea integration..." -GITEA_URL="http://localhost:3000" \ -momentry gitea list --username admin --password "Test3200Test3200Test3200" -echo "✅ Gitea integration OK" - -echo "" -echo "=== All Tests Passed ===" -``` - ---- - -## Unit Test Coverage - -| Module | Tests | Status | -|--------|-------|--------| -| `models.rs` | 0 | ✅ | -| `service.rs` | 5 | ✅ | -| `validator.rs` | 2 | ✅ | -| `gitea.rs` | 3 | ✅ | -| `n8n.rs` | 2 | ✅ | -| `rotation.rs` | 4 | ✅ | -| `anomaly.rs` | 0 | ✅ | -| `blacklist.rs` | 5 | ✅ | -| `encryption.rs` | 2 | ✅ | -| `webhook.rs` | 2 | ✅ | -| `error.rs` | 3 | ✅ | -| `report.rs` | 1 | ✅ | -| `cleanup.rs` | 1 | ✅ | -| **Total** | **30** | **✅** | - ---- - -## CI/CD Integration - -### GitHub Actions / Gitea Actions - -```yaml -name: API Key Tests - -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - services: - postgres: - image: postgres:15 - env: - POSTGRES_USER: accusys - POSTGRES_DB: momentry_test - ports: - - 5432:5432 - redis: - image: redis:7 - ports: - - 6379:6379 - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - run: cargo test --lib api_key -``` - ---- - -## Troubleshooting - -### Common Issues - -1. **Database connection failed** - ```bash - # Check PostgreSQL status - pg_isready -h localhost -p 5432 - ``` - -2. **Redis connection failed** - ```bash - # Check Redis status - redis-cli -a accusys ping - ``` - -3. **Gitea authentication failed** - ```bash - # Verify credentials - curl -u admin:password http://localhost:3000/api/v1/user - ``` diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_API_N8N_GUIDE.md b/docs_v1.0/IMPLEMENTATION/ROOT_API_N8N_GUIDE.md deleted file mode 100644 index fc567b9..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_API_N8N_GUIDE.md +++ /dev/null @@ -1,222 +0,0 @@ -# n8n 呼叫 Momentry API 指南 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-23 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-23 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-26 | 新增 API Key 驗證說明,更新 HTTP Request Node 設定 | OpenCode | deepseek-reasoner | - ---- - -**用途**: 在 n8n workflow 中呼叫 Momentry API - ---- - -## API URL - -在 n8n HTTP Request Node 中,**請使用外部 URL**: - -``` -https://api.momentry.ddns.net -``` - -> ⚠️ **不要使用** `localhost:3002`,因為 n8n 需要從外部訪問 API。 - ---- - -## 常用端點 - -| 方法 | 端點 | 說明 | -|------|------|------| -| GET | `/health` | 健康檢查 | -| POST | `/api/v1/n8n/search` | 語意搜尋(推薦) | -| GET | `/api/v1/videos` | 列出所有影片 | -| GET | `/api/v1/lookup` | 查詢影片 | -| GET | `/api/v1/progress/:uuid` | 處理進度 | -| GET | `/api/v1/jobs` | 任務列表 | -| GET | `/api/v1/jobs/:uuid` | 任務詳情 | - ---- - -## HTTP Request Node 設定 - -### 語意搜尋(推薦) - -``` -Node: HTTP Request -├── URL: https://api.momentry.ddns.net/api/v1/n8n/search -├── Method: POST -├── Authentication: None -├── Send Body: ✓ (checked) -├── Content Type: JSON -├── Body: -│ { -│ "query": "={{ $json.query }}", -│ "limit": "={{ $json.limit || 10 }}" -│ } -├── Send Headers: ✓ (checked) -└── Header Parameters: - └── X-API-Key: {{ $env.MOMENTRY_API_KEY }} -``` - -### 測試用(固定關鍵字) - -``` -Node: HTTP Request -├── URL: https://api.momentry.ddns.net/api/v1/n8n/search -├── Method: POST -├── Send Body: ✓ -├── Content Type: JSON -├── Body: -│ { -│ "query": "charade", -│ "limit": 3 -│ } -├── Send Headers: ✓ (checked) -└── Header Parameters: - └── X-API-Key: {{ $env.MOMENTRY_API_KEY }} -``` - ---- - -## 完整 Workflow 範例 - -### 基本搜尋 Workflow - -```json -{ - "name": "Momentry Video Search", - "nodes": [ - { - "parameters": {}, - "name": "Manual Trigger", - "type": "n8n-nodes-base.manualTrigger", - "position": [250, 300] - }, - { - "parameters": { - "url": "https://api.momentry.ddns.net/api/v1/n8n/search", - "method": "POST", - "sendBody": true, - "contentType": "json", - "body": { - "query": "charade", - "limit": 3 - } - }, - "name": "Search Video API", - "type": "n8n-nodes-base.httpRequest", - "position": [450, 300] - } - ], - "connections": { - "Manual Trigger": { - "main": [[{"node": "Search Video API"}]] - } - } -} -``` - ---- - -## 動態查詢 Workflow - -```json -{ - "name": "Momentry Dynamic Search", - "nodes": [ - { - "parameters": { - "httpMethod": "POST", - "path": "search", - "responseMode": "lastNode" - }, - "name": "Webhook", - "type": "n8n-nodes-base.webhook", - "position": [250, 300] - }, - { - "parameters": { - "url": "https://api.momentry.ddns.net/api/v1/n8n/search", - "method": "POST", - "sendBody": true, - "contentType": "json", - "body": { - "query": "={{ JSON.stringify($json.body.query) }}", - "limit": "={{ $json.body.limit || 5 }}" - } - }, - "name": "Search API", - "type": "n8n-nodes-base.httpRequest", - "position": [450, 300] - } - ], - "connections": { - "Webhook": { - "main": [[{"node": "Search API"}]] - } - } -} -``` - ---- - -## 常見錯誤 - -### 錯誤: 502 Bad Gateway - -**原因**: API 服務未啟動 - -**解決**: -```bash -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist -``` - -### 錯誤: "Your request is invalid" - -**原因**: Body 格式設定錯誤 - -**正確設定**: -- `Content Type`: JSON -- `Body`: 必須是有效的 JSON 物件 - ---- - -## curl 測試 - -在終端機中測試 API: - -> **注意**: 所有 `/api/v1/*` 端點都需要 API Key 驗證。請設定環境變數或直接替換 API Key。 - -```bash -# 設定環境變數(使用您的 API Key) -export MOMENTRY_API_KEY="muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" -``` - -```bash -# 健康檢查 -curl https://api.momentry.ddns.net/health - -# 搜尋測試 (需要 API Key) -curl -X POST https://api.momentry.ddns.net/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: $MOMENTRY_API_KEY" \ - -d '{"query":"charade","limit":3}' -``` - ---- - -## 相關文件 - -- [API_INDEX.md](./API_INDEX.md) - 文件總覽 -- [API_ENDPOINTS.md](./API_ENDPOINTS.md) - 端點完整說明 -- [N8N_HTTP_REQUEST_GUIDE.md](./N8N_HTTP_REQUEST_GUIDE.md) - HTTP Request 詳細設定 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_API_WORDPRESS_GUIDE.md b/docs_v1.0/IMPLEMENTATION/ROOT_API_WORDPRESS_GUIDE.md deleted file mode 100644 index f53ab30..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_API_WORDPRESS_GUIDE.md +++ /dev/null @@ -1,325 +0,0 @@ -# WordPress 呼叫 Momentry API 指南 - -| 項目 | 內容 | -|------|------| -| 版本 | V1.1 | -| 日期 | 2026-03-25 | -| 用途 | 在 WordPress 中呼叫 Momentry API | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.1 | 2026-03-25 | 更新: n8n 搜尋回傳 `file_path` 取代 `media_url`,新增 API Key 驗證說明 | OpenCode | deepseek-reasoner | -| V1.0 | 2026-03-23 | 創建 WordPress API 指南 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## API URL - -在 WordPress 中呼叫 API,**請使用外部 URL**: - -``` -https://api.momentry.ddns.net -``` - -> ⚠️ WordPress 運行於瀏覽器端,無法直接訪問 `localhost`。 - ---- - -## API 認證 - -所有 `/api/v1/*` 端點(除了健康檢查)都需要 API Key 認證。請在請求標頭中加入: - -``` -'headers' => ['Content-Type' => 'application/json', 'X-API-Key' => 'YOUR_API_KEY'] -``` - -**目前示範使用的 API Key**: `demo_api_key_12345` - -> **注意**: 正式環境請使用安全的 API Key 管理機制,避免在客戶端 JavaScript 中暴露 API Key。 - ---- - -## 常用端點 - -| 方法 | 端點 | 說明 | -|------|------|------| -| GET | `/health` | 健康檢查 | -| POST | `/api/v1/search` | 語意搜尋(標準格式) | -| GET | `/api/v1/videos` | 列出所有影片 | -| GET | `/api/v1/lookup` | 查詢影片 | - ---- - -## PHP 範例 - -### 基本搜尋 - -```php - 'charade', - 'limit' => 10 -]; - -$response = wp_remote_post($api_url, [ - 'headers' => ['Content-Type' => 'application/json', 'X-API-Key' => 'YOUR_API_KEY'], - 'body' => json_encode($data), - 'timeout' => 30 -]); - -if (is_wp_error($response)) { - echo '錯誤: ' . $response->get_error_message(); -} else { - $body = json_decode(wp_remote_retrieve_body($response), true); - print_r($body['hits']); -} -?> -``` - -### 列出所有影片 - -```php - ['X-API-Key' => 'YOUR_API_KEY'], - 'timeout' => 30 -]); - -if (!is_wp_error($response)) { - $body = json_decode(wp_remote_retrieve_body($response), true); - foreach ($body['videos'] as $video) { - echo $video['file_name'] . "\n"; - } -} -?> -``` - -### 查詢特定影片 - -```php - ['X-API-Key' => 'YOUR_API_KEY'], - 'timeout' => 30 -]); - -if (!is_wp_error($response)) { - $video = json_decode(wp_remote_retrieve_body($response), true); - echo '檔案: ' . $video['file_name'] . "\n"; - echo '時長: ' . $video['duration'] . ' 秒'; -} -?> -``` - ---- - -## JavaScript 範例 - -### 使用 fetch - -```javascript -// 搜尋影片 -async function searchVideos(query, limit = 10) { - const response = await fetch('https://api.momentry.ddns.net/api/v1/n8n/search', { - method: 'POST', - headers: { 'Content-Type': 'application/json', 'X-API-Key': 'YOUR_API_KEY' }, - body: JSON.stringify({ query, limit }) - }); - - if (!response.ok) { - throw new Error('API 請求失敗'); - } - - return await response.json(); -} - -// 使用範例 -searchVideos('charade', 5) - .then(data => { - data.hits.forEach(hit => { - console.log(`${hit.text} (score: ${hit.score})`); - }); - }); -``` - ---- - -## WordPress Shortcode 範例 - -在 `functions.php` 中註冊短碼: - -```php - '', - 'limit' => '10' - ], $atts); - - if (empty($atts['query'])) { - return '

請提供搜尋關鍵字

'; - } - - $response = wp_remote_post('https://api.momentry.ddns.net/api/v1/n8n/search', [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'X-API-Key' => 'YOUR_API_KEY' // 替換為實際的 API Key - ], - 'body' => json_encode([ - 'query' => $atts['query'], - 'limit' => (int)$atts['limit'] - ]), - 'timeout' => 30 - ]); - - if (is_wp_error($response)) { - return '

搜尋服務暫時無法使用

'; - } - - $data = json_decode(wp_remote_retrieve_body($response), true); - - if (empty($data['hits'])) { - return '

找不到相關結果

'; - } - - $output = '
    '; - foreach ($data['hits'] as $hit) { - // 注意: API 現在返回 file_path 而非 media_url - // 需要將文件路徑轉換為可訪問的 URL - $file_path = $hit['file_path']; - $video_url = convert_file_path_to_url($file_path); // 需要實作此函數 - - $output .= sprintf( - '
  • %s 播放
  • ', - esc_html($hit['text']), - $video_url, - $hit['start'] - ); - } - $output .= '
'; - - return $output; -}); -?> -``` - -**使用方式**: -``` -[momentry_search query="charade" limit="5"] -``` - ---- - -## REST API Endpoint (WP >= 5.0) - -在 WordPress REST API 中註冊自定義端點: - -```php - 'POST', - 'callback' => function($request) { - $response = wp_remote_post( - 'https://api.momentry.ddns.net/api/v1/n8n/search', - [ - 'headers' => ['Content-Type' => 'application/json', 'X-API-Key' => 'YOUR_API_KEY'], - 'body' => json_encode([ - 'query' => $request->get_param('query'), - 'limit' => $request->get_param('limit', 10) - ]) - ] - ); - - if (is_wp_error($response)) { - return new WP_Error('api_error', 'API 請求失敗'); - } - - return json_decode(wp_remote_retrieve_body($response)); - } - ]); -}); -?> -``` - -**呼叫方式**: -``` -POST /wp-json/momentry/v1/search -Body: {"query": "charade", "limit": 5} -``` - ---- - -## 常見錯誤 - -### 錯誤: cURL error 7 - -**原因**: 無法連接到 API - -**檢查**: -1. API 服務是否啟動 -2. 網路是否可達 - -### 錯誤: 502 Bad Gateway - -**原因**: API 服務未啟動 - -**解決**: -```bash -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist -``` - ---- - -## curl 測試 - -在終端機中測試: - -```bash -# 健康檢查 -curl https://api.momentry.ddns.net/health - -# 搜尋測試 -curl -X POST https://api.momentry.ddns.net/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -d '{"query":"charade","limit":5}' -``` - ---- - -## 相關文件 - -- [API_INDEX.md](./API_INDEX.md) - 文件總覽 -- [API_ENDPOINTS.md](./API_ENDPOINTS.md) - 端點完整說明 -- [API_N8N_GUIDE.md](./API_N8N_GUIDE.md) - n8n 使用範例 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_BUILD_VERSION_RECORD.md b/docs_v1.0/IMPLEMENTATION/ROOT_BUILD_VERSION_RECORD.md deleted file mode 100644 index aa45da3..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_BUILD_VERSION_RECORD.md +++ /dev/null @@ -1,667 +0,0 @@ -# Momentry Core 版本紀錄 - -## 版本命名規則 - -### Main Version (主版本) -``` -v{major}.{minor} -例: v0.1, v0.2, v1.0 -``` - -### Build Version (建置版本) -``` -v{major}.{minor}.{YYYYMMDD_HHMMSS} -例: v0.1.20260325_143000 -``` - ---- - -## 版本紀錄存放位置 - -``` -/Users/accusys/momentry/versions/ -├── current/ # 目前使用版本 -│ ├── binary # 當前 binary -│ └── version.json # 版本資訊 -│ -├── releases/ # Release 版本存放 -│ ├── v0.1/ -│ │ ├── v0.1.20260325_143000/ -│ │ │ ├── binary -│ │ │ └── version.json -│ │ ├── v0.1.20260324_100000/ -│ │ │ └── ... -│ │ └── release.json # v0.1 版本總覽 -│ │ -│ └── v0.2/ -│ └── ... -│ -└── changelog.json # 全域版本變更記錄 -``` - ---- - -## version.json 格式 - -```json -{ - "version": "v0.1.20260325_143000", - "main_version": "v0.1", - "build_timestamp": "2026-03-25T14:30:00+08:00", - "git_commit": "83ae050", - "git_branch": "main", - "git_message": "fix: save probe.json to OUTPUT_DIR instead of current directory", - "features": [ - "API Key Authentication", - "Job Worker System" - ], - "fixes": [ - "get_processor_results_by_job column mapping" - ], - "deployed_at": "2026-03-25T15:00:00+08:00", - "deployed_by": "opencode", - "status": "production" -} -``` - ---- - -## release.json 格式 (主版本總覽) - -```json -{ - "version": "v0.1", - "status": "production", - "created_at": "2026-03-14T10:00:00+08:00", - "current_build": "v0.1.20260325_143000", - "builds": [ - { - "build": "v0.1.20260325_143000", - "date": "2026-03-25", - "commits": ["83ae050", "171c36a"], - "summary": "fix: save probe.json, add v2 backup versioning" - }, - { - "build": "v0.1.20260324_100000", - "date": "2026-03-24", - "commits": ["89fbfd6", "3edaf01"], - "summary": "feat: add POST /api/v1/probe endpoint" - } - ], - "changelog": [ - "## v0.1.20260325_143000", - "- 修復 processor_results 欄位映射錯誤", - "- 添加 API Key 認證", - "", - "## v0.1.20260324_100000", - "- 新增 Probe API" - ] -} -``` - ---- - -## changelog.json 格式 (全域變更記錄) - -```json -{ - "updated_at": "2026-03-25T14:30:00+08:00", - "versions": { - "v0.1": { - "status": "production", - "current_build": "v0.1.20260325_143000", - "build_count": 12 - }, - "v0.0": { - "status": "deprecated", - "final_build": "v0.0.20260310_090000" - } - }, - "recent_changes": [ - { - "version": "v0.1.20260325_143000", - "date": "2026-03-25", - "changes": [ - {"type": "fix", "description": "get_processor_results_by_job column mapping"}, - {"type": "feat", "description": "API Key Authentication"} - ] - } - ] -} -``` - ---- - -## Release Script - -### /Users/accusys/momentry/scripts/release.sh - -```bash -#!/bin/bash -set -e - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -PROJECT_DIR="/Users/accusys/momentry_core_0.1" -VERSIONS_DIR="/Users/accusys/momentry/versions" -BACKUP_DIR="/Users/accusys/momentry/backup/bin" -CURRENT_BIN="/Users/accusys/momentry/bin/momentry" - -# 顏色輸出 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } -log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } -log_error() { echo -e "${RED}[ERROR]${NC} $1"; } - -# 解析命令列參數 -MAIN_VERSION="" -while [[ $# -gt 0 ]]; do - case $1 in - -v|--version) - MAIN_VERSION="$2" - shift 2 - ;; - *) - log_error "Unknown option: $1" - exit 1 - ;; - esac -done - -if [ -z "$MAIN_VERSION" ]; then - log_error "請指定主版本: ./release.sh -v v0.1" - exit 1 -fi - -log_info "開始 Release ${MAIN_VERSION}..." - -# 1. 取得 Git 資訊 -GIT_COMMIT=$(git -C "$PROJECT_DIR" rev-parse --short HEAD) -GIT_BRANCH=$(git -C "$PROJECT_DIR" rev-parse --abbrev-ref HEAD) -GIT_MESSAGE=$(git -C "$PROJECT_DIR" log -1 --pretty=%s) -BUILD_TIMESTAMP=$(date +%Y%m%d_%H%M%S) -BUILD_VERSION="${MAIN_VERSION}.${BUILD_TIMESTAMP}" - -log_info "Build Version: ${BUILD_VERSION}" -log_info "Git Commit: ${GIT_COMMIT}" - -# 2. 創建版本目錄 -BUILD_DIR="${VERSIONS_DIR}/releases/${MAIN_VERSION}/${BUILD_VERSION}" -mkdir -p "$BUILD_DIR" -mkdir -p "${VERSIONS_DIR}/current" -mkdir -p "$BACKUP_DIR" - -# 3. 停止 Production Service -log_info "停止 Production Service..." -sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist 2>/dev/null || true - -# 4. 備份當前 Binary -if [ -f "$CURRENT_BIN" ]; then - OLD_VERSION=$(cat "${VERSIONS_DIR}/current/version.json" 2>/dev/null | jq -r '.version // "unknown"') - log_info "備份當前版本: $OLD_VERSION" - cp "$CURRENT_BIN" "${BACKUP_DIR}/momentry_${OLD_VERSION}_$(date +%Y%m%d_%H%M%S)" -fi - -# 5. 編譯 Release 版本 -log_info "編譯 Release 版本..." -cd "$PROJECT_DIR" -cargo build --release --bin momentry - -# 6. 複製到版本目錄 -log_info "複製到版本目錄..." -cp target/release/momentry "${BUILD_DIR}/binary" -cp target/release/momentry "$CURRENT_BIN" - -# 7. 生成 version.json -cat > "${BUILD_DIR}/version.json" << EOF -{ - "version": "${BUILD_VERSION}", - "main_version": "${MAIN_VERSION}", - "build_timestamp": "$(date -Iseconds)", - "git_commit": "${GIT_COMMIT}", - "git_branch": "${GIT_BRANCH}", - "git_message": "${GIT_MESSAGE}", - "features": [], - "fixes": [], - "deployed_at": null, - "deployed_by": null, - "status": "built" -} -EOF - -# 8. 更新 current -cp "${BUILD_DIR}/version.json" "${VERSIONS_DIR}/current/version.json" - -# 9. 更新 changelog.json -UPDATE_CHANGELOG=" -import json -from datetime import datetime - -changelog_path = '${VERSIONS_DIR}/changelog.json' -build_info = { - 'version': '${BUILD_VERSION}', - 'date': datetime.now().strftime('%Y-%m-%d'), - 'commit': '${GIT_COMMIT}', - 'message': '${GIT_MESSAGE}' -} - -try: - with open(changelog_path, 'r') as f: - changelog = json.load(f) -except FileNotFoundError: - changelog = {'updated_at': '', 'versions': {}, 'recent_changes': []} - -changelog['updated_at'] = datetime.now().isoformat() -if '${MAIN_VERSION}' not in changelog['versions']: - changelog['versions']['${MAIN_VERSION}'] = {'status': 'building', 'build_count': 0} - -changelog['versions']['${MAIN_VERSION}']['build_count'] += 1 -changelog['versions']['${MAIN_VERSION}']['current_build'] = '${BUILD_VERSION}' -changelog['recent_changes'].insert(0, build_info) - -with open(changelog_path, 'w') as f: - json.dump(changelog, f, indent=2, ensure_ascii=False) -" -python3 -c "$UPDATE_CHANGELOG" - -# 10. 啟動 Production Service -log_info "啟動 Production Service..." -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 11. 驗證 -sleep 3 -if curl -s http://localhost:3002/health > /dev/null; then - log_info "✓ Release 成功!" - log_info "版本: ${BUILD_VERSION}" - log_info "目錄: ${BUILD_DIR}" -else - log_error "✗ Release 失敗!請檢查服務狀態。" - exit 1 -fi -``` - ---- - -## 查詢版本指令 - -### 查詢目前版本 -```bash -cat /Users/accusys/momentry/versions/current/version.json -``` - -### 查詢所有 Release -```bash -ls -la /Users/accusys/momentry/versions/releases/ -``` - -### 查詢版本歷史 -```bash -cat /Users/accusys/momentry/versions/changelog.json | python3 -m json.tool -``` - -### 查詢特定主版本 -```bash -ls /Users/accusys/momentry/versions/releases/v0.1/ -``` - ---- - -## 版本狀態 - -| 狀態 | 說明 | -|------|------| -| `building` | 建置中 | -| `built` | 已建置,未部署 | -| `testing` | 測試中 | -| `production` | 正式環境使用中 | -| `deprecated` | 已棄用 | -| `archived` | 已封存 | - ---- - -## 版本流程圖 - -``` -develop (git branch) - │ - ▼ -feature/bugfix commit - │ - ▼ -develop ──────────────────┐ - │ │ - │ (merge to main) │ - ▼ │ -main (git) │ - │ │ - ▼ │ -Build v0.1.20260325_143000 - │ │ - ├──► testing (3003) │ - │ │ - │ (approve) │ - ▼ ▼ -v0.1 ───────────────────┘ - │ - ├──► releases/v0.1/v0.1.20260325_143000/ - │ - ├──► current/ (production) - │ - ▼ -changelog.json (update) -``` - ---- - -## Release Note (版本發布說明) - -### Release Note 存放位置 - -``` -/Users/accusys/momentry/versions/releases/{主版本}/{建置版本}/ -├── binary -├── version.json -└── RELEASE_NOTE.md # 發布說明 (Markdown) -``` - -### Release Note 範本 - -```markdown -# Momentry Core v0.1.20260325_143000 Release Note - -## 版本資訊 -- **Build Version**: v0.1.20260325_143000 -- **Main Version**: v0.1 -- **Build Date**: 2026-03-25 14:30:00 -- **Git Commit**: 83ae050 - -## 新功能 (Features) - -### API Key 認證系統 -- 添加 API Key 認證中介層 -- 所有 `/api/v1/*` 端點需要 `X-API-Key` header -- 支援 API Key 使用追蹤和審計日誌 - -### Job Worker 系統 -- 新增 Job Worker 二進位檔 -- 支援最多 2 個並發處理器 -- 新增 `/api/v1/jobs/:uuid` 端點查詢任務詳情 - -## 錯誤修復 (Bug Fixes) - -| Issue | 描述 | -|-------|------| -| #001 | 修復 `get_processor_results_by_job` 欄位映射錯誤 | -| #002 | 修復 API Key 驗證時區處理問題 | - -## API 變更 (API Changes) - -### 新增端點 -| Method | Endpoint | 說明 | -|--------|----------|------| -| GET | `/api/v1/jobs` | 取得所有任務列表 | -| GET | `/api/v1/jobs/:uuid` | 取得特定任務詳情 | - -### 認證變更 -| 端點 | 舊版 | 新版 | -|------|------|------| -| `/api/v1/*` | 公開 | 需要 API Key | - -## 升級指南 - -### 從舊版升級 -1. 備份當前版本 -2. 停止服務 -3. 替換 binary -4. 重啟服務 -5. 更新 API Key 配置 - -### API Key 配置 -```bash -# 請求範例 -curl -H "X-API-Key: your_api_key" \ - "http://localhost:3002/api/v1/videos" -``` - -## 已知問題 (Known Issues) - -- 暫無 - -## 相關文檔 - -- [API 文檔](../docs/API_INDEX.md) -- [版本管理規範](../docs/VERSION_MANAGEMENT.md) - ---- - -## Release Note 自動生成 Script - -### /Users/accusys/momentry/scripts/generate_release_note.sh - -```bash -#!/bin/bash -set -e - -BUILD_VERSION=$1 -MAIN_VERSION=$2 -BUILD_DIR="/Users/accusys/momentry/versions/releases/${MAIN_VERSION}/${BUILD_VERSION}" - -# 取得 Git 資訊 -GIT_COMMITS=$(git log --oneline -10) -GIT_CHANGES=$(git diff --stat HEAD~5..HEAD) - -cat > "${BUILD_DIR}/RELEASE_NOTE.md" << EOF -# Momentry Core ${BUILD_VERSION} Release Note - -## 版本資訊 -- **Build Version**: ${BUILD_VERSION} -- **Main Version**: ${MAIN_VERSION} -- **Build Date**: $(date '+%Y-%m-%d %H:%M:%S') -- **Git Commit**: $(git rev-parse --short HEAD) - -## 變更內容 - -### Commit 記錄 -\`\`\` -${GIT_COMMITS} -\`\`\` - -### 變更統計 -\`\`\` -${GIT_CHANGES} -\`\`\` - -## 新功能 - -## 錯誤修復 - -## API 變更 - -## 升級指南 - -## 已知問題 - -EOF - -echo "Release Note 生成完成: ${BUILD_DIR}/RELEASE_NOTE.md" -``` - ---- - -## Release Note 查詢 - -### 查詢所有 Release Note -```bash -find /Users/accusys/momentry/versions/releases -name "RELEASE_NOTE.md" -``` - -### 查看特定版本 Release Note -```bash -cat /Users/accusys/momentry/versions/releases/v0.1/v0.1.20260325_143000/RELEASE_NOTE.md -``` - -### 查詢最新版本 Release Note -```bash -cat /Users/accusys/momentry/versions/current/RELEASE_NOTE.md -``` - ---- - -## Release Note 範例 - -### 完整 Release Note 範例 - -\`\`\`markdown -# Momentry Core v0.1.20260325_143000 Release Note - -## 版本資訊 -| 項目 | 內容 | -|------|------| -| Build Version | v0.1.20260325_143000 | -| Main Version | v0.1 | -| Build Date | 2026-03-25 14:30:00 | -| Git Commit | 83ae050 | -| Status | ✅ Production | - -## 新功能 (Features) - -### 1. API Key 認證系統 -添加完整的 API Key 認證系統,保護所有 API 端點。 - -**功能:** -- SHA256 key hash 驗證 -- 使用統計追蹤 -- 審計日誌記錄 -- 異常檢測 - -**API 使用方式:** -\`\`\`bash -curl -H "X-API-Key: your_key" \\ - "http://localhost:3002/api/v1/videos" -\`\`\` - -### 2. Job Worker 系統 -新增獨立的 Job Worker 處理影片處理任務。 - -**特性:** -- 最多 2 個並發處理器 -- Polling-based 任務獲取 -- 自動進度追蹤 - -## 錯誤修復 (Bug Fixes) - -| Issue | 描述 | 嚴重性 | -|-------|------|--------| -| #001 | 修復 `get_processor_results_by_job` TIMESTAMP 欄位映射 | 🔴 高 | -| #002 | 修復 3002 port 衝突問題 | 🟡 中 | - -## API 變更 - -### 新增端點 -| Method | Endpoint | 說明 | -|--------|----------|------| -| GET | `/api/v1/jobs` | 取得任務列表 | -| GET | `/api/v1/jobs/:uuid` | 取得任務詳情 | - -### 端點認證狀態 -| 端點 | 認證需求 | -|------|----------| -| `/health` | ❌ 不需要 | -| `/api/v1/*` | ✅ 需要 `X-API-Key` | - -## 升級指南 - -### 前置需求 -- PostgreSQL 資料庫 -- Redis 伺服器 -- MongoDB 快取 - -### 升級步驟 -1. **備份當前版本** - \`\`\`bash - cp /Users/accusys/momentry/bin/momentry \\ - /Users/accusys/momentry/backup/bin/momentry_$(date +%Y%m%d) - \`\`\` - -2. **停止服務** - \`\`\`bash - sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist - \`\`\` - -3. **替換 Binary** - \`\`\`bash - cp v0.1.20260325_143000/binary /Users/accusys/momentry/bin/momentry - \`\`\` - -4. **重啟服務** - \`\`\`bash - sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - \`\`\` - -5. **驗證** - \`\`\`bash - curl http://localhost:3002/health - \`\`\` - -## 已知問題 (Known Issues) - -- 暫無 - -## 技術細節 - -### 認證流程 -\`\`\` -Client Request - │ - ▼ -[X-API-Key Header] ──► Middleware - │ │ - │ ▼ - │ Hash Key (SHA256) - │ │ - │ ▼ - │ DB Lookup - │ │ - │ ▼ - │ Validate Status - │ │ - ▼ ▼ -Handler ◄────────────────────┘ -\`\`\` - -### 資料庫變更 -\`\`\`sql --- 新增 duration_secs 欄位 -ALTER TABLE processor_results -ADD COLUMN IF NOT EXISTS duration_secs DOUBLE PRECISION; -\`\`\` - -## 回滾指南 - -如需回滾到上一版本: -\`\`\`bash -# 1. 停止服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist - -# 2. 恢復舊版 -cp /Users/accusys/momentry/backup/bin/momentry_v0.1.20260324_100000 \\ - /Users/accusys/momentry/bin/momentry - -# 3. 重啟服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist -\`\`\` - -## 聯繫與支援 - -- **Issue Tracker**: https://gitea.momentry.ddns.net/momentry/momentry_core/issues -- **文檔**: https://docs.momentry.ddns.net - ---- - -*Generated: $(date '+%Y-%m-%d %H:%M:%S')* -\`\`\` - -``` diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_DEMO_MANUAL.md b/docs_v1.0/IMPLEMENTATION/ROOT_DEMO_MANUAL.md deleted file mode 100644 index 4fb683e..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_DEMO_MANUAL.md +++ /dev/null @@ -1,686 +0,0 @@ -# Momentry Core API 示範手冊 - -| 項目 | 內容 | -|------|------| -| 建立者 | OpenCode | -| 建立時間 | 2026-03-25 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-25 | 創建示範手冊,包含 Demo API Key 與完整範例 | OpenCode | deepseek-reasoner | - ---- - -**狀態**: 完成 - ---- - -## 快速開始 - -### Demo API Key - -``` -API Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69 -Key ID: muser_68600856036340bcafc01930eb4bd839 -過期日: 2027-03-25 -``` - -### 測試連線 - -```bash -curl http://localhost:3002/health -``` - -```json -{"status":"ok","version":"0.1.0","uptime_ms":456464} -``` - -### 測試認證 - -```bash -curl -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - http://localhost:3002/api/v1/videos | jq '.videos | length' -``` - -```json -13 -``` - ---- - -## 環境 URL - -| 環境 | URL | 用途 | -|------|-----|------| -| **本地開發** | `http://localhost:3002` | 本機開發測試 | -| **外部訪問** | `https://api.momentry.ddns.net` | n8n/WordPress/curl 生產環境 | - ---- - -## 端點總覽 - -| 方法 | 端點 | 說明 | 認證 | -|------|------|------|------| -| GET | `/health` | 健康檢查 | 公開 | -| GET | `/health/detailed` | 詳細健康檢查 | 公開 | -| POST | `/api/v1/register` | 註冊影片 | 需要 | -| POST | `/api/v1/probe` | 探測影片資訊 | 需要 | -| POST | `/api/v1/search` | 語意搜尋 | 需要 | -| POST | `/api/v1/n8n/search` | n8n 格式搜尋 | 需要 | -| POST | `/api/v1/search/hybrid` | 混合搜尋 | 需要 | -| GET | `/api/v1/videos` | 列出所有影片 | 需要 | -| GET | `/api/v1/lookup` | 查詢影片 UUID | 需要 | -| GET | `/api/v1/progress/:uuid` | 處理進度 | 需要 | -| GET | `/api/v1/jobs` | 任務列表 | 需要 | -| GET | `/api/v1/jobs/:uuid` | 任務詳情 | 需要 | - ---- - -## 1. curl 範例 - -### 基本格式 - -```bash -curl -H "X-API-Key: YOUR_API_KEY" \ - -H "Content-Type: application/json" \ - URL -``` - -### 1.1 健康檢查(公開) - -```bash -# 基本健康檢查 -curl http://localhost:3002/health - -# 詳細健康檢查(含服務狀態) -curl http://localhost:3002/health/detailed -``` - -### 1.2 列出影片 - -```bash -curl -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - http://localhost:3002/api/v1/videos | jq '.' -``` - -```json -{ - "videos": [ - { - "uuid": "952f5854b9febad1", - "file_name": "ExaSAN PCIe series - Director Ou Yu-Zhi Shares His Experience.mp4", - "duration": 159.637188, - "width": 640, - "height": 360 - }, - ... - ] -} -``` - -### 1.3 搜尋影片 - -```bash -curl -X POST \ - -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - -H "Content-Type: application/json" \ - -d '{"query": "ExaSAN", "limit": 5}' \ - http://localhost:3002/api/v1/search | jq '.' -``` - -```json -{ - "results": [ - { - "uuid": "952f5854b9febad1", - "chunk_id": "...", - "text": "...", - "score": 0.85, - "start_time": 0.0, - "end_time": 5.0 - } - ], - "total": 1, - "query": "ExaSAN", - "took_ms": 123 -} -``` - -### 1.4 查詢進度 - -```bash -curl -H "X-API-Key: muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" \ - http://localhost:3002/api/v1/progress/952f5854b9febad1 | jq '.' -``` - -```json -{ - "uuid": "952f5854b9febad1", - "overall_progress": 67, - "current_processor": "yolo", - "processors": [ - {"name": "asr", "status": "completed"}, - {"name": "cut", "status": "completed"}, - {"name": "yolo", "status": "running"} - ] -} -``` - ---- - -## 2. n8n 範例 - -### 2.1 HTTP Request 節點設定 - -``` -Method: POST -URL: https://api.momentry.ddns.net/api/v1/search -Authentication: None (使用 Header) - -Headers: -┌─────────────────────┬──────────────────────────────────────────────────┐ -│ Name │ Value │ -├─────────────────────┼──────────────────────────────────────────────────┤ -│ X-API-Key │ muser_68600856036340bcafc01930eb4bd839_... │ -│ Content-Type │ application/json │ -└─────────────────────┴──────────────────────────────────────────────────┘ - -Body Content (JSON): -{ - "query": "{{ $json.search_term }}", - "limit": 5 -} -``` - -### 2.2 n8n 搜尋 Workflow - -```json -{ - "nodes": [ - { - "name": "Manual Trigger", - "type": "n8n-nodes-base.manualTrigger", - "position": [250, 300] - }, - { - "name": "Set Search Term", - "type": "n8n-nodes-base.set", - "parameters": { - "values": { - "json": { - "search_term": "ExaSAN" - } - } - }, - "position": [450, 300] - }, - { - "name": "Search Videos", - "type": "n8n-nodes-base.httpRequest", - "parameters": { - "method": "POST", - "url": "https://api.momentry.ddns.net/api/v1/search", - "authentication": "genericCredentialType", - "genericAuthType": "httpHeaderAuth", - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "X-API-Key", - "value": "muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" - } - ] - }, - "sendBody": true, - "bodyContentType": "json", - "specifyBody": "json", - "jsonBody": "={{ { \"query\": $json.search_term, \"limit\": 5 } }}" - }, - "position": [650, 300] - }, - { - "name": "Process Results", - "type": "n8n-nodes-base.code", - "parameters": { - "jsCode": "// Extract video results\nconst results = $input.first().json.results;\nreturn results.map(r => ({\n uuid: r.uuid,\n text: r.text,\n score: r.score,\n time: `${r.start_time}s - ${r.end_time}s`\n}));" - }, - "position": [850, 300] - } - ], - "connections": { - "Manual Trigger": { - "main": [[{"node": "Set Search Term"}]] - }, - "Set Search Term": { - "main": [[{"node": "Search Videos"}]] - }, - "Search Videos": { - "main": [[{"node": "Process Results"}]] - } - } -} -``` - -### 2.3 n8n 列出影片 Workflow - -```json -{ - "nodes": [ - { - "name": "Get Videos", - "type": "n8n-nodes-base.httpRequest", - "parameters": { - "method": "GET", - "url": "https://api.momentry.ddns.net/api/v1/videos", - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "X-API-Key", - "value": "muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" - } - ] - } - }, - "position": [450, 300] - }, - { - "name": "Extract Video List", - "type": "n8n-nodes-base.code", - "parameters": { - "jsCode": "const videos = $input.first().json.videos;\nreturn videos.map(v => ({\n json: {\n uuid: v.uuid,\n name: v.file_name,\n duration: Math.round(v.duration) + 's',\n resolution: `${v.width}x${v.height}`\n }\n}));" - }, - "position": [650, 300] - }, - { - "name": "Slack Notification", - "type": "n8n-nodes-base.slack", - "parameters": { - "channel": "#momentry", - "text": "=Found {{ $json.length }} videos:\n{{ $json.map(v => `• ${v.name} (${v.duration})`).join(`\n`) }}" - }, - "position": [850, 300] - } - ] -} -``` - -### 2.4 n8n 定時同步 Workflow - -```json -{ - "nodes": [ - { - "name": "Schedule Trigger", - "type": "n8n-nodes-base.scheduleTrigger", - "parameters": { - "rule": { - "interval": [{"field": "hours", "hours": 1}] - } - }, - "position": [250, 300] - }, - { - "name": "Get Pending Videos", - "type": "n8n-nodes-base.httpRequest", - "parameters": { - "method": "GET", - "url": "https://api.momentry.ddns.net/api/v1/videos" - }, - "position": [450, 300] - }, - { - "name": "Filter Processing", - "type": "n8n-nodes-base.filter", - "parameters": { - "conditions": { - "options": {"caseSensitive": true}, - "conditions": [ - {"id": "status", "leftValue": "{{ $json.status }}", "rightValue": "processing"} - ] - } - }, - "position": [650, 300] - } - ] -} -``` - ---- - -## 3. WordPress 範例 - -### 3.1 PHP 函數庫 - -```php - [ - 'X-API-Key' => self::API_KEY, - 'Content-Type' => 'application/json', - ], - 'timeout' => 30, - ]; - - if ($method === 'POST') { - $args['method'] = 'POST'; - $args['body'] = json_encode($data); - } - - $response = wp_remote_request($url, $args); - - if (is_wp_error($response)) { - throw new Exception($response->get_error_message()); - } - - return json_decode(wp_remote_retrieve_body($response), true); - } - - /** - * 列出所有影片 - */ - public function list_videos(): array { - return $this->request('/api/v1/videos'); - } - - /** - * 搜尋影片內容 - */ - public function search(string $query, int $limit = 10): array { - return $this->request('/api/v1/search', [ - 'query' => $query, - 'limit' => $limit, - ], 'POST'); - } - - /** - * 取得影片進度 - */ - public function get_progress(string $uuid): array { - return $this->request("/api/v1/progress/{$uuid}"); - } - - /** - * 檢查健康狀態 - */ - public function health_check(): array { - return $this->request('/health'); - } -} -``` - -### 3.2 短代碼 (Shortcode) - -```php - 10, - ], $atts); - - $api = new Momentry_API(); - - try { - $result = $api->list_videos(); - $videos = array_slice($result['videos'], 0, $atts['limit']); - - ob_start(); - ?> -
-

影片列表

-
    - -
  • - -
    - - UUID: - | 時長: - -
  • - -
-
- 載入失敗: ' . esc_html($e->getMessage()) . '

'; - } -}); - -// 搜尋短代碼 -add_shortcode('momentry_search', function($atts, $content = '') { - $query = sanitize_text_field($content); - - if (empty($query)) { - return '

請提供搜尋關鍵字

'; - } - - $api = new Momentry_API(); - - try { - $result = $api->search($query); - - ob_start(); - ?> -
-

」搜尋結果

- -

沒有找到相關結果

- -
    - -
  • - - - -
    - 相似度: % -
  • - -
- -
- 搜尋失敗: ' . esc_html($e->getMessage()) . '

'; - } -}); -``` - -### 3.3 使用方式 - -在 WordPress 頁面或文章中: - -``` -[momentry_videos limit="5"] - -[momentry_search]ExaSAN[/momentry_search] -``` - -### 3.4 REST API 整合 - -```php - 'GET', - 'callback' => function(WP_REST_Request $request) { - $query = sanitize_text_field($request->get_param('q')); - - if (empty($query)) { - return new WP_Error('missing_query', '需要搜尋關鍵字', ['status' => 400]); - } - - $api = new Momentry_API(); - $result = $api->search($query); - - return new WP_REST_Response($result, 200); - }, - 'permission_callback' => '__return_true', - ]); -}); - -// 使用方式: GET /wp-json/momentry/v1/search?q=ExaSAN -``` - ---- - -## 4. 疑難排解 - -### 4.1 常見錯誤 - -| 錯誤 | 原因 | 解決方案 | -|------|------|----------| -| `401 Unauthorized` | API Key 無效或過期 | 檢查 API Key 是否正確 | -| `500 Internal Server Error` | 伺服器錯誤 | 檢查 `/health/detailed` 服務狀態 | -| `Connection Timeout` | 網路問題 | 確認 `api.momentry.ddns.net` 可達 | - -### 4.2 測試腳本 - -```bash -#!/bin/bash -# test_api.sh - Momentry API 測試腳本 - -API_KEY="muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" -BASE_URL="http://localhost:3002" - -echo "=== 1. 健康檢查 ===" -curl -s "$BASE_URL/health" | jq . -echo "" - -echo "=== 2. 列出影片 ===" -curl -s -H "X-API-Key: $API_KEY" "$BASE_URL/api/v1/videos" | jq '.videos | length' -echo "" - -echo "=== 3. 搜尋測試 ===" -curl -s -X POST -H "X-API-Key: $API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"query": "test", "limit": 3}' \ - "$BASE_URL/api/v1/search" | jq '.results | length' -echo "" - -echo "=== 完成 ===" -``` - -### 4.3 驗證腳本 - -```bash -#!/bin/bash -# verify_auth.sh - 驗證 API Key - -API_KEY="muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" -BASE_URL="http://localhost:3002" - -# 測試 1: 無 API Key -echo "測試 1: 無 API Key" -RESULT=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/api/v1/videos") -[ "$RESULT" = "401" ] && echo "✅ 正確拒絕 (401)" || echo "❌ 預期 401,實際 $RESULT" - -# 測試 2: 有 API Key -echo "測試 2: 有 API Key" -RESULT=$(curl -s -H "X-API-Key: $API_KEY" "$BASE_URL/api/v1/videos") -echo "$RESULT" | jq -e '.videos' > /dev/null && echo "✅ 成功取得資料" || echo "❌ 取得資料失敗" - -# 測試 3: 無效 API Key -echo "測試 3: 無效 API Key" -RESULT=$(curl -s -o /dev/null -w "%{http_code}" -H "X-API-Key: invalid_key" "$BASE_URL/api/v1/videos") -[ "$RESULT" = "401" ] && echo "✅ 正確拒絕 (401)" || echo "❌ 預期 401,實際 $RESULT" -``` - ---- - -## 5. API Key 管理 - -### 5.1 建立新 API Key - -```bash -# 本地建立 -./target/release/momentry api-key create "My App" --key-type user --ttl 90 -``` - -### 5.2 列出 API Keys - -```bash -./target/release/momentry api-key list -``` - -### 5.3 驗證 API Key - -```bash -./target/release/momentry api-key validate --key "YOUR_API_KEY" -``` - -### 5.4 撤銷 API Key - -```bash -./target/release/momentry api-key revoke --key "YOUR_API_KEY" -``` - ---- - -## 附錄 - -### A. 影片 UUID 說明 - -UUID 是基於檔案路徑的 SHA256 哈希前 16 位: - -``` -/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4 - ↓ -SHA256 Hash - ↓ -9760d0820f0cf9a7 -``` - -### B. 處理器狀態 - -| 狀態 | 說明 | -|------|------| -| `pending` | 等待處理 | -| `running` | 處理中 | -| `completed` | 已完成 | -| `failed` | 失敗 | - -### C. 支援的處理器 - -- **ASR**: 語音識別 -- **CUT**: 場景剪切 -- **YOLO**: 物件偵測 - -### D. 聯絡支援 - -- Email: support@momentry.ddns.net -- 文件: https://docs.momentry.ddns.net -- GitHub: https://github.com/anomalyco/momentry diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_FRESH_MAC_INSTALLATION.md b/docs_v1.0/IMPLEMENTATION/ROOT_FRESH_MAC_INSTALLATION.md deleted file mode 100644 index 3f9143a..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_FRESH_MAC_INSTALLATION.md +++ /dev/null @@ -1,707 +0,0 @@ -# Momentry 系統全新 Mac 安裝指南 - -| 項目 | 內容 | -|------|------| -| 建立時間 | 2026-03-23 | -| 文件版本 | V1.0 | -| 適用對象 | 全新 Mac (Intel 或 Apple Silicon) | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | -|------|------|------|--------| -| V1.0 | 2026-03-23 | 創建文件 | OpenCode | - ---- - -## 快速概覽 - -### 安裝時間估算 - -| 項目 | 時間 | -|------|------| -| 系統準備 | 30 分鐘 | -| Homebrew 安裝 | 15 分鐘 | -| 資料庫服務 | 30 分鐘 | -| 應用服務 | 60 分鐘 | -| Momentry Core | 20 分鐘 | -| **總計** | **~2.5 小時** | - -### 系統需求 - -| 項目 | 最低需求 | 推薦需求 | -|------|----------|----------| -| macOS | 13.0 Ventura | 14.0+ Sonoma | -| 記憶體 | 8GB | 16GB+ | -| 儲存空間 | 100GB | 500GB+ | -| CPU | Apple Silicon M1 或 Intel i5 | M2/M3 或 Intel i7+ | - ---- - -## 第一部分:系統準備 - -### 1.1 macOS 初始設定 - -首次開機後,執行以下設定: - -```bash -# 1. 設定電腦名稱 -sudo scutil --set ComputerName "Momentry" -sudo scutil --set LocalHostName "momentry" - -# 2. 啟用 SSH 遠端登入 -sudo systemsetup -setremotelogin on - -# 3. 關閉休眠 (防止遠端斷線) -sudo pmset -a sleep 0 -sudo pmset -a hibernatemode 0 - -# 4. 允許任何來源 App (安裝開發工具用) -sudo spctl --master-disable - -# 5. 設定時區 -sudo systemsetup -settimezone "Asia/Taipei" -``` - -### 1.2 建立管理員帳戶 - -```bash -# 建立 Momentry 管理員帳戶 (可選) -sudo dscl . -create /Users/momentry -sudo dscl . -create /Users/momentry UserShell /bin/zsh -sudo dscl . -create /Users/momentry RealName "Momentry Admin" -sudo dscl . -create /Users/momentry PrimaryGroupID 80 -sudo dscl . -create /Users/momentry UniqueID 1001 -sudo dscl . -passwd /Users/momentry "momentry_password" -sudo dscl . -append /Groups/admin GroupMembership momentry -``` - ---- - -## 第二部分:Homebrew 安裝 - -### 2.1 安裝 Homebrew - -```bash -# 安裝 Homebrew -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - -# Apple Silicon 設定 -echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile -eval "$(/opt/homebrew/bin/brew shellenv)" - -# Intel Mac 設定 -# echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile -# eval "$(/usr/local/bin/brew shellenv)" - -# 驗證 -brew --version -``` - -### 2.2 安裝基礎工具 - -```bash -# 開發工具 -brew install \ - git \ - curl \ - wget \ - jq \ - yq \ - tree \ - htop \ - tmux \ - zsh \ - zsh-completions \ - ncdu \ - httpie \ - openssl \ - readline \ - sqlite \ - python@3.11 \ - rustup-init - -# Rust 初始化 -rustup-init -y -source "$HOME/.cargo/env" - -# Python 虛擬環境 -python3.11 -m venv ~/.venv -source ~/.venv/bin/activate -pip install --upgrade pip -``` - ---- - -## 第三部分:建立目錄結構 - -```bash -# 建立目錄結構 -mkdir -p /Users/accusys/momentry/{var,etc,log,scripts,backup} -mkdir -p /Users/accusys/momentry/var/{postgresql,mongodb,mariadb,redis,qdrant,n8n,ollama,sftpgo} -mkdir -p /Users/accusys/momentry/etc/{sftpgo,caddy,gitea,php} -mkdir -p /Users/accusys/momentry/scripts -mkdir -p /Users/accusys/momentry/backup/{daily,weekly,monthly} -mkdir -p /Users/accusys/workspace/sftpgo -mkdir -p /Users/accusys/sftpgo_test/{demo,uploads} - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry -chown -R accusys:staff /Users/accusys/workspace -chown -R accusys:staff /Users/accusys/sftpgo_test -``` - ---- - -## 第四部分:資料庫服務安裝 - -### 4.1 PostgreSQL - -```bash -# 安裝 -brew install postgresql@18 - -# 啟動服務 -brew services start postgresql@18 - -# 建立資料庫 -createdb momentry -createdb video_register -createdb n8n -createdb sftpgo - -# 建立用戶 -psql -U accusys -d postgres << 'EOF' -CREATE USER sftpgo WITH PASSWORD 'sftpgo_pass_2026'; -GRANT ALL PRIVILEGES ON DATABASE sftpgo TO sftpgo; -GRANT ALL PRIVILEGES ON DATABASE momentry TO accusys; -GRANT ALL PRIVILEGES ON DATABASE video_register TO accusys; -GRANT ALL PRIVILEGES ON DATABASE n8n TO accusys; -EOF - -# 驗證 -pg_isready -h 127.0.0.1 -p 5432 -``` - -### 4.2 MongoDB - -```bash -# 安裝 -brew tap mongodb/brew -brew install mongodb-community - -# 建立資料目錄 -mkdir -p /Users/accusys/momentry/var/mongodb -chown -R accusys:staff /Users/accusys/momentry/var/mongodb - -# 啟動服務 -brew services start mongodb-community - -# 建立用戶 -mongosh admin --eval " -db.createUser({ - user: 'accusys', - pwd: 'Test3200Test3200', - roles: [ - { role: 'readWriteAnyDatabase', db: 'admin' }, - { role: 'dbAdminAnyDatabase', db: 'admin' } - ] -}); -" - -# 驗證 -mongosh --quiet --eval "db.adminCommand('ping')" -``` - -### 4.3 Redis - -```bash -# 安裝 -brew install redis - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/redis - -# 建立配置文件 -cat > /Users/accusys/momentry/etc/redis/redis.conf << 'EOF' -requirepass accusys -dir /Users/accusys/momentry/var/redis -logfile /Users/accusys/momentry/log/redis.log -daemonize no -port 6379 -bind 127.0.0.1 -EOF - -# 啟動服務 -redis-server /Users/accusys/momentry/etc/redis/redis.conf & -sleep 2 - -# 驗證 -redis-cli -a accusys ping -``` - -### 4.4 MariaDB (WordPress) - -```bash -# 安裝 -brew install mariadb - -# 啟動服務 -brew services start mariadb - -# 安全設定 -mysql_secure_installation - -# 建立資料庫 -mysql -u root << 'EOF' -CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress_password'; -GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'localhost'; -FLUSH PRIVILEGES; -EOF - -# 驗證 -mysql -u root -e "SHOW DATABASES;" -``` - ---- - -## 第五部分:應用服務安裝 - -### 5.1 Ollama (LLM) - -```bash -# 安裝 -brew install ollama - -# 建立資料目錄 -mkdir -p /Users/accusys/momentry/var/ollama -mkdir -p ~/.ollama/models - -# 啟動服務 -brew services start ollama - -# 下載模型 -ollama pull llama3.2 -ollama pull nomic-embed-text - -# 驗證 -curl -s http://localhost:11434/api/tags | jq '.models[].name' -``` - -### 5.2 Caddy (反向代理) - -```bash -# 安裝 -brew install caddy - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/caddy - -# 建立 Caddyfile -cat > /Users/accusys/momentry/etc/caddy/Caddyfile << 'EOF' -{ - admin off - auto_https off -} - -# 範例:本地開發 -:8080 { - respond "Momentry Server" 200 -} -EOF - -# 啟動服務 -brew services start caddy - -# 驗證 -curl -s http://localhost:8080 -``` - -### 5.3 Gitea (Git 服務) - -```bash -# 安裝 -brew install gitea - -# 建立資料目錄 -mkdir -p /Users/accusys/momentry/var/gitea -mkdir -p /Users/accusys/momentry/etc/gitea - -# 複製設定檔 -cp /opt/homebrew/etc/gitea/conf/app.ini /Users/accusys/momentry/etc/gitea/ - -# 啟動服務 -brew services start gitea - -# 驗證 -curl -s http://localhost:3000 -``` - -### 5.4 n8n (工作流程自動化) - -```bash -# 安裝 Node.js (如果尚未安裝) -brew install node@22 - -# 全域安裝 n8n -npm install -g n8n - -# 建立資料目錄 -mkdir -p /Users/accusys/momentry/var/n8n - -# 設定環境變數 -export N8N_DATA_DIR=/Users/accusys/momentry/var/n8n -export DB_TYPE=postgresdb -export DB_POSTGRES_HOST=127.0.0.1 -export DB_POSTGRES_PORT=5432 -export DB_POSTGRES_DATABASE=n8n -export DB_POSTGRES_USER=accusys -export DB_POSTGRES_PASSWORD=accusys -export N8N_ENCRYPTION_KEY=Test3200Test3200Test3200 - -# 啟動服務 -n8n start & - -# 驗證 -curl -s http://localhost:5678 -``` - -### 5.5 SFTPGo (SFTP 服務) - -```bash -# 安裝 -brew install sftpgo - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/sftpgo - -# 建立配置文件 -cat > /Users/accusys/momentry/etc/sftpgo/sftpgo.json << 'EOF' -{ - "data_provider": { - "driver": "postgresql", - "host": "127.0.0.1", - "port": 5432, - "username": "sftpgo", - "password": "sftpgo_pass_2026", - "name": "sftpgo", - "create_default_admin": true - }, - "httpd": { - "bind_port": 8080, - "bind_address": "127.0.0.1" - }, - "sftpd": { - "bindings": [ - {"port": 2022} - ] - }, - "ftpd": { - "bindings": [ - {"port": 0} - ] - } -} -EOF - -# 建立 launchd plist -cat > /Library/LaunchDaemons/com.momentry.sftpgo.plist << 'EOF' - - - - - Label - com.momentry.sftpgo - UserName - accusys - WorkingDirectory - /Users/accusys/workspace/sftpgo - ProgramArguments - - /opt/homebrew/bin/sftpgo - serve - --config-file - /Users/accusys/momentry/etc/sftpgo/sftpgo.json - - EnvironmentVariables - - PATH - /opt/homebrew/bin:/opt/homebrew/sbin:/usr/bin:/bin - HOME - /Users/accusys - SFTPGO_DEFAULT_ADMIN_USERNAME - admin - SFTPGO_DEFAULT_ADMIN_PASSWORD - Test3200Test3200 - - RunAtLoad - - KeepAlive - - StandardOutPath - /Users/accusys/momentry/log/sftpgo.log - StandardErrorPath - /Users/accusys/momentry/log/sftpgo.error.log - - -EOF - -# 載入服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.sftpgo.plist - -# 驗證 -sleep 3 -curl -s -X POST http://localhost:8080/api/v2/token -u "admin:Test3200Test3200" -``` - -### 5.6 Qdrant (向量資料庫) - -```bash -# 安裝 Rust (如果尚未安裝) -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -source "$HOME/.cargo/env" - -# 安裝 Qdrant -cargo install qdrant - -# 建立資料目錄 -mkdir -p /Users/accusys/momentry/var/qdrant/storage - -# 啟動服務 -qdrant --data-path /Users/accusys/momentry/var/qdrant/storage --api-key Test3200Test3200Test3200 & - -# 驗證 -sleep 3 -curl -s http://localhost:6333/collections -H "api-key: Test3200Test3200Test3200" -``` - ---- - -## 第六部分:Momentry Core 安裝 - -### 6.1 安裝依賴 - -```bash -# 安裝 Python 依賴 -pip install \ - openai-whisper \ - ultralytics \ - opencv-python \ - pillow \ - python-dotenv \ - requests \ - httpx - -# 安裝 FFmpeg -brew install ffmpeg -``` - -### 6.2 安裝 Momentry Core - -```bash -# 克隆或進入專案目錄 -cd /Users/accusys/momentry_core_0.1 - -# 編譯專案 -cargo build --release - -# 複製執行檔 -cp target/release/momentry /usr/local/bin/ - -# 建立 launchd plist -cat > /Library/LaunchDaemons/com.momentry.api.plist << 'EOF' - - - - - Label - com.momentry.api - UserName - accusys - ProgramArguments - - /usr/local/bin/momentry - server - --host - 0.0.0.0 - --port - 3002 - - EnvironmentVariables - - DATABASE_URL - postgres://accusys:accusys@127.0.0.1:5432/momentry - RUST_LOG - info - - RunAtLoad - - KeepAlive - - StandardOutPath - /Users/accusys/momentry/log/momentry.log - StandardErrorPath - /Users/accusys/momentry/log/momentry.error.log - - -EOF - -# 載入服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 驗證 -sleep 3 -curl -s http://localhost:3002/health -``` - ---- - -## 第七部分:服務驗證 - -### 7.1 健康檢查腳本 - -```bash -#!/bin/bash -# health_check.sh - -echo "==========================================" -echo "Momentry System Health Check" -echo "==========================================" -echo "" - -# PostgreSQL -pg_isready -h 127.0.0.1 -p 5432 > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ PostgreSQL" || echo "❌ PostgreSQL" - -# MongoDB -mongosh --quiet --eval "db.adminCommand('ping')" > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ MongoDB" || echo "❌ MongoDB" - -# Redis -redis-cli -a accusys ping > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ Redis" || echo "❌ Redis" - -# Ollama -curl -s http://localhost:11434/api/tags > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ Ollama" || echo "❌ Ollama" - -# n8n -curl -s http://localhost:5678 > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ n8n" || echo "❌ n8n" - -# SFTPGo -curl -s http://localhost:8080 > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ SFTPGo" || echo "❌ SFTPGo" - -# Qdrant -curl -s http://localhost:6333/ > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ Qdrant" || echo "❌ Qdrant" - -# Momentry API -curl -s http://localhost:3002/health > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ Momentry API" || echo "❌ Momentry API" - -# Caddy -curl -sI http://localhost:8080 > /dev/null 2>&1 -[ $? -eq 0 ] && echo "✅ Caddy" || echo "❌ Caddy" - -echo "" -echo "==========================================" -``` - -### 7.2 執行驗證 - -```bash -# 儲存並執行 -chmod +x health_check.sh -./health_check.sh -``` - ---- - -## 第八部分:重要憑證總覽 - -### 8.1 服務密碼 - -| 服務 | 用戶名 | 密碼 | 用途 | -|------|--------|------|------| -| **PostgreSQL** | accusys | `accusys` | 主要資料庫 | -| **PostgreSQL** | sftpgo | `sftpgo_pass_2026` | SFTPGo 資料庫 | -| **MongoDB** | accusys | `Test3200Test3200` | 文件資料庫 | -| **Redis** | - | `accusys` | 快取服務 | -| **n8n** | - | `Test3200Test3200Test3200` | n8n 加密金鑰 | -| **SFTPGo** | admin | `Test3200Test3200` | SFTPGo 管理員 | -| **Qdrant** | - | `Test3200Test3200Test3200` | Qdrant API Key | -| **MariaDB** | root | (設定時指定) | WordPress 資料庫 | -| **MariaDB** | wordpress | `wordpress_password` | WordPress 資料庫用戶 | - -### 8.2 服務連接埠 - -| 服務 | 連接埠 | 協定 | -|------|--------|------| -| PostgreSQL | 5432 | TCP | -| MongoDB | 27017 | TCP | -| Redis | 6379 | TCP | -| Ollama | 11434 | HTTP | -| n8n | 5678 | HTTP | -| SFTPGo | 8080 | HTTP | -| SFTPGo | 2022 | SFTP | -| Qdrant | 6333 | HTTP | -| Momentry API | 3002 | HTTP | -| Caddy | 80/443 | HTTP/HTTPS | -| Gitea | 3000 | HTTP | -| PHP-FPM | 9000 | TCP | - ---- - -## 第九部分:相關文檔 - -| 文檔 | 說明 | -|------|------| -| `SERVICES.md` | 服務詳細說明 | -| `INSTALL_POSTGRESQL.md` | PostgreSQL 安裝指南 | -| `INSTALL_MONGODB.md` | MongoDB 安裝指南 | -| `INSTALL_REDIS.md` | Redis 安裝指南 | -| `INSTALL_QDRANT.md` | Qdrant 安裝指南 | -| `INSTALL_N8N.md` | n8n 安裝指南 | -| `INSTALL_SFTPGO.md` | SFTPGo 安裝指南 | -| `SFTPGO_DEMO_USER.md` | SFTPGo Demo 用戶指南 | -| `MOMENTRY_CORE_MONITORING.md` | 監控規範 | -| `API_INDEX.md` | API 文件索引 | - ---- - -## 附錄:常見問題 - -### Q1: n8n 無法連接 PostgreSQL - -確保資料庫用戶有登入權限: -```bash -psql -U accusys -d postgres -c "ALTER USER accusys WITH LOGIN;" -``` - -### Q2: SFTPGo 無法啟動 - -檢查 PostgreSQL 是否運行: -```bash -pg_isready -h 127.0.0.1 -p 5432 -``` - -### Q3: Qdrant API Key 無效 - -使用正確的 API Key: -```bash -curl -H "api-key: Test3200Test3200Test3200" http://localhost:6333/collections -``` - -### Q4: Momentry API 無法啟動 - -檢查環境變數: -```bash -export DATABASE_URL="postgres://accusys:accusys@127.0.0.1:5432/momentry" -export RUST_LOG=debug -momentry server --host 0.0.0.0 --port 3002 -``` diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_CADDY.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_CADDY.md deleted file mode 100644 index 5027742..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_CADDY.md +++ /dev/null @@ -1,467 +0,0 @@ -# Caddy 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-16 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-16 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 Caddy Web Server,配置為本地部署,作為反向代理伺服器。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| Caddy | ✅ 已安裝 v2.10.2 | -| 設定檔 | /Users/accusys/momentry/etc/Caddyfile | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.caddy.plist | - ---- - -## 安裝步驟 - -### Step 1: 安裝 Caddy (使用 brew) - -```bash -# 安裝 Caddy -brew install caddy -``` - -**驗證**: -```bash -caddy --version -# v2.10.2 -``` - ---- - -### Step 2: 建立目錄 - -```bash -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/caddy - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/caddy - -# 建立日誌文件 -touch /Users/accusys/momentry/log/caddy.log -touch /Users/accusys/momentry/log/caddy.error.log - -# 設定權限 -# 注意: Caddy 使用 ports 80/443,必須以 root 身份運行 -# 因此 var/caddy 目錄需要 root:admin 權限 -chown -R accusys:staff /Users/accusys/momentry/etc/caddy -chown -R accusys:staff /Users/accusys/momentry/log -sudo chown -R root:admin /Users/accusys/momentry/var/caddy -``` - ---- - -### Step 3: 建立設定檔 - -建立 `/Users/accusys/momentry/etc/Caddyfile`: - -```Caddyfile -{ - email admin@accusys.com.tw - metrics -} - -# 定義日誌 Snippet -(common_log) { - log { - output file /Users/accusys/momentry/log/{args[0]}.log { - roll_size 100mb - roll_keep 5 - roll_keep_for 720h - } - format json - } -} - -# Example: 反向代理到本地服務 -example.momentry.ddns.net { - reverse_proxy localhost:8080 { - header_up Host {upstream_hostport} - } - import common_log example_access -} -``` - ---- - -### Step 4: 使用 plist 開機自動啟動 - -**注意**: Caddy 需要使用 ports 80 和 443,必須以 root 身份運行。 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.caddy.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.caddy.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "caddy" - type: "http" - port: 80 - host: "localhost" - check_url: "http://localhost:2019/config/" - timeout: 5 - enabled: true -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/etc/caddy/` | 配置 | **不要刪除** - Caddy 配置 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/Users/accusys/momentry/var/caddy/` | 數據 | **不要刪除** - Caddy 數據 | -| `/opt/homebrew/opt/caddy/` | 安裝 | **刪除** - Caddy 安裝目錄 | -| `/opt/homebrew/opt/caddy/` | 安裝 | **刪除** - Caddy 安裝目錄 | - -### Step 1: 停止 Caddy - -```bash -# 找到 Caddy 進程 -ps aux | grep caddy | grep -v grep - -# 停止 Caddy -pkill caddy - -# 確認停止 -ps aux | grep caddy | grep -v grep || echo "Caddy 已停止" -``` - ---- - -### Step 2: 卸載 Caddy - -```bash -# 卸載 Caddy -brew uninstall caddy - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.caddy.plist -sudo rm /Library/LaunchDaemons/com.momentry.caddy.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除配置目錄 (可選) -rm -rf /Users/accusys/momentry/etc/Caddyfile - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/caddy.log -rm -f /Users/accusys/momentry/log/caddy.error.log - -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/caddy -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/etc -# /Users/accusys/momentry/log -# /Users/accusys/momentry/var -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== Caddy 卸載後檢查 ===" - -# 1. 檢查 Caddy 進程 -echo "1. Caddy 進程:" -ps aux | grep caddy | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 80/443 -echo "2. Port 80/443:" -(lsof -i :80 > /dev/null 2>&1 || lsof -i :443 > /dev/null 2>&1) && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. caddy 命令 -echo "3. caddy 命令:" -which caddy > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list caddy > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep caddy > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 配置目錄 (可選刪除) -echo "6. 配置目錄:" -[ -d "/Users/accusys/momentry/etc" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 7. 日誌目錄 (可選刪除) -echo "7. 日誌目錄:" -[ -d "/Users/accusys/momentry/log" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - -**預期結果**: -``` -=== Caddy 卸載後檢查 === -1. Caddy 進程: - ✓ 已停止 -2. Port 80/443: - ✓ 已釋放 -3. caddy 命令: - ✓ 已移除 -4. brew 安裝: - ✓ 已移除 -5. launchctl 服務: - ✓ 已移除 -6. 配置目錄: - ✓ 保留 (或 ✗ 已刪除) -7. 日誌目錄: - ✓ 保留 (或 ✗ 已刪除) -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep caddy | grep -v grep - -# 2. 檢查 Port -lsof -i :80 -lsof -i :443 -lsof -i :2019 - -# 3. 測試配置語法 -caddy validate --config /Users/accusys/momentry/etc/Caddyfile - -# 4. 查看 Caddy 版本 -caddy version - -# 5. 重新載入配置 -caddy reload --config /Users/accusys/momentry/etc/Caddyfile - -# 6. 查看日誌 -tail -20 /Users/accusys/momentry/log/caddy.log - -# 7. 查看 Caddy 適配的網站 -curl -I http://localhost:2019/config/ -``` - ---- - -## Caddyfile 範例 - -### 基本反向代理 - -```Caddyfile -{ - email admin@accusys.com.tw -} - -# 反向代理到本地服務 -example.local { - reverse_proxy localhost:8080 -} -``` - -### 帶 SSL 的反向代理 - -```Caddyfile -{ - email admin@accusys.com.tw -} - -# 使用 Let's Encrypt 自動 SSL -example.momentry.ddns.net { - reverse_proxy localhost:8080 { - header_up Host {upstream_hostport} - } -} -``` - -### 多站點配置 - -```Caddyfile -{ - email admin@accusys.com.tw -} - -# 站點 1 -site1.example.com { - reverse_proxy localhost:8080 -} - -# 站點 2 -site2.example.com { - reverse_proxy localhost:8081 -} -``` - ---- - -## 環境變數 - -在 `.env` 中: - -```env -CADDY_CONFIG=/Users/accusys/momentry/etc/Caddyfile -CADDY_HOME=/Users/accusys/.local/share/caddy -``` - ---- - -## 故障排除 - -### Caddy 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/caddy.log - -# 檢查配置語法 -caddy validate --config /Users/accusys/momentry/etc/Caddyfile - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/etc/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/etc -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 80 -lsof -i :80 - -# 終止佔用程序 -kill -``` - -### 需要重新載入配置 - -```bash -# 重新載入配置 (熱重載) -caddy reload --config /Users/accusys/momentry/etc/Caddyfile - -# 或者停止後重新啟動 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.caddy.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.caddy.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/caddy/` | Caddy 安裝目錄 | -| 執行檔 | `/opt/homebrew/opt/caddy/bin/caddy` | Caddy 執行檔 | -| 配置 | `/Users/accusys/momentry/etc/Caddyfile` | 設定檔 | -| 日誌 | `/Users/accusys/momentry/log/caddy.log` | 執行日誌 | -| 錯誤日誌 | `/Users/accusys/momentry/log/caddy.error.log` | 錯誤日誌 | -| 數據 | `/Users/accusys/momentry/var/caddy/` | Caddy 數據目錄 | -| plist | `/Library/LaunchDaemons/com.momentry.caddy.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/caddy_backup/Caddyfile` | 配置備份 | - ---- - -## 常用指令 - -```bash -# 驗證配置 -caddy validate --config /Users/accusys/momentry/etc/Caddyfile - -# 熱重載配置 -caddy reload --config /Users/accusys/momentry/etc/Caddyfile - -# 停止 Caddy -caddy stop - -# 啟動 Caddy -caddy start --config /Users/accusys/momentry/etc/Caddyfile - -# 適配所有網站 -caddy adapt --config /Users/accusys/momentry/etc/Caddyfile --adapter caddyfile -``` - ---- - -## 備份與恢復 - -### 備份 - -```bash -TIMESTAMP=$(date +%Y%m%d_%H%M%S) -BACKUP_DIR="/Users/accusys/momentry/backup/daily/caddy" - -mkdir -p "$BACKUP_DIR" - -# 備份配置 -tar -czf "$BACKUP_DIR/caddy_cfg_${TIMESTAMP}.tar.gz" \ - /Users/accusys/momentry/etc/Caddyfile - -# 驗證 -sha256sum "$BACKUP_DIR/caddy_cfg_${TIMESTAMP}.tar.gz" > "$BACKUP_DIR/caddy_${TIMESTAMP}.sha256" -``` - -### 恢復 - -```bash -# 解壓配置 -tar -xzf /Users/accusys/momentry/backup/daily/caddy/caddy_cfg_20260316_102416.tar.gz -C / - -# 驗證並重載 -caddy validate --config /Users/accusys/momentry/etc/Caddyfile -caddy reload --config /Users/accusys/momentry/etc/Caddyfile -``` - ---- - -## 版本資訊 - -- 版本: 2.10.2 -- 配置: /Users/accusys/momentry/etc/Caddyfile -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_GITEA.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_GITEA.md deleted file mode 100644 index 80423b4..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_GITEA.md +++ /dev/null @@ -1,410 +0,0 @@ -# Gitea 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-15 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-15 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 Gitea Git 服務,配置為本地部署。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| Gitea | ✅ 已安裝 v1.25.3 | -| 數據目錄 | /Users/accusys/momentry/var/gitea/ | -| 配置目錄 | /Users/accusys/momentry/etc/gitea/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.gitea.plist | - ---- - -## 安裝步驟 - -### Step 1: 安裝 Gitea (使用 brew) - -```bash -# 安裝 Gitea -brew install gitea -``` - -**驗證**: -```bash -gitea --version -# gitea version 1.25.3 -``` - ---- - -### Step 2: 建立目錄 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/gitea/data -mkdir -p /Users/accusys/momentry/var/gitea/log - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/gitea - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/gitea.log -touch /Users/accusys/momentry/log/gitea.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/gitea -chown -R accusys:staff /Users/accusys/momentry/etc/gitea -chown -R accusys:staff /Users/accusys/momentry/log -``` - ---- - -### Step 3: 建立設定檔 - -建立 `/Users/accusys/momentry/etc/gitea/app.ini`: - -```ini -APP_NAME = Gitea: Git with a cup of tea -RUN_USER = accusys -WORK_PATH = /Users/accusys/momentry/var/gitea -RUN_MODE = prod - -[database] -DB_TYPE = postgres -HOST = 127.0.0.1:5432 -NAME = gitea -USER = gitea -PASSWD = gitea_pass -SSL_MODE = disable - -[repository] -ROOT = /Users/accusys/momentry/var/gitea/data/gitea-repositories - -[server] -SSH_DOMAIN = gitea.momentry.ddns.net -DOMAIN = gitea.momentry.ddns.net -HTTP_PORT = 3000 -ROOT_URL = http://gitea.momentry.ddns.net:3000/ -APP_DATA_PATH = /Users/accusys/momentry/var/gitea/data -DISABLE_SSH = false -SSH_PORT = 2222 -LFS_START_SERVER = true -OFFLINE_MODE = true - -[lfs] -PATH = /Users/accusys/momentry/var/gitea/data/lfs - -[log] -MODE = console, file -ROOT_PATH = /Users/accusys/momentry/log -``` - ---- - -### Step 4: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.gitea.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.gitea.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "gitea" - type: "http" - port: 3000 - host: "localhost" - check_url: "http://localhost:3000/" - timeout: 5 - enabled: true -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/gitea/` | 數據 | **不要刪除** - Gitea 數據 | -| `/Users/accusys/momentry/etc/gitea/` | 配置 | **不要刪除** - Gitea 配置 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/opt/homebrew/opt/gitea/` | 安裝 | **刪除** - Gitea 安裝目錄 | - -### Step 1: 停止 Gitea - -```bash -# 找到 Gitea 進程 -ps aux | grep gitea | grep -v grep - -# 停止 Gitea -pkill gitea - -# 確認停止 -ps aux | grep gitea | grep -v grep || echo "Gitea 已停止" -``` - ---- - -### Step 2: 卸載 Gitea - -```bash -# 卸載 Gitea -brew uninstall gitea - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.gitea.plist -sudo rm /Library/LaunchDaemons/com.momentry.gitea.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/gitea - -# 刪除配置目錄 (可選) -rm -rf /Users/accusys/momentry/etc/gitea - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/gitea.log -rm -f /Users/accusys/momentry/log/gitea.error.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/etc -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== Gitea 卸載後檢查 ===" - -# 1. 檢查 Gitea 進程 -echo "1. Gitea 進程:" -ps aux | grep gitea | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 3000 -echo "2. Port 3000:" -lsof -i :3000 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. gitea 命令 -echo "3. gitea 命令:" -which gitea > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list gitea > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep gitea > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 數據目錄 (可選刪除) -echo "6. 數據目錄:" -[ -d "/Users/accusys/momentry/var/gitea" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 7. 配置目錄 (可選刪除) -echo "7. 配置目錄:" -[ -d "/Users/accusys/momentry/etc/gitea" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - -**預期結果**: -``` -=== Gitea 卸載後檢查 === -1. Gitea 進程: - ✓ 已停止 -2. Port 3000: - ✓ 已釋放 -3. gitea 命令: - ✓ 已移除 -4. brew 安裝: - ✓ 已移除 -5. launchctl 服務: - ✓ 已移除 -6. 數據目錄: - ✓ 保留 (或 ✗ 已刪除) -7. 配置目錄: - ✓ 保留 (或 ✗ 已刪除) -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep gitea | grep -v grep - -# 2. 檢查 Port -lsof -i :3000 - -# 3. 測試連線 -curl http://localhost:3000/ - -# 4. 查看版本 -gitea --version - -# 5. 驗證配置 -gitea doctor --config /Users/accusys/momentry/etc/gitea/app.ini - -# 6. 查看日誌 -tail -20 /Users/accusys/momentry/log/gitea.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| URL | http://localhost:3000 | -| Domain | gitea.momentry.ddns.net | -| SSH Port | 2222 | -| Database | PostgreSQL (gitea) | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -GITEA_URL=http://localhost:3000 -GITEA_ROOT=/Users/accusys/momentry/var/gitea/data/gitea-repositories -``` - ---- - -## 故障排除 - -### Gitea 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/gitea.log - -# 檢查配置語法 -gitea doctor --config /Users/accusys/momentry/etc/gitea/app.ini - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/var/gitea/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/gitea -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 3000 -lsof -i :3000 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.gitea.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.gitea.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/gitea/` | Gitea 安裝目錄 | -| 執行檔 | `/opt/homebrew/opt/gitea/bin/gitea` | Gitea 執行檔 | -| 數據目錄 | `/Users/accusys/momentry/var/gitea/data/` | 數據儲存 | -| 配置 | `/Users/accusys/momentry/etc/gitea/app.ini` | 設定檔 | -| 日誌 | `/Users/accusys/momentry/log/gitea.log` | 執行日誌 | -| 錯誤日誌 | `/Users/accusys/momentry/log/gitea.error.log` | 錯誤日誌 | -| plist | `/Library/LaunchDaemons/com.momentry.gitea.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/gitea_backup/app.ini` | 配置備份 | - ---- - -## 資料庫資訊 - -Gitea 使用 PostgreSQL 作為資料庫: - -| 項目 | 值 | -|------|-----| -| Database | gitea | -| User | gitea | -| Host | 127.0.0.1:5432 | -| Password | gitea_pass | - ---- - -## 常用指令 - -```bash -# 啟動 Gitea -gitea web --config /Users/accusys/momentry/etc/gitea/app.ini - -# 驗證配置 -gitea doctor --config /Users/accusys/momentry/etc/gitea/app.ini - -# 查看版本 -gitea --version - -# 備份數據 -gitea dump --config /Users/accusys/momentry/etc/gitea/app.ini --zipfile /Users/accusys/momentry/var/gitea_backup.zip -``` - ---- - -## 版本資訊 - -- 版本: 1.25.3 -- HTTP Port: 3000 -- SSH Port: 2222 -- 數據目錄: /Users/accusys/momentry/var/gitea/ -- 配置: /Users/accusys/momentry/etc/gitea/app.ini -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_GITEA_MCP.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_GITEA_MCP.md deleted file mode 100644 index 3929412..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_GITEA_MCP.md +++ /dev/null @@ -1,393 +0,0 @@ -# Gitea MCP Server 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | OpenCode | -| 建立時間 | 2026-03-24 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-24 | 創建文件 | OpenCode | OpenCode / big-pickle | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 Gitea MCP Server,配置為透過 OpenCode MCP 整合存取 Gitea API。 - -Gitea MCP Server 是一個 MCP (Model Context Protocol) 伺服器,提供對 Gitea API 的完整存取能力,包括 repos、issues、pull requests、workflows 等資源管理。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| Gitea MCP Server | ✅ 已安裝 | -| 安裝方式 | Homebrew (`gitea-mcp-server`) | -| Plist | /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist | -| 執行身份 | accusys | -| 監聽端口 | 8787 | -| Gitea 主機 | http://localhost:3000 | -| Launchd 狀態 | ✅ 已註冊 | -| RunAtLoad | ✅ 已設定 | -| KeepAlive | ✅ 已設定 | - ---- - -## 前置條件 - -- Gitea 服務已運行(端口 3000) -- Homebrew 已安裝 -- 管理員權限 - ---- - -## 安裝步驟 - -### Step 1: 安裝 Gitea MCP Server - -```bash -brew install gitea-mcp-server -``` - -**驗證**: - -```bash -which gitea-mcp-server -# /opt/homebrew/bin/gitea-mcp-server - -/opt/homebrew/bin/gitea-mcp-server --help -``` - ---- - -### Step 2: 創建日誌目錄 - -```bash -mkdir -p /Users/accusys/momentry/log - -touch /Users/accusys/momentry/log/gitea-mcp-server.log -touch /Users/accusys/momentry/log/gitea-mcp-server.error.log -``` - ---- - -### Step 3: 獲取 Gitea API Token - -#### 步驟 3.1: 登入 Gitea - -1. 開啟瀏覽器,訪問 http://localhost:3000 -2. 使用管理員帳號登入 - -#### 步驟 3.2: 生成 Personal Access Token - -1. 點擊右上角頭像 → **Settings** -2. 左側選單選擇 **Applications** -3. 在 **Access Tokens** 區塊: - - **Token Name**: `opencode-mcp` - - **Expiration**: 選擇過期時間(如 365 days) - - **Scopes**: 勾選需要的權限 - - `repo` - 倉庫操作 - - `read:user` - 讀取用戶資訊 - - `read:org` - 讀取組織資訊 -4. 點擊 **Generate Token** -5. **立即複製** 生成的 Token - -#### 步驟 3.3: 驗證 Token - -```bash -curl -H "Authorization: token " http://localhost:3000/api/v1/user -``` - ---- - -### Step 4: 創建 Plist 檔案 - -```bash -sudo tee /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist << 'EOF' - - - - - Label - com.momentry.gitea-mcp-server - UserName - accusys - ProgramArguments - - /opt/homebrew/bin/gitea-mcp-server - -transport - http - -port - 8787 - -host - http://localhost:3000 - -token - - - RunAtLoad - - KeepAlive - - StandardOutPath - /Users/accusys/momentry/log/gitea-mcp-server.log - StandardErrorPath - /Users/accusys/momentry/log/gitea-mcp-server.error.log - - -EOF -``` - -**注意**: 將 `` 替換為實際的 Token 值。 - ---- - -### Step 5: 設定權限 - -```bash -sudo chown root:wheel /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist -sudo chmod 644 /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist -``` - ---- - -### Step 6: 載入服務 - -```bash -sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist -``` - ---- - -### Step 7: 驗證服務 - -```bash -# 檢查服務狀態 -sudo launchctl list | grep gitea-mcp-server - -# 檢查進程 -ps aux | grep gitea-mcp-server | grep -v grep - -# 測試端點 -curl -s http://localhost:8787/ -``` - ---- - -### Step 8: 整合 OpenCode MCP - -#### 步驟 8.1: 更新 OpenCode 配置 - -編輯 `~/.config/opencode/opencode.json`: - -```json -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "gitea": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/gitea-mcp-server", - "-token", "", - "-host", "http://localhost:3000" - ] - }, - "n8n": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-n8n"], - "environment": { - "N8N_BASE_URL": "http://localhost:5678", - "N8N_API_KEY": "" - } - } - } -} -``` - -#### 步驟 8.2: 重啟 OpenCode - -```bash -# 停止現有 OpenCode -pkill -f opencode - -# 重新啟動 -opencode -``` - -#### 步驟 8.3: 驗證 MCP 連接 - -在 OpenCode 中執行: - -``` -/mcps -``` - -確認 gitea 顯示為 `connected`。 - ---- - -## Plist 參數說明 - -| 參數 | 說明 | 值 | -|------|------|-----| -| `-transport` | 傳輸類型 | `http` | -| `-port` | HTTP 監聽端口 | `8787` | -| `-host` | Gitea 主機 URL | `http://localhost:3000` | -| `-token` | Gitea API Token | 見 Step 3 | - ---- - -## 管理指令 - -### 啟動服務 - -```bash -sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist -``` - ---- - -### 停止服務 - -```bash -sudo launchctl bootout system/com.momentry.gitea-mcp-server -``` - ---- - -### 重啟服務 - -```bash -sudo launchctl bootout system/com.momentry.gitea-mcp-server -sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist -``` - ---- - -### 查看日誌 - -```bash -# 即時查看日誌 -tail -f /Users/accusys/momentry/log/gitea-mcp-server.log - -# 錯誤日誌 -tail -f /Users/accusys/momentry/log/gitea-mcp-server.error.log -``` - ---- - -## 卸載步驟 - -### Step 1: 停止服務 - -```bash -sudo launchctl bootout system/com.momentry.gitea-mcp-server -``` - ---- - -### Step 2: 移除 Plist - -```bash -sudo rm /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist -``` - ---- - -### Step 3: 從 OpenCode 配置移除 - -編輯 `~/.config/opencode/opencode.json`,移除 `mcp.gitea` 區塊。 - ---- - -## 故障排除 - -### 服務無法啟動 - -1. 檢查 Token 是否正確 -2. 檢查 Gitea 是否運行:`curl -s http://localhost:3000/` -3. 檢查日誌:`/Users/accusys/momentry/log/gitea-mcp-server.error.log` - ---- - -### Token 無效 - -1. 確認 Token 未過期 -2. 確認 Token 有足夠的權限 -3. 重新生成 Token - ---- - -### 端口被佔用 - -```bash -# 檢查端口占用 -lsof -i :8787 - -# 修改 plist 中的端口後重新載入 -``` - ---- - -### OpenCode MCP 未顯示 - -1. 確認 OpenCode 已重啟 -2. 檢查 `~/.config/opencode/opencode.json` 格式正確 -3. 確認 gitea-mcp-server 程序正在運行 - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| Plist | /Library/LaunchDaemons/com.momentry.gitea-mcp-server.plist | Launchd 服務配置 | -| 日誌 | /Users/accusys/momentry/log/gitea-mcp-server.log | 標準輸出日誌 | -| 錯誤日誌 | /Users/accusys/momentry/log/gitea-mcp-server.error.log | 錯誤日誌 | -| OpenCode 配置 | ~/.config/opencode/opencode.json | MCP 設定檔 | -| Gitea | http://localhost:3000 | Gitea Web UI | - ---- - -## 常用指令 - -```bash -# 驗證服務狀態 -sudo launchctl list | grep gitea-mcp-server - -# 查看服務 PID -ps aux | grep gitea-mcp-server | grep -v grep - -# 測試端點 -curl -s http://localhost:8787/ - -# 驗證 Gitea 連接 -curl -H "Authorization: token " http://localhost:3000/api/v1/user - -# 查看即時日誌 -tail -f /Users/accusys/momentry/log/gitea-mcp-server.log -``` - ---- - -## 版本資訊 - -- 版本: 1.0 -- 安裝日期: 2026-03-24 -- 文件更新: 2026-03-24 - ---- - -## 相關文件 - -- [OpenCode MCP 整合](./N8N_MCP_SETUP.md) - n8n MCP 設定說明 -- [服務總覽](./SERVICES.md) - 所有服務狀態總覽 -- [待解決問題](./PENDING_ISSUES.md) - MCP 安裝狀態追蹤 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MARIADB.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MARIADB.md deleted file mode 100644 index 7ebac72..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MARIADB.md +++ /dev/null @@ -1,396 +0,0 @@ -# MariaDB 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-16 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-16 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 MariaDB,配置為本地部署,支援遠端訪問。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| MariaDB | ✅ 已安裝 v12.1.2 | -| 數據目錄 | /Users/accusys/momentry/var/mariadb/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.mariadb.plist | - ---- - -## 安裝步驟 - -### Step 1: 安裝 MariaDB (使用 brew) - -```bash -# 安裝 MariaDB -brew install mariadb -``` - -**驗證**: -```bash -mariadb --version -# mariadb from 12.1.2-MariaDB -``` - ---- - -### Step 2: 建立目錄結構 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/mariadb - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/mariadb - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/mariadb.log -touch /Users/accusys/momentry/log/mariadb.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/mariadb -chown -R accusys:staff /Users/accusys/momentry/etc/mariadb -chown -R accusys:staff /Users/accusys/momentry/log -``` - -**注意**: 如果需要從舊數據遷移,需要先初始化新目錄: -```bash -# 初始化新數據目錄 -mysql_install_db --datadir=/Users/accusys/momentry/var/mariadb -``` - ---- - -### Step 3: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.mariadb.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.mariadb.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -database: - mariadb: - enabled: true - host: "localhost" - port: 3306 - user: "root" -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/mariadb/` | 數據 | **不要刪除** - 數據目錄 | -| `/Users/accusys/momentry/etc/mariadb/` | 配置 | **不要刪除** - 配置目錄 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/opt/homebrew/opt/mariadb/` | 安裝 | **刪除** - MariaDB 安裝目錄 | - -### Step 1: 停止 MariaDB - -```bash -# 找到 MariaDB 進程 -ps aux | grep mariadb | grep -v grep - -# 停止 MariaDB -mysqladmin -u root -p shutdown -# 或 -pkill mariadbd - -# 確認停止 -ps aux | grep mariadb | grep -v grep || echo "MariaDB 已停止" -``` - ---- - -### Step 2: 卸載 MariaDB - -```bash -# 卸載 MariaDB -brew uninstall mariadb - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.mariadb.plist -sudo rm /Library/LaunchDaemons/com.momentry.mariadb.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/mariadb - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/mariadb.log -rm -f /Users/accusys/momentry/log/mariadb.error.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== MariaDB 卸載後檢查 ===" - -# 1. 檢查 MariaDB 進程 -echo "1. MariaDB 進程:" -ps aux | grep mariadb | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 3306 -echo "2. Port 3306:" -lsof -i :3306 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. mariadb 命令 -echo "3. mariadb 命令:" -which mariadb > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list mariadb > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep mariadb > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 數據目錄 (可選刪除) -echo "6. 數據目錄:" -[ -d "/Users/accusys/momentry/var/mariadb" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 7. 日誌目錄 (可選刪除) -echo "7. 日誌目錄:" -[ -d "/Users/accusys/momentry/log" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - -**預期結果**: -``` -=== MariaDB 卸載後檢查 === -1. MariaDB 進程: - ✓ 已停止 -2. Port 3306: - ✓ 已釋放 -3. mariadb 命令: - ✓ 已移除 -4. brew 安裝: - ✓ 已移除 -5. launchctl 服務: - ✓ 已移除 -6. 數據目錄: - ✓ 保留 (或 ✗ 已刪除) -7. 日誌目錄: - ✓ 保留 (或 ✗ 已刪除) -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep mariadb | grep -v grep - -# 2. 檢查 Port -lsof -i :3306 - -# 3. 測試連線 -mariadb -u root -e "SELECT 1;" - -# 4. 查看所有數據庫 -mariadb -u root -e "SHOW DATABASES;" - -# 5. 查看用戶 -mariadb -u root -e "SELECT User, Host FROM mysql.user;" - -# 6. 查看表 -mariadb -u root -e "USE mysql; SHOW TABLES;" - -# 7. 查看日誌 -tail -20 /Users/accusys/momentry/log/mariadb.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| Host | localhost | -| Port | 3306 | -| User | root | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -MARIADB_URL=mariadb://root@localhost:3306 -``` - ---- - -## 遠端訪問 - -- MariaDB 綁定到所有網路介面 (0.0.0.0) -- 本地網路其他機器可透過 IP 訪問 -- 請設定用戶權限限制訪問 - ---- - -## 故障排除 - -### MariaDB 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/mariadb.log - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/var/mariadb/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/mariadb -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 3306 -lsof -i :3306 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.mariadb.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.mariadb.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/mariadb/` | MariaDB 安裝目錄 | -| 執行檔 | `/opt/homebrew/opt/mariadb/bin/mariadbd` | MariaDB 執行檔 | -| 數據目錄 | `/Users/accusys/momentry/var/mariadb/` | 數據儲存 | -| 日誌 | `/Users/accusys/momentry/log/mariadb.log` | 執行日誌 | -| 錯誤日誌 | `/Users/accusys/momentry/log/mariadb.error.log` | 錯誤日誌 | -| plist | `/Library/LaunchDaemons/com.momentry.mariadb.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/mariadb_backup/` | 數據備份 | - ---- - -## 備份與恢復 - -### 備份用戶配置 - -已創建專用備份用戶: -- 用戶名:`momentry_backup` -- 密碼:`momentry_backup_pwd_2026` -- 權限:SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER - -### 備份 (mysqldump) - -```bash -# 備份所有數據庫 -TIMESTAMP=$(date +%Y%m%d_%H%M%S) -mysqldump -u momentry_backup -pmomentry_backup_pwd_2026 --all-databases | gzip > \ - /Users/accusys/momentry/backup/daily/mariadb/mariadb_db_all_${TIMESTAMP}.sql.gz - -# 備份指定數據庫 (WordPress) -mysqldump -u momentry_backup -pmomentry_backup_pwd_2026 wordpress | gzip > \ - /Users/accusys/momentry/backup/daily/mariadb/mariadb_db_wordpress_${TIMESTAMP}.sql.gz - -# 驗證 -sha256sum /Users/accusys/momentry/backup/daily/mariadb/mariadb_db_*.sql.gz > \ - /Users/accusys/momentry/backup/daily/mariadb/mariadb_db_${TIMESTAMP}.sha256 -``` - -### 恢復 (mysql) - -```bash -# 恢復所有數據庫 -gunzip < /Users/accusys/momentry/backup/daily/mariadb/mariadb_db_all_20260316_101802.sql.gz | \ - mysql -u momentry_backup -pmomentry_backup_pwd_2026 - -# 恢復指定數據庫 -gunzip < /Users/accusys/momentry/backup/daily/mariadb/mariadb_db_wordpress_20260316_101802.sql.gz | \ - mysql -u momentry_backup -pmomentry_backup_pwd_2026 wordpress -``` - -### 數據目錄複製 (完整遷移) - 離線 - -```bash -# 1. 停止 MariaDB -mysqladmin -u momentry_backup -pmomentry_backup_pwd_2026 shutdown - -# 2. 複製數據目錄 -cp -r /opt/homebrew/var/mysql/* /Users/accusys/momentry/var/mariadb/ - -# 3. 設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/mariadb - -# 4. 啟動 MariaDB -sudo launchctl load /Library/LaunchDaemons/com.momentry.mariadb.plist -``` - ---- - -## 版本資訊 - -- 版本: 12.1.2 -- Port: 3306 -- User: root -- 數據目錄: /Users/accusys/momentry/var/mariadb/ -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MOMENTRY_API.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MOMENTRY_API.md deleted file mode 100644 index 696dfa8..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MOMENTRY_API.md +++ /dev/null @@ -1,464 +0,0 @@ -# Momentry Core API 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | OpenCode | -| 建立時間 | 2026-03-23 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-23 | 創建文件 | OpenCode | - | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 Momentry Core API 服務,配置為本地部署,並設定開機自動啟動。 - -Momentry Core API 是一個 Rust 編寫的數位資產管理 API 服務,提供: -- 影片搜尋 API (`/api/v1/search`) -- n8n 整合 API (`/api/v1/n8n/search`) -- 健康檢查端點 (`/health`) -- 影片註冊與處理功能 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| Momentry Core API | ✅ 已安裝 v0.1.0 | -| Binary | `/Users/accusys/momentry_core_0.1/target/release/momentry` | -| Port | 3002 | -| 反向代理 | Caddy (`api.momentry.ddns.net`) | -| 數據庫 | PostgreSQL (momentry) | -| 向量庫 | Qdrant | -| Cache | Redis | -| launchd plist | ✅ 已建立 (/Library/LaunchDaemons/com.momentry.api.plist) | - ---- - -## 系統需求 - -### 必要服務 - -| 服務 | 版本 | 用途 | -|------|------|------| -| PostgreSQL | 16+ | 主數據庫 | -| Redis | 1.0+ | 快取與佇列 | -| Qdrant | 1.7+ | 向量搜尋 | -| Ollama | 最新 | LLM 與 Embedding | - -### Rust 環境 - -```bash -# 檢查 Rust 版本 -rustc --version -cargo --version - -# 如需安裝 Rust -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -``` - ---- - -## 安裝步驟 - -### Step 1: 編譯 Momentry Core - -```bash -# 進入專案目錄 -cd /Users/accusys/momentry_core_0.1 - -# 編譯 release 版本 -cargo build --release - -# 驗證編譯結果 -ls -la target/release/momentry -``` - ---- - -### Step 2: 設定環境變數 - -建立環境變數檔案: - -```bash -# 建立執行目錄 -mkdir -p /Users/accusys/momentry_core_0.1/momentry_runtime/env - -# 建立環境變數檔案 -cat > /Users/accusys/momentry_core_0.1/momentry_runtime/env/momentry.env << 'EOF' -# Database Configuration -DATABASE_URL=postgres://accusys@localhost:5432/momentry - -# Redis Configuration -REDIS_URL=redis://:accusys@localhost:6379 -REDIS_PASSWORD=accusys - -# API Server -API_HOST=127.0.0.1 -API_PORT=3002 - -# Ollama (LLM) -OLLAMA_HOST=http://localhost:11434 - -# Qdrant (Vector Database) -QDRANT_URL=http://localhost:6333 -QDRANT_COLLECTION=momentry_chunks -EOF -``` - ---- - -### Step 3: 手動啟動服務 - -```bash -# 啟動 API 服務 -cd /Users/accusys/momentry_core_0.1 -./target/release/momentry server --port 3002 - -# 驗證服務 -curl http://localhost:3002/health -# {"status":"ok","version":"0.1.0","uptime_ms":1234} -``` - ---- - -### Step 4: 設定 Caddy 反向代理 - -在 `/Users/accusys/momentry/etc/Caddyfile` 中新增: - -```caddy -# Momentry Core API -api.momentry.ddns.net { - reverse_proxy localhost:3002 - import common_log momentry_api_access -} -``` - -重新載入 Caddy: - -```bash -# 重新載入配置 -caddy reload --config /Users/accusys/momentry/etc/Caddyfile - -# 驗證 -curl -sk https://api.momentry.ddns.net/health -``` - ---- - -### Step 5: 建立 launchd plist (開機自動啟動) - -建立 plist 檔案: - -```bash -sudo tee /Library/LaunchDaemons/com.momentry.api.plist << 'EOF' - - - - - Label - com.momentry.api - - UserName - accusys - - GroupName - staff - - WorkingDirectory - /Users/accusys/momentry_core_0.1 - - ProgramArguments - - /Users/accusys/momentry_core_0.1/target/release/momentry - server - --port - 3002 - - - EnvironmentVariables - - PATH - /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin - - DATABASE_URL - postgres://accusys@localhost:5432/momentry - - REDIS_URL - redis://:accusys@localhost:6379 - - REDIS_PASSWORD - accusys - - OLLAMA_HOST - http://localhost:11434 - - QDRANT_URL - http://localhost:6333 - - - RunAtLoad - - - KeepAlive - - - StandardOutPath - /Users/accusys/momentry/log/momentry_api.log - - StandardErrorPath - /Users/accusys/momentry/log/momentry_api.error.log - - -EOF -``` - -建立日誌檔案: - -```bash -# 建立日誌目錄(如不存在) -mkdir -p /Users/accusys/momentry/log - -# 建立日誌檔案 -touch /Users/accusys/momentry/log/momentry_api.log -touch /Users/accusys/momentry/log/momentry_api.error.log - -# 設定權限 -chown accusys:staff /Users/accusys/momentry/log/momentry_api.log -chown accusys:staff /Users/accusys/momentry/log/momentry_api.error.log -``` - -載入服務: - -```bash -# 載入服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 驗證服務 -launchctl list | grep momentry.api - -# 檢查服務狀態 -curl http://localhost:3002/health -``` - ---- - -## 卸載步驟 - -### Step 1: 停止並移除服務 - -```bash -# 停止服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist - -# 移除 plist -sudo rm /Library/LaunchDaemons/com.momentry.api.plist -``` - -### Step 2: 移除 Caddy 配置 - -從 `/Users/accusys/momentry/etc/Caddyfile` 中移除 `api.momentry.ddns.net` 區塊。 - -```bash -# 重新載入 Caddy -caddy reload --config /Users/accusys/momentry/etc/Caddyfile -``` - ---- - -## 故障排除 - -### API 返回 502 Bad Gateway - -**問題**: `api.momentry.ddns.net` 返回 502 錯誤 - -**原因**: Momentry Core API 服務未啟動 - -**解決方案**: - -```bash -# 檢查服務狀態 -launchctl list | grep momentry.api - -# 如服務未啟動,手動啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 或手動啟動測試 -cd /Users/accusys/momentry_core_0.1 -./target/release/momentry server --port 3002 -``` - ---- - -### API 返回 404 Not Found - -**問題**: 端點返回 404 - -**原因**: Binary 過舊,缺少該端點 - -**解決方案**: - -```bash -# 重新編譯 -cd /Users/accusys/momentry_core_0.1 -cargo build --release - -# 重啟服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist -``` - ---- - -### 服務無法啟動 - -**問題**: launchd 無法啟動服務 - -**檢查步驟**: - -```bash -# 檢查日誌 -tail -50 /Users/accusys/momentry/log/momentry_api.error.log - -# 檢查 plist 語法 -plutil -lint /Library/LaunchDaemons/com.momentry.api.plist - -# 檢查權限 -ls -la /Users/accusys/momentry_core_0.1/target/release/momentry - -# 手動測試 -/Users/accusys/momentry_core_0.1/target/release/momentry server --port 3002 -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| Binary | `/Users/accusys/momentry_core_0.1/target/release/momentry` | 執行檔 | -| 環境變數 | `/Users/accusys/momentry_core_0.1/momentry_runtime/env/momentry.env` | 環境設定 | -| launchd plist | `/Library/LaunchDaemons/com.momentry.api.plist` | 開機啟動配置 | -| 日誌 | `/Users/accusys/momentry/log/momentry_api.log` | 標準輸出 | -| 錯誤日誌 | `/Users/accusys/momentry/log/momentry_api.error.log` | 錯誤輸出 | -| Caddy 配置 | `/Users/accusys/momentry/etc/Caddyfile` | 反向代理配置 | - ---- - -## 常用指令 - -### 服務管理 - -```bash -# 啟動服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 停止服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist - -# 重啟服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist - -# 檢查服務狀態 -launchctl list | grep momentry.api -``` - -### 健康檢查 - -```bash -# 本地健康檢查 -curl http://localhost:3002/health - -# 詳細健康檢查 -curl http://localhost:3002/health/detailed - -# 外部健康檢查 -curl -sk https://api.momentry.ddns.net/health -``` - -### API 測試 - -```bash -# 搜尋 API -curl -X POST http://localhost:3002/api/v1/search \ - -H "Content-Type: application/json" \ - -d '{"query":"test"}' - -# n8n 搜尋 API -curl -X POST http://localhost:3002/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -d '{"query":"test"}' - -# 列出影片 -curl http://localhost:3002/api/v1/videos -``` - -### 日誌查看 - -```bash -# 查看最近的日誌 -tail -50 /Users/accusys/momentry/log/momentry_api.log - -# 即時監控日誌 -tail -f /Users/accusys/momentry/log/momentry_api.log - -# 查看錯誤日誌 -tail -50 /Users/accusys/momentry/log/momentry_api.error.log -``` - -### 重新編譯 - -```bash -# 編譯 release 版本 -cd /Users/accusys/momentry_core_0.1 -cargo build --release - -# 編譯後重啟服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.api.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.api.plist -``` - ---- - -## API 端點 - -| 端點 | 方法 | 說明 | -|------|------|------| -| `/health` | GET | 健康檢查 | -| `/health/detailed` | GET | 詳細健康檢查 | -| `/api/v1/register` | POST | 註冊影片 | -| `/api/v1/search` | POST | 搜尋影片 | -| `/api/v1/n8n/search` | POST | n8n 格式搜尋 | -| `/api/v1/search/hybrid` | POST | 混合搜尋 | -| `/api/v1/lookup` | GET | 查詢 UUID | -| `/api/v1/videos` | GET | 列出所有影片 | -| `/api/v1/progress/:uuid` | GET | 查詢處理進度 | - ---- - -## 版本資訊 - -- 版本: 0.1.0 -- 安裝日期: 2026-03-23 -- Rust 版本: 1.xx -- 文件更新: 2026-03-23 - ---- - -## 相關文件 - -- `docs/SERVICES.md` - 服務總覽 -- `docs/API_REFERENCE.md` - API 參考 -- `docs/INSTALL_POSTGRESQL.md` - PostgreSQL 安裝 -- `docs/INSTALL_REDIS.md` - Redis 安裝 -- `docs/INSTALL_QDRANT.md` - Qdrant 安裝 -- `docs/PENDING_ISSUES.md` - 待解決問題 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MONGODB.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MONGODB.md deleted file mode 100644 index 9fb46f9..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_MONGODB.md +++ /dev/null @@ -1,392 +0,0 @@ -# MongoDB 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-15 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-15 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 MongoDB Community Edition,配置為本地部署,支援遠端訪問。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| MongoDB (mongodb-community) | ✅ 已安裝 v8.2.6 | -| 數據目錄 | /opt/homebrew/var/mongodb | -| 日誌目錄 | /Users/accusys/momentry/log | - ---- - -## 安裝步驟 - -### Step 1: 安裝 MongoDB Community - -```bash -# 安裝 MongoDB Community -brew tap mongodb/brew -brew install mongodb-community -``` - -**驗證**: -```bash -mongod --version -# db version v8.x.x -mongosh --version -# 2.7.x -sudo launchctl list | grep mongo -# 確認 MongoDB 服務已載入 -``` - ---- - -### Step 2: 數據目錄 (已存在 - 共用) - -數據目錄使用 homebrew 預設位置: -- 數據目錄: `/opt/homebrew/var/mongodb` -- 配置目錄: `/opt/homebrew/etc/mongod.conf` -- 日誌目錄: `/Users/accusys/momentry/log` - -**建立配置目錄和日誌文件**: -```bash -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/mongodb - -# 建立日誌文件 -touch /Users/accusys/momentry/log/mongodb.log -touch /Users/accusys/momentry/log/mongodb.error.log - -# 確認權限: -ls -la /Users/accusys/momentry/ -chown -R accusys:staff /Users/accusys/momentry -``` - ---- - -### Step 3: 使用 LaunchAgent 啟動 (開機自動) - -```bash -# 複製 plist 到 LaunchDaemons 目錄 (開機自動需要 root 權限) -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.mongodb.plist \ - /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.mongodb.plist - -# 驗證 -launchctl list | grep mongodb -pgrep -a mongod -``` - ---- - -### Step 4: 建立資料庫用戶 - -```bash -mongosh --eval ' -use admin -db.createUser({ - user: "accusys", - pwd: "Test3200Test3200", - roles: [ - { role: "readWrite", db: "momentry" }, - { role: "dbAdmin", db: "momentry" } - ] -}) - ---- - -### Step 4: 驗證安裝 - -```bash -# 檢查進程 -pgrep -a mongod - -# 檢查端口 -lsof -i :27017 - -# 測試連線 -mongosh --eval "db.adminCommand('ping')" - -# 檢查 LaunchAgent -launchctl list | grep mongodb -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -database: - mongodb: - enabled: true - host: "localhost" - port: 27017 - user: "accusys" - database: "momentry" -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/` | 共用 | **不要刪除** - 多個系統共用 | -| `/Users/accusys/momentry/var` | 共用 | **不要刪除** - 數據目錄 | -| `/Users/accusys/momentry/etc/mongodb/` | 配置 | **不要刪除** - MongoDB 配置 | -| `/Users/accusys/momentry/log` | 共用 | **不要刪除** - 日誌目錄 | -| `~/.mongosh_history` | 專屬 | 可選刪除 - Mongo Shell 歷史 | - -### Step 1: 停止 MongoDB - -```bash -# 找到 MongoDB 進程 -ps aux | grep mongod | grep -v grep - -# 停止 MongoDB -pkill mongod -# 或 -kill - -# 確認停止 -ps aux | grep mongod | grep -v grep || echo "MongoDB 已停止" -``` - ---- - -### Step 2: 卸載 MongoDB - -```bash -# 完全卸載 (保留數據) -brew uninstall mongodb-community -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除 MongoDB 專屬配置 (如果有) -rm -f ~/.mongosh_history - -# 刪除臨時文件 (可選) -rm -rf /tmp/mongodb-* -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== MongoDB 卸載後檢查 ===" - -# 1. 檢查 MongoDB 進程 -echo "1. MongoDB 進程:" -ps aux | grep mongod | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. 檢查 Port 27017 -echo "2. Port 27017:" -lsof -i :27017 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. 檢查 mongod 命令 -echo "3. mongod 命令:" -which mongod > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. 檢查 launchctl -echo "4. launchctl 服務:" -sudo launchctl list | grep mongo > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. 檢查 Homebrew -echo "5. Homebrew 移除:" -brew list mongo > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 檢查數據目錄 (應該存在) -echo "6. 數據目錄:" -[ -d "/Users/accusys/momentry/var" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 7. 檢查日誌目錄 (應該存在) -echo "7. 日誌目錄:" -[ -d "/Users/accusys/momentry/log" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - -**預期結果**: -``` -=== MongoDB 卸載後檢查 === -1. MongoDB 進程: - ✓ 已停止 -2. Port 27017: - ✓ 已釋放 -3. mongod 命令: - ✓ 已移除 -4. launchctl 服務: - ✓ 已移除 -5. Homebrew 移除: - ✓ 已移除 -6. 數據目錄: - ✓ 保留 -7. 日誌目錄: - ✓ 保留 -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查 Process 是否運行 -ps aux | grep mongo | grep -v grep - -# 2. 檢查 Port 27017 -lsof -i :27017 - -# 3. 測試連線 (無認證) -mongosh --eval "db.adminCommand('ping')" - -# 4. 測試連線 (有認證) -mongosh "mongodb://accusys:Test3200Test3200@localhost:27017/admin" --eval "db.adminCommand('ping')" - -# 5. 查看所有資料庫 -mongosh "mongodb://accusys:Test3200Test3200@localhost:27017/admin" --quiet --eval "db.adminCommand({listDatabases:1}).databases" - -# 6. 查看用戶 -mongosh "mongodb://accusys:Test3200Test3200@localhost:27017/admin" --quiet --eval "db.getUser('accusys')" - -# 7. 查看日誌 -tail -20 /Users/accusys/momentry/log/mongodb.log -tail -20 /Users/accusys/momentry/log/mongodb.error.log -``` - ---- - -## 管理命令 - -### 啟動/停止 - -```bash -# 使用 LaunchAgent (開機自動 - LaunchDaemons 目錄) -sudo launchctl load /Library/LaunchDaemons/com.momentry.mongodb.plist # 啟動 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.mongodb.plist # 停止 - -# 手動啟動 (僅除錯用) -nohup /opt/homebrew/bin/mongod \ - --dbpath /Users/accusys/momentry/var \ - --logpath /Users/accusys/momentry/log/mongodb.log \ - --port 27017 \ - --bind_ip 0.0.0.0 \ - > /Users/accusys/momentry/log/mongodb.log 2>&1 & - -# 強制停止 -pkill mongod -``` - ---- - -## 連線字串 - -```bash -# 無認證 (本地) -mongodb://localhost:27017 - -# 有認證 (admin 資料庫) -mongodb://accusys:Test3200Test3200@localhost:27017/admin - -# 有認證 (momentry 資料庫) -mongodb://accusys:Test3200Test3200@localhost:27017/momentry?authSource=admin -``` - ---- - -## 環境變數 - -在 `.env` 中: - -```env -MONGODB_URL=mongodb://accusys:Test3200Test3200@localhost:27017/admin -MONGODB_DATABASE=momentry -``` - ---- - -## 遠端訪問 - -- MongoDB 綁定到 `0.0.0.0` (所有網路介面) -- 本地網路其他機器可透過 IP 訪問 -- 建議設定防火牆規則限制訪問 IP - ---- - -## 故障排除 - -### MongoDB 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/mongodb.log - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 27017 -lsof -i :27017 - -# 終止佔用程序 -kill -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 數據目錄 | `/Users/accusys/momentry/var` | **共用 - 不要刪除** | -| 日誌目錄 | `/Users/accusys/momentry/log` | **共用 - 不要刪除** | -| mongod | `/opt/homebrew/bin/mongod` | 安裝後存在 | -| Homebrew | `/opt/homebrew/Cellar/mongodb-community/` | 卸載時刪除 | -| Homebrew | `/opt/homebrew/Cellar/mongodb-database-tools/` | 卸載時刪除 | -| Homebrew | `/opt/homebrew/Cellar/mongosh/` | 卸載時刪除 | -| 配置檔 | `/opt/homebrew/etc/mongod.conf` | 卸載時刪除 | - ---- - -## 版本資訊 - -- 用戶: accusys -- 密碼: Test3200Test3200 -- 數據目錄: /Users/accusys/momentry/var (共用 - 不要刪除!) -- 日誌目錄: /Users/accusys/momentry/log (共用 - 不要刪除!) diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_N8N.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_N8N.md deleted file mode 100644 index 616171f..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_N8N.md +++ /dev/null @@ -1,489 +0,0 @@ -# n8n 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-16 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-16 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 n8n 工作流自動化平台,配置為本地部署,使用 Queue 模式。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| n8n | ✅ 已安裝 v2.12.3 | -| 數據目錄 | /Users/accusys/momentry/var/n8n/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Main Plist | /Library/LaunchDaemons/com.momentry.n8n.main.plist | -| Worker Plist | /Library/LaunchDaemons/com.momentry.n8n.worker.plist | -| 數據庫 | PostgreSQL (n8n) | -| 隊列 | Redis | -| Launchd 狀態 | ✅ Main + Worker 已註冊 | -| RunAtLoad | ✅ 已設定 | -| KeepAlive | ✅ 已設定 | - -### 重要更新 (2026-03-24) - -1. **n8n Main + Worker**: 兩個服務都使用自定義 plist -2. **Runner 禁用**: 為避免端口衝突,Main 服務設定 `N8N_RUNNERS_ENABLED=false` -3. **Worker 端口**: Worker 使用 5681, 5682, 5690, 5691 端口 - ---- - -## 安裝步驟 - -### Step 1: 安裝 n8n (使用 brew) - -```bash -# 安裝 n8n -brew install n8n -``` - -**驗證**: -```bash -n8n --version -# 2.12.3 -``` - ---- - -### Step 2: 建立目錄 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/n8n - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/n8n - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/n8n.main.log -touch /Users/accusys/momentry/log/n8n.main.error.log -touch /Users/accusys/momentry/log/n8n.worker.log -touch /Users/accusys/momentry/log/n8n.worker.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/n8n -chown -R accusys:staff /Users/accusys/momentry/etc/n8n -chown -R accusys:staff /Users/accusys/momentry/log -``` - ---- - -### Step 3: 數據遷移 (如果從舊位置遷移) - -```bash -# 停止舊服務 -sudo launchctl unload /Library/LaunchDaemons/com.n8n.main.plist -sudo launchctl unload /Library/LaunchDaemons/com.n8n.worker.plist - -# 複製數據 -cp -r /Users/accusys/.n8n/* /Users/accusys/momentry/var/n8n/ - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/n8n -``` - ---- - -### Step 4: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.n8n.main.plist /Library/LaunchDaemons/ -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.n8n.worker.plist /Library/LaunchDaemons/ - -# 移除舊 plist (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.n8n.main.plist 2>/dev/null -sudo launchctl unload /Library/LaunchDaemons/com.n8n.worker.plist 2>/dev/null -sudo rm /Library/LaunchDaemons/com.n8n.main.plist 2>/dev/null -sudo rm /Library/LaunchDaemons/com.n8n.worker.plist 2>/dev/null - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.worker.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "n8n" - type: "http" - port: 5678 - host: "localhost" - check_url: "http://localhost:5678/" - timeout: 5 - enabled: true -``` - -### 添加健康檢查函數 - -在 `monitor/service/health_check.sh` 中添加: - -```bash -check_n8n() { - local start=$(date +%s%N) - if curl -s http://localhost:5678/ > /dev/null 2>&1; then - local end=$(date +%s%N) - local ms=$(( (end - start) / 1000000 )) - echo -e "${GREEN}✓${NC} n8n (5678) - ${ms}ms" - record_service "n8n" "up" "$ms" "" - return 0 - else - echo -e "${RED}✗${NC} n8n (5678) - Down" - record_service "n8n" "down" "0" "Connection failed" - return 1 - fi -} -``` - -### n8n Workflow 監控 - -n8n 有專門的工作流監控腳本,請參考 `monitor/workflow/n8n_workflow_monitor.sh`。 - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/n8n/` | 數據 | **不要刪除** - n8n 數據 | -| `/Users/accusys/momentry/etc/n8n/` | 配置 | **不要刪除** - n8n 配置 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - n8n 日誌 | -| `/opt/homebrew/lib/node_modules/n8n/` | 安裝 | **刪除** - n8n 安裝目錄 | - -### Step 1: 停止 n8n - -```bash -# 停止 n8n 服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.worker.plist - -# 確認停止 -ps aux | grep n8n | grep -v grep || echo "n8n 已停止" -``` - ---- - -### Step 2: 卸載 n8n - -```bash -# 卸載 n8n -brew uninstall n8n - -# 移除 plist -sudo rm /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo rm /Library/LaunchDaemons/com.momentry.n8n.worker.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/n8n - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/n8n-*.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/log -# PostgreSQL n8n 數據庫 (如需保留) -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== n8n 卸載後檢查 ===" - -# 1. 檢查 n8n 進程 -echo "1. n8n Main 進程:" -ps aux | grep "n8n.*start" | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -echo "2. n8n Worker 進程:" -ps aux | grep "n8n.*worker" | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 8085 -echo "3. Port 8085:" -lsof -i :8085 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. Port 5679 (Worker) -echo "4. Port 5679 (Worker):" -lsof -i :5679 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 4. n8n 命令 -echo "5. n8n 命令:" -which n8n > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. brew 安裝 -echo "6. brew 安裝:" -brew list n8n > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. launchctl 服務 -echo "7. launchctl 服務:" -sudo launchctl list | grep n8n > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" -``` - ---- - -## 備份步驟 - -### 備份 n8n 數據 - -```bash -# 建立備份目錄 -mkdir -p /Users/accusys/momentry/var/n8n_backup - -# 1. 備份 PostgreSQL 數據庫 -PGPASSWORD=accusys pg_dump -U accusys -d n8n > /Users/accusys/momentry/var/n8n_backup/n8n_database_$(date +%Y%m%d).sql - -# 2. 備份用戶數據夾 -cp -r /Users/accusys/momentry/var/n8n /Users/accusys/momentry/var/n8n_backup/ - -# 3. 壓縮備份 -cd /Users/accusys/momentry/var && tar -czvf n8n_backup_$(date +%Y%m%d).tar.gz n8n_backup/ - -# 4. 清理臨時備份 -rm -rf /Users/accusys/momentry/var/n8n_backup -``` - -### 還原數據 - -```bash -# 1. 停止 n8n -sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.worker.plist - -# 2. 還原 PostgreSQL 數據庫 -PGPASSWORD=accusys psql -U accusys -d n8n < /Users/accusys/momentry/var/n8n_backup/n8n_database_20260314.sql - -# 3. 還原用戶數據夾 -rm -rf /Users/accusys/momentry/var/n8n -cp -r /Users/accusys/momentry/var/n8n_backup/n8n /Users/accusys/momentry/var/n8n -chown -R accusys:staff /Users/accusys/momentry/var/n8n - -# 4. 啟動 n8n -sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.worker.plist -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep n8n | grep -v grep - -# 2. 檢查 Port -lsof -i :5678 -lsof -i :5679 - -# 3. 測試連線 -curl http://localhost:5678/ - -# 4. 查看版本 -n8n --version - -# 5. 查看日誌 -tail -20 /Users/accusys/momentry/log/n8n-main.log -tail -20 /Users/accusys/momentry/log/n8n-worker.log - -# 6. 查看錯誤日誌 -tail -20 /Users/accusys/momentry/log/n8n-main.error.log -tail -20 /Users/accusys/momentry/log/n8n-worker.error.log - -# 7. 檢查 launchctl 狀態 -sudo launchctl list | grep n8n -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| URL | http://localhost:5678 | -| Domain | n8n.momentry.ddns.net | -| 數據庫 | PostgreSQL (n8n) | -| 隊列 | Redis | -| Encryption Key | Test3200Test3200Test3200 | - -### Queue 模式端口 - -| 服務 | Port | -|------|------| -| Main | 5678 | -| Task Broker (Worker 連接) | 5679 | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -N8N_URL=http://localhost:5678 -N8N_USER_FOLDER=/Users/accusys/momentry/var/n8n -``` - ---- - -## 故障排除 - -### n8n 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/n8n-main.log -tail -f /Users/accusys/momentry/log/n8n-worker.log - -# 檢查環境變數 -launchctl list | grep n8n - -# 檢查數據庫連線 -PGPASSWORD=accusys psql -U accusys -d n8n -c "SELECT 1" - -# 檢查 Redis 連線 -redis-cli -a accusys ping -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port -lsof -i :8085 - -# 終止佔用程序 -kill -``` - -### 數據庫連線失敗 - -```bash -# 檢查 PostgreSQL -pg_isready -h 127.0.0.1 -p 5432 -U n8n - -# 測試連線 -PGPASSWORD=accusys psql -h 127.0.0.1 -U n8n -d n8n -c "SELECT version();" -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.worker.plist - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.worker.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/lib/node_modules/n8n/` | n8n 安裝目錄 | -| 執行檔 | `/opt/homebrew/bin/n8n` | n8n 執行檔 | -| 數據目錄 | `/Users/accusys/momentry/var/n8n/` | 數據儲存 | -| 配置目錄 | `/Users/accusys/momentry/etc/n8n/` | 配置儲存 | -| Main 日誌 | `/Users/accusys/momentry/log/n8n.main.log` | 主服務日誌 | -| Main 錯誤日誌 | `/Users/accusys/momentry/log/n8n.main.error.log` | 主服務錯誤日誌 | -| Worker 日誌 | `/Users/accusys/momentry/log/n8n.worker.log` | Worker 日誌 | -| Worker 錯誤日誌 | `/Users/accusys/momentry/log/n8n.worker.error.log` | Worker 錯誤日誌 | -| Main Plist | `/Library/LaunchDaemons/com.momentry.n8n.main.plist` | 主服務開機啟動 | -| Worker Plist | `/Library/LaunchDaemons/com.momentry.n8n.worker.plist` | Worker 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/n8n_backup/` | 數據備份 | - ---- - -## 數據庫資訊 - -n8n 使用 PostgreSQL 作為數據庫: - -| 項目 | 值 | -|------|-----| -| Database | n8n | -| User | n8n | -| Host | 127.0.0.1:5432 | -| Password | accusys | - -### Redis 隊列資訊 - -| 項目 | 值 | -|------|-----| -| Host | 127.0.0.1:6379 | -| Password | accusys | -| Mode | Queue (Bull) | - ---- - -## 常用指令 - -```bash -# 啟動 n8n Main -n8n start - -# 啟動 n8n Worker -n8n worker - -# 查看版本 -n8n --version - -# 備份數據 -PGPASSWORD=accusys pg_dump -U accusys -d n8n > n8n_backup.sql - -# 重新載入服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.main.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.main.plist -``` - ---- - -## 版本資訊 - -- 版本: 2.3.5 -- Main Port: 5678 -- Task Broker (Worker): 5679 -- 數據目錄: /Users/accusys/momentry/var/n8n/ -- 日誌目錄: /Users/accusys/momentry/log/ -- 數據庫: PostgreSQL n8n -- 隊列: Redis diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_OLLAMA.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_OLLAMA.md deleted file mode 100644 index 8b24c37..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_OLLAMA.md +++ /dev/null @@ -1,375 +0,0 @@ -# Ollama 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-15 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-15 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 Ollama,配置為本地部署,用於運行大型語言模型 (LLM)。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| Ollama | ✅ 已安裝 v0.13.5 | -| Port | 11434 | -| Models 目錄 | /Users/accusys/momentry/var/ollama/models | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.ollama.plist | - ---- - -## 安裝步驟 - -### Step 1: 安裝 Ollama (使用 brew) - -```bash -# 安裝 Ollama -brew install ollama -``` - -**驗證**: -```bash -ollama --version -# ollama version is 0.13.5 -``` - ---- - -### Step 2: 建立目錄 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/ollama - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/ollama - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/ollama.log -touch /Users/accusys/momentry/log/ollama.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/ollama -chown -R accusys:staff /Users/accusys/momentry/etc/ollama -chown -R accusys:staff /Users/accusys/momentry/log -``` - ---- - -### Step 3: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.ollama.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.ollama.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "ollama" - type: "http" - port: 11434 - host: "localhost" - check_url: "http://localhost:11434/api/tags" - timeout: 5 - enabled: true -``` - -### 添加健康檢查函數 - -在 `monitor/service/health_check.sh` 中添加: - -```bash -check_ollama() { - local start=$(date +%s%N) - if curl -s http://localhost:11434/api/tags > /dev/null 2>&1; then - local end=$(date +%s%N) - local ms=$(( (end - start) / 1000000 )) - echo -e "${GREEN}✓${NC} Ollama (11434) - ${ms}ms" - record_service "ollama" "up" "$ms" "" - return 0 - else - echo -e "${RED}✗${NC} Ollama (11434) - Down" - record_service "ollama" "down" "0" "Connection failed" - return 1 - fi -} -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/ollama/` | 數據 | **不要刪除** - Ollama 數據 | -| `/Users/accusys/momentry/etc/ollama/` | 配置 | **不要刪除** - Ollama 配置 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/opt/homebrew/opt/ollama/` | 安裝 | **刪除** - Ollama 安裝目錄 | - -### Step 1: 停止 Ollama - -```bash -# 找到 Ollama 進程 -ps aux | grep ollama | grep -v grep - -# 停止 Ollama -pkill ollama - -# 確認停止 -ps aux | grep ollama | grep -v grep || echo "Ollama 已停止" -``` - ---- - -### Step 2: 卸載 Ollama - -```bash -# 卸載 Ollama -brew uninstall ollama - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.ollama.plist -sudo rm /Library/LaunchDaemons/com.momentry.ollama.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/ollama.log -rm -f /Users/accusys/momentry/log/ollama.error.log -``` - -**注意: 不要刪除以下目錄**: -```bash -# 這些是重要的,不要刪除! -# /Users/accusys/.ollama/models -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== Ollama 卸載後檢查 ===" - -# 1. 檢查 Ollama 進程 -echo "1. Ollama 進程:" -ps aux | grep ollama | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 11434 -echo "2. Port 11434:" -lsof -i :11434 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. ollama 命令 -echo "3. ollama 命令:" -which ollama > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list ollama > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep ollama > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 模型目錄 (應該保留) -echo "6. 模型目錄:" -[ -d "/Users/accusys/.ollama/models" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep ollama | grep -v grep - -# 2. 檢查 Port -lsof -i :11434 - -# 3. 測試連線 -curl http://localhost:11434/ - -# 4. 查看版本 -ollama --version - -# 5. 查看已安裝的模型 -ollama list - -# 6. 查看日誌 -tail -20 /Users/accusys/momentry/log/ollama.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| Host | localhost | -| Port | 11434 | -| Models | /Users/accusys/.ollama/models | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -OLLAMA_HOST=0.0.0.0:11434 -OLLAMA_MODELS=/Users/accusys/.ollama/models -OLLAMA_FLASH_ATTENTION=1 -OLLAMA_KV_CACHE_TYPE=q8_0 -``` - -### 環境變數說明 - -| 變數 | 說明 | 預設值 | -|------|------|---------| -| OLLAMA_HOST | 綁定主機和端口 | 127.0.0.1:11434 | -| OLLAMA_MODELS | 模型儲存目錄 | ~/.ollama/models | -| OLLAMA_FLASH_ATTENTION | 啟用 Flash Attention | 0 | -| OLLAMA_KV_CACHE_TYPE | KV 緩存類型 | f16 | - ---- - -## 遠端訪問 - -- Ollama 綁定到 `0.0.0.0:11434` (所有網路介面) -- 本地網路其他機器可透過 IP 訪問 -- 請注意安全風險 - ---- - -## 故障排除 - -### Ollama 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/ollama.log - -# 檢查模型目錄權限 -ls -la /Users/accusys/.ollama/models/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/.ollama -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 11434 -lsof -i :11434 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.ollama.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.ollama.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/ollama/` | Ollama 安裝目錄 | -| 執行檔 | `/opt/homebrew/opt/ollama/bin/ollama` | Ollama 執行檔 | -| 數據目錄 | `/Users/accusys/momentry/var/ollama/` | 數據儲存 | -| 配置目錄 | `/Users/accusys/momentry/etc/ollama/` | 配置儲存 | -| 模型目錄 | `/Users/accusys/.ollama/models/` | AI 模型儲存 | -| 日誌 | `/Users/accusys/momentry/log/ollama.log` | 執行日誌 | -| 錯誤日誌 | `/Users/accusys/momentry/log/ollama.error.log` | 錯誤日誌 | -| plist | `/Library/LaunchDaemons/com.momentry.ollama.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/ollama_backup/environment.txt` | 環境變數備份 | - ---- - -## 常用指令 - -```bash -# 查看版本 -ollama --version - -# 查看已安裝的模型 -ollama list - -# 拉取模型 -ollama pull mistral -ollama pull llama2 - -# 運行模型 -ollama run mistral - -# 刪除模型 -ollama remove mistral - -# 查看模型資訊 -ollama show mistral -``` - ---- - -## 已安裝的模型 - -查看已安裝的模型: -```bash -ollama list -``` - ---- - -## 版本資訊 - -- 版本: 0.13.5 -- Port: 11434 -- Models: /Users/accusys/.ollama/models/ -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_PHP.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_PHP.md deleted file mode 100644 index 1a14d1c..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_PHP.md +++ /dev/null @@ -1,395 +0,0 @@ -# PHP 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-16 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-16 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 PHP 及 PHP-FPM,配置為本地部署。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| PHP | ✅ 已安裝 v8.5.2 | -| PHP-FPM | ✅ 執行中 | -| 配置目錄 | /Users/accusys/momentry/etc/php/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.php.plist | - ---- - -## 安裝步驟 - -### Step 1: 安裝 PHP (使用 brew) - -```bash -# 安裝 PHP -brew install php - -# 安裝 PHP-FPM (通常包含在 php 中) -brew install php --fpm -``` - -**驗證**: -```bash -php --version -# PHP 8.5.2 (cli) -``` - ---- - -### Step 2: 建立目錄 - -```bash -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/php - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/php.log -touch /Users/accusys/momentry/log/php.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/etc/php -chown -R accusys:staff /Users/accusys/momentry/log -``` - ---- - -### Step 3: 建立設定檔 - -建立 `/Users/accusys/momentry/etc/php/php-fpm.conf`: - -```ini -[global] -pid = /Users/accusys/momentry/var/php-fpm.pid -error_log = /Users/accusys/momentry/log/php.error.log -log_level = notice - -[www] -user = accusys -group = staff -listen = 127.0.0.1:9000 -listen.owner = accusys -listen.group = staff -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -``` - -複製 php.ini: -```bash -cp /opt/homebrew/etc/php/8.5/php.ini /Users/accusys/momentry/etc/php/ -``` - ---- - -### Step 4: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.php.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.php.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "php-fpm" - type: "tcp" - port: 9000 - host: "localhost" - timeout: 5 - enabled: true -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/etc/php/` | 配置 | **不要刪除** - PHP 配置 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/opt/homebrew/opt/php/` | 安裝 | **刪除** - PHP 安裝目錄 | - -### Step 1: 停止 PHP-FPM - -```bash -# 找到 PHP-FPM 進程 -ps aux | grep php-fpm | grep -v grep - -# 停止 PHP-FPM -pkill php-fpm - -# 確認停止 -ps aux | grep php-fpm | grep -v grep || echo "PHP-FPM 已停止" -``` - ---- - -### Step 2: 卸載 PHP - -```bash -# 卸載 PHP -brew uninstall php - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.php.plist -sudo rm /Library/LaunchDaemons/com.momentry.php.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除配置目錄 (可選) -rm -rf /Users/accusys/momentry/etc/php - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/php.log -rm -f /Users/accusys/momentry/log/php.error.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/etc -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== PHP 卸載後檢查 ===" - -# 1. 檢查 PHP-FPM 進程 -echo "1. PHP-FPM 進程:" -ps aux | grep php-fpm | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 9000 -echo "2. Port 9000:" -lsof -i :9000 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. php 命令 -echo "3. php 命令:" -which php > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list php > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep php > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 配置目錄 (可選刪除) -echo "6. 配置目錄:" -[ -d "/Users/accusys/momentry/etc/php" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 7. 日誌目錄 (可選刪除) -echo "7. 日誌目錄:" -[ -d "/Users/accusys/momentry/log" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查 PHP 版本 -php --version - -# 2. 檢查 PHP-FPM 進程 -ps aux | grep php-fpm | grep -v grep - -# 3. 檢查 Port -lsof -i :9000 - -# 4. 測試 PHP -php -r "echo 'PHP OK' . PHP_EOL;" - -# 5. 查看 PHP 模組 -php -m - -# 6. 查看 PHP 配置 -php -i | grep "Loaded Configuration File" - -# 7. 查看日誌 -tail -20 /Users/accusys/momentry/log/php.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| PHP-FPM Port | 9000 | -| PHP Version | 8.5.2 | -| Config | /Users/accusys/momentry/etc/php/php-fpm.conf | -| php.ini | /Users/accusys/momentry/etc/php/php.ini | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -PHP_INI_SCAN_DIR=/Users/accusys/momentry/etc/php/conf.d -``` - ---- - -## 故障排除 - -### PHP-FPM 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/php.error.log - -# 檢查配置語法 -/opt/homebrew/opt/php/sbin/php-fpm --test --fpm-config /Users/accusys/momentry/etc/php/php-fpm.conf - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/etc/php/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/etc/php -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 9000 -lsof -i :9000 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.php.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.php.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/php/` | PHP 安裝目錄 | -| 執行檔 | `/opt/homebrew/bin/php` | PHP 執行檔 | -| PHP-FPM | `/opt/homebrew/opt/php/sbin/php-fpm` | PHP-FPM 執行檔 | -| php.ini | `/Users/accusys/momentry/etc/php/8.5/php.ini` | PHP 配置 | -| PHP-FPM 配置 | `/Users/accusys/momentry/etc/php/8.5/php-fpm.conf` | PHP-FPM 主配置 | -| PHP-FPM pool | `/Users/accusys/momentry/etc/php/8.5/php-fpm.d/` | Pool 配置 | -| 日誌 | `/Users/accusys/momentry/log/php.log` | 執行日誌 | -| 錯誤日誌 | `/opt/homebrew/var/log/php-fpm.log` | PHP-FPM 錯誤日誌 | -| plist | `/Library/LaunchDaemons/com.momentry.php.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/backup/daily/php/` | 配置備份 | - ---- - -## 常用指令 - -```bash -# 測試 PHP-FPM 配置 -/opt/homebrew/opt/php/sbin/php-fpm --test --fpm-config /Users/accusys/momentry/etc/php/php-fpm.conf - -# 查看 PHP 模組 -php -m - -# 查看已載入的配置 -php -i - -# 測試 PHP 腳本 -php -r "echo 'Hello World' . PHP_EOL;" - -# 查看 PHP-FPM 狀態 -curl http://127.0.0.1:9000/status -``` - ---- - -## 備份與恢復 - -### 備份 - -```bash -TIMESTAMP=$(date +%Y%m%d_%H%M%S) -BACKUP_DIR="/Users/accusys/momentry/backup/daily/php" - -mkdir -p "$BACKUP_DIR" - -# 備份配置 (注意:PHP-FPM 實際使用 /Users/accusys/momentry/etc/php/8.5/ 配置) -tar -czf "$BACKUP_DIR/php_cfg_${TIMESTAMP}.tar.gz" \ - /Users/accusys/momentry/etc/php/8.5/php.ini \ - /Users/accusys/momentry/etc/php/8.5/php-fpm.conf \ - /Users/accusys/momentry/etc/php/8.5/php-fpm.d/ - -# 驗證 -sha256sum "$BACKUP_DIR/php_cfg_${TIMESTAMP}.tar.gz" > "$BACKUP_DIR/php_${TIMESTAMP}.sha256" -``` - -### 恢復 - -```bash -# 解壓配置 -tar -xzf /Users/accusys/momentry/backup/daily/php/php_cfg_20260316_102727.tar.gz -C / - -# 測試配置 -/opt/homebrew/opt/php/sbin/php-fpm --test --fpm-config /Users/accusys/momentry/etc/php/8.5/php-fpm.conf -``` - ---- - -## 版本資訊 - -- PHP Version: 8.5.2 -- PHP-FPM Port: 9000 -- 配置目錄: /Users/accusys/momentry/etc/php/ -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_POSTGRESQL.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_POSTGRESQL.md deleted file mode 100644 index 872dca6..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_POSTGRESQL.md +++ /dev/null @@ -1,397 +0,0 @@ -# PostgreSQL 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-15 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-15 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 PostgreSQL,配置為本地部署,支援遠端訪問。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| PostgreSQL | ✅ 已安裝 v18.1 | -| 數據目錄 | /Users/accusys/momentry/var/postgresql | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.postgresql.plist | -| Launchd 狀態 | ✅ 已註冊 | -| RunAtLoad | ✅ 已設定 | -| KeepAlive | ✅ 已設定 | - -### 重要更新 (2026-03-24) - -1. **資料目錄已變更**: 從 `/opt/homebrew/var/postgresql@18` 遷移到 `/Users/accusys/momentry/var/postgresql` -2. **統一管理**: 所有 Momentry 服務現在都使用 `/Library/LaunchDaemons/` 下的自定義 plist -3. **避免衝突**: 刪除了 homebrew plist,避免 reboot 後使用舊資料目錄 - ---- - -## 安裝步驟 - -### Step 1: 安裝 PostgreSQL (使用 brew) - -```bash -# 安裝 PostgreSQL -brew install postgresql@18 -``` - -**驗證**: -```bash -postgres --version -# postgres (PostgreSQL) 18.1 -``` - ---- - -### Step 2: 建立目錄結構 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/postgresql - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/postgresql - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/postgresql.log -touch /Users/accusys/momentry/log/postgresql.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/postgresql -chown -R accusys:staff /Users/accusys/momentry/etc/postgresql -chown -R accusys:staff /Users/accusys/momentry/log -``` - -**注意**: 如果需要從舊數據遷移,需要先初始化新目錄: -```bash -# 初始化新數據目錄 (會創建默認數據庫) -initdb -D /Users/accusys/momentry/var/postgresql -U accusys -``` - ---- - -### Step 3: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.postgresql.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -database: - postgresql: - enabled: true - host: "localhost" - port: 5432 - user: "accusys" - database: "momentry" -``` - -### 添加健康檢查函數 - -在 `monitor/database/postgres_monitor.sh` 中已包含 PostgreSQL 監控。 - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/postgresql/` | 數據 | **不要刪除** - 數據目錄 | -| `/Users/accusys/momentry/etc/postgresql/` | 配置 | **不要刪除** - 配置目錄 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/opt/homebrew/opt/postgresql@18/` | 安裝 | **刪除** - PostgreSQL 安裝目錄 | - -### Step 1: 停止 PostgreSQL - -```bash -# 找到 PostgreSQL 進程 -ps aux | grep postgres | grep -v grep - -# 停止 PostgreSQL -pg_ctl -D /opt/homebrew/var/postgresql@18 stop -# 或 -pkill -f postgresql - -# 確認停止 -ps aux | grep postgres | grep -v grep || echo "PostgreSQL 已停止" -``` - ---- - -### Step 2: 卸載 PostgreSQL - -```bash -# 卸載 PostgreSQL -brew uninstall postgresql@18 - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.postgresql.plist -sudo rm /Library/LaunchDaemons/com.momentry.postgresql.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/postgresql - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/postgresql.log -rm -f /Users/accusys/momentry/log/postgresql.error.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== PostgreSQL 卸載後檢查 ===" - -# 1. 檢查 PostgreSQL 進程 -echo "1. PostgreSQL 進程:" -ps aux | grep postgres | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 5432 -echo "2. Port 5432:" -lsof -i :5432 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. postgres 命令 -echo "3. postgres 命令:" -which postgres > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list postgresql@18 > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep postgresql > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 數據目錄 (可選刪除) -echo "6. 數據目錄:" -[ -d "/Users/accusys/momentry/var/postgresql" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 7. 日誌目錄 (可選刪除) -echo "7. 日誌目錄:" -[ -d "/Users/accusys/momentry/log" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - -**預期結果**: -``` -=== PostgreSQL 卸載後檢查 === -1. PostgreSQL 進程: - ✓ 已停止 -2. Port 5432: - ✓ 已釋放 -3. postgres 命令: - ✓ 已移除 -4. brew 安裝: - ✓ 已移除 -5. launchctl 服務: - ✓ 已移除 -6. 數據目錄: - ✓ 保留 (或 ✗ 已刪除) -7. 日誌目錄: - ✓ 保留 (或 ✗ 已刪除) -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep postgres | grep -v grep - -# 2. 檢查 Port -lsof -i :5432 - -# 3. 測試連線 -psql -U accusys -l - -# 4. 查看所有數據庫 -psql -U accusys -c "\l" - -# 5. 查看連接 -psql -U accusys -c "\conninfo" - -# 6. 查看表 -psql -U accusys -d momentry -c "\dt" - -# 7. 查看日誌 -tail -20 /Users/accusys/momentry/log/postgresql.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| Host | localhost | -| Port | 5432 | -| User | accusys | -| Database | momentry, video_register, gitea, n8n | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -POSTGRES_URL=postgresql://accusys@localhost:5432 -POSTGRES_DB=momentry -``` - ---- - -## 遠端訪問 - -- PostgreSQL 綁定到所有網路介面 (0.0.0.0) -- 本地網路其他機器可透過 IP 訪問 -- 請設定 `pg_hba.conf` 限制訪問 IP - ---- - -## 故障排除 - -### PostgreSQL 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/postgresql.log - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/var/postgresql/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/postgresql -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 5432 -lsof -i :5432 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.postgresql.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/postgresql@18/` | PostgreSQL 安裝目錄 | -| 執行檔 | `/opt/homebrew/opt/postgresql@18/bin/postgres` | PostgreSQL 執行檔 | -| 數據目錄 | `/Users/accusys/momentry/var/postgresql/` | 數據儲存 | -| 日誌 | `/Users/accusys/momentry/log/postgresql.log` | 執行日誌 | -| 錯誤日誌 | `/Users/accusys/momentry/log/postgresql.error.log` | 錯誤日誌 | -| plist | `/Library/LaunchDaemons/com.momentry.postgresql.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/momentry_db_backup_latest.sql` | momentry 數據庫備份 | -| 備份 | `/Users/accusys/momentry/var/video_register_db_backup_latest.sql` | video_register 數據庫備份 | - ---- - -## 備份與恢復 - -### 備份 (pg_dump) - -```bash -# 備份 momentry 數據庫 -pg_dump -U accusys momentry > /Users/accusys/momentry/var/momentry_db_backup_latest.sql - -# 備份 video_register 數據庫 -pg_dump -U accusys video_register > /Users/accusys/momentry/var/video_register_db_backup_latest.sql -``` - -### 恢復 (psql) - -```bash -# 恢復 momentry 數據庫 -psql -U accusys -d momentry < /Users/accusys/momentry/var/momentry_db_backup_latest.sql - -# 恢復 video_register 數據庫 -psql -U accusys -d video_register < /Users/accusys/momentry/var/video_register_db_backup_latest.sql -``` - -### 數據目錄複製 (完整遷移) - -```bash -# 1. 停止 PostgreSQL -pg_ctl -D /Users/accusys/momentry/var/postgresql stop - -# 2. 複製數據目錄 -cp -r /opt/homebrew/var/postgresql@18/* /Users/accusys/momentry/var/postgresql/ - -# 3. 設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/postgresql - -# 4. 啟動 PostgreSQL -sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist -``` - ---- - -## 版本資訊 - -- 版本: 18.1 -- Port: 5432 -- User: accusys -- 數據目錄: /Users/accusys/momentry/var/postgresql/ -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_QDRANT.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_QDRANT.md deleted file mode 100644 index 1b03200..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_QDRANT.md +++ /dev/null @@ -1,472 +0,0 @@ -# Qdrant 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-16 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-16 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 Qdrant Vector Database,配置為本地部署,支援遠端訪問。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| Qdrant | ✅ 已安裝 v1.17.0 | -| 數據目錄 | /Users/accusys/momentry/var/qdrant/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.qdrant.plist | - ---- - -## 安裝步驟 - -### Step 1: 安裝 Qdrant (使用 cargo) - -```bash -# 安裝 Qdrant 從 GitHub -cargo install --git https://github.com/qdrant/qdrant.git --locked -``` - -**驗證**: -```bash -qdrant --version -# qdrant 1.17.0 -``` - ---- - -### Step 2: 驗證 Qdrant 安裝 - -```bash -# 驗證 Qdrant 安裝 -~/.cargo/bin/qdrant --version -# qdrant 1.17.0 -``` - ---- - -### Step 3: 建立目錄結構 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/qdrant - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/qdrant - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/qdrant.log -touch /Users/accusys/momentry/log/qdrant.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/qdrant -chown -R accusys:staff /Users/accusys/momentry/etc/qdrant -chown -R accusys:staff /Users/accusys/momentry/log -``` - ---- - -### Step 4: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.qdrant.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.qdrant.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -database: - qdrant: - enabled: true - host: "localhost" - port: 6333 -``` - -### 添加健康檢查函數 - -在 `monitor/database/qdrant_monitor.sh` 中已包含 Qdrant 監控。 - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/qdrant/` | 數據 | **不要刪除** - Qdrant 數據 | -| `/Users/accusys/momentry/etc/qdrant/` | 配置 | **不要刪除** - Qdrant 配置 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `~/.cargo/bin/qdrant` | 安裝 | **刪除** - Qdrant 執行檔 | - -### Step 1: 停止 Qdrant - -```bash -# 找到 Qdrant 進程 -ps aux | grep qdrant | grep -v grep - -# 停止 Qdrant -pkill qdrant -# 或 -kill - -# 確認停止 -ps aux | grep qdrant | grep -v grep || echo "Qdrant 已停止" -``` - ---- - -### Step 2: 卸載 Qdrant (cargo) - -```bash -# 移除 cargo 安裝的 Qdrant -cargo uninstall qdrant - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.qdrant.plist -sudo rm /Library/LaunchDaemons/com.momentry.qdrant.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/qdrant - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/qdrant.log -rm -f /opt/homebrew/var/log/qdrant.error.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== Qdrant 卸載後檢查 ===" - -# 1. 檢查 Qdrant 進程 -echo "1. Qdrant 進程:" -ps aux | grep qdrant | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 6333 -echo "2. Port 6333:" -lsof -i :6333 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. Port 6334 -echo "3. Port 6334:" -lsof -i :6334 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 4. qdrant 命令 -echo "4. qdrant 命令:" -which qdrant > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. cargo 安裝 -echo "5. cargo 安裝:" -cargo install --list | grep qdrant > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. launchctl 服務 -echo "6. launchctl 服務:" -sudo launchctl list | grep qdrant > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 7. 數據目錄 (可選刪除) -echo "7. 數據目錄:" -[ -d "/Users/accusys/momentry/var/qdrant" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 8. 日誌目錄 (可選刪除) -echo "8. 日誌目錄:" -[ -d "/Users/accusys/momentry/log" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - -**預期結果**: -``` -=== Qdrant 卸載後檢查 === -1. Qdrant 進程: - ✓ 已停止 -2. Port 6333: - ✓ 已釋放 -3. Port 6334: - ✓ 已釋放 -4. qdrant 命令: - ✓ 已移除 -5. cargo 安裝: - ✓ 已移除 -6. launchctl 服務: - ✓ 已移除 -7. 數據目錄: - ✓ 保留 (或 ✗ 已刪除) -8. 日誌目錄: - ✓ 保留 (或 ✗ 已刪除) -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep qdrant | grep -v grep - -# 2. 檢查 Port -lsof -i :6333 -lsof -i :6334 - -# 3. 測試連線 (無認證) -curl http://localhost:6333/collections - -# 4. 測試連線 (有認證) -curl -H "api-key: Test3200Test3200Test3200" http://localhost:6333/collections - -# 5. 查看所有 collections -curl -s -H "api-key: Test3200Test3200Test3200" http://localhost:6333/collections - -# 6. 查看日誌 -tail -20 /Users/accusys/momentry/log/qdrant.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| REST API | http://localhost:6333 | -| gRPC | localhost:6334 | -| API Key | Test3200Test3200Test3200 | -| Qdrant UI | http://localhost:6333/dashboard | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -QDRANT_URL=http://localhost:6333 -QDRANT_API_KEY=Test3200Test3200Test3200 -``` - ---- - -## 遠端訪問 - -- Qdrant 綁定到 `0.0.0.0` (所有網路介面) -- 本地網路其他機器可透過 IP 訪問 -- 建議設定防火牆規則限制訪問 IP - ---- - -## 故障排除 - -### Qdrant 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/qdrant.log - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/var/qdrant/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/qdrant -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 6333 -lsof -i :6333 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.qdrant.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.qdrant.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| `/Users/accusys/.cargo/bin/qdrant` | 二進制 | cargo 安裝位置 (直接使用) | -| `/opt/homebrew/bin/qdrant` | 符號連結 | ~~已棄用~~ - 不再需要 | -| 數據目錄 | `/Users/accusys/momentry/var/qdrant/` | 數據儲存 | -| 日誌 | `/Users/accusys/momentry/log/qdrant.log` | 執行日誌 | -| 錯誤日誌 | `/opt/homebrew/var/log/qdrant.error.log` | 錯誤日誌 | -| plist | `/Library/LaunchDaemons/com.momentry.qdrant.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/qdrant_backup/` | 數據備份 | - ---- - -## 備份與恢復 - -### 備份 - -Qdrant 提供兩種備份方式:Snapshots (推薦) 和手動複製。 - -#### 方式一:使用 Snapshots API (推薦) - -```bash -# 創建備份目錄 -mkdir -p /Users/accusys/momentry/var/qdrant_backup - -# 獲取所有 collections -curl -s -H "api-key: Test3200Test3200Test3200" \ - http://localhost:6333/collections | jq -r '.result[].name' - -# 為每個 collection 創建 snapshot -# 假設 collection 名稱為 "chunks" -curl -X POST -H "api-key: Test3200Test3200Test3200" \ - http://localhost:6333/collections/chunks/snapshots \ - -o /Users/accusys/momentry/var/qdrant_backup/chunks_snapshot_$(date +%Y%m%d).tar.gz -``` - -#### 方式二:手動複製數據目錄 (停機備份) - -```bash -# 停止 Qdrant -pkill qdrant - -# 等待停止 -sleep 2 - -# 複製數據目錄 -TIMESTAMP=$(date +%Y%m%d) -mkdir -p /Users/accusys/momentry/var/qdrant_backup -tar -czf /Users/accusys/momentry/var/qdrant_backup/qdrant_data_${TIMESTAMP}.tar.gz \ - -C /Users/accusys/momentry/var qdrant/ - -# 啟動 Qdrant -launchctl load /Library/LaunchDaemons/com.momentry.qdrant.plist -``` - -#### 自動備份腳本 - -```bash -#!/bin/bash -# backup_qdrant.sh -set -e - -QDRANT_HOST="localhost" -QDRANT_PORT="6333" -QDRANT_API_KEY="Test3200Test3200Test3200" -BACKUP_DIR="/Users/accusys/momentry/var/qdrant_backup" -TIMESTAMP=$(date +%Y%m%d_%H%M%S) - -mkdir -p "$BACKUP_DIR" - -echo "開始 Qdrant 備份..." - -# 獲取所有 collections -COLLECTIONS=$(curl -s -H "api-key: $QDRANT_API_KEY" \ - http://${QDRANT_HOST}:${QDRANT_PORT}/collections | \ - jq -r '.result[].name') - -if [ -z "$COLLECTIONS" ]; then - echo "警告: 沒有找到任何 collections" -else - for COLLECTION in $COLLECTIONS; do - echo "備份 collection: $COLLECTION" - curl -X POST -H "api-key: $QDRANT_API_KEY" \ - "http://${QDRANT_HOST}:${QDRANT_PORT}/collections/${COLLECTION}/snapshots" \ - -o "${BACKUP_DIR}/${COLLECTION}_${TIMESTAMP}.tar.gz" 2>/dev/null || \ - echo "警告: $COLLECTION 備份失敗" - done -fi - -# 壓縮所有 snapshot -cd "$BACKUP_DIR" -tar -czf qdrant_snapshots_${TIMESTAMP}.tar.gz *.tar.gz 2>/dev/null || true -rm -f *.tar.gz - -# 清理 30 天前的備份 -find "$BACKUP_DIR" -name "qdrant_snapshots_*.tar.gz" -mtime +30 -delete - -echo "Qdrant 備份完成: ${BACKUP_DIR}/qdrant_snapshots_${TIMESTAMP}.tar.gz" -``` - -### 恢復 - -```bash -# 停止 Qdrant -pkill qdrant -sleep 2 - -# 解壓縮備份 -TIMESTAMP="20260315" -tar -xzf /Users/accusys/momentry/var/qdrant_backup/qdrant_snapshots_${TIMESTAMP}.tar.gz \ - -C /Users/accusys/momentry/var/qdrant_backup/ - -# 恢復數據目錄 (方式二備份) -# rm -rf /Users/accusys/momentry/var/qdrant/* -# tar -xzf /Users/accusys/momentry/var/qdrant_backup/qdrant_data_${TIMESTAMP}.tar.gz \ -# -C /Users/accusys/momentry/var/ - -# 啟動 Qdrant -launchctl load /Library/LaunchDaemons/com.momentry.qdrant.plist -``` - -### 排程備份 - -```bash -# 編輯 crontab -crontab -e - -# 添加每天凌晨 3 點執行備份 -0 3 * * * /Users/accusys/momentry/scripts/backup_qdrant.sh >> /Users/accusys/momentry/log/backup.log 2>&1 -``` - ---- - -## 版本資訊 - -- 版本: 1.17.0 -- API Key: Test3200Test3200Test3200 -- 數據目錄: /Users/accusys/momentry/var/qdrant/ -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_REDIS.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_REDIS.md deleted file mode 100644 index 16d1569..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_REDIS.md +++ /dev/null @@ -1,481 +0,0 @@ -# Redis 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-15 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-15 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-21 | 更新 rust redis crate 版本至 0.32.7 | OpenCode | - | -| V1.2 | 2026-03-21 | 添加 Redis 用戶配置說明 | OpenCode | - | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 Redis,配置為本地部署,支援遠端訪問。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| Redis | ✅ 已安裝 v8.4.0 | -| 數據目錄 | /opt/homebrew/var/db/redis/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.redis.plist | - ---- - -## 安裝步驟 - -### Step 1: 安裝 Redis (使用 brew) - -```bash -# 安裝 Redis -brew install redis -``` - -**驗證**: -```bash -redis-server --version -# Redis server v8.4.0 -``` - ---- - -### Step 2: 建立目錄結構 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/redis - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/redis - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/redis.log -touch /Users/accusys/momentry/log/redis.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/redis -chown -R accusys:staff /Users/accusys/momentry/etc/redis -chown -R accusys:staff /Users/accusys/momentry/log -``` - ---- - -### Step 3: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.redis.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.redis.plist -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/redis/` | 數據 | **不要刪除** - 數據目錄 | -| `/Users/accusys/momentry/etc/redis/` | 配置 | **不要刪除** - 配置目錄 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/opt/homebrew/opt/redis/` | 安裝 | **刪除** - Redis 安裝目錄 | - -### Step 1: 停止 Redis - -```bash -# 找到 Redis 進程 -ps aux | grep redis | grep -v grep - -# 停止 Redis -redis-cli -a accusys SHUTDOWN -# 或 -pkill redis-server - -# 確認停止 -ps aux | grep redis | grep -v grep || echo "Redis 已停止" -``` - ---- - -### Step 2: 卸載 Redis - -```bash -# 卸載 Redis -brew uninstall redis - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.redis.plist -sudo rm /Library/LaunchDaemons/com.momentry.redis.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/redis - -# 刪除配置目錄 (可選) -rm -rf /Users/accusys/momentry/etc/redis - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/redis.log -rm -f /Users/accusys/momentry/log/redis.error.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/etc -# /Users/accusys/momentry/log -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== Redis 卸載後檢查 ===" - -# 1. 檢查 Redis 進程 -echo "1. Redis 進程:" -ps aux | grep redis | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 6379 -echo "2. Port 6379:" -lsof -i :6379 > /dev/null 2>&1 && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. redis-server 命令 -echo "3. redis-server 命令:" -which redis-server > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list redis > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep redis > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 數據目錄 (可選刪除) -echo "6. 數據目錄:" -[ -d "/Users/accusys/momentry/var/redis" ] && echo " ✓ 保留" || echo " ✗ 已刪除" - -# 7. 日誌目錄 (可選刪除) -echo "7. 日誌目錄:" -[ -d "/Users/accusys/momentry/log" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - -**預期結果**: -``` -=== Redis 卸載後檢查 === -1. Redis 進程: - ✓ 已停止 -2. Port 6379: - ✓ 已釋放 -3. redis-server 命令: - ✓ 已移除 -4. brew 安裝: - ✓ 已移除 -5. launchctl 服務: - ✓ 已移除 -6. 數據目錄: - ✓ 保留 (或 ✗ 已刪除) -7. 日誌目錄: - ✓ 保留 (或 ✗ 已刪除) -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "redis" - type: "tcp" - port: 6379 - host: "localhost" - timeout: 5 - enabled: true -``` - -### 添加健康檢查函數 - -在 `monitor/service/health_check.sh` 中添加: - -```bash -check_redis() { - local start=$(date +%s%N) - if redis-cli -a accusys ping > /dev/null 2>&1; then - local end=$(date +%s%N) - local ms=$(( (end - start) / 1000000 )) - echo -e "${GREEN}✓${NC} Redis (6379) - ${ms}ms" - record_service "redis" "up" "$ms" "" - return 0 - else - echo -e "${RED}✗${NC} Redis (6379) - Down" - record_service "redis" "down" "0" "Connection failed" - return 1 - fi -} -``` - -```bash -# 1. 檢查進程 -ps aux | grep redis | grep -v grep - -# 2. 檢查 Port -lsof -i :6379 - -# 3. 測試連線 (無認證) -redis-cli -a accusys PING - -# 4. 測試連線 (有認證) -redis-cli -a accusys -e "PING" - -# 5. 查看所有 keys -redis-cli -a accusys KEYS '*' - -# 6. 查看 info -redis-cli -a accusys INFO - -# 7. 查看日誌 -tail -20 /Users/accusys/momentry/log/redis.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| Host | localhost | -| Port | 6379 | -| Password | accusys | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -REDIS_URL=redis://:accusys@localhost:6379 -``` - ---- - -## 遠端訪問 - -- Redis 綁定到 `0.0.0.0` (所有網路介面) -- 本地網路其他機器可透過 IP 訪問 -- 密碼認證: `accusys` - ---- - -## 故障排除 - -### Redis 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/redis.log - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/var/redis/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/redis -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port 6379 -lsof -i :6379 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.redis.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.redis.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/redis/` | Redis 安裝目錄 | -| 執行檔 | `/opt/homebrew/opt/redis/bin/redis-server` | Redis 執行檔 | -| 數據目錄 | `/Users/accusys/momentry/var/redis/` | 數據儲存 | -| 配置目錄 | `/Users/accusys/momentry/etc/redis/` | 配置儲存 | -| 日誌 | `/Users/accusys/momentry/log/redis.log` | 執行日誌 | -| 錯誤日誌 | `/Users/accusys/momentry/log/redis.error.log` | 錯誤日誌 | -| plist | `/Library/LaunchDaemons/com.momentry.redis.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/var/redis_backup_latest.rdb` | 數據備份 | - ---- - -## 備份與恢復 - -### 備份 - -```bash -# 觸發保存並備份 -redis-cli -a accusys SAVE -cp /opt/homebrew/var/db/redis/dump.rdb /Users/accusys/momentry/var/redis_backup_latest.rdb -``` - -### 恢復 - -```bash -# 停止 Redis -redis-cli -a accusys SHUTDOWN - -# 複製備份文件覆蓋 -cp /Users/accusys/momentry/var/redis_backup_latest.rdb /Users/accusys/momentry/var/redis/dump.rdb - -# 啟動 Redis -sudo launchctl load /Library/LaunchDaemons/com.momentry.redis.plist -``` - ---- - -## 版本資訊 - -| 項目 | 值 | -|------|-----| -| Redis Server | 8.4.0 | -| Rust redis crate | 0.32.7 | -| Port | 6379 | -| Password | accusys | -| 數據目錄 | /Users/accusys/momentry/var/redis/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | - ---- - -## Rust redis crate 版本 - -Cargo.toml 中的 redis 依賴: - -```toml -redis = { version = "0.32", features = ["tokio-comp"] } -``` - -### 版本歷史 - -| 版本 | 日期 | 變更 | -|------|------|-------| -| 0.25.4 | - | 原始版本(有未來相容性警告) | -| 0.32.7 | 2026-03-21 | **升級** - 修復 Rust 2024 never type 回退問題 | - -### 升級說明 - -升級到 0.32.x 的優點: -- 修復 Rust 2024 edition 未來相容性問題 -- API 完全向後相容 -- 無需修改現有程式碼 - ---- - -## Redis 用戶配置說明 - -### 當前狀態 - -| 項目 | 狀態 | -|------|------| -| 用戶類型 | 僅有 `default` 用戶 | -| 自訂用戶 | ❌ 未配置 | -| ACL 持久化 | ❌ 未配置 | - -### Redis ACL 狀態 - -```bash -# 查看 ACL -redis-cli -a accusys ACL LIST - -# 輸出: -# user default on sanitize-payload #hash ~* &* +@all -``` - -### 連線格式說明 - -| 格式 | 狀態 | 說明 | -|------|------|------| -| `redis://:accusys@localhost:6379` | ✅ 正確 | 使用默認用戶 + 密碼 | -| `redis://accusys:accusys@localhost:6379` | ❌ 失敗 | 用戶 `accusys` 不存在 | - -### 為何用戶名不可用 - -1. **Redis 啟動方式**:使用 `--requirepass` 參數,僅設定默認用戶密碼 -2. **無 ACL 配置文件**:未指定 `--aclfile` 參數 -3. **動態建立用戶**:手動建立的用戶不會持久化(重啟後消失) - -### 解決方案 - -#### 方案 A:使用默認用戶(現行) - -```env -REDIS_URL=redis://:accusys@localhost:6379 -``` - -**適用於**:單一應用、簡單部署 - -#### 方案 B:建立 ACL 配置文件 - -```bash -# 1. 建立 ACL 文件 -cat > /Users/accusys/momentry/etc/redis/users.acl << 'EOF' -user default on sanitize-payload ~* &* +@all >accusys -user accusys on sanitize-payload ~* &* +@all >accusys -EOF - -# 2. 修改 plist (添加 --aclfile 參數) -# --aclfile /Users/accusys/momentry/etc/redis/users.acl - -# 3. 重啟 Redis -sudo launchctl unload /Library/LaunchDaemons/com.momentry.redis.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.redis.plist -``` - -**適用於**:多應用、需要用戶隔離 - -### 參考 - -- 問題追蹤:`docs/PENDING_ISSUES.md` 問題 #5 -- 測試結果:2026-03-21 Redis 認證測試 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_RUSTDESK.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_RUSTDESK.md deleted file mode 100644 index 9fb7c16..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_RUSTDESK.md +++ /dev/null @@ -1,300 +0,0 @@ -# RustDesk 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-15 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-15 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -## 概述 - -本文檔說明如何在 macOS 上安裝 RustDesk 遠端桌面服務,配置為本地部署。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| RustDesk | ✅ 已安裝 | -| 數據目錄 | /Users/accusys/momentry/var/rustdesk/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| HBBS Plist | /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist | -| HBBR Plist | /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist | - ---- - -## 服務端口 - -| 服務 | Port | 協議 | -|------|------|------| -| hbbs (TCP) | 21115 | 主端口 | -| hbbs (TCP/UDP) | 21116 | NAT 測試 | -| hbbs (WebSocket) | 21118 | WebSocket | -| hbbr (TCP) | 21117 | 中繼端口 | -| hbbr (TCP) | 21119 | 中繼 extra | - ---- - -## 安裝步驟 - -### Step 1: 安裝 RustDesk (使用 brew) - -```bash -# 安裝 RustDesk -brew install rustdesk -``` - -**驗證**: -```bash -hbbs --version -hbbr --version -``` - ---- - -### Step 2: 建立目錄 - -```bash -# 建立數據目錄 -mkdir -p /Users/accusys/momentry/var/rustdesk - -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/rustdesk - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立日誌文件 -touch /Users/accusys/momentry/log/rustdesk.hbbs.log -touch /Users/accusys/momentry/log/rustdesk.hbbs.error.log -touch /Users/accusys/momentry/log/rustdesk.hbbr.log -touch /Users/accusys/momentry/log/rustdesk.hbbr.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/var/rustdesk -chown -R accusys:staff /Users/accusys/momentry/etc/rustdesk -chown -R accusys:staff /Users/accusys/momentry/log -``` - ---- - -### Step 3: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.rustdesk.hbbs.plist /Library/LaunchDaemons/ -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.rustdesk.hbbr.plist /Library/LaunchDaemons/ - -# 移除舊 plist (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.rustdesk.hbbs.plist 2>/dev/null -sudo launchctl unload /Library/LaunchDaemons/com.rustdesk.hbbr.plist 2>/dev/null -sudo rm /Library/LaunchDaemons/com.rustdesk.hbbs.plist 2>/dev/null -sudo rm /Library/LaunchDaemons/com.rustdesk.hbbr.plist 2>/dev/null - -# 載入並啟動 -sudo launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist -``` - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "rustdesk-hbbs" - type: "tcp" - port: 21115 - host: "localhost" - timeout: 5 - enabled: true - - name: "rustdesk-hbbr" - type: "tcp" - port: 21117 - host: "localhost" - timeout: 5 - enabled: true -``` - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/var/rustdesk/` | 數據 | **不要刪除** - RustDesk 數據 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/opt/homebrew/bin/hbbr` | 安裝 | **刪除** - RustDesk 安裝 | -| `/opt/homebrew/bin/hbbs` | 安裝 | **刪除** - RustDesk 安裝 | - -### Step 1: 停止 RustDesk - -```bash -# 停止 RustDesk 服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist - -# 確認停止 -ps aux | grep rustdesk | grep -v grep || echo "RustDesk 已停止" -``` - ---- - -### Step 2: 卸載 RustDesk - -```bash -# 卸載 RustDesk -brew uninstall rustdesk - -# 移除 plist -sudo rm /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist -sudo rm /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除數據目錄 (可選) -rm -rf /Users/accusys/momentry/var/rustdesk - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/rustdesk-*.log -``` - -**注意: 不要刪除以下共用目錄**: -```bash -# 這些是共用的,不要刪除! -# /Users/accusys/momentry/var -# /Users/accusys/momentry/log -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep rustdesk | grep -v grep - -# 2. 檢查 Port -lsof -i :21115 -lsof -i :21116 -lsof -i :21117 -lsof -i :21118 -lsof -i :21119 - -# 3. 測試連線 -nc -zv localhost 21115 -nc -zv localhost 21116 - -# 4. 查看日誌 -tail -20 /Users/accusys/momentry/log/rustdesk-hbbs.log -tail -20 /Users/accusys/momentry/log/rustdesk-hbbr.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| Server ID | 59.124.167.225 | -| NAT Test Port | 21116 | -| Relay Port | 21117, 21119 | - ---- - -## 故障排除 - -### RustDesk 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/rustdesk-hbbs.log -tail -f /Users/accusys/momentry/log/rustdesk-hbbr.log - -# 檢查數據目錄權限 -ls -la /Users/accusys/momentry/var/rustdesk/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/var/rustdesk -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port -lsof -i :21116 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 -sudo launchctl unload /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/bin/hbbs` | RustDesk Server 執行檔 | -| 安裝 | `/opt/homebrew/bin/hbbr` | RustDesk Relay 執行檔 | -| 數據目錄 | `/Users/accusys/momentry/var/rustdesk/` | 數據儲存 | -| HBBS 日誌 | `/Users/accusys/momentry/log/rustdesk-hbbs.log` | 服務日誌 | -| HBBR 日誌 | `/Users/accusys/momentry/log/rustdesk-hbbr.log` | 中繼日誌 | -| HBBS Plist | `/Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist` | 開機啟動 | -| HBBR Plist | `/Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist` | 開機啟動 | - ---- - -## 版本資訊 - -- 安裝方式: Homebrew (Cask) -- Client 版本: 1.4.6 -- Server 版本: 1.1.15 (hbbs/hbbr binaries from homebrew) -- 數據目錄: /Users/accusys/momentry/var/rustdesk/ -- 日誌目錄: /Users/accusys/momentry/log/ - ---- - -## 注意事項 - -### Server 版本 - -Homebrew 的 RustDesk Cask 只提供客戶端應用程序。服務器二進制文件 (hbbs, hbbr) 需要從其他來源安裝或自行編譯。當前使用的版本較舊 (1.1.15)。 - -如需更新服務器版本,可以考慮: -1. 從源代碼編譯最新版本 -2. 使用 RustDesk 官方提供的 Docker 鏡像 -3. 等待 Homebrew 添加服務器公式 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_SFTPGO.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_SFTPGO.md deleted file mode 100644 index 67b8867..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_SFTPGO.md +++ /dev/null @@ -1,1061 +0,0 @@ -# SFTPGo 安裝指南 (本地部署) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-18 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-18 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-22 | 添加備份還原、API管理、Hook配置 | opencode | OpenCode | - ---- - -## 更新紀錄 - -- **2026-03-22**: - - 成功使用統一備份系統還原 SFTPGo 到 20260321_101928 時間點 - - 重置 admin 密碼為 `Test3200Test3200` - - 修復 demo 用戶權限格式 (從 `["*"]` 改為 `{" /":["*"]}`) - - 通过 API 创建并配置 `demo` 用户和 `demo` 組 - - 配置 SFTPGo Hook 實現自動化檔案註冊 - - 確認 API 認證方式為 Basic Auth (GET `/api/v2/token`) - -## 概述 - -本文檔說明如何在 macOS 上安裝 SFTPGo,配置為本地部署,用於 SFTP/FTP/WebDAV 檔案傳輸服務。 - ---- - -## 當前狀態 - -| 項目 | 狀態 | -|------|------| -| SFTPGo | ✅ 已安裝 v2.7.0 | -| Port | 8080 (HTTP), 2022 (SFTP) | -| 配置目錄 | /Users/accusys/momentry/etc/sftpgo/ | -| 日誌目錄 | /Users/accusys/momentry/log/ | -| Plist | /Library/LaunchDaemons/com.momentry.sftpgo.plist | -| API 狀態 | ✅ 已啟用 (`enable_rest_api: true`) | -| Hook 狀態 | ✅ 已配置 (執行於檔案上傳時) | - ---- - -## 備份與還原機制 - -SFTPGo 使用 Momentry 統一備份系統進行完整的配置與數據庫備份。 - -### 備份內容 - -```bash -# 備份目錄 -/Users/accusys/momentry/backup/daily/sftpgo/ - -# 備份文件範例 -sftpgo_cfg_20260321_101928.tar.gz # 配置文件 -sftpgo_db_20260321_101928.sql.gz # PostgreSQL 數據庫 -sftpgo_20260321_101928.sha256 # 校驗和 -``` - -### 列出可用備份時間點 - -```bash -/Users/accusys/momentry/scripts/backup_all.sh list | grep sftpgo -``` - -### 執行備份 - -```bash -# 備份 SFTPGo (配置 + 數據庫) -/Users/accusys/momentry/scripts/backup_all.sh sftpgo full - -# 手動備份單一服務 -/Users/accusys/momentry/scripts/backup_all.sh sftpgo cfg -``` - -### 執行還原 - -```bash -# 1. 備份當前狀態 (安全措施) -/Users/accusys/momentry/scripts/backup_all.sh sftpgo full - -# 2. 還原到指定時間點 -/Users/accusys/momentry/scripts/backup_all.sh restore sftpgo 20260321_101928 - -# 3. 驗證還原結果 -curl http://localhost:8080/api/v2/version -psql -U sftpgo -d sftpgo -c "SELECT username, status FROM admins;" -``` - -### 還原流程说明 - -`backup_all.sh` 的 `restore_sftpgo()` 函数会执行以下步骤 (第 517-546 行): - -1. **停止 SFTPGo** - 使用 `pkill -f sftpgo` -2. **恢复配置文件** - 从 `sftpgo_cfg_*.tar.gz` 恢复到 `/Users/accusys/momentry/etc/sftpgo/` -3. **恢复 PostgreSQL 数据库**: - - 删除现有数据库 (如存在) - - 创建新数据库并设置所有者 - - 从 `sftpgo_db_*.sql.gz` 导入数据 -4. **重启 SFTPGo** - 手动启动服务 - -### 備份狀態檢查 - -```bash -/Users/accusys/momentry/scripts/backup_all.sh status -``` - -此命令會顯示所有服務的最新備份狀態與大小。 - ---- - -## 安裝步驟 - -### Step 1: 安裝 SFTPGo (使用 brew) - -```bash -# 安裝 SFTPGo -brew install sftpgo -``` - -**驗證**: -```bash -sftpgo --version -# SFTPGo 2.7.0 -``` - ---- - -### Step 2: 建立目錄 - -```bash -# 建立配置目錄 -mkdir -p /Users/accusys/momentry/etc/sftpgo - -# 建立日誌目錄 -mkdir -p /Users/accusys/momentry/log - -# 建立工作目錄 -mkdir -p /Users/accusys/workspace/sftpgo - -# 建立日誌文件 -touch /Users/accusys/momentry/log/sftpgo.log -touch /Users/accusys/momentry/log/sftpgo.error.log - -# 設定權限 -chown -R accusys:staff /Users/accusys/momentry/etc/sftpgo -chown -R accusys:staff /Users/accusys/momentry/log -chown -R accusys:staff /Users/accusys/workspace/sftpgo -``` - ---- - -### Step 3: 建立設定檔 - -建立 `/Users/accusys/momentry/etc/sftpgo/sftpgo.json`: - -```json -{ - "common": { - "idle_timeout": 15, - "upload_mode": 0, - "max_per_host_connections": 20 - }, - "users": [ - { - "username": "accusys", - "password": "", - "public_keys": [], - "home_dir": "/Users/accusys/workspace/sftpgo", - "uid": 501, - "gid": 20, - "permissions": { - "/": ["*"] - } - } - ], - "httpd": { - "bind_port": 8080, - "bind_address": "0.0.0.0" - }, - "ftpd": { - "bind_port": 21, - "bind_address": "0.0.0.0" - }, - "sftpd": { - "bind_port": 2022, - "bind_address": "0.0.0.0" - }, - "webdavd": { - "bind_port": 0, - "bind_address": "" - } -} -``` - ---- - -### Step 4: 使用 plist 開機自動啟動 - -```bash -# 複製 plist 到 LaunchDaemons 目錄 -sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.sftpgo.plist /Library/LaunchDaemons/ - -# 載入並啟動 -sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.sftpgo.plist -``` - -#### Plist 環境變量說明 - -plist 包含以下環境變量用於自動創建 admin 用戶: - -| 環境變量 | 值 | 說明 | -|----------|------|------| -| `SFTPGO_DEFAULT_ADMIN_USERNAME` | `admin` | 默認管理員用戶名 | -| `SFTPGO_DEFAULT_ADMIN_PASSWORD` | `Test3200Test3200` | 默認管理員密碼 | - -**注意**: 這些變量僅在首次啟動時用於創建 admin 用戶。如果 admin 已存在,則不會覆蓋。 - ---- - -## 監控配置 - -### 添加到監控配置 - -在 `monitor/config/monitor_config.yaml` 中添加: - -```yaml -service: - services: - - name: "sftpgo" - type: "http" - port: 8080 - host: "localhost" - check_url: "http://localhost:8080/api/v2/info" - timeout: 5 - enabled: true -``` - -### API 監控端點 - -| 端點 | 說明 | 認證 | -|------|------|------| -| `/api/v2/info` | 伺服器資訊 | ❌ 不需要 | -| `/api/v2/healthz` | 健康檢查 | ❌ 不需要 | -| `/api/v2/version` | 版本資訊 | ❌ 不需要 | -| `/api/v2/token` | 獲取 Token | ✅ Basic Auth | -| `/api/v2/admins` | 管理員列表 | ✅ Bearer Token | -| `/api/v2/users` | 用戶列表 | ✅ Bearer Token | -| `/api/v2/groups` | 組列表 | ✅ Bearer Token | - ---- - ---- - -## 卸載步驟 - -### 重要: 路徑說明 - -| 路徑 | 類型 | 說明 | -|------|------|------| -| `/Users/accusys/momentry/etc/sftpgo/` | 配置 | **不要刪除** - SFTPGo 配置 | -| `/Users/accusys/momentry/log/` | 日誌 | **不要刪除** - 日誌目錄 | -| `/Users/accusys/workspace/sftpgo/` | 數據 | **不要刪除** - 上傳檔案目錄 | -| `/opt/homebrew/opt/sftpgo/` | 安裝 | **刪除** - SFTPGo 安裝目錄 | - -### Step 1: 停止 SFTPGo - -```bash -# 找到 SFTPGo 進程 -ps aux | grep sftpgo | grep -v grep - -# 停止 SFTPGo -pkill sftpgo - -# 確認停止 -ps aux | grep sftpgo | grep -v grep || echo "SFTPGo 已停止" -``` - ---- - -### Step 2: 卸載 SFTPGo - -```bash -# 卸載 SFTPGo -brew uninstall sftpgo - -# 移除 plist -sudo launchctl unload /Library/LaunchDaemons/com.momentry.sftpgo.plist -sudo rm /Library/LaunchDaemons/com.momentry.sftpgo.plist -``` - ---- - -### Step 3: 刪除專屬檔案 - -```bash -# 刪除配置目錄 (可選) -rm -rf /Users/accusys/momentry/etc/sftpgo - -# 刪除日誌 (可選) -rm -f /Users/accusys/momentry/log/sftpgo.log -rm -f /Users/accusys/momentry/log/sftpgo.error.log -``` - -**注意: 不要刪除以下目錄**: -```bash -# 這些是重要的,不要刪除! -# /Users/accusys/momentry/etc/sftpgo -# /Users/accusys/momentry/log -# /Users/accusys/workspace/sftpgo -``` - ---- - -### Step 4: 卸載後檢查清單 - -```bash -echo "=== SFTPGo 卸載後檢查 ===" - -# 1. 檢查 SFTPGo 進程 -echo "1. SFTPGo 進程:" -ps aux | grep sftpgo | grep -v grep && echo " ✗ 仍在運行" || echo " ✓ 已停止" - -# 2. Port 8080/2022 -echo "2. Port 8080/2022:" -(lsof -i :8080 > /dev/null 2>&1 || lsof -i :2022 > /dev/null 2>&1) && echo " ✗ 仍被佔用" || echo " ✓ 已釋放" - -# 3. sftpgo 命令 -echo "3. sftpgo 命令:" -which sftpgo > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 4. brew 安裝 -echo "4. brew 安裝:" -brew list sftpgo > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 5. launchctl 服務 -echo "5. launchctl 服務:" -sudo launchctl list | grep sftpgo > /dev/null 2>&1 && echo " ✗ 仍存在" || echo " ✓ 已移除" - -# 6. 配置目錄 (可選刪除) -echo "6. 配置目錄:" -[ -d "/Users/accusys/momentry/etc/sftpgo" ] && echo " ✓ 保留" || echo " ✗ 已刪除" -``` - ---- - -## 手動檢查命令 - -```bash -# 1. 檢查進程 -ps aux | grep sftpgo | grep -v grep - -# 2. 檢查 Port -lsof -i :8080 -lsof -i :2022 - -# 3. 測試連線 -curl http://localhost:8080/ - -# 4. 查看版本 -sftpgo --version - -# 5. 驗證配置 -sftpgo validate --config /Users/accusys/momentry/etc/sftpgo/sftpgo.json - -# 6. 查看日誌 -tail -20 /Users/accusys/momentry/log/sftpgo.log -``` - ---- - -## 連線資訊 - -| 項目 | 值 | -|------|-----| -| HTTP/WebDAV | http://localhost:8080 | -| SFTP | localhost:2022 | -| FTP | localhost:21 | -| Admin API | http://localhost:8080/api/v2/info | - ---- - -## 環境變數 - -在 `.env` 中: - -```env -SFTPGO_CONFIG=/Users/accusys/momentry/etc/sftpgo/sftpgo.json -SFTPGO_DATA_DIR=/Users/accusys/workspace/sftpgo -``` - ---- - -## 管理員帳戶修復 - -### 透過 Web 管理面板重置密碼 (推薦) - -1. 前往 **http://localhost:8080/web/admin/login** -2. 點擊 **Forgot password?** -3. 輸入 **Installation Code**: `Test3200Test3200` -4. 為 `admin` 設定新密碼 - -### 透過 SQL 直接重建管理員帳戶 - -如果 Web 面板無法使用,可直接操作 PostgreSQL 資料庫: - -#### 連線到資料庫 - -```bash -psql -U accusys -d sftpgo -``` - -#### 插入管理員帳戶 - -```sql -INSERT INTO admins ( - username, - description, - password, - email, - status, - permissions, - filters, - additional_info, - last_login, - role_id, - created_at, - updated_at -) VALUES ( - 'admin', - '', - '$2a$10$3Boql8AHoxPXWWmgmJiN5.b8s1Z65gNp1yqKQvZ5SOEv7j8NRA58.', - '', - 1, - '["*"]', - '{"require_two_factor":false,"totp_config":{"secret":{}},"preferences":{}}', - '', - 0, - NULL, - EXTRACT(EPOCH FROM NOW())::bigint * 1000, - EXTRACT(EPOCH FROM NOW())::bigint * 1000 -); -``` - -**預設密碼**: `Test3200Test3200` - -#### 使用 bcrypt 生成密碼哈希 - -```bash -python3 -c "import bcrypt; print(bcrypt.hashpw(b'Test3200Test3200', bcrypt.gensalt(rounds=10)).decode())" -``` - -### 使用 CLI 重置密碼 - -```bash -# 停止 SFTPGo (如果正在运行) -pkill -f sftpgo - -# 重置密碼 (互動式) -sftpgo resetpwd --admin admin --config-file /Users/accusys/momentry/etc/sftpgo/sftpgo.json - -# 重新啟動 SFTPGo -/opt/homebrew/opt/sftpgo/bin/sftpgo serve --config-file /Users/accusys/momentry/etc/sftpgo/sftpgo.json & -``` - -### 使用 Expect 自動化密碼重置 - -如果需要自動化重置,可以創建 expect 腳本: - -```bash -# resetpwd.exp -#!/usr/bin/expect -f -set timeout 10 -set admin_user [lindex $argv 0] -set new_password [lindex $argv 1] - -spawn sftpgo resetpwd --admin $admin_user --config-file /Users/accusys/momentry/etc/sftpgo/sftpgo.json -expect "Enter Password:" -send "$new_password\r" -expect "Enter Password:" -send "$new_password\r" -expect eof -``` - -執行: -```bash -chmod +x resetpwd.exp -expect resetpwd.exp admin Test3200Test3200 -``` - ---- - -### 透過 CLI 重置密碼 - -```bash -# 停止 SFTPGo -kill $(pgrep -f "sftpgo serve") - -# 重置密碼 (互動式) -sftpgo resetpwd --admin admin --config-file /Users/accusys/momentry/etc/sftpgo/sftpgo.json - -# 重新啟動 SFTPGo -sftpgo serve --config-file /Users/accusys/momentry/etc/sftpgo/sftpgo.json & -``` - -### 驗證管理員帳戶 - -```sql --- 檢查 admin 是否存在 -SELECT id, username, status, last_login FROM admins; - --- 檢查使用者是否存在 (SFTP/WebDAV 登入) -SELECT id, username, status, home_dir FROM users; -``` - ---- - -## API 管理用戶與組 - -SFTPGo 提供 RESTful API 用於管理用戶和組,支援自動化運維。 - -### API 認證方式 - -- **獲取 Access Token** (使用 Basic Auth): -```bash -TOKEN=$(curl -s -X GET http://localhost:8080/api/v2/token \ - -u "admin:Test3200Test3200" | jq -r '.access_token') -``` - -- **使用 Token 調用 API**: -```bash -curl -X GET http://localhost:8080/api/v2/admins \ - -H "Authorization: Bearer $TOKEN" -``` - -**注意**: `/api/v2/token` 端點使用 `GET` 方法,而非 `POST`。 - -### 列出所有用戶 - -```bash -TOKEN=$(curl -s -X GET http://localhost:8080/api/v2/token -u "admin:Test3200Test3200" | jq -r '.access_token') -curl -s -X GET "http://localhost:8080/api/v2/users?limit=100" \ - -H "Authorization: Bearer $TOKEN" | jq -r '.[] | "\(.username) status=\(.status) home=\(.home_dir)"' -``` - -### 創建用戶 - -```bash -curl -s -X POST http://localhost:8080/api/v2/users \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "username": "demo", - "password": "demopassword123", - "email": "demo@momentry.local", - "status": 1, - "home_dir": "/Users/accusys/sftpgo_test/demo", - "uid": 501, - "gid": 20, - "permissions": { - "/": ["*"] - } - }' -``` - -**權限格式注意**: 必須為 `map[string][]string` 格式,例如: -```json -{ - "/": ["*"], - "/upload": ["read", "write"] -} -``` - -### 修復用戶權限格式 - -如果權限存儲為數組 `["*"]` 而非 map,API 會返回錯誤: -``` -unable to deserialize permissions for user "demo": json: cannot unmarshal array into Go value of type map[string][]string -``` - -修復方法: -```bash -psql -h 127.0.0.1 -p 5432 -U sftpgo -d sftpgo -c \ - "UPDATE users SET permissions = '{\" /\":[\"*\"]}'::jsonb WHERE username='demo';" -``` - -### 創建組 - -```bash -curl -s -X POST http://localhost:8080/api/v2/groups \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "demo", - "description": "Demo group for SFTP uploads" - }' -``` - -### 將用戶加入組 - -查看 User Schema 中的 `groups` 欄位為 `GroupMapping` 數組: -```json -{ - "groups": [ - { - "name": "demo", - "type": 1 // 1=主要組, 2=次要組, 3=僅成員身份 - } - ] -} -``` - -更新用戶組關聯: -```bash -curl -s -X PUT http://localhost:8080/api/v2/users/demo \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "groups": [ - { - "name": "demo", - "type": 1 - } - ], - "permissions": { - "/": ["*"] - } - }' -``` - -**重要**: 更新用戶時必須提供完整的必要欄位 (如 `permissions`),否則會驗證失敗。 - -### API 端點對照表 - -| 功能 | 端點 | 方法 | -|------|------|------| -| 獲取 Token | `/api/v2/token` | GET (Basic Auth) | -| 列出管理員 | `/api/v2/admins` | GET | -| 列出用戶 | `/api/v2/users` | GET | -| 創建用戶 | `/api/v2/users` | POST | -| 獲取用戶 | `/api/v2/users/{username}` | GET | -| 更新用戶 | `/api/v2/users/{username}` | PUT | -| 刪除用戶 | `/api/v2/users/{username}` | DELETE | -| 列出組 | `/api/v2/groups` | GET | -| 創建組 | `/api/v2/groups` | POST | -| 獲取組 | `/api/v2/groups/{name}` | GET | -| 更新組 | `/api/v2/groups/{name}` | PUT | -| 刪除組 | `/api/v2/groups/{name}` | DELETE | - -完整的 API 文件請參考: http://localhost:8080/openapi/ - ---- - -## Hook 配置 - -SFTPGo Hook 用於在檔案操作時觸發外部腳本,實現自動化處理。 - -### 配置文件位置 - -`/Users/accusys/momentry/etc/sftpgo/sftpgo.json` - -### 通用 Actions 配置 - -在 `common.actions` 中配置: -```json -{ - "common": { - "actions": { - "execute_on": ["add"], // 觸發時機: 檔案上傳完成後 - "execute_sync": [], // 同步執行 ([]) - "hook": "/path/to/hook.sh" // Hook 腳本路徑 - } - } -} -``` - -### Hook 腳本範例 - -位置: `/Users/accusys/sftpgo_test/register_hook.sh` - -```bash -#!/bin/bash -# SFTPGo Hook - 檔案上傳後自動註冊到 Momentry Core - -# SFTPGo 傳遞的環境變數 -# ${SFTPGO_ACTION} - 操作類型 (add, delete, etc.) -# ${SFTPGO_USERNAME} - 用戶名 -# ${SFTPGO_FILEPATH} - 檔案路徑 (相對首頁目錄) -# ${SFTPGO_FILESIZE} - 檔案大小 -# ${SFTPGO_TIMESTAMP} - 操作時間戳 - -# 絕對路徑轉換 -UPLOAD_DIR="/Users/accusys/sftpgo_test/demo" -RELATIVE_PATH="${SFTPGO_FILEPATH#./}" -ABS_PATH="${UPLOAD_DIR}/${RELATIVE_PATH}" - -# 日誌記錄 -LOG_FILE="/Users/accusys/sftpgo_test/hook.log" -echo "$(date '+%Y-%m-%d %H:%M:%S') - User: ${SFTPGO_USERNAME}, File: ${ABS_PATH}, Size: ${SFTPGO_FILESIZE}" >> "$LOG_FILE" - -# 調用 Momentry Core 註冊 API -API_URL="http://localhost:8080/api/v1/register" -RESPONSE=$(curl -s -X POST "$API_URL" \ - -H "Content-Type: multipart/form-data" \ - -F "file=@${ABS_PATH}" \ - --connect-timeout 10 --max-time 300) - -echo "$(date '+%Y-%m-%d %H:%M:%S') - API Response: ${RESPONSE}" >> "$LOG_FILE" -``` - -### Hook 執行權限 - -```bash -chmod +x /Users/accusys/sftpgo_test/register_hook.sh -``` - -### Hook 執行時間點 - -`execute_on` 支援以下值: -| 值 | 觸發時機 | -|-----|----------| -| `add` | 檔案上傳完成後 | -| `delete` | 檔案刪除後 | -| `upload_complete` | 上傳完成 (multipart) | -| `download` | 檔案下載時 | -| `rename` | 檔案重命名後 | -| `mkdir` | 建立目錄後 | -| `rmdir` | 刪除目錄後 | - -### Hook 執行模式 - -- **同步執行** (`execute_sync`): Hook 腳本在 SFTPGo 操作返回客戶端前執行 -- **非同步執行** (預設): Hook 腳本在后台執行,不阻塞客戶端 - -### 重新載入配置 - -修改 Hook 配置後,需重新載入 SFTPGo: -```bash -# 如果是 plist 啟動的服務 -sudo launchctl kickstart -k system/local.sftpgo - -# 或手動重啟 -pkill -f sftpgo -sftpgo serve --config-file /Users/accusys/momentry/etc/sftpgo/sftpgo.json & -``` - -### Hook 故障排除 - -- **檢查 Hook 日誌**: -```bash -tail -f /Users/accusys/sftpgo_test/hook.log -``` - -- **手動測試 Hook 腳本**: -```bash -export SFTPGO_USERNAME=demo -export SFTPGO_FILEPATH="./test.txt" -export SFTPGO_FILESIZE=1024 -export SFTPGO_ACTION=add -/Users/accusys/sftpgo_test/register_hook.sh -``` - -- **SFTPGo 錯誤日誌**: -```bash -tail -20 /Users/accusys/momentry/log/sftpgo.error.log -``` - ---- - -| 資料表 | 用途 | 登入 URL | -|--------|------|----------| -| `admins` | 管理員用戶 | `/web/admin/login` | -| `users` | 檔案傳輸用戶 | `/web/client/login` | - -### Demo 用戶與組設置 - -#### 建立 Demo 目錄 - -```bash -mkdir -p /Users/accusys/sftpgo_test/demo -``` - -#### 創建 Demo 組 - -```bash -TOKEN=$(curl -s -X GET http://localhost:8080/api/v2/token -u "admin:Test3200Test3200" | jq -r '.access_token') -curl -s -X POST http://localhost:8080/api/v2/groups \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "demo", - "description": "Demo group for SFTP uploads" - }' -``` - -#### 創建 Demo 用戶並加入組 - -如果 `demo` 用戶不存在: -```bash -curl -s -X POST http://localhost:8080/api/v2/users \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "username": "demo", - "password": "demopassword123", - "email": "demo@momentry.local", - "status": 1, - "home_dir": "/Users/accusys/sftpgo_test/demo", - "uid": 501, - "gid": 20, - "permissions": { - "/": ["*"] - } - }' -``` - -如果用戶已存在但權限格式錯誤,需修復: -```bash -psql -h 127.0.0.1 -p 5432 -U sftpgo -d sftpgo -c \ - "UPDATE users SET permissions = '{\" /\":[\"*\"]}'::jsonb WHERE username='demo';" -``` - -將用戶加入 `demo` 組 (主要組): -```bash -curl -s -X PUT http://localhost:8080/api/v2/users/demo \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "groups": [ - { - "name": "demo", - "type": 1 - } - ], - "permissions": { - "/": ["*"] - } - }' -``` - -#### 驗證設置 - -```bash -# 檢查用戶 -curl -s -X GET "http://localhost:8080/api/v2/users/demo" \ - -H "Authorization: Bearer $TOKEN" | jq . - -# 檢查組 -curl -s -X GET "http://localhost:8080/api/v2/groups/demo" \ - -H "Authorization: Bearer $TOKEN" | jq . -``` - -#### SFTP 連接測試 - -```bash -# 使用 SFTP 連接 -sshpass -p "demopassword123" sftp -P 2022 demo@localhost - -# 上傳測試文件 -sftp> put test.txt -``` - -#### 預期行為 - -1. 檔案上傳完成後,SFTPGo 觸發 Hook -2. Hook 腳本執行並記錄到 `/Users/accusys/sftpgo_test/hook.log` -3. Hook 調用 Momentry Core API 完成註冊 -4. 查看注册狀態: `tail -f /Users/accusys/sftpgo_test/hook.log` - ---- - -## 常見問題 - -### "無效的憑證" 即使密碼正確 - -- PostgreSQL 中的密碼哈希可能不符合 SFTPGo 預期格式 -- 使用 Web 面板的 **Forgot password** 功能而非直接 SQL 更新 - -### CSRF Token 錯誤 - -- 清除瀏覽器中 `localhost:8080` 的 cookies -- 使用無痕/私密瀏覽視窗 - ---- - -## 端到端測試流程 - -### 1. 準備工作 - -```bash -# 確認 SFTPGo 運行中 -curl http://localhost:8080/healthz - -# 確認 Momentry Core API 運行中 -curl http://localhost:8080/api/v1/health -``` - -### 2. SFTP 上傳測試 - -```bash -# 連接到 SFTPGo -sshpass -p "demopassword123" sftp -P 2022 demo@localhost - -# 上傳測試文件 -sftp> put /path/to/video.mp4 -``` - -### 3. 驗證 Hook 執行 - -```bash -# 查看 Hook 日誌 -tail -f /Users/accusys/sftpgo_test/hook.log - -# 預期看到類似輸出: -# 2026-03-22 01:30:00 - User: demo, File: /Users/accusys/sftpgo_test/demo/video.mp4, Size: 10485760 -# 2026-03-22 01:30:05 - API Response: {"uuid":"abc123","status":"registered"} -``` - -### 4. 檢查 Momentry Core 註冊狀態 - -```bash -# 使用 Momentry CLI 檢查 -/Users/accusys/momentry/target/debug/momentry list --api-key - -# 或直接查詢資料庫 -psql -U accusys -d momentry -c "SELECT uuid, filename, status FROM videos WHERE filename='video.mp4';" -``` - -### 5. 檢查處理狀態 - -```bash -# 查看處理佇列 -curl http://localhost:8080/api/v1/queue - -# 查看 searchable 狀態 -curl "http://localhost:8080/api/v1/searchable?filename=video.mp4&user=demo" -``` - -### 6. 故障排除檢查清單 - -```bash -# 1. SFTPGo 狀態 -ps aux | grep sftpgo -curl http://localhost:8080/healthz - -# 2. Hook 腳本權限 -ls -l /Users/accusys/sftpgo_test/register_hook.sh - -# 3. Hook 日誌 -tail -20 /Users/accusys/sftpgo_test/hook.log - -# 4. Momentry Core 日誌 -tail -20 /Users/accusys/momentry/log/momentry.log - -# 5. SFTPGo 日誌 -tail -20 /Users/accusys/momentry/log/sftpgo.log - -# 6. PostgreSQL 連接 -psql -U sftpgo -d sftpgo -c "SELECT 1;" - -# 7. 端口可用性 -lsof -i :8080 # SFTPGo HTTP -lsof -i :2022 # SFTP -lsof -i :5678 # Momentry Core (Primary) -``` - ---- - -## 故障排除 - -### SFTPGo 無法啟動 - -```bash -# 檢查日誌 -tail -f /Users/accusys/momentry/log/sftpgo.log - -# 驗證配置語法 -sftpgo validate --config /Users/accusys/momentry/etc/sftpgo/sftpgo.json - -# 檢查目錄權限 -ls -la /Users/accusys/momentry/etc/sftpgo/ - -# 重新設定權限 -chown -R $(whoami):staff /Users/accusys/momentry/etc/sftpgo -``` - -### Port 被佔用 - -```bash -# 檢查哪個程序佔用 port -lsof -i :8080 -lsof -i :2022 - -# 終止佔用程序 -kill -``` - -### 需要重新載入 plist - -```bash -# 卸載舊服務 (如果存在) -sudo launchctl unload /Library/LaunchDaemons/com.momentry.sftpgo.plist 2>/dev/null - -# 載入新服務 -sudo launchctl load /Library/LaunchDaemons/com.momentry.sftpgo.plist -``` - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| 安裝 | `/opt/homebrew/opt/sftpgo/` | SFTPGo 安裝目錄 | -| 執行檔 | `/opt/homebrew/opt/sftpgo/bin/sftpgo` | SFTPGo 執行檔 | -| 配置 | `/Users/accusys/momentry/etc/sftpgo/sftpgo.json` | 設定檔 | -| 日誌 | `/Users/accusys/momentry/log/sftpgo.log` | 執行日誌 | -| 錯誤日誌 | `/Users/accusys/momentry/log/sftpgo.error.log` | 錯誤日誌 | -| 工作目錄 | `/Users/accusys/workspace/sftpgo/` | 上傳檔案目錄 | -| plist | `/Library/LaunchDaemons/com.momentry.sftpgo.plist` | 開機啟動 | -| 備份 | `/Users/accusys/momentry/backup/daily/sftpgo/` | 配置與數據庫備份 | -| 備份配置 | `/Users/accusys/momentry/var/sftpgo_backup/` | 實時配置備份 (含 sftpgo.json, sftpgo.db) | -| Hook 腳本 | `/Users/accusys/sftpgo_test/register_hook.sh` | 自動註冊腳本 | -| Hook 日誌 | `/Users/accusys/sftpgo_test/hook.log` | Hook 執行記錄 | -| Demo 目錄 | `/Users/accusys/sftpgo_test/demo` | Demo 用戶首頁目錄 | - ---- - -## 常用指令 - -```bash -# 驗證配置 -sftpgo validate --config /Users/accusys/momentry/etc/sftpgo/sftpgo.json - -# 查看版本 -sftpgo --version - -# 查看可用命令 -sftpgo --help - -# 重載配置 (熱重載) -sftpgo reload --config /Users/accusys/momentry/etc/sftpgo/sftpgo.json -``` - ---- - -## 版本資訊 - -- 版本: 2.7.0 -- HTTP Port: 8080 -- SFTP Port: 2022 -- FTP Port: 21 -- 配置: /Users/accusys/momentry/etc/sftpgo/sftpgo.json -- 工作目錄: /Users/accusys/workspace/sftpgo -- 日誌目錄: /Users/accusys/momentry/log/ diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_WORDPRESS.md b/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_WORDPRESS.md deleted file mode 100644 index 5e69b25..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_INSTALL_WORDPRESS.md +++ /dev/null @@ -1,332 +0,0 @@ -# WordPress 安裝指南 (Portal) - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-22 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode / big-pickle | - ---- - -## 1. 概述 - -本文檔說明 Momentry Portal 的 WordPress 安裝配置,作為系統入口整合 n8n 自動化與 sftpgo 檔案服務。 - ---- - -## 2. 當前狀態 - -| 項目 | 狀態 | -|------|------| -| WordPress 版本 | 6.x | -| URL | https://wp.momentry.ddns.net | -| 安裝路徑 | `/Users/accusys/wordpress/web` | -| 資料庫 | wordpress (MariaDB) | -| 資料庫用戶 | wp_user | - ---- - -## 3. 目錄結構 - -``` -/Users/accusys/wordpress/ -├── web/ # WordPress 主目錄 -│ ├── wp-admin/ # WordPress 管理面板 -│ ├── wp-content/ # 內容目錄 -│ │ ├── ai1wm-backups/ # 備份檔案 (*.wpress) -│ │ ├── languages/ # 語言檔案 -│ │ ├── plugins/ # 插件目錄 -│ │ ├── themes/ # 主題目錄 -│ │ ├── uploads/ # 上傳檔案 -│ │ └── cache/ # 快取目錄 -│ ├── wp-includes/ # WordPress 核心 -│ └── wp-config.php # 配置文件 -├── docker-compose.yml # Docker 配置 -└── wordpress_backup.sql # 資料庫備份 -``` - -### 空間使用 - -| 目錄 | 大小 | 說明 | -|------|------|------| -| `ai1wm-backups/` | ~250MB | 完整備份 (保留 2 個) | -| `plugins/` | 80MB | 插件 | -| `themes/` | 14MB | 主題 | -| `uploads/` | 12MB | 上傳檔案 | - ---- - -## 4. 程式碼位置 - -自訂程式碼存放位置: - -| 類型 | 路徑 | -|------|------| -| 主題 | `/Users/accusys/wordpress/web/wp-content/themes/` | -| 插件 | `/Users/accusys/wordpress/web/wp-content/plugins/` | -| 必須插件 | `/Users/accusys/wordpress/web/wp-content/mu-plugins/` | - ---- - -## 5. 插件清單 - -| 插件 | 用途 | 說明 | -|------|------|------| -| elementor | 頁面建構 | 視覺化頁面編輯器 | -| all-in-one-wp-migration | 網站遷移/備份 | 完整網站備份工具 | -| akismet | 垃圾留言過濾 | 保護留言區域 | -| code-snippets | 自訂程式碼 | 無需修改主題即可添加 PHP | - -### Elementor 版本 -- 版本: 最新穩定版 -- 用途: 頁面建構(開發階段) - -### 未來計畫 -- Phase 2: OpenCode 重構 -- 目標: 交付無 Elementor 依賴版本 - ---- - -## 6. 主題清單 - -| 主題 | 說明 | -|------|------| -| twentytwentyfive | 目前使用主題 | -| twentytwentyfour | 備用 | -| twentytwentythree | 備用 | - ---- - -## 7. 整合計畫 - -### 7.1 n8n 整合 - -n8n 作為自動化引擎,WordPress 頁面透過 REST API 或 Webhook 與 n8n 通訊。 - -| 整合方式 | 說明 | -|----------|------| -| REST API | WordPress 呼叫 n8n API | -| Webhook | n8n 觸發 WordPress 動作 | - -### 7.2 sftpgo 整合 - -sftpgo 作為檔案服務,WordPress 頁面提供檔案上傳/下載功能。 - -| 整合方式 | 說明 | -|----------|------| -| WebDAV | 透過 WebDAV API 操作檔案 | -| REST API | 透過 sftpgo API 操作檔案 | - ---- - -## 8. 管理命令 - -### 8.1 清理 ai1wm 備份 - -```bash -# 查看現有備份 -ls -lt /Users/accusys/wordpress/web/wp-content/ai1wm-backups/*.wpress - -# 保留最近 2 個,刪除舊的 -ls -t /Users/accusys/wordpress/web/wp-content/ai1wm-backups/*.wpress | tail -n +3 | xargs rm - -# 驗證結果 -du -sh /Users/accusys/wordpress/web/wp-content/ai1wm-backups/ -``` - -### 8.2 清理 WordPress 快取 - -```bash -# 刪除 Object Cache -wp cache flush - -# 刪除 Elementor 快取 -wp elementor flush_css - -# 刪除全部快取 -wp cache flush && wp elementor flush_css -``` - -### 8.3 資料庫操作 - -```bash -# 匯出資料庫 -mysqldump -u wp_user -p wordpress > wordpress_backup.sql - -# 匯入資料庫 -mysql -u wp_user -p wordpress < wordpress_backup.sql -``` - -### 8.4 權限檢查 - -```bash -# 檢查目錄權限 -ls -la /Users/accusys/wordpress/web/wp-content/ - -# 確認 wp-content 可寫入 -chown -R _www:_www /Users/accusys/wordpress/web/wp-content/ -chmod -R 755 /Users/accusys/wordpress/web/wp-content/ -``` - ---- - -## 9. 故障排除 - -### 9.1 常見問題 - -| 問題 | 解決方案 | -|------|----------| -| 頁面載入緩慢 | 清理 Elementor/Object Cache | -| 上傳檔案失敗 | 檢查 wp-content/uploads 權限 | -| 502/504 錯誤 | 重啟 PHP-FPM | -| 資料庫連線失敗 | 檢查 wp-config.php 設定 | - -### 9.2 診斷命令 - -```bash -# 檢查 PHP-FPM 狀態 -lsof -i :9000 - -# 檢查 MySQL/MariaDB 狀態 -lsof -i :3306 - -# 檢查 Apache/Nginx 狀態 -lsof -i :80 - -# 查看 WordPress 錯誤日誌 -tail -100 /Users/accusys/momentry/log/php-fpm.log -``` - ---- - -## 10. 開發協作 - -### 10.1 與 marcom 團隊協作 - -| 角色 | 負責 | -|------|------| -| marcom 團隊 | Figma 設計 / Elementor 建構 | -| OpenCode | 程式碼實作 / 重構 | - -### 10.2 開發流程 - -``` -Phase 1: marcom 建構 (現在) -└── Elementor 頁面建構 - -Phase 2: 交付審視 (TBD) -└── 功能確認 / 重構評估 - -Phase 3: OpenCode 重構 (討論後) -└── 純程式碼實作 -└── 交付客戶 (無 Elementor 依賴) -``` - ---- - -## 11. PHP LSP 開發環境 - -### 11.1 軟體需求 - -| 軟體 | 版本 | 安裝方式 | -|------|------|----------| -| PHP | 8.0+ | 已安裝 (8.5.2) | -| Composer | 2.0+ | `brew install composer` | -| phpactor | Latest | PHAR 安裝 | - -### 11.2 安裝步驟 - -#### 1. 安裝 Composer - -```bash -brew install composer -``` - -#### 2. 安裝 phpactor - -```bash -curl -sSL https://github.com/phpactor/phpactor/releases/latest/download/phpactor.phar -o ~/bin/phpactor -chmod +x ~/bin/phpactor -export PATH="$HOME/bin:$PATH" -``` - -#### 3. 安裝 WordPress Stubs - -```bash -cd /Users/accusys/wordpress/web -composer require --dev php-stubs/wordpress-stubs -``` - -#### 4. 設定 phpactor - -```bash -# 設定檔位置 -mkdir -p ~/.config/phpactor - -# 設定內容 -cat > ~/.config/phpactor/phpactor.json << 'EOF' -{ - "core.min_memory_limit": 1610612736, - "worse_reflection.additive_stubs": [ - "/Users/accusys/wordpress/web/vendor/php-stubs/wordpress-stubs/wordpress-stubs.php" - ] -} -EOF -``` - -#### 5. 建立索引 - -```bash -cd /Users/accusys/wordpress/web -~/bin/phpactor index:build --reset -``` - -### 11.3 OpenCode 使用方式 - -```bash -# 確認安裝 -~/bin/phpactor --version - -# 查詢類別 -~/bin/phpactor class:search "WP_User" - -# 查看類別資訊 -~/bin/phpactor index:query WP_User - -# 導航到定義 -~/bin/phpactor navigate /path/to/file.php - -# 查詢參照 -~/bin/phpactor references /path/to/file.php -``` - -### 11.4 常用指令 - -| 指令 | 用途 | -|------|------| -| `phpactor class:search` | 搜尋類別 | -| `phpactor index:query` | 查詢索引 | -| `phpactor index:build` | 建立索引 | -| `phpactor index:clean` | 清除索引 | -| `phpactor config:dump` | 顯示設定 | - ---- - -## 12. 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| WordPress 主目錄 | `/Users/accusys/wordpress/web` | 網站根目錄 | -| 備份目錄 | `/Users/accusys/momentry/backup/wordpress/` | 每日備份 | -| 日誌目錄 | `/Users/accusys/momentry/log/` | PHP/Apache 日誌 | -| phpactor | `~/bin/phpactor` | PHP LSP 主程式 | -| phpactor 設定 | `~/.config/phpactor/phpactor.json` | LSP 設定檔 | -| WordPress Stubs | `/Users/accusys/wordpress/web/vendor/php-stubs/` | WordPress 函數定義 | diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_DEMO.md b/docs_v1.0/IMPLEMENTATION/ROOT_N8N_DEMO.md deleted file mode 100644 index eb7f720..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_DEMO.md +++ /dev/null @@ -1,249 +0,0 @@ -# n8n 整合範例 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-18 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-18 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-25 | 更新API回應格式 (media_url→file_path) 與認證標頭 | OpenCode | deepseek-reasoner | - ---- - -## 基本設定 - -### API 端點 -- **Base URL:** `http://localhost:3002/api/v1` -- **Method:** `POST` -- **Content-Type:** `application/json` -- **Authentication:** `X-API-Key: YOUR_API_KEY` (所有 `/api/v1/*` 端點皆需要) - ---- - -## Workflow 1: 基礎搜尋 - -### Trigger: Manual / Webhook - -``` -[Manual Trigger] - ↓ -[HTTP Request] → POST http://localhost:3002/api/v1/search - ↓ -[Set] → 設定搜尋詞 "charade" - ↓ -[Code] → 處理回傳結果 - ↓ -[Respond] -``` - -### HTTP Request 設定 -```json -{ - "url": "http://localhost:3002/api/v1/search", - "method": "POST", - "body": { - "query": "={{ $json.searchTerm }}", - "limit": 5 - }, - "options": { - "headers": { - "Content-Type": "application/json", - "X-API-Key": "YOUR_API_KEY" - } - } -} -``` - -### Code (處理結果) -```javascript -const results = $input.first().json.results; - -const videoUrl = "https://wp.momentry.ddns.net/Old_Time_Movie_Show_-_Charade_1963.HD.mov"; - -return results.map(r => ({ - chunk_id: r.chunk_id, - text: r.text, - start: r.start_time, - end: r.end_time, - score: r.score, - video_url: `${videoUrl}#t=${r.start_time},${r.end_time}` -})); -``` - ---- - -## Workflow 2: n8n 專用格式 - -使用 `/n8n/search` 端點(已包含 file_path) - -### HTTP Request -```json -{ - "url": "http://localhost:3002/api/v1/n8n/search", - "method": "POST", - "body": { - "query": "={{ $json.searchTerm }}", - "limit": 5 - }, - "options": { - "headers": { - "Content-Type": "application/json", - "X-API-Key": "YOUR_API_KEY" - } - } -} -``` - -### 回傳格式 -```json -{ - "query": "charade", - "count": 5, - "hits": [ - { - "id": "sentence_0006", - "vid": "a1b10138a6bbb0cd", - "start": 48.8, - "end": 55.44, - "title": "Chunk sentence_0006", - "text": "fun plot twists...", - "score": 0.526, - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4" - } - ] -} -``` - -> **注意**: API 現在返回 `file_path`(檔案系統路徑)而非 `media_url`(網頁 URL)。如需在網頁中播放影片,請將檔案路徑轉換為可訪問的 URL(例如透過 SFTPGo 分享連結)。 - ---- - -## Workflow 3: 訊息機器人整合 - -### Telegram Bot 範例 - -``` -[Webhook: Telegram] - ↓ -[Extract: /search charade] - ↓ -[HTTP Request] → POST /api/v1/search - ↓ -[Format Response] - ↓ -[Telegram: Send Message] -``` - -### 回傳格式 -``` -🎬 搜尋結果: "charade" - -1. "fun plot twists, Woody Dialog and charming performances..." - ⏱ 48.8s - 55.4s - 📊 分數: 0.526 - -2. "Don't you like me to say that a pretty girl..." - ⏱ 4745.6s - 4748.6s - 📊 分數: 0.525 -``` - ---- - -## Workflow 4: 多影片搜尋 - -### 取得所有影片 -``` -[HTTP Request] -GET http://localhost:3002/api/v1/videos -``` - -### 依 UUID 篩選 -```json -{ - "query": "charade", - "limit": 5, - "uuid": "a1b10138a6bbb0cd" -} -``` - ---- - -## Workflow 5: 定時更新 - -``` -[Cron: 每小時] - ↓ -[HTTP Request] → GET /api/v1/videos - ↓ -[Loop Over Items] - ↓ -[Check: 新影片?] - ↓ -[Process: 執行 vectorize] -``` - ---- - -## 實用場景 - -### 1. 客服機器人 -用戶問「這部片在哪一段有談到 charade?」 -→ 搜尋 API → 回傳時戳 → 直接播放該片段 - -### 2. 內容推薦 -根據用戶輸入的關鍵字,找到相關影片片段 - -### 3. 自動化剪輯 -搜尋多個片段 → 組合成精華影片 - ---- - -## 錯誤處理 - -```javascript -const response = $input.first(); - -if (!response.json.results || response.json.results.length === 0) { - return { - success: false, - message: "找不到相關結果" - }; -} - -return { - success: true, - count: response.json.results.length, - data: response.json.results -}; -``` - ---- - -## 測試用 cURL - -```bash -# 基本搜尋 -curl -X POST http://localhost:3002/api/v1/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 3}' - -# n8n 格式 -curl -X POST http://localhost:3002/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 3}' - -# 取得影片列表 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos - -# 取得特定影片的區塊 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos/a1b10138a6bbb0cd/chunks -``` diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_DEMO_EXECUTION_LOG.md b/docs_v1.0/IMPLEMENTATION/ROOT_N8N_DEMO_EXECUTION_LOG.md deleted file mode 100644 index 81838ae..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_DEMO_EXECUTION_LOG.md +++ /dev/null @@ -1,355 +0,0 @@ -# n8n Video RAG Demo - API 執行記錄 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-22 | -| 文件版本 | V1.1 | -| 目標 | 完整執行 n8n Video RAG Workflow 並記錄所有 API 呼叫 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode | -| V1.1 | 2026-03-26 | 更新 API 範例,新增 X-API-Key 驗證標頭 | OpenCode | deepseek-reasoner | - ---- - -## Phase 1: SFTPGo 準備 - -### Step 1.1: 取得 Demo User Token - -**API 呼叫:** -```bash -curl -X GET "http://localhost:8080/api/v2/user/token" \ - -u "demo:demopassword123" -``` - -**Request:** -``` -GET /api/v2/user/token -Authorization: Basic ZG9tbzpkZW1vcGFzc3dvcmQxMjM= -``` - -**Response (200 OK):** -```json -{ - "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "expires_at": "2026-03-22T07:05:57Z" -} -``` - -**Token 有效期限:** 20 分鐘 - -**Session Token (Demo User):** -``` -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiQVBJVXNlciIsIjo6MSJdLCJleHAiOjE3NzQxNjMxNTcsImlhdCI6MTc3NDE2MTk1NywianRpIjoiZDZ2cDA5YWcyZnIwMnY3aTlybDAiLCJuYmYiOjE3NzQxNjE5NDcsInN1YiI6IjE3NzQxNjE5NTM0OTMiLCJ1c2VybmFtZSI6ImRlbW8ifQ.yw0UCv8sQXXCkOr7qmK2ejLzuoA8IDrmC9bpgFE4R_Q -``` - -**結果:** ✅ 成功 - ---- - -### Step 1.2: 上傳測試影片到 SFTPGo - -**影片選擇:** `Old_Time_Movie_Show_-_Charade_1963.HD.mov` (2.3 GB) -- 路徑: `/Users/accusys/test_video/Old_Time_Movie_Show_-_Charade_1963.HD.mov` -- ASR Segments: 1,917 (已預處理) - -**API 呼叫:** -```bash -TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." -curl -X POST "http://localhost:8080/api/v2/user/files" \ - -H "Authorization: Bearer $TOKEN" \ - -F "path=/demo" \ - -F "mkdir_parents=true" \ - -F "filenames=@/Users/accusys/test_video/Old_Time_Movie_Show_-_Charade_1963.HD.mov" -``` - -**Request:** -``` -POST /api/v2/user/files -Authorization: Bearer -Content-Type: multipart/form-data - -path: /demo -mkdir_parents: true -filenames: @/path/to/Old_Time_Movie_Show_-_Charade_1963.HD.mov -``` - -**Response (201 Created):** -```json -{"message":"Upload completed"} -``` - -**上傳統計:** -- 檔案大小: 2,361,629,896 bytes (2.3 GB) -- 上傳時間: 7 秒 -- 平均速度: ~337 MB/s - -**結果:** ✅ 成功 - ---- - -### Step 1.3: 建立分享連結 - -**API 呼叫:** -```bash -curl -X POST "http://localhost:8080/api/v2/user/shares" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "Charade_1963_Demo", - "paths": ["/Old_Time_Movie_Show_-_Charade_1963.HD.mov"], - "scope": 1, - "expires_at": 0 - }' -``` - -**Request:** -```json -POST /api/v2/user/shares -Authorization: Bearer -Content-Type: application/json - -{ - "name": "Charade_1963_Demo", - "paths": ["/Old_Time_Movie_Show_-_Charade_1963.HD.mov"], - "scope": 1, - "expires_at": 0 -} -``` - -**Response (200 OK):** -```json -{"message":"Share created"} -``` - -**結果:** ✅ 成功 - ---- - -### Step 1.4: 驗證上傳結果 - -**API 呼叫 - 列出分享:** -```bash -curl -X GET "http://localhost:8080/api/v2/user/shares" \ - -H "Authorization: Bearer $TOKEN" -``` - -**Response:** -```json -[ - { - "id": "CjmQfrkXY5qDtC46WVZY2S", - "name": "Charade_1963_Demo", - "scope": 1, - "paths": [ - "/Old_Time_Movie_Show_-_Charade_1963.HD.mov" - ], - "username": "demo", - "created_at": 1774162072853, - "updated_at": 1774162072853, - "password": "" - } -] -``` - -**分享連結:** -- Share ID: `CjmQfrkXY5qDtC46WVZY2S` -- Browse URL: `http://localhost:8080/web/client/pubshares/CjmQfrkXY5qDtC46WVZY2S/browse` - -**本地目錄驗證:** -``` -/Users/accusys/sftpgo_test/demo/ -└── Old_Time_Movie_Show_-_Charade_1963.HD.mov (2,361,629,896 bytes) -``` - -**結果:** ✅ 成功 - ---- - -## Phase 2: Momentry 註冊 - -### Step 2.1: 健康檢查 - -**API 呼叫:** -```bash -curl -X GET "http://localhost:3002/health" -``` - -**Response:** -``` -(待填寫) -``` - ---- - -### Step 2.2: 註冊影片 - -**API 呼叫:** -```bash -curl -X POST "http://localhost:3002/api/v1/register" \ - -H "Content-Type: application/json" \ - -d '{ - "path": "/Users/accusys/sftpgo_test/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov" - }' -``` - -**Request:** -```json -POST /api/v1/register -Content-Type: application/json - -{ - "path": "/Users/accusys/sftpgo_test/demo/Old_Time_Movie_Show_-_Charade_1963.HD.mov" -} -``` - -**Response:** -``` -(待填寫) -{ - "uuid": "...", - "video_id": ..., - "file_name": "...", - "duration": ..., - "width": ..., - "height": ... -} -``` - ---- - -## Phase 3: 處理進度追蹤 - -### Step 3.1: 查詢處理進度 (新版 API) - -**API 呼叫:** -```bash -curl -X GET "http://localhost:3002/api/v1/progress/{uuid}" -``` - -**Response (新版 - 包含影片資訊與系統資源):** -```json -{ - "uuid": "a1b10138a6bbb0cd", - "user": null, - "group": null, - "file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov", - "duration": 6879.33, - "overall_progress": 28, - "cpu_percent": 3.7, - "gpu_percent": null, - "memory_percent": 0.1, - "memory_mb": 19328, - "processors": [ - {"name": "asr", "status": "complete", "current": 1867, "total": 0, "progress": 100, "message": "1867 segments"}, - {"name": "cut", "status": "complete", "current": 1331, "total": 1331, "progress": 100, "message": "1331 scenes"}, - {"name": "asrx", "status": "error", "current": 0, "total": 0, "progress": 0, "message": "0 segments"}, - {"name": "yolo", "status": "progress", "current": 69400, "total": 412343, "progress": 16, "message": "frame 69400"}, - {"name": "ocr", "status": "pending", "current": 0, "total": 0, "progress": 0, "message": ""}, - {"name": "face", "status": "pending", "current": 0, "total": 0, "progress": 0, "message": ""}, - {"name": "pose", "status": "pending", "current": 0, "total": 0, "progress": 0, "message": ""} - ] -} -``` - -**欄位說明:** -| 欄位 | 說明 | -|------|------| -| uuid | 影片唯一識別碼 | -| user | 處理所屬用戶 (如已設定) | -| group | 處理所屬群組 (如已設定) | -| file_name | 影片檔案名稱 | -| duration | 影片時長 (秒) | -| overall_progress | 整體進度 (百分比) | -| cpu_percent | CPU 使用率 (%) | -| gpu_percent | GPU 使用率 (%),無 GPU 則為 null | -| memory_percent | 記憶體使用率 (%) | -| memory_mb | 記憶體使用量 (MB) | -| processors | 各處理器狀態陣列 | -``` - ---- - -## Phase 4: 自然語言檢索 - -### Step 4.1: RAG 搜尋 - -**API 呼叫:** -```bash -curl -X POST "http://localhost:3002/api/v1/search" \ - -H "Content-Type: application/json" \ - -d '{ - "query": "What is the movie about?", - "limit": 10, - "uuid": "..." - }' -``` - -**Request:** -```json -POST /api/v1/search -Content-Type: application/json - -{ - "query": "What is the movie about?", - "limit": 10, - "uuid": "" -} -``` - -**Response:** -``` -(待填寫) -``` - ---- - -### Step 4.2: n8n 搜尋 (含 file_path) - -**API 呼叫:** -```bash -curl -X POST "http://localhost:3002/api/v1/n8n/search" \ - -H "Content-Type: application/json" \ - -H "X-API-Key: demo_api_key_12345" \ - -d '{ - "query": "What is the movie about?", - "limit": 10, - "uuid": "..." - }' -``` - -**Response:** -``` -(待填寫) -``` - ---- - -## 憑證彙整 - -| 服務 | 項目 | 值 | -|------|------|------| -| SFTPGo | API Base | `http://localhost:8080/api/v2` | -| SFTPGo | Demo User | `demo` | -| SFTPGo | Demo Password | `demopassword123` (已重設) | -| SFTPGo | Demo Home | `/Users/accusys/sftpgo_test/demo` | -| SFTPGo | Token Endpoint | `/api/v2/user/token` | -| SFTPGo | Share ID | `CjmQfrkXY5qDtC46WVZY2S` | -| Momentry | Server | `http://localhost:3002` | -| Momentry | MEDIA_BASE_URL | `https://wp.momentry.ddns.net` | - ---- - -## 版本歷史 - -| 日期 | 版本 | 變更 | -|------|------|------| -| 2026-03-22 | v1.0 | 初始建立文件 | -| 2026-03-22 | v1.1 | 成功取得 Demo Token | -| 2026-03-22 | v1.2 | Phase 1 完成 (上傳 Charade 2.3GB) | diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_HTTP_REQUEST_GUIDE.md b/docs_v1.0/IMPLEMENTATION/ROOT_N8N_HTTP_REQUEST_GUIDE.md deleted file mode 100644 index 74cf856..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_HTTP_REQUEST_GUIDE.md +++ /dev/null @@ -1,269 +0,0 @@ -# n8n HTTP Request Node 設定指南 - -| 項目 | 內容 | -|------|------| -| 建立者 | OpenCode | -| 建立時間 | 2026-03-26 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-23 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-26 | 新增 API Key 驗證說明,更新 curl 範例 | OpenCode | deepseek-reasoner | - ---- - -> **API URL 說明**: -> - **本地測試**: `http://localhost:3002` -> - **n8n workflow**: `https://api.momentry.ddns.net` -> -> ⚠️ 在 n8n 中請使用 `api.momentry.ddns.net`,不要使用 `localhost:3002` - ---- - -## 錯誤排除 - -### 錯誤訊息: "Your request is invalid or could not be processed by the service" - -這通常表示 HTTP Request Node 的設定不正確。 - ---- - -## 正確的 Node 設定方式 - -### 方法 1: 使用 JSON Body (推薦) - -``` -Node: HTTP Request -├── URL: https://api.momentry.ddns.net/api/v1/n8n/search -├── Method: POST -├── Authentication: None -├── Send Body: ✓ (checked) -├── Content Type: JSON -├── Body: -│ { -│ "query": "={{ $json.query }}", -│ "limit": "={{ $json.limit }}" -│ } -├── Send Headers: ✓ (checked) -└── Header Parameters: - └── X-API-Key: {{ $env.MOMENTRY_API_KEY }} -``` - -### 方法 2: 使用 Raw Body + Headers - -``` -Node: HTTP Request -├── URL: https://api.momentry.ddns.net/api/v1/n8n/search -├── Method: POST -├── Authentication: None -├── Send Body: ✓ (checked) -├── Specify Body: Using JSON -├── JSON Body: -│ { -│ "query": "charade", -│ "limit": 3 -│ } -├── Send Headers: ✓ (checked) -└── Header Parameters: - ├── Content-Type: application/json - └── X-API-Key: {{ $env.MOMENTRY_API_KEY }} -``` - -### 方法 3: 最簡單的 Hardcoded 測試 - -``` -Node: HTTP Request -├── URL: https://api.momentry.ddns.net/api/v1/n8n/search -├── Method: POST -├── Send Body: ✓ -├── Content Type: JSON -└── Body: - { - "query": "charade", - "limit": 3 - } -``` - ---- - -## 常見錯誤與解決 - -### ❌ 錯誤 1: Body 格式錯誤 - -**錯誤設定:** -``` -Body Parameters: - query = {{ $json.query }} - limit = {{ $json.limit }} -``` - -**正確設定:** -``` -Content Type: JSON -Body: -{ - "query": "={{ $json.query }}", - "limit": "={{ $json.limit }}" -} -``` - -### ❌ 錯誤 2: 缺少引號 - -**錯誤:** -```json -{ - query: "charade", - limit: 3 -} -``` - -**正確:** -```json -{ - "query": "charade", - "limit": 3 -} -``` - -### ❌ 錯誤 3: URL 錯誤 - -**錯誤:** -``` -URL: http://localhost:3002/api/v1/n8n/search -``` - -**正確:** -``` -URL: https://api.momentry.ddns.net/api/v1/n8n/search -``` - ---- - -## 測試步驟 - -### 步驟 1: 創建最簡單的測試 - -1. 新建工作流程 -2. 添加 **Manual Trigger** Node -3. 添加 **HTTP Request** Node -4. 設定如下: - - URL: `https://api.momentry.ddns.net/api/v1/n8n/search` - - Method: POST - - Send Body: ✓ - - Content Type: JSON - - Body: `{"query": "charade", "limit": 2}` - -### 步驟 2: 執行測試 - -1. 點擊 **Execute Workflow** -2. 查看 HTTP Request Node 的輸出 -3. 應該看到 JSON 回應 - -### 步驟 3: 確認成功 - -成功的回應應該包含: -```json -{ - "query": "charade", - "count": 2, - "hits": [...] -} -``` - ---- - -## 直接複製使用的工作流程 JSON - -```json -{ - "name": "Video Search - Working Example", - "nodes": [ - { - "parameters": {}, - "name": "When clicking \"Execute Workflow\"", - "type": "n8n-nodes-base.manualTrigger", - "typeVersion": 1, - "position": [250, 300] - }, - { - "parameters": { - "url": "https://api.momentry.ddns.net/api/v1/n8n/search", - "method": "POST", - "sendBody": true, - "contentType": "json", - "body": { - "query": "charade", - "limit": 3 - }, - "options": {} - }, - "name": "Search Video API", - "type": "n8n-nodes-base.httpRequest", - "typeVersion": 4.1, - "position": [450, 300] - } - ], - "connections": { - "When clicking \"Execute Workflow\"": { - "main": [ - [ - { - "node": "Search Video API", - "type": "main", - "index": 0 - } - ] - ] - } - }, - "settings": { - "executionOrder": "v1" - } -} -``` - -**導入方式:** -1. 在 n8n UI 中,點擊左上角的 Menu -2. 選擇 **Import from File** -3. 選擇上面的 JSON 文件 - ---- - -## 驗證 API 可用性 - -在終端機測試: -```bash -# 需要 API Key 驗證 (設定環境變數或直接替換) -export MOMENTRY_API_KEY="muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69" - -curl -X POST https://api.momentry.ddns.net/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: $MOMENTRY_API_KEY" \ - -d '{"query":"charade","limit":2}' -``` - -如果 curl 成功但 n8n 失敗,問題在於 n8n HTTP Request Node 的設定。 - ---- - -## 需要幫助? - -如果仍然無法工作: -1. 開啟工作流程 -2. 點擊 HTTP Request Node -3. 點擊右上角的 **Execute Node** 單獨執行 -4. 查看錯誤訊息的詳細內容 -5. 檢查 Network tab 中的 request/response - ---- - -## 相關文件 - -- [API_INDEX.md](./API_INDEX.md) - 文件總覽(起點) -- [API_N8N_GUIDE.md](./API_N8N_GUIDE.md) - n8n 快速使用指南 -- [API_ENDPOINTS.md](./API_ENDPOINTS.md) - 端點完整說明 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_INTEGRATION_GUIDE.md b/docs_v1.0/IMPLEMENTATION/ROOT_N8N_INTEGRATION_GUIDE.md deleted file mode 100644 index 241def5..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_INTEGRATION_GUIDE.md +++ /dev/null @@ -1,575 +0,0 @@ -# Momentry n8n 整合使用手冊 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-23 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-22 | 創建 n8n 整合手冊 | Warren | OpenCode | -| V1.1 | 2026-03-23 | 新增 API Key 驗證與完整工作流範例 | Warren | OpenCode | - ---- - -**目標讀者**: n8n 使用者、DevOps - ---- - -## 目錄 - -1. [概述](#1-概述) -2. [前置作業](#2-前置作業) -3. [建立 n8n API Key](#3-建立-n8n-api-key) -4. [在 n8n 中使用 Momentry API](#4-在-n8n-中使用-momentry-api) -5. [工作流範例](#5-工作流範例) -6. [常見問題](#6-常見問題) - ---- - -## 1. 概述 - -### 1.1 什麼是 n8n? - -n8n 是一個開源的工作流自動化工具,可以連接各種服務和 API。 - -### 1.2 為什麼需要整合? - -| 場景 | 說明 | -|------|------| -| 自動化影片處理 | 新影片上傳時自動觸發處理流程 | -| 監控告警 | API Key 異常時發送通知 | -| 定時備份 | 定期備份 API Key 資料 | -| 跨系統同步 | 與其他系統同步 API Key 狀態 | - -### 1.3 架構圖 - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ 觸發器 │────▶│ n8n 工作流 │────▶│ Momentry │ -│ (Webhook/ │ │ (處理邏輯) │ │ API │ -│ Cron) │ └─────────────┘ └─────────────┘ -└─────────────┘ │ │ - │ │ - ▼ ▼ - ┌─────────────┐ ┌─────────────┐ - │ 通知 │ │ 動作 │ - │ (Slack/Email)│ │ (建立/查詢) │ - └─────────────┘ └─────────────┘ -``` - ---- - -### 1.4 API URL 選擇 - -| 環境 | URL | 說明 | -|------|-----|------| -| **本地測試** | `http://localhost:3002` | 直接訪問 API | -| **n8n workflow** | `https://api.momentry.ddns.net` | 通過反向代理 | - -> ⚠️ **重要**: 在 n8n HTTP Request Node 中,請使用 `https://api.momentry.ddns.net` 而非 `localhost:3002`,因為 n8n 需要從外部訪問 API。 - -**本地測試時**: -```bash -curl http://localhost:3002/health -``` - -**n8n Workflow 中**: -``` -URL: https://api.momentry.ddns.net/api/v1/n8n/search -``` - ---- - -## 2. 前置作業 - -### 2.1 確認服務狀態 - -```bash -# 檢查 Momentry API -curl http://localhost:3002/health - -# 檢查 n8n -curl https://n8n.momentry.ddns.net/api/v1/workflows \ - -H "X-N8N-API-KEY: your-api-key" -``` - -### 2.2 取得 n8n API Key - -#### 方式 A: 透過 Momentry CLI - -```bash -# 建立 n8n API Key -momentry n8n create \ - --api-key "your-existing-n8n-api-key" \ - --label "momentry-integration" \ - --expires-in-days 90 - -# 輸出: -# ✅ n8n API Key created successfully! -# API Key: eyJhbGciOiJIUzI1NiIs... -``` - -#### 方式 B: 透過 n8n 介面 - -1. 登入 n8n: https://n8n.momentry.ddns.net -2. 前往 Settings → n8n API -3. 點擊「Create an API Key」 -4. 複製 API Key - -### 2.3 設定環境變數 - -在 n8n 中設定以下環境變數: - -| 變數名稱 | 值 | 說明 | -|----------|-----|------| -| `MOMENTRY_API_URL` | `http://localhost:3002` | Momentry API URL | -| `MOMENTRY_API_KEY` | `your-api-key` | Momentry API Key | - ---- - -## 3. 建立 n8n API Key - -### 3.1 CLI 命令 - -```bash -# 基本建立 -momentry n8n create \ - --api-key \ - --label - -# 設定過期時間 -momentry n8n create \ - --api-key \ - --label "ci-pipeline" \ - --expires-in-days 30 -``` - -### 3.2 範例:建立監控用 Key - -```bash -momentry n8n create \ - --api-key "n8n_api_1234567890" \ - --label "monitoring-key" \ - --expires-in-days 180 - -# 輸出: -# ✅ n8n API Key created successfully! -# Key ID: abc123-def456 -# Label: monitoring-key -# API Key: eyJhbGciOiJIUz... -``` - -### 3.3 列出已建立的 Key - -```bash -momentry n8n list --api-key - -# 輸出: -# 📋 n8n API Keys -# ┌────────────────────────────────────────────────────────────────────────────┐ -# │ Label │ ID │ -# ├────────────────────────────────────────────────────────────────────────────┤ -# │ monitoring-key │ abc123-def456 │ -# │ ci-pipeline │ xyz789-abc123 │ -# └────────────────────────────────────────────────────────────────────────────┘ -``` - ---- - -## 4. 在 n8n 中使用 Momentry API - -> ⚠️ **注意**: API Key 管理端點 (`/api/v1/api-keys/*`) 目前仍在規劃中,尚未實作。以下為規劃中的 API 說明。 - -### 4.1 設定 HTTP Request 節點 - -``` -Method: POST -URL: {{ $env.MOMENTRY_API_URL }}/api/v1/api-keys -Headers: - X-API-Key: {{ $env.MOMENTRY_API_KEY }} - Content-Type: application/json -Body: - { - "name": "auto-generated-key", - "key_type": "service", - "ttl_days": 90 - } -``` - -### 4.2 可用的 API 端點 - -> ⚠️ **API Key 管理端點為規劃功能,目前尚未實作** - -#### 已實作端點 - -| 方法 | 端點 | 說明 | -|------|------|------| -| GET | `/health` | 健康檢查 | -| POST | `/api/v1/search` | 語意搜尋 | -| POST | `/api/v1/n8n/search` | n8n 格式搜尋 | -| GET | `/api/v1/videos` | 列出所有影片 | -| GET | `/api/v1/lookup` | 查詢影片 | -| GET | `/api/v1/progress/:uuid` | 處理進度 | - -#### 規劃中端點 *(尚未實作)* - -| 方法 | 端點 | 說明 | -|------|------|------| -| GET | `/api/v1/api-keys` | 列出所有 API Keys | -| POST | `/api/v1/api-keys` | 建立新的 API Key | -| DELETE | `/api/v1/api-keys/{id}` | 刪除 API Key | -| POST | `/api/v1/api-keys/{id}/rotate` | 請求 Key 輪換 | - ---- - -## 5. 工作流範例 - -### 範例 1:定時檢查 API Key 狀態 - -**目的**: 每天早上 9 點檢查即將過期的 API Keys - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ Schedule │────▶│ HTTP │────▶│ Filter │────▶│ Slack │ -│ (每天 9AM) │ │ Request │ │ (7天內過期) │ │ 通知 │ -└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ -``` - -**HTTP Request 設定**: - -```json -{ - "method": "GET", - "url": "{{ $env.MOMENTRY_API_URL }}/api/v1/api-keys", - "headers": { - "X-API-Key": "{{ $env.MOMENTRY_API_KEY }}" - } -} -``` - -**Filter 設定**: - -```javascript -// 檢查是否在 7 天內過期 -const expiresAt = new Date($json.expires_at); -const now = new Date(); -const sevenDaysLater = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); - -return expiresAt <= sevenDaysLater && expiresAt > now; -``` - -**Slack 通知格式**: - -``` -⚠️ API Key 即將過期提醒 - -以下 API Key 將在 7 天內過期: -{{ $json.map(k => `• ${k.name} (${k.key_id}) - 過期時間: ${k.expires_at}`).join('\n') }} - -請及時處理! -``` - ---- - -### 範例 2:新影片上傳時自動建立 API Key - -**目的**: 當有新影片上傳時,自動為該影片建立專用 API Key - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ Webhook │────▶│ HTTP │────▶│ Set │────▶│ Respond │ -│ 觸發器 │ │ Request │ │ (組裝回應) │ │ Webhook │ -└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ -``` - -**Webhook 設定**: - -``` -Method: POST -Path: /new-video -``` - -**HTTP Request 設定**: - -```json -{ - "method": "POST", - "url": "{{ $env.MOMENTRY_API_URL }}/api/v1/api-keys", - "headers": { - "X-API-Key": "{{ $env.MOMENTRY_API_KEY }}" - }, - "body": { - "name": "video-{{ $json.video_id }}", - "key_type": "service", - "permissions": ["read"], - "ttl_days": 30 - } -} -``` - -**回應格式**: - -```json -{ - "success": true, - "video_id": "{{ $json.video_id }}", - "api_key_id": "{{ $json.key_id }}", - "message": "API Key 已建立" -} -``` - ---- - -### 範例 3:API Key 異常告警 - -**目的**: 監控 API Key 異常使用,發送告警通知 - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ Webhook │────▶│ Switch │────▶│ Email │ │ Slack │ -│ (異常通知) │ │ (嚴重程度) │────▶│ 通知 │ │ 通知 │ -└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ -``` - -**Webhook 觸發設定** (在 Momentry 中): - -```bash -export WEBHOOK_URL="https://n8n.momentry.ddns.net/webhook/anomaly-alert" -export WEBHOOK_EVENTS="anomaly_detected,rate_limited,ip_blocked" -``` - -**Switch 節點設定**: - -```javascript -// 根據嚴重程度分流 -switch ($json.data.severity) { - case 'critical': - return 0; // Email + Slack - case 'high': - return 1; // Slack only - default: - return 2; // Log only -} -``` - -**Email 通知格式**: - -``` -Subject: [{{ $json.data.severity }}] API Key 異常告警 - {{ $json.data.key_id }} - -Dear Admin, - -偵測到 API Key 異常使用: - -Key ID: {{ $json.data.key_id }} -異常類型: {{ $json.data.anomaly_type }} -嚴重程度: {{ $json.data.severity }} -時間: {{ $json.timestamp }} - -請立即檢查系統狀態。 - -Best regards, -Momentry Monitoring -``` - ---- - -### 範例 4:定時備份 API Key 統計 - -**目的**: 每週一早上備份 API Key 統計報表 - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ Schedule │────▶│ HTTP │────▶│ Google │ -│ (每週一) │ │ Request │ │ Sheets │ -└─────────────┘ └─────────────┘ └─────────────┘ -``` - -**HTTP Request 設定**: - -```json -{ - "method": "GET", - "url": "{{ $env.MOMENTRY_API_URL }}/api/v1/api-keys/stats", - "headers": { - "X-API-Key": "{{ $env.MOMENTRY_API_KEY }}" - } -} -``` - -**Google Sheets 設定**: - -``` -Spreadsheet: Momentry API Key Reports -Sheet: Weekly Stats -Append Row: - - Date: {{ $now }} - - Total Keys: {{ $json.total_keys }} - - Active Keys: {{ $json.active_keys }} - - Expired Keys: {{ $json.expired_keys }} - - Anomalies (24h): {{ $json.anomalies_last_24h }} -``` - ---- - -### 範例 5:自動輪換即將過期的 Key - -**目的**: 自動為即將過期的 Key 請求輪換 - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ Schedule │────▶│ HTTP │────▶│ Filter │────▶│ HTTP │ -│ (每天) │ │ (取得 Keys) │ │ (即將過期) │ │ (請求輪換) │ -└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ -``` - -**第一個 HTTP Request (取得 Keys)**: - -```json -{ - "method": "GET", - "url": "{{ $env.MOMENTRY_API_URL }}/api/v1/api-keys", - "headers": { - "X-API-Key": "{{ $env.MOMENTRY_API_KEY }}" - } -} -``` - -**Filter 設定**: - -```javascript -// 14 天內過期且未請求輪換的 Key -const expiresAt = new Date($json.expires_at); -const now = new Date(); -const fourteenDaysLater = new Date(now.getTime() + 14 * 24 * 60 * 60 * 1000); - -return expiresAt <= fourteenDaysLater && - !$json.rotation_required && - $json.status === 'active'; -``` - -**第二個 HTTP Request (請求輪換)**: - -```json -{ - "method": "POST", - "url": "{{ $env.MOMENTRY_API_URL }}/api/v1/api-keys/{{ $json.key_id }}/rotate", - "headers": { - "X-API-Key": "{{ $env.MOMENTRY_API_KEY }}" - }, - "body": { - "reason": "auto_rotation_approaching_expiry" - } -} -``` - ---- - -## 6. 常見問題 - -### Q1: n8n 無法連接到 Momentry API - -**檢查項目**: - -```bash -# 1. 確認 API 是否運行 -curl http://localhost:3002/health - -# 2. 確認 API Key 是否有效 -momentry api-key validate --key "your-key" - -# 3. 檢查防火牆設定 -nc -zv localhost 3002 -``` - -### Q2: API Key 建立失敗 - -**可能原因**: -- API Key 已存在 -- 權限不足 -- 格式錯誤 - -**解決方式**: - -```bash -# 檢查現有 Keys -momentry api-key list - -# 使用不同的 label -momentry n8n create --api-key "..." --label "unique-label-$(date +%s)" -``` - -### Q3: Webhook 通知沒有收到 - -**檢查項目**: - -```bash -# 1. 確認 Webhook URL 設定 -echo $WEBHOOK_URL - -# 2. 測試 Webhook -curl -X POST $WEBHOOK_URL \ - -H "Content-Type: application/json" \ - -d '{"test": true}' - -# 3. 檢查 n8n 工作流是否啟用 -# 登入 n8n → 檢查工作流狀態 -``` - -### Q4: 如何撤銷 n8n API Key - -```bash -# 列出所有 Keys -momentry n8n list --api-key "your-admin-key" - -# 刪除指定 Key -momentry n8n delete \ - --api-key "your-admin-key" \ - --label "key-to-delete" -``` - ---- - -## 附錄 - -### A. n8n 工作流匯出 - -將上述範例工作流匯入 n8n: - -1. 複製工作流 JSON -2. 登入 n8n -3. 點擊「+」→「Import from File」 -4. 貼上 JSON 並儲存 - -### B. 環境變數總覽 - -```bash -# Momentry -MOMENTRY_API_URL=http://localhost:3002 -MOMENTRY_API_KEY=your-api-key - -# n8n -N8N_URL=https://n8n.momentry.ddns.net -N8N_API_KEY=your-n8n-api-key - -# Webhook -WEBHOOK_URL=https://n8n.momentry.ddns.net/webhook/alerts -WEBHOOK_SECRET=your-secret -WEBHOOK_EVENTS=anomaly_detected,key_expired,key_revoked -``` - -### C. 相關文件 - -| 文件 | 說明 | -|------|------| -| [API_INDEX.md](./API_INDEX.md) | 文件總覽(起點) | -| [API_N8N_GUIDE.md](./API_N8N_GUIDE.md) | n8n 快速使用指南 | -| `docs/API_KEY_MANAGEMENT.md` | API Key 管理系統設計 | -| `docs/API_KEY_ARCHITECTURE.md` | 系統架構圖 | -| `docs/API_KEY_INTEGRATION_TESTS.md` | 整合測試文件 | diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_MCP_SETUP.md b/docs_v1.0/IMPLEMENTATION/ROOT_N8N_MCP_SETUP.md deleted file mode 100644 index d00670d..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_MCP_SETUP.md +++ /dev/null @@ -1,227 +0,0 @@ -# OpenCode n8n MCP 整合設定 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-23 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-23 | 創建 n8n MCP 整合設定文件 | Warren | OpenCode | - ---- - -> 建立時間: 2026-03-23 -> 更新時間: 2026-03-23 - ---- - -## n8n MCP 工具列表 (43 個) - -### Workflows (10) -| 工具 | 說明 | -|------|------| -| `n8n_list_workflows` | 列出所有 workflows | -| `n8n_get_workflow` | 取得 workflow 詳情 | -| `n8n_create_workflow` | 建立新 workflow | -| `n8n_update_workflow` | 更新 workflow | -| `n8n_delete_workflow` | 刪除 workflow | -| `n8n_activate_workflow` | 啟用 workflow | -| `n8n_deactivate_workflow` | 停用 workflow | -| `n8n_execute_workflow` | 執行 workflow | -| `n8n_get_workflow_tags` | 取得 workflow 標籤 | -| `n8n_update_workflow_tags` | 更新 workflow 標籤 | - -### Executions (3) -| 工具 | 說明 | -|------|------| -| `n8n_list_executions` | 列出執行記錄 | -| `n8n_get_execution` | 取得執行詳情 | -| `n8n_delete_execution` | 刪除執行記錄 | - -### Data Tables (8) -| 工具 | 說明 | -|------|------| -| `n8n_list_datatables` | 列出資料表 | -| `n8n_create_datatable` | 建立資料表 | -| `n8n_get_datatable` | 取得資料表結構 | -| `n8n_get_datatable_rows` | 取得資料表列 | -| `n8n_insert_datatable_rows` | 插入資料列 | -| `n8n_update_datatable_rows` | 更新資料列 | -| `n8n_upsert_datatable_row` | 插入或更新資料列 | -| `n8n_delete_datatable_rows` | 刪除資料列 | - -### Tags (5) -| 工具 | 說明 | -|------|------| -| `n8n_list_tags` | 列出所有標籤 | -| `n8n_get_tag` | 取得標籤 | -| `n8n_create_tag` | 建立標籤 | -| `n8n_update_tag` | 更新標籤 | -| `n8n_delete_tag` | 刪除標籤 | - -### Credentials (4) -| 工具 | 說明 | -|------|------| -| `n8n_list_credentials` | 列出憑證 | -| `n8n_create_credential` | 建立憑證 | -| `n8n_delete_credential` | 刪除憑證 | -| `n8n_get_credential_schema` | 取得憑證 schema | - -### Users (3) -| 工具 | 說明 | -|------|------| -| `n8n_list_users` | 列出使用者 | -| `n8n_get_user` | 取得使用者 | -| `n8n_delete_user` | 刪除使用者 | - -### Variables (3) -| 工具 | 說明 | -|------|------| -| `n8n_list_variables` | 列出變數 | -| `n8n_create_variable` | 建立變數 | -| `n8n_delete_variable` | 刪除變數 | - -### 其他 (7) -| 工具 | 說明 | -|------|------| -| `n8n_list_projects` | 列出專案 | -| `n8n_create_project` | 建立專案 | -| `n8n_update_project` | 更新專案 | -| `n8n_delete_project` | 刪除專案 | -| `n8n_generate_audit` | 產生安全審計報告 | -| `n8n_health_check` | 健康檢查 | -| `n8n_trigger_webhook` | 觸發 webhook | - ---- - -## 安裝步驟 - -### 1. 安裝 n8n MCP Server - -```bash -npm install -g @nextoolsolutions/mcp-n8n -``` - -驗證: -```bash -which mcp-n8n -# /opt/homebrew/bin/mcp-n8n -``` - -### 2. 取得 n8n API Key - -1. 開啟 n8n UI: `http://localhost:5678` -2. 登入後點擊右上角 **Settings** → **API** -3. 點擊 **Create New API Key** -4. 複製產生的 key - -### 3. 設定 OpenCode MCP 設定檔 - -建立或編輯 `~/.config/opencode/opencode.json`: - -```json -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "gitea": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/gitea-mcp-server", - "-token", "", - "-host", "http://localhost:3000" - ] - }, - "n8n": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-n8n"], - "environment": { - "N8N_BASE_URL": "http://localhost:5678", - "N8N_API_KEY": "" - } - } - } -} -``` - -### 4. 驗證 MCP 運作 - -重啟 OpenCode,確認 n8n MCP tools 可用。 - ---- - -## n8n API 端點 - -n8n v2 REST API 路徑為 `/rest/`(不是 `/api/v1/`) - -| 端點 | 方法 | 說明 | -|------|------|------| -| `/rest/workflows` | GET | 列出 workflows | -| `/rest/workflows/:id` | GET | 取得 workflow | -| `/rest/workflows` | POST | 建立 workflow | -| `/rest/workflows/:id` | PUT | 更新 workflow | -| `/rest/workflows/:id` | DELETE | 刪除 workflow | -| `/rest/workflows/:id/activate` | POST | 啟用 workflow | -| `/rest/workflows/:id/deactivate` | POST | 停用 workflow | -| `/rest/workflows/:id/execute` | POST | 執行 workflow | - -**認證方式:** -```bash -curl -H "X-N8N-API-KEY: YOUR_API_KEY" \ - http://localhost:5678/rest/workflows -``` - ---- - -## 疑難排解 - -### API 404 問題 - -如果 API 傳回 404,檢查: - -1. **n8n 是否運行中** - ```bash - curl http://localhost:5678 - ``` - -2. **n8n 初始設定(重要!)** - - 第一次使用必須在瀏覽器完成初始化 - - 開啟 `http://localhost:5678` - - 按照畫面指示建立管理員帳號 - - 完成後才能使用 API - -3. **API Key 是否正確** - ```bash - curl -H "X-N8N-API-KEY: YOUR_KEY" \ - http://localhost:5678/rest/workflows - ``` - -### n8n 初始設定(第一次使用) - -1. 開啟瀏覽器: `http://localhost:5678` -2. 輸入 email 和密碼建立管理員帳號 -3. 完成後進入 Settings → API -4. 建立 API Key 並複製 - -### CLI Import vs PostgreSQL - -n8n 使用 PostgreSQL 儲存資料: -- CLI `n8n import:workflow` 可能寫入 SQLite -- 手動在 UI import 會寫入 PostgreSQL - -建議直接使用 UI 或 MCP import。 - ---- - -## 相關文件 - -- [OPENCODE_GUIDE.md](./OPENCODE_GUIDE.md) - OpenCode 使用規範 -- [INSTALL_N8N.md](./INSTALL_N8N.md) - n8n 安裝指南 -- [N8N_DEMO_WORKFLOW.md](./N8N_DEMO_WORKFLOW.md) - n8n Workflow 範例 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_SETUP_COMPLETE.md b/docs_v1.0/IMPLEMENTATION/ROOT_N8N_SETUP_COMPLETE.md deleted file mode 100644 index 6148bfc..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_SETUP_COMPLETE.md +++ /dev/null @@ -1,152 +0,0 @@ -# Momentry Video RAG - n8n 工作流程設定完成 - -## ✅ 最終成功版本 - -| 項目 | 內容 | -|------|------| -| **工作流程名稱** | Video Search - Working v3 | -| **ID** | 4vQo8I4SXEaR5E1A | -| **狀態** | ✅ SUCCESS | -| **執行 ID** | 1620 | - ---- - -## 成功關鍵 - -### HTTP Request Node 正確設定 -```json -{ - "url": "https://api.momentry.ddns.net/api/v1/n8n/search", - "method": "POST", - "sendBody": true, - "specifyBody": "json", - "jsonBody": "{\"query\":\"charade\",\"limit\":3}", - "options": {} -} -``` - -**重點**: -- ✅ `specifyBody`: "json" (不是 "body") -- ✅ `jsonBody`: 字串格式 (不是物件) -- ✅ 使用 `"{\"query\":\"..."}` 轉義引號 - ---- - -## 所有可用工作流程 - -| 工作流程 | ID | 狀態 | 說明 | -|---------|-----|------|------| -| Video Search - Working v3 | 4vQo8I4SXEaR5E1A | ✅ 成功 | **推薦使用** | -| Video Search - HTTP Only | tZbljQCFZDOJ4C0s | ❌ 失敗 | body 格式錯誤 | -| Video Search - Debug Simple | e2CMjonwILMUYjp0 | ⚠️ 待測 | Code Node 版本 | -| Video Search - Instant | zC5K3TbFzWGAh0la | ❌ 失敗 | `$httpRequest` 不可用 | - ---- - -## 如何使用 - -### 方法 1: 直接執行 -```bash -# 開啟工作流程 -open https://n8n.momentry.ddns.net/workflow/4vQo8I4SXEaR5E1A -``` - -然後: -1. 點擊 **"Execute Workflow"** ▶️ -2. 點擊 **"Show Result"** 節點 -3. 查看 JSON 結果 - -### 方法 2: 修改搜尋關鍵字 -1. 點擊 **"Search API"** 節點 -2. 修改 `jsonBody`: - ```json - "{\"query\":\"您的關鍵字\",\"limit\":5}" - ``` -3. 儲存並重新執行 - ---- - -## API 端點 - -### Momentry Core API -``` -POST https://api.momentry.ddns.net/api/v1/n8n/search -Content-Type: application/json - -Body: -{ - "query": "charade", - "limit": 3, - "uuid": "可選的影片UUID" -} -``` - -### 直接測試 -```bash -curl -X POST https://api.momentry.ddns.net/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -d '{"query":"charade","limit":3}' -``` - ---- - -## 已建立的文件 - -| 文件 | 路徑 | 內容 | -|------|------|------| -| API URL 範例 | `docs/API_URL_EXAMPLES.md` | 完整 URL 和 curl 指令 | -| HTTP Request 指南 | `docs/N8N_HTTP_REQUEST_GUIDE.md` | Node 設定說明 | -| 輸出查看指南 | `docs/N8N_VIEW_OUTPUT_GUIDE.md` | 如何查看結果 | -| MCP 測試報告 | `docs/N8N_MCP_TEST_REPORT.md` | 43 個 MCP 工具 | -| API 修復總結 | `docs/N8N_API_FIX_SUMMARY.md` | 問題修復過程 | -| 工作流程 JSON | `docs/n8n_workflow_video_rag_mcp.json` | 原始工作流程 | -| 測試腳本 | `docs/test_all.sh` | 自動測試腳本 | - ---- - -## 服務狀態 - -✅ **Momentry Core**: https://api.momentry.ddns.net (Port 3002) -✅ **n8n**: https://n8n.momentry.ddns.net (Port 5678) -✅ **MCP 整合**: 43 個工具可用 - ---- - -## 下一步建議 - -### 1. 建立帶有參數的工作流程 -修改現有工作流程,讓 query 和 limit 可以動態輸入: -- 添加 Webhook Node 接收外部請求 -- 或使用 Set Node 設定變數 - -### 2. 建立完整的 RAG 流程 -結合 OpenAI: -- 搜尋影片片段 -- 使用 GPT 生成回答 -- 回傳格式化的 RAG 結果 - -### 3. 自動化監控 -- 建立定時執行的工作流程 -- 監控 API 健康狀態 -- 發送 Telegram/Email 通知 - ---- - -## 問題排除 - -如果再次遇到 "Your request is invalid": -1. 檢查 `specifyBody` 必須設為 `"json"` -2. `jsonBody` 必須是字串格式,不是物件 -3. 確保使用正確的 JSON 轉義: `{\"key\":\"value\"}` - ---- - -## 完成!🎉 - -所有設定已完成: -- ✅ n8n REST API 修復並運作正常 -- ✅ MCP 整合完成 (43 個工具) -- ✅ Momentry Core API 可外部存取 -- ✅ 成功的工作流程已創建並測試 - -您可以開始使用 n8n 自動化管理 Momentry Core 了! diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_VIEW_OUTPUT_GUIDE.md b/docs_v1.0/IMPLEMENTATION/ROOT_N8N_VIEW_OUTPUT_GUIDE.md deleted file mode 100644 index 945540c..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_N8N_VIEW_OUTPUT_GUIDE.md +++ /dev/null @@ -1,141 +0,0 @@ -# n8n 工作流程輸出查看指南 - -## 問題:"Node executed successfully but no output data" - -這是正常的!在 n8n 中,你需要**點擊節點**才能看到輸出資料。 - ---- - -## 如何查看輸出資料 - -### 方法 1: 點擊節點查看 - -1. 執行工作流程後(點擊 Execute Workflow) -2. **點擊任何一個節點**(Node) -3. 在右側面板會顯示該節點的輸出 -4. 查看 **JSON** 分頁看到完整資料 - -### 方法 2: 查看執行記錄 - -1. 執行工作流程 -2. 點擊左側的 **"Executions"** 選單 -3. 找到最近的執行記錄 -4. 點擊展開查看每個節點的輸出 - -### 方法 3: 使用 Respond to Webhook - -如果你想直接看到結果,添加一個 Respond to Webhook 節點: - -```javascript -// 在最後一個節點之後添加: -Node: Respond to Webhook -├── Response Mode: Last Node -└── Response Body: {{ JSON.stringify($json) }} -``` - ---- - -## 新增的工作流程 - -### ✅ Video Search - Debug Simple -- **ID**: e2CMjonwILMUYjp0 -- **URL**: https://n8n.momentry.ddns.net/workflow/e2CMjonwILMUYjp0 - -這個版本保證有輸出! - -### 執行步驟 - -1. 開啟工作流程 -2. 點擊 **"Execute Workflow"** ▶️ -3. 等待執行完成(約 3-5 秒) -4. **點擊最後一個節點** "Step 3 - Show Results" -5. 查看右側的 **JSON** 分頁 - -### 預期看到的輸出 - -```json -{ - "status": "SUCCESS", - "query": "charade", - "totalResults": 2, - "firstHit": { - "text": "fun plot twists, Woody Dialog and charming perform...", - "time": "48.8s - 55.44s", - "score": "53%" - } -} -``` - -或如果失敗: - -```json -{ - "status": "FAILED", - "error": "error message here" -} -``` - ---- - -## 截圖說明 - -### 執行後的畫面 -``` -┌─────────────────────────────────────┐ -│ When clicking "Execute Workflow" │ ✅ (綠色勾) -├─────────────────────────────────────┤ -│ Step 1 - Set Query │ ✅ (綠色勾) -├─────────────────────────────────────┤ -│ Step 2 - Call API │ ✅ (綠色勾) ← 點擊這裡 -├─────────────────────────────────────┤ -│ Step 3 - Show Results │ ✅ (綠色勾) ← 或這個 -└─────────────────────────────────────┘ - -[右側面板 - 點擊節點後顯示] -┌─────────────────────────────────────┐ -│ Node: Step 2 - Call API │ -│ │ -│ [JSON] [Table] [Schema] │ ← 點擊 JSON -│ │ -│ { │ -│ "success": true, │ -│ "query": "charade", │ -│ ... │ -│ } │ -└─────────────────────────────────────┘ -``` - ---- - -## 快速測試 - -如果不想用瀏覽器,直接在這裡執行: - -```bash -# 開啟簡化版工作流程 -open https://n8n.momentry.ddns.net/workflow/e2CMjonwILMUYjp0 -``` - -然後: -1. 點擊 **Execute Workflow** -2. 點擊 **"Step 3 - Show Results"** 節點 -3. 看右側 JSON 面板 - ---- - -## 如果仍然看不到資料 - -檢查: -1. ✅ 工作流程已儲存 -2. ✅ 點擊了正確的節點(有綠色勾的) -3. ✅ 右側面板已展開(點擊 JSON 分頁) -4. ✅ 沒有紅色錯誤訊息 - ---- - -## 聯絡支援 - -如果還是有問題,請告訴我: -1. 你點擊的是哪個節點? -2. 右側面板顯示什麼? -3. 有沒有紅色錯誤訊息? diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_OPENCODE_GUIDE.md b/docs_v1.0/IMPLEMENTATION/ROOT_OPENCODE_GUIDE.md deleted file mode 100644 index bff48f8..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_OPENCODE_GUIDE.md +++ /dev/null @@ -1,430 +0,0 @@ -# OpenCode 使用規範 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-21 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | -|------|------|------|--------| -| V1.0 | 2026-03-21 | 創建文件 | Warren | -| V1.1 | 2026-03-21 | 新增 MCP 設定章節 | OpenCode | - ---- - -## 概述 - -本文檔定義使用 OpenCode 進行專案開發的最佳實踐,確保開發效率和程式碼品質。 - ---- - -## 任務管理 - -### 任務批次策略 - -**原則**: 一次處理 1-2 個功能,完成後驗證,再繼續下一個。 - -| 批次大小 | 適用場景 | 說明 | -|----------|----------|------| -| 1 個 | 緊急修復、簡單任務 | 快速完成 | -| 2-3 個 | 一般功能開發 | 平衡效率與品質 | -| 3+ 個 | 大型重構 | 需要更詳細的追蹤 | - -### 驗證流程 - -每個任務完成後必須執行: - -```bash -# 1. 編譯檢查 -cargo check - -# 2. Lint 檢查 -cargo clippy --lib - -# 3. 單元測試 -cargo test --lib - -# 4. 格式化檢查 -cargo fmt -- --check -``` - ---- - -## 溝通模式 - -### 有效的任務描述 - -**建議格式**: -``` -執行 [功能名稱] -- 優先級: 高/中/低 -- 驗收標準: [明確的標準] -- 約束: [限制條件] -``` - -**範例**: -``` -實作 monitor_jobs 表 -- 優先級: 高 -- 驗收標準: CRUD 操作可用,單元測試通過 -- 約束: 使用現有架構 -``` - -### 明確的暫停點 - -在每個階段完成後主動詢問: - -``` -[任務] 完成。要繼續: -1. 實作功能 A -2. 添加測試 -3. 更新文檔 -``` - -### 不建議的溝通 - -| 模式 | 問題 | 建議 | -|------|------|------| -| 一次指定太多項目 | 增加複雜度,難以追蹤 | 分批處理 | -| 模糊的任務描述 | 難以評估進度 | 使用明確的驗收標準 | -| 從不驗證 | 累積問題 | 每步驟完成後驗證 | - ---- - -## 決策點 - -### 常見決策點 - -| 階段 | 問題 | 選項 | -|------|------|------| -| 開始 | 如何開始? | 先了解現況 / 直接實作 | -| 實作 | 實作方式? | 保持現有架構 / 重構 | -| 驗證 | 通過了嗎? | 繼續 / 修復問題 | -| 完成 | 還有什麼? | 下一個任務 / 結束 | - -### 決策準則 - -1. **安全優先**: 破壞性變更需要明確確認 -2. **驗證後繼續**: 每步驟完成後驗證 -3. **文檔同步**: 變更後更新文檔 - ---- - -## 文檔使用 - -### 必讀文檔 - -| 文檔 | 用途 | 查閱時機 | -|------|------|----------| -| `AGENTS.md` | 專案規範 | 每次對話開始 | -| `docs/*.md` | 技術規格 | 功能實作前 | - -### 文檔更新時機 - -| 變更類型 | 需要更新 | -|----------|----------| -| 新功能 | `AGENTS.md` + 相關技術文檔 | -| 架構變更 | `ARCHITECTURE_EVALUATION.md` | -| 問題修復 | `PENDING_ISSUES.md` | -| 環境變更 | `INSTALL_*.md` | - ---- - -## 審查清單 - -### 實作完成後檢查 - -- [ ] `cargo clippy --lib` 通過 -- [ ] `cargo test --lib` 通過 -- [ ] `cargo fmt -- --check` 通過 -- [ ] 文檔已更新 -- [ ] 新功能有單元測試 -- [ ] Pre-commit hook 通過 - -### 對話結束前 - -- [ ] 所有變更已驗證 -- [ ] 文檔已同步 -- [ ] 下一步計劃明確 - ---- - -## 範例流程 - -### 範例 1: 實作新功能 - -``` -用戶: 實作使用者認證功能 - -OpenCode: -1. 分析現有架構 -2. 創建任務清單 -3. 實作核心功能 -4. 添加單元測試 -5. 更新文檔 -6. 驗證通過 - -用戶: 完成,繼續下一個 -``` - -### 範例 2: 修復問題 - -``` -用戶: 修復登入超時問題 - -OpenCode: -1. 重現問題 -2. 分析根因 -3. 實作修復 -4. 驗證修復 -5. 添加測試防止回歸 - -用戶: 確認修復完成 -``` - ---- - -## 常見問題 - -### Q: 如何避免一次處理太多? - -**A**: 使用 `/todo` 追蹤任務,分批處理。 - -### Q: 如何確保文檔同步? - -**A**: 每個任務完成後檢查是否需要更新文檔。 - -### Q: 何時應該結束對話? - -**A**: 當主要任務完成,且沒有緊急的後續步驟時。 - ---- - -## MCP 設定 - -### 設定檔案 - -OpenCode MCP 設定位於 `~/.config/opencode/opencode.json` - -### 已啟用的 MCP Servers - -| Server | 用途 | 命令 | -|--------|------|------| -| gitea | Gitea API 操作 | `/opt/homebrew/bin/gitea-mcp-server` | -| n8n | n8n Workflow 操作 | `/opt/homebrew/bin/mcp-n8n` | -| postgres | PostgreSQL 資料庫查詢 | `/opt/homebrew/bin/mcp-server-postgres` | -| redis | Redis 快取操作 | `/opt/homebrew/bin/mcp-server-redis` | -| qdrant | Qdrant 向量搜尋 | `/opt/homebrew/bin/mcp-server-qdrant` | -| filesystem | 檔案系統操作 | `/opt/homebrew/bin/mcp-server-filesystem` | - -### MCP 設定格式 - -**Schema 參考**: `https://opencode.ai/config.json` - -**必要欄位**: -| 欄位 | 類型 | 說明 | -|------|------|------| -| `type` | string | `"local"` 或 `"remote"` | -| `command` | array | 命令和參數(local 必要) | -| `url` | string | 遠端 URL(remote 必要) | - -**可選欄位**: -| 欄位 | 類型 | 說明 | -|------|------|------| -| `environment` | object | 環境變數(local only) | -| `enabled` | boolean | 是否啟用 | -| `timeout` | number | 請求超時(毫秒) | -| `headers` | object | 請求頭(remote only) | - -**Local MCP 範例**: -```json -{ - "mcp": { - "gitea": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/gitea-mcp-server", - "-token", "", - "-host", "http://localhost:3000" - ] - }, - "n8n": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-n8n"], - "environment": { - "N8N_BASE_URL": "http://localhost:5678", - "N8N_API_KEY": "" - } - }, - "postgres": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-server-postgres"], - "environment": { - "DATABASE_URL": "postgresql://accusys:accusys@localhost:5432/momentry" - } - }, - "redis": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-server-redis"], - "environment": { - "REDIS_URL": "redis://:accusys@localhost:6379" - } - }, - "qdrant": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-server-qdrant"], - "environment": { - "QDRANT_URL": "http://localhost:6333", - "QDRANT_API_KEY": "" - } - }, - "filesystem": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-server-filesystem"], - "args": ["/Users/accusys/momentry"] - } - } -} -``` - -**Remote MCP 範例**: -```json -{ - "mcp": { - "jira": { - "type": "remote", - "url": "https://jira.example.com/mcp", - "enabled": true, - "headers": { - "Authorization": "Bearer your-token" - } - } - } -} -``` - -### n8n MCP 工具 (43 個) - -#### Workflows (10) -| 工具 | 說明 | -|------|------| -| `n8n_list_workflows` | 列出所有 workflows | -| `n8n_get_workflow` | 取得 workflow 詳情 | -| `n8n_create_workflow` | 建立新 workflow | -| `n8n_update_workflow` | 更新 workflow | -| `n8n_delete_workflow` | 刪除 workflow | -| `n8n_activate_workflow` | 啟用 workflow | -| `n8n_deactivate_workflow` | 停用 workflow | -| `n8n_execute_workflow` | 執行 workflow | -| `n8n_get_workflow_tags` | 取得 workflow 標籤 | -| `n8n_update_workflow_tags` | 更新 workflow 標籤 | - -#### Executions (3) -| 工具 | 說明 | -|------|------| -| `n8n_list_executions` | 列出執行記錄 | -| `n8n_get_execution` | 取得執行詳情 | -| `n8n_delete_execution` | 刪除執行記錄 | - -#### Data Tables (8) -| 工具 | 說明 | -|------|------| -| `n8n_list_datatables` | 列出資料表 | -| `n8n_create_datatable` | 建立資料表 | -| `n8n_get_datatable` | 取得資料表結構 | -| `n8n_get_datatable_rows` | 取得資料表列 | -| `n8n_insert_datatable_rows` | 插入資料列 | -| `n8n_update_datatable_rows` | 更新資料列 | -| `n8n_upsert_datatable_row` | 插入或更新資料列 | -| `n8n_delete_datatable_rows` | 刪除資料列 | - -#### Tags (5) -| 工具 | 說明 | -|------|------| -| `n8n_list_tags` | 列出所有標籤 | -| `n8n_get_tag` | 取得標籤 | -| `n8n_create_tag` | 建立標籤 | -| `n8n_update_tag` | 更新標籤 | -| `n8n_delete_tag` | 刪除標籤 | - -#### Credentials (4) -| 工具 | 說明 | -|------|------| -| `n8n_list_credentials` | 列出憑證 | -| `n8n_create_credential` | 建立憑證 | -| `n8n_delete_credential` | 刪除憑證 | -| `n8n_get_credential_schema` | 取得憑證 schema | - -#### Users (3) -| 工具 | 說明 | -|------|------| -| `n8n_list_users` | 列出使用者 | -| `n8n_get_user` | 取得使用者 | -| `n8n_delete_user` | 刪除使用者 | - -#### Variables (3) -| 工具 | 說明 | -|------|------| -| `n8n_list_variables` | 列出變數 | -| `n8n_create_variable` | 建立變數 | -| `n8n_delete_variable` | 刪除變數 | - -#### 其他 (7) -| 工具 | 說明 | -|------|------| -| `n8n_list_projects` | 列出專案 | -| `n8n_create_project` | 建立專案 | -| `n8n_update_project` | 更新專案 | -| `n8n_delete_project` | 刪除專案 | -| `n8n_generate_audit` | 產生安全審計報告 | -| `n8n_health_check` | 健康檢查 | -| `n8n_trigger_webhook` | 觸發 webhook | - -### 安裝 n8n MCP - -```bash -npm install -g @nextoolsolutions/mcp-n8n -``` - -### n8n API Key 設定 - -1. 開啟 n8n UI (http://localhost:5678) -2. 前往 Settings → API -3. 建立 API Key -4. 將 API Key 加入 `opencode.json` 的 `N8N_API_KEY` - -### 驗證 MCP 運作 - -```bash -# 測試 MCP server -N8N_BASE_URL=https://n8n.momentry.ddns.net \ -N8N_API_KEY="your-key" \ -mcp-n8n - -# 測試工具列表 -echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test", "version": "1.0"}}} -{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}' | \ -N8N_BASE_URL=https://n8n.momentry.ddns.net \ -N8N_API_KEY="your-key" \ -mcp-n8n -``` - ---- - -## 相關文件 - -- [AGENTS.md](../AGENTS.md) - 專案開發規範 -- [ARCHITECTURE_EVALUATION.md](./ARCHITECTURE_EVALUATION.md) - 架構優化評估 -- [PENDING_ISSUES.md](./PENDING_ISSUES.md) - 待解決問題追蹤 -- [INSTALL_N8N.md](./INSTALL_N8N.md) - n8n 安裝指南 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_OPENCODE_MCP_INSTALL.md b/docs_v1.0/IMPLEMENTATION/ROOT_OPENCODE_MCP_INSTALL.md deleted file mode 100644 index 409e131..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_OPENCODE_MCP_INSTALL.md +++ /dev/null @@ -1,535 +0,0 @@ -# OpenCode MCP Servers 安裝指南 - -| 項目 | 內容 | -|------|------| -| 建立者 | OpenCode | -| 建立時間 | 2026-03-24 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-24 | 創建文件 | OpenCode | OpenCode / big-pickle | -| V1.1 | 2026-03-24 | 新增 sentry, context7, playwright MCP | OpenCode | OpenCode / big-pickle | - ---- - -## 概述 - -本文檔說明如何在 macOS 上為 OpenCode 安裝和配置 MCP (Model Context Protocol) Servers,透過標準化的協定讓 AI 助手能夠存取各種外部服務和工具。 - -MCP Servers 提供: -- 標準化的工具調用介面 -- 安全的資源存取控制 -- 統一的配置和管理方式 - ---- - -## 已安裝的 MCP Servers - -| Server | 安裝方式 | 用途 | 狀態 | -|--------|----------|------|------| -| gitea | Homebrew | Gitea API 操作 | ✅ | -| n8n | NPM (@nextoolsolutions/mcp-n8n) | n8n Workflow 管理 | ✅ | -| postgres | NPM (@modelcontextprotocol/server-postgres) | PostgreSQL 資料庫查詢 | ✅ | -| redis | NPM (@modelcontextprotocol/server-redis) | Redis 快取操作 | ✅ | -| mongodb | NPM (mongodb-mcp-server) | MongoDB 文件資料庫 | ✅ | -| qdrant | Python (qdrant/mcp-server-qdrant) | Qdrant 向量搜尋 | ✅ | -| filesystem | NPM (@modelcontextprotocol/server-filesystem) | 檔案系統操作 | ✅ | -| sentry | NPM (@sentry/mcp-server) | 錯誤追蹤和監控 | ⏳ | -| context7 | NPM (@upstash/context7-mcp) | 技術文檔搜尋 | ✅ | -| playwright | NPM (@playwright/mcp) | 瀏覽器自動化 | ✅ | - ---- - -## 前置條件 - -- OpenCode 已安裝 -- Node.js (用於 NPM 套件) -- Python 3.11+ (用於 qdrant-mcp) -- 相關服務已運行 (PostgreSQL, Redis, Qdrant, Gitea, n8n, MongoDB) - ---- - -## 安裝步驟 - -### Step 1: 安裝 NPM MCP Servers - -```bash -npm install -g @modelcontextprotocol/server-postgres -npm install -g @modelcontextprotocol/server-redis -npm install -g @modelcontextprotocol/server-filesystem -npm install -g @modelcontextprotocol/server-everything -npm install -g @nextoolsolutions/mcp-n8n -npm install -g mongodb-mcp-server -npm install -g @sentry/mcp-server -npm install -g @upstash/context7-mcp -npm install -g @playwright/mcp -``` - -**驗證**: - -```bash -which mcp-server-postgres -which mcp-server-redis -which mcp-server-filesystem -which mcp-n8n -which mongodb-mcp-server -which sentry-mcp -which context7-mcp -which playwright-mcp -``` - ---- - -### Step 2: 安裝 gitea-mcp-server - -```bash -brew install gitea-mcp-server -``` - -**驗證**: - -```bash -which gitea-mcp-server -``` - ---- - -### Step 3: 安裝 MongoDB MCP Server (已包含在 Step 1) - -MongoDB MCP 已透過 NPM 安裝: - -```bash -npm install -g mongodb-mcp-server -``` - ---- - -### Step 4: 安裝 Qdrant MCP Server (Python) - -```bash -cd /tmp -git clone https://github.com/qdrant/mcp-server-qdrant.git -cd mcp-server-qdrant -/opt/homebrew/bin/python3.11 -m pip install -e . -``` - -**驗證**: - -```bash -which mcp-server-qdrant -``` - ---- - -### Step 5: 配置 OpenCode MCP 設定 - -編輯 `~/.config/opencode/opencode.json`: - -```json -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "gitea": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/gitea-mcp-server", - "-token", - "", - "-host", - "http://localhost:3000" - ] - }, - "n8n": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-n8n"], - "environment": { - "N8N_BASE_URL": "http://localhost:5678", - "N8N_API_KEY": "" - } - }, - "postgres": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/mcp-server-postgres", - "postgresql://accusys:accusys@localhost:5432/momentry" - ] - }, - "redis": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/mcp-server-redis", - "redis://:accusys@localhost:6379" - ] - }, - "mongodb": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mongodb-mcp-server"], - "environment": { - "MONGODB_URI": "mongodb://localhost:27017" - } - }, - "qdrant": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-server-qdrant"], - "environment": { - "QDRANT_URL": "http://localhost:6333", - "QDRANT_API_KEY": "" - } - }, - "filesystem": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/mcp-server-filesystem", - "/Users/accusys/momentry" - ] - }, - "sentry": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/sentry-mcp", - "--access-token", - "" - ] - }, - "context7": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/context7-mcp"] - }, - "playwright": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/playwright-mcp"] - } - } -} -``` - ---- - -### Step 6: 驗證 MCP Servers - -```bash -# 列出所有 MCP servers -opencode mcp ls - -# 或在 OpenCode 中執行 -/mcps -``` - ---- - -## MCP Server 工具說明 - -### gitea - -| 工具 | 說明 | -|------|------| -| list_repos | 列出倉庫 | -| get_repo | 取得倉庫詳情 | -| list_issues | 列出 Issues | -| create_issue | 建立 Issue | -| list_pulls | 列出 Pull Requests | - ---- - -### n8n (43 個工具) - -#### Workflows (10) -| 工具 | 說明 | -|------|------| -| n8n_list_workflows | 列出所有 workflows | -| n8n_get_workflow | 取得 workflow 詳情 | -| n8n_create_workflow | 建立新 workflow | -| n8n_update_workflow | 更新 workflow | -| n8n_delete_workflow | 刪除 workflow | -| n8n_activate_workflow | 啟用 workflow | -| n8n_deactivate_workflow | 停用 workflow | -| n8n_execute_workflow | 執行 workflow | -| n8n_get_workflow_tags | 取得 workflow 標籤 | -| n8n_update_workflow_tags | 更新 workflow 標籤 | - -#### Executions (3) -| 工具 | 說明 | -|------|------| -| n8n_list_executions | 列出執行記錄 | -| n8n_get_execution | 取得執行詳情 | -| n8n_delete_execution | 刪除執行記錄 | - -#### Data Tables (8) -| 工具 | 說明 | -|------|------| -| n8n_list_datatables | 列出資料表 | -| n8n_create_datatable | 建立資料表 | -| n8n_get_datatable | 取得資料表結構 | -| n8n_get_datatable_rows | 取得資料表列 | -| n8n_insert_datatable_rows | 插入資料列 | -| n8n_update_datatable_rows | 更新資料列 | -| n8n_upsert_datatable_row | 插入或更新資料列 | -| n8n_delete_datatable_rows | 刪除資料列 | - -#### Tags (5) -| 工具 | 說明 | -|------|------| -| n8n_list_tags | 列出所有標籤 | -| n8n_get_tag | 取得標籤 | -| n8n_create_tag | 建立標籤 | -| n8n_update_tag | 更新標籤 | -| n8n_delete_tag | 刪除標籤 | - -#### 其他 (17) -| 工具 | 說明 | -|------|------| -| n8n_list_credentials | 列出憑證 | -| n8n_create_credential | 建立憑證 | -| n8n_delete_credential | 刪除憑證 | -| n8n_get_credential_schema | 取得憑證 schema | -| n8n_list_users | 列出使用者 | -| n8n_get_user | 取得使用者 | -| n8n_delete_user | 刪除使用者 | -| n8n_list_variables | 列出變數 | -| n8n_create_variable | 建立變數 | -| n8n_delete_variable | 刪除變數 | -| n8n_list_projects | 列出專案 | -| n8n_create_project | 建立專案 | -| n8n_update_project | 更新專案 | -| n8n_delete_project | 刪除專案 | -| n8n_generate_audit | 產生安全審計報告 | -| n8n_health_check | 健康檢查 | -| n8n_trigger_webhook | 觸發 webhook | - ---- - -### postgres - -| 工具 | 說明 | -|------|------| -| query | 執行唯讀 SQL 查詢 | - -**範例**: - -```json -{ - "sql": "SELECT * FROM users LIMIT 10;" -} -``` - ---- - -### redis - -| 工具 | 說明 | -|------|------| -| set | 設定 key-value 配對 | -| get | 取得 key 的值 | -| delete | 刪除 key(s) | -| list | 列出符合模式的 keys | - ---- - -### mongodb - -| 工具 | 說明 | -|------|------| -| mongodb_list_databases | 列出所有資料庫 | -| mongodb_list_collections | 列出資料庫中的集合 | -| mongodb_find | 查詢文件 | -| mongodb_insert_one | 插入單個文件 | -| mongodb_insert_many | 插入多個文件 | -| mongodb_update_one | 更新單個文件 | -| mongodb_update_many | 更新多個文件 | -| mongodb_delete_one | 刪除單個文件 | -| mongodb_delete_many | 刪除多個文件 | -| mongodb_aggregate | 聚合查詢 | - -**範例**: - -```json -{ - "database": "momentry", - "collection": "videos", - "filter": {"uuid": "abc123"} -} -``` - ---- - -### qdrant - -| 工具 | 說明 | -|------|------| -| 查詢工具 | 向量搜尋和集合管理 | - ---- - -### filesystem - -| 工具 | 說明 | -|------|------| -| read_file | 讀取檔案 | -| write_file | 寫入檔案 | -| list_directory | 列出目錄 | -| create_directory | 建立目錄 | - ---- - -### sentry - -| 工具 | 說明 | -|------|------| -| sentry_list_issues | 列出 issues | -| sentry_get_issue | 取得 issue 詳情 | -| sentry_create_issue | 建立 issue | -| sentry_update_issue | 更新 issue | -| sentry_list_projects | 列出專案 | -| sentry_search_docs | 搜尋 Sentry 文件 | - -**注意**: 需要設定 `SENTRY_ACCESS_TOKEN` - -**取得 Token**: -1. 登入 https://sentry.io -2. Settings → Developer Tools → API Keys -3. 建立新 Token (需要 `event:read`, `project:read` 權限) - ---- - -### context7 - -| 工具 | 說明 | -|------|------| -| context7_resolve-library-id | 解析函式庫 ID | -| context7_query-docs | 查詢函式庫文件 | - -**用途**: 即時技術文件和函式庫查詢,獲取最新的 API 語法和範例。 - ---- - -### playwright - -| 工具 | 說明 | -|------|------| -| playwright_navigate | 導航到 URL | -| playwright_screenshot | 截圖 | -| playwright_click | 點擊元素 | -| playwright_type | 輸入文字 | -| playwright_evaluate | 執行 JavaScript | - -**用途**: 瀏覽器自動化測試、網頁截圖、網頁內容抓取。 - ---- - -## 管理指令 - -### 新增 MCP Server - -```bash -opencode mcp add -``` - -### 列出 MCP Servers - -```bash -opencode mcp ls -``` - -### 認證 OAuth Server - -```bash -opencode mcp auth -``` - ---- - -## 故障排除 - -### MCP Server 連線失敗 - -1. 檢查服務是否運行: - ```bash - # PostgreSQL - pg_isready -h localhost -p 5432 - - # Redis - redis-cli -a accusys ping - - # Qdrant - curl -s http://localhost:6333/ - ``` - -2. 檢查 MCP Server 是否安裝: - ```bash - which mcp-server-postgres - which mcp-server-redis - ``` - -3. 驗證配置格式正確 - ---- - -### Token 或 API Key 無效 - -1. PostgreSQL: 確認使用者名稱和密碼 -2. Redis: 確認密碼 -3. n8n: 確認 API Key 未過期 -4. Gitea: 確認 Token 有效 - ---- - -## 檔案位置 - -| 類型 | 路徑 | 說明 | -|------|------|------| -| OpenCode 配置 | ~/.config/opencode/opencode.json | MCP 設定檔 | -| Gitea MCP | /opt/homebrew/bin/gitea-mcp-server | 安裝路徑 | -| n8n MCP | /opt/homebrew/bin/mcp-n8n | 安裝路徑 | -| Postgres MCP | /opt/homebrew/bin/mcp-server-postgres | 安裝路徑 | -| Redis MCP | /opt/homebrew/bin/mcp-server-redis | 安裝路徑 | -| Qdrant MCP | /opt/homebrew/bin/mcp-server-qdrant | 安裝路徑 | -| Filesystem MCP | /opt/homebrew/bin/mcp-server-filesystem | 安裝路徑 | - ---- - -## 常用指令 - -```bash -# 列出所有 MCP servers -opencode mcp ls - -# 測試 PostgreSQL MCP -echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query","arguments":{"sql":"SELECT 1;"}}}' | \ - /opt/homebrew/bin/mcp-server-postgres postgresql://accusys:accusys@localhost:5432/momentry - -# 測試 Redis MCP -echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"ping","arguments":{}}}' | \ - /opt/homebrew/bin/mcp-server-redis redis://:accusys@localhost:6379 -``` - ---- - -## 版本資訊 - -- 版本: 1.0 -- 安裝日期: 2026-03-24 -- 文件更新: 2026-03-24 - ---- - -## 相關文件 - -- [OpenCode Guide](./OPENCODE_GUIDE.md) - OpenCode 使用指南 -- [Gitea MCP 安裝](./INSTALL_GITEA_MCP.md) - Gitea MCP 詳細設定 -- [n8n MCP 設定](./N8N_MCP_SETUP.md) - n8n MCP 詳細設定 -- [服務總覽](./SERVICES.md) - 所有服務狀態總覽 diff --git a/docs_v1.0/IMPLEMENTATION/ROOT_YOLO_RESUME_INTEGRATION.md b/docs_v1.0/IMPLEMENTATION/ROOT_YOLO_RESUME_INTEGRATION.md deleted file mode 100644 index d4c0248..0000000 --- a/docs_v1.0/IMPLEMENTATION/ROOT_YOLO_RESUME_INTEGRATION.md +++ /dev/null @@ -1,102 +0,0 @@ -# YOLO Resume 功能整合規劃 - -## 現有資源 - -### 1. video_yolo_player 專案 -**位置**: `/Users/accusys/video_yolo_player/video_yolo_object_prescan.py` - -**功能**: -- ✅ Ctrl+C 暫停並保存進度 -- ✅ 自動從上一次繼續 (自動偵測 last_processed_frame) -- ✅ 可配置自動保存間隔 (預設 30 秒) -- ✅ 完整 metadata 追蹤 (處理時間、檢測數量等) -- ✅ 互動式詢問是否繼續 - -### 2. momentry_core_0.1 專案 -**位置**: `/Users/accusys/momentry_core_0.1/scripts/yolo_processor.py` - -## 整合狀態 - -| 項目 | 狀態 | 完成日期 | -|------|------|----------| -| Python script 整合 | ✅ 已完成 | 2026-03-22 | -| Rust JSON 格式支援 | ✅ 已完成 | 2026-03-22 | -| Auto-save 功能 (時間) | ✅ 已完成 | 2026-03-22 | -| Auto-save 功能 (frame) | ✅ 已完成 | 2026-03-22 | -| Ctrl+C 信號處理 | ✅ 已完成 | 2026-03-22 | -| --force 參數 | ✅ 已完成 | 2026-03-22 | -| --auto-save-frames 參數 | ✅ 已完成 | 2026-03-22 | - -## 已實作功能 - -### momentry_core_0.1/scripts/yolo_processor.py - -```python -# 新增功能: -def load_existing_data(output_file) # 載入現有資料 -def save_detection_data(output_file) # 保存進度 -def signal_handler(signum, frame) # Ctrl+C 處理 - -# 新增參數: ---auto-save 30 # 自動保存間隔 (秒) ---auto-save-frames 300 # 每 N frames 保存一次 (先到為準) ---force # 強制從頭開始 -``` - -### 輸出格式 - -```json -{ - "metadata": { - "video_path": "...", - "fps": 24.0, - "total_frames": 1000, - "status": "in_progress" | "completed" | "interrupted", - "total_detections": 5000, - "processing_time": 120.5, - "auto_save_count": 4, - "auto_save_interval": 30, - "auto_save_frames": 300, - "last_saved_frame": 12500, - "last_saved_at": "ISO timestamp" - }, - "frames": { - "1": { "frame_number": 1, "time_seconds": 0.0, "detections": [...] }, - "2": { "frame_number": 2, "time_seconds": 0.042, "detections": [...] } - } -} -``` - -### Auto-save 觸發條件 - -**滿足以下任一條件就會寫入磁碟:** -1. 距離上次儲存已超過 `--auto-save` 秒數 -2. 距離上次儲存已處理超過 `--auto-save-frames` 個 frames - -### 使用方式 - -```bash -# 第一次執行 (預設: 30秒 或 300 frames) -python yolo_processor.py video.mp4 output.json --uuid "abc123" - -# 中斷後繼續 (自動偵測) -python yolo_processor.py video.mp4 output.json --uuid "abc123" - -# 強制從頭開始 -python yolo_processor.py video.mp4 output.json --force - -# 自訂自動保存間隔 -python yolo_processor.py video.mp4 output.json --auto-save 10 --auto-save-frames 100 -``` - -### Rust 端支援 - -`check_json_completeness()` 已更新以支援新格式: -- 讀取 `frames` dict 的最後一個 key 作為 `last_processed_frame` -- 檢查 `metadata.status` 判斷是否完成 - -## 待測試項目 - -- [ ] 實際執行中斷後繼續 -- [ ] 驗證 large video (如 Old_Time_Movie_Show) 繼續處理 -- [ ] 驗證 Rust --resume 參數正確傳遞 diff --git a/docs_v1.0/IMPLEMENTATION/SFTPGO_DEMO_USER.md b/docs_v1.0/IMPLEMENTATION/SFTPGO_DEMO_USER.md deleted file mode 100644 index 95083e1..0000000 --- a/docs_v1.0/IMPLEMENTATION/SFTPGO_DEMO_USER.md +++ /dev/null @@ -1,523 +0,0 @@ ---- -document_type: "implementation_guide" -service: "MOMENTRY_CORE" -title: "SFTPGo Demo 用戶指南" -date: "2026-04-25" -version: "V1.0" -status: "active" -owner: "Warren" -created_by: "OpenCode" -tags: - - "demo" - - "sftpgo" - - "用戶指南" -ai_query_hints: - - "查詢 SFTPGo Demo 用戶指南 的內容" - - "SFTPGo Demo 用戶指南 的主要目的是什麼?" - - "如何操作或實施 SFTPGo Demo 用戶指南?" ---- - -# SFTPGo Demo 用戶指南 - -## Web 管理介面 - -**URL**: https://sftpgo.momentry.ddns.net - -### 登入方式 - -| 角色 | 用戶名 | 密碼 | -|------|--------|------| -| **Demo 用戶** | `demo` | `demopassword123` | - -### 可用功能 - -- 瀏覽個人目錄結構 -- 上傳、下載檔案 -- 查看上傳記錄 - ---- - -## 快速連線資訊 - -| 項目 | 值 | -|------|-----| -| **主機** | `sftpgo.momentry.ddns.net` | -| **SFTP 連接埠** | `2022` | -| **用戶名** | `demo` | -| **密碼** | `demopassword123` | -| **主目錄** | `/demo` | - ---- - -## 連線方式 - -### 1. 命令列 SFTP - -```bash -# 使用密碼連線 -sshpass -p "demopassword123" sftp -P 2022 demo@sftpgo.momentry.ddns.net - -# 使用金鑰連線 (需先設定) -sftp -P 2022 -i ~/.ssh/id_rsa demo@sftpgo.momentry.ddns.net -``` - -### 2. FileZilla - -1. **主機**: `sftp://sftpgo.momentry.ddns.net` -2. **連接埠**: `2022` -3. **協定**: `SFTP` -4. **登入類型**: `一般` -5. **用戶名**: `demo` -6. **密碼**: `demopassword123` - -### 3. Cyberduck (macOS) - -1. 選擇 **連線 > 新連線** -2. 協定選擇 **SFTP (SSH File Transfer Protocol)** -3. 伺服器: `sftpgo.momentry.ddns.net` -4. 連接埠: `2022` -5. 使用者名稱: `demo` -6. 密碼: `demopassword123` - -### 4. curl 上傳 - -```bash -curl -u demo:demopassword123 \ - -T /path/to/video.mp4 \ - sftp://sftpgo.momentry.ddns.net:2022/demo/ -``` - ---- - -## SFTP 基本操作 - -### 連線後常用指令 - -```bash -# 進入互動式模式 -sftp demo@sftpgo.momentry.ddns.net -P 2022 - -# 常用指令 -sftp> pwd # 顯示目前目錄 -sftp> ls # 列出檔案 -sftp> ls -la # 詳細列表 -sftp> cd uploads # 切換目錄 -sftp> mkdir videos # 建立目錄 -sftp> put local.mp4 # 上傳檔案 -sftp> get remote.mp4 # 下載檔案 -sftp> rm old.mp4 # 刪除檔案 -sftp> exit # 斷線 -``` - -### 批次上傳 - -```bash -# 上傳多個檔案 -sshpass -p "demopassword123" sftp -P 2022 demo@sftpgo.momentry.ddns.net <" - exit 1 -fi - -sshpass -p "$PASS" sftp -P $PORT $USER@$HOST < {remote_path}") - - sftp.close() - transport.close() - -if __name__ == "__main__": - if len(sys.argv) < 2: - print("用法: python upload_sftp.py <檔案路徑>") - sys.exit(1) - - upload_file(sys.argv[1]) -``` - -安裝依賴: -```bash -pip install paramiko -``` - ---- - -## WebDAV 替代方案 - -如果 SFTP 連線有問題,可使用 WebDAV: - -| 項目 | 值 | -|------|-----| -| **URL** | `https://momentry.ddns.net/webdav/` | -| **用戶名** | `demo` | -| **密碼** | `demopassword123` | - -### curl 使用 WebDAV - -```bash -# 上傳 -curl -u demo:demopassword123 \ - -T video.mp4 \ - "https://momentry.ddns.net/webdav/demo/uploads/" - -# 下載 -curl -u demo:demopassword123 \ - -o video.mp4 \ - "https://momentry.ddns.net/webdav/demo/uploads/video.mp4" - -# 列出目錄 -curl -u demo:demopassword123 \ - -X PROPFIND \ - "https://momentry.ddns.net/webdav/demo/" \ - -H "Depth: 1" -``` - ---- - -## 故障排除 - -### 連線被拒絕 - -```bash -# 檢查 SFTPGo 是否運行 -curl -s http://localhost:8080/api/v2/status | jq .status - -# 檢查連接埠 -nc -zv momentry.ddns.net 2022 -``` - -### 認證失敗 - -確認密碼是否正確: -```bash -# 測試認證 -curl -u demo:demopassword123 \ - "https://momentry.ddns.net/webdav/" -I -``` - -### 權限不足 - -上傳目錄可能需要先建立: -```bash -sshpass -p "demopassword123" sftp -P 2022 demo@sftpgo.momentry.ddns.net <EnvironmentVariables - - SFTPGO_DEFAULT_ADMIN_USERNAME - admin - SFTPGO_DEFAULT_ADMIN_PASSWORD - Test3200Test3200 - -``` - -#### Step 3: 重啟 SFTPGo - -```bash -launchctl unload homebrew.mxcl.sftpgo -launchctl load homebrew.mxcl.sftpgo -``` - -#### Step 4: 驗證管理員 - -```bash -curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" -``` - -成功回應: -```json -{ - "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "token_type": "bearer", - "expires_in": 1200 -} -``` - -### REST API 認證流程 - -#### 1. 獲取 Token - -```bash -curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" -``` - -#### 2. 使用 Token 訪問 API - -```bash -TOKEN=$(curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" | jq -r '.access_token') - -# 查看所有用戶 -curl -s http://localhost:8080/api/v2/users \ - -H "Authorization: Bearer $TOKEN" - -# 查看系統狀態 -curl -s http://localhost:8080/api/v2/status \ - -H "Authorization: Bearer $TOKEN" -``` - -### 常用管理操作 - -#### 查看所有用戶 - -```bash -TOKEN=$(curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" | jq -r '.access_token') - -curl -s http://localhost:8080/api/v2/users \ - -H "Authorization: Bearer $TOKEN" | jq . -``` - -#### 建立新用戶 - -```bash -TOKEN=$(curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" | jq -r '.access_token') - -curl -s -X POST http://localhost:8080/api/v2/users \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "username": "newuser", - "password": "userpassword123", - "email": "user@example.com", - "status": 1, - "home_dir": "/Users/accusys/momentry/var/sftpgo/data/newuser", - "uid": 501, - "gid": 20, - "permissions": { - "/": ["*"] - } - }' -``` - -#### 建立用戶組 - -```bash -TOKEN=$(curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" | jq -r '.access_token') - -curl -s -X POST http://localhost:8080/api/v2/groups \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "editors", - "description": "Editor group with upload permissions" - }' -``` - -#### 刪除用戶 - -```bash -TOKEN=$(curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" | jq -r '.access_token') - -curl -s -X DELETE http://localhost:8080/api/v2/users/username \ - -H "Authorization: Bearer $TOKEN" -``` - -#### 修改用戶密碼 - -```bash -TOKEN=$(curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" | jq -r '.access_token') - -curl -s -X PUT http://localhost:8080/api/v2/users/demo \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "password": "newpassword456" - }' -``` - -### 重要設定 - -| 設定項目 | 值 | 說明 | -|----------|-----|------| -| **SFTP 連接埠** | `2022` | SSH 檔案傳輸協定 | -| **HTTP/WebDAV 連接埠** | `8080` | 內部 HTTP 服務 | -| **WebAdmin 連接埠** | `8080` | 管理介面 (`/web/admin`) | -| **WebClient 連接埠** | `8080` | 用戶介面 (`/web/client`) | -| **資料庫** | PostgreSQL | 用戶和設定儲存 | -| **Hook 腳本** | `/Users/accusys/sftpgo_test/register_hook.sh` | 上傳後自動化處理 | -| **安裝碼** | `Test3200Test3200` | 首次設定管理員所需 | -| **create_default_admin** | `true` | 自動創建管理員 | -| **Token 有效期** | 1200 秒 (20分鐘) | JWT 過期時間 | - -### 用戶目錄結構 - -所有 SFTPGo 用戶資料統一存放在 `/Users/accusys/momentry/var/sftpgo/data/` 目錄下: - -| 用戶 | 資料夾路徑 | 密碼 | 說明 | -|------|------------|------|------| -| **demo** | `/Users/accusys/momentry/var/sftpgo/data/demo` | `demopassword123` | Demo 用戶上傳目錄 | -| **momentry** | `/Users/accusys/momentry/var/sftpgo/data/momentry` | `momentry123` | Momentry 系統用戶 | -| **warren** | `/Users/accusys/momentry/var/sftpgo/data/warren` | `warren123` | 其他用戶 | - -### API Token 獲取方式 - -```bash -# 注意:使用 GET 而非 POST -curl -s -X GET "http://localhost:8080/api/v2/token" \ - -u "admin:Test3200Test3200" | jq .access_token -``` - -### 故障排除 - -| 問題 | 解決方案 | -|------|----------| -| 無法獲取 Token | 確認環境變數已正確設定並重啟 SFTPGo | -| SFTP 連線被拒絕 | 檢查 SFTPGo 服務: `launchctl list \| grep sftpgo` | -| 無法登入 WebAdmin | 確認 admin 用戶存在: 檢查 plist 中環境變數是否正確 | -| 上傳失敗 | 檢查 Hook 腳本: `tail -f /Users/accusys/momentry/log/sftpgo.error.log` | -| 權限不足 | 檢查用戶權限或更新 `permissions` 設定 | -| API 返回 401 | Token 過期,需重新獲取: `curl -X POST .../token -u "admin:pass"` | | - ---- - -## 安全注意事項 - -- **密碼保護**: `demopassword123` 為 demo 帳戶密碼 -- **限制存取**: Demo 用戶只能訪問 `/demo` 目錄 -- **監控**: 所有上傳都有日誌記錄 -- **生產環境**: 正式環境應使用更強的密碼和金鑰認證 diff --git a/docs_v1.0/IMPLEMENTATION/VIDEO_REGISTRATION.md b/docs_v1.0/IMPLEMENTATION/VIDEO_REGISTRATION.md deleted file mode 100644 index 9a8ccce..0000000 --- a/docs_v1.0/IMPLEMENTATION/VIDEO_REGISTRATION.md +++ /dev/null @@ -1,246 +0,0 @@ -# Video Registration - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-25 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-25 | 創建文件 | Warren | OpenCode | -| V1.1 | 2026-03-26 | 修正 curl 範例,新增 API Key 驗證標頭 | OpenCode | deepseek-reasoner | - ---- - -## 概述 - -影片註冊 API (`POST /api/v1/register`) 用於將影片加入 Momentry Core 系統進行處理。 - -## 路徑格式 - -### 支援的路徑格式 - -| 格式 | 範例 | 說明 | -|------|------|------| -| 相對路徑 | `./demo/video.mp4` | 推薦格式 | -| 相對路徑(無 ./) | `demo/video.mp4` | 自動加上 `./` | -| 絕對路徑 | `/Users/.../sftpgo/data/demo/video.mp4` | 支援但不推薦 | - -### 路徑結構 - -``` -./username/filepath -│ │ │ -│ │ └── 檔案路徑(可以是多層目錄) -│ └── 使用者名稱(SFTPgo 用戶目錄名稱) -└── 相對路徑前綴 -``` - -**範例**: -- `./demo/video.mp4` → username=`demo`, filepath=`video.mp4` -- `./demo/movies/2024/video.mp4` → username=`demo`, filepath=`movies/2024/video.mp4` -- `./warren/project1/interview.mp4` → username=`warren`, filepath=`project1/interview.mp4` - -## UUID 計算 - -### 計算規則 - -``` -UUID = SHA256(username/filepath)[0:16] -``` - -**範例**: -```rust -// 路徑: ./demo/video.mp4 -// username: "demo" -// filepath: "video.mp4" -// key: "demo/video.mp4" -// UUID: SHA256("demo/video.mp4")[0:16] -``` - -### 特性 - -| 特性 | 說明 | -|------|------| -| 用戶隔離 | 不同用戶的相同檔名會產生不同 UUID | -| 一致性 | 相同相對路徑一定產生相同 UUID | -| 遷移安全 | SFTPgo 資料路徑變更後 UUID 保持一致 | - -### 範例 - -```rust -// 用戶 demo 的影片 -compute_uuid_from_relative_path("./demo/video.mp4") -// → "9760d0820f0cf9a7" - -// 用戶 warren 的相同檔名影片 -compute_uuid_from_relative_path("./warren/video.mp4") -// → "a1b2c3d4e5f6g7h8" (不同的 UUID) -``` - -## 重複註冊檢查 - -### 行為 - -1. 系統檢查 UUID 是否已存在於資料庫 -2. 如果存在,返回 `already_exists: true` 和現有影片資訊 -3. 如果不存在,創建新的影片記錄 - -### API 回應 - -**新註冊**: -```json -{ - "uuid": "9760d0820f0cf9a7", - "video_id": 18, - "job_id": 2, - "file_name": "video.mp4", - "duration": 159.637188, - "width": 640, - "height": 360, - "already_exists": false -} -``` - -**重複註冊**: -```json -{ - "uuid": "9760d0820f0cf9a7", - "video_id": 18, - "job_id": 2, - "file_name": "video.mp4", - "duration": 159.637188, - "width": 640, - "height": 360, - "already_exists": true -} -``` - -## SFTPgo 整合 - -### 目錄結構 - -SFTPgo 的用戶目錄結構: - -``` -/Users/accusys/momentry/var/sftpgo/data/ -├── demo/ ← 用戶目錄 -│ ├── video.mp4 -│ └── movies/ -│ └── movie1.mp4 -├── warren/ ← 用戶目錄 -│ └── project1/ -│ └── interview.mp4 -└── momentry/ ← 用戶目錄 - └── presentation.mp4 -``` - -### 註冊流程 - -1. SFTPgo 用戶上傳檔案到各自的目錄 -2. n8n 或其他服務調用註冊 API -3. 使用相對路徑格式:`./username/filepath` -4. 系統計算 UUID 並檢查重複 -5. 創建處理任務 - -## 程式碼範例 - -### 註冊影片 - -```bash -# 使用相對路徑註冊 -curl -X POST http://localhost:3002/api/v1/register \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"path": "./demo/video.mp4"}' - -# 或使用多層目錄 -curl -X POST http://localhost:3002/api/v1/register \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"path": "./demo/movies/2024/video.mp4"}' -``` - -### UUID 計算函數 - -```rust -// 使用相對路徑計算 UUID -pub fn compute_uuid_from_relative_path(relative_path: &str) -> String { - let (username, filepath) = extract_user_from_relative_path(relative_path); - compute_uuid(&username, &filepath) -} - -// 從相對路徑提取用戶名和檔案路徑 -pub fn extract_user_from_relative_path(relative_path: &str) -> (String, String) { - let path = relative_path.strip_prefix("./").unwrap_or(relative_path); - let path_buf = PathBuf::from(path); - - let mut components = path_buf.components(); - let username = components - .next() - .map(|c| c.as_os_str().to_string_lossy().to_string()) - .unwrap_or_default(); - - let filepath: String = components - .map(|c| c.as_os_str().to_string_lossy().to_string()) - .collect::>() - .join("/"); - - (username, filepath) -} -``` - -## 相關 API - -### Probe API(僅探測,不註冊) - -如果只需要取得影片資訊而不註冊,可以使用 Probe API: - -```bash -curl -X POST http://localhost:3002/api/v1/probe \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"path": "./demo/video.mp4"}' -``` - -**回應範例**: -```json -{ - "uuid": "a1b10138a6bbb0cd", - "file_name": "video.mp4", - "duration": 120.5, - "width": 1920, - "height": 1080, - "fps": 30.0, - "cached": false, - "format": {...}, - "streams": [...] -} -``` - -**與 Register API 的差異**: - -| 功能 | Probe API | Register API | -|------|-----------|---------------| -| 計算 UUID | ✓ | ✓ | -| 執行 ffprobe | ✓ | ✓ | -| 儲存 probe.json | ✓ | ✓ | -| 寫入 videos 表 | ✗ | ✓ | -| 建立 monitor_job | ✗ | ✓ | -| 返回 job_id | ✗ | ✓ | -| 適用場景 | 預覽影片資訊 | 註冊並處理影片 | - -## 相關檔案 - -| 檔案 | 說明 | -|------|------| -| `src/core/storage/uuid.rs` | UUID 計算邏輯 | -| `src/api/server.rs` | 註冊與 Probe API 實現 | -| `src/core/probe/ffprobe.rs` | ffprobe 整合 | -| `docs/SFTPGO_DEMO_USER.md` | SFTPgo 用戶設置 | -| `docs/API_ENDPOINTS.md` | API 端點總覽 | diff --git a/docs_v1.0/OPERATIONS/DEVELOPMENT_LOG.md b/docs_v1.0/OPERATIONS/DEVELOPMENT_LOG.md deleted file mode 100644 index 3c30a41..0000000 --- a/docs_v1.0/OPERATIONS/DEVELOPMENT_LOG.md +++ /dev/null @@ -1,540 +0,0 @@ -# Momentry Core 開發日誌 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-18 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-18 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | - ---- - -> **文檔維護開始**:2026-03-18 -> **⚠️ 補充說明**:事後補記(2026-03-18 以前),僅供參考。未來紀錄將即時記錄,參考價值較高。 - ---- - -## 開發工具 - -### Coding LLM 模型 - -| 階段 | 工具 | 模型 | ID | 說明 | -|------|------|------|-----|------| -| **初期** | Claude CLI | - | - | 初始專案架構建立 | -| **中期** | OpenCode | big-pickle | opencode/big-pickle | 主要開發協作者 | - -**切換記錄**: -- 初期使用 Claude CLI 建立專案基本架構 -- 中期切換至 OpenCode (big-pickle) 進行主要功能開發 - ---- - -## 2026-03-17 - -### ML 模型選用 - -| Processor | 模型 | 版本/大小 | 說明 | -|----------|------|-----------|------| -| **ASR** | WhisperX (faster-whisper) | base, int8 | 語音識別 + 對話分段 | -| **CUT** | PySceneDetect | 0.6.7.1 | ContentDetector 場景檢測 | -| **YOLO** | YOLOv8n | yolov8n.pt (6.2MB) | 物體檢測(nano 版本最快) | -| **OCR** | EasyOCR | 1.7.2 | 文字識別 | -| **Face** | OpenCV Haar Cascade | built-in | 人臉檢測(無需額外下載) | -| **Pose** | YOLOv8n-Pose | yolov8n-pose.pt (6.5MB) | 姿態估計(nano 版本) | - -**模型下載**: -- YOLOv8n: `yolov8n.pt` (6.2MB) -- YOLOv8n-Pose: `yolov8n-pose.pt` (6.5MB) - -**Python 依賴**: -``` -torch==2.8.0 -whisperx==3.8.2 -ultralytics==8.4.23 -scenedetect==0.6.7.1 -easyocr==1.7.2 -opencv-python==4.13.0.92 -``` - ---- - -### ASR 實作完成 -- 完成 Python ML processor scripts(使用本地模型) - - `asrx_processor.py` - whisperx for speaker diarization - - `cut_processor.py` - PySceneDetect for scene detection - - `yolo_processor.py` - YOLOv8 for object detection - - `ocr_processor.py` - EasyOCR for text recognition - - `face_processor.py` - OpenCV Haar Cascade for face detection - - `pose_processor.py` - YOLOv8 Pose for pose estimation - -- 更新 `requirements.txt` with all dependencies -- 安裝完成:torch 2.8.0, whisperx 3.8.2, ultralytics 8.4.23, scenedetect 0.6.7.1, easyocr 1.7.2, opencv-python 4.13.0.92 -- 下載模型:YOLOv8n.pt (6.2MB), YOLOv8n-Pose.pt (6.5MB) - -### Async Streaming 實作 -- 更新 Rust processor modules 使用 async streaming 進行 real-time progress - - `src/core/processor/asr.rs` - - `src/core/processor/cut.rs` - - `src/core/processor/yolo.rs` - - `src/core/processor/ocr.rs` - - `src/core/processor/face.rs` - - `src/core/processor/pose.rs` - -### 測試結果 -- 測試影片:BigBuckBunny_320x180.mp4 -- ASR: 4 segments -- CUT: 134 scenes -- YOLO: 14315 frames(每幀處理耗時) -- OCR: 40 frames with text -- Face: 44 frames with faces -- Pose: Timeout - ---- - -### Warning 清理 -修復 clippy warnings: -- 移除未使用的 imports (HashMap in mongodb_db.rs, postgres_db.rs) -- 新增 `#[allow(dead_code)]` 標註未使用變數 -- 新增 `Default` implementation for MongoDb, QdrantDb -- 將 `probe` module 重新命名為 `ffprobe` -- 新增 `player` feature in Cargo.toml -- 修復 `format_in_format_args` 警告 - ---- - -### TUI Progress Window 實作 -建立新的 UI module: -- 建立 `src/ui/mod.rs` -- 建立 `src/ui/progress/mod.rs` - -實作功能: -- ProcessorProgress 結構(追蹤每個 processor 狀態) -- ProgressState 結構(管理所有 processors) -- ProgressUi 結構(ratatui TUI 渲染) -- 整合到 `src/main.rs` 的 process 命令 - -TUI 顯示: -``` -┌ Processing: BigBuckBunny_320x180.mp4 ────────────────────────────────────────┐ -│ ASR [████████████] 100% (4 segs) │ -│ CUT [████████████] 100% (134 scenes) │ -│ ASRX [████████████] 100% (0 segs) │ -│ YOLO [██░░░░░░░░░░░] 30% (4200/14315) ETA 2:30 │ -│ OCR [---------] 0% │ -│ Face [---------] 0% │ -│ Pose [---------] 0% │ -└──────────────────────────────────────────────────────────────────────────────┘ -``` - ---- - -### 輸出位置討論 -討論 stdout vs stderr vs TUI 的輸出配置: -- 最終結果 → stdout -- Python progress → 需改用 Redis Pub/Sub -- TUI Progress → stderr (ratatui) - ---- - -## 2026-03-18 - -### Redis Message Bus 設計 -討論使用 Redis 作為消息總線,分離 Python 輸出與 Rust TUI 顯示。 - -設計重點: -1. 頻道命名:`momentry:progress:{uuid}` -2. 本地 Redis:`localhost:6379` -3. 失敗策略:完全失效(因 stdout 問題未解決) - -### UUID 使用時機分析 -分析 Redis Key 上使用 UUID 的時機: - -**全局 Keys(無 UUID)**: -- health, stats, jobs 管理 - -**Per-Video Keys(UUID 必要)**: -- job:{uuid}, progress:{uuid}, metrics:{uuid} - -**Per-Processor Keys(UUID + Processor 必要)**: -- job:{uuid}:processor:{name} - -### 備份系統整合 -參考 `docs/SERVICE_ADDITION_GUIDE.md` 設計規範,規劃 OutputDir 模組: - -1. **環境變數**: - - `MOMENTRY_OUTPUT_DIR` - JSON 輸出目錄 - - `MOMENTRY_BACKUP_DIR` - 備份目錄(預設:`/Users/accusys/momentry/backup/momentry`) - - `MOMENTRY_BACKUP_ENABLED` - 啟用備份 - -2. **命名格式**: - - 備份格式:`momentry_data_{YYYYMMDD}_{HHMMSS}_{uuid}.{ext}` - - 校驗和:`{filename}.sha256` - -3. **CLI 命令**: - - `cargo run -- backup list` - 列出備份 - - `cargo run -- backup cleanup` - 清理舊備份 - - `cargo run -- backup verify` - 驗證備份 - ---- - -### 監控系統整合 -討論將 momentry_core 納入監控系統: - -1. **Layer 2: Service 監控** - - 新增 momentry_core CLI 檢查 - -2. **Layer 7: Backup 監控** - - 新增 momentry 備份配置 - -3. **Redis 監控** - - 健康檢查 - - Job 狀態監控 - - 即時進度監控 - ---- - -## 實作完成項目 - -### 程式碼變更 - -| 日期 | 檔案 | 變更 | -|------|------|------| -| 2026-03-17 | `src/core/processor/*.rs` | Async streaming 更新 | -| 2026-03-17 | `src/ui/mod.rs` | 新增 UI module | -| 2026-03-17 | `src/ui/progress/mod.rs` | 新增 Progress TUI | -| 2026-03-17 | `src/main.rs` | 整合 Progress UI | -| 2026-03-18 | `src/core/storage/output_dir.rs` | 新增 OutputDir 模組 | -| 2026-03-18 | `src/core/storage/mod.rs` | 新增 output_dir export | -| 2026-03-18 | `src/core/db/redis_client.rs` | 新增 Redis 客戶端(Hash + Pub/Sub) | -| 2026-03-18 | `src/core/db/mod.rs` | 新增 redis_client export | - -### 新增檔案 - -| 日期 | 檔案 | 說明 | -|------|------|------| -| 2026-03-18 | `docs/MOMENTRY_CORE_REDIS_KEYS.md` | Redis Key 設計規範 | -| 2026-03-18 | `docs/MOMENTRY_CORE_MONITORING.md` | 監控規範(暫定) | -| 2026-03-18 | `scripts/redis_publisher.py` | Redis 訊息發布模組 | - -### 更新檔案 - -| 日期 | 檔案 | 說明 | -|------|------|------| -| 2026-03-17 | `Cargo.toml` | 新增 player feature | -| 2026-03-17 | `src/lib.rs` | 新增 ui module exports | -| 2026-03-18 | `docs/PENDING_ISSUES.md` | 新增問題 #2, #3 | -| 2026-03-18 | `src/core/storage/output_dir.rs` | 預設改為 `./output` | -| 2026-03-18 | `scripts/yolo_processor.py` | 新增 --uuid 參數 + Redis | -| 2026-03-18 | `scripts/cut_processor.py` | 新增 Redis | -| 2026-03-18 | `scripts/ocr_processor.py` | 新增 Redis | -| 2026-03-18 | `scripts/face_processor.py` | 新增 --uuid 參數 + Redis | -| 2026-03-18 | `scripts/pose_processor.py` | 新增 --uuid 參數 + Redis | -| 2026-03-18 | `scripts/asr_processor.py` | 新增 --uuid 參數 + Redis | -| 2026-03-18 | `scripts/asrx_processor.py` | 新增 --uuid 參數 + Redis | -| 2026-03-18 | `requirements.txt` | 新增 redis>=5.0.0 | -| 2026-03-18 | `src/core/processor/yolo.rs` | 新增 uuid 參數 | -| 2026-03-18 | `src/core/processor/cut.rs` | 新增 uuid 參數 | -| 2026-03-18 | `src/core/processor/ocr.rs` | 新增 uuid 參數 | -| 2026-03-18 | `src/core/processor/face.rs` | 新增 uuid 參數 | -| 2026-03-18 | `src/core/processor/pose.rs` | 新增 uuid 參數 | -| 2026-03-18 | `src/core/processor/asr.rs` | 新增 uuid 參數 | -| 2026-03-18 | `src/core/processor/asrx.rs` | 新增 uuid 參數 | -| 2026-03-18 | `src/main.rs` | 更新所有 processor 調用傳入 uuid | -| 2026-03-18 | `Cargo.toml` | 新增 futures-util 依賴 | -| 2026-03-18 | `src/core/db/redis_client.rs` | 新增 subscribe_and_callback 方法,密碼認證 | -| 2026-03-18 | `src/ui/progress/mod.rs` | 新增 update_from_redis 方法 | -| 2026-03-18 | `scripts/redis_publisher.py` | 新增密碼認證支援 | -| 2026-03-18 | 測試 | Redis Pub/Sub 成功運作 | - ---- - -## 待解決問題 - -### 問題 #1: sqlx async INSERT 不會實際寫入數據庫 -- 狀態:待解決 -- 影響:`store_vector` 函數,PVector 存儲 - -### 問題 #2: TUI 與 stdout 輸出混合 -- 狀態:已解決 -- 解決方案:使用 Redis Message Bus -- 進度: - - ✅ Redis 客戶端 (`src/core/db/redis_client.rs`) - - ✅ Python redis_publisher.py - - ✅ 所有 Python processors 更新完成 - - ✅ 所有 Rust processor 函數更新完成 - - ✅ main.rs 調用更新完成 - - ✅ Rust TUI Redis 訂閱已完成 - -### 問題 #3: Redis Message Bus 尚未實作 -- 狀態:已解決 -- 詳細設計:參考 `docs/MOMENTRY_CORE_REDIS_KEYS.md` -- 進度:Python 端 + Rust 端均已完成 - ---- - -## 環境變數 - -```bash -# 輸出目錄 -MOMENTRY_OUTPUT_DIR=./output # 預設 - -# 備份 -MOMENTRY_BACKUP_ENABLED=false # 預設 -MOMENTRY_BACKUP_DIR=/Users/accusys/momentry/backup/momentry - -# Redis(未來實作) -REDIS_URL=redis://localhost:6379 -REDIS_PASSWORD=accusys -``` - ---- - -## 數據庫 - -- PostgreSQL: `postgres://accusys@localhost:5432/momentry` -- Redis: `localhost:6379`(待實作) -- Qdrant: `localhost:6333` - ---- - -## 指令範例 - -```bash -# 註冊視頻 -cargo run -- register /path/to/video.mp4 - -# 處理視頻 -cargo run -- process - -# 列出備份 -cargo run -- backup list - -# 清理備份 -cargo run -- backup cleanup - -# 驗證備份 -cargo run -- backup verify - -# 查看狀態 -cargo run -- status - -# API Server -cargo run -- server --host 0.0.0.0 --port 3000 -``` - ---- - -## 2026-03-18 (進行中) - -### Redis Message Bus 實作 - -**問題**:TUI 與 Python stdout 輸出混合,導致 TUI 顯示混亂 - -**解決方案**:使用 Redis Pub/Sub 作為訊息匯流排 - -**實作內容**: - -| 元件 | 檔案 | 狀態 | -|------|------|------| -| Redis 客戶端 | `src/core/db/redis_client.rs` | ✅ | -| Progress 訂閱 | `src/main.rs` | ✅ | -| UI 更新 | `src/ui/progress/mod.rs` | ✅ | -| Python Publisher | `scripts/redis_publisher.py` | ✅ | -| Python Processors | 7 個 `scripts/*_processor.py` | ✅ | -| Rust 函數 | `src/core/processor/*.rs` | ✅ | - -**流程**: -``` -Python Processor ──(Redis Pub)──> Redis ──(Subscribe)──> Rust TUI -``` - -**測試結果**: -- Redis 連線 ✅ -- 密碼認證 ✅ -- 即時進度發布 ✅ -- TUI 即時更新 ✅ - -**新增依賴**: -- `futures-util = "0.3"` (Cargo.toml) -- `redis >= 5.0.0` (requirements.txt) - ---- - -## 2026-03-18 (HTTP API) - -### HTTP API 實作 - -**問題**:TUI 運作正常但使用者偏好 HTTP API 來查詢進度 - -**解決方案**:建立 HTTP 端點 + Redis Hash 儲存 - -**實作內容**: - -| 元件 | 檔案 | 變更 | -|------|------|------| -| HTTP 端點 | `src/api/server.rs` | 新增 `/api/v1/progress/:uuid` | -| Redis Hash 查詢 | `src/core/db/redis_client.rs` | 新增 `get_processor_status` 方法 | -| Progress 儲存 | `src/main.rs` | 新增 Redis HSET 儲存進度 | - -**API 端點**: -``` -GET /api/v1/progress/:uuid - -Response: -{ - "uuid": "5dea6618a606e7c7", - "processors": [ - {"name": "asr", "status": "complete", "current": 0, "total": 0, "message": "7 segments"}, - {"name": "cut", "status": "complete", "current": 134, "total": 134, "message": "134 scenes"}, - {"name": "yolo", "status": "complete", "current": 14300, "total": 14315, "message": "..."}, - ... - ] -} -``` - -**流程**: -``` -Python Processor ──(Redis Pub)──> Redis ──(Subscribe)──> Rust TUI - └──(HSET)──> Redis Hash - │ -HTTP Client ──(GET /progress/:uuid)──> Rust API ─(HGETALL)──> Redis Hash -``` - -**測試結果**: -- ✅ 編譯成功 -- ✅ API 伺服器啟動 (port 3002) -- ✅ 即時進度查詢 -- ✅ 完整流程測試 (BigBuckBunny_320x180.mp4) - -**除錯記錄**: -1. 語法錯誤:main.rs 有重複程式碼區塊 (lines 297-322),已移除 -2. DB 連線池:從 5 增加到 10 個連線 -3. PostgreSQL 狀態:處理 shutdown 狀態,殺掉 stale 連線 - -**新增變更**: -- `src/api/server.rs` - 新增進度端點 -- `src/core/db/redis_client.rs` - 新增 `get_processor_status` 方法 -- `src/core/db/postgres_db.rs` - 連線池 5→10 -- `src/main.rs` - Redis Hash 儲存 + 語法修復 - -**使用方式**: -```bash -# 啟動 API 伺服器 -cargo run --bin momentry -- server --host 127.0.0.1 --port 3002 - -# 註冊影片 -cargo run --bin momentry -- register ~/test_video/BigBuckBunny_320x180.mp4 - -# 處理影片 -cargo run --bin momentry -- process - -# 查詢進度 -curl http://127.0.0.1:3002/api/v1/progress/ -``` - ---- - -## 2026-03-18 (Dashboard) - -### Web Dashboard 實作 - -**目標**:建立 Web 介面監控 momentry_core 處理進度 - -**技術選擇**:Static HTML + JavaScript (非 WASM) - -**實作內容**: - -| 元件 | 檔案 | 說明 | -|------|------|------| -| Dashboard | `momentry_dashboard/dist/index.html` | 靜態 HTML 頁面 | -| API 代理 | Caddyfile port 3200 | 反向代理到 API server | - -**功能**: -- 影片列表顯示 -- 即時進度條 (每 5 秒自動刷新) -- 搜尋功能 -- 處理器狀態 (ASR/CUT/YOLO/OCR/Face/Pose) - -**訪問**: -- Dashboard: http://localhost:3200 -- API: http://localhost:3200/api/v1/* - ---- - -## 發生問題記錄 - -### HTTP API 問題 - -1. **語法錯誤** (main.rs) - - 位置:lines 297-322 - - 原因:重複的程式碼區塊 - - 解決:移除重複區塊 - -2. **DB 連線池耗盡** - - 原因:預設 5 個連線不足 - - 解決:增加到 10 個連線 - -3. **PostgreSQL shutdown 狀態** - - 原因:共享記憶體未釋放 - - 解決:殺掉 stale 連線 - -### WASM Dashboard 問題 - -1. **Yew 版本問題** - - 嘗試:yew 0.21 → 0.23 - - 問題:feature 名稱變更 (`web-sys` → `web_sys` → `csr`) - - 解決:放棄 WASM,改用靜態 HTML - -2. **編譯錯誤** - - `wasm32-unknown-unknown` target 未安裝 - - 解決:`rustup target add wasm32-unknown-unknown` - -3. **Yew 0.23 API 變更** - - Properties 需要 PartialEq derive - - 多處 API 語法變更 - - 放棄 WASM 方案 - -### Gitea Push 問題 - -1. **Remote URL 錯誤** - - 原因:使用 localhost:3000 而非 gitea.momentry.ddns.net - - 解決:建立新 repo `momentry_core_0_1` - -2. **認證問題** - - SSH key 未授權 - - 密碼認證成功推送 - -### Caddy 設定問題 - -1. **API 代理順序** - - 問題:try_files 在 reverse_proxy 之前導致 API 回傳 HTML - - 解決:使用 `handle` 區塊明確定義順序 - -```caddyfile -:3200 { - handle /api/* { - reverse_proxy localhost:3002 - } - handle { - root * /Users/accusys/momentry_dashboard/dist - try_files {path} /index.html - file_server - } -} -``` - ---- - -## 未來工作 - -- [ ] 修復 WASM Dashboard (Yew 0.23 相容性) -- [ ] 新增影片播放器整合 -- [ ] WebSocket 實時推送 -- [ ] 移動端響應式設計 diff --git a/docs_v1.0/OPERATIONS/MOMENTRY_CORE_REDIS_KEYS.md b/docs_v1.0/OPERATIONS/MOMENTRY_CORE_REDIS_KEYS.md deleted file mode 100644 index cabef36..0000000 --- a/docs_v1.0/OPERATIONS/MOMENTRY_CORE_REDIS_KEYS.md +++ /dev/null @@ -1,283 +0,0 @@ -# Momentry Core Redis Key 設計規範 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-17 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-17 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-25 | 新增可配置 Redis Key Prefix | Warren | OpenCode / GLM-5 | - ---- - -## 1. 概述 - -本文檔說明 momentry_core 如何使用 Redis 作為監控和狀態管理系統。 - -## 2. 可配置 Redis Key Prefix - -### 2.1 環境變數 - -從 V1.1 開始,所有 Redis Keys 都支援自定義前綴: - -```bash -MOMENTRY_REDIS_PREFIX=momentry: -``` - -此設定允許多個 momentry 實例共用同一個 Redis 伺服器,例如: -- **生產環境**: `MOMENTRY_REDIS_PREFIX=momentry:` -- **開發環境**: `MOMENTRY_REDIS_PREFIX=momentry_dev:` - -### 2.2 Key 格式 - -所有 Key 都遵循以下格式: - -``` -{prefix}{key_type}:{uuid} -``` - -範例 (生產環境): -``` -momentry:job:5dea6618a606e7c7 -momentry:jobs:active -momentry:health:current -``` - -範例 (開發環境): -``` -momentry_dev:job:5dea6618a606e7c7 -momentry_dev:jobs:active -momentry_dev:health:current -``` - -### 2.3 預設值 - -| Binary | 預設 Port | 預設 Redis Prefix | -|--------|-----------|-------------------| -| `momentry` (生產) | 3002 | `momentry:` | -| `momentry_playground` (開發) | 3003 | `momentry_dev:` | - -## 3. UUID 使用時機 - -### 3.1 全局 Keys(無 UUID) - -- 單一實例全局狀態 -- 聚合統計數據 - -### 3.2 Per-Video Keys(UUID 必要) - -- 每個視頻獨立處理狀態 -- 即時進度追蹤 - -### 3.3 Per-Processor Keys(UUID + Processor 必要) - -- 每個 processor 獨立狀態 - -## 4. Key 命名空間 - -``` -momentry -├── health: # 健康檢查 -│ ├── current # 當前狀態 (TTL: 60s) -│ └── services # 依賴服務狀態 -├── config: # 配置 -├── stats: # 聚合統計 -│ ├── total_jobs # 總 Jobs 數 -│ ├── processed_today # 今日處理數 -│ ├── cpu:current # 當前 CPU 使用 -│ └── memory:current # 當前 Memory 使用 -├── jobs: # Jobs 管理 -│ ├── active # Set: 運行中 UUIDs -│ ├── completed # Set: 完成 UUIDs -│ └── failed # Set: 失敗 UUIDs -├── job:{uuid} # Per-Video Job 狀態 (TTL: 24h) -│ ├── status # 狀態 String -│ ├── video_path # 視頻路徑 -│ ├── current_processor # 當前 processor -│ ├── progress_total # 總進度 -│ ├── progress_current # 當前進度 -│ ├── started_at # 開始時間 -│ ├── updated_at # 最後更新 -│ └── processor:{name} # Per-Processor 狀態 -│ ├── status -│ ├── progress -│ ├── current -│ ├── total -│ └── started_at -├── progress:{uuid} # Pub/Sub 頻道 (即時進度) -├── result:{uuid} # 處理結果 Hash -├── output:{uuid} # 輸出路徑 -├── metrics:{uuid} # Per-Video 指標 -│ ├── cpu # CPU 歷史 List (100條, TTL: 1h) -│ ├── memory # Memory 歷史 List (100條, TTL: 1h) -│ └── duration # 處理時長 -└── log:{uuid} # 處理日誌 String -``` - -## 5. Key 詳細說明 - -### 全局 Keys - -| Key | Type | TTL | 說明 | -|-----|------|-----|------| -| `momentry:health:current` | String | 60s | 當前健康狀態 | -| `momentry:health:services` | Hash | 60s | 依賴服務健康狀態 | -| `momentry:stats:total_jobs` | String | - | 總 Jobs 數 | -| `momentry:stats:processed_today` | String | 86400s | 今日處理數 | -| `momentry:stats:cpu:current` | String | 10s | 當前 CPU 使用 | -| `momentry:stats:memory:current` | String | 10s | 當前 Memory 使用 | -| `momentry:jobs:active` | Set | - | 運行中 Job UUIDs | -| `momentry:jobs:completed` | Set | - | 完成 Job UUIDs | -| `momentry:jobs:failed` | Set | - | 失敗 Job UUIDs | - -### Per-Video Keys - -| Key | Type | TTL | 說明 | -|-----|------|-----|------| -| `momentry:job:{uuid}` | Hash | 24h | Job 完整狀態 | -| `momentry:job:{uuid}:status` | String | 24h | Job 狀態 | -| `momentry:progress:{uuid}` | Pub/Sub | - | 即時進度頻道 | -| `momentry:result:{uuid}` | Hash | 24h | 處理結果 | -| `momentry:output:{uuid}` | String | 24h | 輸出路徑 | -| `momentry:metrics:{uuid}:cpu` | List | 1h | CPU 歷史 (100條) | -| `momentry:metrics:{uuid}:memory` | List | 1h | Memory 歷史 (100條) | -| `momentry:metrics:{uuid}:duration` | String | 24h | 處理時長 | -| `momentry:log:{uuid}` | String | 24h | 處理日誌 | - -### Per-Processor Keys - -| Key | Type | TTL | 說明 | -|-----|------|-----|------| -| `momentry:job:{uuid}:processor:{name}` | Hash | 24h | Processor 狀態 | -| `momentry:job:{uuid}:processor:{name}:status` | String | 24h | 狀態 | -| `momentry:job:{uuid}:processor:{name}:progress` | String | 24h | 進度百分比 | -| `momentry:job:{uuid}:processor:{name}:current` | String | 24h | 當前項目 | -| `momentry:job:{uuid}:processor:{name}:total` | String | 24h | 總項目數 | -| `momentry:job:{uuid}:processor:{name}:started_at` | String | 24h | 開始時間 | - -## 6. TTL 策略 - -| Key 類型 | TTL | 原因 | -|----------|-----|------| -| Health | 60s | 需要定期更新 | -| Job | 24h | 處理完成後保留一天 | -| Processor | 24h | 處理完成後保留一天 | -| Metrics | 1h | 只保留近期歷史 | -| Progress Pub/Sub | - | 不持久,僅即時訊息 | -| Stats | 無 | 持久統計 | - -## 7. 訊息格式 - -### Pub/Sub 訊息 (progress:{uuid}) - -```json -{ - "type": "info | progress | complete | error", - "processor": "yolo | ocr | face | pose | cut | asr | asrx", - "timestamp": 1700000000, - "data": { - "message": "Processing frame 5000", - "current": 5000, - "total": 14315 - } -} -``` - -### Job 狀態 Hash - -```json -{ - "uuid": "5dea6618a606e7c7", - "video_path": "/path/to/video.mp4", - "status": "running", - "current_processor": "yolo", - "progress_total": 70, - "progress_current": 50, - "started_at": 1700000000, - "updated_at": 1700000100, - "error_count": 0, - "last_error": "" -} -``` - -### Processor 狀態 Hash - -```json -{ - "name": "yolo", - "status": "running", - "progress": 70, - "current_frame": 10000, - "total_frames": 14315, - "started_at": 1700000000, - "updated_at": 1700000100 -} -``` - -## 8. 實作函數 (Rust) - -所有 Redis Key 生成函數使用 `REDIS_KEY_PREFIX` 靜態變數: - -```rust -use crate::core::config::REDIS_KEY_PREFIX; - -fn global_key(key: &str) -> String { - format!("{}{}", REDIS_KEY_PREFIX, key) -} - -fn job_key(uuid: &str) -> String { - format!("{}job:{}", REDIS_KEY_PREFIX, uuid) -} - -fn processor_key(uuid: &str, processor: &str) -> String { - format!("{}job:{}:processor:{}", REDIS_KEY_PREFIX, uuid, processor) -} - -fn progress_channel(uuid: &str) -> String { - format!("{}progress:{}", REDIS_KEY_PREFIX, uuid) -} - -fn metrics_key(uuid: &str, metric: &str) -> String { - format!("{}metrics:{}:{}", REDIS_KEY_PREFIX, uuid, metric) -} - -fn jobs_set_key(status: &str) -> String { - format!("{}jobs:{}", REDIS_KEY_PREFIX, status) -} -``` - -**注意**: `REDIS_KEY_PREFIX` 定義於 `src/core/config.rs`,由環境變數 `MOMENTRY_REDIS_PREFIX` 控制。 - -## 9. 環境變數 - -```bash -# Redis 連接 -REDIS_URL=redis://localhost:6379 -REDIS_PASSWORD=accusys -REDIS_DB=0 - -# Redis Key Prefix (可選,預設: momentry:) -MOMENTRY_REDIS_PREFIX=momentry: - -# 生產環境範例 (.env) -MOMENTRY_SERVER_PORT=3002 -MOMENTRY_REDIS_PREFIX=momentry: - -# 開發環境範例 (.env.development) -MOMENTRY_SERVER_PORT=3003 -MOMENTRY_REDIS_PREFIX=momentry_dev: -``` - -## 11. 監控腳本 - -使用 Redis 進行監控的腳本應參考: - -- `monitor/service/momentry_redis_monitor.sh` - Redis 健康檢查 -- `monitor/service/momentry_job_monitor.sh` - Job 狀態監控 diff --git a/docs_v1.0/OPERATIONS/MOMENTRY_RAG_PRESENTATION.md b/docs_v1.0/OPERATIONS/MOMENTRY_RAG_PRESENTATION.md deleted file mode 100644 index be7e58b..0000000 --- a/docs_v1.0/OPERATIONS/MOMENTRY_RAG_PRESENTATION.md +++ /dev/null @@ -1,334 +0,0 @@ -# Momentry Core 影片 RAG 系統說明稿 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-22 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-25 | 更新API回應格式 (media_url→file_path) 與認證標頭 | OpenCode | deepseek-reasoner | - ---- - -## 系統架構 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ 使用者 │ -│ (marcom 團隊) │ -└─────────────────┬───────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ WordPress 入口 │ -│ (wp.momentry.ddns.net) │ -└─────────────────┬───────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ n8n 自動化 │ -│ (localhost:5678) │ -│ │ -│ [Webhook] → [HTTP Request] → [處理結果] → [回覆用戶] │ -└─────────────────┬───────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Momentry Core API │ -│ (localhost:3002) │ -│ │ -│ POST /api/v1/search → 語意搜尋 │ -│ POST /api/v1/n8n/search → n8n 專用格式 │ -│ GET /api/v1/videos → 影片列表 │ -└─────────────────┬───────────────────────────────────────────┘ - │ - ┌─────────┴──────────┐ - ▼ ▼ -┌───────────────┐ ┌───────────────┐ -│ PostgreSQL │ │ Qdrant │ -│ (chunks) │ │ (vectors) │ -└───────────────┘ └───────────────┘ -``` - ---- - -## 資料流程 - -``` -1. 上傳影片 → SFTPGo -2. 影片註冊 → PostgreSQL -3. ASR 處理 → 產生字幕區塊 -4. 儲存 chunks → PostgreSQL -5. 向量化 → Qdrant -6. 搜尋查詢 → API -7. 回傳結果 → n8n → 用戶 -``` - ---- - -## 示範影片 - -| 項目 | 內容 | -|------|------| -| 檔案名稱 | Old_Time_Movie_Show_-_Charade_1963.HD.mov | -| UUID | a1b10138a6bbb0cd | -| 時長 | 6879 秒(約 1.9 小時) | -| 區塊數 | 3,886 個 | -| 向量數 | 3,688 個 | - ---- - -## API 端點 - -### 1. 語意搜尋 - -``` -POST http://localhost:3002/api/v1/search -``` - -**請求:** -```json -{ - "query": "charade", - "limit": 5, - "uuid": "a1b10138a6bbb0cd" -} -``` - -> **注意**: -> 1. **API 認證**: 所有 `/api/v1/*` 端點需要 `X-API-Key` 標頭 -> 2. **檔案路徑轉換**: API 現在返回 `file_path`(檔案系統路徑),需要轉換為可訪問的 URL(例如透過 SFTPGo 分享連結) - ---- - -### 2. n8n 專用格式 - -``` -POST http://localhost:3002/api/v1/n8n/search -``` - -**請求:** -```json -{ - "query": "charade", - "limit": 5 -} -``` - -**回應:** -```json -{ - "query": "charade", - "count": 5, - "hits": [ - { - "id": "sentence_0006", - "vid": "a1b10138a6bbb0cd", - "start": 48.8, - "end": 55.44, - "title": "Chunk sentence_0006", - "text": "fun plot twists...", - "score": 0.526, - "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4" - } - ] -} -``` - ---- - -## 實作範例 - -### n8n Workflow 設計 - -``` -┌─────────────┐ -│ Webhook │ ← 接收用戶搜尋請求 -└──────┬──────┘ - │ - ▼ -┌─────────────┐ -│ HTTP Request│ → POST /api/v1/n8n/search -└──────┬──────┘ - │ - ▼ -┌─────────────┐ -│ Code │ → 處理回傳結果 -└──────┬──────┘ - │ - ▼ -┌─────────────┐ -│ Telegram │ → 回覆給用戶 -│ (或 LINE) │ -└─────────────┘ -``` - ---- - -## Step-by-Step n8n Workflow - -### Step 1: 建立 Webhook - -1. n8n 開新 Workflow -2. 新增 node: **Webhook** -3. 設定 path: `video-search` -4. 複製 Webhook URL - ---- - -### Step 2: 設定 HTTP Request - -1. 新增 node: **HTTP Request** -2. 設定: - ``` - Method: POST - URL: http://localhost:3002/api/v1/n8n/search - Body Content Type: JSON - Headers: X-API-Key (需設定) - ``` - -3. Body: -```json -{ - "query": "={{ $json.body }}", - "limit": 5 -} -``` - ---- - -### Step 3: 處理結果 (Code) - -```javascript -const hits = $input.first().json.hits; - -if (!hits || hits.length === 0) { - return { - json: { message: "找不到相關結果" } - }; -} - -const results = hits.map((hit, index) => ({ - number: index + 1, - text: hit.text, - time: `${hit.start}s - ${hit.end}s`, - score: Math.round(hit.score * 100) + "%", - // 注意: API 現在返回 file_path(檔案系統路徑),需要轉換為可訪問的 URL - url: hit.file_path + "#t=" + hit.start + "," + hit.end // 需實作檔案路徑轉換為 URL -})); - -return { json: { results } }; -``` - -> **注意**: -> 1. **API 認證**: 所有 `/api/v1/*` 端點需要 `X-API-Key` 標頭 -> 2. **檔案路徑轉換**: API 現在返回 `file_path`(檔案系統路徑),需要轉換為可訪問的 URL(例如透過 SFTPGo 分享連結) - ---- - -### Step 4: 格式化輸出 - -**Telegram 格式:** -``` -🎬 搜尋結果: "{{ $json.query }}" - -1️⃣ "fun plot twists, Woody Dialog and charming performances..." - ⏱ 48.8s - 55.4s - 📊 相關度: 53% - -2️⃣ "Don't you like me to say that a pretty girl..." - ⏱ 4745.6s - 4748.6s - 📊 相關度: 52% -``` - ---- - -## 測試指令 - -### curl 測試 - -```bash -# 語意搜尋 -curl -X POST http://localhost:3002/api/v1/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 3}' - -# n8n 格式 -curl -X POST http://localhost:3002/api/v1/n8n/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: YOUR_API_KEY" \ - -d '{"query": "charade", "limit": 3}' - -# 影片列表 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos - -# 特定影片區塊 -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos/a1b10138a6bbb0cd/chunks -``` - ---- - -## 實際搜尋範例 - -| 搜尋詞 | 結果摘要 | -|--------|----------| -| `charade` | "fun plot twists, Woody Dialog and charming performances..." | -| `woody` | "Well, you thick skull hair, brain half-witted..." | -| `classic movie` | "Hello and welcome to the old-time movie show..." | -| `charming` | "fun plot twists, Woody Dialog and charming performances..." | - ---- - -## 資料庫狀態 - -| 資料庫 | 資料筆數 | 狀態 | -|--------|----------|------| -| PostgreSQL (videos) | 4 | ✅ | -| PostgreSQL (chunks) | 3,950 | ✅ | -| PostgreSQL (vectors) | 1,870 | ✅ | -| Qdrant (vectors) | 3,688 | ✅ | -| Redis (job cache) | 4 keys | ✅ | - ---- - -## 下一步 - -1. **建立 SFTPGo 分享連結** - - 開啟 http://localhost:8080 - - 登入 demo / demopassword123 - - 建立影片分享連結 - -2. **測試 n8n Workflow** - - 匯入 Postman Collection - - 建立 Webhook - - 測試搜尋 - -3. **整合到 WordPress** - - 建立表單接收用戶輸入 - - 呼叫 n8n Webhook - - 顯示搜尋結果 - ---- - -## 快速開始 - -```bash -# 1. 測試搜尋 API -curl -X POST http://localhost:3002/api/v1/search \ - -H "Content-Type: application/json" \ - -d '{"query": "charade", "limit": 3}' - -# 2. 查看影片列表 -curl http://localhost:3002/api/v1/videos - -# 3. 查看 n8n 是否運行 -curl http://localhost:5678 -``` diff --git a/docs_v1.0/OPERATIONS/PENDING_ISSUES.md b/docs_v1.0/OPERATIONS/PENDING_ISSUES.md deleted file mode 100644 index c1ae54a..0000000 --- a/docs_v1.0/OPERATIONS/PENDING_ISSUES.md +++ /dev/null @@ -1,813 +0,0 @@ -# 待解決問題追蹤 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-17 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-17 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-21 | 更新問題狀態 | OpenCode | - | -| V1.2 | 2026-03-21 | 添加備份機制優化待辦 | OpenCode | - | -| V1.3 | 2026-03-21 | 完成清理硬編碼密碼 | OpenCode | - | -| V1.4 | 2026-03-21 | 完成 OpenCode n8n MCP 整合 | OpenCode | - | -| V1.5 | 2026-03-21 | 完成 API Key Management 核心模組 | OpenCode | - | -| V1.6 | 2026-03-23 | 添加 Momentry Core API launchd 待辦 | OpenCode | - | -| V1.7 | 2026-03-23 | 完成 Momentry Core API launchd 設定 | OpenCode | - | -| V1.8 | 2026-03-24 | 完成服務統一遷移,所有服務使用自定義 plist | OpenCode | big-pickle | -| V1.9 | 2026-03-24 | 建立統一會員系統實作計畫 | OpenCode | big-pickle | -| V2.0 | 2026-03-24 | 建立 Job Worker 實作計畫 | OpenCode | big-pickle | - ---- - -## 問題 #1: sqlx async INSERT 不會實際寫入數據庫 - -### 問題描述 -使用 sqlx async 執行 INSERT 時,報告成功(rows_affected=1),但數據沒有實際寫入數據庫。 - -### 嘗試過的解決方案 -| # | 嘗試方法 | 結果 | -|---|---------|------| -| 1 | 使用 `execute()` | 報告成功但未寫入 | -| 2 | 使用 `fetch()` | 同樣問題 | -| 3 | 使用交易 | 同樣問題 | -| 4 | 使用連接池 `acquire()` | 同樣問題 | -| 5 | 每個操作創建新連接池 | 同樣問題 | -| 6 | 使用 `std::process::Command` 同步調用 psql | 同樣問題 | -| 7 | 使用 `tokio::task::spawn_blocking` | 同樣問題 | - -### 觀察到的現象 -- 直接用 psql 命令行可以成功寫入 -- 用另一個 PostgreSQL client 可以成功寫入 -- sqlx 查詢 COUNT(*) 可以正確讀取數據 -- 但 sqlx INSERT 報告成功卻不寫入 - -### 懷疑方向 -- sqlx 連接池與 PostgreSQL 的某種交互問題 -- Rust async runtime 與 PostgreSQL client 的問題 -- postgresql.conf 配置問題 - -### 臨時解決方案 -- Qdrant 向量存儲正常工作(不受影響) -- 存儲狀態追蹤功能正常運作 - -### 負責人 -- - -### 建立日期 -2026-03-17 - -### 備註 -影響 `store_vector` 函數,PVector 存儲無法正常工作,但 QVector 正常運作 - -### 2026-03-21 調查結果 - -#### 測試結果 -- 直接 psql INSERT: ✅ 成功 -- 資料寫入驗證: ✅ 成功 - -#### 發現的問題 -`store_vector` 函數 (`postgres_db.rs:819-860`) 存在以下問題: - -```rust -// 問題 1: 錯誤被靜默忽略 -match join_result { - Ok((cid, Ok(output))) => { - if !output.status.success() { - let err = String::from_utf8_lossy(&output.stderr); - tracing::error!("psql error for {}: {}", cid, err); - // 沒有返回錯誤!只是記錄日誌 - } - } - // ... -} -Ok(()) // 即使失敗也返回 Ok -``` - -#### 建議修復 -1. 讓 `store_vector` 返回實際結果 -2. 在失敗時返回 `Err` -3. 添加單元測試驗證 - -#### 下一步 -- [x] 修復 `store_vector` 錯誤處理 -- [x] 添加單元測試 -- [ ] 重現並確認問題根因 - -### 2026-03-21 修復完成 - -已修復 `store_vector` 函數的錯誤處理: - -```rust -// 修復前:錯誤被靜默忽略 -match join_result { - Ok((cid, Ok(output))) => { - if !output.status.success() { - tracing::error!("..."); // 只記錄,不返回錯誤 - } - } -} -Ok(()) // 即使失敗也返回 Ok - -// 修復後:正確傳播錯誤 -let (cid, output) = result; -let output = output.map_err(|e| anyhow::anyhow!(...))?; -if !output.status.success() { - anyhow::bail!("psql INSERT failed..."); -} -``` - ---- - -## 問題 #2: TUI 與 stdout 輸出混合 - -### 問題描述 -Python processors 的 progress 輸出蓋過 TUI,導致使用者無法清楚看到處理進度。 - -### 解決方案 -~~使用 TUI 渲染到 stderr~~ → 使用 Redis Pub/Sub 作為消息總線 - -### 當前狀態 -| 子項目 | 狀態 | -|--------|------| -| RedisPublisher Python 端 | ✅ 已實作 | -| Rust Redis 客戶端 | ✅ 已實作 (`redis_client.rs`) | -| Rust 訂閱更新 TUI | ✅ 已實作 (main.rs) | -| 中斷後繼續/重做 | 🔜 待實作 | - -### 負責人 -- - -### 建立日期 -2026-03-17 - -### 更新日期 -2026-03-21 - -### 參考文檔 -- `docs/MOMENTRY_CORE_REDIS_KEYS.md` -- `scripts/redis_publisher.py` -- `src/core/db/redis_client.rs` - ---- - -## 問題 #3: Redis Message Bus 尚未實作 - -### 問題描述 -根據設計規範,需要使用 Redis 作為監控和狀態管理系統。 - -### 當前狀態 - -| 實作項目 | 狀態 | 說明 | -|---------|------|------| -| Redis 客戶端 (Hash) | ✅ | `redis_client.rs` | -| Redis 客戶端 (Pub/Sub) | ✅ | `redis_client.rs::subscribe_progress()` | -| Python RedisPublisher | ✅ | `scripts/redis_publisher.py` | -| Rust 訂閱頻道 | ✅ | `main.rs` 中的 redis 訂閱邏輯 | -| 監控腳本 | ✅ | `monitor/service/health_check.sh` | - -### 負責人 -- - -### 建立日期 -2026-03-17 - -### 更新日期 -2026-03-21 - -### 優先級 -~~高~~ → 中 - 核心功能已完成 - -### 參考文檔 -- `docs/MOMENTRY_CORE_REDIS_KEYS.md` -- `docs/MOMENTRY_CORE_MONITORING.md` - ---- - -## 架構優化待評估 - -詳細內容請參考 [ARCHITECTURE_EVALUATION.md](./ARCHITECTURE_EVALUATION.md) - -| 項目 | 複雜度 | 優先級 | -|------|--------|--------| -| PostgreSQL → Redis 故障轉移 | 中 | 待評估 | -| 連接池監控 | 低 | 待評估 | -| Processor 重試機制 | 中 | 待評估 | -| PyO3 整合 | 高 | 低 | -| HTTP 健康端點 | 低 | ✅ 已完成 | -| Commit Message Lint | 低 | ✅ 已完成 | - ---- - -## 備份機制優化 (2026-03-21) - -### 問題分析 - -| 問題 | 嚴重性 | 說明 | -|------|--------|------| -| 溫冷分層未啟用 | 中 | weekly/monthly/archive 目錄為空 | -| 清理策略未執行 | 高 | 每日備份保留過多,空間浪費 | -| 無異地備份 | 高 | 無遠程備份(雲端/另一設備) | -| 備份驗證未自動化 | 中 | 只檢查文件存在,沒驗證可恢復性 | -| Gitea 大文件 | 中 | 每次備份 1GB,頻率過高 | -| 密碼硬編碼 | 高 | 腳本中有多處明文密碼 | - -### 待辦事項 - -| # | 任務 | 優先級 | 狀態 | -|---|------|--------|------| -| 1 | 啟用溫冷分層 (`backup_monitor.sh tier`) | 高 | 待辦 | -| 2 | 啟用清理策略 (`backup_monitor.sh cleanup`) | 高 | 待辦 | -| 3 | 添加備份驗證腳本 | 高 | 待辦 | -| 4 | 優化 Gitea 備份頻率 (改為週備份) | 中 | 待辦 | -| 5 | 創建外部備份腳本 (rsync/雲端) | 高 | 待辦 | -| 6 | 清理腳本中的硬編碼密碼 | 高 | ✅ 已完成 | - -### 推薦備份策略 - -| 層級 | 保留時間 | 頻率 | 目標 | -|------|----------|------|------| -| Hot | 7 天 | 每日 | 本地 SSD | -| Warm | 30 天 | 每週 | 本地 HDD | -| Cold | 90 天 | 每月 | 外部存儲 | -| Archive | 1 年 | 每季 | 離線/雲端 | - -### 建議的 Crontab - -```bash -# 每日備份 (排除 Gitea) -0 3 * * 1-6 /Users/accusys/momentry/scripts/backup_all.sh all_except_gitea - -# 每週完整備份 (含 Gitea) -0 3 * * 0 /Users/accusys/momentry/scripts/backup_all.sh all - -# 每週溫冷分層 -0 4 * * 0 /Users/accusys/momentry_core_0.1/monitor/storage/backup_monitor.sh tier - -# 每週清理 -0 5 * * 0 /Users/accusys/momentry_core_0.1/monitor/storage/backup_monitor.sh cleanup - -# 每月驗證 -0 6 1 * * /Users/accusys/momentry/scripts/verify_backup.sh -``` - -### 負責人 -- - -### 參考文件 -- `/Users/accusys/momentry/scripts/backup_all.sh` -- `/Users/accusys/momentry_core_0.1/monitor/storage/backup_monitor.sh` -- `/Users/accusys/momentry/backup/` - ---- - -## OpenCode n8n MCP 整合 (2026-03-21) - -### 完成狀態 - -| 項目 | 狀態 | 說明 | -|------|------|------| -| n8n REST API 啟用 | ✅ | `N8N_PUBLIC_API_ENABLED=true` | -| API Key 生成 | ✅ | Settings → API | -| MCP Server 安裝 | ✅ | `@nextoolsolutions/mcp-n8n` | -| OpenCode 設定 | ✅ | `~/.config/opencode/opencode.json` | -| 43 工具可用 | ✅ | workflows, executions, datatables, tags 等 | - -### 設定檔案 - -`~/.config/opencode/opencode.json`: -```json -{ - "mcp": { - "gitea": { - "type": "local", - "enabled": true, - "command": [ - "/opt/homebrew/bin/gitea-mcp-server", - "-token", "", - "-host", "http://localhost:3000" - ] - }, - "n8n": { - "type": "local", - "enabled": true, - "command": ["/opt/homebrew/bin/mcp-n8n"], - "environment": { - "N8N_BASE_URL": "http://localhost:5678", - "N8N_API_KEY": "" - } - } - } -} -``` - -### 重要提醒 - -1. **API Key 安全**: 避免提交到 Git -2. **n8n 需通過反向代理**: localhost:5678 無法直接訪問 API,需通過 Caddy -3. **重啟生效**: 修改 `opencode.json` 後需重啟 OpenCode - -### 參考文件 -- `docs/OPENCODE_GUIDE.md` - MCP 設定章節 -- `docs/INSTALL_N8N.md` - n8n 安裝指南 - ---- - -## n8n API 備份腳本 (2026-03-21) - -### 腳本位置 - -| 腳本 | 說明 | 依賴 | -|------|------|------| -| `monitor/workflow/backup_n8n_api.py` | REST API 備份 | requests | -| `monitor/workflow/backup_n8n_mcp.py` | MCP 備份(開發中) | mcp SDK | - -### 使用方式 - -```bash -# 備份所有 workflows -N8N_API_KEY="..." python3.11 backup_n8n_api.py - -# 只顯示變更(不備份) -N8N_API_KEY="..." python3.11 backup_n8n_api.py --diff - -# 差異備份(只備份變更的 workflows) -N8N_API_KEY="..." python3.11 backup_n8n_api.py --incremental - -# 列出可用備份 -python3.11 backup_n8n_api.py --list - -# 驗證最新備份 -python3.11 backup_n8n_api.py --verify - -# 顯示備份統計 -python3.11 backup_n8n_api.py --stats - -# 只備份啟用的 workflows -N8N_API_KEY="..." python3.11 backup_n8n_api.py --active-only - -# 備份失敗的執行記錄 -N8N_API_KEY="..." python3.11 backup_n8n_api.py --failed-only -``` - -### 功能 - -- [x] REST API 備份 -- [x] 變更偵測 -- [x] SHA256 校驗 -- [x] 備份版本化 -- [x] 差異備份(`--incremental`) -- [x] 備份驗證(`--verify`) -- [x] 備份統計(`--stats`) -- [x] 失敗執行記錄備份(`--failed-only`) -- [ ] 選擇性備份(按 Tags) - -### 備份位置 - -``` -/Users/accusys/momentry/backup/n8n_workflows/api/ -├── 20260321_122059/ -│ ├── workflows.json # 21 workflows -│ ├── workflows.json.sha256 # SHA256 校驗 -│ ├── tags.json # Tags(若有) -│ └── manifest.json # 元數據 -└── ... -``` - -### Crontab 建議 - -```bash -# 每日備份(下午 3 點) -0 15 * * * N8N_API_KEY="..." /opt/homebrew/bin/python3.11 /Users/accusys/momentry_core_0.1/monitor/workflow/backup_n8n_api.py >> /Users/accusys/momentry/log/monitor/workflow_backup_api.log 2>&1 -``` - ---- - -## API Key Management System (2026-03-21) - -### 設計目標 - -為 Momentry Core 實現完整的 API Key 管理系統,包括: -- API Key 生成(安全隨機) -- Key 哈希(SHA256) -- 異常檢測 -- 強制輪換機制 -- 審計日誌 - -### 模組架構 - -``` -src/core/api_key/ -├── mod.rs # 模組導出 -├── models.rs # 數據模型和類型 -├── service.rs # 核心服務邏輯 -├── anomaly.rs # 異常檢測 -└── rotation.rs # 輪換管理 -``` - -### Key 類型 - -| 類型 | 前綴 | 默認 TTL | 寬限期 | -|------|------|----------|--------| -| System | `msys_` | 365 天 | 72 小時 | -| User | `muser_` | 90 天 | 24 小時 | -| Service | `msvc_` | 180 天 | 48 小時 | -| Integration | `mint_` | 30 天 | 24 小時 | -| Emergency | `memg_` | 1 天 | 0 小時 | - -### Key 格式 - -``` -{prefix}{uuid}_{timestamp}_{random} -例如: muser_a1b2c3d4e5f6_1710998400_abc12345 -``` - -### 異常檢測閾值 - -| 指標 | 閾值 | -|------|------| -| 每分鐘請求數 | 1000 | -| 每小時請求數 | 10000 | -| 錯誤率 | 50% | -| 每小時唯一 IP 數 | 5 | -| 鎖定閾值 | 3 次觸發 | - -### 實現狀態 - -| 組件 | 狀態 | 說明 | -|------|------|------| -| 數據模型 | ✅ 完成 | `models.rs` | -| Key 生成/哈希 | ✅ 完成 | `service.rs` | -| 異常檢測 | ✅ 完成 | `anomaly.rs` | -| 輪換機制 | ✅ 完成 | `rotation.rs` | -| CLI 命令 | ✅ 完成 | `main.rs` | -| 數據庫集成 | ✅ 完成 | `postgres_db.rs` | -| Redis 告警 | ✅ 完成 | `redis_client.rs` | -| 數據庫遷移 | ✅ 完成 | `migrations/001_api_key_management.sql` | -| 單元測試 | ✅ 完成 | 55 個測試通過 | - -### CLI 命令 - -```bash -# 創建 API Key -momentry api-key create --key-type service --ttl 90 - -# 列出所有 Keys -momentry api-key list - -# 驗證 Key -momentry api-key validate --key - -# 撤銷 Key -momentry api-key revoke --key - -# 請求輪換 -momentry api-key rotate --key - -# 顯示統計 -momentry api-key stats -``` - -### 參考文件 - -- `src/core/api_key/` - API Key 模組 -- `docs/API_KEY_MANAGEMENT.md` - 設計文檔 -- `migrations/001_api_key_management.sql` - 數據庫遷移 - ---- - -## 問題 #5: Redis 用戶名問題 (2026-03-21) - -### 問題描述 - -Redis 僅有 `default` 用戶,無 `accusys` 用戶。`.env` 檔案使用 `redis://accusys:accusys@localhost:6379` 格式會導致認證失敗。 - -### 測試結果 - -| URL 格式 | 結果 | -|----------|------| -| `redis://accusys:accusys@localhost:6379` | ❌ AUTH failed | -| `redis://:accusys@localhost:6379` | ✅ PONG | - -### Redis ACL 狀態 - -``` -user default on sanitize-payload #1bd51c... ~* &* +@all -requirepass: accusys -``` - -### 根本原因 - -1. Redis 啟動時僅設定 `--requirepass accusys` -2. 未建立自訂用戶 `accusys` -3. ACL 變更不會持久化(無 config file) - -### 已執行修復 - -| 項目 | 修改 | -|------|------| -| `.env` | `redis://accusys:accusys@localhost:6379` → `redis://:accusys@localhost:6379` | - -### 待解決問題 - -1. **ACL 持久化**:Redis 啟動後手動建立的用戶不會保留(重啟後消失) -2. **需配置 ACL 文件**:建議建立 `users.acl` 並在 plist 中指定 - -### 建議解決方案 - -#### 方案 A:使用默認用戶(現行) - -```bash -# .env -REDIS_URL=redis://:accusys@localhost:6379 -``` - -**優點**:簡單,無需修改 Redis 配置 -**缺點**:所有應用共享默認用戶 - -#### 方案 B:建立 ACL 配置文件 - -```bash -# 1. 創建 ACL 文件 -cat > /Users/accusys/momentry/etc/redis/users.acl << 'EOF' -user default on sanitize-payload ~* &* +@all >accusys -user accusys on sanitize-payload ~* &* +@all >accusys -EOF - -# 2. 修改 plist 添加 --aclfile 參數 ---aclfile /Users/accusys/momentry/etc/redis/users.acl - -# 3. 重啟 Redis -sudo launchctl unload /Library/LaunchDaemons/com.momentry.redis.plist -sudo launchctl load /Library/LaunchDaemons/com.momentry.redis.plist -``` - -**優點**:支持多用戶,ACL 持久化 -**缺點**:需修改 plist 並重啟 - -### 影響範圍 - -- `src/core/config.rs` - REDIS_URL 讀取 -- `src/core/db/redis_client.rs` - Redis 連線 -- `momentry api-key` 命令 - 異常告警 - -### 狀態 - -- [x] 已確認問題存在 -- [x] 已修改 `.env` 使用默認用戶 -- [ ] 待決定是否實施 ACL 方案 - ---- - -## 問題 #6: Momentry Core API 未開機自動啟動 (2026-03-23) - -### 問題描述 - -Momentry Core API 服務 (`momentry server --port 3002`) 未設定 launchd,導致: -1. 系統重啟後 API 服務不會自動啟動 -2. `api.momentry.ddns.net` 返回 502 Bad Gateway -3. n8n workflow 呼叫 API 時失敗 - -### 發現過程 - -1. n8n workflow 呼叫 `https://api.momentry.ddns.net/api/v1/n8n/search` 返回 502 -2. 檢查發現 port 3002 無服務運行 -3. Caddy 配置正向確,但後端服務未啟動 -4. 手動啟動服務後 API 正常運作 - -### 配置需求 - -| 項目 | 值 | -|------|-----| -| 服務名稱 | `com.momentry.api` | -| 二進位檔 | `/Users/accusys/momentry_core_0.1/target/release/momentry` | -| 命令 | `server --port 3002` | -| Port | 3002 | -| 環境變數 | `DATABASE_URL`, `REDIS_URL` 等 | - -### 待辦事項 - -- [x] 建立 `docs/INSTALL_MOMENTRY_API.md` 安裝文件 -- [x] 建立 `/Library/LaunchDaemons/com.momentry.api.plist` -- [x] 設定環境變數 (`DATABASE_URL`, `REDIS_URL` 等) -- [x] 測試 launchctl load/unload -- [x] 驗證開機自動啟動 (launchd 載入成功) - -### 完成日期 -2026-03-23 - -### 參考文件 - -- `/Library/LaunchDaemons/com.momentry.n8n.main.plist` - n8n plist 範例 -- `docs/INSTALL_N8N.md` - plist 配置說明 - ---- - -## 服務統一遷移 (2026-03-24) - -### 問題描述 - -Reboot 後發現 n8n workflow 數量從 42 變成 41,確認是 PostgreSQL 資料庫問題。經過調查發現: - -1. **兩組不同的 PostgreSQL 資料目錄**: - - Homebrew plist: `/opt/homebrew/var/postgresql@18` (有最新資料) - - Custom plist: `/Users/accusys/momentry/var/postgresql` (可能是舊資料) - -2. **Reboot 時 custom plist 搶先啟動**,使用了錯誤的資料目錄 - -### 解決方案 - -1. **統一使用 custom plist**: - - 刪除 homebrew plist (`~/Library/LaunchAgents/homebrew.mxcl.postgresql@18.plist`) - - Custom plist 使用 `/Users/accusys/momentry/var/postgresql` 作為資料目錄 - - 將所有 14 個服務的 plist 註冊到 launchd - -2. **所有已遷移的服務**: - -| 服務 | Plist | 資料目錄 | -|------|-------|----------| -| PostgreSQL | ✅ | `/Users/accusys/momentry/var/postgresql` | -| MariaDB | ✅ | `/Users/accusys/momentry/var/mariadb` | -| MongoDB | ✅ | `/opt/homebrew/var/mongodb` | -| Redis | ✅ | - | -| Ollama | ✅ | - | -| Qdrant | ✅ | - | -| n8n Main | ✅ | - | -| n8n Worker | ✅ | - | -| Caddy | ✅ | - | -| SFTPGo | ✅ | - | -| Gitea | ✅ | - | -| Gitea MCP | ✅ | - | -| PHP | ✅ | - | -| Momentry API | ✅ | - | -| RustDesk HBBR | ✅ | - | -| RustDesk HBBS | ✅ | - | - -### 還發現的 Homebrew 服務 (未遷移) - -| 服務 | 建議 | -|------|------| -| homebrew.mxcl.grafana | ⚠️ 考慮遷移 | -| homebrew.mxcl.prometheus | ⚠️ 考慮遷移 | -| homebrew.mxcl.openwebui | ⚠️ 考慮遷移 | -| homebrew.mxcl.kafka | ⚠️ 考慮遷移 | -| homebrew.mxcl.seaweedfs | ⚠️ 考慮遷移 | -| homebrew.mxcl.netdata | ⚠️ 考慮遷移 | -| homebrew.mxcl.ddclient | ⚠️ 動態 DNS | -| homebrew.mxcl.shadowsocks-rust | ⚠️ VPN | - -### 預防措施 - -1. **確保統一資料目錄**:所有服務只使用一個資料目錄 -2. **Reboot 測試**:遷移完成後需進行 Reboot 測試 -3. **文件同步**:plist 檔案同步到 repo - -### 完成日期 -2026-03-24 - -### 參考文件 - -- `docs/SERVICES.md` - 服務管理文檔 -- `docs/SERVICE_ADDITION_GUIDE.md` - 服務添加規範 -- `momentry_runtime/plist/` - plist 檔案存放位置 - ---- - -## Job Worker 實作 (2026-03-24) - -### 目標 - -實作輪詢式 Job Worker,實現檔案註冊後自動觸發處理: - -1. **輪詢機制**:Worker 定期輪詢 jobs 佇列 -2. **並行處理**:最多 2 個 processor 同時執行 -3. **失敗容忍**:任一模組獨立,失敗可接續 - -### 設計決策 - -| 項目 | 決策 | 理由 | -|------|------|------| -| 觸發方式 | 輪詢(Job Worker) | 暫無可靠 API 觸發 | -| 並行處理 | 最多 2 個 | 可根據 CPU/GPU 調整 | -| 失敗處理 | 獨立模組,部分完成可接續 | 任何模組失敗都產出狀態 | -| Worker 啟動 | 獨立進程 | 隔離、易管理 | -| 並行上限 | 環境變數 + 預設值 | 靈活調整 | -| 狀態同步 | PostgreSQL + Redis | 可靠 + 即時 | - -### 環境變數 - -| 變數 | 預設值 | 說明 | -|------|--------|------| -| `MOMENTRY_MAX_CONCURRENT` | 2 | 最大並行 processor 數 | -| `MOMENTRY_POLL_INTERVAL` | 5 | 輪詢間隔(秒) | -| `MOMENTRY_WORKER_ENABLED` | true | 是否啟用 worker | - -### 實作計畫 - -詳細內容請參考 [JOB_WORKER_IMPLEMENTATION_PLAN.md](./JOB_WORKER_IMPLEMENTATION_PLAN.md) - -### Phase 規劃 - -| Phase | 任務 | 預估工時 | -|-------|------|----------| -| 1 | 資料庫遷移 | 2h | -| 2 | Worker 框架 | 4h | -| 3 | Register API 整合 | 2h | -| 4 | Processor 執行 | 4h | -| 5 | 進度追蹤 | 2h | -| 6 | API 端點 | 3h | -| 7 | CLI 命令 | 2h | -| 8 | 測試 | 4h | - -**總預估**: ~23h - -### 實作結構 - -``` -src/ -├── worker/ -│ ├── mod.rs # Worker 模組導出 -│ ├── config.rs # Worker 配置 -│ ├── worker.rs # Worker 主邏輯 -│ ├── processor.rs # Processor 執行器 -│ ├── queue.rs # Job 佇列管理 -│ └── progress.rs # 進度追蹤 -├── api/ -│ └── server.rs # 更新 Register API -└── main.rs # 新增 worker 命令 -``` - -### 狀態 - -- [x] 系統分析完成 -- [x] 實作計畫文件建立 -- [ ] Phase 1: 資料庫遷移 -- [ ] Phase 2: Worker 框架 -- [ ] Phase 3: Register API 整合 -- [ ] Phase 4: Processor 執行 -- [ ] Phase 5-8: 依序實作 - -### 參考文件 - -- `docs/JOB_WORKER_IMPLEMENTATION_PLAN.md` - 完整實作計畫 -- `docs/PROCESSING_PIPELINE.md` - 處理流程 -- `docs/MOMENTRY_CORE_REDIS_KEYS.md` - Redis Key 設計 - ---- - -## 統一會員系統 + 影片歸屬追蹤 (2026-03-24) - -### 目標 - -建立統一的會員系統: -1. WordPress 作為唯一登入入口 -2. 每個影片關聯到 user_id(追蹤歸屬) -3. Per-user 配額管理 -4. API 端點啟用認證 - -### 實作計畫 - -詳細內容請參考 [USER_MANAGEMENT_PLAN.md](./USER_MANAGEMENT_PLAN.md) - -### Phase 規劃 - -| Phase | 任務 | 複雜度 | 優先級 | 預估工時 | -|-------|------|--------|--------|----------| -| 1 | WordPress Application Passwords 測試 | 低 | P0 | 1.5h | -| 2 | 資料庫遷移 (users 表) | 中 | P0 | 3h | -| 3 | API auth middleware | 中 | P0 | 4h | -| 4 | Register API 更新 | 低 | P0 | 2h | -| 5 | Admin users API | 中 | P1 | 4h | -| 6 | n8n workflow | 中 | P1 | 6h | -| 7 | 配額管理 | 中 | P2 | 4h | -| 8 | 測試驗證 | 中 | P2 | 4h | - -**總預估**: ~28.5h - -### 待確認事項 - -- [ ] WordPress 用戶建立方式(手動/Elementor表單) -- [ ] API Key 格式確認 -- [ ] SFTPGo 整合方式 -- [ ] 配額管理策略 -- [ ] 用戶刪除同步流程 - -### 狀態 - -- [x] 系統分析完成 -- [x] 實作計畫文件建立 -- [ ] Phase 1: WordPress 認證測試 -- [ ] Phase 2: 資料庫遷移 -- [ ] Phase 3-8: 依序實作 - -### 參考文件 - -- `docs/USER_MANAGEMENT_PLAN.md` - 完整實作計畫 -- `docs/API_KEY_MANAGEMENT.md` - API Key 管理 -- `docs/SFTPGO_DEMO_USER.md` - SFTPGo 用戶設定 diff --git a/docs_v1.0/OPERATIONS/PROCESSING_PIPELINE.md.bak b/docs_v1.0/OPERATIONS/PROCESSING_PIPELINE.md.bak deleted file mode 100644 index 28c151e..0000000 --- a/docs_v1.0/OPERATIONS/PROCESSING_PIPELINE.md.bak +++ /dev/null @@ -1,293 +0,0 @@ -# Video Processing Pipeline - 處理流程 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-22 | -| 文件版本 | V1.1 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode | -| V1.1 | 2026-03-26 | 更新流程圖文字 (media_url→file_path) | OpenCode | deepseek-reasoner | - ---- - -## 處理流程架構 - -``` -┌─────────────────────────────────────────────────────────────────────────────┐ -│ Video Processing Pipeline │ -├─────────────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 1: JSON 生成 (Process) │ │ -│ │ │ │ -│ │ video.mp4 ──→ [ASR] ──→ asr.json (語音辨識) │ │ -│ │ ──→ [CUT] ──→ cut.json (場景偵測) │ │ -│ │ ──→ [ASRX] ──→ asrx.json (說話者分離) │ │ -│ │ ──→ [YOLO] ──→ yolo.json (物體偵測) │ │ -│ │ ──→ [OCR] ──→ ocr.json (文字辨識) │ │ -│ │ ──→ [Face] ──→ face.json (人臉偵測) │ │ -│ │ ──→ [Pose] ──→ pose.json (姿態估計) │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 2: 入庫 (Import) │ │ -│ │ │ │ -│ │ .json files ──→ PostgreSQL (fs_json = true) │ │ -│ │ ↓ │ │ -│ │ pre_chunks 表 (from ASR, CUT) │ │ -│ │ frames 表 (from YOLO, OCR, Face, Pose) │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 3: Chunk 生成 (Chunk) │ │ -│ │ │ │ -│ │ pre_chunks ──→ [Chunk Rule] ──→ chunks 表 │ │ -│ │ ↓ │ │ -│ │ 清洗 → 純文字 │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 4: 向量化 (Vectorize) │ │ -│ │ │ │ -│ │ chunks ──→ [Embedding Model] ──→ vectors │ │ -│ │ ↓ │ │ -│ │ Qdrant (主要向量庫) │ │ -│ │ PGVector (備份向量庫) │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ ↓ │ -│ ┌─────────────────────────────────────────────────────────────────────┐ │ -│ │ Stage 5: 搜尋 (Search) │ │ -│ │ │ │ -│ │ Natural Language Query ──→ [Embedding] ──→ [Qdrant Search] │ │ -│ │ ↓ │ │ -│ │ 返回結果含 file_path │ │ -│ └─────────────────────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────────────┘ -``` - ---- - -## CLI 命令 - -### Stage 1: JSON 生成 (Process) - -```bash -# 基本用法 -cargo run --bin momentry -- process - -# 只處理特定模組 -cargo run --bin momentry -- process --modules asr,cut - -# 強制重新處理(忽略完整性檢查) -cargo run --bin momentry -- process --force - -# 從中斷點續傳 -cargo run --bin momentry -- process --resume - -# 模組使用雲端處理 -cargo run --bin momentry -- process --modules yolo,face --cloud yolo - -# 完整範例 -cargo run --bin momentry -- process /path/to/video.mp4 \ - --modules asr,cut,yolo,ocr \ - --cloud yolo -``` - -### Stage 2: 入庫 (Import) - -```bash -# 目前入庫在 process 完成後自動執行 -# 計劃新增獨立的 import 命令 -# cargo run --bin momentry -- import -``` - -### Stage 3: Chunk 生成 - -```bash -# 生成 chunks -cargo run --bin momentry -- chunk -``` - -### Stage 4: 向量化 - -```bash -# 向量化 chunks -cargo run --bin momentry -- vectorize - -# 指定模型 -cargo run --bin momentry -- vectorize --model sentence-transformers/all-MiniLM-L6-v2 -``` - ---- - -## 處理模式選項 - -### --force (強制重新處理) - -- 刪除現有的 JSON 檔案 -- 從頭開始處理 -- 適用於:處理失敗、模型更新、需要重新處理 - -```bash -# 強制重新處理 YOLO -cargo run --bin momentry -- process --modules yolo --force -``` - -### --resume (續傳) - -- 檢查現有 JSON 的進度 -- 從中斷點繼續處理 -- 適用於:處理中斷、系統崩潰後恢復 - -```bash -# 從上次中斷點繼續 -cargo run --bin momentry -- process --resume -``` - -### 預設行為 (Smart Mode) - -- 如果 JSON 完全:跳過 -- 如果 JSON 不完整:警告 + 跳過(需要 --resume 或 --force) -- 如果 JSON 不存在:處理 - -``` -Output: -ASR: ✓ Already complete, skipping - -⚠️ Found incomplete JSON file: /path/to/yolo.json - Progress: 73800/412343 (17.9%) - Use --resume to continue from checkpoint - Use --force to reprocess from scratch -YOLO: ✓ Already complete, skipping -``` - ---- - -## 可用模組 - -| 模組 | 功能 | 輸出 | 用途 | -|------|------|------|------| -| asr | 自動語音辨識 | asr.json | 語音轉文字 | -| cut | 場景偵測 | cut.json | 影片分段 | -| asrx | 說話者分離 | asrx.json | 多人對話分析 | -| yolo | 物體偵測 | yolo.json | 物體辨識 | -| ocr | 文字辨識 | ocr.json | 畫面文字 | -| face | 人臉偵測 | face.json | 人臉辨識 | -| pose | 姿態估計 | pose.json | 人體姿態 | - ---- - -## 向量化模型選擇 - -### 統一嵌入模型 -Momentry Core 統一使用 **`nomic-embed-text-v2-moe:latest`** 作為所有規則的嵌入模型: - -```bash -# 統一模型(所有 Rule 1/2/3 使用) ---model nomic-embed-text-v2-moe:latest -``` - -### 模型特性 -| 特性 | 說明 | -|------|------| -| **模型名稱** | `nomic-embed-text-v2-moe:latest` | -| **向量維度** | 768 維 | -| **多語言支持** | ✅ 完整支持(英語、中文、日語、韓語等) | -| **模型架構** | Mixture of Experts (MoE) | -| **推理速度** | 快速,適合實時應用 | - -### 使用方式 -```bash -# 向量化命令 -cargo run --bin momentry -- vectorize --model nomic-embed-text-v2-moe:latest -``` - ---- - -## 資料庫儲存 - -### PostgreSQL (主要關聯式資料庫) - -- 影片資訊 -- Chunks 資料 -- Pre-chunks 資料 -- Frames 資料 -- 使用者資料 - -### Qdrant (主要向量資料庫) - -- Chunk 向量 -- 相似度搜尋 - -### PGVector (備份向量資料庫) - -- Chunk 向量副本 -- 備援機制 - ---- - -## Pipeline 狀態追蹤 - -### PostgreSQL 狀態欄位 - -```sql --- 影片處理狀態 -videos.status: 'pending' | 'processing' | 'completed' | 'failed' - --- 檔案處理狀態 -videos.fs_json: true/false -videos.fs_chunks: true/false -videos.fs_vectors: true/false - --- pre_chunks 狀態 -pre_chunks.imported: true/false - --- frames 狀態 -frames.imported: true/false - --- chunks 狀態 -chunks.cleaned: true/false -chunks.vectorized: true/false -``` - -### 進度查詢 API - -```bash -# 查詢處理進度 -curl http://localhost:3002/api/v1/progress/{uuid} - -# 回應範例 -{ - "uuid": "a1b10138a6bbb0cd", - "file_name": "video.mp4", - "overall_progress": 65, - "cpu_percent": 45.2, - "gpu_percent": 98.5, - "memory_mb": 8500, - "processors": [ - {"name": "asr", "status": "complete", "progress": 100}, - {"name": "cut", "status": "complete", "progress": 100}, - {"name": "yolo", "status": "progress", "progress": 45}, - {"name": "ocr", "status": "pending", "progress": 0} - ] -} -``` - ---- - -## 下一步 - -1. **API 端點** - 支援 --modules 和 --cloud 參數 -2. **獨立 Import 命令** - 分離入庫流程 -3. **獨立 Chunk 命令** - 分離 chunk 生成 -4. **獨立 Vectorize 命令** - 分離向量化流程 -5. **模型管理** - 新增、選擇、預覽模型 - diff --git a/docs_v1.0/OPERATIONS/PYTHON.md b/docs_v1.0/OPERATIONS/PYTHON.md deleted file mode 100644 index 58d88ee..0000000 --- a/docs_v1.0/OPERATIONS/PYTHON.md +++ /dev/null @@ -1,568 +0,0 @@ -# Python 開發規範 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-16 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-16 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-21 | 新增 RedisPublisher API 文檔 | OpenCode | - | - ---- - -## 概述 - -本文檔定義 Momentry 專案中 Python 程式碼的開發標準與最佳實踐。 - ---- - -## 版本管理 - -### 鎖定版本 - -| 版本 | 用途 | 路徑 | -|------|------|------| -| Python 3.11.14 | Momentry venv | /Users/accusys/momentry_core_0.1/venv/bin/python | -| Python 3.11.14 | 系統安裝 | /opt/homebrew/bin/python3.11 | -| Python 3.14.3 | 系統預設 | /opt/homebrew/bin/python3 | -| Python 3.9.6 | 系統預設 (備用) | /usr/bin/python3 | - -### 版本選擇原則 - -- **Momentry 專案**:使用 venv 中的 Python 3.11.14 -- **新專案**:建議使用 venv 管理 -- **系統工具**:可使用系統預設版本 - ---- - -## 腳本規範 - -### Shebang 宣告 - -所有 Momentry Python 腳本必須在第一行宣告明確的 Python 路徑: - -```python -#!/opt/homebrew/bin/python3.11 -``` - -**錯誤範例**: -```python -#!/usr/bin/env python3 # 會解析到系統預設 (3.14.3) -#!/usr/bin/python3 # 會使用系統 Python (3.9.6) -``` - -**正確範例**: -```python -#!/opt/homebrew/bin/python3.11 -import sys -... -``` - -### 檔案結構 - -``` -scripts/ -├── asr_processor.py # ASR 處理腳本 -├── thumbnail_extractor.py # 縮圖提取腳本 -└── new_script.py # 新腳本模板 -``` - -### 腳本模板 - -```python -#!/opt/homebrew/bin/python3.11 -""" -腳本名稱 -簡短描述腳本功能 - -用法: - python3.11 script.py - -作者: Momentry Team -版本: 1.0.0 -""" - -import argparse -import json -import logging -import sys -from pathlib import Path - -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s - %(levelname)s - %(message)s", - stream=sys.stderr, -) -logger = logging.getLogger(__name__) - - -def main(): - parser = argparse.ArgumentParser(description="腳本功能描述") - parser.add_argument("input", help="輸入檔案或參數") - parser.add_argument("-o", "--output", default="output.json", help="輸出檔案") - parser.add_argument("-v", "--verbose", action="store_true", help="詳細輸出") - parser.add_argument("-c", "--count", type=int, default=10, help="數量") - - args = parser.parse_args() - - if args.verbose: - logger.setLevel(logging.DEBUG) - - # 業務邏輯 - result = process_data(args.input, args.count) - - # 輸出 JSON結果 - print(json.dumps(result)) - - -def process_data(input_path: str, count: int) -> dict: - """處理資料並返回結果""" - logger.info(f"Processing: {input_path}") - - # TODO: 實作業務邏輯 - - return { - "status": "success", - "input": input_path, - "count": count, - } - - -if __name__ == "__main__": - main() -``` - ---- - -## 與 Rust 整合 - -### 使用 venv (目前採用) - -Momentry 使用 venv 管理 Python 環境,避免與系統其他程式衝突。 - -#### 建立 venv - -```bash -# 建立虛擬環境 -cd /Users/accusys/momentry_core_0.1 -/opt/homebrew/bin/python3.11 -m venv venv - -# 啟用虛擬環境 -source venv/bin/activate - -# 安裝依賴 -pip install -r requirements.txt -``` - -#### 從 Rust 呼叫 venv Python - -```rust -use std::path::Path; - -let script_path = Path::new(env!("CARGO_MANIFEST_DIR")) - .join("scripts") - .join("asr_processor.py"); - -// 使用 venv 中的 Python -let venv_python = Path::new(env!("CARGO_MANIFEST_DIR")) - .join("venv") - .join("bin") - .join("python"); - -let output = Command::new(venv_python) - .arg(script_path) - .arg(video_path) - .output() - .context("Failed to run processor")?; -``` - -**優點**: -- 專案依賴隔離 -- 不同專案可使用不同 Python 版本 -- 易於重現環境 -- 不影響系統其他程式 - ---- - -## 依賴管理 - -### venv 目錄結構 - -``` -momentry_core_0.1/ -├── venv/ # 虛擬環境 -│ ├── bin/ -│ │ ├── python # Python 3.11.14 -│ │ ├── pip -│ │ └── ... -│ └── lib/python3.11/ # 安裝的套件 -├── requirements.txt # 依賴列表 -├── scripts/ # Python 腳本 -│ ├── asr_processor.py -│ └── thumbnail_extractor.py -└── src/ # Rust 程式碼 -``` - -### 使用虛擬環境 - -```bash -# 啟用虛擬環境 -source venv/bin/activate - -# 安裝依賴 -pip install faster-whisper - -# 退出虛擬環境 -deactivate -``` - -# 退出虛擬環境 -deactivate -``` - -### 依賴列表格式 - -建立 `requirements.txt`: - -``` -faster-whisper>=1.0.0 -ffmpeg-python>=0.2.0 -Pillow>=10.0.0 -``` - -### 安裝專案依賴 - -```bash -# 使用 python3.11 安裝 -/opt/homebrew/bin/python3.11 -m pip install -r requirements.txt -``` - ---- - -## RedisPublisher 進度發布 - -### 概述 - -`redis_publisher.py` 提供統一的進度發布介面,用於 Python 處理器向 Rust 端的 TUI 即時回報進度。 - -### 基本用法 - -```python -#!/opt/homebrew/bin/python3.11 -import sys -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -from redis_publisher import RedisPublisher - -def process_video(video_path: str, uuid: str): - pub = RedisPublisher(uuid) - - pub.info("asr", "Starting ASR processing") - pub.progress("asr", current=50, total=100, message="Processing segment") - pub.complete("asr", "Transcription complete") -``` - -### API 參考 - -| 方法 | 說明 | 範例 | -|------|------|------| -| `info(proc, msg)` | 發布資訊訊息 | `pub.info("asr", "Model loaded")` | -| `progress(proc, cur, tot, msg)` | 發布進度 | `pub.progress("asr", 50, 100, "...")` | -| `complete(proc, msg)` | 發布完成 | `pub.complete("asr", "Done")` | -| `error(proc, msg)` | 發布錯誤 | `pub.error("asr", "Failed")` | -| `warning(proc, msg)` | 發布警告 | `pub.warning("asr", "Retry...")` | -| `percentage(proc, pct, msg)` | 發布百分比 | `pub.percentage("asr", 50.5, "50%")` | - -### 結構化訊息格式 - -```python -from redis_publisher import MessageType, ProgressContext - -# 使用 Context Manager -with ProgressContext(pub, "asr"): - # 自動發布開始/完成/錯誤 - run_asr() - -# 帶 extra 資料 -pub.progress("asr", current=50, total=100, message="...", - extra={"fps": 30.5, "model": "tiny"}) -``` - -### 環境變數 - -| 變數 | 預設值 | 說明 | -|------|--------|------| -| `REDIS_URL` | `redis://:accusys@localhost:6379` | Redis 連線 URL | -| `REDIS_PASSWORD` | `accusys` | Redis 密碼 | - ---- - -## 程式碼規範 - -### Import 排序 - -```python -# 1. 標準庫 -import sys -import os -import json -import logging -from pathlib import Path -from typing import Optional - -# 2. 第三方庫 -import numpy as np -import pandas as pd -from faster_whisper import WhisperModel - -# 3. 本地模組 -from . import local_module -from ..package import module -``` - -### 命名規範 - -| 類型 | 規範 | 範例 | -|------|------|------| -| 模組/檔案 | snake_case | `asr_processor.py` | -| 類別 | PascalCase | `class VideoProcessor` | -| 函數/變數 | snake_case | `def process_video()` | -| 常量 | UPPER_SNAKE_CASE | `MAX_WORKERS = 4` | -| 私有成員 | _leading_underscore | `_private_method()` | - -### 類型提示 - -```python -from typing import Optional, List, Dict - -def process_video( - video_path: str, - options: Optional[Dict[str, int]] = None, -) -> List[Dict[str, float]]: - """處理影片並返回結果""" - ... -``` - -### 錯誤處理 - -```python -import logging -from pathlib import Path - -logger = logging.getLogger(__name__) - - -def process_video(video_path: str) -> dict: - path = Path(video_path) - - if not path.exists(): - logger.error(f"Video file not found: {video_path}") - raise FileNotFoundError(f"Video not found: {video_path}") - - try: - result = _do_process(path) - logger.info(f"Processed successfully: {path}") - return result - except Exception as e: - logger.exception(f"Processing failed: {e}") - raise -``` - -### 日誌規範 - -```python -import logging -import sys - -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s - %(levelname)s - %(message)s", - stream=sys.stderr, -) -logger = logging.getLogger(__name__) - -# 使用說明 -logger.info("Starting process...") -logger.debug(f"Input: {input_path}") -logger.warning(f"Using fallback: {reason}") -logger.error(f"Failed: {error}") -``` - ---- - -## 測試規範 - -### 測試結構 - -``` -tests/ -├── __init__.py -├── test_asr_processor.py -└── test_thumbnail_extractor.py -``` - -### 測試範例 - -```python -import pytest -from pathlib import Path -import sys - -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) - -from asr_processor import run_asr - - -def test_asr_processor_with_valid_video(tmp_path): - video_path = tmp_path / "test.mp4" - output_path = tmp_path / "output.json" - - # 建立測試影片 - video_path.write_text("dummy") - - # 執行 - result = run_asr(str(video_path), str(output_path)) - - # 斷言 - assert output_path.exists() - assert result["segments"] - - -def test_asr_processor_with_invalid_video(): - with pytest.raises(FileNotFoundError): - run_asr("/nonexistent/video.mp4", "/tmp/output.json") -``` - -### 執行測試 - -```bash -# 使用 python3.11 執行測試 -/opt/homebrew/bin/python3.11 -m pytest tests/ -v - -# 包含覆蓋率 -/opt/homebrew/bin/python3.11 -m pytest tests/ --cov=scripts -``` - ---- - -## 監控配置 - -### 監控腳本 - -在 `monitor/config/monitor_config.yaml` 中配置: - -```yaml -service: - - name: "python" - type: "process" - process_name: "python3" - enabled: true - check_interval: 60 - version_lock: "3.11.14" - scripts: - - "/Users/accusys/momentry_core_0.1/scripts/asr_processor.py" - - "/Users/accusys/momentry_core_0.1/scripts/thumbnail_extractor.py" -``` - -### 檢查版本 - -```bash -# 執行 Python 監控 -bash /Users/accusys/momentry_core_0.1/monitor/control/monitor_control.sh check python - -# 查看資料庫記錄 -psql -U accusys -h localhost -d momentry -c "SELECT * FROM python_version_baseline;" -``` - ---- - -## CI/CD 考量 - -### GitHub Actions 範例 - -```yaml -name: Python Tests - -on: [push, pull_request] - -jobs: - test: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.11 - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Run tests - run: | - python -m pytest tests/ -v -``` - ---- - -## 常見問題 - -### Q: 為什麼腳本要用 `#!/opt/homebrew/bin/python3.11` 而不是 `#!/usr/bin/env python3`? - -A: `#!/usr/bin/env python3` 會解析 PATH 中的第一個 `python3`,在 macOS 上可能是: -- `/opt/homebrew/bin/python3` (3.14.3) -- `/usr/bin/python3` (3.9.6) - -明確指定路徑可確保使用正確版本。 - -### Q: Rust 呼叫 Python 腳本時如何確保版本正確? - -A: 有三種方式: -1. Rust 程式碼中使用明確路徑:`Command::new("/opt/homebrew/bin/python3.11")` -2. 設定環境變數 PATH -3. 建立系統別名(不推薦,影響其他程式) - -### Q: 如何管理多個 Python 版本? - -A: 建議使用: -- **pyenv**:管理多個 Python 版本 -- **venv**:隔離專案依賴 -- **Docker**:容器化環境 - ---- - -## 檢查清單 - -新增 Python 腳本時確認: - -- [ ] 使用 `#!/opt/homebrew/bin/python3.11` shebang -- [ ] 包含 docstring 說明功能 -- [ ] 使用 argparse 處理命令行參數 -- [ ] 使用 logging 進行日誌輸出 -- [ ] 錯誤處理適當 -- [ ] 類型提示完整 -- [ ] 更新監控配置 -- [ ] 建立測試案例 - ---- - -## 版本速查 - -| 版本 | 用途 | 路徑 | -|------|------|------| -| 3.11.14 | Momentry venv | /Users/accusys/momentry_core_0.1/venv/bin/python | -| 3.11.14 | 系統安裝 | /opt/homebrew/bin/python3.11 | -| 3.14.3 | 系統預設 | /opt/homebrew/bin/python3 | - ---- - -## 相關文件 - -- [NODEJS.md](./NODEJS.md) - Node.js 開發指南 -- [RUST_DEVELOPMENT.md](./RUST_DEVELOPMENT.md) - Rust 開發規範 -- [monitor_config.yaml](../monitor/config/monitor_config.yaml) - 監控配置 -- [python_monitor.sh](../monitor/service/python_monitor.sh) - Python 監控腳本 diff --git a/docs_v1.0/OPERATIONS/ROOT_BACKUP_VERSIONING.md b/docs_v1.0/OPERATIONS/ROOT_BACKUP_VERSIONING.md deleted file mode 100644 index a486482..0000000 --- a/docs_v1.0/OPERATIONS/ROOT_BACKUP_VERSIONING.md +++ /dev/null @@ -1,450 +0,0 @@ -# Momentry 備份版本管理規範 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren / OpenCode | -| 建立時間 | 2026-03-25 | -| 文件版本 | V1.0 | - ---- - -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | -|------|------|------|--------| -| V1.0 | 2026-03-25 | 建立備份版本管理規範 | OpenCode | - ---- - -## 1. 概述 - -本文檔定義 Momentry 系統的備份版本管理規範,確保新舊架構之間的回滾相容性。 - -### 1.1 版本定義 - -| 版本 | 日期 | 說明 | -|------|------|------| -| v1 | 2026-03-18 | 初始備份架構(不包含新架構組件)| -| v2 | 2026-03-25 | 新架構備份(包含 monitor_jobs, processor_results, Output 目錄)| - -### 1.2 備份版本格式 - -| 版本 | 檔案命名格式 | -|------|-------------| -| v1 | `{service}_{type}_{YYYYMMDD}_{HHMMSS}.{ext}` | -| v2 | `{service}_{type}_v2_{YYYYMMDD}_{HHMMSS}.{ext}` | - -### 1.3 各版本涵蓋範圍 - -| 組件 | v1 | v2 | -|------|-----|-----| -| PostgreSQL (videos, chunks) | ✅ | ✅ | -| PostgreSQL (monitor_jobs) | ❌ | ✅ | -| PostgreSQL (processor_results) | ❌ | ✅ | -| Redis | ✅ | ✅ | -| MongoDB Cache | ⚠️ | ⚠️ | -| Output (probe.json) | ❌ | ✅ | - -> ⚠️ MongoDB 備份目前存在路徑問題,正在修復中 - ---- - -## 2. 備份版本識別 - -### 2.1 檔名識別 - -```bash -# 識別版本 -detect_version() { - local backup_file=$1 - if echo "$backup_file" | grep -q "_v2_"; then - echo "v2" - else - echo "v1" - fi -} - -# 使用範例 -detect_version "postgresql_db_momentry_v2_20260325_030000.sql.gz" -# 輸出: v2 - -detect_version "postgresql_db_momentry_20260324_030000.sql.gz" -# 輸出: v1 -``` - -### 2.2 內容識別 - -```bash -# 檢查是否為 v2 備份 -is_v2_backup() { - local backup_file=$1 - gzip -dc "$backup_file" 2>/dev/null | grep -q "monitor_jobs" && echo "yes" || echo "no" -} - -# 檢查是否包含 processor_results -has_processor_results() { - local backup_file=$1 - gzip -dc "$backup_file" 2>/dev/null | grep -q "processor_results" && echo "yes" || echo "no" -} -``` - -### 2.3 檔案大小比較 - -| 版本 | PostgreSQL 備份大小 | 說明 | -|------|---------------------|------| -| v1 | ~18-19 MB | 基本資料表 | -| v2 | >19 MB | 包含新表格和索引 | - ---- - -## 3. 回滾策略 - -### 3.1 回滾流程圖 - -``` -┌─────────────────────────────────────────┐ -│ 選擇還原目標 │ -└─────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────┐ -│ 選擇備份版本 │ -│ ┌───────────┐ ┌───────────┐ │ -│ │ v1 備份 │ │ v2 備份 │ │ -│ └───────────┘ └───────────┘ │ -└─────────────────────────────────────────┘ - │ - ┌─────────┴─────────┐ - ▼ ▼ - ┌──────────┐ ┌──────────┐ - │ v1 回滾 │ │ v2 回滾 │ - └──────────┘ └──────────┘ - │ │ - ▼ ▼ - ┌──────────┐ ┌──────────┐ - │ 基本資料庫 │ │ 完整還原 │ - └──────────┘ └──────────┘ -``` - -### 3.2 回滾矩陣 - -| 還原目標 | v1 備份 | v2 備份 | -|----------|---------|---------| -| 基本資料庫 | ✅ | ✅ | -| + monitor_jobs | ❌ | ✅ | -| + processor_results | ❌ | ✅ | -| + Output 檔案 | ❌ | ✅ | -| + MongoDB Cache | ⚠️ | ⚠️ | - -### 3.3 回滾相容性說明 - -#### v1 → v2(支援) - -- v1 備份可以還原到 v2 架構 -- 新架構組件會從空白狀態開始 -- 不會造成資料損壞 - -#### v2 → v1(⚠️ 警告) - -``` -⚠️ v2 回滾到 v1 可能導致資料丟失 - -影響範圍: -- monitor_jobs 資料會消失 -- processor_results 資料會消失 -- Output 檔案參照可能失效 - -建議: -1. 在還原前建立 v2 快照 -2. 或使用隔離還原(staging restore) -``` - ---- - -## 4. 還原腳本保護機制 - -### 4.1 還原前檢查 - -```bash -# 還原前檢查版本相容性 -pre_restore_check() { - local backup_file=$1 - local version=$(detect_version "$backup_file") - local current_db_version=$(check_current_db_version) - - echo "備份版本: $version" - echo "目前版本: $current_db_version" - - # v2 → v1: 警告但允許(使用者需確認) - if [ "$version" = "v1" ] && [ "$current_db_version" = "v2" ]; then - echo "⚠️ 警告:即將回滾到 v1" - echo "影響:monitor_jobs 和 processor_results 資料將被清除" - read -p "確認繼續?(y/N): " confirm - [ "$confirm" != "y" ] && exit 1 - fi - - # v1 → v2: 直接允許 - if [ "$version" = "v1" ] && [ "$current_db_version" = "v2" ]; then - echo "ℹ️ 提示:新架構組件將重新初始化" - fi - - # v2 → v2: 直接允許 - # v1 → v1: 直接允許 -} -``` - -### 4.2 隔離還原(Staging Restore) - -```bash -# 只還原到暫存資料庫,不影響生產 -restore_to_staging() { - local backup_file=$1 - local version=$(detect_version "$backup_file") - - echo "執行隔離還原..." - echo "版本: $version" - - # 建立暫存資料庫 - PGPASSWORD="$PG_PASSWORD" psql -U "$PG_USER" -d postgres << EOF - DROP DATABASE IF EXISTS momentry_staging; - CREATE DATABASE momentry_staging; - EOF - - # 還原到暫存資料庫 - PGPASSWORD="$PG_PASSWORD" pg_restore -U "$PG_USER" -d "momentry_staging" \ - --no-owner --no-acl "$backup_file" - - echo "✅ 還原完成:momentry_staging" - echo "驗證命令:psql -U accusys -d momentry_staging -c '\\dt'" -} -``` - -### 4.3 版本驗證命令 - -```bash -# 識別所有備份版本 -ls /Users/accusys/momentry/backup/daily/postgresql/*.sql.gz | \ - xargs -I {} sh -c 'echo "{}: $(detect_version {})"' - -# 驗證 v2 備份內容 -verify_v2_backup() { - local backup_file=$1 - - echo "驗證備份: $backup_file" - - # 檢查 monitor_jobs - if gzip -dc "$backup_file" | grep -q "monitor_jobs"; then - echo "✅ 包含 monitor_jobs" - else - echo "❌ 缺少 monitor_jobs" - return 1 - fi - - # 檢查 processor_results - if gzip -dc "$backup_file" | grep -q "processor_results"; then - echo "✅ 包含 processor_results" - else - echo "❌ 缺少 processor_results" - return 1 - fi - - echo "✅ v2 備份驗證通過" -} -``` - ---- - -## 5. 版本遷移 - -### 5.1 v1 → v2 遷移步驟 - -| 步驟 | 說明 | 驗證 | -|------|------|------| -| 1 | 確認所有 v1 備份已完成 | `ls *.sql.gz \| grep -v v2` | -| 2 | 修改 `backup_all.sh` 加入 v2 標記 | 確認 TIMESTAMP 包含 `v2_` | -| 3 | 修正 MongoDB 路徑 | 確認指向正確目錄 | -| 4 | 新增 Output 目錄備份 | 確認 probe.json 被備份 | -| 5 | 執行測試備份 | 驗證命名格式正確 | -| 6 | 驗證 v2 備份完整性 | `verify_v2_backup` | -| 7 | 正式啟用 v2 備份 | 確認 crontab 使用新版 | - -### 5.2 遷移驗證清單 - -```bash -#!/bin/bash -# verify_v2_migration.sh - -echo "=== v2 遷移驗證 ===" - -# 1. 檢查備份腳本 -echo "1. 檢查備份腳本..." -if grep -q "v2_" /Users/accusys/momentry/scripts/backup_all.sh; then - echo " ✅ 版本標記已啟用" -else - echo " ❌ 版本標記未啟用" -fi - -# 2. 檢查 MongoDB 路徑 -echo "2. 檢查 MongoDB 路徑..." -if grep -q "/opt/homebrew/var/mongodb" /Users/accusys/momentry/scripts/backup_all.sh; then - echo " ✅ MongoDB 路徑已修正" -else - echo " ❌ MongoDB 路徑未修正" -fi - -# 3. 檢查 Output 目錄備份 -echo "3. 檢查 Output 目錄備份..." -if grep -q "momentry_output" /Users/accusys/momentry/scripts/backup_all.sh; then - echo " ✅ Output 目錄備份已啟用" -else - echo " ❌ Output 目錄備份未啟用" -fi - -# 4. 檢查最新備份 -echo "4. 檢查最新備份..." -latest_backup=$(ls -t /Users/accusys/momentry/backup/daily/postgresql/*.sql.gz 2>/dev/null | head -1) -if [ -n "$latest_backup" ]; then - version=$(detect_version "$latest_backup") - echo " 最新備份: $(basename $latest_backup)" - echo " 版本: $version" - if [ "$version" = "v2" ]; then - verify_v2_backup "$latest_backup" - fi -fi - -echo "=== 驗證完成 ===" -``` - ---- - -## 6. 疑難排解 - -### 6.1 常見問題 - -| 問題 | 原因 | 解決方案 | -|------|------|----------| -| 無法識別版本 | 檔名被修改 | 使用內容分析 `gzip -dc \| grep "monitor_jobs"` | -| v2 備份還原失敗 | 磁碟空間不足 | 清理空間後重試 | -| v1 還原覆蓋 v2 | 操作失誤 | 使用隔離還原保護生產資料 | -| MongoDB 備份為空 | 路徑錯誤 | 修正為 `/opt/homebrew/var/mongodb` | - -### 6.2 緊急回滾流程 - -```bash -#!/bin/bash -# emergency_restore.sh - -set -e - -BACKUP_FILE=$1 -VERSION=$2 - -echo "=== 緊急回滾 ===" -echo "備份檔案: $BACKUP_FILE" -echo "目標版本: $VERSION" - -# 1. 建立當前狀態快照 -echo "1. 建立當前狀態快照..." -NOW=$(date +%Y%m%d_%H%M%S) -pg_dump -U accusys -d momentry | gzip > "/tmp/momentry_emergency_$NOW.sql.gz" -echo " 快照: /tmp/momentry_emergency_$NOW.sql.gz" - -# 2. 執行還原 -echo "2. 執行還原..." -gunzip -c "$BACKUP_FILE" | psql -U accusys -d momentry - -# 3. 驗證 -echo "3. 驗證還原..." -psql -U accusys -d momentry -c "SELECT COUNT(*) FROM monitor_jobs;" - -echo "=== 回滾完成 ===" -``` - ---- - -## 7. 備份清單(v2) - -### 7.1 每日備份(v2 格式) - -| 服務 | 備份項目 | 檔案命名 | 說明 | -|------|----------|----------|------| -| PostgreSQL | momentry | `postgresql_db_momentry_v2_{date}_{time}.sql.gz` | 完整資料庫 | -| PostgreSQL | video_register | `postgresql_db_video_register_v2_{date}_{time}.sql.gz` | 影片註冊資料 | -| Redis | RDB | `redis_rdb_v2_{date}_{time}.rdb` | Redis 快照 | -| MongoDB | 資料 | `mongodb_data_v2_{date}_{time}.tar.gz` | MongoDB 資料 | -| n8n | 資料+DB | `n8n_{date}_{time}.tar.gz`, `n8n_db_{date}_{time}.sql.gz` | n8n 完整 | -| SFTPGo | 配置+DB | `sftpgo_{date}_{time}.tar.gz`, `sftpgo_db_{date}_{time}.sql.gz` | SFTPGo | -| Gitea | 資料 | `gitea_{date}_{time}.tar.gz` | Gitea | -| Output | 檔案 | `momentry_output_v2_{date}_{time}.tar.gz` | probe.json 等 | - -### 7.2 備份保留策略 - -| 類型 | 保留期限 | 位置 | -|------|----------|------| -| 每日備份 | 7 天 | `backup/daily/` | -| 每週備份 | 4 週 | `backup/weekly/` | -| 每月備份 | 12 個月 | `backup/monthly/` | -| 歸檔 | 1 年+ | `backup/archive/` | - ---- - -## 8. 相關文件 - -| 文件 | 說明 | -|------|------| -| [SERVICES.md](./SERVICES.md) | 服務說明 | -| [MOMENTRY_CORE_MONITORING.md](./MOMENTRY_CORE_MONITORING.md) | 監控規範 | -| `/Users/accusys/momentry/scripts/backup_all.sh` | 備份腳本 | -| `/Users/accusys/momentry/scripts/restore_all.sh` | 還原腳本 | -| `/Users/accusys/momentry_core_0.1/monitor/storage/backup_monitor.sh` | 備份監控 | - ---- - -## 附錄 A:v2 備份完整性檢查清單 - -```bash -#!/bin/bash -# check_v2_integrity.sh - -BACKUP_DIR="/Users/accusys/momentry/backup/daily" - -echo "=== v2 備份完整性檢查 ===" - -# 檢查 PostgreSQL -echo "1. PostgreSQL..." -pg_backup=$(ls -t "$BACKUP_DIR/postgresql"/postgresql_db_momentry_v2_*.sql.gz 2>/dev/null | head -1) -if [ -n "$pg_backup" ]; then - echo " 備份: $(basename $pg_backup)" - verify_v2_backup "$pg_backup" -else - echo " ❌ 未找到 v2 備份" -fi - -# 檢查 Output -echo "2. Output 目錄..." -output_backup=$(ls -t "$BACKUP_DIR/momentry"/momentry_output_v2_*.tar.gz 2>/dev/null | head -1) -if [ -n "$output_backup" ]; then - echo " 備份: $(basename $output_backup)" - echo " ✅ Output 備份已存在" -else - echo " ❌ 未找到 Output 備份" -fi - -# 檢查 MongoDB -echo "3. MongoDB..." -mongo_backup=$(ls -t "$BACKUP_DIR/mongodb"/mongodb_data_v2_*.tar.gz 2>/dev/null | head -1) -if [ -n "$mongo_backup" ]; then - size=$(stat -f%z "$mongo_backup" 2>/dev/null || stat -c%s "$mongo_backup" 2>/dev/null) - echo " 備份: $(basename $mongo_backup)" - echo " 大小: $size bytes" - if [ "$size" -gt 1000 ]; then - echo " ✅ MongoDB 備份有效" - else - echo " ⚠️ MongoDB 備份可能為空" - fi -else - echo " ❌ 未找到 MongoDB 備份" -fi - -echo "=== 檢查完成 ===" -``` diff --git a/docs_v1.0/OPERATIONS/ROOT_FILE_CHANGE_MANAGEMENT.md b/docs_v1.0/OPERATIONS/ROOT_FILE_CHANGE_MANAGEMENT.md deleted file mode 100644 index ca285ed..0000000 --- a/docs_v1.0/OPERATIONS/ROOT_FILE_CHANGE_MANAGEMENT.md +++ /dev/null @@ -1,323 +0,0 @@ -# 文件修改管理規範 v1.0 - -| 項目 | 內容 | -|------|------| -| 建立者 | Warren | -| 建立時間 | 2026-03-22 | -| 文件版本 | V1.0 | - ---- - -## 1. 概述 - -本文檔定義 Momentry 專案的文件修改流程,確保不同工具/模型對文件的一致性理解,防止誤修改並保留完整的修改紀錄。 - -### 1.1 適用範圍 - -- 所有 `.md` 文件(技術文檔、安裝指南、API 文件等) -- 所有 `.rs` 文件(Rust 源代碼) -- 所有 `.sh` 文件(Shell 腳本) -- 所有 `.yaml` / `.yml` 文件(配置文件) -- 所有 `.json` 文件(配置及數據文件) - -### 1.2 核心原則 - -1. **先讀後改**:修改前必須完整閱讀相關文件 -2. **預檢清單**:修改前執行預檢查步驟 -3. **變更對照**:修改後必須比對差異 -4. **驗證確認**:變更後執行驗證測試 -5. **完整紀錄**:所有修改必須記錄於版本歷史 - ---- - -## 2. 修改前預檢清單 - -### 2.1 文件閱讀要求 - -修改文件前,必須完成以下閱讀: - -| 步驟 | 項目 | 說明 | -|------|------|------| -| 1 | 閱讀完整文件 | 不可僅閱讀部分章節 | -| 2 | 理解文件用途 | 確認文件的目標讀者 | -| 3 | 確認現有術語 | 使用一致的術語和命名 | -| 4 | 查閱相關文件 | 確認相關聯的文件 | - -### 2.2 預檢問題清單 - -在修改前回答以下問題: - -``` -□ 1. 此修改是否影響其他文件? -□ 2. 此修改是否與現有規範衝突? -□ 3. 此修改是否需要更新版本歷史? -□ 4. 此修改是否需要新增測試? -□ 5. 此修改是否需要通知相關人員? -□ 6. 此修改是否有破壞性變更(Breaking Change)? -``` - -### 2.3 預檢命令 - -修改前執行以下命令確認現有狀態: - -```bash -# 1. 確認 git 狀態 -git status - -# 2. 檢查相關文件的最新版本 -git log -3 --oneline - -# 3. 查看現有版本歷史 -cat docs/.md | grep -A 20 "版本歷史" -``` - ---- - -## 3. 文件修改流程 - -### 3.1 標準修改流程 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Step 1: 閱讀 │ -│ ├─ 完整閱讀目標文件 │ -│ └─ 閱讀相關聯文件 │ -├─────────────────────────────────────────────────────────────┤ -│ Step 2: 預檢 │ -│ ├─ 回答預檢問題清單 │ -│ └─ 執行預檢命令 │ -├─────────────────────────────────────────────────────────────┤ -│ Step 3: 規劃 │ -│ ├─ 說明修改內容 │ -│ └─ 列出變更差異 │ -├─────────────────────────────────────────────────────────────┤ -│ Step 4: 修改 │ -│ ├─ 執行修改 │ -│ └─ 更新版本歷史 │ -├─────────────────────────────────────────────────────────────┤ -│ Step 5: 驗證 │ -│ ├─ 執行 lint/format 檢查 │ -│ └─ 執行相關測試 │ -├─────────────────────────────────────────────────────────────┤ -│ Step 6: 提交 │ -│ └─ 撰寫清晰的 commit message │ -└─────────────────────────────────────────────────────────────┘ -``` - -### 3.2 預修改彙報格式 - -在執行修改前,必須先彙報以下內容: - -```markdown -## 檔案 -`` - -## 修改原因 -<說明修改的目的> - -## 變更內容 -```diff -- <刪除的內容> -+ <新增的內容> -``` - -## 版本歷史更新 -| 版本 | 日期 | 內容 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| Vx.x | YYYY-MM-DD | <修改說明> | <操作者> | <使用的工具> | -``` - -### 3.3 版本歷史格式 - -每個文件頂部必須包含版本歷史表: - -```markdown -## 版本歷史 - -| 版本 | 日期 | 目的 | 操作人 | 工具/模型 | -|------|------|------|--------|-----------| -| V1.0 | 2026-03-15 | 創建文件 | Warren | OpenCode / MiniMax M2.5 | -| V1.1 | 2026-03-22 | 更新內容 | Warren | OpenCode / big-pickle | -``` - ---- - -## 4. 變更對照 - -### 4.1 diff 對照 - -修改後必須提供 diff 對照: - -```bash -git diff -``` - -### 4.2 變更類型分類 - -| 類型 | 標記 | 說明 | -|------|------|------| -| 新增 | `+` | 新增內容 | -| 刪除 | `-` | 刪除內容 | -| 修改 | `~` | 修改內容 | -| 移動 | `↕` | 移動位置 | -| 格式 | `@` | 格式變更 | - -### 4.3 變更確認清單 - -``` -□ 1. diff 輸出已確認 -□ 2. 變更符合預期 -□ 3. 無意外變更 -□ 4. 版本歷史已更新 -□ 5. 其他關聯文件已檢查 -``` - ---- - -## 5. 驗證流程 - -### 5.1 自動化驗證 - -修改後執行以下自動化檢查: - -```bash -# Rust 文件 -cargo fmt -- --check -cargo clippy --lib -cargo test --lib - -# Python 文件 -ruff check -ruff format --check - -# Markdown 文件 -markdownlint - -# Shell 文件 -shellcheck -S error -``` - -### 5.2 手動驗證清單 - -``` -□ 1. 文件語法正確 -□ 2. 連結有效 -□ 3. 格式一致 -□ 4. 術語一致 -□ 5. 版本歷史完整 -□ 6. 變更記錄清晰 -``` - ---- - -## 6. 提交規範 - -### 6.1 Commit Message 格式 - -``` -: - - - -