最近想多总结、创作。但是创建一篇文章还是有些麻烦的,我是使用md文档管理博文的,其中需要设置文件的文件名、文章的标题、路由、创建时间、分类、标签等。

最先我是手动复制一篇模板,然后逐个修改上述参数。后来使用node脚本可以自动设置文件名、文章路由、创建时间。

文章的文件名和路由通常是一致的,且为了seo友好,通常设置语义化英文。但是我的英文随着毕业,越来越差劲了,每回都是先想好中文标题,然后Google翻译为英文,然后再使用脚本创建文件,填入中文标题。说实话挺费劲的,我最先想好的的文章标题,居然需要粘贴两次才能正式确认。

这个机械的过程,完全可以使用 AI 帮助我完成,综合考量之下,我发现互联网活佛 Cloudflare 的 Workers AI 可以完美的满足我的需求:

这样我就可以直接在脚本中插入中文参数,然后 AI 自动翻译为英文,设置为文件名和文章路由,无需打开翻译软件。例如: pnpm new-post 快速创建一篇博文

然后我就获得了 quick-post-creation.md 文件如下:

md
---
title: '快速创建一篇博客文章'
path: '/posts/quick-post-creation'
createdAt: '2026-05-18T16:35:42+08:00'
categories: []
tags: []
---

看起来很完美,省下的功夫够我多写两篇博文了,下面记录一下我的脚本:

javascript
import fs from 'fs'
import path from 'path'
import dotenv from 'dotenv'

dotenv.config({
  path: process.env.NUXT_ENV_DOTENV || '.env.production',
})

// =====================  Cloudflare API 配置  =====================
const CLOUDFLARE_ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID
const CLOUDFLARE_API_TOKEN = process.env.CLOUDFLARE_API_TOKEN
const CLOUDFLARE_AI_MODEL = process.env.CLOUDFLARE_AI_MODEL

if (!CLOUDFLARE_ACCOUNT_ID || !CLOUDFLARE_API_TOKEN || !CLOUDFLARE_AI_MODEL) {
  console.error('❌ 环境变量读取失败!请检查 .env 文件是否配置完整')
  console.error('CLOUDFLARE_ACCOUNT_ID:', CLOUDFLARE_ACCOUNT_ID)
  console.error(
    'CLOUDFLARE_API_TOKEN:',
    CLOUDFLARE_API_TOKEN ? '已配置' : '未配置',
  )
  process.exit(1)
}
// ===============================================================

function pad(n) {
  return String(n).padStart(2, '0')
}
function formatLocalISO(d = new Date()) {
  const year = d.getFullYear()
  const month = pad(d.getMonth() + 1)
  const day = pad(d.getDate())
  const hours = pad(d.getHours())
  const minutes = pad(d.getMinutes())
  const seconds = pad(d.getSeconds())
  const offsetMin = -d.getTimezoneOffset()
  const sign = offsetMin >= 0 ? '+' : '-'
  const offH = pad(Math.floor(Math.abs(offsetMin) / 60))
  const offM = pad(Math.abs(offsetMin) % 60)
  return `'${year}-${month}-${day}T${hours}:${minutes}:${seconds}${sign}${offH}:${offM}'`
}

async function generateSlugFromChineseTitle(chineseTitle) {
  try {
    const prompt = `请将以下中文标题翻译成纯英文,仅返回英文,无任何其他文字,如无必要无需使用the开头,在保证语义完整的情况下尽量简洁干练,用于URL路径:"${chineseTitle}"`

    // 调用 Cloudflare AI API
    const response = await fetch(
      `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/run/${CLOUDFLARE_AI_MODEL}`,
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${CLOUDFLARE_API_TOKEN}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          messages: [{ role: 'user', content: prompt }],
        }),
      },
    )

    const result = await response.json()

    // 接口调用失败处理
    if (!result.success) {
      throw new Error(result.errors?.[0]?.message || 'Cloudflare API 调用失败')
    }

    const englishText = result.result.response.trim()
    // 生成URL友好的slug
    const slug = englishText
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-+|-+$/g, '')

    return slug
  } catch (err) {
    console.error('Cloudflare AI生成失败:', err.message)
    process.exit(1)
  }
}

async function main() {
  const chineseTitle = process.argv[2]
  if (!chineseTitle) {
    console.log('用法:pnpm new-post "中文文章标题"')
    process.exit(1)
  }

  const slug = await generateSlugFromChineseTitle(chineseTitle)
  const filename = `${slug}.md`
  const title = chineseTitle

  const targetDir = path.resolve(process.cwd(), 'content', 'posts')
  const targetPath = path.join(targetDir, filename)

  if (fs.existsSync(targetPath)) {
    console.error('文件已存在:', targetPath)
    process.exit(1)
  }

  await fs.promises.mkdir(targetDir, { recursive: true })

  const templatePath = path.resolve(
    process.cwd(),
    'scripts',
    'temp',
    'default.md',
  )
  let tpl = ''
  try {
    tpl = await fs.promises.readFile(templatePath, 'utf8')
  } catch (e) {
    tpl = `---
title: '${title}'
path: '/posts/${slug}'
createdAt: ${formatLocalISO()}
categories: []
tags: []
draft: true
---
`
  }

  if (/^---\n[\s\S]*?\n---/m.test(tpl)) {
    tpl = tpl.replace(/^title:.*$/m, `title: '${title}'`)
    tpl = tpl.replace(/^path:.*$/m, `path: '/posts/${slug}'`)
    tpl = tpl.replace(/^createdAt:.*$/m, `createdAt: ${formatLocalISO()}`)
  } else {
    tpl =
      `---
title: '${title}'
path: '/posts/${slug}'
createdAt: ${formatLocalISO()}
categories: []
tags: []
draft: true
---

` + tpl
  }

  await fs.promises.writeFile(targetPath, tpl, 'utf8')
  console.log('✅ 创建成功:', path.relative(process.cwd(), targetPath))
  console.log('📝 标题:', title)
  console.log('🔗 路径:', `/posts/${slug}`)
}

main().catch((err) => {
  console.error('❌ 执行失败:', err)
  process.exit(1)
})