Skip to main content
Tất cả runtime của Asset Index nằm trong .asset_index/ ở root repo. Folder này nằm trong .gitignore và có thể xoá bất kỳ lúc nào (rebuild lần sau sẽ tốn thời gian + LLM call).
.asset_index/
├── index.db                  # SQLite + sqlite-vec database
├── state.json                # runtime state của watcher
└── logs/
    ├── watcher.out.log       # stdout của watcher
    └── watcher.err.log       # stderr (lỗi quan trọng)

index.db

SQLite database chứa 3 bảng (xem schema.sql):

assets

Mỗi row = 1 file media đã index.
CộtKiểuVai trò
idTEXT PKSHA-256 hash của file (lowercase hex)
file_nameTEXTTên file (không kèm path)
file_pathTEXT UNIQUEPath tuyệt đối
source_rootTEXTraw_assets hoặc jobs
job_idTEXTNULL nếu thuộc raw_assets pool
media_typeTEXTimage / video / audio
size_bytesINTEGERKích thước file
mtimeREALModification time (unix epoch)
width, heightINTEGERCho image + video
duration_seconds, fpsREALCho video + audio
has_audioINTEGER0/1 cho video
style, summaryTEXTMô tả do Gemini sinh
transcriptTEXTCho audio (Whisper output)
audio_roleTEXTvoice_over / background_music / sound_effect
tags_json, mood_json, scenes_jsonTEXTJSON arrays
raw_jsonTEXTToàn bộ output gốc của analyzer (audit)
embed_sourceTEXTText đã đem đi embed
embed_modelTEXTtext-embedding-3-small
indexed_atTEXTTimestamp ISO

assets_vec (virtual table sqlite-vec)

CREATE VIRTUAL TABLE assets_vec USING vec0(
  id TEXT PRIMARY KEY,
  embedding FLOAT[1536]
);
Lưu embedding 1536 chiều, dùng cho K-NN search. id join với assets.id.

process_log

Audit trail mỗi lần process_file() chạy:
CộtVai trò
idAuto-increment PK
file_pathPath file đã process
content_hashSHA-256 (nếu compute thành công)
statusok / skipped / failed
errorMessage lỗi (nếu fail)
ran_atTimestamp ISO
Dùng để debug “file này đã từng được process chưa”.

state.json

Watcher viết file này định kỳ — dùng để check trạng thái nhanh mà không cần đọc DB:
{
  "pid": 12345,
  "watcher_started_at": "2026-04-27T08:00:00+07:00",
  "processed_count": 87,
  "last_processed_at": "2026-04-27T10:15:23+07:00",
  "last_processed_path": "raw_assets/images/IMG_0042.jpg",
  "last_error": null,
  "watch_paths": ["raw_assets"],
  "debounce_seconds": 1.5
}
pid được dùng làm single-instance lock — nếu watcher khác cố start sẽ check psutil.pid_exists(pid) và refuse khởi động trùng.

logs/

Stdout, gồm:
  • [watcher] starting… — khởi động
  • [watcher] processed <path> in <X>ms — mỗi file index xong
  • [watcher] skipped <path> — đã có hash khớp
  • [watcher] scan-on-start: N files — đếm khi khởi động
Stderr, gồm:
  • Stack trace khi analyzer fail
  • Cảnh báo từ ffprobe
  • API error từ Gemini/OpenAI (có thể có rate-limit retry message)
Log không tự rotate — nếu file lớn quá có thể truncate thủ công:
> .asset_index/logs/watcher.out.log
> .asset_index/logs/watcher.err.log

Backup / Migration

Để backup index hoàn chỉnh, copy nguyên .asset_index/:
tar -czf asset-index-backup-$(date +%Y%m%d).tar.gz .asset_index/
Restore bằng cách extract về root repo. Lưu ý: file_path trong assets là path tuyệt đối — nếu repo move sang máy khác, query có thể fail. Workaround: re-export bằng exporter.py rồi re-import path tương đối.

Bước tiếp theo

Idempotency

Re-index không tốn LLM call.

Cross-platform

Notes cho macOS / Windows / Linux.