V.AISTUDIO / app /seo_gen.py
bep40's picture
Upload app/seo_gen.py
9d4ca77 verified
Raw
History Blame
4.17 kB
#!/usr/bin/env python3
import json, re, unicodedata, os, time
from huggingface_hub import HfApi, hf_hub_download
def download_index():
print("[1/4] Downloading index.html...")
path = hf_hub_download("bep40/V.AISTUDIO", "index.html", repo_type="space")
with open(path) as f:
html = f.read()
print(f" Downloaded {len(html):,} bytes")
return html
def extract_products(html):
print("[2/4] Extracting products...")
idx = html.find('var products = ')
if idx == -1:
idx = html.find('var products=')
if idx == -1:
idx = html.find('products=')
if idx == -1:
raise ValueError("Cannot find products")
start = html.find('[', idx)
bracket_count = 0
end = start
in_string = False
for i in range(start, len(html)):
c = html[i]
if c == '"' and (i == 0 or html[i-1] != '\\'):
in_string = not in_string
elif not in_string:
if c == '[': bracket_count += 1
elif c == ']':
bracket_count -= 1
if bracket_count == 0:
end = i + 1
break
raw = html[start:end]
products = json.loads(raw)
print(f" Found {len(products):,} products")
if products:
print(f" Sample: {json.dumps(products[0], ensure_ascii=False)[:200]}")
return products
def generate_stubs(products):
print("[3/4] Generating stubs...")
saved = 0
seen = set()
api = HfApi()
for p in products:
slug = p.get('slug', '')
if not slug:
slug = p.get('name', f'p-{saved}')
slug = unicodedata.normalize('NFKD', slug).lower()
slug = re.sub(r'[^a-z0-9]+', '-', slug).strip('-')
slug = re.sub(r'-+', '-', slug)
orig_slug = slug
counter = 0
while slug in seen:
counter += 1
slug = f'{orig_slug}-{counter}'
seen.add(slug)
name = p.get('name', '')
brand = p.get('brand', '')
img = p.get('image', '')
desc = p.get('description', '')[:160]
desc = re.sub(r'<[^>]*>', '', desc)
desc = re.sub(r'\s+', ' ', desc).strip()
title = f'{name} | {brand} - V.AISTUDIO' if brand else f'{name} - V.AISTUDIO'
title_esc = title.replace('&', '&amp;').replace('"', '&quot;').replace('<', '&lt;')
desc_esc = desc.replace('&', '&amp;').replace('"', '&quot;').replace('<', '&lt;')
stub = f'''<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,follow">
<title>{title_esc}</title>
<meta name="description" content="{desc_esc}">
<link rel="canonical" href="https://bep40-v-aistudio.static.hf.space/san-pham/{slug}/">
<meta property="og:type" content="product">
<meta property="og:title" content="{title_esc}">
<meta property="og:description" content="{desc_esc}">
<meta property="og:image" content="{img}">
<meta property="og:url" content="https://bep40-v-aistudio.static.hf.space/san-pham/{slug}/">
<meta name="twitter:card" content="summary_large_image">
<script>window.location.replace("/?product={slug}");</script>
</head>
<body><h1><a href="/?product={slug}">{title_esc}</a></h1></body>
</html>'''
# Upload directly via API
try:
api.upload_file(
path_or_fileobj=stub.encode('utf-8'),
path_in_repo=f"san-pham/{slug}/index.html",
repo_id="bep40/V.AISTUDIO",
repo_type="space",
commit_message=f"Add SEO stub for {name}"
)
saved += 1
if saved % 100 == 0:
time.sleep(1)
print(f" Uploaded {saved} stubs...")
except Exception as e:
print(f" ERROR {slug}: {e}")
break
print(f" Total: {saved} stubs uploaded")
return saved
def main():
html = download_index()
products = extract_products(html)
saved = generate_stubs(products)
print(f"\nDONE! {saved} stubs created")
print("Verify: https://bep40-v-aistudio.static.hf.space/san-pham/<slug>/")
if __name__ == "__main__":
main()