Files
landing_page/backend/scripts/export_ts_to_json.py
T
Godopu fb6881070c feat(backend,docker,docs): implement Go/Gin/SQLite REST API server, Docker containerization, and architecture specifications
- Implement standalone Go backend API server using Gin and pure-Go SQLite (modernc.org/sqlite)
- Add 11-table schema DDL migrations (000001_init.up.sql) based on DATA_TABLE.md
- Add seed data ingestion tool (cmd/seed) and static TypeScript content exporter (cmd/export-content)
- Add configuration loader (internal/config) supporting environment variables and .env files (HOST, PORT, DB_PATH, GIN_MODE, CORS_ALLOW_ORIGINS, AUTO_MIGRATE)
- Add lightweight multi-stage Dockerfile and docker-compose.yml with persistent SQLite volume
- Add comprehensive architecture specification (ARCHITECTURE.md) and REST API interface specification (API_INTERFACE.md)
- Harmonize frontend publications page to consume isHighlight flag from database-synced content
2026-08-24 17:34:51 +09:00

176 lines
7.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Exports curated data from refer_landing_page/content/*.ts and app/page.tsx into backend/seed/data/*.json.
Ensures is_highlight is properly tagged on the 5 representative publications.
"""
import json
import os
import re
import sys
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
CONTENT_DIR = os.path.join(REPO_ROOT, "refer_landing_page", "content")
SEED_DATA_DIR = os.path.join(REPO_ROOT, "backend", "seed", "data")
PAGE_TSX = os.path.join(REPO_ROOT, "refer_landing_page", "app", "page.tsx")
os.makedirs(SEED_DATA_DIR, exist_ok=True)
HIGHLIGHT_TITLES = {
"Globally Integrated Trust Authority (GITA) for Resource-Constrained Edge Devices in IoT and 6G",
"Application Level Trust Authority (APPLETA) for Resource-Constrained Edge Devices in IoT and 6G",
"mQUIC: Use of QUIC for Handover Support with Connection Migration in Wireless/Mobile Networks",
"Use of QUIC for CoAP Transport in IoT Networks",
"Use of QUIC for Mobile-Oriented Future Internet (Q-MOFI)",
}
def clean_json_str(s):
# Remove trailing commas before ] or }
s = re.sub(r',\s*\]', ']', s)
s = re.sub(r',\s*\}', '}', s)
return s
def extract_json_array_from_ts(filepath, var_name):
with open(filepath, "r", encoding="utf-8") as f:
content = f.read()
# Match export const <var_name>[: Type] = [ ... ];
pattern = rf'export\s+const\s+{var_name}(?:\s*:\s*[^=]+)?\s*=\s*(\[\s*[\s\S]*?\s*\]);'
match = re.search(pattern, content)
if not match:
raise ValueError(f"Could not find array literal for '{var_name}' in {filepath}")
array_str = clean_json_str(match.group(1))
return json.loads(array_str)
def main():
print("=== Extracting TypeScript content to JSON for SQLite seeding ===")
# 1. Projects
projects_file = os.path.join(CONTENT_DIR, "projects.ts")
projects = extract_json_array_from_ts(projects_file, "researchProjects")
with open(os.path.join(SEED_DATA_DIR, "research_projects.json"), "w", encoding="utf-8") as f:
json.dump(projects, f, indent=2, ensure_ascii=False)
print(f"✓ Extracted {len(projects)} research projects")
# 2. Research Areas (from app/page.tsx)
with open(PAGE_TSX, "r", encoding="utf-8") as f:
page_src = f.read()
areas_match = re.search(r'const\s+RESEARCH_AREAS(?:\s*:\s*[^=]+)?\s*=\s*(\[\s*[\s\S]*?\s*\]);', page_src)
if not areas_match:
raise ValueError("Could not find RESEARCH_AREAS in app/page.tsx")
areas_str = clean_json_str(areas_match.group(1))
areas_list = json.loads(areas_str)
research_areas = [{"name_en": name, "name_kr": None, "display_order": i + 1} for i, name in enumerate(areas_list)]
with open(os.path.join(SEED_DATA_DIR, "research_areas.json"), "w", encoding="utf-8") as f:
json.dump(research_areas, f, indent=2, ensure_ascii=False)
print(f"✓ Extracted {len(research_areas)} research areas")
# 3. Members & Alumni
members_file = os.path.join(CONTENT_DIR, "members.ts")
active_members = extract_json_array_from_ts(members_file, "activeMembers")
alumni = extract_json_array_from_ts(members_file, "alumni")
# Format active members with is_advisor
formatted_members = []
for i, m in enumerate(active_members):
formatted_members.append({
"name_ko": m["ko"],
"name_en": m["en"],
"degree": m["degree"],
"affiliation": m.get("affiliation"),
"email": "sjkoh@knu.ac.kr" if m["degree"] == "Professor" else None,
"is_advisor": m["degree"] == "Professor",
"display_order": i + 1,
})
with open(os.path.join(SEED_DATA_DIR, "members.json"), "w", encoding="utf-8") as f:
json.dump(formatted_members, f, indent=2, ensure_ascii=False)
print(f"✓ Extracted {len(formatted_members)} active members")
formatted_alumni = []
for a in alumni:
formatted_alumni.append({
"name_ko": a["ko"],
"name_en": a["en"],
"degree": a["degree"],
"graduated_at": a["graduatedAt"],
"major": a.get("major"),
"current_position": a.get("currentPosition"),
})
with open(os.path.join(SEED_DATA_DIR, "alumni.json"), "w", encoding="utf-8") as f:
json.dump(formatted_alumni, f, indent=2, ensure_ascii=False)
print(f"✓ Extracted {len(formatted_alumni)} alumni")
# 4. Publications & Patents
pubs_file = os.path.join(CONTENT_DIR, "publications.ts")
raw_pubs = extract_json_array_from_ts(pubs_file, "publications")
raw_patents = extract_json_array_from_ts(pubs_file, "patents")
matched_highlights = []
formatted_pubs = []
for p in raw_pubs:
title_clean = p["title"].strip()
is_hl = title_clean in HIGHLIGHT_TITLES
if is_hl:
matched_highlights.append(title_clean)
formatted_pubs.append({
"category": p["category"],
"title": p["title"],
"authors": p.get("authors"),
"venue": p["venue"],
"volume": p.get("volume"),
"published_at": p["publishedAt"],
"kci": bool(p.get("kci", False)),
"doi": p.get("doi"),
"is_highlight": is_hl,
})
if len(matched_highlights) != 5:
raise ValueError(f"Highlight matching error: expected exactly 5 matched highlights, found {len(matched_highlights)}: {matched_highlights}")
with open(os.path.join(SEED_DATA_DIR, "publications.json"), "w", encoding="utf-8") as f:
json.dump(formatted_pubs, f, indent=2, ensure_ascii=False)
print(f"✓ Extracted {len(formatted_pubs)} publications (exactly {len(matched_highlights)} highlights tagged)")
formatted_patents = []
for pat in raw_patents:
formatted_patents.append({
"title": pat["title"],
"inventors": pat["inventors"],
"application_no": pat["applicationNo"],
"application_at": pat["applicationAt"],
"registration_no": pat.get("registrationNo"),
"registration_at": pat.get("registrationAt"),
"country": pat["country"],
"published_at": pat["publishedAt"],
})
with open(os.path.join(SEED_DATA_DIR, "patents.json"), "w", encoding="utf-8") as f:
json.dump(formatted_patents, f, indent=2, ensure_ascii=False)
print(f"✓ Extracted {len(formatted_patents)} patents")
# 5. Lectures (Semesters & Courses)
lectures_file = os.path.join(CONTENT_DIR, "lectures.ts")
raw_semesters = extract_json_array_from_ts(lectures_file, "semesters")
with open(os.path.join(SEED_DATA_DIR, "lectures.json"), "w", encoding="utf-8") as f:
json.dump(raw_semesters, f, indent=2, ensure_ascii=False)
total_courses = sum(len(s.get("courses", [])) for s in raw_semesters)
print(f"✓ Extracted {len(raw_semesters)} semesters with {total_courses} courses")
# 6. Standardization
standards_file = os.path.join(CONTENT_DIR, "standards.ts")
raw_standards = extract_json_array_from_ts(standards_file, "standardsBodies")
with open(os.path.join(SEED_DATA_DIR, "standards.json"), "w", encoding="utf-8") as f:
json.dump(raw_standards, f, indent=2, ensure_ascii=False)
total_docs = sum(
sum(len(p.get("documents", [])) for p in b.get("projects", []))
for b in raw_standards
)
print(f"✓ Extracted {len(raw_standards)} standards bodies with {total_docs} documents")
print("=== Extraction completed successfully ===")
if __name__ == "__main__":
main()