perf: AI机器人支持自定义模型

This commit is contained in:
kuaifan 2025-02-08 12:34:20 +09:00
parent 6bcc7b6c49
commit fb286cea3c
5 changed files with 92 additions and 31 deletions

View File

@ -1028,6 +1028,7 @@ class DialogController extends AbstractController
* @apiParam {String} [silence] 是否静默发送 * @apiParam {String} [silence] 是否静默发送
* - no: 正常发送(默认) * - no: 正常发送(默认)
* - yes: 静默发送 * - yes: 静默发送
* @apiParam {String} [model_name] 模型名称仅AI机器人支持
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -1048,6 +1049,7 @@ class DialogController extends AbstractController
$key = trim(Request::input('key')); $key = trim(Request::input('key'));
$text_type = strtolower(trim(Request::input('text_type'))); $text_type = strtolower(trim(Request::input('text_type')));
$silence = in_array(strtolower(trim(Request::input('silence'))), ['yes', 'true', '1']); $silence = in_array(strtolower(trim(Request::input('silence'))), ['yes', 'true', '1']);
$model_name = trim(Request::input('model_name'));
$markdown = in_array($text_type, ['md', 'markdown']); $markdown = in_array($text_type, ['md', 'markdown']);
// //
$result = []; $result = [];
@ -1119,12 +1121,18 @@ class DialogController extends AbstractController
if (empty($key)) { if (empty($key)) {
$key = $desc; $key = $desc;
} }
if ($model_name) {
$msgData['model_name'] = $model_name;
}
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'longtext', $msgData, $user->userid, false, false, $silence, $key); $result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'longtext', $msgData, $user->userid, false, false, $silence, $key);
} else { } else {
$msgData = ['text' => $text]; $msgData = ['text' => $text];
if ($markdown) { if ($markdown) {
$msgData['type'] = 'md'; $msgData['type'] = 'md';
} }
if ($model_name) {
$msgData['model_name'] = $model_name;
}
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence, $key); $result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence, $key);
} }
} }

View File

@ -188,23 +188,25 @@ class UserBot extends AbstractModel
]; ];
default: default:
if (preg_match('/^ai-(.*?)@bot\.system$/', $email)) { if (preg_match('/^ai-(.*?)@bot\.system$/', $email, $match)) {
if (!Base::judgeClientVersion('0.42.62')) { if (!Base::judgeClientVersion('0.42.62')) {
return [ return [
'key' => '%3A.clear', 'key' => '%3A.clear',
'label' => Doo::translate('清空上下文') 'label' => Doo::translate('清空上下文')
]; ];
} }
$aibotSetting = Base::setting('aibotSetting');
return [ return [
[ [
'key' => 'ai-newchat', 'key' => '~ai-model-select',
'label' => Doo::translate('开启新对话'), 'label' => Doo::translate('选择模型'),
'config' => [] 'config' => [
'model' => $aibotSetting[$match[1] . '_model']
]
], ],
[ [
'key' => 'ai-historychat', 'key' => '%3A.clear',
'label' => Doo::translate('历史对话'), 'label' => Doo::translate('清空上下文')
'config' => []
] ]
]; ];
} }

View File

@ -431,6 +431,9 @@ class BotReceiveMsgTask extends AbstractTask
'agency' => $setting[$type . '_agency'], 'agency' => $setting[$type . '_agency'],
'server_url' => $serverUrl, 'server_url' => $serverUrl,
]; ];
if ($msg->msg['model_name']) {
$extras['model_name'] = $msg->msg['model_name'];
}
if ($type === 'wenxin') { if ($type === 'wenxin') {
$extras['api_key'] .= ':' . $setting['wenxin_secret']; $extras['api_key'] .= ':' . $setting['wenxin_secret'];
} }

View File

@ -256,7 +256,7 @@
<div v-else-if="quickShow" class="chat-bottom-menu"> <div v-else-if="quickShow" class="chat-bottom-menu">
<ul class="scrollbar-hidden"> <ul class="scrollbar-hidden">
<li v-for="item in quickMsgs" @click.stop="sendQuick(item, $event)"> <li v-for="item in quickMsgs" @click.stop="sendQuick(item, $event)">
<div class="bottom-menu-desc no-dark-content" :style="item.style || null">{{item.label}}</div> <div class="bottom-menu-desc no-dark-content" :style="item.style || null">{{quickLabel(item)}}</div>
</li> </li>
</ul> </ul>
</div> </div>
@ -870,9 +870,14 @@ export default {
replyMsgAutoMention: false, // @ replyMsgAutoMention: false, // @
waitUnreadData: new Map(), // waitUnreadData: new Map(), //
replyEmojiIngs: {}, // replyEmojiIngs: {}, //
dialogAiModel: [], // AI
} }
}, },
async created() {
this.dialogAiModel = await $A.IDBArray('dialogAiModel')
},
mounted() { mounted() {
this.subMsgListener() this.subMsgListener()
emitter.on('dialogMsgChange', this.onMsgChange); emitter.on('dialogMsgChange', this.onMsgChange);
@ -1594,6 +1599,18 @@ export default {
} }
}, },
/**
* 发送数据处理
* @param data
* @returns {*}
*/
sendDataHandle(data) {
if (this.isAiBot) {
data.model_name = this.aiModelValue()
}
return data
},
/** /**
* 发送消息 * 发送消息
* @param text * @param text
@ -1641,13 +1658,13 @@ export default {
// //
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'dialog/msg/sendtext', url: 'dialog/msg/sendtext',
data: { data: this.sendDataHandle({
dialog_id: this.dialogId, dialog_id: this.dialogId,
update_id, update_id,
text: textBody, text: textBody,
text_type: textType, text_type: textType,
silence, silence,
}, }),
method: 'post', method: 'post',
complete: _ => this.$store.dispatch("cancelLoad", `msg-${update_id}`) complete: _ => this.$store.dispatch("cancelLoad", `msg-${update_id}`)
}).then(({data}) => { }).then(({data}) => {
@ -1680,13 +1697,13 @@ export default {
this.$store.dispatch("call", { this.$store.dispatch("call", {
requestId: tempMsg.id, requestId: tempMsg.id,
url: 'dialog/msg/sendtext', url: 'dialog/msg/sendtext',
data: { data: this.sendDataHandle({
dialog_id: tempMsg.dialog_id, dialog_id: tempMsg.dialog_id,
reply_id: tempMsg.reply_id, reply_id: tempMsg.reply_id,
text: textBody, text: textBody,
text_type: textType, text_type: textType,
silence, silence,
}, }),
method: 'post', method: 'post',
}).then(({data}) => { }).then(({data}) => {
this.sendSuccess(data, tempMsg.id) this.sendSuccess(data, tempMsg.id)
@ -1799,6 +1816,31 @@ export default {
}); });
}, },
/**
* Ai模型值
* @returns {*}
*/
aiModelValue() {
const item = this.dialogAiModel.find(({dialog_id}) => dialog_id == this.dialogId)
return item?.model
},
/**
* 快捷菜单标签
* @param key
* @param label
* @param config
* @returns {*}
*/
quickLabel({key, label, config}) {
if (key === '~ai-model-select') {
const model = this.aiModelValue()
if (model) return model
if (config?.model) return config.model
}
return label
},
/** /**
* 发送快捷消息 * 发送快捷消息
* @param item * @param item
@ -1856,30 +1898,36 @@ export default {
}); });
break; break;
// //
case "ai-newchat": case "~ai-model-select":
if (!this.isAiBot) { if (!this.isAiBot) {
return return
} }
const list = AIModelList(this.dialogData.email).map(value => ({label: value, value: value}))
const configModel = item.config?.model
if (configModel && !list.find(({value}) => value === configModel)) {
list.unshift({label: configModel, value: configModel})
}
this.$store.state.menuOperation = { this.$store.state.menuOperation = {
event, event,
list: AIModelList(this.dialogData.email).map(value => ({label: value, value: value})), list,
scrollHide: true, scrollHide: true,
onUpdate: async (model) => { onUpdate: async model => {
this.dialogAiModel = [
...this.dialogAiModel.filter(({dialog_id}) => dialog_id !== this.dialogId),
{dialog_id: this.dialogId, model}
]
await $A.IDBSet('dialogAiModel', this.dialogAiModel)
} }
} }
break; break;
//
case "ai-historychat":
if (!this.isAiBot) {
return
}
break;
// //
default: default:
if (/^~/.test(item.key)) {
$A.modalWarning("当前客户端不支持该指令");
break;
}
this.sendMsg(`<p><span data-quick-key="${item.key}">${item.label}</span></p>`) this.sendMsg(`<p><span data-quick-key="${item.key}">${item.label}</span></p>`)
break; break;
} }

View File

@ -91,7 +91,7 @@ export default {
link: 'https://platform.openai.com/account/api-keys' link: 'https://platform.openai.com/account/api-keys'
}, },
{ {
label: '模型', label: '默认模型',
prop: 'openai_model', prop: 'openai_model',
type: 'auto-complete', type: 'auto-complete',
data: AIModelList('openai'), data: AIModelList('openai'),
@ -132,7 +132,7 @@ export default {
link: 'https://docs.anthropic.com/en/api/getting-started' link: 'https://docs.anthropic.com/en/api/getting-started'
}, },
{ {
label: '模型', label: '默认模型',
prop: 'claude_model', prop: 'claude_model',
type: 'auto-complete', type: 'auto-complete',
data: AIModelList('claude'), data: AIModelList('claude'),
@ -167,7 +167,7 @@ export default {
link: 'https://platform.deepseek.com/api_keys' link: 'https://platform.deepseek.com/api_keys'
}, },
{ {
label: '模型', label: '默认模型',
prop: 'deepseek_model', prop: 'deepseek_model',
type: 'auto-complete', type: 'auto-complete',
data: AIModelList('deepseek'), data: AIModelList('deepseek'),
@ -208,7 +208,7 @@ export default {
link: 'https://makersuite.google.com/app/apikey' link: 'https://makersuite.google.com/app/apikey'
}, },
{ {
label: '模型', label: '默认模型',
prop: 'gemini_model', prop: 'gemini_model',
type: 'auto-complete', type: 'auto-complete',
data: AIModelList('gemini'), data: AIModelList('gemini'),
@ -242,7 +242,7 @@ export default {
link: 'https://bigmodel.cn/usercenter/apikeys' link: 'https://bigmodel.cn/usercenter/apikeys'
}, },
{ {
label: '模型', label: '默认模型',
prop: 'zhipu_model', prop: 'zhipu_model',
type: 'auto-complete', type: 'auto-complete',
data: AIModelList('zhipu'), data: AIModelList('zhipu'),
@ -276,7 +276,7 @@ export default {
link: 'https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key' link: 'https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key'
}, },
{ {
label: '模型', label: '默认模型',
prop: 'qianwen_model', prop: 'qianwen_model',
type: 'auto-complete', type: 'auto-complete',
data: AIModelList('qianwen'), data: AIModelList('qianwen'),
@ -317,7 +317,7 @@ export default {
link: 'https://console.bce.baidu.com/qianfan/ais/console/applicationConsole/application/v1' link: 'https://console.bce.baidu.com/qianfan/ais/console/applicationConsole/application/v1'
}, },
{ {
label: '模型', label: '默认模型',
prop: 'wenxin_model', prop: 'wenxin_model',
type: 'auto-complete', type: 'auto-complete',
data: AIModelList('wenxin'), data: AIModelList('wenxin'),