小问题功能修复

This commit is contained in:
wangjinlei
2026-06-04 09:35:19 +08:00
parent 2155fc1207
commit bbd690ca0f
2 changed files with 127 additions and 41 deletions

View File

@@ -30,6 +30,6 @@ class UserFieldAiFill
$job->delete(); $job->delete();
$delay = max(0, (int) (isset($data['delay']) ? $data['delay'] : 1)); $delay = max(0, (int) (isset($data['delay']) ? $data['delay'] : 1));
// $svc->enqueueNextFieldAi($delay, $queue, $userId, $force); $svc->enqueueNextFieldAi($delay, $queue, $userId, $force);
} }
} }

View File

@@ -509,6 +509,24 @@ class PromotionService
} }
} }
// 仅当模板真正引用了 LLM 占位符llm_description / ai_content_analysis /
// ai_advised_topics / llm_advised_topics时才调用 LLM避免无谓的请求与开销。
$llmNeed = $this->detectLlmTemplateNeed(
$task['template_id'],
$task['journal_id'],
intval($task['style_id'] ?? 0)
);
if (!$llmNeed['need']) {
$llmText = '';
$llmStatus = 0;
$advisedText = '';
$advisedStatus = 0;
$expert['llm_description'] = '';
$expert['ai_advised_topics'] = '';
$expert['role'] = $this->mapExpertTypeRole($expertType);
$this->log("prepareSingleEmail log_id={$logId} skip_llm (template has no llm placeholders)");
} else {
// 一次 LLM 调用生成两段内容description + advised_topics // 一次 LLM 调用生成两段内容description + advised_topics
$llmResult = [ $llmResult = [
'description' => '', 'description' => '',
@@ -551,6 +569,7 @@ class PromotionService
$expert['ai_advised_topics'] = $advisedText; $expert['ai_advised_topics'] = $advisedText;
$expert['role'] = $this->mapExpertTypeRole($expertType); $expert['role'] = $this->mapExpertTypeRole($expertType);
} }
}
$expertVars = $this->buildExpertVars($expert); $expertVars = $this->buildExpertVars($expert);
$journalVars = $this->buildJournalVars($journal); $journalVars = $this->buildJournalVars($journal);
@@ -935,6 +954,73 @@ class PromotionService
// ==================== Template Rendering ==================== // ==================== Template Rendering ====================
/**
* 检测邮件模板(含 style 头尾)是否包含需要 LLM 生成的占位符。
*
* @return array{need:bool,need_description:bool,need_advised_topics:bool,tags:array<int,string>}
*/
public function detectLlmTemplateNeed($templateId, $journalId, $styleId = 0)
{
$descriptionTags = ['llm_description', 'ai_content_analysis'];
$advisedTags = ['ai_advised_topics', 'llm_advised_topics'];
$allTags = array_merge($descriptionTags, $advisedTags);
$parts = [];
$tpl = Db::name('mail_template')
->where('template_id', $templateId)
->where('journal_id', $journalId)
->where('state', 0)
->find();
if ($tpl) {
$parts[] = (string)($tpl['subject'] ?? '');
$parts[] = (string)($tpl['body_html'] ?? '');
}
$styleId = intval($styleId);
if ($styleId > 0) {
$style = Db::name('mail_style')->where('style_id', $styleId)->where('state', 0)->find();
if ($style) {
$parts[] = (string)($style['header_html'] ?? '');
$parts[] = (string)($style['footer_html'] ?? '');
}
}
$haystack = implode("\n", $parts);
$found = [];
foreach ($allTags as $tag) {
if ($this->templateContainsVar($haystack, $tag)) {
$found[] = $tag;
}
}
$needDesc = (bool) array_intersect($found, $descriptionTags);
$needAdvised = (bool) array_intersect($found, $advisedTags);
return [
'need' => !empty($found),
'need_description' => $needDesc,
'need_advised_topics' => $needAdvised,
'tags' => $found,
];
}
/**
* 模板是否包含某变量占位符(支持 {{ var }} 与 {var})。
*/
protected function templateContainsVar($haystack, $varName)
{
if (!is_string($haystack) || $haystack === '' || $varName === '') {
return false;
}
$quoted = preg_quote($varName, '/');
if (preg_match('/\{\{\s*' . $quoted . '\s*\}\}/', $haystack)) {
return true;
}
if (strpos($haystack, '{' . $varName . '}') !== false) {
return true;
}
return false;
}
public function renderFromTemplate($templateId, $journalId, $varsJson, $styleId = 0) public function renderFromTemplate($templateId, $journalId, $varsJson, $styleId = 0)
{ {
$tpl = Db::name('mail_template')->where('template_id', $templateId)->where('journal_id', $journalId)->where('state', 0)->find(); $tpl = Db::name('mail_template')->where('template_id', $templateId)->where('journal_id', $journalId)->where('state', 0)->find();