restore gpt seo copy pipeline and stabilize seo tkd output
This commit is contained in:
@@ -26,8 +26,10 @@ class SeoCopyFallbackBuilder
|
||||
{
|
||||
$strSiteName = self::siteName($arrFacts);
|
||||
$strScopes = self::joinItems((array)($arrFacts['content_scopes'] ?? []), 3, '影视内容');
|
||||
$strLanding = $strSiteName . '首页当前覆盖' . $strScopes . '等常见内容入口,适合先看首屏推荐,再按分类、榜单或搜索继续缩小范围。';
|
||||
|
||||
return [
|
||||
'search_landing' => $strLanding,
|
||||
'intro_text' => $strSiteName . '首页当前覆盖' . $strScopes . '等常见内容入口,建议先看首屏内容卡片,再继续按分类、榜单或搜索缩小范围。',
|
||||
'intro_meta' => '首页更适合先发现值得点开的内容,说明性提示只做辅助,不建议压住首屏主体内容。',
|
||||
'guide_cards' => [
|
||||
@@ -94,8 +96,10 @@ class SeoCopyFallbackBuilder
|
||||
private static function buildRankIndex(array $arrFacts): array
|
||||
{
|
||||
$strPeriods = self::joinItems((array)($arrFacts['rank_periods'] ?? []), 3, '常见榜单周期');
|
||||
$strLanding = '当前榜单首页汇总了' . $strPeriods . '等常见周期入口,适合先确定周期,再继续进入具体榜单列表页。';
|
||||
|
||||
return [
|
||||
'search_landing' => $strLanding,
|
||||
'intro_text' => '当前榜单首页汇总了' . $strPeriods . '等常见周期入口,适合先确定要看的榜单范围再继续下钻。',
|
||||
'intro_meta' => '如果你更关心具体周期,可以直接进入对应榜单列表页,再继续看详情和播放路径。',
|
||||
'guide_cards' => [
|
||||
@@ -111,8 +115,10 @@ class SeoCopyFallbackBuilder
|
||||
$strPeriod = self::fallback((string)($arrFacts['rank_period_name'] ?? ''), '当前周期');
|
||||
$strScope = self::fallback((string)($arrFacts['rank_scope_name'] ?? ''), '当前范围');
|
||||
$intVisible = (int)($arrFacts['page_stats']['visible'] ?? 0);
|
||||
$strLanding = '当前榜单列表页展示的是' . $strScope . '下的' . $strPeriod . '结果,当前页可继续浏览的条目约为' . max(1, $intVisible) . '条。';
|
||||
|
||||
return [
|
||||
'search_landing' => $strLanding,
|
||||
'intro_text' => '当前榜单列表页展示的是' . $strScope . '下的' . $strPeriod . '结果,当前页可继续浏览的条目约为' . max(1, $intVisible) . '条。',
|
||||
'intro_meta' => '如果你想横向对比结果,可以切到其他周期榜单,或者直接进入详情页继续确认内容。',
|
||||
'guide_cards' => [
|
||||
|
||||
@@ -24,7 +24,93 @@ class SeoCopyStore
|
||||
return trim($strTemplate);
|
||||
}
|
||||
|
||||
return trim(strtr($strTemplate, $arrReplace));
|
||||
foreach ($arrTokens as $strKey => $mValue) {
|
||||
$strKey = trim((string)$strKey);
|
||||
if ($strKey === '' || trim((string)$mValue) !== '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$strTemplate = self::stripEmptyTokenArtifacts($strTemplate, $strKey);
|
||||
}
|
||||
|
||||
return self::normalizeInterpolatedText(strtr($strTemplate, $arrReplace));
|
||||
}
|
||||
|
||||
private static function stripEmptyTokenArtifacts(string $strTemplate, string $strKey): string
|
||||
{
|
||||
$strToken = preg_quote('{' . $strKey . '}', '/');
|
||||
$arrLabelMap = [
|
||||
'video_alias' => ['别名'],
|
||||
'year' => ['年份'],
|
||||
'area_name' => ['地区'],
|
||||
'lang_name' => ['语言'],
|
||||
'actor_names' => ['演员'],
|
||||
'director_names' => ['导演'],
|
||||
'remarks' => ['备注'],
|
||||
'play_line' => ['播放线路', '线路'],
|
||||
'episode_name' => ['集数', '期数', '剧集'],
|
||||
];
|
||||
|
||||
foreach ((array)($arrLabelMap[$strKey] ?? []) as $strLabel) {
|
||||
$strLabel = preg_quote($strLabel, '/');
|
||||
$arrLabelPatterns = [
|
||||
'/' . $strLabel . '\s*' . $strToken . '\s*[、,,]/u',
|
||||
'/[、,,]\s*' . $strLabel . '\s*' . $strToken . '/u',
|
||||
'/' . $strLabel . '\s*' . $strToken . '/u',
|
||||
];
|
||||
|
||||
foreach ($arrLabelPatterns as $strPattern) {
|
||||
$strTemplate = preg_replace($strPattern, '', $strTemplate) ?? $strTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
$arrPatterns = [
|
||||
// 删掉前置连词 + 空 token,例如 “和{remarks}”
|
||||
'/\s*(?:和|及|与|并|或)\s*' . $strToken . '/u',
|
||||
// 删掉空 token + 后置连词,例如 “{remarks}和”
|
||||
'/' . $strToken . '\s*(?:和|及|与|并|或)\s*/u',
|
||||
// 删掉与空 token 紧邻的顿号/逗号
|
||||
'/[、,,]\s*' . $strToken . '/u',
|
||||
'/' . $strToken . '\s*[、,,]/u',
|
||||
// 默认兜底:直接删掉空 token
|
||||
'/' . $strToken . '/u',
|
||||
];
|
||||
|
||||
foreach ($arrPatterns as $strPattern) {
|
||||
$strTemplate = preg_replace($strPattern, '', $strTemplate) ?? $strTemplate;
|
||||
}
|
||||
|
||||
return $strTemplate;
|
||||
}
|
||||
|
||||
private static function normalizeInterpolatedText(string $strValue): string
|
||||
{
|
||||
$strValue = preg_replace('/\{[a-z0-9_]+\}/iu', '', $strValue) ?? $strValue;
|
||||
$strValue = str_replace(['高清高清播放', '高清高清'], ['高清播放', '高清'], $strValue);
|
||||
$strValue = preg_replace('/\s{2,}/u', ' ', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/\s*[_||]+\s*/u', ' - ', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/\s*-\s*-\s*/u', ' - ', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(会把|把)([^,。;!?、\\s]{1,24})和([^,。;!?、\\s]{1,24})(等资料|这类线索)/u', '$1$2、$3$4', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(年份|地区|语言|演员|导演|备注|别名|线路|集数)(?=[A-Za-z0-9])/u', '$1 ', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(地区|语言|演员|导演|备注|别名)([\p{Han}A-Za-z])/u', '$1 $2', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/地区\s*([^,。;!?、]+?)和语言\s*([^,。;!?、]+)/u', '地区 $1,语言 $2', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(会把)([^,。;!?、\\s]{1,24})、([^,。;!?、\\s]{1,24})(这类线索)/u', '$1$2和$3$4', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(会把)([^,。;!?、\\s]{1,24})、([^,。;!?、\\s]{1,24})(等资料)/u', '$1$2、$3$4', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/补看(\d{4}[^、,。;!?]*?)、([\p{Han}A-Za-z]{1,20})、([\p{Han}A-Za-z]{1,20})与([\p{Han}A-Za-z·、,,]{1,40})/u', '补看 $1、$2、$3,以及$4', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(别名|年份|地区|语言|演员|导演|备注)\s+与/u', '$1与', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/本页,建议/u', '本页建议', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/本页,适合/u', '本页适合', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/本页,方便/u', '本页方便', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/([、,,])(?:\s*\\1)+/u', '$1', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/([((【\[])\s*[、,,\-]+\s*/u', '$1', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/\s*[、,,\-]+\s*([))】\]])/u', '$1', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(会把|把|将|用|看)、/u', '$1', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/(\d{4})-\d{2}-\d{2}(?:\s+\d{2}:\d{2}:\d{2})?/u', '$1', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/\s*([,。;!?、])/u', '$1', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/([((【\[])\s+/u', '$1', $strValue) ?? $strValue;
|
||||
$strValue = preg_replace('/\s+([))】\]])/u', '$1', $strValue) ?? $strValue;
|
||||
|
||||
return trim($strValue);
|
||||
}
|
||||
|
||||
public static function buildPageKey(array|string $mValue, string $strFallback = 'index'): string
|
||||
|
||||
@@ -4,6 +4,31 @@ namespace app\common\helper;
|
||||
|
||||
class SeoWordsHelper
|
||||
{
|
||||
/**
|
||||
* Resolve a stable forge keyword from video seo words.
|
||||
*/
|
||||
public static function resolveForgeWord(array $video = [], int $intForgeId = 1): string
|
||||
{
|
||||
$intForgeId = max(1, $intForgeId);
|
||||
|
||||
$arrWords = array_values(array_filter(array_map(
|
||||
static fn($mVal): string => trim((string)$mVal),
|
||||
(array)($video['v_seo_words'] ?? [])
|
||||
), static fn(string $strVal): bool => $strVal !== ''));
|
||||
|
||||
if (!empty($arrWords)) {
|
||||
$intIndex = ($intForgeId - 1) % count($arrWords);
|
||||
return $arrWords[$intIndex];
|
||||
}
|
||||
|
||||
$strName = trim((string)($video['v_name'] ?? ''));
|
||||
if ($strName !== '') {
|
||||
return $strName;
|
||||
}
|
||||
|
||||
return trim((string)($video['v_name_en'] ?? ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 $intRewrite 处理 SeoWords
|
||||
*/
|
||||
@@ -22,32 +47,39 @@ class SeoWordsHelper
|
||||
// 0:原序全部
|
||||
case 0:
|
||||
$arrSeoWords = $words;
|
||||
break;
|
||||
|
||||
// 1:前 6
|
||||
// 1:前 6
|
||||
case 1:
|
||||
$arrSeoWords = array_slice($words, 0, 6);
|
||||
break;
|
||||
|
||||
// 2:随机 8
|
||||
// 2:随机 8
|
||||
case 2:
|
||||
shuffle($words);
|
||||
$arrSeoWords = array_slice($words, 0, 8);
|
||||
break;
|
||||
|
||||
// 3:插年份
|
||||
// 3:插年份
|
||||
case 3:
|
||||
$arrSeoWords = self::appendYear($words, $video);
|
||||
break;
|
||||
|
||||
// 4:插“在线观看 / 免费 / 高清”
|
||||
// 4:插“在线观看 / 免费 / 高清”
|
||||
case 4:
|
||||
$arrSeoWords = self::appendSuffix($words);
|
||||
break;
|
||||
|
||||
// 5:重排 + 去重
|
||||
// 5:重排 + 去重
|
||||
case 5:
|
||||
shuffle($words);
|
||||
$arrSeoWords = array_values(array_unique($words));
|
||||
break;
|
||||
|
||||
// 兜底
|
||||
// 兜底
|
||||
default:
|
||||
$arrSeoWords = array_slice($words, 0, 6);
|
||||
break;
|
||||
}
|
||||
|
||||
$arrNewsSeoWords = [];
|
||||
|
||||
@@ -83,7 +83,7 @@ class UrlBuilder
|
||||
return $this->replacePattern($pattern, [
|
||||
'strParentCategory' => $strParentCategory,
|
||||
'strCategory' => $strCategory,
|
||||
'intPage' => max(1, (int)$intPage),
|
||||
'intPage' => $this->normalizePageValue($intPage),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -226,4 +226,13 @@ class UrlBuilder
|
||||
}
|
||||
return $this->trimSlash($pattern);
|
||||
}
|
||||
|
||||
protected function normalizePageValue(int|string $page): string
|
||||
{
|
||||
if (is_string($page) && strpos($page, '{page}') !== false) {
|
||||
return '{page}';
|
||||
}
|
||||
|
||||
return (string)max(1, (int)$page);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user