chenpei d0dc94e36d feat: 将弹幕功能替换为AI聊天助手
新功能:
- 创建AI聊天助手组件(AIChatWidget)
- 支持文字+图片多模态对话
- 集成Gemini AI API
- 支持图片编辑和内容生成
- 实时对话历史管理
- 优雅的UI设计,支持黑夜模式

技术实现:
- 后端API代理Gemini API(/api/ai-chat)
- 支持最多5张图片上传
- 流式响应处理
- 对话历史管理
- Base64图片处理

配置:
- 在.env中添加Gemini API配置
- GEMINI_API_KEY
- GEMINI_API_BASE_URL
- GEMINI_MODEL

替换原弹幕功能,提供更强大的AI助手体验!
2025-10-27 17:45:37 +08:00

89 lines
2.6 KiB
JavaScript
Executable File
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 {KJUR, hextob64} = require('jsrsasign')
const HashMap = {
SHA256withRSA: 'SHA256withRSA',
SHA1withRSA: 'SHA1withRSA'
}
const PEM_BEGIN = '-----BEGIN PRIVATE KEY-----\n'
const PEM_END = '\n-----END PRIVATE KEY-----'
/**
* rsa签名参考:https://www.jianshu.com/p/145eab95322c
*/
exports.SignUtil = {
/**
* 创建签名
* @param params 请求参数
* @param privateKey 私钥,PKCS8
* @param signType 签名类型,RSA,RSA2
* @returns 返回签名内容
*/
createSign(params, privateKey, signType) {
const content = this.getSignContent(params)
return this.sign(content, privateKey, signType)
},
sign: function (content, privateKey, signType) {
if (signType.toUpperCase() === 'RSA') {
return this.rsaSign(content, privateKey, HashMap.SHA1withRSA)
} else if (signType.toUpperCase() === 'RSA2') {
return this.rsaSign(content, privateKey, HashMap.SHA256withRSA)
} else {
throw 'signType错误'
}
},
/**
* rsa签名
* @param content 签名内容
* @param privateKey 私钥
* @param hash hash算法,SHA256withRSA,SHA1withRSA
* @returns 返回签名字符串,base64
*/
rsaSign: function (content, privateKey, hash) {
privateKey = this._formatKey(privateKey)
// 创建 Signature 对象
const signature = new KJUR.crypto.Signature({
alg: hash,
//!这里指定 私钥 pem!
prvkeypem: privateKey
})
signature.updateString(content)
const signData = signature.sign()
// 将内容转成base64
return hextob64(signData)
},
_formatKey: function (key) {
if (!key.startsWith(PEM_BEGIN)) {
key = PEM_BEGIN + key
}
if (!key.endsWith(PEM_END)) {
key = key + PEM_END
}
return key
},
/**
* 获取签名内容
* @param params 请求参数
* @returns {string}
*/
getSignContent: function (params) {
const paramNames = []
for(const key in params) {
paramNames.push(key)
}
paramNames.sort()
const paramNameValue = []
for (let i = 0, len = paramNames.length; i < len; i++) {
const paramName = paramNames[i];
const val = params[paramName];
if (paramName && val) {
paramNameValue.push(`${paramName}=${typeof val === 'object' ? JSON.stringify(val) : val}`)
}
}
return paramNameValue.join('&')
}
}