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

329 lines
9.9 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 {AppTokenRequest} = require("./request/AppTokenRequest")
const {UserTokenRequest} = require("./request/UserTokenRequest")
const {CompanyAllUserPostRequest} = require("./request/CompanyAllUserPostRequest")
const {StoreExtendPostRequest} = require("./request/StoreExtendPostRequest")
const {UserAuthStorePostRequest} = require("./request/UserAuthStorePostRequest")
const {UserAuthApiRequest} = require("./request/UserAuthApiRequest")
const {UserOpenIdRequest} = require("./request/UserOpenIdRequest")
const fs = require('fs')
const path = require('path')
const dotenv = require('dotenv')
const OpenClient = require('./common/OpenClient')
// 应用ID
const appId = ''
// 应用私钥,2048位,PKCS8
const privateKey = ''
// 接口url
const url = 'https://sbappstoreapi.ziniao.com'
// 创建客户端
const openClient = new OpenClient(appId, privateKey, url)
// 存储token信息
let tokenInfo = {
appAuthToken: '',
requestId: '',
lastUpdated: null,
expiresIn: 7200000 // 默认过期时间为2小时(毫秒)
}
// 尝试加载环境变量
dotenv.config({ path: path.resolve(__dirname, '../.env') })
function printResult(data) {
// 成功
if (data.code === '0' || data.code === 0) {
console.log('成功', data);
console.log('\n结果\n', data.data)
return data;
} else {
console.error('失败', data)
return null;
}
}
/**
* 获取用户token
*/
function getUserToken() {
// 创建请求
const request = new UserTokenRequest()
// 设置业务参数
request.bizModel = {
'userCode': '填写code'
}
openClient.execute(request, printResult)
}
/**
* 获取应用token
* @param {Function} callback 可选的回调函数
* @returns {Promise} 返回一个Promise
*/
function getAppToken(callback) {
return new Promise((resolve, reject) => {
try {
// 创建请求
const request = new AppTokenRequest()
// 更新客户端配置为环境变量中的值
if (process.env.APP_ID && process.env.PRIVATE_KEY) {
openClient.appId = process.env.APP_ID;
openClient.privateKey = process.env.PRIVATE_KEY;
openClient.url = process.env.API_URL || url;
}
openClient.execute(request, (data) => {
const result = printResult(data);
if (result && result.data) {
// 提取token值用于日志显示和调试
const appAuthToken = result.data.appAuthToken || '';
// requestId可能在顶层或者data中
const requestId = result.request_id || result.data.request_id || '';
console.log('获取到的token详情:');
console.log('- appAuthToken:', appAuthToken);
console.log('- requestId:', requestId);
console.log('- 原始data:', JSON.stringify(result.data));
// 直接更新tokenInfo对象
tokenInfo.appAuthToken = appAuthToken;
tokenInfo.requestId = requestId;
tokenInfo.lastUpdated = new Date();
console.log('Token已更新:', {
appAuthToken: tokenInfo.appAuthToken,
requestId: tokenInfo.requestId,
lastUpdated: tokenInfo.lastUpdated
});
// 立即更新process.env中的值,确保当前进程也能立即使用新token
process.env.APP_AUTH_TOKEN = appAuthToken;
process.env.REQUEST_ID = requestId;
// 更新环境变量文件
updateEnvFile();
if (callback) callback(result.data);
resolve(result.data);
} else {
const error = new Error('获取应用Token失败');
if (callback) callback(null, error);
reject(error);
}
})
} catch (error) {
console.error('获取Token异常:', error);
if (callback) callback(null, error);
reject(error);
}
});
}
/**
* 更新.env文件中的token信息
*/
function updateEnvFile() {
try {
const envFilePath = path.resolve(__dirname, '../.env');
// 读取现有.env文件
let envContent = '';
if (fs.existsSync(envFilePath)) {
envContent = fs.readFileSync(envFilePath, 'utf8');
}
// 解析为对象
const envVars = {};
envContent.split('\n').forEach(line => {
if (line.trim() && !line.startsWith('#')) {
const parts = line.split('=');
if (parts.length >= 2) {
const key = parts[0].trim();
const value = parts.slice(1).join('=').trim();
envVars[key] = value;
}
}
});
// 更新token值
envVars['APP_AUTH_TOKEN'] = tokenInfo.appAuthToken;
envVars['REQUEST_ID'] = tokenInfo.requestId;
// 转换回字符串
let newEnvContent = '';
for (const key in envVars) {
newEnvContent += `${key}=${envVars[key]}\n`;
}
// 写回文件
fs.writeFileSync(envFilePath, newEnvContent);
console.log('.env文件已更新');
// 重新加载环境变量
dotenv.config({ path: envFilePath });
} catch (error) {
console.error('更新.env文件失败:', error);
}
}
/**
* 初始化token刷新机制
* @param {number} refreshInterval 刷新间隔(毫秒),默认7200000(2小时)
*/
function initTokenRefresh(refreshInterval = 7200000) {
// 立即获取一次token
getAppToken().catch(err => console.error('初始化token获取失败:', err));
// 设置定时器定期刷新token
setInterval(() => {
console.log('定时刷新token...');
getAppToken().catch(err => console.error('定时刷新token失败:', err));
}, refreshInterval);
console.log(`已设置token自动刷新,间隔: ${refreshInterval}ms (${refreshInterval/3600000}小时)`);
}
/**
* 获取当前token信息
* @returns {Object} token信息对象
*/
function getTokenInfo() {
return { ...tokenInfo };
}
/**
* 获取用户openId
*/
function getUserOpenId() {
// 创建请求
const request = new UserOpenIdRequest()
// request.bizModel = {
// type: 1
// }
const userToken = '填写user_token'
openClient.executeUserToken(request, userToken, printResult)
}
/**
* 获取当前用户接口权限
*/
function getUserAuthApi() {
// 创建请求
const request = new UserAuthApiRequest()
const userToken = '填写user_token'
openClient.executeUserToken(request, userToken, printResult)
}
/**
* 获取店铺基础信息接口
*/
function getStoreExtendInfo() {
// 创建请求
const request = new StoreExtendPostRequest()
// 设置业务参数
request.bizModel = {
storeIds: [16116283712285,15870176292166]
}
const userToken = '填写user_token'
openClient.executeUserToken(request, userToken, printResult)
}
/**
* 获取当前用户可访问环境基础信息
*/
function getUserAuthStore() {
// 创建请求
const request = new UserAuthStorePostRequest()
// 设置业务参数
request.bizModel = {
storeIds: [16116283712285,15870176292166]
}
const userToken = '填写user_token'
openClient.executeUserToken(request, userToken, printResult)
}
/**
* 获取公司所有员工接口
*/
function getCompanyAllUser() {
// 创建请求
const request = new CompanyAllUserPostRequest()
const userToken = '填写user_token'
openClient.executeUserToken(request, userToken, printResult)
}
/**
* 检查token是否有效
* @returns {boolean} token是否有效
*/
function isTokenValid() {
// 检查token是否存在
if (!tokenInfo.appAuthToken || !tokenInfo.requestId) {
console.log('Token不存在或不完整');
return false;
}
// 检查token是否过期
if (!tokenInfo.lastUpdated) {
console.log('Token未设置更新时间');
return false;
}
const now = new Date();
const tokenAge = now - tokenInfo.lastUpdated;
// 如果token年龄超过expiresIn (默认2小时),则认为已过期
if (tokenAge >= tokenInfo.expiresIn) {
console.log(`Token已过期,年龄: ${tokenAge}ms,过期时间: ${tokenInfo.expiresIn}ms`);
return false;
}
// 如果token将在10分钟内过期,提前刷新
const tenMinutes = 10 * 60 * 1000;
if (tokenAge >= tokenInfo.expiresIn - tenMinutes) {
console.log(`Token即将过期,触发提前刷新`);
// 异步刷新token,不阻塞当前操作
getAppToken().catch(err => console.error('提前刷新token失败:', err));
}
return true;
}
// 导出功能
module.exports = {
getAppToken,
getUserToken,
getUserOpenId,
getUserAuthApi,
getStoreExtendInfo,
getUserAuthStore,
getCompanyAllUser,
initTokenRefresh,
getTokenInfo,
isTokenValid
};
// 以下代码在被导入时不执行,只在直接运行main.js时执行
if (require.main === module) {
// 初始化token刷新,每2小时自动更新一次
initTokenRefresh();
}
// getUserToken()
// getAppToken()
// getUserOpenId()
// getUserAuthApi()
// getCompanyAllUser()
// getStoreExtendInfo()
// getUserAuthStore()
// operateStorePlugin()
// test()