新功能: - 创建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助手体验!
329 lines
9.9 KiB
JavaScript
Executable File
329 lines
9.9 KiB
JavaScript
Executable File
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()
|
||
|