|
|
@@ -257,6 +257,50 @@ class DeepSeekService
|
|
|
Utils::throwError('20003:不支持的模型: ' . $model);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ public function createGenerateText($data) {
|
|
|
+ $file = getProp($data, 'file');
|
|
|
+ $uid = Site::getUid();
|
|
|
+ $cpid = Site::getCpid();
|
|
|
+
|
|
|
+ if (!$file) {
|
|
|
+ Utils::throwError('20003:请上传文件');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取文件内容
|
|
|
+ $content = $this->extractFileContent($file);
|
|
|
+ if (!$content) {
|
|
|
+ Utils::throwError('20003:无法提取文件内容,请检查文件格式');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取原始文件名(不含扩展名)作为script_name
|
|
|
+ $originalName = $file->getClientOriginalName();
|
|
|
+ $script_name = pathinfo($originalName, PATHINFO_FILENAME);
|
|
|
+
|
|
|
+ if (!$script_name) {
|
|
|
+ $script_name = '剧本_' . date('YmdHis');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果剧本名称已存在,添加时间戳后缀
|
|
|
+ if (DB::table('mp_scripts')->where('script_name', $script_name)->where('is_deleted', 0)->exists()) {
|
|
|
+ $script_name .= '_' . date('YmdHis');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 插入数据到mp_scripts表
|
|
|
+ $script_id = DB::table('mp_scripts')->insertGetId([
|
|
|
+ 'script_name' => $script_name,
|
|
|
+ 'user_id' => $uid,
|
|
|
+ 'cpid' => $cpid,
|
|
|
+ 'content' => $content,
|
|
|
+ 'created_at' => date('Y-m-d H:i:s'),
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'script_id' => $script_id,
|
|
|
+ 'script_name' => $script_name
|
|
|
+ ];
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 通用文生文方法(非流式版本)- 支持多模型、图片输入、JSON输出和模板提示词
|
|
|
@@ -274,6 +318,36 @@ class DeepSeekService
|
|
|
$imageUrls = getProp($data, 'image_urls', []); // 支持图片URL
|
|
|
$responseFormat = getProp($data, 'response_format', 'text'); // 新增: 响应格式,默认text,可选json
|
|
|
$templateId = getProp($data, 'template_id', 0); // 新增: 模板ID
|
|
|
+ $script_id = getProp($data, 'script_id', 0); // 新增: 剧本ID
|
|
|
+ $sequence = getProp($data, 'sequence', 0); // 新增: 剧集序号
|
|
|
+
|
|
|
+ // 新增: 如果提供了script_id,从数据库获取剧本内容作为原文
|
|
|
+ $originalContent = '';
|
|
|
+ if ($script_id > 0) {
|
|
|
+ $script = DB::table('mp_scripts')
|
|
|
+ ->where('id', $script_id)
|
|
|
+ ->where('is_deleted', 0)
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$script) {
|
|
|
+ Utils::throwError('20003:剧本不存在或已删除');
|
|
|
+ }
|
|
|
+
|
|
|
+ $originalContent = $script->content ?? '';
|
|
|
+
|
|
|
+ if (empty($originalContent)) {
|
|
|
+ Utils::throwError('20003:剧本内容为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将剧本内容添加到提示词前面
|
|
|
+ if (!empty($originalContent)) {
|
|
|
+ if (!empty($prompt)) {
|
|
|
+ $prompt = "原文内容:\n" . $originalContent . "\n\n用户要求:\n" . $prompt;
|
|
|
+ } else {
|
|
|
+ $prompt = "原文内容:\n" . $originalContent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// 新增: 如果提供了template_id,从数据库获取template_prompt
|
|
|
if ($templateId > 0) {
|
|
|
@@ -292,7 +366,7 @@ class DeepSeekService
|
|
|
// 模板为准,用户输入作为补充要求
|
|
|
if (!empty($templatePrompt)) {
|
|
|
if (!empty($prompt)) {
|
|
|
- $prompt = $templatePrompt . "\n\n用户要求:\n" . $prompt;
|
|
|
+ $prompt = $templatePrompt . "\n\n" . $prompt;
|
|
|
} else {
|
|
|
$prompt = $templatePrompt;
|
|
|
}
|
|
|
@@ -461,6 +535,7 @@ class DeepSeekService
|
|
|
}
|
|
|
|
|
|
// 根据模型类型选择调用方法(复用现有的chatOnly方法)
|
|
|
+ $aiResult = null;
|
|
|
if (in_array($model, ['deepseek-reasoner', 'deepseek-chat', 'deepseek-v4-flash', 'deepseek-v4-pro'])) {
|
|
|
// DeepSeek 官方模型使用现有的 chatOnly 方法
|
|
|
$result = $this->chatOnly($post_data);
|
|
|
@@ -468,7 +543,7 @@ class DeepSeekService
|
|
|
// 记录实际使用的模型
|
|
|
dLog('deepseek')->info('newGenerateText使用DeepSeek模型', ['requested_model' => $model, 'actual_model' => $model]);
|
|
|
|
|
|
- return [
|
|
|
+ $aiResult = [
|
|
|
'content' => $result['fullContent'],
|
|
|
'reasoning_content' => $result['fullReasoningContent'],
|
|
|
'usage' => $result['usage'],
|
|
|
@@ -481,7 +556,7 @@ class DeepSeekService
|
|
|
|
|
|
dLog('deepseek')->info('newGenerateText使用GPT-5.4模型', ['requested_model' => $model]);
|
|
|
|
|
|
- return [
|
|
|
+ $aiResult = [
|
|
|
'content' => $result['fullContent'],
|
|
|
'reasoning_content' => '',
|
|
|
'usage' => $result['usage'],
|
|
|
@@ -501,7 +576,7 @@ class DeepSeekService
|
|
|
]);
|
|
|
|
|
|
// 火山引擎返回的数据结构使用 fullContent 和 fullReasoningContent
|
|
|
- return [
|
|
|
+ $aiResult = [
|
|
|
'content' => $result['fullContent'] ?? $result['content'] ?? '',
|
|
|
'reasoning_content' => $result['fullReasoningContent'] ?? $result['reasoning_content'] ?? '',
|
|
|
'usage' => $result['usage'] ?? [],
|
|
|
@@ -511,14 +586,65 @@ class DeepSeekService
|
|
|
} else {
|
|
|
Utils::throwError('20003:不支持的模型: ' . $model);
|
|
|
}
|
|
|
+
|
|
|
+ // 新增: 如果提供了script_id,保存对话记录
|
|
|
+ if ($script_id > 0 && $aiResult) {
|
|
|
+ try {
|
|
|
+ $uid = Site::getUid();
|
|
|
+ $now = now();
|
|
|
+
|
|
|
+ // 获取用户原始的prompt(不包含剧本内容)
|
|
|
+ $originalPrompt = getProp($data, 'prompt', '');
|
|
|
+
|
|
|
+ $records = [
|
|
|
+ [
|
|
|
+ 'uid' => $uid,
|
|
|
+ 'script_id' => $script_id,
|
|
|
+ 'sequence' => $sequence,
|
|
|
+ 'role' => 'user',
|
|
|
+ 'content' => $originalPrompt,
|
|
|
+ 'created_at' => $now,
|
|
|
+ 'updated_at' => $now,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'uid' => $uid,
|
|
|
+ 'script_id' => $script_id,
|
|
|
+ 'sequence' => $sequence,
|
|
|
+ 'role' => 'assistant',
|
|
|
+ 'content' => $aiResult['content'],
|
|
|
+ 'created_at' => $now,
|
|
|
+ 'updated_at' => $now,
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+
|
|
|
+ DB::table('mp_script_records')->insert($records);
|
|
|
+
|
|
|
+ dLog('deepseek')->info('保存剧本对话记录成功', ['script_id' => $script_id, 'sequence' => $sequence]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 记录错误但不影响主流程
|
|
|
+ dLog('deepseek')->error('保存剧本对话记录失败: ' . $e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $aiResult;
|
|
|
}
|
|
|
|
|
|
public function saveScriptChatHistory($data) {
|
|
|
$uid = Site::getUid();
|
|
|
+ $rid = getProp($data, 'rid');
|
|
|
$script_id = getProp($data, 'script_id');
|
|
|
$sequence = getProp($data, 'sequence', 0);
|
|
|
- $messages = getProp($data, 'messages', []);
|
|
|
+ $products = getProp($data, 'products', []);
|
|
|
|
|
|
+ if (!$rid) {
|
|
|
+ Utils::throwError('20003:请选择对话记录ID');
|
|
|
+ }
|
|
|
+
|
|
|
+ $record = DB::table('mp_script_records')->where('id', $rid)->first();
|
|
|
+ if (!$record) {
|
|
|
+ Utils::throwError('20003:对话记录不存在');
|
|
|
+ }
|
|
|
+
|
|
|
if (!$script_id) {
|
|
|
Utils::throwError('20003:请选择剧本');
|
|
|
}
|
|
|
@@ -529,48 +655,24 @@ class DeepSeekService
|
|
|
}
|
|
|
|
|
|
// 解析 messages(可能是 JSON 字符串或数组)
|
|
|
- if (is_string($messages)) {
|
|
|
- $messages = json_decode($messages, true);
|
|
|
+ if (is_string($products)) {
|
|
|
+ $products = json_decode($products, true);
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
|
Utils::throwError('20003:消息格式错误');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!is_array($messages) || empty($messages)) {
|
|
|
+ if (empty($products)) {
|
|
|
Utils::throwError('20003:消息不能为空');
|
|
|
}
|
|
|
|
|
|
- // 提取 role 为 user 和 assistant 的消息并保存
|
|
|
- $records = [];
|
|
|
- $now = now();
|
|
|
-
|
|
|
- foreach ($messages as $message) {
|
|
|
- if (!isset($message['role']) || !isset($message['content'])) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // 只处理 user 和 assistant 角色
|
|
|
- if (!in_array($message['role'], ['user', 'assistant'])) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- $records[] = [
|
|
|
- 'uid' => $uid,
|
|
|
- 'script_id' => $script_id,
|
|
|
- 'sequence' => $sequence,
|
|
|
- 'role' => $message['role'],
|
|
|
- 'content' => is_array($message['content']) ? json_encode($message['content'], JSON_UNESCAPED_UNICODE) : $message['content'],
|
|
|
- 'created_at' => $now,
|
|
|
- 'updated_at' => $now,
|
|
|
- ];
|
|
|
- }
|
|
|
-
|
|
|
- if (empty($records)) {
|
|
|
- Utils::throwError('20003:没有有效的对话记录');
|
|
|
- }
|
|
|
+ $json = json_decode($products, 256);
|
|
|
|
|
|
// 批量插入数据
|
|
|
- return DB::table('mp_script_records')->insert($records);
|
|
|
+ return DB::table('mp_script_records')->where('id', $rid)->update([
|
|
|
+ 'products' => $json,
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -609,16 +711,18 @@ class DeepSeekService
|
|
|
}
|
|
|
|
|
|
// 查询记录并按 id 正序排序
|
|
|
- $records = $query->select('script_id', 'sequence', 'role', 'content', 'created_at')
|
|
|
+ $records = $query->select('id', 'script_id', 'sequence', 'role', 'content', 'products', 'created_at')
|
|
|
->orderBy('created_at', 'asc')
|
|
|
->orderBy('id', 'asc')
|
|
|
->get()
|
|
|
->map(function ($record) {
|
|
|
return [
|
|
|
+ 'rid' => $record->id,
|
|
|
'script_id' => $record->script_id,
|
|
|
'sequence' => $record->sequence,
|
|
|
'role' => $record->role,
|
|
|
'content' => $record->content,
|
|
|
+ 'products' => $record->products ? json_decode($record->products) : [],
|
|
|
'created_at' => $record->created_at,
|
|
|
];
|
|
|
})
|