1
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
namespace app\common;
|
||||
|
||||
use think\Db;
|
||||
use think\Queue;
|
||||
use GuzzleHttp\Client;
|
||||
use think\Env;
|
||||
|
||||
class ExpertFinderService
|
||||
{
|
||||
@@ -74,64 +76,105 @@ class ExpertFinderService
|
||||
$fieldEnrich = 0;
|
||||
|
||||
foreach ($experts as $expert) {
|
||||
|
||||
|
||||
$email = strtolower(trim($expert['email']));
|
||||
if (empty($email)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$exists = Db::name('expert')->where('email', $email)->find();
|
||||
$exists = Db::name('expert')->where('email', $email)->find();
|
||||
$expertId = null;
|
||||
|
||||
if ($exists) {
|
||||
$existing++;
|
||||
$fieldEnrich += $this->enrichExpertField($exists['expert_id'], $field);
|
||||
continue;
|
||||
}
|
||||
|
||||
$insert = [
|
||||
'name' => mb_substr($expert['name'], 0, 255),
|
||||
'email' => mb_substr($email, 0, 128),
|
||||
'affiliation' => mb_substr($expert['affiliation'], 0, 128),
|
||||
'source' => mb_substr($source, 0, 128),
|
||||
'ctime' => time(),
|
||||
'ltime' => 0,
|
||||
'state' => 0,
|
||||
];
|
||||
|
||||
try {
|
||||
$expertId = Db::name('expert')->insertGetId($insert);
|
||||
$this->enrichExpertField($expertId, $field);
|
||||
if(isset($expert['papers'])&&is_array($expert['papers'])){
|
||||
$this->savePaper($expertId, $expert['papers']);
|
||||
$expertId = intval($exists['expert_id']);
|
||||
} else {
|
||||
try {
|
||||
$expertId = Db::name('expert')->insertGetId([
|
||||
'name' => mb_substr($expert['name'], 0, 255),
|
||||
'email' => mb_substr($email, 0, 128),
|
||||
'affiliation' => mb_substr($expert['affiliation'], 0, 128),
|
||||
'source' => mb_substr($source, 0, 128),
|
||||
'ctime' => time(),
|
||||
'ltime' => 0,
|
||||
'state' => 0,
|
||||
]);
|
||||
$inserted++;
|
||||
} catch (\Exception $e) {
|
||||
$existing++;
|
||||
continue;
|
||||
}
|
||||
$inserted++;
|
||||
} catch (\Exception $e) {
|
||||
$existing++;
|
||||
}
|
||||
|
||||
$papers = (isset($expert['papers']) && is_array($expert['papers'])) ? $expert['papers'] : [];
|
||||
$fieldEnrich += $this->saveFieldWithPapers($expertId, $field, $source, $papers);
|
||||
}
|
||||
|
||||
return ['inserted' => $inserted, 'existing' => $existing, 'field_enriched' => $fieldEnrich];
|
||||
}
|
||||
|
||||
private function savePaper($expertId, $papers)
|
||||
/**
|
||||
* 保存领域与论文的关联。
|
||||
* 有论文时:每篇论文一行(expert_id + field + source + paper_article_id 去重)。
|
||||
* 无论文时:只存一条领域行(expert_id + field 去重)。
|
||||
*/
|
||||
private function saveFieldWithPapers($expertId, $field, $source, $papers)
|
||||
{
|
||||
foreach ($papers as $paper){
|
||||
$check = Db::name('expert_paper')->where("expert_id",$expertId)->where('paper_article_id',$paper['article_id'])->find();
|
||||
if($check){
|
||||
continue;
|
||||
}
|
||||
$insert = [
|
||||
'expert_id' => $expertId,
|
||||
'paper_title' => isset($paper['title'])?mb_substr($paper['title'], 0, 255):"",
|
||||
'paper_article_id' => $paper['article_id'] ?? 0,
|
||||
'paper_journal' => isset($paper['journal'])?mb_substr($paper['journal'], 0, 128):"",
|
||||
'ctime' => time(),
|
||||
];
|
||||
Db::name('expert_paper')->insert($insert);
|
||||
}
|
||||
}
|
||||
$field = trim($field);
|
||||
if (empty($field)) return 0;
|
||||
|
||||
$added = 0;
|
||||
|
||||
if (empty($papers)) {
|
||||
$exists = Db::name('expert_field')
|
||||
->where('expert_id', $expertId)
|
||||
->where('field', $field)
|
||||
->where('state', 0)
|
||||
->find();
|
||||
if (!$exists) {
|
||||
Db::name('expert_field')->insert([
|
||||
'expert_id' => $expertId,
|
||||
'source' => mb_substr((string)$source, 0, 64),
|
||||
'field' => mb_substr($field, 0, 128),
|
||||
'paper_title' => '',
|
||||
'paper_article_id' => '',
|
||||
'paper_journal' => '',
|
||||
'state' => 0,
|
||||
]);
|
||||
$added = 1;
|
||||
}
|
||||
} else {
|
||||
foreach ($papers as $paper) {
|
||||
$articleId = isset($paper['article_id']) ? (string)$paper['article_id'] : '';
|
||||
if ($articleId === '' || $articleId === '0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$check = Db::name('expert_field')
|
||||
->where('expert_id', $expertId)
|
||||
->where('field', $field)
|
||||
->where('source', $source)
|
||||
->where('paper_article_id', $articleId)
|
||||
->where('state', 0)
|
||||
->find();
|
||||
if ($check) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Db::name('expert_field')->insert([
|
||||
'expert_id' => $expertId,
|
||||
'source' => mb_substr((string)$source, 0, 64),
|
||||
'paper_title' => isset($paper['title']) ? mb_substr((string)$paper['title'], 0, 255) : '',
|
||||
'paper_article_id' => mb_substr($articleId, 0, 64),
|
||||
'paper_journal' => isset($paper['journal']) ? mb_substr((string)$paper['journal'], 0, 255) : '',
|
||||
'field' => mb_substr($field, 0, 128),
|
||||
'state' => 0,
|
||||
]);
|
||||
$added++;
|
||||
}
|
||||
}
|
||||
|
||||
return $added;
|
||||
}
|
||||
|
||||
public function getFetchLog($field, $source)
|
||||
{
|
||||
@@ -536,25 +579,94 @@ class ExpertFinderService
|
||||
];
|
||||
}
|
||||
|
||||
// ==================== DB Helpers ====================
|
||||
// ==================== Country Resolution ====================
|
||||
|
||||
private function enrichExpertField($expertId, $field)
|
||||
/**
|
||||
* 启动国家解析链:找到下一个缺国家的专家推入队列。
|
||||
* 队列 Job 处理完一个后会再调此方法,自动找下一个,直到全部处理完。
|
||||
* 控制器只需调一次即可。
|
||||
*
|
||||
* @param int $delay 延迟秒数(防止打满模型,默认1秒)
|
||||
* @return bool 是否成功推入了一条
|
||||
*/
|
||||
public function enqueueNextCountryFill($delay = 1)
|
||||
{
|
||||
$field = trim($field);
|
||||
if (empty($field)) return 0;
|
||||
|
||||
$exists = Db::name('expert_field')
|
||||
->where('expert_id', $expertId)
|
||||
->where('field', $field)
|
||||
->where('state', 0)
|
||||
$row = Db::name('expert')
|
||||
->where('affiliation', '<>', '')
|
||||
->where(function ($q) {
|
||||
$q->where('country_id', 0)
|
||||
->whereOr('country_id', 'null')
|
||||
->whereOr('country', '');
|
||||
})
|
||||
->where('state', '<>', 5)
|
||||
->field('expert_id, affiliation')
|
||||
->order('expert_id asc')
|
||||
->find();
|
||||
if ($exists) return 0;
|
||||
Db::name('expert_field')->insert([
|
||||
'expert_id' => $expertId,
|
||||
'field' => mb_substr($field, 0, 128),
|
||||
'state' => 0,
|
||||
|
||||
if (!$row) {
|
||||
$this->log('[CountryFill] no more pending experts');
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'expert_id' => intval($row['expert_id']),
|
||||
'affiliation' => trim((string)$row['affiliation']),
|
||||
];
|
||||
|
||||
if ($delay > 0) {
|
||||
Queue::later($delay, 'app\api\job\FillExpertCountry@fire', $data, 'FetchExperts');
|
||||
} else {
|
||||
Queue::push('app\api\job\FillExpertCountry@fire', $data, 'FetchExperts');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对单个专家执行国家解析(同步),由队列 Job FillExpertCountry 调用,也可直接调用测试。
|
||||
*/
|
||||
public function fillExpertCountry($expertId, $affiliation)
|
||||
{
|
||||
$affiliation = trim((string)$affiliation);
|
||||
if ($affiliation === '') return;
|
||||
|
||||
$resolver = new CountryResolverService([
|
||||
'chat_url' => trim((string)Env::get('expert_country_chat_url', Env::get('citation_chat_url', 'http://chat.taimed.cn/v1/chat/completions'))),
|
||||
'chat_model' => trim((string)Env::get('expert_country_chat_model', Env::get('citation_chat_model', 'gpt-4.1'))),
|
||||
'api_key' => trim((string)Env::get('expert_country_chat_api_key', Env::get('citation_chat_api_key', ''))),
|
||||
'timeout' => max(20, intval(Env::get('expert_country_chat_timeout', 60))),
|
||||
]);
|
||||
return 1;
|
||||
|
||||
$result = $resolver->resolve($affiliation);
|
||||
if (empty($result)) return;
|
||||
|
||||
$countryId = 0;
|
||||
$enName = '';
|
||||
|
||||
if (!empty($result['code'])) {
|
||||
$row = Db::name('country')->where('code', strtoupper(trim((string)$result['code'])))->find();
|
||||
if ($row) {
|
||||
$countryId = intval($row['country_id']);
|
||||
$enName = (string)$row['en_name'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($countryId === 0 && !empty($result['en_name'])) {
|
||||
$row = Db::name('country')
|
||||
->whereRaw("LOWER(en_name) = ?", [strtolower(trim((string)$result['en_name']))])
|
||||
->find();
|
||||
if ($row) {
|
||||
$countryId = intval($row['country_id']);
|
||||
$enName = (string)$row['en_name'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($countryId > 0 && $enName !== '') {
|
||||
Db::name('expert')->where('expert_id', intval($expertId))->update([
|
||||
'country_id' => $countryId,
|
||||
'country' => $enName,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Text Helpers ====================
|
||||
|
||||
Reference in New Issue
Block a user