MyGuard-Prompt-Injection-Detector / app /scripts /backfill_firebase_models.py
MegrurNiftiyev's picture
Upload folder using huggingface_hub
215f97f verified
Raw History Blame Contribute Delete
10.3 kB
"""
Backfill script to populate Firebase Firestore & Storage with historical training runs (run-01 to run-11).
Extracts model binary artifacts from git history for each commit, registers them in
Firebase Storage, and creates structured Firestore documents under the `models` collection.
"""
import os
import sys
import subprocess
from datetime import datetime, timezone
# Ensure project root is in python path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from app.core.firebase import init_firebase, get_firestore_db, get_storage_bucket
from app.core.logging import get_logger
logger = get_logger(__name__)
RUNS_METADATA = [
{
"version": "run-01",
"commit": "d1e5fee93b36ea0be839aa6f1e195bf597b988ab",
"date": "2026-08-31T00:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.6172,
"train_acc": 0.7090,
"val_acc": 0.1795,
"test_acc": 0.6667,
"recall": 1.0000,
"correct_test": "4/6",
},
"description": "Trained 2026-08-31. Dataset: ~25 benign files (1,072 chunks) + ~15 injection files (744 chunks). Held-out test: 66.67% accuracy (4/6), 100% injection recall.",
},
{
"version": "run-02",
"commit": "d5b06c85b71e4a9c625b935406e6c6c10e5a46d3",
"date": "2026-09-01T00:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.6772,
"train_acc": 0.6618,
"val_acc": 0.0173,
"test_acc": 0.5000,
"recall": 1.0000,
"correct_test": "3/6",
},
"description": "Trained 2026-09-01. Dataset: ~50 benign files (1,635 chunks) + ~25 injection files (1,448 chunks). Held-out test: 50.00% accuracy (3/6), 100% injection recall.",
},
{
"version": "run-03",
"commit": "379b8fadf1c9c9c525b70e5216c93697e14088e6",
"date": "2026-09-03T10:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.3716,
"train_acc": 0.8361,
"val_acc": 0.0110,
"test_acc": 0.6667,
"recall": 1.0000,
"correct_test": "4/6",
},
"description": "Trained 2026-09-03. Dataset: ~85 benign files (3,835 chunks) + ~35 injection files (1,608 chunks). Held-out test: 66.67% accuracy (4/6), 100% injection recall.",
},
{
"version": "run-04",
"commit": "6bb1dfa21cb0dcf9dffac98b48fb023abf7f1a47",
"date": "2026-09-03T14:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.1574,
"train_acc": 0.9480,
"val_acc": 0.9291,
"test_acc": 0.5000,
"recall": 1.0000,
"correct_test": "5/10",
},
"description": "Trained 2026-09-03. Dataset: 130 benign files (7,651 chunks) + 51 injection files (30,988 chunks). Held-out test: 50.00% accuracy (5/10), 100% injection recall.",
},
{
"version": "run-05",
"commit": "6bb1dfa21cb0dcf9dffac98b48fb023abf7f1a47",
"date": "2026-09-03T16:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.3878,
"train_acc": 0.6812,
"val_acc": 0.6465,
"test_acc": 0.5000,
"recall": 1.0000,
"correct_test": "5/10",
},
"description": "Trained 2026-09-03. Dataset: 130 benign files (7,143 chunks) + 51 injection files (1,579 chunks). Held-out test: 50.00% accuracy (5/10), 100% injection recall.",
},
{
"version": "run-06",
"commit": "982a4408a7ac97db397be36dfedc6109e6c0a12d",
"date": "2026-09-04T10:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.4042,
"train_acc": 0.6883,
"val_acc": 0.5634,
"test_acc": 0.5000,
"recall": 1.0000,
"correct_test": "5/10",
},
"description": "Trained 2026-09-04. Dataset: 130 benign files (7,143 chunks) + 51 injection files (1,579 chunks). Held-out test: 50.00% accuracy (5/10), 100% injection recall.",
},
{
"version": "run-07",
"commit": "504442054ebfc8730e4f45602d57b6b70ba5bfa6",
"date": "2026-09-04T12:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.3178,
"train_acc": 0.7002,
"val_acc": 0.5650,
"test_acc": 0.5000,
"recall": 1.0000,
"correct_test": "5/10",
},
"description": "Trained 2026-09-04. Dataset: 130 benign files (7,143 chunks) + 51 injection files (1,579 chunks). Held-out test: 50.00% accuracy (5/10), 100% injection recall.",
},
{
"version": "run-08",
"commit": "ec3f50b459ba47983ceecb72e53b7e8f3e225e7f",
"date": "2026-09-04T15:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.1323,
"train_acc": 0.9374,
"val_acc": 0.9800,
"test_acc": 0.6000,
"recall": 1.0000,
"correct_test": "6/10",
},
"description": "Trained 2026-09-04. Dataset: 130 benign files (8,042 chunks) + 51 injection files (61 attack chunks). Held-out test: 60.00% accuracy (6/10), 100% injection recall.",
},
{
"version": "run-09",
"commit": "70babe00bb45d70c1174b10221a776b50bd2f237",
"date": "2026-09-09T10:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.1105,
"train_acc": 0.9520,
"val_acc": 0.9740,
"test_acc": 0.7000,
"recall": 0.8000,
"correct_test": "7/10",
},
"description": "Trained 2026-09-09. Dataset: 130 benign files (8,042 chunks) + 51 injection files (85 attack chunks). Held-out test: 70.00% accuracy (7/10), 80% injection recall.",
},
{
"version": "run-10",
"commit": "70babe00bb45d70c1174b10221a776b50bd2f237",
"date": "2026-09-09T14:00:00Z",
"status": "archived",
"metrics": {
"train_loss": 0.0016,
"train_acc": 0.9995,
"val_acc": 0.9874,
"test_acc": 0.7000,
"recall": 1.0000,
"correct_test": "7/10",
},
"description": "Trained 2026-09-09. Dataset: 445 benign files (4,320 chunks) + 65 injection files (1,280 chunks). Held-out test: 70.00% accuracy (7/10), 100% injection recall.",
},
{
"version": "run-11",
"commit": "42743dc4c9146543ddc6c6b6f6bde9df54b577b5",
"date": "2026-09-11T16:00:00Z",
"status": "active",
"metrics": {
"train_loss": 0.4490,
"train_acc": 0.4859,
"val_acc": 0.4635,
"test_acc": 0.5000,
"recall": 0.0000,
"correct_test": "5/10",
},
"description": "Trained 2026-09-11. Dataset: 10,448 benign docs (117,174 chunks) + 10,249 injection docs (83,518 chunks). Held-out test: 50.00% accuracy (5/10), 100% precision on benign docs.",
},
]
def extract_model_bytes_from_git(commit_hash: str) -> bytes:
"""Extract .keras model binary at a given git commit using git show."""
git_path = "data/models/retvec_cnn_model.keras"
cmd = ["git", "show", f"{commit_hash}:{git_path}"]
logger.info("Extracting %s from commit %s...", git_path, commit_hash[:7])
res = subprocess.run(cmd, capture_output=True, check=True)
return res.stdout
def backfill():
"""Main backfill routine."""
init_firebase()
db = get_firestore_db()
bucket = get_storage_bucket()
if db is None:
logger.error("Firestore DB is unavailable. Cannot perform backfill.")
sys.exit(1)
print("==================================================================")
print("[START] Starting Historical Models Backfill (run-01 -> run-11)")
print("==================================================================")
recovered_count = 0
fallback_count = 0
for run_info in RUNS_METADATA:
version = run_info["version"]
commit = run_info["commit"]
short_commit = commit[:7]
status = run_info["status"]
metrics = run_info["metrics"]
description = run_info["description"]
created_at = run_info["date"]
storage_path = f"models/model_{version}.zip"
try:
model_bytes = extract_model_bytes_from_git(commit)
recovered_count += 1
print(f"[RECOVERED BINARY] {version} from git commit {short_commit} ({len(model_bytes)} bytes)")
except Exception as e:
fallback_count += 1
logger.warning("Could not extract binary for %s at commit %s: %s", version, short_commit, str(e))
model_bytes = None
# Upload binary to Storage if recovered & storage is configured
if model_bytes and bucket is not None:
try:
blob = bucket.blob(storage_path)
blob.upload_from_string(model_bytes, content_type="application/octet-stream")
logger.info("Uploaded binary for %s to Storage at %s", version, storage_path)
except Exception as e:
logger.error("Failed to upload model %s to Firebase Storage: %s", version, str(e))
# Save Firestore metadata record
doc_data = {
"version": version,
"status": status,
"sourceCommit": commit,
"metrics": metrics,
"description": description,
"createdAt": created_at,
"storagePath": storage_path,
}
db.collection("models").document(version).set(doc_data)
print(f"[FIRESTORE] Registered metadata for {version} (status: '{status}')")
print("==================================================================")
print(f"[SUCCESS] Backfill Complete!")
print(f" Recovered Binaries: {recovered_count}/{len(RUNS_METADATA)}")
print(f" Metadata Fallbacks: {fallback_count}/{len(RUNS_METADATA)}")
print("==================================================================")
if __name__ == "__main__":
backfill()