-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsemantic_alignment.py
More file actions
84 lines (66 loc) · 2.99 KB
/
Copy pathsemantic_alignment.py
File metadata and controls
84 lines (66 loc) · 2.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# structuredweb_auditor/rules/semantic_alignment.py
import re
from bs4 import BeautifulSoup
from typing import List, Dict
# Common and domain-specific noise terms to skip
STOPWORDS = set([
"the", "and", "for", "with", "that", "this", "from", "are", "was", "were",
"has", "have", "had", "you", "your", "our", "but", "not", "any", "can",
"more", "all", "its", "out", "get", "how", "use", "see", "now", "new",
"we", "us", "they", "their", "them", "it", "on", "in", "by", "as", "an",
"of", "a", "to", "is", "or", "be", "at", "via", "if",
# AI Structured Web domain-specific noise
"structured", "web", "ai", "indexer", "resolver", "node", "mesh",
"verify", "dual", "layered", "handshake", "agent", "subnode", "compliance",
"claim", "license", "category", "link", "endpoint", "semantic", "trust"
])
def extract_keywords(text: str) -> List[str]:
words = re.findall(r"\b[a-zA-Z0-9]{3,}\b", text.lower())
return [word for word in words if word not in STOPWORDS]
def extract_json_ld_keywords(json_ld_blocks: List[dict]) -> List[str]:
descriptions = []
def extract_desc(obj):
if isinstance(obj, dict):
for k, v in obj.items():
if "description" in k.lower() or "keywords" in k.lower():
if isinstance(v, str):
descriptions.append(v)
elif isinstance(v, list):
descriptions.extend([str(i) for i in v])
elif isinstance(v, (dict, list)):
extract_desc(v)
elif isinstance(obj, list):
for item in obj:
extract_desc(item)
for block in json_ld_blocks:
extract_desc(block)
return extract_keywords(" ".join(descriptions))
def extract_microdata_keywords(microdata_items: List[dict]) -> List[str]:
desc_texts = []
for item in microdata_items:
props = item.get("props", {})
for key, val in props.items():
if "description" in key.lower() and isinstance(val, str):
desc_texts.append(val)
return extract_keywords(" ".join(desc_texts))
def audit_semantic_alignment(
html: str,
json_ld_blocks: List[dict],
microdata_items: List[dict]
) -> Dict:
soup = BeautifulSoup(html, "html.parser")
html_text = soup.get_text(separator=" ", strip=True)
html_keywords = set(extract_keywords(html_text))
json_keywords = set(extract_json_ld_keywords(json_ld_blocks))
micro_keywords = set(extract_microdata_keywords(microdata_items))
sd_keywords = json_keywords.union(micro_keywords)
shared = sd_keywords.intersection(html_keywords)
alignment_percent = (
round(len(shared) / len(sd_keywords) * 100, 2) if sd_keywords else 0
)
return {
"alignment_percent": alignment_percent,
"shared_terms": sorted(list(shared)),
"missing_terms": sorted(list(sd_keywords - html_keywords)),
"total_sd_terms": len(sd_keywords)
}