import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { TeknavData } from '../teknav-data.js'; import { renderStaticFallback, replaceStaticFallback } from './static-fallback.mjs'; const SITE_URL = (process.env.TEKNAV_SITE_URL || process.env.VITE_SITE_URL || 'https://www.teknav.ir').replace(/\/$/, ''); const SITE_NAME = 'تکناو'; const DEFAULT_IMAGE = `${SITE_URL}/images/og/default.jpg`; const DEFAULT_KEYWORDS = 'تکناو, فناوری, هوش مصنوعی, علم داده, امنیت سایبری, نرم افزار, سخت افزار, استارتاپ, آینده فناوری, تحلیل تکنولوژی'; const template = readFileSync(resolve('dist/index.html'), 'utf8'); function esc(value) { return String(value ?? '') .replace(/&/g, '&') .replace(/"/g, '"') .replace(//g, '>'); } function clean(value) { return String(value ?? '').replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim(); } function truncate(value, max = 155) { const text = clean(value); return text.length > max ? `${text.slice(0, max - 1).trim()}…` : text; } const org = { '@type': ['Organization', 'NewsMediaOrganization'], '@id': `${SITE_URL}/#organization`, name: 'تکناو', alternateName: ['Teknav', 'تکنّاو'], url: SITE_URL, logo: { '@type': 'ImageObject', '@id': `${SITE_URL}/#logo`, url: `${SITE_URL}/favicon.png`, width: 512, height: 512, }, image: { '@id': `${SITE_URL}/#logo` }, }; const website = { '@type': 'WebSite', '@id': `${SITE_URL}/#website`, url: SITE_URL, name: 'تکناو', alternateName: 'Teknav', inLanguage: 'fa-IR', publisher: { '@id': `${SITE_URL}/#organization` }, }; const GLOSSARY_SAMEAS_MAP = { ai: [ 'https://www.wikidata.org/wiki/Q11660', 'https://fa.wikipedia.org/wiki/%D9%87%D9%88%D8%B4_%D9%85%D8%B5%D9%86%D9%88%D8%B5%DB%8C' ], llm: [ 'https://www.wikidata.org/wiki/Q115305900', 'https://fa.wikipedia.org/wiki/%D9%85%D8%AF%D9%84_%D8%B2%D8%A8%D8%A7%D9%86%DB%8C_%D8%A8%D8%B2%D8%B1%DA%AF' ], rag: [ 'https://www.wikidata.org/wiki/Q124378129', 'https://en.wikipedia.org/wiki/Retrieval-augmented_generation' ], 'prompt-injection': [ 'https://www.wikidata.org/wiki/Q117409023', 'https://en.wikipedia.org/wiki/Prompt_injection' ], 'vector-database': [ 'https://www.wikidata.org/wiki/Q119790697', 'https://en.wikipedia.org/wiki/Vector_database' ], 'agentic-ai': [ 'https://www.wikidata.org/wiki/Q127415174' ] }; function buildBreadcrumb(items) { return { '@type': 'BreadcrumbList', itemListElement: items.map((item, idx) => ({ '@type': 'ListItem', position: idx + 1, name: item.name, ...(item.path ? { item: `${SITE_URL}${item.path}` } : {}), })), }; } let count = 0; function writePage(routePath, title, description, keywords, jsonLdGraph) { const canonical = `${SITE_URL}${routePath}`; const jsonLd = JSON.stringify({ '@context': 'https://schema.org', '@graph': [ org, website, ...jsonLdGraph, ] }); let html = template; html = html.replace(//, ``); html = html.replace(/[^<]*<\/title>/, `<title>${title}`); html = html.replace(/(/, ``); html = html.replace(/`); html = replaceStaticFallback(html, renderStaticFallback({ eyebrow: 'تکناو', title, description, facts: [ { label: 'زبان', value: 'فارسی' }, { label: 'نشانی canonical', value: canonical }, ], links: [ { href: '/', label: SITE_NAME, text: 'صفحه اصلی' }, { href: '/articles', label: 'مقاله‌های فناوری', text: 'آرشیو تحلیل‌ها' }, { href: '/authors', label: 'نویسندگان تکناو', text: 'پروفایل نویسندگان' }, ], })); // Normalize path format for directory creation const relativeDir = routePath.startsWith('/') ? routePath.slice(1) : routePath; const localDir = resolve(`dist/${relativeDir}`); mkdirSync(localDir, { recursive: true }); writeFileSync(`${localDir}/index.html`, html, 'utf8'); count++; } // 1. Generate Categories for (const category of TeknavData.categories ?? []) { const name = category.name; const description = category.description || `مقاله‌ها و تحلیل‌های فارسی تکناو درباره ${name}.`; const path = `/category/${category.slug}`; const title = `${name} | مقاله‌ها و تحلیل‌های تکناو`; const keywords = `${name}, مقاله ${name}, تحلیل ${name}, فناوری, تکناو`; const jsonLdGraph = [ { '@type': 'CollectionPage', name, description, url: `${SITE_URL}${path}`, inLanguage: 'fa-IR', }, buildBreadcrumb([ { name: SITE_NAME, path: '/' }, { name } ]), ]; writePage(path, title, description, keywords, jsonLdGraph); } // 2. Generate Tags for (const tag of TeknavData.tags ?? []) { const name = tag.name; const path = `/tag/${encodeURIComponent(name)}`; const title = `برچسب ${name} | مقاله‌های تکنـاو`; const description = `همه مقاله‌های تکنـاو درباره ${name}، همراه با تحلیل فارسی، داده و مسیرهای مرتبط برای مطالعه بیشتر.`; const keywords = `${name}, تکنـاو, مقاله فناوری, تحلیل فناوری`; const jsonLdGraph = [ { '@type': 'CollectionPage', name: `برچسب ${name}`, url: `${SITE_URL}${path}`, inLanguage: 'fa-IR', }, buildBreadcrumb([ { name: SITE_NAME, path: '/' }, { name: 'برچسب‌ها', path: '/articles' }, { name } ]), ]; writePage(path, title, description, keywords, jsonLdGraph); } // 3. Generate Glossary for (const term of TeknavData.glossary ?? []) { const slug = term.slug; const path = `/glossary/${slug}`; const title = `${term.term} چیست؟ | فرهنگ واژگان تکنّاو`; const description = truncate(term.summary, 155); const keywords = `${term.term}, ${term.english || ''}, فرهنگ واژگان فناوری, تکنّاو`; const sameAs = GLOSSARY_SAMEAS_MAP[slug] || []; const jsonLdGraph = [ { '@type': 'DefinedTerm', name: term.term, alternateName: term.english, description, inDefinedTermSet: `${SITE_URL}/glossary`, url: `${SITE_URL}${path}`, sameAs, }, term.faqs?.length ? { '@type': 'FAQPage', mainEntity: term.faqs.map(([q, a]) => ({ '@type': 'Question', name: q, acceptedAnswer: { '@type': 'Answer', text: a }, })), } : null, buildBreadcrumb([ { name: SITE_NAME, path: '/' }, { name: 'فرهنگ واژگان', path: '/articles' }, { name: term.term } ]), ].filter(Boolean); writePage(path, title, description, keywords, jsonLdGraph); } // 4. Generate Topics for (const topic of TeknavData.topicHubs ?? []) { const slug = topic.slug; const path = `/topics/${slug}`; const name = topic.title; const description = topic.description || `مقاله‌ها و تحلیل‌های تکناو درباره ${name}.`; const title = topic.seoTitle || `${name} | خوشه موضوعی تکناو`; const keywords = (topic.keywords ?? [name, 'تکناو', 'تحلیل فناوری']).join(', '); const jsonLdGraph = [ { '@type': 'CollectionPage', name, description, url: `${SITE_URL}${path}`, inLanguage: 'fa-IR', isPartOf: { '@id': `${SITE_URL}/#website` }, }, topic.faqs?.length ? { '@type': 'FAQPage', mainEntity: topic.faqs.map(([q, a]) => ({ '@type': 'Question', name: q, acceptedAnswer: { '@type': 'Answer', text: a }, })), } : null, buildBreadcrumb([ { name: SITE_NAME, path: '/' }, { name: 'موضوعات', path: '/articles' }, { name } ]), ].filter(Boolean); writePage(path, title, description, keywords, jsonLdGraph); } // 5. Generate Series Pages for (const series of TeknavData.articleSeries ?? []) { const slug = series.slug; const path = `/series/${slug}`; const name = series.title; const description = truncate(series.description || 'سری مقاله‌های تکناو برای دنبال کردن یک موضوع فناوری به‌ترتیب تحریریه.', 155); const title = `${name} | سری مقاله‌های تکناو`; const keywords = `${name}, سری مقاله, تکناو, تحلیل فناوری`; const jsonLdGraph = [ { '@type': 'CollectionPage', name, description, url: `${SITE_URL}${path}`, inLanguage: 'fa-IR', }, buildBreadcrumb([ { name: SITE_NAME, path: '/' }, { name: 'سری مقاله‌ها', path: '/articles' }, { name } ]), ]; writePage(path, title, description, keywords, jsonLdGraph); } // 6. Generate Static / Core Pages const staticPages = [ { path: '/articles', title: 'مقاله‌های فناوری | تکناو', description: 'آرشیو مقاله‌های فارسی تکناو درباره هوش مصنوعی، علم داده، امنیت سایبری، نرم‌افزار، سخت‌افزار و آینده فناوری.', keywords: DEFAULT_KEYWORDS, jsonLdGraph: [{ '@type': 'CollectionPage', name: 'مقاله‌های فناوری تکناو', url: `${SITE_URL}/articles`, inLanguage: 'fa-IR' }] }, { path: '/authors', title: 'نویسندگان تکناو | تحلیلگران فناوری', description: 'آشنایی با نویسندگان و تحلیلگران تکناو در حوزه هوش مصنوعی، امنیت سایبری، نرم‌افزار، سخت‌افزار و استارتاپ.', keywords: 'نویسندگان تکناو, تحلیلگر فناوری, نویسنده هوش مصنوعی, نویسنده امنیت سایبری', jsonLdGraph: [{ '@type': 'CollectionPage', name: 'نویسندگان تکناو', url: `${SITE_URL}/authors`, inLanguage: 'fa-IR' }] }, { path: '/newsletter', title: 'آرشیو خبرنامه تکنـاو | تحلیل هفتگی فناوری', description: 'آرشیو خبرنامه‌های ارسال‌شده تکنـاو درباره هوش مصنوعی، امنیت سایبری، نرم‌افزار، سخت‌افزار، استارتاپ و داده.', keywords: 'خبرنامه تکنـاو, آرشیو خبرنامه فناوری, تحلیل هفتگی فناوری, هوش مصنوعی, امنیت سایبری', jsonLdGraph: [ { '@type': 'CollectionPage', name: 'آرشیو خبرنامه تکنـاو', url: `${SITE_URL}/newsletter`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'خبرنامه' }]) ] }, { path: '/jobs', title: 'فرصت‌های شغلی فناوری | تکناو', description: 'آگهی‌های شغلی منتخب فناوری و امکان ثبت موقعیت شغلی شرکت‌ها در تکناو.', keywords: 'شغل فناوری, استخدام برنامه نویس, استخدام هوش مصنوعی, تکناو جابز', jsonLdGraph: [ { '@type': 'CollectionPage', name: 'فرصت‌های شغلی فناوری | تکناو', url: `${SITE_URL}/jobs`, inLanguage: 'fa-IR', description: 'آگهی‌های شغلی منتخب فناوری و امکان ثبت موقعیت شغلی شرکت‌ها در تکناو.' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'فرصت‌های شغلی فناوری' }]) ] }, { path: '/courses', title: 'دوره‌های تخصصی فناوری | تکناو', description: 'دوره‌های فارسی تکناو برای هوش مصنوعی، امنیت، نرم‌افزار و مهارت‌های فنی محصول‌محور.', keywords: 'دوره فناوری, آموزش هوش مصنوعی, آموزش امنیت, دوره فارسی برنامه نویسی', jsonLdGraph: [ { '@type': 'CollectionPage', name: 'دوره‌های تخصصی فناوری | تکناو', url: `${SITE_URL}/courses`, inLanguage: 'fa-IR', description: 'دوره‌های فارسی تکناو برای هوش مصنوعی، امنیت، نرم‌افزار و مهارت‌های فنی محصول‌محور.' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'دوره‌های تخصصی فناوری' }]) ] }, { path: '/membership', title: 'عضویت پریمیوم تکناو | محتوای اختصاصی فناوری', description: 'عضویت پریمیوم تکناو برای تجربه بدون تبلیغ، محتوای اختصاصی و دسترسی بهتر به دوره‌ها و گزارش‌های تخصصی.', keywords: 'عضویت تکناو, محتوای پریمیوم فناوری, تحلیل اختصاصی فناوری', jsonLdGraph: [ { '@type': 'CollectionPage', name: 'عضویت پریمیوم تکناو | محتوای اختصاصی فناوری', url: `${SITE_URL}/membership`, inLanguage: 'fa-IR', description: 'عضویت پریمیوم تکناو برای تجربه بدون تبلیغ، محتوای اختصاصی و دسترسی بهتر به دوره‌ها و گزارش‌های تخصصی.' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'عضویت پریمیوم تکناو' }]) ] }, { path: '/about', title: 'درباره ما | تکناو', description: 'درباره رسانه فارسی تکناو و ماموریت ما در تحلیل فناوری، هوش مصنوعی و امنیت سایبری.', keywords: 'درباره تکناو, ماموریت تکناو, رسانه فناوری, تحلیل هوش مصنوعی', jsonLdGraph: [ { '@type': 'WebPage', '@id': `${SITE_URL}/about#webpage`, name: 'درباره ما | تکناو', description: 'درباره رسانه فارسی تکناو و ماموریت ما در تحلیل فناوری، هوش مصنوعی و امنیت سایبری.', url: `${SITE_URL}/about`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'درباره ما' }]) ] }, { path: '/contact', title: 'تماس با ما | تکناو', description: 'ارتباط با تیم تحریریه و پشتیبانی تکناو برای نظرات، پیشنهادات و همکاری.', keywords: 'تماس با تکناو, پشتیبانی تکناو, همکاری با تکناو, تبلیغات تکناو', jsonLdGraph: [ { '@type': 'WebPage', '@id': `${SITE_URL}/contact#webpage`, name: 'تماس با ما | تکناو', description: 'ارتباط با تیم تحریریه و پشتیبانی تکناو برای نظرات، پیشنهادات و همکاری.', url: `${SITE_URL}/contact`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'تماس با ما' }]) ] }, { path: '/terms', title: 'قوانین و مقررات | تکناو', description: 'شرایط استفاده و قوانین و مقررات استفاده از محتوا و خدمات رسانه تکناو.', keywords: 'قوانین تکناو, مقررات تکناو, شرایط استفاده تکناو', jsonLdGraph: [ { '@type': 'WebPage', '@id': `${SITE_URL}/terms#webpage`, name: 'قوانین و مقررات | تکناو', description: 'شرایط استفاده و قوانین و مقررات استفاده از محتوا و خدمات رسانه تکناو.', url: `${SITE_URL}/terms`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'قوانین و مقررات' }]) ] }, { path: '/privacy', title: 'حریم خصوصی | تکناو', description: 'سیاست حریم خصوصی و نحوه حفاظت از اطلاعات کاربران در رسانه تکناو.', keywords: 'حریم خصوصی تکناو, سیاست حریم خصوصی, امنیت اطلاعات کاربران', jsonLdGraph: [ { '@type': 'WebPage', '@id': `${SITE_URL}/privacy#webpage`, name: 'حریم خصوصی | تکناو', description: 'سیاست حریم خصوصی و نحوه حفاظت از اطلاعات کاربران در رسانه تکناو.', url: `${SITE_URL}/privacy`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'حریم خصوصی' }]) ] }, { path: '/tools', title: 'ابزارهای تخصصی فناوری | تکناو', description: 'جعبه‌ابزار تخصصی تکناو برای توسعه‌دهندگان، مهندسان داده و تحلیلگران؛ شامل نرمال‌ساز متن و ماشین‌حساب RAG.', keywords: 'ابزار توسعه دهنده, نرمال ساز متن, ماشین حساب RAG, جعبه ابزار تکناو', jsonLdGraph: [ { '@type': 'CollectionPage', name: 'ابزارهای تخصصی فناوری | تکناو', url: `${SITE_URL}/tools`, inLanguage: 'fa-IR', description: 'جعبه‌ابزار تخصصی تکناو برای توسعه‌دهندگان، مهندسان داده و تحلیلگران؛ شامل نرمال‌ساز متن و ماشین‌حساب RAG.' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'ابزارها' }]) ] }, { path: '/tools/nlp-normalizer', title: 'نرمال‌ساز متن فارسی (NLP) | ابزارهای تکناو', description: 'ابزار تخصصی پاکسازی، نیم‌فاصله‌گذاری و پیش‌پردازش متن فارسی برای تسک‌های پردازش زبان طبیعی و مدل‌های زبانی.', keywords: 'نرمال ساز متن فارسی, نیم فاصله گذاری, پیش پردازش متن فارسی, NLP فارسی', jsonLdGraph: [ { '@type': 'WebPage', '@id': `${SITE_URL}/tools/nlp-normalizer#webpage`, name: 'نرمال‌ساز متن فارسی (NLP) | ابزارهای تکناو', description: 'ابزار تخصصی پاکسازی، نیم‌فاصله‌گذاری و پیش‌پردازش متن فارسی برای تسک‌های پردازش زبان طبیعی و مدل‌های زبانی.', url: `${SITE_URL}/tools/nlp-normalizer`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'ابزارها', path: '/tools' }, { name: 'نرمال‌ساز متن فارسی' }]) ] }, { path: '/tools/rag-calculator', title: 'ماشین‌حساب ظرفیت و هزینه RAG | ابزارهای تکناو', description: 'ماشین‌حساب تخصصی محاسبه تعداد توکن، فضای پایگاه‌داده برداری، هزینه‌های استنتاج LLM و پهنای باند معماری RAG.', keywords: 'هزینه RAG, ماشین حساب RAG, پهنای باند RAG, پایگاه داده برداری', jsonLdGraph: [ { '@type': 'WebPage', '@id': `${SITE_URL}/tools/rag-calculator#webpage`, name: 'ماشین‌حساب ظرفیت و هزینه RAG | ابزارهای تکناو', description: 'ماشین‌حساب تخصصی محاسبه تعداد توکن، فضای پایگاه‌داده برداری، هزینه‌های استنتاج LLM و پهنای باند معماری RAG.', url: `${SITE_URL}/tools/rag-calculator`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'ابزارها', path: '/tools' }, { name: 'ماشین‌حساب RAG' }]) ] }, { path: '/tekrag-persian', title: 'بنچمارک TekRag | ارزیابی سامانه‌های RAG فارسی', description: 'درگاه رسمی بنچمارک TekRag؛ اولین فریم‌ورک استاندارد ارزیابی دقت، بازیابی و پاسخ‌دهی سیستم‌های RAG زبان فارسی.', keywords: 'TekRag benchmark, بنچمارک RAG فارسی, ارزیابی سیستم RAG, هوش مصنوعی فارسی', jsonLdGraph: [ { '@type': 'WebPage', '@id': `${SITE_URL}/tekrag-persian#webpage`, name: 'بنچمارک TekRag | ارزیابی سامانه‌های RAG فارسی', description: 'درگاه رسمی بنچمارک TekRag؛ اولین فریم‌ورک استاندارد ارزیابی دقت، بازیابی و پاسخ‌دهی سیستم‌های RAG زبان فارسی.', url: `${SITE_URL}/tekrag-persian`, inLanguage: 'fa-IR' }, buildBreadcrumb([{ name: SITE_NAME, path: '/' }, { name: 'بنچمارک TekRag' }]) ] } ]; for (const pg of staticPages) { writePage(pg.path, pg.title, pg.description, pg.keywords, pg.jsonLdGraph); } console.log(`[semantic-pages] generated ${count} static semantic HTML pages`);