mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-15 17:16:16 -08:00
Refactor documentation for clarity and consistency
- Updated descriptions and terminology across various component documentation files for improved clarity. - Changed headings and section titles for better readability and consistency. - Enhanced the language and structure of the documentation to provide clearer guidance on usage and configuration. - Removed the `fix-docs.js` script as its functionality has been integrated into the translation process. - Improved the translation script to handle Markdown code block issues and added retry logic for API calls.
This commit is contained in:
1 parent
3adff76edf
commit
92f09a4290
15 files changed
+413
-372
No files matched your search
+147
-33
@@ -13,14 +13,81 @@ const srcDirs = ['docs/advanced', 'docs/component', 'docs/start']
|
||||
const indexFile = 'docs/index.md'
|
||||
const outputRoot = path.join(rootDir, 'docs/en')
|
||||
const API_URL = 'https://api.deepseek.com/v1/chat/completions'
|
||||
const API_KEY = process.env.DEEPL_API_KEY
|
||||
const API_KEY = process.env.DEEPSEEK_API_KEY
|
||||
|
||||
// 配置常量
|
||||
const MAX_CONCURRENT_REQUESTS = 5 // 并发请求数
|
||||
const REQUEST_TIMEOUT = 60000 // 请求超时时间 60秒
|
||||
const MAX_RETRIES = 3 // 最大重试次数
|
||||
const CHUNK_SIZE = 4000 // 分块大小
|
||||
|
||||
if (!API_KEY) {
|
||||
console.error('❌ Missing DEEPL_API_KEY in .env file')
|
||||
console.error('❌ Missing DEEPSEEK_API_KEY in .env file')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function splitMarkdown(text, maxLen = 4000) {
|
||||
// ==================== Markdown 修复功能 ====================
|
||||
|
||||
/**
|
||||
* 修复 Markdown 代码块闭合问题
|
||||
* - 遇到 ## 标题时补上遗漏的 ```
|
||||
* - 遇到 ::: 时补上遗漏的 ```
|
||||
* - 文件末尾检查是否需要补上
|
||||
*/
|
||||
function fixMarkdownCodeBlocks(content) {
|
||||
const lines = content.split('\n')
|
||||
const fixedLines = []
|
||||
let inCodeBlock = false
|
||||
let fixes = 0
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
|
||||
// 检查是否进入代码块
|
||||
if (line.startsWith('```') && !inCodeBlock) {
|
||||
inCodeBlock = true
|
||||
fixedLines.push(line)
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查是否正常退出代码块
|
||||
if (line.startsWith('```') && inCodeBlock) {
|
||||
inCodeBlock = false
|
||||
fixedLines.push(line)
|
||||
continue
|
||||
}
|
||||
|
||||
// 在代码块中遇到标题(缺少 ```)
|
||||
if (inCodeBlock && line.startsWith('## ')) {
|
||||
fixedLines.push('```')
|
||||
fixedLines.push('')
|
||||
inCodeBlock = false
|
||||
fixes++
|
||||
}
|
||||
|
||||
// 在代码块中遇到 :::(admonition)
|
||||
if (inCodeBlock && line.startsWith(':::')) {
|
||||
fixedLines.push('```')
|
||||
fixedLines.push('')
|
||||
inCodeBlock = false
|
||||
fixes++
|
||||
}
|
||||
|
||||
fixedLines.push(line)
|
||||
}
|
||||
|
||||
// 文件末尾仍在代码块中
|
||||
if (inCodeBlock) {
|
||||
fixedLines.push('```')
|
||||
fixes++
|
||||
}
|
||||
|
||||
return { content: fixedLines.join('\n'), fixes }
|
||||
}
|
||||
|
||||
// ==================== 翻译功能 ====================
|
||||
|
||||
function splitMarkdown(text, maxLen = CHUNK_SIZE) {
|
||||
const lines = text.split('\n')
|
||||
const chunks = []
|
||||
let buffer = ''
|
||||
@@ -45,17 +112,72 @@ function cleanTranslation(text) {
|
||||
return text
|
||||
.replace(/^```(markdown|md)?/gi, '')
|
||||
.replace(/```$/g, '')
|
||||
.replace(/^(Here('|’)s|Below is|Translation|The English version|Here is)[::]?\s*/gi, '')
|
||||
.replace(/^(Here('|')s|Below is|Translation|The English version|Here is)[::]?\s*/gi, '')
|
||||
.replace(/(Translation completed\.?|End of translation\.?)$/gi, '')
|
||||
.trim()
|
||||
}
|
||||
|
||||
async function translateText(text) {
|
||||
const chunks = splitMarkdown(text, 4000)
|
||||
async function callDeepSeekAPI(prompt, tag, chunkId) {
|
||||
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
||||
try {
|
||||
console.log(`🔹 [${tag}] Translating chunk ${chunkId} (attempt ${attempt}/${MAX_RETRIES})`)
|
||||
const controller = new AbortController()
|
||||
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT)
|
||||
|
||||
const res = await fetch(API_URL, {
|
||||
method: 'POST',
|
||||
signal: controller.signal,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${API_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'deepseek-chat',
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
temperature: 0.2,
|
||||
}),
|
||||
})
|
||||
clearTimeout(timeout)
|
||||
|
||||
// 处理限流情况
|
||||
if (res.status === 429) {
|
||||
const delay = Math.pow(2, attempt) * 1000
|
||||
console.log(`⏳ [${tag}] Rate limited, waiting ${delay}ms...`)
|
||||
await new Promise(r => setTimeout(r, delay))
|
||||
continue
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.text()
|
||||
console.error(`[${tag}] API Error:`, error)
|
||||
throw new Error(`DeepSeek API error: ${res.status}`)
|
||||
}
|
||||
|
||||
const data = await res.json()
|
||||
if (!data.choices || !data.choices[0]) {
|
||||
throw new Error('Invalid API response: missing choices')
|
||||
}
|
||||
return data.choices[0].message?.content?.trim() || ''
|
||||
}
|
||||
catch (err) {
|
||||
if (err.name === 'AbortError') {
|
||||
console.error(`[${tag}] Request timeout for chunk ${chunkId}`)
|
||||
}
|
||||
if (attempt === MAX_RETRIES) {
|
||||
throw err
|
||||
}
|
||||
const delay = 1000 * attempt
|
||||
console.log(`⚠️ [${tag}] Retry ${attempt}/${MAX_RETRIES} after ${delay}ms...`)
|
||||
await new Promise(r => setTimeout(r, delay))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function translateText(text, fileName) {
|
||||
const chunks = splitMarkdown(text, CHUNK_SIZE)
|
||||
let result = ''
|
||||
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
console.log(`🔹 Translating chunk ${i + 1}/${chunks.length}`)
|
||||
const prompt = `
|
||||
You are a professional English technical translator for documentation.
|
||||
Translate the following Markdown content from Simplified Chinese to fluent English.
|
||||
@@ -64,29 +186,9 @@ Return ONLY the translated Markdown content — do NOT add any explanations, pre
|
||||
|
||||
Text to translate:
|
||||
${chunks[i]}
|
||||
`.trim()
|
||||
`.trim()
|
||||
|
||||
const res = await fetch(API_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${API_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'deepseek-chat',
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
temperature: 0.2,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.text()
|
||||
console.error('API Error:', error)
|
||||
throw new Error(`DeepSeek API error: ${res.status}`)
|
||||
}
|
||||
|
||||
const data = await res.json()
|
||||
const raw = data.choices?.[0]?.message?.content?.trim() || ''
|
||||
const raw = await callDeepSeekAPI(prompt, fileName, `${i + 1}/${chunks.length}`)
|
||||
const translated = cleanTranslation(raw)
|
||||
result += `\n\n${translated}`
|
||||
}
|
||||
@@ -96,14 +198,26 @@ ${chunks[i]}
|
||||
|
||||
async function processFile(inputPath, outputPath) {
|
||||
const content = fs.readFileSync(inputPath, 'utf8')
|
||||
const fileName = path.basename(inputPath)
|
||||
console.log(`🌍 Translating: ${inputPath}`)
|
||||
const translated = await translateText(content)
|
||||
|
||||
// 1. 翻译
|
||||
let translated = await translateText(content, fileName)
|
||||
|
||||
// 2. 修复 Markdown 语法
|
||||
const { content: fixed, fixes } = fixMarkdownCodeBlocks(translated)
|
||||
if (fixes > 0) {
|
||||
console.log(`🔧 [${fileName}] Fixed ${fixes} unclosed code blocks`)
|
||||
translated = fixed
|
||||
}
|
||||
|
||||
// 3. 保存
|
||||
fs.mkdirSync(path.dirname(outputPath), { recursive: true })
|
||||
fs.writeFileSync(outputPath, translated, 'utf8')
|
||||
console.log(`✅ Saved: ${outputPath}`)
|
||||
}
|
||||
|
||||
async function runWithConcurrency(tasks, limit = 5) {
|
||||
async function runWithConcurrency(tasks, limit = MAX_CONCURRENT_REQUESTS) {
|
||||
const results = []
|
||||
const executing = new Set()
|
||||
for (const task of tasks) {
|
||||
@@ -137,8 +251,8 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`🧠 Total files: ${tasks.length}, concurrency: 5`)
|
||||
await runWithConcurrency(tasks, 5)
|
||||
console.log(`🧠 Total files: ${tasks.length}, concurrency: ${MAX_CONCURRENT_REQUESTS}`)
|
||||
await runWithConcurrency(tasks, MAX_CONCURRENT_REQUESTS)
|
||||
console.log('🎉 Translation complete!')
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user