Files
platform-pipi/packages/voice-production/scripts/generate_char_introduce.js
T
2026-01-30 16:04:10 +08:00

254 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require("fs");
const path = require("path");
const https = require("https");
const crypto = require("crypto");
// 腾讯云混元大模型配置
// 请设置环境变量 TENCENT_SECRET_ID 和 TENCENT_SECRET_KEY
const SECRET_ID = process.env.TENCENT_SECRET_ID;
const SECRET_KEY = process.env.TENCENT_SECRET_KEY;
// API配置
const HOST = "hunyuan.tencentcloudapi.com";
const SERVICE = "hunyuan";
const REGION = "ap-guangzhou";
const ACTION = "ChatCompletions";
const VERSION = "2023-09-01";
const MODEL = "hunyuan-lite"; // 使用混元lite模型,可根据需要更换
// 签名相关函数
function sha256(message, secret = "", encoding = "hex") {
const hmac = secret
? crypto.createHmac("sha256", secret)
: crypto.createHash("sha256");
return hmac.update(message).digest(encoding);
}
function getDate(timestamp) {
const date = new Date(timestamp * 1000);
const year = date.getUTCFullYear();
const month = ("0" + (date.getUTCMonth() + 1)).slice(-2);
const day = ("0" + date.getUTCDate()).slice(-2);
return `${year}-${month}-${day}`;
}
function generateSignature(secretId, secretKey, host, payload, timestamp) {
const date = getDate(timestamp);
// 步骤1:拼接规范请求串
const httpRequestMethod = "POST";
const canonicalUri = "/";
const canonicalQueryString = "";
const contentType = "application/json";
const canonicalHeaders = `content-type:${contentType}\nhost:${host}\nx-tc-action:${ACTION.toLowerCase()}\n`;
const signedHeaders = "content-type;host;x-tc-action";
const hashedRequestPayload = sha256(payload);
const canonicalRequest = `${httpRequestMethod}\n${canonicalUri}\n${canonicalQueryString}\n${canonicalHeaders}\n${signedHeaders}\n${hashedRequestPayload}`;
// 步骤2:拼接待签名字符串
const algorithm = "TC3-HMAC-SHA256";
const credentialScope = `${date}/${SERVICE}/tc3_request`;
const hashedCanonicalRequest = sha256(canonicalRequest);
const stringToSign = `${algorithm}\n${timestamp}\n${credentialScope}\n${hashedCanonicalRequest}`;
// 步骤3:计算签名
const secretDate = sha256(date, "TC3" + secretKey, "buffer");
const secretService = sha256(SERVICE, secretDate, "buffer");
const secretSigning = sha256("tc3_request", secretService, "buffer");
const signature = sha256(stringToSign, secretSigning);
// 步骤4:拼接Authorization
const authorization = `${algorithm} Credential=${secretId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
return authorization;
}
// 调用混元API
async function callHunyuan(prompt) {
return new Promise((resolve, reject) => {
const timestamp = Math.floor(Date.now() / 1000);
const payload = JSON.stringify({
Model: MODEL,
Messages: [
{
Role: "user",
Content: prompt,
},
],
Stream: false,
});
const authorization = generateSignature(
SECRET_ID,
SECRET_KEY,
HOST,
payload,
timestamp
);
const options = {
hostname: HOST,
port: 443,
path: "/",
method: "POST",
headers: {
"Content-Type": "application/json",
Host: HOST,
"X-TC-Action": ACTION,
"X-TC-Version": VERSION,
"X-TC-Timestamp": timestamp.toString(),
"X-TC-Region": REGION,
Authorization: authorization,
},
};
const req = https.request(options, (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
try {
const result = JSON.parse(data);
if (result.Response && result.Response.Choices) {
resolve(result.Response.Choices[0].Message.Content.trim());
} else if (result.Response && result.Response.Error) {
reject(new Error(result.Response.Error.Message));
} else {
reject(new Error("Unknown API response: " + data));
}
} catch (e) {
reject(e);
}
});
});
req.on("error", reject);
req.write(payload);
req.end();
});
}
// 为单个汉字生成介绍
async function generateIntroduce(char) {
const prompt = `请为汉字"${char}"生成一个简短的词组介绍,格式为"${char}XXX的${char}",其中XXX是一个包含该汉字的常见词语。
例如:
- 汉字"天"的介绍是"天,天空的天"
- 汉字"地"的介绍是"地,大地的地"
- 汉字"人"的介绍是"人,人民的人"
请只输出介绍内容,不要包含其他解释。比如对于"天",只输出"天,天空的天"。`;
try {
const response = await callHunyuan(prompt);
// 清理响应,只保留核心内容
let introduce = response.replace(/["""]/g, "").trim();
// 如果响应包含多余内容,尝试提取核心部分
const match = introduce.match(/..+的./);
if (match) {
introduce = match[0];
}
// 确保格式正确:如果没有逗号,添加逗号
if (!introduce.startsWith(char + "")) {
// 尝试提取词组部分
const wordMatch = introduce.match(/(.+的.)/);
if (wordMatch) {
introduce = `${char}${wordMatch[1]}`;
} else {
introduce = `${char}${char}字的${char}`;
}
}
return introduce;
} catch (error) {
console.error(`生成 "${char}" 介绍失败:`, error.message);
return `${char}${char}字的${char}`;
}
}
// 延时函数
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// 主函数
async function main() {
// 检查环境变量
if (!SECRET_ID || !SECRET_KEY) {
console.error("请设置环境变量 TENCENT_SECRET_ID 和 TENCENT_SECRET_KEY");
console.error("例如:");
console.error(
" export TENCENT_SECRET_ID=your_secret_id"
);
console.error(
" export TENCENT_SECRET_KEY=your_secret_key"
);
process.exit(1);
}
// 读取汉字数据
const charStringPath = path.join(
__dirname,
"../data/char/char_string.json"
);
const charString = JSON.parse(fs.readFileSync(charStringPath, "utf-8"));
// 获取所有汉字
const chars = charString["3500"].split("");
console.log(`共有 ${chars.length} 个汉字需要处理`);
// 检查是否有已存在的进度文件
const outputPath = path.join(
__dirname,
"../data/char/char_introduce.json"
);
let results = [];
let startIndex = 0;
if (fs.existsSync(outputPath)) {
try {
results = JSON.parse(fs.readFileSync(outputPath, "utf-8"));
startIndex = results.length;
console.log(`发现已有进度,从第 ${startIndex + 1} 个汉字继续`);
} catch (e) {
console.log("已有文件解析失败,从头开始");
}
}
// 批量处理
const BATCH_SIZE = 10; // 每批处理10个
const DELAY_BETWEEN_BATCHES = 1000; // 批次间延迟1秒
for (let i = startIndex; i < chars.length; i += BATCH_SIZE) {
const batch = chars.slice(i, Math.min(i + BATCH_SIZE, chars.length));
console.log(
`处理第 ${i + 1} - ${Math.min(i + BATCH_SIZE, chars.length)} 个汉字...`
);
// 并行处理当前批次
const batchResults = await Promise.all(
batch.map(async (char, idx) => {
// 每个请求之间稍微错开
await delay(idx * 100);
const introduce = await generateIntroduce(char);
console.log(` ${char}: ${introduce}`);
return { char, introduce };
})
);
results.push(...batchResults);
// 每批处理完后保存进度
fs.writeFileSync(outputPath, JSON.stringify(results, null, 2), "utf-8");
console.log(`已保存进度:${results.length}/${chars.length}`);
// 批次间延迟,避免API限流
if (i + BATCH_SIZE < chars.length) {
await delay(DELAY_BETWEEN_BATCHES);
}
}
console.log(`\n完成!共生成 ${results.length} 个汉字介绍`);
console.log(`结果已保存到: ${outputPath}`);
}
main().catch(console.error);