feat: 添加额外数据处理,优化AI助手消息生成与发送逻辑

This commit is contained in:
kuaifan 2025-11-07 20:38:06 +00:00
parent e801c09c0f
commit 892ad395a7
8 changed files with 228 additions and 157 deletions

View File

@ -1027,25 +1027,25 @@ class DialogController extends AbstractController
} }
/** /**
* @api {post} api/dialog/msg/ai_generate 使用 AI 助手生成消息 * @api {post} api/dialog/msg/aiprompt AI 提示词助手
* *
* @apiDescription 需要token身份根据上下文自动生成拟发送的聊天消 * @apiDescription 需要token身份整理当前会话的系统提示词与上下文信
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup dialog * @apiGroup dialog
* @apiName msg__ai_generate * @apiName msg__aiprompt
* *
* @apiParam {Number} dialog_id 对话ID * @apiParam {Number} dialog_id 对话ID
* @apiParam {String} content 消息需求描述 * @apiParam {String} content 消息需求描述(用于提示词整理,可为空)
* @apiParam {String} [draft] 当前草稿内容HTML 格式) * @apiParam {String} [draft] 当前草稿内容HTML 格式)
* @apiParam {Number} [quote_id] 引用消息ID * @apiParam {Number} [quote_id] 引用消息ID
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据 * @apiSuccess {Object} data 返回数据
* @apiSuccess {String} data.text AI 生成的消息文本Markdown 格式) * @apiSuccess {String} data.system_prompt AI 使用的系统提示词
* @apiSuccess {String} data.html AI 生成的消息内容HTML 格式) * @apiSuccess {String} data.context_prompt AI 使用的上下文提示词
*/ */
public function msg__ai_generate() public function msg__aiprompt()
{ {
$user = User::auth(); $user = User::auth();
$user->checkChatInformation(); $user->checkChatInformation();
@ -1055,9 +1055,6 @@ class DialogController extends AbstractController
if ($dialog_id <= 0) { if ($dialog_id <= 0) {
return Base::retError('参数错误'); return Base::retError('参数错误');
} }
if ($content === '') {
return Base::retError('消息需求描述不能为空');
}
$dialog = WebSocketDialog::checkDialog($dialog_id); $dialog = WebSocketDialog::checkDialog($dialog_id);
@ -1144,12 +1141,16 @@ class DialogController extends AbstractController
} }
// 生成消息 // 生成消息
$result = AI::generateMessage($content, $context); $systemPrompt = AI::messageSystemPrompt();
if (Base::isError($result)) { $contextPrompt = AI::buildMessageContextPrompt($context);
return Base::retError('生成消息失败', $result); if ($content) {
$contextPrompt .= "\n\n请根据以上信息,结合提示词生成一条待发送的消息:\n\n";
} }
return Base::retSuccess('生成消息成功', $result['data']); return Base::retSuccess('success', [
'system_prompt' => $systemPrompt,
'context_prompt' => $contextPrompt,
]);
} }
/** /**
@ -1179,6 +1180,7 @@ class DialogController extends AbstractController
* - no: 正常发送(默认) * - no: 正常发送(默认)
* - yes: 静默发送 * - yes: 静默发送
* @apiParam {String} [model_name] 模型名称仅AI机器人支持 * @apiParam {String} [model_name] 模型名称仅AI机器人支持
* @apiParam {Object} [extra_data] 附加数据(保存到附加表)
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -1200,6 +1202,7 @@ class DialogController extends AbstractController
$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')); $model_name = trim(Request::input('model_name'));
$extra_data = Request::input('extra_data');
$markdown = in_array($text_type, ['md', 'markdown']); $markdown = in_array($text_type, ['md', 'markdown']);
// //
$result = []; $result = [];
@ -1233,14 +1236,14 @@ class DialogController extends AbstractController
$text = WebSocketDialogMsg::formatMsg($text, $dialog_id); $text = WebSocketDialogMsg::formatMsg($text, $dialog_id);
} }
$strlen = mb_strlen($text); $strlen = mb_strlen($text);
$noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text)); $reallen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
if ($strlen < 1) { if ($strlen < 1) {
return Base::retError('消息内容不能为空'); return Base::retError('消息内容不能为空');
} }
if ($noimglen > 200000) { if ($reallen > 200000) {
return Base::retError('消息内容最大不能超过200000字'); return Base::retError('消息内容最大不能超过200000字');
} }
if ($noimglen > 5000) { if ($reallen > 5000) {
// 内容过长转成文件发送 // 内容过长转成文件发送
$path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/"; $path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/";
Base::makeDir(public_path($path)); Base::makeDir(public_path($path));
@ -1282,7 +1285,7 @@ class DialogController extends AbstractController
if ($model_name) { if ($model_name) {
$msgData['model_name'] = $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, $extra_data);
} else { } else {
$msgData = ['text' => $text]; $msgData = ['text' => $text];
if ($markdown) { if ($markdown) {
@ -1291,7 +1294,7 @@ class DialogController extends AbstractController
if ($model_name) { if ($model_name) {
$msgData['model_name'] = $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, $extra_data);
} }
} }
return $result; return $result;
@ -3134,11 +3137,11 @@ class DialogController extends AbstractController
// //
WebSocketDialog::checkDialog($dialog_id); WebSocketDialog::checkDialog($dialog_id);
$strlen = mb_strlen($text); $strlen = mb_strlen($text);
$noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text)); $reallen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
if ($strlen < 1 || empty($list)) { if ($strlen < 1 || empty($list)) {
return Base::retError('内容不能为空'); return Base::retError('内容不能为空');
} }
if ($noimglen > 200000) { if ($reallen > 200000) {
return Base::retError('内容最大不能超过200000字'); return Base::retError('内容最大不能超过200000字');
} }
// //
@ -3283,11 +3286,11 @@ class DialogController extends AbstractController
}); });
} else { } else {
$strlen = mb_strlen($text); $strlen = mb_strlen($text);
$noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text)); $reallen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
if ($strlen < 1) { if ($strlen < 1) {
return Base::retError('内容不能为空'); return Base::retError('内容不能为空');
} }
if ($noimglen > 200000) { if ($reallen > 200000) {
return Base::retError('内容最大不能超过200000字'); return Base::retError('内容最大不能超过200000字');
} }
$msgData = [ $msgData = [

View File

@ -43,6 +43,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property \Illuminate\Support\Carbon|null $deleted_at * @property \Illuminate\Support\Carbon|null $deleted_at
* @property-read int|mixed $percentage * @property-read int|mixed $percentage
* @property-read \App\Models\User|null $user * @property-read \App\Models\User|null $user
* @property-read \App\Models\WebSocketDialogMsgExtra|null $extra
* @property-read \App\Models\WebSocketDialog|null $webSocketDialog * @property-read \App\Models\WebSocketDialog|null $webSocketDialog
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend() * @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden() * @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
@ -111,6 +112,14 @@ class WebSocketDialogMsg extends AbstractModel
return $this->hasOne(User::class, 'userid', 'userid'); return $this->hasOne(User::class, 'userid', 'userid');
} }
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function extra(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(WebSocketDialogMsgExtra::class, 'msg_id', 'id');
}
/** /**
* 阅读占比 * 阅读占比
* @return int|mixed * @return int|mixed
@ -1233,9 +1242,10 @@ class WebSocketDialogMsg extends AbstractModel
* @param bool|null $push_silence 推送-静默 * @param bool|null $push_silence 推送-静默
* - type = [text|file|record|meeting] 默认为false * - type = [text|file|record|meeting] 默认为false
* @param string|null $search_key 搜索关键词(用于搜索,留空则自动生成) * @param string|null $search_key 搜索关键词(用于搜索,留空则自动生成)
* @param array|null $extra_data 额外数据(仅在发送消息时有效)
* @return array * @return array
*/ */
public static function sendMsg($action, $dialog_id, $type, $msg, $sender = null, $push_self = false, $push_retry = false, $push_silence = null, $search_key = null) public static function sendMsg($action, $dialog_id, $type, $msg, $sender = null, $push_self = false, $push_retry = false, $push_silence = null, $search_key = null, $extra_data = null)
{ {
$link = 0; $link = 0;
$mtype = $type; $mtype = $type;
@ -1380,10 +1390,17 @@ class WebSocketDialogMsg extends AbstractModel
'msg' => $msg, 'msg' => $msg,
'read' => 0, 'read' => 0,
]); ]);
AbstractModel::transaction(function () use ($search_key, $dialogMsg) { AbstractModel::transaction(function () use ($search_key, $dialogMsg, $extra_data) {
$dialogMsg->send = 1; $dialogMsg->send = 1;
$dialogMsg->generateKeyAndSave($search_key); $dialogMsg->generateKeyAndSave($search_key);
// //
if ($extra_data) {
WebSocketDialogMsgExtra::createInstance([
'msg_id' => $dialogMsg->id,
'data' => Base::array2json($extra_data),
])->save();
}
//
WebSocketDialogSession::updateTitle($dialogMsg->session_id, $dialogMsg); WebSocketDialogSession::updateTitle($dialogMsg->session_id, $dialogMsg);
// //
if ($dialogMsg->type === 'meeting') { if ($dialogMsg->type === 'meeting') {

View File

@ -0,0 +1,56 @@
<?php
namespace App\Models;
use App\Module\Base;
/**
* App\Models\WebSocketDialogMsgExtra
*
* @property int $id
* @property int|null $msg_id 消息ID
* @property string|null $data 长内容
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\WebSocketDialogMsg|null $webSocketDialogMsg
* @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|WebSocketDialogMsgExtra newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgExtra newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgExtra query()
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgExtra whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgExtra whereData($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgExtra whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgExtra whereMsgId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgExtra whereUpdatedAt($value)
* @mixin \Eloquent
*/
class WebSocketDialogMsgExtra extends AbstractModel
{
/**
* @param $value
* @return array
*/
public function getDataAttribute($value)
{
if (is_array($value)) {
return $value;
}
return Base::json2array($value);
}
/**
* 关联到消息
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function webSocketDialogMsg(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(WebSocketDialogMsg::class, 'msg_id', 'id');
}
}

View File

@ -556,72 +556,6 @@ class AI
]); ]);
} }
/**
* 通过 openAI 生成聊天消息
* @param string $text 用户提供的提示词
* @param array $context 上下文信息
* @return array
*/
public static function generateMessage($text, $context = [])
{
$text = trim((string)$text);
if ($text === '') {
return Base::retError("消息提示词不能为空");
}
$contextPrompt = self::buildMessageContextPrompt($context);
$post = json_encode([
"model" => "gpt-5-mini",
"reasoning_effort" => "minimal",
"messages" => [
[
"role" => "system",
"content" => <<<EOF
你是一名专业的沟通助手,协助用户编写得体、清晰且具行动指向的即时消息。
写作要求:
1. 根据用户提供的需求与上下文生成完整消息,语气需符合业务沟通场景,保持真诚、礼貌且高效
2. 默认使用简洁的短段落,可使用 Markdown 基础格式(加粗、列表、引用)增强结构,但不要输出代码块或 JSON
3. 如果上下文包含引用信息或草稿,请在消息中自然呼应相关要点
4. 如无特别说明,将消息长度控制在 60-180 字;若需更短或更长,遵循用户描述
5. 如需提出行动或问题,请明确表达,避免含糊
输出规范:
- 仅返回可直接发送的消息内容
- 禁止在内容前后添加额外说明、标签或引导语
EOF
],
[
"role" => "user",
"content" => ($contextPrompt ? $contextPrompt . "\n\n" : "") . "请根据以上信息,并结合以下提示词生成一条待发送的消息:\n\n" . $text
],
],
]);
$ai = new self($post);
$ai->setTimeout(45);
$res = $ai->request();
if (Base::isError($res)) {
return Base::retError("消息生成失败", $res);
}
$content = trim($res['data']);
$content = preg_replace('/^\s*```(?:markdown|md|text)?\s*/i', '', $content);
$content = preg_replace('/\s*```\s*$/', '', $content);
$content = trim($content);
if ($content === '') {
return Base::retError("消息生成结果为空");
}
return Base::retSuccess("success", [
'text' => $content,
'html' => Base::markdown2html($content),
]);
}
/** /**
* 对工作汇报内容进行分析 * 对工作汇报内容进行分析
* @param Report $report * @param Report $report
@ -836,7 +770,25 @@ class AI
return empty($prompts) ? "" : implode("\n", $prompts); return empty($prompts) ? "" : implode("\n", $prompts);
} }
private static function buildMessageContextPrompt($context) public static function messageSystemPrompt()
{
return <<<EOF
你是一名专业的沟通助手,协助用户编写得体、清晰且具行动指向的即时消息。
写作要求:
1. 根据用户提供的需求与上下文生成完整消息,语气需符合业务沟通场景,保持真诚、礼貌且高效
2. 默认使用简洁的短段落,可使用 Markdown 基础格式(加粗、列表、引用)增强结构,但不要输出代码块或 JSON
3. 如果上下文包含引用信息或草稿,请在消息中自然呼应相关要点
4. 如无特别说明,将消息长度控制在 60-180 字;若需更短或更长,遵循用户描述
5. 如需提出行动或问题,请明确表达,避免含糊
输出规范:
- 仅返回可直接发送的消息内容
- 禁止在内容前后添加额外说明、标签或引导语
EOF;
}
public static function buildMessageContextPrompt($context)
{ {
$prompts = []; $prompts = [];

View File

@ -66,7 +66,7 @@ class BotReceiveMsgTask extends AbstractTask
} }
// 判断消息是否存在 // 判断消息是否存在
$msg = WebSocketDialogMsg::with(['user'])->find($this->msgId); $msg = WebSocketDialogMsg::with(['user', 'extra'])->find($this->msgId);
if (empty($msg)) { if (empty($msg)) {
return; return;
} }
@ -523,6 +523,16 @@ class BotReceiveMsgTask extends AbstractTask
{$sendText} {$sendText}
EOF; EOF;
} }
// 处理额外数据
if ($msg->extra && $msg->extra->data) {
$extraData = $msg->extra->data;
if ($extraData['system_prompt']) {
$extras['system_message'] = $extraData['system_prompt'];
}
if ($extraData['context_prompt']) {
$sendText = $extraData['context_prompt'] . $sendText;
}
}
$webhookUrl = "http://nginx/ai/chat"; $webhookUrl = "http://nginx/ai/chat";
} else { } else {
// 用户机器人 // 用户机器人

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateWebSocketDialogMsgExtrasTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('web_socket_dialog_msg_extras', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('msg_id')->nullable()->default(0)->comment('消息ID');
$table->longText('data')->nullable()->comment('额外数据');
$table->timestamps();
$table->foreign('msg_id')->references('id')->on('web_socket_dialog_msgs')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('web_socket_dialog_msg_extras');
}
}

View File

@ -133,6 +133,7 @@ export default {
inputAutosize: this.defaultInputAutosize, inputAutosize: this.defaultInputAutosize,
inputMaxlength: this.defaultInputMaxlength, inputMaxlength: this.defaultInputMaxlength,
inputOnOk: null, inputOnOk: null,
inputOnBeforeSend: null,
// //
inputModel: '', inputModel: '',
@ -186,6 +187,7 @@ export default {
this.inputAutosize = params.autosize || this.defaultInputAutosize; this.inputAutosize = params.autosize || this.defaultInputAutosize;
this.inputMaxlength = params.maxlength || this.defaultInputMaxlength; this.inputMaxlength = params.maxlength || this.defaultInputMaxlength;
this.inputOnOk = params.onOk || null; this.inputOnOk = params.onOk || null;
this.inputOnBeforeSend = params.onBeforeSend || null;
} }
this.responses = []; this.responses = [];
this.pendingResponses = []; this.pendingResponses = [];
@ -368,7 +370,7 @@ export default {
prompt: rawValue, prompt: rawValue,
}); });
this.scrollResponsesToBottom(); this.scrollResponsesToBottom();
const message = await this.sendAiMessage(dialogId, this.formatPlainText(rawValue), modelOption.value); const message = await this.sendAiMessage(dialogId, rawValue, modelOption.value);
if (responseEntry) { if (responseEntry) {
responseEntry.userid = userid; responseEntry.userid = userid;
responseEntry.message = message; responseEntry.message = message;
@ -476,11 +478,11 @@ export default {
const {data} = await this.$store.dispatch("call", { const {data} = await this.$store.dispatch("call", {
url: 'dialog/msg/sendtext', url: 'dialog/msg/sendtext',
method: 'post', method: 'post',
data: { data: await this.buildPayloadData({
dialog_id: dialogId, dialog_id: dialogId,
text, text,
model_name: model, model_name: model,
}, }),
}); });
if (data) { if (data) {
this.$store.dispatch("saveDialogMsg", data); this.$store.dispatch("saveDialogMsg", data);
@ -494,15 +496,26 @@ export default {
}, },
/** /**
* 将纯文本转换成HTML * 构建最终发送的数据
*/ */
formatPlainText(text) { async buildPayloadData(data) {
const escaped = `${text}` if (typeof this.inputOnBeforeSend !== 'function') {
.replace(/&/g, '&amp;') return data;
.replace(/</g, '&lt;') }
.replace(/>/g, '&gt;') try {
.replace(/\n/g, '<br/>'); const result = this.inputOnBeforeSend(data);
return `<p>${escaped}</p>`; if (result && typeof result.then === 'function') {
const resolved = await result;
if ($A.isJson(resolved)) {
return resolved;
}
} else if ($A.isJson(result)) {
return result;
}
} catch (e) {
console.warn('[AIAssistant] onBeforeSend error:', e);
}
return data;
}, },
/** /**
@ -681,16 +694,19 @@ export default {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
max-height: calc(100vh - 344px);
@media (height <= 900px) {
max-height: calc(100vh - 214px);
}
.ai-assistant-output { .ai-assistant-output {
flex: 1;
min-height: 0;
padding: 12px; padding: 12px;
border-radius: 8px; border-radius: 8px;
background: #f8f9fb; background: #f8f9fb;
border: 1px solid rgba(0, 0, 0, 0.04); border: 1px solid rgba(0, 0, 0, 0.04);
max-height: calc(100vh - 390px);
overflow-y: auto; overflow-y: auto;
@media (height <= 900px) {
max-height: calc(100vh - 260px);
}
} }
.ai-assistant-output-item + .ai-assistant-output-item { .ai-assistant-output-item + .ai-assistant-output-item {

View File

@ -342,7 +342,7 @@ import clickoutside from "../../../../directives/clickoutside";
import longpress from "../../../../directives/longpress"; import longpress from "../../../../directives/longpress";
import {inputLoadAdd, inputLoadIsLast, inputLoadRemove} from "./one"; import {inputLoadAdd, inputLoadIsLast, inputLoadRemove} from "./one";
import {languageList, languageName} from "../../../../language"; import {languageList, languageName} from "../../../../language";
import {isMarkdownFormat} from "../../../../utils/markdown"; import {isMarkdownFormat, MarkdownConver} from "../../../../utils/markdown";
import emitter from "../../../../store/events"; import emitter from "../../../../store/events";
import historyMixin from "./history"; import historyMixin from "./history";
@ -1904,63 +1904,45 @@ export default {
return; return;
} }
if (!this.dialogId) { if (!this.dialogId) {
$A.messageWarning(this.$L('当前未选择会话')); $A.messageWarning('当前未选择会话');
return; return;
} }
let canceled = false; emitter.emit('openAIAssistant', {
$A.modalInput({ placeholder: this.$L('请简要描述消息的主题、语气或要点AI 将生成完整消息'),
title: 'AI 生成', onBeforeSend: async (sendData) => {
placeholder: '请简要描述消息的主题、语气或要点AI 将生成完整消息', if (!sendData) {
inputProps: { return sendData;
type: 'textarea',
rows: 2,
autosize: {minRows: 2, maxRows: 6},
maxlength: 500,
},
onCancel: () => {
canceled = true;
},
onOk: (value) => {
if (!value) {
return '请输入消息需求';
} }
return new Promise((resolve, reject) => { try {
if (canceled) { const {data: extraData} = await this.$store.dispatch('call', {
reject(); url: 'dialog/msg/aiprompt',
return;
}
this.$store.dispatch('call', {
url: 'dialog/msg/ai_generate',
data: { data: {
dialog_id: this.dialogId, dialog_id: this.dialogId,
content: value, content: sendData.text,
draft: this.value || '', draft: this.value || '',
quote_id: this.quoteData?.id || 0, quote_id: this.quoteData?.id || 0,
}, },
timeout: 45 * 1000,
}).then(({data}) => {
const html = data && (data.html || data.text) ? (data.html || data.text) : '';
if (canceled) {
resolve();
return;
}
if (!html) {
reject(this.$L('AI 未生成内容'));
return;
}
this.$emit('input', html);
this.$nextTick(() => this.focus());
resolve();
}).catch(({msg}) => {
if (canceled) {
resolve();
return;
}
reject(msg);
}); });
}); if ($A.isJson(extraData)) {
} sendData.extra_data = extraData;
}) }
return sendData;
} catch (error) {
const msg = error?.msg || 'AI 提示生成失败';
$A.modalError(msg);
throw error;
}
},
onOk: ({aiContent}) => {
if (!aiContent) {
$A.messageWarning('AI 未生成内容');
return;
}
const html = MarkdownConver(aiContent);
this.$emit('input', html);
this.$nextTick(() => this.focus());
},
});
}, },
onFullInput() { onFullInput() {