🙆‍♀️

Sunoのプロンプトが200文字までなので、DeepL API & 文字数カウンターを作ってみた

2024/10/31に公開

はじめに

DeepL API & 文字数カウンター
https://gist.github.com/sarap422/b2c0fdff98b14197cc7fd41541b5cf34

Sunoのプロンプトは200文字までという制限があります。長文を分割するのは手間がかかるので、文字数をカウントしながら翻訳できるツールを作ってみました。DeepL API Freeを使用することで、月50万文字まで無料で高精度な翻訳が利用できます。

DeepL API Freeの特徴

  • 月間50万文字まで無料
  • 高精度な機械翻訳
  • シンプルなAPI
  • 多言語対応(28言語以上)
  • セキュアな通信(HTTPS必須)

実装手順

1. DeepL API Freeのアカウント作成

  1. DeepL API Freeにアクセス
  2. アカウントを作成
  3. APIキーを取得(形式: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:fx

2. CORSの問題を解決するためのプロキシ作成

ブラウザから直接DeepL APIを呼び出すとCORSエラーが発生するため、PHPでプロキシを作成します。

<?php
// translation-proxy.php

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Type: application/json; charset=utf-8');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit();
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['error' => 'Method not allowed']);
    exit();
}

$json = file_get_contents('php://input');
$data = json_decode($json, true);

if (!isset($data['text']) || !isset($data['source_lang']) || 
    !isset($data['target_lang']) || !isset($data['api_key'])) {
    http_response_code(400);
    echo json_encode(['error' => 'Missing required parameters']);
    exit();
}

$url = 'https://api-free.deepl.com/v2/translate';
$params = http_build_query([
    'text' => $data['text'],
    'source_lang' => $data['source_lang'],
    'target_lang' => $data['target_lang']
]);

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL => $url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $params,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: DeepL-Auth-Key ' . $data['api_key'],
        'Content-Type: application/x-www-form-urlencoded'
    ],
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_TIMEOUT => 30
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    http_response_code(500);
    echo json_encode(['error' => 'Curl error: ' . curl_error($ch)]);
    curl_close($ch);
    exit();
}

curl_close($ch);
http_response_code($httpCode);
echo $response;

3. フロントエンド実装

HTMLでUIを作成し、JavaScriptで文字数カウントと翻訳機能を実装します。

<div class="translation-container">
  <div class="api-key-section">
    <label for="api-key">DeepL API Key:</label>
    <input type="text" id="api-key">
  </div>

  <div class="language-selection">
    <select id="source-lang">
      <option value="JA">日本語</option>
      <option value="EN">英語</option>
      <option value="IT">イタリア語</option>
      <option value="FR">フランス語</option>
    </select><select id="target-lang">
      <option value="EN">英語</option>
      <option value="JA">日本語</option>
      <option value="IT">イタリア語</option>
      <option value="FR">フランス語</option>
    </select>
  </div>

  <textarea id="input-text" placeholder="ここにテキストを入力"></textarea>
  
  <div id="count">
    半角文字換算:0文字<br>
    全角文字換算:0文字<br>
    DeepL API Free 残り文字数:500,000文字
  </div>

  <button id="translate-button">翻訳</button>
  <div id="translation-result"></div>
  <div id="error-message"></div>
</div>

4. 主要な機能の実装

// 文字数カウント機能
function countCharacters(text) {
  let fullWidthCount = 0;
  let halfWidthCount = 0;
  for (let char of text) {
    if (char.match(/[^\x00-\xff]/)) {  // 全角文字の判定
      fullWidthCount += 1;
      halfWidthCount += 2;
    } else {
      halfWidthCount += 1;
      fullWidthCount += 0.5;
    }
  }
  return { halfWidth: halfWidthCount, fullWidth: fullWidthCount };
}

// 翻訳機能
async function translateText() {
  // APIキーと入力テキストの取得
  const apiKey = document.getElementById('api-key').value.trim();
  const text = document.getElementById('input-text').value.trim();
  
  // バリデーション
  if (!apiKey || !text) return;

  try {
    const response = await fetch('/path/to/translation-proxy.php', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        text,
        source_lang: document.getElementById('source-lang').value,
        target_lang: document.getElementById('target-lang').value,
        api_key: apiKey
      })
    });

    const data = await response.json();
    if (data.translations) {
      showTranslation(data.translations[0].text);
    }
  } catch (error) {
    showError(error.message);
  }
}

実装のポイント

  1. 文字数カウント

    • 全角/半角を区別してカウント
    • リアルタイムでの更新
    • 月間制限(50万文字)との比較
  2. セキュリティ対策

    • APIキーの保護(プロキシ経由)
    • XSS対策
    • 入力値のバリデーション
  3. UX向上

    • エラーメッセージの表示
    • ローディング状態の表示
    • APIキーの保存(LocalStorage)
  4. 保守性

    • モジュール化されたコード
    • エラーハンドリング
    • コメントによる説明

カスタマイズのヒント

  1. 追加可能な機能

    • 翻訳履歴の保存
    • 文字数制限のアラート
    • ショートカットキー
    • 翻訳結果のコピー機能
  2. スタイリング

    • レスポンシブデザイン
    • ダークモード対応
    • アニメーション効果

注意点

  • DeepL API Freeの利用制限(月間50万文字)を超えないよう注意
  • APIキーは適切に管理(環境変数やconfig管理推奨)
  • プロキシファイルのパーミッション設定に注意
  • HTTPS環境での運用推奨

まとめ

DeepL API Freeを使用することで、高品質な翻訳機能を無料で利用できます。文字数カウンターと組み合わせることで、制限を意識しながら効率的に翻訳作業を行えます。

また、このコードはGitHubで公開されているDeepLの公式クライアントライブラリと互換性があり、必要に応じて拡張することも可能です。

参考リンク

Discussion