From df0f0515a0e0fa1fab9a30ec1bc844fa0d2b0b87 Mon Sep 17 00:00:00 2001 From: Adrian Miesikowski Date: Tue, 17 Feb 2026 23:55:48 +0100 Subject: [PATCH] feat: add OpenClaw LLM scoring pipeline for all domains and surface in panel --- api.php | 5 ++- export_latest_domains.py | 23 +++++++++++++ import_llm_scores.py | 71 ++++++++++++++++++++++++++++++++++++++++ index.html | 4 ++- init_db.py | 11 +++++++ refresh_domain_data.py | 10 ++++++ 6 files changed, 122 insertions(+), 2 deletions(-) create mode 100755 export_latest_domains.py create mode 100755 import_llm_scores.py diff --git a/api.php b/api.php index 60e8d36..c8ea37e 100644 --- a/api.php +++ b/api.php @@ -33,12 +33,15 @@ if ($action === 'domains') { $prevRunId = $prev['run_id'] ?? ''; $sql = "SELECT d.domain, d.tld, d.score, d.status, d.keywords_json, + ls.llm_score, ls.decision, ls.reason, CASE WHEN :prev = '' THEN 1 WHEN EXISTS (SELECT 1 FROM domains p WHERE p.run_id = :prev AND p.domain = d.domain) THEN 0 ELSE 1 END AS is_new - FROM domains d WHERE d.run_id = :run"; + FROM domains d + LEFT JOIN llm_scores ls ON ls.run_id = d.run_id AND ls.domain = d.domain + WHERE d.run_id = :run"; if ($q !== '') $sql .= " AND d.domain LIKE :q"; if ($tld !== '') $sql .= " AND d.tld = :tld"; diff --git a/export_latest_domains.py b/export_latest_domains.py new file mode 100755 index 0000000..3af3e67 --- /dev/null +++ b/export_latest_domains.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +import json +import sqlite3 +from pathlib import Path + +BASE = Path(__file__).resolve().parent +DB = BASE / 'data' / 'domainhunter.db' + +con = sqlite3.connect(DB) +cur = con.cursor() +run_id = cur.execute("SELECT value FROM metadata WHERE key='latest_run_id'").fetchone() +run_id = run_id[0] if run_id else '' +scanned = cur.execute("SELECT value FROM metadata WHERE key='latest_scanned_at'").fetchone() +scanned = scanned[0] if scanned else '' +rows = cur.execute("SELECT domain,tld,score,status,keywords_json FROM domains WHERE run_id=? ORDER BY score DESC,domain ASC", (run_id,)).fetchall() +items=[] +for d,tld,score,status,kw in rows: + try: + kws=json.loads(kw or '[]') + except Exception: + kws=[] + items.append({"domain":d,"tld":tld,"score":score,"status":status,"keywords":kws}) +print(json.dumps({"runId":run_id,"scannedAt":scanned,"items":items}, ensure_ascii=False, indent=2)) diff --git a/import_llm_scores.py b/import_llm_scores.py new file mode 100755 index 0000000..e185bfd --- /dev/null +++ b/import_llm_scores.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +import json +import sqlite3 +import sys +from pathlib import Path + +BASE = Path(__file__).resolve().parent +DB = BASE / 'data' / 'domainhunter.db' + + +def main(): + if len(sys.argv) < 2: + print('Usage: import_llm_scores.py ') + sys.exit(1) + + src = Path(sys.argv[1]) + if not src.exists(): + print(f'File not found: {src}') + sys.exit(2) + + payload = json.loads(src.read_text(encoding='utf-8')) + items = payload if isinstance(payload, list) else payload.get('items', []) + + con = sqlite3.connect(DB) + cur = con.cursor() + cur.executescript(''' + CREATE TABLE IF NOT EXISTS llm_scores ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + run_id TEXT, + domain TEXT, + llm_score REAL, + decision TEXT, + reason TEXT, + updated_at TEXT, + UNIQUE(run_id, domain) + ); + ''') + + run_id = None + if isinstance(payload, dict): + run_id = payload.get('runId') + if not run_id: + r = cur.execute("SELECT value FROM metadata WHERE key='latest_run_id'").fetchone() + run_id = (r[0] if r else '') + + count = 0 + for it in items: + d = (it.get('domain') or '').strip().lower() + if not d: + continue + score = it.get('llm_score', None) + dec = (it.get('decision') or '').strip().lower()[:32] + reason = (it.get('reason') or '').strip()[:500] + cur.execute(''' + INSERT INTO llm_scores(run_id, domain, llm_score, decision, reason, updated_at) + VALUES(?,?,?,?,?,datetime('now')) + ON CONFLICT(run_id, domain) DO UPDATE SET + llm_score=excluded.llm_score, + decision=excluded.decision, + reason=excluded.reason, + updated_at=excluded.updated_at + ''', (run_id, d, score, dec, reason)) + count += 1 + + con.commit() + con.close() + print(f'OK imported llm scores: {count} for run {run_id}') + + +if __name__ == '__main__': + main() diff --git a/index.html b/index.html index 9e2c4db..58247c5 100644 --- a/index.html +++ b/index.html @@ -54,7 +54,7 @@

TOP domen + porównanie cen (rejestracja / odnowienie)

- +
DomenaTLDScoreStatusOferty (top 3)
DomenaTLDScoreLLMStatusOferty (top 3)
@@ -133,9 +133,11 @@ function renderRows(){ }).join('') : `Brak danych cenowych dla .${d.tld}`; + const llm = (d.llm_score!==null && d.llm_score!==undefined) ? `${Number(d.llm_score).toFixed(1)} ${d.decision ? `(${d.decision})` : ''}` : '—'; tr.innerHTML = `${d.domain} ${d.is_new ? `NEW` : ''} .${d.tld} ${d.score} + ${llm} ${d.status || 'available'} ${offersHtml}`; rows.appendChild(tr); diff --git a/init_db.py b/init_db.py index 0edf923..e2bfb8e 100644 --- a/init_db.py +++ b/init_db.py @@ -37,6 +37,17 @@ CREATE TABLE IF NOT EXISTS registrar_prices ( updated_at TEXT, UNIQUE(registrar, tld) ); + +CREATE TABLE IF NOT EXISTS llm_scores ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + run_id TEXT, + domain TEXT, + llm_score REAL, + decision TEXT, + reason TEXT, + updated_at TEXT, + UNIQUE(run_id, domain) +); ''') con.commit() con.close() diff --git a/refresh_domain_data.py b/refresh_domain_data.py index e6590a3..6b7c020 100755 --- a/refresh_domain_data.py +++ b/refresh_domain_data.py @@ -96,6 +96,16 @@ def main(): updated_at TEXT, UNIQUE(registrar, tld) ); + CREATE TABLE IF NOT EXISTS llm_scores ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + run_id TEXT, + domain TEXT, + llm_score REAL, + decision TEXT, + reason TEXT, + updated_at TEXT, + UNIQUE(run_id, domain) + ); ''') run_id = latest.get('runId')