マストドンのクライアントアプリに翻訳機能を追加するため、「みんなの自動翻訳」というAPIを見つけたので試してみた。
最初に実装結果
ただ書いた通り翻訳の精度がどれほどのものかは英語が読めないのでわからない。
今更だけどせっかくなので、ほかの翻訳サイトで試してみようと思い、threadsのwhitehouseのアカウントに行ったら削除されていた。 トランプ政権要職であるイーロンの商売敵だし、仕方ないとは言え、驚くべき仕事の速さ。
最後の投稿だけ残っていたのでそれで試してみる。
原文は下記の通り。
President Joe Biden, Vice President Kamala Harris, First Lady Jill Biden, and Second Gentleman Douglas Emhoff gather on the North Portico of the White House for the final time.
みんなの自動翻訳は
ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・トレーシー・ジェイコブズ大統領夫人、ダグラス・エンホフ第二紳士が、最後にホワイトハウスの北ポルティコに集まります。
DeepLは
ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・バイデン大統領夫人、ダグラス・エムホフ副大統領夫人がホワイトハウスの北ポルティコに集合。
Google翻訳は
ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・バイデン大統領夫人、ダグラス・エムホフ二等紳士が最後にホワイトハウスの北柱廊玄関に集まる。
ChatGPTは
ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・バイデン大統領夫人、ダグラス・エムホフセカンドジェントルマンが、ホワイトハウスの北ポルチコで最後の時間を共に過ごしました。
こうやってみるとChatGPTが圧倒的に良い翻訳だと思うけど、みんなの自動翻訳も意図は伝わるので問題はない。
みんなの自動翻訳とは?
自動翻訳をみんなで育てるサイトみんなの自動翻訳@TexTra®
話題のニューラル機械翻訳(NMT)、最新の自動翻訳研究に基づく、「高精度自動翻訳エンジン」とのこと。
つまり、テキストの翻訳を行う際に、従来のルールベースや統計的機械翻訳(SMT)と異なり、ニューラルネットワークを使って文脈や意味を考慮した高精度な翻訳を実現できるということらしい。
提供元は国立研究開発法人情報通信研究機構 先進的音声翻訳研究開発推進センターで公式サイトに行くと翻訳アプリとかもリリースしていた。全く知らなかったけど、国の研究でこんなことをしていたのかと驚いた。
特徴
- 一般的なWeb翻訳と同様、誰でも簡単にお使いいただけます。
- 日本語・英語・中国語・韓国語の4言語を中心に多言語に対応。
- ブログ・レシピ・エッセイ・新聞などの一般的な文章はもちろん、特許・論文・マニュアルなどの
- 専門分野の長文翻訳も得意です。
- 面倒なインストールは不要︕ 翻訳エディタのご利用が可能です。
- 翻訳をサポートする便利なツールが満載︕
- MS Word、Excel、PowerPoint上のテキストを自動翻訳するアドイン。
- Firefox、Thunderbird、Chrome上での自動翻訳、辞書引きのアドイン。
- Trados上での翻訳、辞書引き機能を提供するアドイン。
- TexTra Clipboard︓クリップボードにコピーしたテキストを翻訳するアプリ。
- 自動翻訳、辞書引き、用語検索、類似文検索の機能をWeb APIとして公開しています。
使用する上での注意点
アプリ作成する上で気になることを調べてみた。
- 商用利用は禁止
- 1日500回までのアクセス
上記を考えると本番運用は難しそうに感じる。 参考にDeepL API Freeは1ヶ月あたり50万文字まで無料とのこと。
ちなみに参考のDeepL API Freeとコスパで比較すると、マストドンの最大文字数500で計算で
- 1日500回までのアクセスの場合、1ヶ月で15,000回のリクエストが可能。
- 1ヶ月あたり50万文字の制限の場合、1ヶ月で1,000回のリクエストが可能。
なので「みんなの自動翻訳」のほうがコスパはいい。
DeepL API Freeは商用利用可能なので本番で運用するならこちらにする必要があるけど。
使い方
みんなの自動翻訳APIは認証が必要になる。
なのでサーバー側で叩いく必要がある。
丁寧にサンプルコード(PHP
、Node.js
、Python3
、Java
、C#
、VB
)があったので、それを参考にする。
サーバーを用意するのは面倒だったのでNext
のapp/api
でnodejs
を実行し、エンドポイントを作成した。
/app/api/translate/route.ts
を用意してそこに書く。
import { NextResponse } from "next/server";
export async function POST(req: Request) {
try {
const body = await req.json();
if (!body || !body.text) {
return NextResponse.json(
{ error: "Text is required for translation" },
{ status: 400 },
);
}
const { text } = body;
const url = "https://mt-auto-minhon-mlt.ucri.jgn-x.jp";
const key = "xxxxxxxxxxxxxxxxxx";
const secret = "xxxxxxxxxxxxxxxxxx";
const name = "xxxxxxxxxxxxxxxxxx";
const api_name = "mt";
const api_param = "generalNT_en_ja";
let access_token = null;
// アクセストークン取得
const tokenResponse = await fetch(`${url}/oauth2/token.php`, {
method: "POST",
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: key,
client_secret: secret,
}),
});
if (!tokenResponse.ok) {
throw new Error("Failed to fetch access token");
}
const tokenData = await tokenResponse.json();
access_token = tokenData.access_token;
if (!access_token) {
return NextResponse.json(
{ error: "Access token not found" },
{ status: 400 },
);
}
// APIリクエストの形式を修正
const apiResponse = await fetch(`${url}/api/`, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
access_token: access_token,
key: key, // API Key
api_name: api_name,
api_param: api_param,
name: name, // ログインID
type: "json", // レスポンスタイプ
text: text, // 翻訳テキスト
}),
});
if (!apiResponse.ok) {
throw new Error("API request failed");
}
const apiData = await apiResponse.json();
const response = NextResponse.json(apiData);
response.headers.set("Access-Control-Allow-Origin", "*");
response.headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.headers.set(
"Access-Control-Allow-Headers",
"Content-Type, Authorization",
);
return response;
} catch (error: unknown) {
// エラーがオブジェクトかどうかをチェック
if (error instanceof Error) {
const response = NextResponse.json(
{ error: `Error: ${error.message}` },
{ status: 500 },
);
response.headers.set("Access-Control-Allow-Origin", "*");
return response;
} else {
const response = NextResponse.json(
{ error: "Unknown error occurred" },
{ status: 500 },
);
response.headers.set("Access-Control-Allow-Origin", "*");
return response;
}
}
}
// OPTIONS メソッド対応
export async function OPTIONS() {
const response = new NextResponse(null, { status: 204 });
response.headers.set("Access-Control-Allow-Origin", "*");
response.headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.headers.set(
"Access-Control-Allow-Headers",
"Content-Type, Authorization",
);
return response;
}
特筆すべきこともないので、これでbuild
してbody
を持たせたうえでエンドポイントを叩けば期待する翻訳テキストが返却される。
言語の判定とか多言語用のAPIがどれかわからなかったので、それを使えばマストドンのStatus
をみて多言語対応もできそうな感じだった。