📌

選択範囲の英語をDenoを使って、みんなの自動翻訳@TexTra®のWeb APIで翻訳してみる

2022/11/27に公開

みんなの自動翻訳@TexTra®のWeb API

みんなの自動翻訳@TexTra®は、国立研究開発法人情報通信研究機構(NICT)が開発した自動翻訳サイトです。Web APIは、OAuthでアクセス認可を受ける形態で実装されています。ユーザ登録するとWeb APIでアクセスするためのアクセスキーなどが取得できます。

DenoでWeb APIにて翻訳

Node.js版プログラムソースコードはは公式で公開されていますが、学習のためDeno版に書き換えています。

利用例としては、Linux デスクトップのターミナル上でNu Shellのhelp saveの表示結果のSave a string to foo.txt in the current directoryをマウスで選択しておきます。この状態でNu Shell上で下記コマンド実行します。まずxselにより選択部分が標準出力に出力され、その内容の有効部分を選択して、今回のWeb API実行プログラムのrequest_textra.tsを動かします。request_textra.tsは翻訳結果を標準出力に出力します。

❯ xsel -o | last 1 | $in.0 | deno run --allow-env --allow-net request_textra.ts
カレントディレクトリのfoo.jsonにレコードを保存する

ソースコード

Web API詳細で得られる、API Key, API secretおよびユーザIDを環境変数に登録しておきます。Nu shellの場合,env.nuに登録しておきます。

let-env TEXTRA_API_KEY = "API Keyをここにペースト"
let-env TEXTRA_API_SECRET = "API secretをここにペースト"
let-env TEXTRA_LOGIN_NAME = "ユーザIDをここにペースト"

ソースコードは次のとおりです。とりあえず、動作しますが、何分初心者なんで参考までに。

// deno run --allow-env --allow-net

const env = Deno.env.toObject();
const decoder = new TextDecoder();

const url = "https://mt-auto-minhon-mlt.ucri.jgn-x.jp"; // 基底URL (https://xxx.jpまでを入力)
const key = env.TEXTRA_API_KEY; // API key
const secret = env.TEXTRA_API_SECRET; // API secret
const name = env.TEXTRA_LOGIN_NAME; // ログインID

const api_name = "mt"; // API名 (https://xxx.jp/api/mt/generalNT_ja_en/ の場合は、"mt")
const api_param = "generalNT_en_ja"; // API値 (https://xxx.jp/api/mt/generalNT_ja_en/ の場合は、"generalNT_ja_en")

let access_token = null;
/** fallbak text */
const input_text =
  "Deno (/ˈdiːnoʊ/, pronounced dee-no) is a JavaScript, TypeScript, and WebAssembly runtime with secure defaults and a great developer experience.";

let input_text_stdin = '';

for await (const chunk of Deno.stdin.readable) {
  const text = decoder.decode(chunk);
  input_text_stdin += text;
}

function request_token_endpoint(): Promise<Response> {
  // RFC 6749 (The OAuth 2.0 Authorization Framework)
  // https://darutk.medium.com/diagrams-and-movies-of-all-the-oauth-2-0-flows-194f3c3ade85
  // (1) Request To Token Endpoint
  const form_token_endpoint = new FormData();
  form_token_endpoint.append("grant_type", "client_credentials");
  /** Set API Key */
  form_token_endpoint.append("client_id", key);
  /** Set API secret */
  form_token_endpoint.append("client_secret", secret);
  /** Set Access token url */
  form_token_endpoint.append("urlAccessToken", url + "/oauth2/token.php");

  return fetch(url + "/oauth2/token.php", {
    method: "POST",
    body: form_token_endpoint,
  });
}

request_token_endpoint().then((response) => {
  if ((response) && (response.body)) {
    return response.body.getReader().read();
  } else {
    return Promise.reject(
      new Error(`Rresponse data from token endpointer is nil.`),
    );
  }
}).then((body_data) => {
  if (body_data) {
    const r = decoder.decode((body_data).value);
    access_token = JSON.parse(r).access_token;
    // // (2) Call API
    const form_api = new FormData();
    form_api.append("access_token", access_token);
    form_api.append("key", key);
    form_api.append("api_name", api_name);
    form_api.append("api_param", api_param);
    form_api.append("name", name);
    form_api.append("type", "json");
    form_api.append("text", input_text_stdin.trim() || input_text);
    return fetch(url + "/api/", {
      method: "POST",
      body: form_api,
    });
  } else {
    return Promise.reject(new Error(`API response body data is empty.`));
  }
}).then((response) => {
  if ((response) && (response.body)) {
    return response.body.getReader().read();
  } else {
    return Promise.reject(new Error(`API response body data is empty.`));
  }
}).then((body_data) => {
  if (body_data) {
    const r = decoder.decode((body_data).value);
    const api_result = JSON.parse(r).resultset.result.text;
    console.log(api_result);
  }
}).catch((e) => {
  console.log("Error:", e);
});

Tips

なぜか、fetch()で以下のようにheadersをつけるとうまく動作しなかった。bodyプロパティにFormDataを使うと"Content-Typemultipart/form-dataになるでしょうかね?いろいろ調べたんですが、わかりませんでした。

const response = await fetch("http://localhost:8080", {
    method: "POST",
    headers: { "Content-Type": "multipart/form-data" },
    body: form 
});

Discussion