prompt),同一次请求内避免重复查库 */ private static $stylePromptCache = []; /** * 把画风提示词插入 act_show_content 中每个「画面:[…]」块 * * @param string $content act_show_content 内容 * @param int $animeId 所属动漫ID * @return string 处理后的内容(开关关闭、无画风提示词时原样返回) */ public static function insertArtStylePrompt($content, $animeId) { if (!config('anime.act_show_art_style_enabled', false)) { return $content; } if (!is_string($content) || $content === '' || strpos($content, '画面:') === false) { return $content; } $prompt = self::getArtStylePrompt($animeId); if ($prompt === '') { return $content; } $huamianLen = strlen('画面:'); $insertPositions = []; $skipped = 0; $offset = 0; while (($pos = strpos($content, '画面:', $offset)) !== false) { $searchStart = $pos + $huamianLen; $closePos = strpos($content, ']', $searchStart); if ($closePos === false) { // 该「画面:」块找不到闭合 ],跳过 $skipped++; break; } // 闭合 ] 之前已经出现下一个「画面:」,说明当前块没有闭合 ],跳过当前块 $nextPos = strpos($content, '画面:', $searchStart); if ($nextPos !== false && $nextPos < $closePos) { $skipped++; $offset = $nextPos; continue; } $inner = substr($content, $searchStart, $closePos - $searchStart); // 画面块内没有 [,] 或已经跨到其它字段行,说明不是标准的「画面:[…]」,跳过 if (strpos($inner, '[') === false || preg_match('/(^|\n)\s*(运镜|配音台词|背景音效|出场角色|场景|出场道具|【(?:镜头|分镜))/u', $inner)) { $skipped++; $offset = $closePos + 1; continue; } if (strpos($inner, $prompt) !== false) { // 已包含画风提示词,避免重复插入 $skipped++; } else { $insertPositions[] = [ 'pos' => $closePos, 'needComma' => !preg_match('/[,,、]\s*$/u', $inner), ]; } $offset = $closePos + 1; } if ($insertPositions) { // 从后往前插入,避免前面的插入影响后面的位置 foreach (array_reverse($insertPositions) as $item) { $insertText = ($item['needComma'] ? ',' : '') . $prompt; $content = substr($content, 0, $item['pos']) . $insertText . substr($content, $item['pos']); } dLog('anime')->debug('act_show_content 插入画风提示词', [ 'anime_id' => (int)$animeId, 'inserted' => count($insertPositions), 'skipped' => $skipped, ]); } elseif ($skipped > 0) { dLog('anime')->warning('act_show_content 未找到可插入的「画面:[…]」块', [ 'anime_id' => (int)$animeId, 'skipped' => $skipped, ]); } return $content; } /** * 按动漫ID取画风提示词(mp_animes.art_style_type -> mp_art_styles.prompt) * * @param int $animeId * @return string 取不到时返回空字符串 */ private static function getArtStylePrompt($animeId) { $animeId = (int)$animeId; if ($animeId <= 0) { return ''; } if (!array_key_exists($animeId, self::$stylePromptCache)) { $prompt = ''; $anime = DB::table('mp_animes')->where('id', $animeId)->first(['art_style_type']); $artStyleType = $anime ? trim((string)$anime->art_style_type) : ''; if ($artStyleType !== '') { $styleRow = DB::table('mp_art_styles') ->where('art_style', $artStyleType) ->where('is_deleted', 0) ->first(['prompt']); $prompt = $styleRow ? trim((string)$styleRow->prompt) : ''; } self::$stylePromptCache[$animeId] = $prompt; } return self::$stylePromptCache[$animeId]; } }