vomebook commited on
Commit
28df2ce
·
verified ·
1 Parent(s): 03bf6c9

Upload prepare_fulltext_index.py

Browse files
Files changed (1) hide show
  1. prepare_fulltext_index.py +90 -0
prepare_fulltext_index.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Activate a verified CCRD index generation from a mounted HF Storage Bucket."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import json
8
+ import os
9
+ import sqlite3
10
+ from pathlib import Path
11
+
12
+
13
+ BASE_DIR = Path(__file__).resolve().parent
14
+ FULLTEXT_DIR = Path(os.environ.get("CCRD_FULLTEXT_DIR", str(BASE_DIR / "data/fulltext")))
15
+ BUCKET_DIR = os.environ.get("CCRD_INDEX_BUCKET_DIR", "").strip()
16
+ TOKENIZER_VERSION = "cjk-bigram-boundary-fts5-v5"
17
+ SOURCES = ("CCRD", "CW")
18
+
19
+
20
+ def sha256(path: Path) -> str:
21
+ digest = hashlib.sha256()
22
+ with path.open("rb") as handle:
23
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
24
+ digest.update(chunk)
25
+ return digest.hexdigest()
26
+
27
+
28
+ def validated_database(bucket: Path, source: str, details: object) -> Path:
29
+ if not isinstance(details, dict):
30
+ raise ValueError(f"{source}: missing manifest details")
31
+ relative_path = details.get("path")
32
+ expected_hash = details.get("sha256")
33
+ expected_documents = details.get("documents")
34
+ expected_fts_rows = details.get("fts_rows")
35
+ if not isinstance(relative_path, str) or not relative_path.startswith("generations/"):
36
+ raise ValueError(f"{source}: invalid database path")
37
+ if not isinstance(expected_hash, str) or len(expected_hash) != 64:
38
+ raise ValueError(f"{source}: invalid database hash")
39
+ if not isinstance(expected_documents, int) or not isinstance(expected_fts_rows, int):
40
+ raise ValueError(f"{source}: invalid document counts")
41
+
42
+ path = (bucket / relative_path).resolve()
43
+ if bucket not in path.parents or not path.is_file():
44
+ raise ValueError(f"{source}: database is outside the bucket or missing")
45
+ if sha256(path) != expected_hash:
46
+ raise ValueError(f"{source}: database hash mismatch")
47
+ with sqlite3.connect(f"file:{path}?mode=ro&immutable=1", uri=True) as connection:
48
+ tokenizer = connection.execute("SELECT value FROM metadata WHERE key = 'tokenizer_version'").fetchone()
49
+ documents = int(connection.execute("SELECT COUNT(*) FROM documents").fetchone()[0])
50
+ fts_rows = int(connection.execute("SELECT COUNT(*) FROM content_fts").fetchone()[0])
51
+ integrity = connection.execute("PRAGMA integrity_check").fetchone()[0]
52
+ if not tokenizer or tokenizer[0] != TOKENIZER_VERSION:
53
+ raise ValueError(f"{source}: tokenizer version mismatch")
54
+ if documents != expected_documents or fts_rows != expected_fts_rows or integrity != "ok":
55
+ raise ValueError(f"{source}: database structure mismatch")
56
+ return path
57
+
58
+
59
+ def main() -> int:
60
+ if not BUCKET_DIR:
61
+ print("ccrd_bucket_index=disabled")
62
+ return 1
63
+ bucket = Path(BUCKET_DIR).resolve()
64
+ manifest_path = bucket / "current.json"
65
+ try:
66
+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
67
+ if manifest.get("format") != 1 or manifest.get("tokenizer_version") != TOKENIZER_VERSION:
68
+ raise ValueError("invalid manifest version")
69
+ databases = manifest.get("databases")
70
+ if not isinstance(databases, dict):
71
+ raise ValueError("missing databases manifest")
72
+ paths = {source: validated_database(bucket, source, databases.get(source)) for source in SOURCES}
73
+ except Exception as exc:
74
+ print(f"ccrd_bucket_index=unavailable:{type(exc).__name__}:{exc}")
75
+ return 1
76
+
77
+ FULLTEXT_DIR.mkdir(parents=True, exist_ok=True)
78
+ for source, path in paths.items():
79
+ target = FULLTEXT_DIR / f"{source}.sqlite3"
80
+ temporary = target.with_suffix(".sqlite3.bucket")
81
+ temporary.unlink(missing_ok=True)
82
+ temporary.symlink_to(path)
83
+ temporary.replace(target)
84
+ (FULLTEXT_DIR / "build-status.json").write_text(json.dumps({"state": "ready", "source": "bucket"}), encoding="utf-8")
85
+ print("ccrd_bucket_index=ready")
86
+ return 0
87
+
88
+
89
+ if __name__ == "__main__":
90
+ raise SystemExit(main())