小问题功能修复

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

@@ -509,47 +509,66 @@ class PromotionService
}
}
// 一次 LLM 调用生成两段内容(description + advised_topics
$llmResult = [
'description' => '',
'description_status' => 0,
'advised_topics' => '',
'advised_topics_status' => 0,
];
try {
$llm = new PromotionLlmService();
$llmResult = $llm->generateEmailContent(
$expert,
$journal ?: [],
$overlapFields,
$taskFields,
$fieldSet
);
} catch (\Exception $e) {
$fbDesc = '';
$fbAdvised = '';
try {
$fbSvc = isset($llm) ? $llm : new PromotionLlmService();
$fbDesc = $fbSvc->getFallback();
$fbAdvised = $fbSvc->getAdvisedFallback();
} catch (\Exception $ignore) {
}
$llmResult = [
'description' => $fbDesc,
'description_status' => 2,
'advised_topics' => $fbAdvised,
'advised_topics_status' => 2,
];
$this->log("prepareSingleEmail log_id={$logId} llm_exception=" . $e->getMessage());
}
$llmText = (string)$llmResult['description'];
$llmStatus = intval($llmResult['description_status']);
$advisedText = (string)$llmResult['advised_topics'];
$advisedStatus = intval($llmResult['advised_topics_status']);
// 仅当模板真正引用了 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)
);
$expert['llm_description'] = $llmText;
$expert['ai_advised_topics'] = $advisedText;
$expert['role'] = $this->mapExpertTypeRole($expertType);
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
$llmResult = [
'description' => '',
'description_status' => 0,
'advised_topics' => '',
'advised_topics_status' => 0,
];
try {
$llm = new PromotionLlmService();
$llmResult = $llm->generateEmailContent(
$expert,
$journal ?: [],
$overlapFields,
$taskFields,
$fieldSet
);
} catch (\Exception $e) {
$fbDesc = '';
$fbAdvised = '';
try {
$fbSvc = isset($llm) ? $llm : new PromotionLlmService();
$fbDesc = $fbSvc->getFallback();
$fbAdvised = $fbSvc->getAdvisedFallback();
} catch (\Exception $ignore) {
}
$llmResult = [
'description' => $fbDesc,
'description_status' => 2,
'advised_topics' => $fbAdvised,
'advised_topics_status' => 2,
];
$this->log("prepareSingleEmail log_id={$logId} llm_exception=" . $e->getMessage());
}
$llmText = (string)$llmResult['description'];
$llmStatus = intval($llmResult['description_status']);
$advisedText = (string)$llmResult['advised_topics'];
$advisedStatus = intval($llmResult['advised_topics_status']);
$expert['llm_description'] = $llmText;
$expert['ai_advised_topics'] = $advisedText;
$expert['role'] = $this->mapExpertTypeRole($expertType);
}
}
$expertVars = $this->buildExpertVars($expert);
@@ -935,6 +954,73 @@ class PromotionService
// ==================== 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)
{
$tpl = Db::name('mail_template')->where('template_id', $templateId)->where('journal_id', $journalId)->where('state', 0)->find();