|
|
""" |
|
|
Script to verify database setup and migrations. |
|
|
""" |
|
|
import os |
|
|
import sys |
|
|
from pathlib import Path |
|
|
|
|
|
ROOT_DIR = Path(__file__).resolve().parents[2] |
|
|
BACKEND_DIR = ROOT_DIR / "backend" |
|
|
|
|
|
HUE_PORTAL_DIR = BACKEND_DIR / "hue_portal" |
|
|
|
|
|
for path in (HUE_PORTAL_DIR, BACKEND_DIR, ROOT_DIR): |
|
|
if str(path) not in sys.path: |
|
|
sys.path.insert(0, str(path)) |
|
|
|
|
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hue_portal.hue_portal.settings") |
|
|
|
|
|
import django |
|
|
django.setup() |
|
|
|
|
|
from django.db import connection |
|
|
from hue_portal.core.models import Procedure, Fine, Office, Advisory, AuditLog, MLMetrics, Synonym |
|
|
|
|
|
|
|
|
def verify_extensions(): |
|
|
"""Verify PostgreSQL extensions are enabled.""" |
|
|
print("\n" + "="*60) |
|
|
print("Verifying PostgreSQL Extensions") |
|
|
print("="*60) |
|
|
|
|
|
with connection.cursor() as cursor: |
|
|
cursor.execute(""" |
|
|
SELECT extname, extversion |
|
|
FROM pg_extension |
|
|
WHERE extname IN ('pg_trgm', 'unaccent') |
|
|
ORDER BY extname; |
|
|
""") |
|
|
results = cursor.fetchall() |
|
|
|
|
|
if results: |
|
|
print("β
Extensions enabled:") |
|
|
for extname, extversion in results: |
|
|
print(f" - {extname}: {extversion}") |
|
|
else: |
|
|
print("β No extensions found") |
|
|
return len(results) == 2 |
|
|
|
|
|
|
|
|
def verify_tables(): |
|
|
"""Verify all tables exist.""" |
|
|
print("\n" + "="*60) |
|
|
print("Verifying Tables") |
|
|
print("="*60) |
|
|
|
|
|
tables = [ |
|
|
("core_procedure", Procedure), |
|
|
("core_fine", Fine), |
|
|
("core_office", Office), |
|
|
("core_advisory", Advisory), |
|
|
("core_auditlog", AuditLog), |
|
|
("core_mlmetrics", MLMetrics), |
|
|
("core_synonym", Synonym), |
|
|
] |
|
|
|
|
|
all_ok = True |
|
|
for table_name, model_class in tables: |
|
|
try: |
|
|
count = model_class.objects.count() |
|
|
print(f"β
{table_name}: {count} records") |
|
|
except Exception as e: |
|
|
print(f"β {table_name}: Error - {e}") |
|
|
all_ok = False |
|
|
|
|
|
return all_ok |
|
|
|
|
|
|
|
|
def verify_fields(): |
|
|
"""Verify BM25 and embedding fields exist.""" |
|
|
print("\n" + "="*60) |
|
|
print("Verifying Fields") |
|
|
print("="*60) |
|
|
|
|
|
models_to_check = [ |
|
|
("Procedure", Procedure), |
|
|
("Fine", Fine), |
|
|
("Office", Office), |
|
|
("Advisory", Advisory), |
|
|
] |
|
|
|
|
|
all_ok = True |
|
|
for model_name, model_class in models_to_check: |
|
|
has_tsv = hasattr(model_class, 'tsv_body') |
|
|
has_embedding = hasattr(model_class, 'embedding') |
|
|
|
|
|
if has_tsv and has_embedding: |
|
|
print(f"β
{model_name}: tsv_body β, embedding β") |
|
|
else: |
|
|
print(f"β {model_name}: tsv_body={has_tsv}, embedding={has_embedding}") |
|
|
all_ok = False |
|
|
|
|
|
|
|
|
has_intent = hasattr(AuditLog, 'intent') |
|
|
has_confidence = hasattr(AuditLog, 'confidence') |
|
|
has_latency = hasattr(AuditLog, 'latency_ms') |
|
|
|
|
|
if has_intent and has_confidence and has_latency: |
|
|
print(f"β
AuditLog: intent β, confidence β, latency_ms β") |
|
|
else: |
|
|
print(f"β AuditLog: intent={has_intent}, confidence={has_confidence}, latency_ms={has_latency}") |
|
|
all_ok = False |
|
|
|
|
|
|
|
|
if hasattr(MLMetrics, 'date'): |
|
|
print(f"β
MLMetrics: model exists") |
|
|
else: |
|
|
print(f"β MLMetrics: model not found") |
|
|
all_ok = False |
|
|
|
|
|
return all_ok |
|
|
|
|
|
|
|
|
def verify_indexes(): |
|
|
"""Verify GIN indexes for tsv_body.""" |
|
|
print("\n" + "="*60) |
|
|
print("Verifying Indexes") |
|
|
print("="*60) |
|
|
|
|
|
with connection.cursor() as cursor: |
|
|
cursor.execute(""" |
|
|
SELECT indexname, tablename |
|
|
FROM pg_indexes |
|
|
WHERE schemaname = 'public' |
|
|
AND indexname LIKE '%_tsv_idx' |
|
|
ORDER BY tablename; |
|
|
""") |
|
|
results = cursor.fetchall() |
|
|
|
|
|
if results: |
|
|
print("β
GIN indexes found:") |
|
|
for indexname, tablename in results: |
|
|
print(f" - {indexname} on {tablename}") |
|
|
else: |
|
|
print("β οΈ No GIN indexes found (may need to run migrations)") |
|
|
|
|
|
return len(results) >= 4 |
|
|
|
|
|
|
|
|
def test_bm25_search(): |
|
|
"""Test BM25 search functionality.""" |
|
|
print("\n" + "="*60) |
|
|
print("Testing BM25 Search") |
|
|
print("="*60) |
|
|
|
|
|
try: |
|
|
from hue_portal.core.search_ml import search_with_ml |
|
|
|
|
|
|
|
|
from hue_portal.core.models import Fine |
|
|
|
|
|
if Fine.objects.count() > 0: |
|
|
results = search_with_ml( |
|
|
Fine.objects.all(), |
|
|
query="vượt ΔΓ¨n Δα»", |
|
|
text_fields=["name", "code", "article"], |
|
|
top_k=5, |
|
|
use_hybrid=False |
|
|
) |
|
|
print(f"β
BM25 search test: Found {len(results)} results") |
|
|
if results: |
|
|
print(f" First result: {results[0].name[:50]}...") |
|
|
return True |
|
|
else: |
|
|
print("β οΈ No Fine records to test with") |
|
|
return True |
|
|
except Exception as e: |
|
|
print(f"β BM25 search test failed: {e}") |
|
|
return False |
|
|
|
|
|
|
|
|
def main(): |
|
|
print("="*60) |
|
|
print("Database Setup Verification") |
|
|
print("="*60) |
|
|
|
|
|
results = { |
|
|
"extensions": verify_extensions(), |
|
|
"tables": verify_tables(), |
|
|
"fields": verify_fields(), |
|
|
"indexes": verify_indexes(), |
|
|
"bm25_search": test_bm25_search(), |
|
|
} |
|
|
|
|
|
print("\n" + "="*60) |
|
|
print("Summary") |
|
|
print("="*60) |
|
|
|
|
|
all_passed = all(results.values()) |
|
|
|
|
|
for check, passed in results.items(): |
|
|
status = "β
PASS" if passed else "β FAIL" |
|
|
print(f"{status}: {check}") |
|
|
|
|
|
if all_passed: |
|
|
print("\nπ All checks passed! Database is ready.") |
|
|
else: |
|
|
print("\nβ οΈ Some checks failed. Please review above.") |
|
|
|
|
|
return 0 if all_passed else 1 |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
sys.exit(main()) |
|
|
|
|
|
|