mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-11 18:42:54 +00:00
perf: AI机器人支持多会话
This commit is contained in:
parent
6338a44cc1
commit
6bcc7b6c49
@ -189,10 +189,22 @@ class UserBot extends AbstractModel
|
||||
|
||||
default:
|
||||
if (preg_match('/^ai-(.*?)@bot\.system$/', $email)) {
|
||||
return [
|
||||
[
|
||||
if (!Base::judgeClientVersion('0.42.62')) {
|
||||
return [
|
||||
'key' => '%3A.clear',
|
||||
'label' => Doo::translate('清空上下文')
|
||||
];
|
||||
}
|
||||
return [
|
||||
[
|
||||
'key' => 'ai-newchat',
|
||||
'label' => Doo::translate('开启新对话'),
|
||||
'config' => []
|
||||
],
|
||||
[
|
||||
'key' => 'ai-historychat',
|
||||
'label' => Doo::translate('历史对话'),
|
||||
'config' => []
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property int|null $read 已阅数量
|
||||
* @property int|null $send 发送数量
|
||||
* @property int|null $tag 标注会员ID
|
||||
* @property string|null $session 会话标识符
|
||||
* @property int|null $todo 设为待办会员ID
|
||||
* @property int|null $link 是否存在链接
|
||||
* @property int|null $modify 是否编辑
|
||||
@ -69,6 +70,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereReplyId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereReplyNum($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereSend($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereSession($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereTag($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereTodo($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereType($value)
|
||||
|
||||
61
app/Models/WebSocketDialogSession.php
Normal file
61
app/Models/WebSocketDialogSession.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketDialogSession
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $dialog_id 对话ID
|
||||
* @property int $userid 用户ID
|
||||
* @property string $title 会话标题
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\WebSocketDialog|null $dialog
|
||||
* @property-read \App\Models\User $user
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession whereTitle($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogSession whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class WebSocketDialogSession extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* 可以批量赋值的属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'dialog_id',
|
||||
'userid',
|
||||
'title',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取关联的对话
|
||||
*/
|
||||
public function dialog()
|
||||
{
|
||||
return $this->belongsTo(WebSocketDialog::class, 'dialog_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联的用户
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'userid');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class WebSocketDialogMsgsAddSession extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('web_socket_dialog_msgs', 'session')) {
|
||||
$table->string('session', 36)->nullable()->default('')->after('tag')->comment('会话标识符');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
$table->dropColumn('session');
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateWebSocketDialogSessionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (!Schema::hasTable('web_socket_dialog_sessions')) {
|
||||
Schema::create('web_socket_dialog_sessions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->bigInteger('dialog_id')->unsigned()->index()->comment('对话ID');
|
||||
$table->bigInteger('userid')->unsigned()->index()->comment('用户ID');
|
||||
$table->string('title', 255)->default('')->comment('会话标题');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('web_socket_dialog_sessions');
|
||||
}
|
||||
}
|
||||
@ -255,7 +255,7 @@
|
||||
</div>
|
||||
<div v-else-if="quickShow" class="chat-bottom-menu">
|
||||
<ul class="scrollbar-hidden">
|
||||
<li v-for="item in quickMsgs" @click.stop="sendQuick(item)">
|
||||
<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>
|
||||
</li>
|
||||
</ul>
|
||||
@ -707,6 +707,7 @@ import touchclick from "../../../directives/touchclick";
|
||||
import {languageList} from "../../../language";
|
||||
import {isLocalResourcePath} from "../../../components/Replace/utils";
|
||||
import emitter from "../../../store/events";
|
||||
import {AIModelList} from "../../../store/utils";
|
||||
|
||||
export default {
|
||||
name: "DialogWrapper",
|
||||
@ -1801,8 +1802,9 @@ export default {
|
||||
/**
|
||||
* 发送快捷消息
|
||||
* @param item
|
||||
* @param event
|
||||
*/
|
||||
sendQuick(item) {
|
||||
sendQuick(item, event = undefined) {
|
||||
switch (item.key) {
|
||||
// 位置签到
|
||||
case "locat-checkin":
|
||||
@ -1854,6 +1856,28 @@ export default {
|
||||
});
|
||||
break;
|
||||
|
||||
// 开启新对话
|
||||
case "ai-newchat":
|
||||
if (!this.isAiBot) {
|
||||
return
|
||||
}
|
||||
this.$store.state.menuOperation = {
|
||||
event,
|
||||
list: AIModelList(this.dialogData.email).map(value => ({label: value, value: value})),
|
||||
scrollHide: true,
|
||||
onUpdate: async (model) => {
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// 历史对话
|
||||
case "ai-historychat":
|
||||
if (!this.isAiBot) {
|
||||
return
|
||||
}
|
||||
break;
|
||||
|
||||
// 发送快捷指令
|
||||
default:
|
||||
this.sendMsg(`<p><span data-quick-key="${item.key}">${item.label}</span></p>`)
|
||||
|
||||
@ -65,6 +65,7 @@
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import {AIModelList} from "../../../../store/utils";
|
||||
|
||||
export default {
|
||||
name: "SystemAibot",
|
||||
@ -93,16 +94,7 @@ export default {
|
||||
label: '模型',
|
||||
prop: 'openai_model',
|
||||
type: 'auto-complete',
|
||||
data: [
|
||||
'gpt-4',
|
||||
'gpt-4-turbo',
|
||||
'gpt-4o',
|
||||
'gpt-4o-mini',
|
||||
'gpt-3.5-turbo',
|
||||
'gpt-3.5-turbo-16k',
|
||||
'gpt-3.5-turbo-0125',
|
||||
'gpt-3.5-turbo-1106'
|
||||
],
|
||||
data: AIModelList('openai'),
|
||||
noFilter: true,
|
||||
placeholder: '请输入模型名称',
|
||||
tipPrefix: '查看说明',
|
||||
@ -143,17 +135,7 @@ export default {
|
||||
label: '模型',
|
||||
prop: 'claude_model',
|
||||
type: 'auto-complete',
|
||||
data: [
|
||||
'claude-3-5-sonnet-latest',
|
||||
'claude-3-5-sonnet-20241022',
|
||||
'claude-3-5-haiku-latest',
|
||||
'claude-3-5-haiku-20241022',
|
||||
'claude-3-opus-latest',
|
||||
'claude-3-opus-20240229',
|
||||
'claude-3-haiku-20240307',
|
||||
'claude-2.1',
|
||||
'claude-2.0'
|
||||
],
|
||||
data: AIModelList('claude'),
|
||||
noFilter: true,
|
||||
placeholder: '请输入模型名称',
|
||||
tipPrefix: '查看说明',
|
||||
@ -188,15 +170,19 @@ export default {
|
||||
label: '模型',
|
||||
prop: 'deepseek_model',
|
||||
type: 'auto-complete',
|
||||
data: [
|
||||
'deepseek-chat',
|
||||
'deepseek-reasoner'
|
||||
],
|
||||
data: AIModelList('deepseek'),
|
||||
noFilter: true,
|
||||
placeholder: '请输入模型名称',
|
||||
tipPrefix: '查看说明',
|
||||
link: 'https://api-docs.deepseek.com/zh-cn/quick_start/pricing'
|
||||
},
|
||||
{
|
||||
label: 'Base URL',
|
||||
prop: 'deepseek_base_url',
|
||||
type: 'input',
|
||||
placeholder: 'Enter base URL...',
|
||||
tip: 'API请求的基础URL路径,如果没有请留空'
|
||||
},
|
||||
{
|
||||
label: '使用代理',
|
||||
prop: 'deepseek_agency',
|
||||
@ -225,12 +211,7 @@ export default {
|
||||
label: '模型',
|
||||
prop: 'gemini_model',
|
||||
type: 'auto-complete',
|
||||
data: [
|
||||
'gemini-1.5-flash',
|
||||
'gemini-1.5-flash-8b',
|
||||
'gemini-1.5-pro',
|
||||
'gemini-1.0-pro',
|
||||
],
|
||||
data: AIModelList('gemini'),
|
||||
noFilter: true,
|
||||
placeholder: '请输入模型名称',
|
||||
tipPrefix: '查看说明',
|
||||
@ -264,17 +245,7 @@ export default {
|
||||
label: '模型',
|
||||
prop: 'zhipu_model',
|
||||
type: 'auto-complete',
|
||||
data: [
|
||||
'glm-4',
|
||||
'glm-4-plus',
|
||||
'glm-4-air',
|
||||
'glm-4-airx',
|
||||
'glm-4-long',
|
||||
'glm-4-flash',
|
||||
'glm-4v',
|
||||
'glm-4v-plus',
|
||||
'glm-3-turbo'
|
||||
],
|
||||
data: AIModelList('zhipu'),
|
||||
noFilter: true,
|
||||
placeholder: '请输入模型名称',
|
||||
tipPrefix: '查看说明',
|
||||
@ -308,15 +279,7 @@ export default {
|
||||
label: '模型',
|
||||
prop: 'qianwen_model',
|
||||
type: 'auto-complete',
|
||||
data: [
|
||||
'qwen-turbo',
|
||||
'qwen-turbo-latest',
|
||||
'qwen-plus',
|
||||
'qwen-plus-latest',
|
||||
'qwen-max',
|
||||
'qwen-max-latest',
|
||||
'qwen-long',
|
||||
],
|
||||
data: AIModelList('qianwen'),
|
||||
noFilter: true,
|
||||
placeholder: '请输入模型名称',
|
||||
tipPrefix: '查看说明',
|
||||
@ -357,18 +320,7 @@ export default {
|
||||
label: '模型',
|
||||
prop: 'wenxin_model',
|
||||
type: 'auto-complete',
|
||||
data: [
|
||||
'ernie-4.0-8k',
|
||||
'ernie-4.0-8k-latest',
|
||||
'ernie-4.0-turbo-128k',
|
||||
'ernie-4.0-turbo-8k',
|
||||
'ernie-3.5-128k',
|
||||
'ernie-3.5-8k',
|
||||
'ernie-speed-128k',
|
||||
'ernie-speed-8k',
|
||||
'ernie-lite-8k',
|
||||
'ernie-tiny-8k',
|
||||
],
|
||||
data: AIModelList('wenxin'),
|
||||
noFilter: true,
|
||||
placeholder: '请输入模型名称',
|
||||
tipPrefix: '查看说明',
|
||||
|
||||
88
resources/assets/js/store/utils.js
vendored
88
resources/assets/js/store/utils.js
vendored
@ -162,3 +162,91 @@ export class SSEClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function AIModelList(email) {
|
||||
switch (email) {
|
||||
case "openai":
|
||||
case "ai-openai@bot.system":
|
||||
return [
|
||||
'gpt-4',
|
||||
'gpt-4-turbo',
|
||||
'gpt-4o',
|
||||
'gpt-4o-mini',
|
||||
'gpt-3.5-turbo',
|
||||
'gpt-3.5-turbo-16k',
|
||||
'gpt-3.5-turbo-0125',
|
||||
'gpt-3.5-turbo-1106'
|
||||
]
|
||||
|
||||
case "claude":
|
||||
case "ai-claude@bot.system":
|
||||
return [
|
||||
'claude-3-5-sonnet-latest',
|
||||
'claude-3-5-sonnet-20241022',
|
||||
'claude-3-5-haiku-latest',
|
||||
'claude-3-5-haiku-20241022',
|
||||
'claude-3-opus-latest',
|
||||
'claude-3-opus-20240229',
|
||||
'claude-3-haiku-20240307',
|
||||
'claude-2.1',
|
||||
'claude-2.0'
|
||||
]
|
||||
|
||||
case "deepseek":
|
||||
case "ai-deepseek@bot.system":
|
||||
return [
|
||||
'deepseek-chat',
|
||||
'deepseek-reasoner'
|
||||
]
|
||||
|
||||
case "wenxin":
|
||||
case "ai-wenxin@bot.system":
|
||||
return [
|
||||
'gemini-1.5-flash',
|
||||
'gemini-1.5-flash-8b',
|
||||
'gemini-1.5-pro',
|
||||
'gemini-1.0-pro',
|
||||
]
|
||||
|
||||
case "qianwen":
|
||||
case "ai-qianwen@bot.system":
|
||||
return [
|
||||
'glm-4',
|
||||
'glm-4-plus',
|
||||
'glm-4-air',
|
||||
'glm-4-airx',
|
||||
'glm-4-long',
|
||||
'glm-4-flash',
|
||||
'glm-4v',
|
||||
'glm-4v-plus',
|
||||
'glm-3-turbo'
|
||||
]
|
||||
|
||||
case "gemini":
|
||||
case "ai-gemini@bot.system":
|
||||
return [
|
||||
'qwen-turbo',
|
||||
'qwen-turbo-latest',
|
||||
'qwen-plus',
|
||||
'qwen-plus-latest',
|
||||
'qwen-max',
|
||||
'qwen-max-latest',
|
||||
'qwen-long',
|
||||
]
|
||||
|
||||
case "zhipu":
|
||||
case "ai-zhipu@bot.system":
|
||||
return [
|
||||
'ernie-4.0-8k',
|
||||
'ernie-4.0-8k-latest',
|
||||
'ernie-4.0-turbo-128k',
|
||||
'ernie-4.0-turbo-8k',
|
||||
'ernie-3.5-128k',
|
||||
'ernie-3.5-8k',
|
||||
'ernie-speed-128k',
|
||||
'ernie-speed-8k',
|
||||
'ernie-lite-8k',
|
||||
'ernie-tiny-8k',
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user