105 lines
3.7 KiB
Python
105 lines
3.7 KiB
Python
import os
|
|
import json
|
|
import sqlite3
|
|
import requests
|
|
from typing import Dict, Any
|
|
from rapidfuzz import fuzz
|
|
|
|
class WikidataVerifier:
|
|
"""
|
|
Checks if an artist has a Wikidata entity with local SQLite caching.
|
|
"""
|
|
SEARCH_URL = "https://www.wikidata.org/w/api.php"
|
|
|
|
def __init__(self, db_path: str = ".cache/verifiers_cache.sqlite"):
|
|
self.headers = {
|
|
"User-Agent": "HiffiArtistIntelligence/1.0 (contact@superlabs.co)"
|
|
}
|
|
self.db_path = db_path
|
|
os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
|
|
self._init_db()
|
|
|
|
def _init_db(self):
|
|
with sqlite3.connect(self.db_path) as conn:
|
|
conn.execute("""
|
|
CREATE TABLE IF NOT EXISTS wikidata_cache (
|
|
artist_name TEXT PRIMARY KEY,
|
|
data_json TEXT,
|
|
cached_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
|
|
def _get_cache(self, name: str) -> Dict[str, Any]:
|
|
with sqlite3.connect(self.db_path) as conn:
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT data_json FROM wikidata_cache WHERE artist_name = ?", (name.lower(),))
|
|
row = cursor.fetchone()
|
|
if row:
|
|
return json.loads(row[0])
|
|
return None
|
|
|
|
def _set_cache(self, name: str, data: Dict[str, Any]):
|
|
with sqlite3.connect(self.db_path) as conn:
|
|
conn.execute(
|
|
"INSERT OR REPLACE INTO wikidata_cache (artist_name, data_json) VALUES (?, ?)",
|
|
(name.lower(), json.dumps(data))
|
|
)
|
|
|
|
def verify_artist(self, name: str) -> Dict[str, Any]:
|
|
if not name or not name.strip():
|
|
return {"verified": False, "confidence": 0.0, "reason": "empty_name"}
|
|
|
|
cleaned_name = name.strip()
|
|
|
|
# Check local cache first
|
|
cached = self._get_cache(cleaned_name)
|
|
if cached:
|
|
return cached
|
|
|
|
params = {
|
|
"action": "wbsearchentities",
|
|
"format": "json",
|
|
"language": "en",
|
|
"type": "item",
|
|
"search": cleaned_name,
|
|
"limit": 3
|
|
}
|
|
|
|
try:
|
|
resp = requests.get(self.SEARCH_URL, headers=self.headers, params=params, timeout=10)
|
|
if resp.status_code != 200:
|
|
result = {"verified": False, "confidence": 0.0, "status_code": resp.status_code}
|
|
return result
|
|
|
|
results = resp.json().get("search", [])
|
|
if not results:
|
|
result = {"verified": False, "confidence": 0.0, "reason": "not_found"}
|
|
self._set_cache(cleaned_name, result)
|
|
return result
|
|
|
|
best = results[0]
|
|
label = best.get("label", "")
|
|
desc = best.get("description", "").lower()
|
|
|
|
music_keywords = ["musician", "singer", "rapper", "band", "record producer", "songwriter", "artist", "group"]
|
|
is_music_entity = any(k in desc for k in music_keywords)
|
|
|
|
similarity = fuzz.token_sort_ratio(cleaned_name.lower(), label.lower()) / 100.0
|
|
confidence = round(similarity * (1.0 if is_music_entity else 0.5), 2)
|
|
|
|
result = {
|
|
"verified": confidence >= 0.75,
|
|
"confidence": confidence,
|
|
"wikidata_id": best.get("id"),
|
|
"label": label,
|
|
"description": best.get("description", "")
|
|
}
|
|
self._set_cache(cleaned_name, result)
|
|
return result
|
|
except Exception as e:
|
|
return {"verified": False, "confidence": 0.0, "error": str(e)}
|
|
|
|
if __name__ == "__main__":
|
|
verifier = WikidataVerifier()
|
|
print("Testing Wikidata Caching...")
|
|
print(verifier.verify_artist("Kendrick Lamar")) |