Merge branch 'v2' into v2

This commit is contained in:
ifeif 2024-03-03 00:36:26 +08:00 committed by GitHub
commit fe4288a3d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 761 additions and 90 deletions

View file

@ -56,7 +56,7 @@ export default class BingDrawClient {
fetchOptions.agent = proxy(Config.proxy)
}
let success = false
let retry = 5
let retry = 1
let response
while (!success && retry >= 0) {
response = await fetch(url, Object.assign(fetchOptions, { body, redirect: 'manual', method: 'POST', credentials: 'include' }))

View file

@ -16,7 +16,7 @@ export async function getChatHistoryGroup (e, num) {
}
chats = chats.slice(0, num)
try {
let mm = await e.group.getMemberMap()
let mm = await e.bot.gml
for (const chat of chats) {
if (e.adapter === 'shamrock') {
if (chat.sender?.user_id === 0) {

View file

@ -130,19 +130,14 @@ export class ClaudeAIClient {
async sendMessage (text, conversationId, attachments = []) {
let body = {
conversation_uuid: conversationId,
organization_uuid: this.organizationId,
text,
attachments,
completion: {
incremental: true,
model: 'claude-2.1',
prompt: text,
timezone: 'Asia/Hong_Kong'
}
files: [],
model: 'claude-2.1',
prompt: text,
timezone: 'Asia/Hong_Kong'
}
let host = Config.claudeAIReverseProxy || 'https://claude.ai'
let url = host + '/api/append_message'
let url = host + `/api/organizations/${this.organizationId}/chat_conversations/${conversationId}/completion`
const cycleTLS = await initCycleTLS()
let streamDataRes = await cycleTLS(url, {
ja3: this.JA3,
@ -160,7 +155,7 @@ export class ClaudeAIClient {
let streamData = streamDataRes.body
// console.log(streamData)
let responseText = ''
let streams = streamData.split('\n\n')
let streams = streamData.split('\n').filter(s => s?.includes('data: '))
for (let s of streams) {
let jsonStr = s.replace('data: ', '').trim()
try {

View file

@ -14,7 +14,7 @@ import { translate } from './translate.js'
import uploadRecord from './uploadRecord.js'
import Version from './version.js'
import fetch, { FormData, fileFromSync } from 'node-fetch'
import https from "https";
import https from 'https'
let pdfjsLib
try {
pdfjsLib = (await import('pdfjs-dist')).default
@ -1055,10 +1055,14 @@ export async function getOrDownloadFile (destPath, url, ignoreCertificateError =
* @param destPath 目标路径如received/abc.pdf. 目前如果文件名重复会覆盖
* @param absolute 是否是绝对路径默认为false此时拼接在data/chatgpt下
* @param ignoreCertificateError 忽略证书错误
* @param headers
* @returns {Promise<string>} 最终下载文件的存储位置
*/
export async function downloadFile (url, destPath, absolute = false, ignoreCertificateError = true) {
export async function downloadFile (url, destPath, absolute = false, ignoreCertificateError = true, headers) {
let init = {}
if (headers) {
init.headers = headers
}
if (ignoreCertificateError && url.startsWith('https')) {
init.agent = new https.Agent({
rejectUnauthorized: !ignoreCertificateError
@ -1261,3 +1265,52 @@ export async function extractContentFromFile (fileMsgElem, e) {
return {}
}
}
/**
* generated by ai
* @param email
* @returns {string}
*/
export function maskEmail (email) {
// 使用正则表达式匹配电子邮件地址的用户名和域名部分
const regex = /^([^@]+)@([^@]+)$/
const match = email.match(regex)
if (!match) {
throw new Error('Invalid email format')
}
// 获取用户名和域名
const username = match[1]
const domain = match[2]
// 对用户名部分进行部分打码
const maskedUsername = maskString(username)
// 对域名部分进行部分打码
const maskedDomain = maskString(domain)
// 构造新的电子邮件地址
const maskedEmail = maskedUsername + '@' + maskedDomain
return maskedEmail
}
/**
* generated by ai
* @param str
* @returns {*|string}
*/
function maskString (str) {
// 如果字符串长度小于等于2直接返回原字符串
if (str.length <= 2) {
return str
}
// 取字符串的前三个字符和后三个字符,中间使用*代替
const firstThreeChars = str.substring(0, 3)
const lastThreeChars = str.substring(str.length - 3)
const maskedChars = '*'.repeat(str.length - 6)
return firstThreeChars + maskedChars + lastThreeChars
}

View file

@ -176,6 +176,9 @@ const defaultConfig = {
// origin: https://generativelanguage.googleapis.com
geminiBaseUrl: 'https://gemini.ikechan8370.com',
chatglmRefreshToken: '',
sunoSessToken: '',
sunoClientToken: '',
translateSource: 'openai',
version: 'v2.7.10'
}
const _path = process.cwd()

View file

@ -470,7 +470,7 @@ export async function convertFaces (msg, handleAt = false, e) {
let groupCardQQMap = {}
if (handleAt) {
try {
groupMembers = await e.group.getMemberMap()
groupMembers = e.bot.gml
} catch (err) {
console.error(`Failed to get group members: ${err}`)
}

8
utils/jwt.js Normal file
View file

@ -0,0 +1,8 @@
export function decrypt (jwtToken) {
const [encodedHeader, encodedPayload, signature] = jwtToken.split('.')
const decodedHeader = Buffer.from(encodedHeader, 'base64').toString('utf-8')
const decodedPayload = Buffer.from(encodedPayload, 'base64').toString('utf-8')
return decodedPayload
}

View file

@ -1,5 +1,13 @@
import md5 from 'md5'
import _ from 'lodash'
import { Config } from './config.js'
import { ChatGPTAPI } from './openai/chatgpt-api.js'
import { newFetch } from './proxy.js'
import { CustomGoogleGeminiClient } from '../client/CustomGoogleGeminiClient.js'
import XinghuoClient from './xinghuo/xinghuo.js'
import {getImg, getMessageById, upsertMessage} from './common.js'
import {QwenApi} from "./alibaba/qwen-api.js";
import {v4 as uuid} from "uuid";
// 代码参考https://github.com/yeyang52/yenai-plugin/blob/b50b11338adfa5a4ef93912eefd2f1f704e8b990/model/api/funApi.js#L25
export const translateLangSupports = [
@ -20,7 +28,7 @@ export const translateLangSupports = [
{ code: 'zh-CHS', label: '中文', abbr: '中', alphabet: 'Z' }
]
const API_ERROR = '出了点小问题,待会再试试吧'
export async function translate (msg, to = 'auto') {
export async function translateOld (msg, to = 'auto') {
let from = 'auto'
if (to !== 'auto') to = translateLangSupports.find(item => item.abbr == to)?.code
if (!to) return `未找到翻译的语种,支持的语言为:\n${translateLangSupports.map(item => item.abbr).join('')}\n`
@ -95,3 +103,113 @@ export async function translate (msg, to = 'auto') {
return API_ERROR
}
}
/**
*
* @param msg 要翻译的
* @param from 语种
* @param to 语种
* @param ai ai来源支持openai, gemini, xh, qwen
* @returns {Promise<*|string>}
*/
export async function translate (msg, to = 'auto', from = 'auto', ai = Config.translateSource) {
try {
let lang = '中'
if (to !== 'auto') {
lang = translateLangSupports.find(item => item.abbr == to)?.code
}
if (!lang) return `未找到翻译的语种,支持的语言为:\n${translateLangSupports.map(item => item.abbr).join('')}\n`
// if ai is not in the list, throw error
if (!['openai', 'gemini', 'xh', 'qwen'].includes(ai)) throw new Error('ai来源错误')
let system = `You will be provided with a sentence in the language with language code [${from}], and your task is to translate it into [${lang}]. Just print the result without any other words.`
if (Array.isArray(msg)) {
let result = []
for (let i = 0; i < msg.length; i++) {
let item = msg[i]
let res = await translate(item, to, from, ai)
result.push(res)
}
return result
}
switch (ai) {
case 'openai': {
let api = new ChatGPTAPI({
apiBaseUrl: Config.openAiBaseUrl,
apiKey: Config.apiKey,
fetch: newFetch
})
const res = await api.sendMessage(msg, {
systemMessage: system,
completionParams: {
model: 'gpt-3.5-turbo'
}
})
return res.text
}
case 'gemini': {
let client = new CustomGoogleGeminiClient({
key: Config.geminiKey,
model: Config.geminiModel,
baseUrl: Config.geminiBaseUrl,
debug: Config.debug
})
let option = {
stream: false,
onProgress: (data) => {
if (Config.debug) {
logger.info(data)
}
},
system
}
let res = await client.sendMessage(msg, option)
return res.text
}
case 'xh': {
let client = new XinghuoClient({
ssoSessionId: Config.xinghuoToken
})
let response = await client.sendMessage(msg, { system })
return response.text
}
case 'qwen': {
let completionParams = {
parameters: {
top_p: Config.qwenTopP || 0.5,
top_k: Config.qwenTopK || 50,
seed: Config.qwenSeed > 0 ? Config.qwenSeed : Math.floor(Math.random() * 114514),
temperature: Config.qwenTemperature || 1,
enable_search: !!Config.qwenEnableSearch
}
}
if (Config.qwenModel) {
completionParams.model = Config.qwenModel
}
let opts = {
apiKey: Config.qwenApiKey,
debug: false,
systemMessage: system,
completionParams,
fetch: newFetch
}
let client = new QwenApi(opts)
let option = {
timeoutMs: 600000,
completionParams
}
let result
try {
result = await client.sendMessage(msg, option)
} catch (err) {
logger.error(err)
throw new Error(err)
}
return result.text
}
}
} catch (e) {
logger.error(e)
logger.info('基于LLM的翻译失败转用老版翻译')
return await translateOld(msg, to)
}
}

View file

@ -395,7 +395,7 @@ export default class XinghuoClient {
logger.warn('星火设定序列化失败,本次对话不附带设定')
}
} else {
Prompt = Config.xhPrompt ? [{ role: 'system', content: Config.xhPrompt }] : []
Prompt = option.system ? [{ role: 'system', content: option.system }] : []
}
if (Config.xhPromptEval) {
Prompt.forEach(obj => {