Hyperf 百度翻譯接口實現方案

保留 HTML/XML 標簽結構,僅翻譯文本內容,避免破壞富文本格式。采用「HTML 解析 → 文本提取 → 批量翻譯 → 回填」的流程。

百度翻譯集成方案:富文本內容翻譯系統
HTML 解析 + 百度翻譯 API 集成

文件結構

app/
├── Controller/
│   └── TranslationController.php
├── Service/
│   ├── BaiduTranslator.php
│   └── HtmlParser.php
├── Job/
│   └── TranslateContentJob.php
├── Model/
│   └── Article.php
config/
│   └── autoload/
│       └── translation.php

代碼實現

  1. 配置文件 config/autoload/translation.php
<?phpreturn ['baidu' => ['appid' => env('BAIDU_TRANSLATE_APPID', ''),'secret' => env('BAIDU_TRANSLATE_SECRET', ''),'api_url' => 'https://fanyi-api.baidu.com/api/trans/vip/fieldtranslate','chunk_size' => 30, // 每次翻譯的文本段落數'max_length' => 5000, // 單次請求最大字節數'preserve_tags' => 'p,div,span,h1,h2,h3,h4,h5,h6,ul,ol,li,table,tr,td,th,img,video,a,strong,em,b,i,u','ignore_tags' => 'code,pre,script,style',],
];
  1. 模型 app/Model/Article.php
<?phpdeclare(strict_types=1);namespace App\Model;use Hyperf\DbConnection\Model\Model;/*** @property int $id * @property string $title * @property string $content * @property string $en_content * @property int $translation_status 0-未翻譯 1-翻譯中 2-翻譯完成 3-翻譯失敗* @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at */
class Article extends Model
{const STATUS_PENDING = 0;const STATUS_PROCESSING = 1;const STATUS_COMPLETED = 2;const STATUS_FAILED = 3;protected ?string $table = 'articles';protected array $fillable = ['title', 'content', 'en_content', 'translation_status'];protected array $casts = ['id' => 'integer','translation_status' => 'integer','created_at' => 'datetime','updated_at' => 'datetime'];
}
  1. HTML 解析器 app/Service/HtmlParser.php
<?phpdeclare(strict_types=1);namespace App\Service;use voku\helper\HtmlDomParser;class HtmlParser
{public function extractTextNodes(string $html): array{$dom = HtmlDomParser::str_get_html($html);$textNodes = [];// 遍歷所有元素$dom->filter('*')->each(function ($node) use (&$textNodes) {// 跳過忽略標簽$ignoreTags = explode(',', config('translation.baidu.ignore_tags', 'code,pre,script,style'));if (in_array($node->tag, $ignoreTags)) {return;}// 只處理沒有子元素的文本節點if ($node->text() && !$node->hasChildren()) {$textNodes[] = ['node' => $node,'text' => $node->text(),'outer_html' => $node->outerhtml];}// 處理圖片alt屬性if ($node->tag === 'img' && $node->alt) {$textNodes[] = ['node' => $node,'text' => $node->alt,'is_attr' => 'alt','outer_html' => $node->outerhtml];}// 處理視頻標題if ($node->tag === 'video' && $node->title) {$textNodes[] = ['node' => $node,'text' => $node->title,'is_attr' => 'title','outer_html' => $node->outerhtml];}});return $textNodes;}public function replaceTranslatedText(array $originalNodes, array $translatedTexts): string{$html = '';$index = 0;foreach ($originalNodes as $nodeInfo) {if (isset($nodeInfo['is_attr'])) {// 屬性翻譯$nodeInfo['node']->setAttribute($nodeInfo['is_attr'], $translatedTexts[$index] ?? $nodeInfo['text']);} else {// 文本節點翻譯$nodeInfo['node']->innertext = htmlspecialchars($translatedTexts[$index] ?? $nodeInfo['text']);}$html .= $nodeInfo['node']->outerhtml;$index++;}return $html;}
}
  1. 百度翻譯服務 app/Service/BaiduTranslator.php
<?phpdeclare(strict_types=1);namespace App\Service;use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Guzzle\ClientFactory;
use Hyperf\Utils\Arr;
use Hyperf\Utils\Codec\Json;class BaiduTranslator
{#[Inject]private ClientFactory $clientFactory;#[Inject]private HtmlParser $htmlParser;public function translate(string $html): string{// 1. 提取需要翻譯的文本節點$textNodes = $this->htmlParser->extractTextNodes($html);if (empty($textNodes)) {return $html;}// 2. 提取純文本內容用于翻譯$texts = array_column($textNodes, 'text');// 3. 分批翻譯文本$chunks = array_chunk($texts, config('translation.baidu.chunk_size', 30));$translatedChunks = [];foreach ($chunks as $chunk) {$translatedChunks[] = $this->translateChunk($chunk);}$translatedTexts = array_merge(...$translatedChunks);// 4. 將翻譯結果替換回HTMLreturn $this->htmlParser->replaceTranslatedText($textNodes, $translatedTexts);}private function translateChunk(array $texts): array{$client = $this->clientFactory->create();$appId = config('translation.baidu.appid');$secret = config('translation.baidu.secret');// 生成簽名$salt = time();$combinedText = implode("\n", $texts);$sign = md5($appId . $combinedText . $salt . $secret);// 構造請求參數$params = ['q' => $combinedText,'from' => 'zh','to' => 'en','appid' => $appId,'salt' => $salt,'sign' => $sign,'tag_handling' => '1', // 開啟HTML標簽處理'ignore_tags' => config('translation.baidu.ignore_tags', 'code,pre,script,style'),'preserve_tags' => config('translation.baidu.preserve_tags', 'p,div,span')];try {$response = $client->post(config('translation.baidu.api_url'), ['form_params' => $params,'timeout' => 15]);$result = Json::decode($response->getBody()->getContents());if (isset($result['error_code'])) {throw new \RuntimeException("百度翻譯錯誤: {$result['error_code']} - {$result['error_msg']}");}$translated = $result['trans_result'] ?? [];return array_map(function ($item) {return $item['dst'] ?? '';}, $translated);} catch (\Throwable $e) {// 記錄錯誤并返回原文logger()->error('百度翻譯失敗: ' . $e->getMessage(), ['texts' => $texts,'exception' => $e]);return $texts; // 返回原文作為降級處理}}
}
  1. 異步任務 app/Job/TranslateContentJob.php

declare(strict_types=1);namespace App\Job;use App\Model\Article;
use App\Service\BaiduTranslator;
use Hyperf\AsyncQueue\Job;class TranslateContentJob extends Job
{public int $articleId;public function __construct(int $articleId){$this->articleId = $articleId;}public function handle(){$article = Article::find($this->articleId);if (!$article) {logger()->warning("文章不存在: {$this->articleId}");return;}try {// 更新狀態為翻譯中$article->translation_status = Article::STATUS_PROCESSING;$article->save();// 執行翻譯$translator = make(BaiduTranslator::class);$enContent = $translator->translate($article->content);// 更新結果$article->en_content = $enContent;$article->translation_status = Article::STATUS_COMPLETED;$article->save();} catch (\Throwable $e) {$article->translation_status = Article::STATUS_FAILED;$article->save();logger()->error("文章翻譯失敗: {$e->getMessage()}", ['article_id' => $this->articleId,'exception' => $e]);}}
}
  1. 控制器 app/Controller/TranslationController.php
<?phpdeclare(strict_types=1);namespace App\Controller;use App\Job\TranslateContentJob;
use App\Model\Article;
use App\Service\BaiduTranslator;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Utils\ApplicationContext;/*** @AutoController()*/
class TranslationController
{#[Inject]private BaiduTranslator $translator;/*** 實時翻譯接口* * @PostMapping(path="/translate")*/public function translate(){$html = $this->request->post('content', '');if (empty($html)) {return $this->response->json(['code' => 400,'message' => '內容不能為空']);}try {$start = microtime(true);$translatedContent = $this->translator->translate($html);$time = round(microtime(true) - $start, 3);return $this->response->json(['code' => 0,'message' => '翻譯成功','data' => ['content' => $translatedContent,'time' => $time . 's']]);} catch (\Throwable $e) {return $this->response->json(['code' => 500,'message' => '翻譯失敗: ' . $e->getMessage()]);}}/*** 創建文章并異步翻譯* * @PostMapping(path="/article")*/public function createArticle(){$title = $this->request->post('title', '');$content = $this->request->post('content', '');if (empty($title) || empty($content)) {return $this->response->json(['code' => 400,'message' => '標題和內容不能為空']);}try {// 創建文章$article = Article::create(['title' => $title,'content' => $content,'translation_status' => Article::STATUS_PENDING]);// 加入翻譯隊列$queue = ApplicationContext::getContainer()->get(DriverFactory::class)->get('default');$queue->push(new TranslateContentJob($article->id));return $this->response->json(['code' => 0,'message' => '文章創建成功,翻譯任務已提交','data' => ['id' => $article->id,'translation_status' => $article->translation_status]]);} catch (\Throwable $e) {return $this->response->json(['code' => 500,'message' => '文章創建失敗: ' . $e->getMessage()]);}}/*** 查詢文章翻譯狀態* * @GetMapping(path="/article/status/{id}")*/public function getTranslationStatus($id){$article = Article::find($id);if (!$article) {return $this->response->json(['code' => 404,'message' => '文章不存在']);}$statusMap = [Article::STATUS_PENDING => '等待翻譯',Article::STATUS_PROCESSING => '翻譯中',Article::STATUS_COMPLETED => '翻譯完成',Article::STATUS_FAILED => '翻譯失敗'];return $this->response->json(['code' => 0,'data' => ['id' => $article->id,'status' => $article->translation_status,'status_text' => $statusMap[$article->translation_status] ?? '未知狀態','en_content' => $article->en_content]]);}
}
  1. 環境配置 .env
BAIDU_TRANSLATE_APPID=your_app_id
BAIDU_TRANSLATE_SECRET=your_secret_key

完結!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93234.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93234.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93234.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

字節跳動 VeOmni 框架開源:統一多模態訓練效率飛躍!

資料來源&#xff1a;火山引擎-開發者社區 多模態時代的訓練痛點&#xff0c;終于有了“特效藥” 當大模型從單一語言向文本 圖像 視頻的多模態進化時&#xff0c;算法工程師們的訓練流程卻陷入了 “碎片化困境”&#xff1a; 當業務要同時迭代 DiT、LLM 與 VLM時&#xff0…

配置docker pull走http代理

之前寫了一篇自建Docker鏡像加速器服務的博客&#xff0c;需要用到境外服務器作為代理&#xff0c;但是一般可能沒有境外服務器&#xff0c;只有http代理&#xff0c;所以如果本地使用想走代理可以用以下方式 臨時生效&#xff08;只對當前終端有效&#xff09; 設置環境變量…

OpenAI 開源模型 gpt-oss 本地部署詳細教程

OpenAI 最近發布了其首個開源的開放權重模型gpt-oss&#xff0c;這在AI圈引起了巨大的轟動。對于廣大開發者和AI愛好者來說&#xff0c;這意味著我們終于可以在自己的機器上&#xff0c;完全本地化地運行和探索這款強大的模型了。 本教程將一步一步指導你如何在Windows和Linux…

力扣-5.最長回文子串

題目鏈接 5.最長回文子串 class Solution {public String longestPalindrome(String s) {boolean[][] dp new boolean[s.length()][s.length()];int maxLen 0;String str s.substring(0, 1);for (int i 0; i < s.length(); i) {dp[i][i] true;}for (int len 2; len …

Apache Ignite超時管理核心組件解析

這是一個非常關鍵且設計精巧的 定時任務與超時管理組件 —— GridTimeoutProcessor&#xff0c;它是 Apache Ignite 內核中負責 統一調度和處理所有異步超時事件的核心模塊。&#x1f3af; 一、核心職責統一管理所有需要“在某個時間點觸發”的任務或超時邏輯。它相當于 Ignite…

DAY 42 Grad-CAM與Hook函數

知識點回顧回調函數lambda函數hook函數的模塊鉤子和張量鉤子Grad-CAM的示例# 定義一個存儲梯度的列表 conv_gradients []# 定義反向鉤子函數 def backward_hook(module, grad_input, grad_output):# 模塊&#xff1a;當前應用鉤子的模塊# grad_input&#xff1a;模塊輸入的梯度…

基于 NVIDIA 生態的 Dynamo 風格分布式 LLM 推理架構

網羅開發&#xff08;小紅書、快手、視頻號同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企業從事人工智能項目研發管理工作&#xff0c;平時熱衷于分享各種編程領域的軟硬技能知識以及前沿技術&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

《吃透 C++ 類和對象(中):拷貝構造函數與賦值運算符重載深度解析》

&#x1f525;個人主頁&#xff1a;草莓熊Lotso &#x1f3ac;作者簡介&#xff1a;C研發方向學習者 &#x1f4d6;個人專欄&#xff1a; 《C語言》 《數據結構與算法》《C語言刷題集》《Leetcode刷題指南》 ??人生格言&#xff1a;生活是默默的堅持&#xff0c;毅力是永久的…

Python 環境隔離實戰:venv、virtualenv 與 conda 的差異與最佳實踐

那天把項目部署到測試環境&#xff0c;結果依賴沖突把服務拉崩了——本地能跑&#xff0c;線上不能跑。折騰半天才發現&#xff1a;我和同事用的不是同一套 site-packages&#xff0c;版本差異導致運行時異常。那一刻我徹底明白&#xff1a;虛擬環境不是可選項&#xff0c;它是…

[ 數據結構 ] 時間和空間復雜度

1.算法效率算法效率分析分為兩種 : ①時間效率, ②空間效率 時間效率即為 時間復雜度 , 時間復雜度主要衡量一個算法的運行速度空間效率即為 空間復雜度 , 空間復雜度主要衡量一個算法所需要的額外空間2.時間復雜度2.1 時間復雜度的概念定義 : 再計算機科學中 , 算法的時間復雜…

一,設計模式-單例模式

目的設計單例模式的目的是為了解決兩個問題&#xff1a;保證一個類只有一個實例這種需求是需要控制某些資源的共享權限&#xff0c;比如文件資源、數據庫資源。為該實例提供一個全局訪問節點相較于通過全局變量保存重要的共享對象&#xff0c;通過一個封裝的類對象&#xff0c;…

AIStarter修復macOS 15兼容問題:跨平臺AI項目管理新體驗

AIStarter是全網唯一支持Windows、Mac和Linux的AI管理平臺&#xff0c;為開發者提供便捷的AI項目管理體驗。近期&#xff0c;熊哥在視頻中分享了針對macOS 15系統無法打開AIStarter的修復方案&#xff0c;最新版已完美兼容。本文基于視頻內容&#xff0c;詳解修復細節與使用技巧…

LabVIEW 紡織檢測數據傳遞

基于 LabVIEW 實現紡織檢測系統中上位機&#xff08;PC 機&#xff09;與下位機&#xff08;單片機&#xff09;的串口數據傳遞&#xff0c;成功應用于煮繭機溫度測量系統。通過采用特定硬件架構與軟件設計&#xff0c;實現了溫度數據的高效采集、傳輸與分析&#xff0c;操作簡…

ECCV-2018《Variational Wasserstein Clustering》

核心思想 該論文提出了一個基于最優傳輸(optimal transportation) 理論的新型聚類方法&#xff0c;稱為變分Wasserstein聚類(Variational Wasserstein Clustering, VWC)。其核心思想有三點&#xff1a;建立最優傳輸與k-means聚類的聯系&#xff1a;作者指出k-means聚類問題本質…

部署 Docker 應用詳解(MySQL + Tomcat + Nginx + Redis)

文章目錄一、MySQL二、Tomcat三、Nginx四、Redis一、MySQL 搜索 MySQL 鏡像下載 MySQL 鏡像創建 MySQL 容器 docker run -i -t/d -p 3307:3306 --namec_mysql -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD123456 m…

VR全景導覽在大型活動中的應用實踐:優化觀眾體驗與現場管理

大型演出賽事往往吸引海量觀眾&#xff0c;但復雜的場館環境常帶來諸多困擾&#xff1a;如何快速找到座位看臺區域&#xff1f;停車位如何規劃&#xff1f;附近公交地鐵站在哪&#xff1f;這些痛點直接影響觀眾體驗與現場秩序。VR全景技術為解決這些問題提供了有效方案。通過在…

OpenJDK 17 JIT編譯器堆棧分析

##堆棧(gdb) bt #0 PhaseOutput::safepoint_poll_table (this0x7fffd0bfb950) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/output.hpp:173 #1 0x00007ffff689634e in PhaseOutput::fill_buffer (this0x7fffd0bfb950, cb0x7fffd0bfb970, blk_starts0x7fffb0…

功能測試中常見的面試題-二

二、測試設計與用例編寫題解釋等價類劃分 (Equivalence Partitioning) 和邊界值分析 (Boundary Value Analysis)&#xff1f;并舉例說明。等價類劃分 (EP)&#xff1a; 將輸入域劃分為若干組&#xff08;等價類&#xff09;&#xff0c;假設同一組內的數據對揭露程序錯誤具有等…

SOLi-LABS Page-4 (Challenges)--54-65關

sql-54 翻譯一下頁面&#xff0c;得知我們只有十次機會。id參數是單引號閉合。 ?id-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schemadatabase()-- 我得到的表名是igsyiz2p7z。&#xff08;每個人得到的應該都不一樣&#…

docker代碼如何在vscod上修改

基于 docker-compose.yml文件&#xff08;包含 ??emqx??&#xff08;MQTT服務&#xff09;、??backend??&#xff08;后端服務&#xff09;、??mysql??&#xff08;數據庫&#xff09;&#xff09;的詳細運行、調試、增改刪操作說明&#xff0c;結合流程圖示意&…