bep40 commited on
Commit
1c3caa0
·
verified ·
1 Parent(s): a9568f3

Upload app/generate_all_stubs.py

Browse files
Files changed (1) hide show
  1. app/generate_all_stubs.py +111 -0
app/generate_all_stubs.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Generate SEO stubs for ALL products in index.html - run during build.sh"""
3
+ import json, re, unicodedata, os, time, urllib.request
4
+ from huggingface_hub import HfApi
5
+
6
+ SPACE_ID = "bep40/V.AISTUDIO"
7
+ BASE_URL = "https://bep40-v-aistudio.static.hf.space"
8
+
9
+ def download_index():
10
+ print("Downloading index.html...")
11
+ api = HfApi()
12
+ path = api.hf_hub_download(SPACE_ID, "index.html", repo_type="space")
13
+ with open(path, 'r') as f:
14
+ return f.read()
15
+
16
+ def extract_products(html):
17
+ print("Extracting products...")
18
+ idx = html.find('var products = ')
19
+ if idx == -1:
20
+ idx = html.find('products = [')
21
+ if idx == -1:
22
+ raise ValueError("Products not found")
23
+ start = html.find('[', idx)
24
+ # Parse JSON array
25
+ bracket = 0
26
+ end = start
27
+ in_str = False
28
+ for i in range(start, len(html)):
29
+ c = html[i]
30
+ if c == '"' and html[i-1] != '\\':
31
+ in_str = not in_str
32
+ elif not in_str:
33
+ if c == '[': bracket += 1
34
+ elif c == ']':
35
+ bracket -= 1
36
+ if bracket == 0:
37
+ end = i + 1
38
+ break
39
+ products = json.loads(html[start:end])
40
+ print(f"Found {len(products)} products")
41
+ return products
42
+
43
+ def slugify(name):
44
+ s = unicodedata.normalize('NFKD', name).lower()
45
+ s = re.sub(r'[^a-z0-9]+', '-', s).strip('-')
46
+ s = re.sub(r'-+', '-', s)
47
+ return s
48
+
49
+ def create_stub(p):
50
+ slug = p.get('slug') or slugify(p.get('name', 'p'))
51
+ name = p.get('name', 'Product')[:200]
52
+ brand = p.get('brand', '')
53
+ price = p.get('price', '')
54
+ img = p.get('image', BASE_URL + '/logo/logo_600.png')
55
+ desc = re.sub(r'<[^>]+>', '', str(p.get('description', '')))[:160]
56
+ title = f"{name} | {brand} - V.AISTUDIO" if brand else f"{name} - V.AISTUDIO"
57
+ return f'''<!DOCTYPE html>
58
+ <html lang="vi">
59
+ <head>
60
+ <meta charset="UTF-8">
61
+ <meta name="robots" content="noindex,follow">
62
+ <link rel="canonical" href="{BASE_URL}/san-pham/{slug}/">
63
+ <meta property="og:type" content="product">
64
+ <meta property="og:title" content="{title}">
65
+ <meta property="og:description" content="{desc}">
66
+ <meta property="og:image" content="{img}">
67
+ <meta property="og:url" content="{BASE_URL}/san-pham/{slug}/">
68
+ <meta property="og:site_name" content="V.AISTUDIO">
69
+ <meta name="twitter:card" content="summary_large_image">
70
+ <script>window.location.replace("/?product={slug}");</script>
71
+ </head>
72
+ <body><h1><a href="/?product={slug}">{title}</a></h1></body>
73
+ </html>'''
74
+
75
+ def main():
76
+ html = download_index()
77
+ products = extract_products(html)
78
+ api = HfApi()
79
+ seen = {}
80
+ uploaded = 0
81
+ for p in products:
82
+ slug = p.get('slug') or slugify(p.get('name', 'p'))
83
+ if slug in seen:
84
+ seen[slug] += 1
85
+ slug = f"{slug}-{seen[slug]}"
86
+ else:
87
+ seen[slug] = 0
88
+ stub = create_stub(p)
89
+ try:
90
+ api.upload_file(
91
+ path_or_fileobj=stub.encode(),
92
+ path_in_repo=f"san-pham/{slug}/index.html",
93
+ repo_id=SPACE_ID, repo_type="space",
94
+ commit_message=f"SEO stub: {p.get('name', 'product')[:50]}"
95
+ )
96
+ uploaded += 1
97
+ if uploaded % 100 == 0:
98
+ print(f" {uploaded} uploaded...")
99
+ except Exception as e:
100
+ print(f" Error: {e}")
101
+ print(f"Done! {uploaded} stubs")
102
+ # Update .rebuild to trigger next build
103
+ api.upload_file(
104
+ path_or_fileobj=f"# rebuild {time.time()}".encode(),
105
+ path_in_repo=".rebuild",
106
+ repo_id=SPACE_ID, repo_type="space",
107
+ commit_message="Trigger rebuild complete"
108
+ )
109
+
110
+ if __name__ == "__main__":
111
+ main()