no message
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command;
|
||||
|
||||
use app\api\logic\ArticleLogic;
|
||||
use app\common\enum\YesNoEnum;
|
||||
use app\common\model\article\Article;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
|
||||
class WorldcupArticleTranslate extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('worldcup_article_translate')
|
||||
->setDescription('预热世界杯英文资讯翻译缓存');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$articles = Article::field('id,cid,title,desc,content,ext,is_show,delete_time')
|
||||
->where('cid', 22)
|
||||
->where('is_show', YesNoEnum::YES)
|
||||
// 与前台世界杯资讯列表保持一致,只预热用户最先看到的 50 条。
|
||||
->order('published_at', 'desc')
|
||||
->order('id', 'desc')
|
||||
->limit(50)
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
if (empty($articles)) {
|
||||
$output->writeln('<comment>[WorldcupTranslate] 没有找到可处理的世界杯文章</comment>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
$translated = 0;
|
||||
$skippedExist = 0;
|
||||
$skippedNonEnglish = 0;
|
||||
$failed = 0;
|
||||
|
||||
foreach ($articles as $article) {
|
||||
$ext = $this->decodeExt($article['ext'] ?? []);
|
||||
if (!empty($ext['translated_content'])) {
|
||||
$skippedExist++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->isProbablyEnglish($article)) {
|
||||
$skippedNonEnglish++;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ArticleLogic::autoTranslateArticle($article);
|
||||
if ($result !== '') {
|
||||
$translated++;
|
||||
$output->writeln(sprintf('[WorldcupTranslate] 已翻译文章 #%d %s', $article['id'], $article['title'] ?? ''));
|
||||
} else {
|
||||
$failed++;
|
||||
$output->writeln(sprintf('<comment>[WorldcupTranslate] 翻译失败或无结果 #%d %s</comment>', $article['id'], $article['title'] ?? ''));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$failed++;
|
||||
$output->writeln(sprintf('<error>[WorldcupTranslate] 异常 #%d %s - %s</error>', $article['id'], $article['title'] ?? '', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln(sprintf(
|
||||
'[WorldcupTranslate] 完成,翻译 %d 条,已存在 %d 条,跳过非英文 %d 条,失败 %d 条',
|
||||
$translated,
|
||||
$skippedExist,
|
||||
$skippedNonEnglish,
|
||||
$failed
|
||||
));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function isProbablyEnglish(array $article): bool
|
||||
{
|
||||
$text = trim(implode(' ', [
|
||||
(string) ($article['title'] ?? ''),
|
||||
(string) ($article['desc'] ?? ''),
|
||||
$this->normalizeText((string) ($article['content'] ?? '')),
|
||||
]));
|
||||
|
||||
if ($text === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/[\x{4e00}-\x{9fff}]/u', $text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$letterCount = preg_match_all('/[A-Za-z]/', $text);
|
||||
$wordCount = preg_match_all('/\b[A-Za-z]{2,}\b/', $text);
|
||||
|
||||
// 世界杯资讯里不少正文并不长,阈值过高会误杀正常英文稿件。
|
||||
return $letterCount >= 30 && $wordCount >= 5;
|
||||
}
|
||||
|
||||
private function normalizeText(string $content): string
|
||||
{
|
||||
if ($content === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$content = strip_tags($content);
|
||||
$content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
$content = preg_replace('/\s+/u', ' ', $content);
|
||||
|
||||
return trim($content);
|
||||
}
|
||||
|
||||
private function decodeExt($ext): array
|
||||
{
|
||||
if (is_array($ext)) {
|
||||
return $ext;
|
||||
}
|
||||
|
||||
if (is_string($ext) && $ext !== '') {
|
||||
$data = json_decode($ext, true);
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user