作者的ai总结field
This commit is contained in:
@@ -1406,8 +1406,8 @@ class EmailClient extends Base
|
||||
return jsonError('Factory is disabled');
|
||||
}
|
||||
$expertType = intval($factory['expert_type']);
|
||||
if (!in_array($expertType, [2, 3, 5], true)) {
|
||||
return jsonError('Only expert_type=2(Editorial Board), 3(Young Editorial Board) or 5(Expert pool) is supported currently');
|
||||
if (!in_array($expertType, [2, 3, 4, 5, 6], true)) {
|
||||
return jsonError('Unsupported expert_type; supported: 2=编委, 3=青年编委, 4=作者, 5=专家库, 6=往期青年编委');
|
||||
}
|
||||
|
||||
$journalId = intval($factory['journal_id']);
|
||||
@@ -2260,7 +2260,7 @@ class EmailClient extends Base
|
||||
* 每日自动生成推广任务(由 Linux crontab 调用)
|
||||
*
|
||||
* 逻辑:
|
||||
* 1. 查询所有 state=0 的任务工厂(支持 expert_type=2 编委 / =5 expert 库;其他类型预留)
|
||||
* 1. 查询所有 state=0 的任务工厂(支持 expert_type=2/3/4/5/6)
|
||||
* 2. JOIN journal 确认期刊有效(state=0, start_promotion=1)
|
||||
* 3. 按 factory_id + send_date 检查去重
|
||||
* 4. template/style: 工厂 > 0 用工厂的,否则用期刊默认
|
||||
@@ -2282,7 +2282,7 @@ class EmailClient extends Base
|
||||
->alias('f')
|
||||
->join('t_journal j', 'j.journal_id = f.journal_id', 'inner')
|
||||
->where('f.state', 0)
|
||||
->where('f.expert_type', 'in', [2, 3, 5])
|
||||
->where('f.expert_type', 'in', [2, 3, 4, 5, 6])
|
||||
->where('j.state', 0)
|
||||
->where('f.start_promotion', 1)
|
||||
->field('f.*, j.title as journal_title, j.default_template_id, j.default_style_id')
|
||||
@@ -2684,6 +2684,7 @@ class EmailClient extends Base
|
||||
3 => 'Young Editorial Board',
|
||||
4 => 'Author',
|
||||
5 => 'Expert Pool',
|
||||
6 => 'Past Young Editorial Board',
|
||||
];
|
||||
return isset($map[intval($t)]) ? $map[intval($t)] : 'Unknown';
|
||||
}
|
||||
@@ -2694,7 +2695,7 @@ class EmailClient extends Base
|
||||
* - expert_type = 5:从 t_expert 库选人(按领域 / 国家 / 频次)
|
||||
* 频次:e.ltime(成功发送后回写)+ t_promotion_email_log 中「待发送 state=0 的入队时间 ctime」
|
||||
* (避免「今日生成任务明日发送」时 ltime 未变导致连续两天选到同一拨人)
|
||||
* - expert_type ∈ {1,2,3,4}:从系统内部表选人(主编/编委/青年编委/作者),fields 与国家筛选忽略;
|
||||
* - expert_type ∈ {1,2,3,4,6}:从系统内部表选人(主编/编委/青年编委/作者/往期青年编委),fields 与国家筛选忽略;
|
||||
* 频次按 t_promotion_email_log:已发/退信用 send_time;待发送队列用 ctime(同上)
|
||||
*
|
||||
* 返回行 shape 已对齐:
|
||||
@@ -2782,7 +2783,7 @@ class EmailClient extends Base
|
||||
*
|
||||
* 频次:扣除「同 expert_type 下,no_repeat_days 内 (1) 已发出或退信,或 (2) 仍在队列待发送(state=0,按 ctime)」的人
|
||||
*
|
||||
* @param int $expertType 1=主编 2=编委 3=青年编委 4=作者
|
||||
* @param int $expertType 1=主编 2=编委 3=青年编委 4=作者 6=往期青年编委
|
||||
* @param int $journalId
|
||||
* @param int $noRepeatDays
|
||||
* @param int $limit
|
||||
@@ -2817,11 +2818,12 @@ class EmailClient extends Base
|
||||
break;
|
||||
|
||||
case 1: // 主编(预留,本期不实现)
|
||||
break;
|
||||
case 4: // 作者(预留)
|
||||
Db::name("article_author")->alias('aa')
|
||||
return [];
|
||||
|
||||
case 4: // 作者:该刊投稿作者(按邮箱关联 t_user)
|
||||
$query = Db::name('article_author')->alias('aa')
|
||||
->join('t_user u', 'u.email = aa.email', 'inner')
|
||||
->join("t_article a","a.article_id = aa.article_id","left")
|
||||
->join('t_article a', 'a.article_id = aa.article_id', 'inner')
|
||||
->join('t_user_reviewer_info uri', 'uri.reviewer_id = u.user_id', 'left')
|
||||
->where('a.journal_id', $journalId)
|
||||
->where('u.email', '<>', '')
|
||||
@@ -2843,6 +2845,10 @@ class EmailClient extends Base
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!isset($query)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($noRepeatDays > 0) {
|
||||
$cutoff = intval(time() - ($noRepeatDays * 86400));
|
||||
$expertTypeSafe = intval($expertType);
|
||||
|
||||
@@ -166,7 +166,7 @@ class UserFieldAiService
|
||||
|
||||
while (true) {
|
||||
$query = Db::name('user')->alias('u')
|
||||
->leftJoin('t_user_reviewer_info uri', 'uri.reviewer_id = u.user_id')
|
||||
->join('t_user_reviewer_info uri', 'uri.reviewer_id = u.user_id',"left")
|
||||
->where('u.user_id', '>', $cursor);
|
||||
if (!$force) {
|
||||
$query->where(function ($q) {
|
||||
@@ -270,13 +270,70 @@ class UserFieldAiService
|
||||
return array_values(array_unique(array_filter(array_map('trim', $titles))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 OpenAI 兼容 chat/completions 完整 URL。
|
||||
* base.model_url 常为站点根(如 http://chat.taimed.cn),直接 POST 会 404。
|
||||
*/
|
||||
private function resolveLlmChatUrl()
|
||||
{
|
||||
$candidates = [
|
||||
// Env::get('user_field_ai.chat_url', ''),
|
||||
// Env::get('promotion.promotion_llm_url', ''),
|
||||
// Env::get('expert_country_chat_url', ''),
|
||||
// Env::get('citation_chat_url', ''),
|
||||
Env::get('base.model_url1', ''),
|
||||
];
|
||||
foreach ($candidates as $u) {
|
||||
$u = trim((string) $u);
|
||||
if ($u === '') {
|
||||
continue;
|
||||
}
|
||||
$normalized = $this->normalizeChatCompletionsUrl($u);
|
||||
if ($normalized !== '') {
|
||||
return $normalized;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
private function normalizeChatCompletionsUrl($url)
|
||||
{
|
||||
$url = trim((string) $url);
|
||||
if ($url === '') {
|
||||
return '';
|
||||
}
|
||||
if (stripos($url, 'chat/completions') !== false) {
|
||||
return $url;
|
||||
}
|
||||
return rtrim($url, '/') . '/v1/chat/completions';
|
||||
}
|
||||
|
||||
private function resolveLlmModel()
|
||||
{
|
||||
$candidates = [
|
||||
Env::get('user_field_ai.chat_model', ''),
|
||||
Env::get('base.model', ''),
|
||||
Env::get('promotion.promotion_llm_model', ''),
|
||||
Env::get('expert_country_chat_model', ''),
|
||||
Env::get('citation_chat_model', ''),
|
||||
'gpt-4.1',
|
||||
];
|
||||
foreach ($candidates as $m) {
|
||||
$m = trim((string) $m);
|
||||
if ($m !== '' && strtolower($m) !== 'your-model-name') {
|
||||
return $m;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
private function summarizeWithLlm(array $context)
|
||||
{
|
||||
$url = trim((string) Env::get('user_field_ai.chat_url', Env::get('expert_country_chat_url', Env::get('citation_chat_url', ''))));
|
||||
$model = trim((string) Env::get('user_field_ai.chat_model', Env::get('expert_country_chat_model', Env::get('citation_chat_model', 'gpt-4.1'))));
|
||||
$url = $this->resolveLlmChatUrl();
|
||||
$model = $this->resolveLlmModel();
|
||||
$apiKey = trim((string) Env::get('user_field_ai.chat_api_key', Env::get('expert_country_chat_api_key', Env::get('citation_chat_api_key', ''))));
|
||||
if ($url === '' || $model === '') {
|
||||
throw new Exception('user_field_ai chat not configured (chat_url / chat_model)');
|
||||
throw new Exception('user_field_ai chat not configured (set user_field_ai.chat_url or promotion PROMOTION_LLM_URL / base.model_url)');
|
||||
}
|
||||
|
||||
$payloadJson = json_encode($context, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
@@ -321,7 +378,10 @@ class UserFieldAiService
|
||||
throw new Exception('LLM curl error: ' . $err);
|
||||
}
|
||||
if ($code < 200 || $code >= 300) {
|
||||
throw new Exception('LLM HTTP ' . $code . ': ' . mb_substr((string) $raw, 0, 400));
|
||||
$hint = ($code === 404 && stripos($url, 'chat/completions') === false)
|
||||
? ' (chat_url may be missing /v1/chat/completions)'
|
||||
: '';
|
||||
throw new Exception('LLM HTTP ' . $code . $hint . ': ' . mb_substr((string) $raw, 0, 400));
|
||||
}
|
||||
|
||||
$data = json_decode($raw, true);
|
||||
@@ -378,7 +438,6 @@ class UserFieldAiService
|
||||
}
|
||||
Db::name('user_reviewer_info')->insert([
|
||||
'reviewer_id' => $userId,
|
||||
'ctime' => time(),
|
||||
'state' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user