|
|
@@ -3733,7 +3733,8 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
* - messages:原样透传(文本 + image_url 图片内容元素均支持);
|
|
|
* - 采样/输出类参数走白名单透传(temperature / top_p / max_tokens / max_completion_tokens /
|
|
|
* frequency_penalty / presence_penalty / stop / response_format / n / seed / user / prompt_cache_key);
|
|
|
- * - temperature:gpt-6.1 系仅支持默认值 1,调用方传入其它值时不下发(改用上游默认值,规避 400);
|
|
|
+ * - 采样参数能力兜底:BO-CHAT 推理模型(gpt-5.6 / gpt-6 / gpt-6.1 等)仅支持默认采样温度 1,
|
|
|
+ * 且不接受 frequency_penalty / presence_penalty;传入非 1 温度或这些参数会返回 400,这里统一剔除;
|
|
|
* - reasoning_effort:按模型取支持档位(gpt-6.1 系为 low / medium / high / xhigh,不支持 none;
|
|
|
* 其余 BO-CHAT 模型为 none / low / medium / high),非法值不下发;
|
|
|
* gpt-6.1 系未显式指定时默认 high(等价默认开启思考,规避该系不支持 none 的报错);
|
|
|
@@ -3823,11 +3824,13 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
$payload['reasoning_effort'] = $effort;
|
|
|
}
|
|
|
|
|
|
- // gpt-6.1 系仅支持默认采样温度(1):调用方传入非 1 的温度时不下发,
|
|
|
- // 交由上游使用默认值,规避 "temperature does not support X" 的 400
|
|
|
- if ($effortNoNone && isset($payload['temperature']) && (float)$payload['temperature'] !== 1.0) {
|
|
|
+ // 采样参数能力兜底:BO-CHAT(gpt-5.6 / gpt-6 / gpt-6.1 等)推理模型仅支持默认采样温度(1),
|
|
|
+ // 且不接受 frequency_penalty / presence_penalty;下发这些参数会返回 400,这里统一剔除,
|
|
|
+ // 交由上游使用默认值(否则会直接报错,或导致异常/不完整输出)。
|
|
|
+ if (isset($payload['temperature']) && (float)$payload['temperature'] !== 1.0) {
|
|
|
unset($payload['temperature']);
|
|
|
}
|
|
|
+ unset($payload['frequency_penalty'], $payload['presence_penalty']);
|
|
|
|
|
|
if ($stream && !isset($payload['stream_options'])) {
|
|
|
$payload['stream_options'] = ['include_usage' => true];
|
|
|
@@ -4016,17 +4019,18 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 正文为空(且不是内容审核拦截):本次调用无有效产出,只记 token 不扣积分,再按配置重试
|
|
|
- if ($fullContent === '' && $finishReason !== 'content_filter') {
|
|
|
+ // 正文为空,或被长度上限截断(finish_reason=length):本次调用产出不可用
|
|
|
+ // (且不是内容审核拦截),只记 token 不扣积分,再按配置重试
|
|
|
+ if (($fullContent === '' || $finishReason === 'length') && $finishReason !== 'content_filter') {
|
|
|
$this->recordAttemptTokens(
|
|
|
$usage,
|
|
|
$charge_context,
|
|
|
$model,
|
|
|
- '百度BO-CHAT第' . ($attempt + 1) . '次调用未返回正文,仅记录token不扣积分'
|
|
|
+ '百度BO-CHAT第' . ($attempt + 1) . '次调用未返回可用正文,仅记录token不扣积分'
|
|
|
);
|
|
|
|
|
|
if ($attempt < $maxRetries) {
|
|
|
- dLog('deepseek')->warning('百度BO-CHAT返回空内容,准备重试', [
|
|
|
+ dLog('deepseek')->warning('百度BO-CHAT返回空/截断内容,准备重试', [
|
|
|
'model' => $model,
|
|
|
'retry' => $attempt + 1,
|
|
|
'max_retries' => $maxRetries,
|
|
|
@@ -4037,7 +4041,7 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- dLog('deepseek')->error('百度BO-CHAT返回空内容,重试次数已用完', [
|
|
|
+ dLog('deepseek')->error('百度BO-CHAT返回空/截断内容,重试次数已用完', [
|
|
|
'model' => $model,
|
|
|
'attempt' => $attempt + 1,
|
|
|
'max_retries' => $maxRetries,
|
|
|
@@ -14761,6 +14765,28 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
$originSegmentCount = count($segments);
|
|
|
$user_prompt .= "- 本集原有{$originSegmentCount}个片段,必须严格生成{$originSegmentCount}个片段(##片段1 到 ##片段{$originSegmentCount}),不得多不得少。\n";
|
|
|
}
|
|
|
+
|
|
|
+ // 整集模式(episode_id>0):在原提示词后追加独立的“本集改动点”模块。
|
|
|
+ // 该模块自身格式独立,不影响上面【分段剧本】的既有格式要求;
|
|
|
+ // 生成后由解析阶段抽出写入 check_points 字段,不参与分段剧本解析。
|
|
|
+ if ($episode_id > 0) {
|
|
|
+ $user_prompt .= "\n\n【本集改动点模块-必须输出】\n";
|
|
|
+ $user_prompt .= "- 在完整输出【分段剧本】(从“###分段剧本”开始,到最后一个“##片段N”结束)之后,必须再输出一个独立模块,严格按下列格式(两条分隔行必须原样输出,不得增删或改写任何字符):\n";
|
|
|
+ $user_prompt .= "#####本集改动点#####\n";
|
|
|
+ $user_prompt .= "1.分段X镜头Y:<标题>\n";
|
|
|
+ $user_prompt .= "· 原描述:<原文或忠实概括>。\n";
|
|
|
+ $user_prompt .= "· 修改为:<新稿原文或忠实概括>。\n";
|
|
|
+ $user_prompt .= "· 改动说明:<实际调整及文本可确认的影响>。\n";
|
|
|
+ $user_prompt .= "#####本集改动点结束#####\n";
|
|
|
+ $user_prompt .= "- 规则:\n";
|
|
|
+ $user_prompt .= " 1.“分段X”对应“##片段X”,镜头沿用实际编号;修改、新增、合并、拆分按新稿定位,删除按原稿定位并标“删除”。编号不同须注明原稿位置;无编号用可核实位置,禁止编造。\n";
|
|
|
+ $user_prompt .= " 2.一项一主题;连续镜头可用Y-Z,非连续位置逐一列明。只列实质改动,不单列标点、空格或不改含义的措辞。\n";
|
|
|
+ $user_prompt .= " 3.保留核验所需关键信息;引号内须为对应原文,概括不加引号、不增信息。不强认原稿有错或猜测创作意图。\n";
|
|
|
+ $user_prompt .= " 4.新增的原描述写“原稿无此内容”;删除的修改为写“已删除”;合并、拆分列明两版对应位置和关系。\n";
|
|
|
+ $user_prompt .= "- 缺原稿时,模块内仅写“无法对比:未提供【原分段剧本】。”;无实质改动时仅写“无实质性改动。”,均保留分隔行。\n";
|
|
|
+ $user_prompt .= "- 输出前核验差异、位置、引用及对应关系,避免重复、遗漏或虚构。仅输出剧本正文与改动点模块,不输出分析、前言或总结。\n";
|
|
|
+ $user_prompt .= "- 除【分段剧本】与该【本集改动点】模块外,不得输出任何其它内容;两者缺一视为输出无效。\n";
|
|
|
+ }
|
|
|
|
|
|
$system_prompt = "\n\n【输出格式铁律-最高优先级】\n";
|
|
|
if ($isActIdMode) {
|
|
|
@@ -14778,6 +14804,9 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
// $system_prompt .= "- 请严格参考【本集原始内容】或【原分段剧本内容】进行本次生成,注意新生成的分段剧本内容一定不要跟【原分段剧本内容】一致,要进行一定程度调整\n";
|
|
|
$system_prompt .= "- 【重要】必须参考【本集原始内容】与【原分段剧本内容】中的剧情脉络、角色、场景、道具和分段结构,但严禁原样复制或几乎照抄原文;必须围绕【用户要求】对相关内容进行实质性修改,若生成结果与【原分段剧本内容】完全一致或未体现用户要求,视为生成失败\n";
|
|
|
$system_prompt .= "- 请仅生成<分段剧本>部分,不要生成其他任何内容:\n";
|
|
|
+ if ($episode_id > 0) {
|
|
|
+ $system_prompt .= "- 【整集模式唯一例外】必须在【分段剧本】之后追加【本集改动点】模块(含固定的起止分隔行“#####本集改动点##### / #####本集改动点结束#####”,格式见用户消息的【本集改动点模块-必须输出】);除该模块外不得输出其它任何内容。\n";
|
|
|
+ }
|
|
|
$system_prompt .= "- 第一优先级:片段时长上限(单个片段不超过15秒,超过必须切为新片段)\n";
|
|
|
$system_prompt .= "- 每个分镜包含:分镜序号、出场角色、场景、出场道具、画面、运镜、配音台词、背景音效\n";
|
|
|
$system_prompt .= "- 场景必须从【场景列表参考】中选择(如果提供了场景列表),场景名必须精确匹配【场景列表参考】中的名称(如需匹配“酒店会客室-景池筹备会版”,而不是“酒店会客室”,不得缺少“-”前后和“:”前面的任何内容,不能自创,不能自创){$scenes_ref}\n";
|
|
|
@@ -14882,6 +14911,22 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
|
|
|
$generated_content = $fullContent;
|
|
|
|
|
|
+ // 整集模式:先抽出【本集改动点】模块写入 check_points,并从生成正文中剥离该模块,
|
|
|
+ // 避免其内容干扰后续分段剧本的解析
|
|
|
+ $check_points = '';
|
|
|
+ if ($episode_id > 0) {
|
|
|
+ if (preg_match('/#####\s*本集改动点\s*#####(.*?)(?:#####\s*本集改动点结束\s*#####|$)/su', $generated_content, $cpMatch)) {
|
|
|
+ $check_points = trim($cpMatch[1]);
|
|
|
+ $generated_content = trim(str_replace($cpMatch[0], '', $generated_content));
|
|
|
+ } else {
|
|
|
+ dLog('deepseek')->warning('regenerateSegmentScript 未找到【本集改动点】模块', [
|
|
|
+ 'episode_id' => $episode_id,
|
|
|
+ 'content_length' => mb_strlen($generated_content),
|
|
|
+ 'content_tail' => mb_substr($generated_content, -300),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 归一化"场景:"标签换行格式:场景:\n场景名\n => 场景:场景名\n,保证场景字段为一行
|
|
|
$generated_content = preg_replace('/场景[::]\s*\n\s*([^\n]+)/u', '场景:$1', $generated_content);
|
|
|
|
|
|
@@ -15252,6 +15297,7 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
'title' => getProp($episode, 'title', ''),
|
|
|
'episode_number' => $target_episode_number,
|
|
|
'is_generated' => getProp($episode, 'is_generated', 0),
|
|
|
+ 'check_points' => $check_points,
|
|
|
'acts' => $previewActs,
|
|
|
];
|
|
|
}
|
|
|
@@ -15331,7 +15377,7 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
}
|
|
|
|
|
|
// 构造返回数据结构(参考AnimeService返回格式,但不包含products)
|
|
|
- return [
|
|
|
+ $result = [
|
|
|
'anime_id' => $target_anime_id,
|
|
|
'episode_id' => $target_episode_id,
|
|
|
'title' => getProp($episode, 'title', ''),
|
|
|
@@ -15339,6 +15385,11 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
'is_generated' => getProp($episode, 'is_generated', 0),
|
|
|
'acts' => $saved_acts,
|
|
|
];
|
|
|
+ // 整集模式(episode_id>0):附带本集改动点 (从生成结果中抽出的独立模块)
|
|
|
+ if ($episode_id > 0) {
|
|
|
+ $result['check_points'] = $check_points;
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
dLog('deepseek')->error('重新生成分段剧本失败: ' . $e->getMessage());
|