import os import re import json import uuid import urllib.request import urllib.parse PROJECT_ID = "gdvj8e5j" DATASET = "production" TOKEN = "skdQbMqjLbrlUWE69MCg8uUwYlwz0yDv3T6hlkmk8TnwvpexPoOF7xVK7VhVimpnSVMbzn5lXjSqlSkdPwJYA6eF86SZAdHguvAtVrJeAXUQjAOjLgifGjhafmoRdK86wwLDcDBSIP7IdMju1JABNsD3PwfElzoiGcZDYL83ZUK8VQia0Cp7" API_VERSION = "2024-10-31" BASE_MUTATE_URL = f"https://{PROJECT_ID}.api.sanity.io/v{API_VERSION}/data/mutate/{DATASET}" BASE_QUERY_URL = f"https://{PROJECT_ID}.api.sanity.io/v{API_VERSION}/data/query/{DATASET}" IMAGES_DIR = "/opt/ai-os/products/ceo/projects/blog/vwg-content/tai-sao-chon-viet-nam/images" DRAFT_PATH = "/opt/ai-os/products/ceo/projects/blog/vwg-content/tai-sao-chon-viet-nam/draft_vi_v1.md" def get_existing_assets(): # Query assets already uploaded query = '*[_type == "sanity.imageAsset"]{_id, originalFilename, url}' url = f"{BASE_QUERY_URL}?" + urllib.parse.urlencode({"query": query}) req = urllib.request.Request(url, headers={"Authorization": f"Bearer {TOKEN}"}) with urllib.request.urlopen(req) as resp: res = json.loads(resp.read().decode())["result"] assets = {} for a in res: fn = a.get("originalFilename") if fn: assets[fn] = {"id": a["_id"], "url": a["url"]} return assets def make_span(text, marks=None): return { "_key": uuid.uuid4().hex[:8], "_type": "span", "marks": marks or [], "text": text } def make_block(text, style="normal", list_item=None, level=None): return { "_key": uuid.uuid4().hex[:8], "_type": "block", "style": style, "markDefs": [], "children": [make_span(text)], **({"listItem": list_item, "level": level or 1} if list_item else {}) } def parse_draft(md_path, uploaded_assets): with open(md_path, "r", encoding="utf-8") as f: content = f.read() lines = content.split("\n") # Defaults seo_title = "Tại sao chọn Việt Nam tổ chức đám cưới điểm đến?" meta_desc = "Tìm hiểu lý do nhiều cặp đôi chọn Việt Nam làm nơi tổ chức đám cưới điểm đến cùng các bối cảnh đa dạng và những điều cần lưu ý." # Parse metadata header strictly body_start_idx = 0 for idx, line in enumerate(lines): stripped = line.strip() if stripped.startswith("Meta title:"): seo_title = stripped.replace("Meta title:", "").strip() elif stripped.startswith("Meta description:"): meta_desc = stripped.replace("Meta description:", "").strip() elif stripped.startswith("# "): body_start_idx = idx break body_lines = lines[body_start_idx:] blocks = [] idx = 0 in_faq_section = False faq_items = [] cur_q = "" cur_a = [] while idx < len(body_lines): line = body_lines[idx] stripped = line.strip() if not stripped: idx += 1 continue # Stop and omit any code blocks (like ```json ... ``` at the bottom) if stripped.startswith("```"): while idx < len(body_lines) and not body_lines[idx].strip().endswith("```") and idx + 1 < len(body_lines): idx += 1 idx += 1 continue # Handle Table if stripped.startswith("|") and stripped.endswith("|"): table_rows = [] while idx < len(body_lines): t_line = body_lines[idx].strip() if t_line.startswith("|") and t_line.endswith("|"): cells = [c.strip() for c in t_line.split("|")[1:-1]] if not all(c.startswith("-") or not c for c in cells): table_rows.append(cells) idx += 1 else: break if table_rows: blocks.append({ "_key": uuid.uuid4().hex[:8], "_type": "tableBlock", "rows": [ {"_key": uuid.uuid4().hex[:8], "cells": r} for r in table_rows ] }) continue # Detect FAQ Section if stripped.startswith("## Các câu hỏi thường gặp") or stripped.startswith("## FAQ"): in_faq_section = True blocks.append(make_block(stripped[3:].strip(), "h2")) idx += 1 continue if in_faq_section: # Check if another H2 starts (end of FAQ) if stripped.startswith("## ") and not stripped.startswith("### "): if cur_q and cur_a: faq_items.append({"question": cur_q, "answer": " ".join(cur_a)}) cur_q, cur_a = "", [] if faq_items: blocks.append({ "_key": uuid.uuid4().hex[:8], "_type": "faqAccordion", "items": faq_items }) faq_items = [] in_faq_section = False # Do not increment, let normal processing take this H2 continue if stripped.startswith("### "): if cur_q and cur_a: faq_items.append({"question": cur_q, "answer": " ".join(cur_a)}) cur_q, cur_a = "", [] cur_q = stripped[4:].strip() idx += 1 continue elif cur_q: cur_a.append(stripped) idx += 1 continue # Markdown image img_match = re.match(r'!\[(.*?)\]\((.*?)\)', stripped) if img_match: alt = img_match.group(1).strip() src = img_match.group(2).strip() filename = os.path.basename(src) asset_info = uploaded_assets.get(filename) if asset_info: blocks.append({ "_key": uuid.uuid4().hex[:8], "_type": "image", "asset": { "_type": "reference", "_ref": asset_info["id"] }, "alt": alt }) idx += 1 continue # Skip comment metadata or caption lines if stripped.startswith("