|
|
@@ -118,7 +118,7 @@ class AnimeService
|
|
|
if (!$anime_id) Utils::throwError('20003:请选择对话!');
|
|
|
|
|
|
$query = DB::table('mp_anime_records as ar')->leftJoin('mp_anime_episodes as ae', 'ar.episode_id', '=', 'ae.id')->where('ar.anime_id', $anime_id)
|
|
|
- ->where('ar.sequence', $sequence)->select('ar.role', 'ar.content', 'ar.created_at', 'ar.episode_id', 'ae.title as episode_title', 'ae.created_at as episode_created_at');
|
|
|
+ ->where('ar.sequence', $sequence)->where('segment_id', 0)->select('ar.role', 'ar.content', 'ar.created_at', 'ar.episode_id', 'ae.title as episode_title', 'ae.created_at as episode_created_at');
|
|
|
|
|
|
return $query->orderBy('ar.id')->get()->map(function ($value) {
|
|
|
$value = (array)$value;
|
|
|
@@ -741,6 +741,7 @@ class AnimeService
|
|
|
|
|
|
public function chatChangeImg($data) {
|
|
|
$segment_id = getProp($data, 'segment_id');
|
|
|
+ $type = getProp($data, 'type', 1); // 类型: 1.对话改图 2.图片生成
|
|
|
$prompt = getProp($data, 'prompt');
|
|
|
if (!$prompt || !$segment_id) {
|
|
|
Utils::throwError('1002:请输入提示词,并且选择分镜');
|
|
|
@@ -786,7 +787,7 @@ class AnimeService
|
|
|
|
|
|
try {
|
|
|
$params = [
|
|
|
- 'alias_segment_id' => $segment_id,
|
|
|
+ 'alias_segment_id' => $type == 2 ? $segment_id : 0,
|
|
|
'prompt' => $prompt,
|
|
|
'ref_img_urls' => !empty($ref_img_url) ? [$ref_img_url] : [],
|
|
|
'width' => $width,
|
|
|
@@ -812,9 +813,79 @@ class AnimeService
|
|
|
$img_url = $this->loopGetPicTaskResult($task_id);
|
|
|
|
|
|
if (!$img_url) Utils::throwError('20003:图片生成中,请稍后刷新');
|
|
|
+
|
|
|
+ // 图片生成后新增对话记录
|
|
|
+ try {
|
|
|
+ $uid = Site::getUid();
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+
|
|
|
+ // 获取segment的anime_id和episode_number
|
|
|
+ $segmentInfo = DB::table('mp_episode_segments as es')
|
|
|
+ ->join('mp_anime_episodes as ae', 'es.episode_id', '=', 'ae.id')
|
|
|
+ ->where('es.segment_id', $segment_id)
|
|
|
+ ->select('ae.anime_id', 'ae.episode_number')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if ($segmentInfo) {
|
|
|
+ $anime_id = getProp($segmentInfo, 'anime_id');
|
|
|
+ $episode_number = getProp($segmentInfo, 'episode_number');
|
|
|
+
|
|
|
+ // 使用AI反推图片提示词
|
|
|
+ $pic_prompt = $this->generateImagePromptFromUrl($img_url);
|
|
|
+
|
|
|
+ // 保存对话记录
|
|
|
+ $records = [
|
|
|
+ [
|
|
|
+ 'uid' => $uid,
|
|
|
+ 'anime_id' => $anime_id,
|
|
|
+ 'sequence' => $episode_number,
|
|
|
+ 'role' => 'user',
|
|
|
+ 'content' => $prompt,
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'img_url' => '',
|
|
|
+ 'created_at' => $now,
|
|
|
+ 'updated_at' => $now
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'uid' => $uid,
|
|
|
+ 'anime_id' => $anime_id,
|
|
|
+ 'sequence' => $episode_number,
|
|
|
+ 'role' => 'assistant',
|
|
|
+ 'content' => $pic_prompt,
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'img_url' => $img_url,
|
|
|
+ 'created_at' => $now,
|
|
|
+ 'updated_at' => $now
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+
|
|
|
+ DB::table('mp_anime_records')->insert($records);
|
|
|
+ }
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 记录日志但不影响主流程
|
|
|
+ dLog('anime')->error('保存对话记录失败: ' . $e->getMessage(), [
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'img_url' => $img_url
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
return $img_url;
|
|
|
}
|
|
|
|
|
|
+ public function segmentChatHistory($data) {
|
|
|
+ $segment_id = getProp($data, 'segment_id');
|
|
|
+
|
|
|
+ if (!$segment_id) Utils::throwError('20003:请选择分镜!');
|
|
|
+
|
|
|
+ $query = DB::table('mp_anime_records')->where('segment_id', $segment_id)->select('role', 'content', 'segment_id', 'image_url', 'video_url', 'created_at');
|
|
|
+
|
|
|
+ return $query->orderBy('ar.id')->get()->map(function ($value) {
|
|
|
+ $value = (array)$value;
|
|
|
+ $value['created_at'] = transDate($value['created_at']);
|
|
|
+ return $value;
|
|
|
+ })->toArray();
|
|
|
+ }
|
|
|
+
|
|
|
public function changeEpisodeRoles($data) {
|
|
|
$anime_id = getProp($data, 'anime_id');
|
|
|
$episode_id = getProp($data, 'episode_id');
|
|
|
@@ -2323,23 +2394,26 @@ class AnimeService
|
|
|
$model = getProp($task, 'model');
|
|
|
$isVolcModel = in_array($model, \App\Consts\BaseConst::VOLC_PIC_MODELS);
|
|
|
|
|
|
- // 火山API是同步返回结果的,直接检查任务状态
|
|
|
- if ($isVolcModel) {
|
|
|
- // 火山API任务,直接返回结果(已在创建时处理完成)
|
|
|
- if ($task->status === 'success' && $task->result_url) {
|
|
|
- $result_urls = is_array($task->result_url) ? $task->result_url : json_decode($task->result_url, true);
|
|
|
- return is_array($result_urls) ? $result_urls[0] : $task->result_url;
|
|
|
- }
|
|
|
- return '';
|
|
|
- }
|
|
|
-
|
|
|
- // 即梦AI需要轮询查询状态
|
|
|
+ // 轮询查询任务状态(火山API和即梦AI都需要轮询)
|
|
|
$start_count = 0;
|
|
|
$img_url = '';
|
|
|
while ($start_count <= 20) { // 循环20次请求,每3s一次
|
|
|
sleep(3);
|
|
|
|
|
|
$task = MpGeneratePicTask::where('id', $task_id)->first();
|
|
|
+
|
|
|
+ // 如果任务已经完成,直接返回结果
|
|
|
+ if ($task->status === 'success' && $task->result_url) {
|
|
|
+ $result_urls = is_array($task->result_url) ? $task->result_url : json_decode($task->result_url, true);
|
|
|
+ return is_array($result_urls) ? $result_urls[0] : $task->result_url;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果任务已失败,返回空
|
|
|
+ if ($task->status === 'failed') {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询任务状态
|
|
|
$statusInfo = $this->aiImageGenerationService->queryTaskStatus($task);
|
|
|
|
|
|
if ($statusInfo['status'] === 'success') {
|
|
|
@@ -3141,4 +3215,38 @@ class AnimeService
|
|
|
return $segment_content;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据图片URL使用AI反推图片提示词
|
|
|
+ *
|
|
|
+ * @param string $img_url 图片URL
|
|
|
+ * @return string 反推的提示词
|
|
|
+ */
|
|
|
+ private function generateImagePromptFromUrl($img_url) {
|
|
|
+ try {
|
|
|
+ // 获取默认模型
|
|
|
+ $model = 'doubao-seed-2-0-mini-260215';
|
|
|
+
|
|
|
+ // 构建请求参数
|
|
|
+ $params = [
|
|
|
+ 'model' => $model,
|
|
|
+ 'prompt' => '请详细描述这张图片的内容,包括场景、人物、构图、色彩等元素,用于生成图片的提示词。',
|
|
|
+ 'image_urls' => [$img_url],
|
|
|
+ 'stream' => false,
|
|
|
+ 'thinking' => ['type' => 'disabled'] // 不使用思考模式
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 调用DeepSeek服务的volcEngineChatCompletion方法(非流式)
|
|
|
+ $result = $this->DeepSeekService->volcEngineChatCompletion($params);
|
|
|
+
|
|
|
+ // 返回生成的内容
|
|
|
+ return getProp($result, 'fullContent', '图片描述生成失败');
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ dLog('anime')->error('AI反推图片提示词失败: ' . $e->getMessage(), [
|
|
|
+ 'img_url' => $img_url
|
|
|
+ ]);
|
|
|
+ return '图片描述生成失败: ' . $e->getMessage();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|