Skip to content

Conversation

@tegnike
Copy link
Owner

@tegnike tegnike commented Dec 10, 2024

Summary by CodeRabbit

  • 新機能

    • NijiVoiceサービスのための新しい環境変数が追加されました。
    • アプリケーションにNijiVoiceの音声合成機能が統合されました。
    • 言語選択にNijiVoiceが追加され、音声設定が可能になりました。
    • NijiVoice APIを使用するための新しいAPIエンドポイントが実装されました。
  • バグ修正

    • なし
  • ドキュメント

    • 日本語、韓国語、中国語の翻訳ファイルにNijiVoice関連のエントリが追加されました。
  • チョア

    • 設定ストアにNijiVoice関連の新しいプロパティが追加されました。

@vercel
Copy link

vercel bot commented Dec 10, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
aituber-kit ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 10, 2024 11:15pm

@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2024

Walkthrough

このプルリクエストでは、NijiVoiceサービスに関連する新しい環境変数とローカリゼーションエントリが追加されました。具体的には、.env.env.exampleファイルに新しい変数が追加され、複数の言語の翻訳ファイルにNijiVoice関連のキーが追加されています。また、NijiVoiceの音声選択機能を実装するために、いくつかのコンポーネントとAPIハンドラーが変更されました。これにより、NijiVoiceサービスの設定と利用が可能になります。

Changes

ファイルパス 変更概要
.env, .env.example 新しい環境変数 NIJIVOICE_API_KEY, NEXT_PUBLIC_NIJIVOICE_ACTOR_ID, NEXT_PUBLIC_NIJIVOICE_SPEED を追加
locales/en/translation.json, locales/ja/translation.json, locales/ko/translation.json, locales/zh/translation.json NijiVoice関連の新しい翻訳キーを追加: UsingNijiVoice, NijiVoiceInfo, NijiVoiceApiKey, NijiVoiceActorId, NijiVoiceSpeed
src/components/settings/based.tsx 言語選択ロジックに nijivoice オプションを追加
src/components/settings/voice.tsx NijiVoiceの音声選択機能を追加し、APIキー、アクターID、速度の状態管理を実装
src/features/constants/settings.ts AIVoice 型に nijivoice を追加
src/features/messages/speakCharacter.ts createSpeakCharacter 関数にNijiVoice用の条件分岐を追加
src/features/messages/synthesizeVoiceNijivoice.ts 新しい非同期関数 synthesizeVoiceNijivoiceApi を追加
src/features/stores/settings.ts ModelProvider インターフェースに新しいプロパティを追加: nijivoiceApiKey, nijivoiceActorId, nijivoiceSpeed
src/pages/api/get-nijivoice-actors.ts NijiVoiceの声優を取得する新しいAPIハンドラーを追加
src/pages/api/tts-nijivoice.ts NijiVoiceを使用したTTS機能のための新しいAPIハンドラーを追加

Possibly related PRs


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Experiment)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (6)
src/pages/api/get-nijivoice-actors.ts (1)

14-24: パフォーマンスとエラーハンドリングの改善が必要です

  1. レスポンスのキャッシュ
  2. タイムアウトの設定
  3. より詳細なエラーメッセージ

以下の修正を提案します:

 try {
+  const controller = new AbortController();
+  const timeoutId = setTimeout(() => controller.abort(), 5000);
+
   const response = await fetch(
     'https://api.nijivoice.com/api/platform/v1/voice-actors',
     {
       headers: {
         'x-api-key': nijivoiceApiKey as string,
+        'Cache-Control': 'public, max-age=300',
       },
+      signal: controller.signal,
     }
   )
+  clearTimeout(timeoutId);
+
+  if (!response.ok) {
+    throw new Error(`HTTP error! status: ${response.status}`);
+  }
   const data = await response.json()
   return res.status(200).json(data)
src/features/messages/synthesizeVoiceNijivoice.ts (1)

9-36: エラーハンドリングの改善が必要です

  1. 再試行メカニズムの追加
  2. より具体的なエラーメッセージ
  3. i18n対応

以下の修正を提案します:

+const MAX_RETRIES = 3;
+const RETRY_DELAY = 1000;
+
+async function delay(ms: number) {
+  return new Promise(resolve => setTimeout(resolve, ms));
+}
+
 export async function synthesizeVoiceNijivoiceApi(
   talk: Talk,
   apiKey: string,
   voiceActorId: string,
   speed: number
 ) {
+  let attempts = 0;
   try {
-    const res = await fetch('/api/tts-nijivoice', {
-      method: 'POST',
+    while (attempts < MAX_RETRIES) {
+      try {
+        const res = await fetch('/api/tts-nijivoice', {
+          method: 'POST',
...
+        return await res.arrayBuffer();
+      } catch (error) {
+        attempts++;
+        if (attempts === MAX_RETRIES) throw error;
+        await delay(RETRY_DELAY * attempts);
+      }
+    }
-    return await res.arrayBuffer()
   } catch (error) {
     if (error instanceof Error) {
-      throw new Error(`Nijivoiceでエラーが発生しました: ${error.message}`)
+      throw new Error(`音声合成中にエラーが発生しました: ${error.message}`)
     } else {
-      throw new Error('Nijivoiceで不明なエラーが発生しました')
+      throw new Error('音声合成中に予期せぬエラーが発生しました')
     }
   }
 }
.env.example (1)

88-92: 環境変数の追加についてドキュメント改善の提案

NijiVoice関連の環境変数が適切に追加されていますが、以下の改善を提案します:

  1. 各変数の期待される値や形式について説明を追加
  2. NEXT_PUBLIC_NIJIVOICE_SPEEDの有効な範囲を明記

以下のような形でコメントを追加することを提案します:

 # NijiVoice
-NIJIVOICE_API_KEY=
+# APIキー(必須)
+NIJIVOICE_API_KEY=""
-NEXT_PUBLIC_NIJIVOICE_ACTOR_ID=
+# アクターID(必須)
+NEXT_PUBLIC_NIJIVOICE_ACTOR_ID=""
-NEXT_PUBLIC_NIJIVOICE_SPEED=
+# 音声の速度(オプション、デフォルト: 1.0、範囲: 0.5-2.0)
+NEXT_PUBLIC_NIJIVOICE_SPEED=""
src/features/stores/settings.ts (1)

257-262: 速度パラメータの検証を追加することを推奨します。

現在の実装では、nijivoiceSpeedのパース失敗時のフォールバック処理は実装されていますが、有効な範囲の検証が行われていません。

以下のような検証ロジックの追加を提案します:

  nijivoiceSpeed:
-   parseFloat(process.env.NEXT_PUBLIC_NIJIVOICE_SPEED || '1.0') || 1.0,
+   (() => {
+     const speed = parseFloat(process.env.NEXT_PUBLIC_NIJIVOICE_SPEED || '1.0') || 1.0;
+     return Math.max(0.5, Math.min(2.0, speed)); // 一般的なTTS速度の範囲に制限
+   })(),
src/components/settings/voice.tsx (2)

854-859: 話者データの型安全性が必要です

any型の使用を避け、話者データの型を明示的に定義することを推奨します。

以下の実装を提案します:

interface NijiVoiceActor {
  id: string;
  name: string;
}

const [nijivoiceSpeakers, setNijivoiceSpeakers] = useState<NijiVoiceActor[]>([]);

// マッピング部分の修正
{nijivoiceSpeakers.map((actor: NijiVoiceActor) => (
  <option key={actor.id} value={actor.id}>
    {actor.name}
  </option>
))}

825-879: UIのエラー状態とローディング状態の表示が必要です

ユーザー体験を向上させるため、話者一覧の取得状態をUIに反映することを推奨します。

以下のような条件付きレンダリングの追加を提案します:

 <div className="mt-8">
+  {isLoading && (
+    <div className="text-warning">読み込み中...</div>
+  )}
+  {error && (
+    <div className="text-error">{error}</div>
+  )}
   <select
     value={nijivoiceActorId}
     onChange={(e) => {
       settingsStore.setState({
         nijivoiceActorId: e.target.value,
       })
     }}
     className="px-16 py-8 bg-surface1 hover:bg-surface1-hover rounded-8"
+    disabled={isLoading}
   >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3ce77ad and 463ac1f.

📒 Files selected for processing (14)
  • .env (1 hunks)
  • .env.example (1 hunks)
  • locales/en/translation.json (1 hunks)
  • locales/ja/translation.json (1 hunks)
  • locales/ko/translation.json (1 hunks)
  • locales/zh/translation.json (1 hunks)
  • src/components/settings/based.tsx (1 hunks)
  • src/components/settings/voice.tsx (4 hunks)
  • src/features/constants/settings.ts (1 hunks)
  • src/features/messages/speakCharacter.ts (2 hunks)
  • src/features/messages/synthesizeVoiceNijivoice.ts (1 hunks)
  • src/features/stores/settings.ts (3 hunks)
  • src/pages/api/get-nijivoice-actors.ts (1 hunks)
  • src/pages/api/tts-nijivoice.ts (1 hunks)
🔇 Additional comments (9)
src/features/constants/settings.ts (1)

38-38: AIVoiceタイプへのnijivoiceの追加を承認します

変更は適切に実装されていますが、以下の点を確認することをお勧めします。

✅ Verification successful

nijivoiceの実装が適切に行われていることを確認しました

voice.tsxコンポーネントにnijivoiceのオプションが正しく実装され、必要な設定項目(APIキー、話者ID、速度など)も適切に組み込まれています。また、関連するAPI実装やストア設定も整っています。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: voice選択UIコンポーネントでnijivoiceが適切に処理されているか確認

# Test: Check if nijivoice is properly handled in voice selection components
rg -l "AIVoice.*nijivoice" src/components/

Length of output: 44


Script:

#!/bin/bash
# Search for voice selection related components and their usage of AIVoice
rg -A 5 "AIVoice" src/components/ src/features/

Length of output: 2448


Script:

#!/bin/bash
# Search for any nijivoice related implementations
rg "nijivoice" src/

Length of output: 3533


Script:

#!/bin/bash
# Find voice selection related components
fd "voice" src/components/

Length of output: 60

.env (1)

88-92: 環境変数の追加が.env.exampleと一致していることを確認

.env.exampleファイルと同様の変更が適切に実装されています。変数の配置と形式が一貫しており、問題ありません。

src/components/settings/based.tsx (1)

66-67: 実装は適切です!

日本語専用のTTSサービスとしてNijiVoiceを他の日本語TTSサービス(voicevox、koeiromap、aivis_speech)と同様に扱う実装になっています。非日本語が選択された場合、適切にGoogleTTSに切り替わります。

src/features/messages/speakCharacter.ts (1)

18-18: 実装は論理的で一貫性があります!

NijiVoice TTSの実装が他のTTSサービスと同様のパターンで実装されており、以下の点で適切です:

  • 必要なパラメータ(apiKey、actorId、speed)が正しく渡されている
  • 既存のエラーハンドリング機構を活用している
  • コードの構造が他のTTSサービスと統一されている

Also applies to: 125-131

locales/zh/translation.json (2)

67-71: 翻訳の追加は適切です!

NijiVoice関連の翻訳が以下の点で適切に実装されています:

  • 他のTTSサービスと同様の翻訳キー構造を維持
  • 必要なUI要素(APIキー、話者ID、速度)の翻訳を網羅
  • 既存の翻訳スタイルとフォーマットに準拠

67-71: 他の言語ファイルでの翻訳の存在を確認してください

全ての言語ファイルで同じNijiVoice関連の翻訳キーが実装されていることを確認します。

✅ Verification successful

NijiVoice関連の翻訳キーは全ての言語ファイルで正しく実装されています

検証の結果、以下のNijiVoice関連の翻訳キーが全ての言語ファイル(en, ja, ko, zh)で適切に実装されていることを確認しました:

  • UsingNijiVoice
  • NijiVoiceInfo
  • NijiVoiceApiKey
  • NijiVoiceActorId
  • NijiVoiceSpeed
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 全言語ファイルでNijiVoice関連の翻訳キーの存在を確認

echo "Checking NijiVoice translations in all language files..."
for key in "UsingNijiVoice" "NijiVoiceInfo" "NijiVoiceApiKey" "NijiVoiceActorId" "NijiVoiceSpeed"; do
  echo "\nChecking key: $key"
  rg "\"$key\":" locales/
done

Length of output: 2663

locales/ja/translation.json (1)

67-71: にじボイス関連の翻訳が適切に追加されています!

翻訳の内容が明確で、他のTTSサービスの翻訳と一貫性が保たれています。

locales/ko/translation.json (1)

67-71: 韓国語の翻訳が適切に実装されています!

日本語版と同じ構造を保ちながら、適切に韓国語に翻訳されています。

src/features/stores/settings.ts (1)

74-76: ModelProviderインターフェースの拡張が適切に実装されています!

にじボイスの設定に必要な型定義が他のTTSサービスと同様のパターンで追加されています。

Comment on lines +7 to +12
const { apiKey } = req.query

const nijivoiceApiKey = apiKey || process.env.NIJIVOICE_API_KEY
if (!nijivoiceApiKey) {
return res.status(400).json({ error: 'API key is required' })
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

API キーの検証を強化する必要があります

API キーのフォーマット検証を追加することで、不正なリクエストを早期に検出できます。

以下の修正を提案します:

 const { apiKey } = req.query
 
 const nijivoiceApiKey = apiKey || process.env.NIJIVOICE_API_KEY
 if (!nijivoiceApiKey) {
   return res.status(400).json({ error: 'API key is required' })
 }
+if (typeof nijivoiceApiKey !== 'string' || !nijivoiceApiKey.match(/^[A-Za-z0-9-_]+$/)) {
+  return res.status(400).json({ error: 'Invalid API key format' })
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { apiKey } = req.query
const nijivoiceApiKey = apiKey || process.env.NIJIVOICE_API_KEY
if (!nijivoiceApiKey) {
return res.status(400).json({ error: 'API key is required' })
}
const { apiKey } = req.query
const nijivoiceApiKey = apiKey || process.env.NIJIVOICE_API_KEY
if (!nijivoiceApiKey) {
return res.status(400).json({ error: 'API key is required' })
}
if (typeof nijivoiceApiKey !== 'string' || !nijivoiceApiKey.match(/^[A-Za-z0-9-_]+$/)) {
return res.status(400).json({ error: 'Invalid API key format' })
}

Comment on lines +3 to +8
export async function synthesizeVoiceNijivoiceApi(
talk: Talk,
apiKey: string,
voiceActorId: string,
speed: number
) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

入力パラメータの検証が必要です

パラメータの型と値の検証を追加することで、より堅牢な実装になります。

以下の修正を提案します:

 export async function synthesizeVoiceNijivoiceApi(
   talk: Talk,
   apiKey: string,
   voiceActorId: string,
   speed: number
 ) {
+  if (!talk?.message) {
+    throw new Error('メッセージが必要です');
+  }
+  if (speed < 0.5 || speed > 2.0) {
+    throw new Error('速度は0.5から2.0の間で指定してください');
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function synthesizeVoiceNijivoiceApi(
talk: Talk,
apiKey: string,
voiceActorId: string,
speed: number
) {
export async function synthesizeVoiceNijivoiceApi(
talk: Talk,
apiKey: string,
voiceActorId: string,
speed: number
) {
if (!talk?.message) {
throw new Error('メッセージが必要です');
}
if (speed < 0.5 || speed > 2.0) {
throw new Error('速度は0.5から2.0の間で指定してください');
}

Comment on lines +39 to +45
const audioResponse = await axios.get(audioUrl, {
responseType: 'stream',
timeout: 30000,
})

res.setHeader('Content-Type', 'audio/mpeg')
audioResponse.data.pipe(res)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

ストリーミングの改善が必要です

  1. メモリリークの防止
  2. エラーハンドリングの追加
  3. Content-Length ヘッダーの設定

以下の修正を提案します:

-    const audioResponse = await axios.get(audioUrl, {
-      responseType: 'stream',
-      timeout: 30000,
-    })
-
-    res.setHeader('Content-Type', 'audio/mpeg')
-    audioResponse.data.pipe(res)
+    const audioResponse = await axios.get(audioUrl, {
+      responseType: 'arraybuffer',
+      timeout: 30000,
+    })
+
+    res.setHeader('Content-Type', 'audio/mpeg')
+    res.setHeader('Content-Length', audioResponse.data.length)
+    res.send(audioResponse.data)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const audioResponse = await axios.get(audioUrl, {
responseType: 'stream',
timeout: 30000,
})
res.setHeader('Content-Type', 'audio/mpeg')
audioResponse.data.pipe(res)
const audioResponse = await axios.get(audioUrl, {
responseType: 'arraybuffer',
timeout: 30000,
})
res.setHeader('Content-Type', 'audio/mpeg')
res.setHeader('Content-Length', audioResponse.data.length)
res.send(audioResponse.data)

Comment on lines +13 to +18
const { script, speed, voiceActorId, apiKey } = req.body

const nijivoiceApiKey = apiKey || process.env.NIJIVOICE_API_KEY
if (!nijivoiceApiKey) {
return res.status(400).json({ error: 'API key is required' })
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

リクエストボディの検証が必要です

入力パラメータの存在チェックと型チェックを追加することで、より安全な実装になります。

以下の修正を提案します:

-  const { script, speed, voiceActorId, apiKey } = req.body
+  const { script, speed, voiceActorId, apiKey } = req.body
+
+  if (!script || typeof script !== 'string') {
+    return res.status(400).json({ error: 'スクリプトが必要です' })
+  }
+  if (!voiceActorId || typeof voiceActorId !== 'string') {
+    return res.status(400).json({ error: 'ボイスアクターIDが必要です' })
+  }
+  if (typeof speed !== 'number' || speed < 0.5 || speed > 2.0) {
+    return res.status(400).json({ error: '速度は0.5から2.0の間で指定してください' })
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { script, speed, voiceActorId, apiKey } = req.body
const nijivoiceApiKey = apiKey || process.env.NIJIVOICE_API_KEY
if (!nijivoiceApiKey) {
return res.status(400).json({ error: 'API key is required' })
}
const { script, speed, voiceActorId, apiKey } = req.body
if (!script || typeof script !== 'string') {
return res.status(400).json({ error: 'スクリプトが必要です' })
}
if (!voiceActorId || typeof voiceActorId !== 'string') {
return res.status(400).json({ error: 'ボイスアクターIDが必要です' })
}
if (typeof speed !== 'number' || speed < 0.5 || speed > 2.0) {
return res.status(400).json({ error: '速度は0.5から2.0の間で指定してください' })
}
const nijivoiceApiKey = apiKey || process.env.NIJIVOICE_API_KEY
if (!nijivoiceApiKey) {
return res.status(400).json({ error: 'API key is required' })
}

Comment on lines +46 to +49
} catch (error) {
console.error('Error in Nijivoice TTS:', error)
res.status(500).json({ error: 'Internal Server Error' })
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

エラーハンドリングの標準化が必要です

エラーレスポンスの形式を統一し、より詳細な情報を提供することで、デバッグが容易になります。

以下の修正を提案します:

   } catch (error) {
-    console.error('Error in Nijivoice TTS:', error)
-    res.status(500).json({ error: 'Internal Server Error' })
+    console.error('NijivoiceのTTSでエラーが発生:', error)
+    if (axios.isAxiosError(error)) {
+      const status = error.response?.status || 500
+      const message = error.response?.data?.message || 'サーバーエラーが発生しました'
+      return res.status(status).json({
+        error: message,
+        code: error.code,
+        details: process.env.NODE_ENV === 'development' ? error.message : undefined
+      })
+    }
+    res.status(500).json({
+      error: '予期せぬエラーが発生しました',
+      details: process.env.NODE_ENV === 'development' ? String(error) : undefined
+    })
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (error) {
console.error('Error in Nijivoice TTS:', error)
res.status(500).json({ error: 'Internal Server Error' })
}
} catch (error) {
console.error('NijivoiceのTTSでエラーが発生:', error)
if (axios.isAxiosError(error)) {
const status = error.response?.status || 500
const message = error.response?.data?.message || 'サーバーエラーが発生しました'
return res.status(status).json({
error: message,
code: error.code,
details: process.env.NODE_ENV === 'development' ? error.message : undefined
})
}
res.status(500).json({
error: '予期せぬエラーが発生しました',
details: process.env.NODE_ENV === 'development' ? String(error) : undefined
})
}

Comment on lines +67 to +71
"UsingNijiVoice": "NijiVoice",
"NijiVoiceInfo": "NijiVoice API is used. It supports only Japanese. API key can be obtained from the URL below.",
"NijiVoiceApiKey": "NijiVoice API Key",
"NijiVoiceActorId": "NijiVoice Actor ID",
"NijiVoiceSpeed": "NijiVoice Speed",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

にじボイスのAPIキー取得URLの追加が必要です

NijiVoiceInfoの翻訳文で「下記のURL」と記載されていますが、実際のURLが定義されていません。ElevenLabsなど他の音声サービスと同様に、APIキー取得用の具体的なURLを追加する必要があります。以下の2点の対応をお願いします:

  • NijiVoiceInfoの文言から「下記のURL」という記述を削除するか、
  • APIキー取得用のURLを示す新しいキーを追加する
🔗 Analysis chain

APIキー取得用URLの追加が必要です

NijiVoiceInfoの翻訳文に「URL below」という記述がありますが、実際のURLが提供されていません。他の音声サービスと同様に、APIキーを取得するための具体的なURLを追加することを推奨します。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 他の音声サービスのURL参照パターンを確認
rg -A 1 "url=\"http" locales/

Length of output: 30


Script:

#!/bin/bash
# Search for URL patterns in translation files
rg -i "url" locales/

# Also check for any existing voice service related URLs
rg -i "voice.*url|url.*voice" locales/

Length of output: 4129


Script:

#!/bin/bash
# Search for any URL key-value pairs in the translation files
rg -i "\".*url\".*:.*\"http" locales/

# Also check for any URL references in the codebase related to NijiVoice
rg -i "nijivoice.*url|url.*nijivoice" .

Length of output: 546

Comment on lines +62 to +80
const [nijivoiceSpeakers, setNijivoiceSpeakers] = useState<Array<any>>([])

// にじボイスの話者一覧を取得する関数
const fetchNijivoiceSpeakers = async () => {
try {
const response = await fetch(
`/api/get-nijivoice-actors?apiKey=${nijivoiceApiKey}`
)
const data = await response.json()
if (data.voiceActors) {
const sortedActors = data.voiceActors.sort(
(a: any, b: any) => a.id - b.id
)
setNijivoiceSpeakers(sortedActors)
}
} catch (error) {
console.error('Failed to fetch nijivoice speakers:', error)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

ローディング状態とエラー状態の管理が必要です

話者一覧の取得中やエラー発生時のユーザー体験を改善するため、ローディング状態とエラー状態の管理を追加することを推奨します。

以下の実装を提案します:

const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);

const fetchNijivoiceSpeakers = async () => {
  setIsLoading(true);
  setError(null);
  try {
    const response = await fetch('/api/get-nijivoice-actors', {
      headers: {
        'Authorization': `Bearer ${nijivoiceApiKey}`
      }
    });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    if (data.voiceActors) {
      const sortedActors = data.voiceActors.sort(
        (a: any, b: any) => a.id - b.id
      );
      setNijivoiceSpeakers(sortedActors);
    }
  } catch (error) {
    console.error('Failed to fetch nijivoice speakers:', error);
    setError(t('Errors.TTSServiceError', { 
      serviceName: 'NijiVoice',
      message: error instanceof Error ? error.message : String(error)
    }));
  } finally {
    setIsLoading(false);
  }
};

Comment on lines +67 to +69
const response = await fetch(
`/api/get-nijivoice-actors?apiKey=${nijivoiceApiKey}`
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

APIキーをURLパラメータとして送信することは安全ではありません

APIキーをURLパラメータとして送信すると、サーバーログやブラウザ履歴に記録される可能性があります。代わりにAuthorizationヘッダーを使用することを推奨します。

以下の修正を提案します:

-      const response = await fetch(
-        `/api/get-nijivoice-actors?apiKey=${nijivoiceApiKey}`
-      )
+      const response = await fetch('/api/get-nijivoice-actors', {
+        headers: {
+          'Authorization': `Bearer ${nijivoiceApiKey}`
+        }
+      })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const response = await fetch(
`/api/get-nijivoice-actors?apiKey=${nijivoiceApiKey}`
)
const response = await fetch('/api/get-nijivoice-actors', {
headers: {
'Authorization': `Bearer ${nijivoiceApiKey}`
}
})

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
src/components/settings/voice.tsx (2)

859-863: 型安全性を向上させる必要があります

nijivoiceSpeakersの型がArray<any>として定義されています。これは型安全性を損なう可能性があります。

以下のような型定義を追加することを推奨します:

interface NijiVoiceActor {
  id: string;
  name: string;
}

const [nijivoiceSpeakers, setNijivoiceSpeakers] = useState<NijiVoiceActor[]>([]);

870-874: スピード調整の粒度が粗すぎる可能性があります

現在のスピード調整のステップ値が0.1と大きく、細かい調整が難しい可能性があります。より細かい調整を可能にすることを検討してください。

以下の修正を提案します:

  <input
    type="range"
    min={0.4}
    max={3.0}
-   step={0.1}
+   step={0.01}
    value={nijivoiceSpeed}
    // ... rest of the code
  />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 463ac1f and d925dac.

📒 Files selected for processing (1)
  • src/components/settings/voice.tsx (4 hunks)
🔇 Additional comments (2)
src/components/settings/voice.tsx (2)

67-69: ⚠️ Potential issue

APIキーをURLパラメータとして送信することはセキュリティ上のリスクがあります

APIキーをURLパラメータとして送信すると、サーバーログやブラウザ履歴に記録される可能性があります。代わりにAuthorizationヘッダーを使用することを推奨します。

以下の修正を提案します:

-      const response = await fetch(
-        `/api/get-nijivoice-actors?apiKey=${nijivoiceApiKey}`
-      )
+      const response = await fetch('/api/get-nijivoice-actors', {
+        headers: {
+          'Authorization': `Bearer ${nijivoiceApiKey}`
+        }
+      })

Likely invalid or redundant comment.


77-79: 🛠️ Refactor suggestion

エラーハンドリングを改善する必要があります

現在のエラーハンドリングではコンソールにログを出力するだけです。ユーザーにエラーを通知し、適切なフォールバック処理を実装することを推奨します。

以下の実装を提案します:

+ const [error, setError] = useState<string | null>(null);
  const fetchNijivoiceSpeakers = async () => {
+   setError(null);
    try {
      // ... existing code ...
    } catch (error) {
      console.error('Failed to fetch nijivoice speakers:', error);
+     setError(t('Errors.TTSServiceError', { 
+       serviceName: 'NijiVoice',
+       message: error instanceof Error ? error.message : String(error)
+     }));
    }
  }

Likely invalid or redundant comment.

@tegnike tegnike merged commit 186205a into develop Dec 10, 2024
3 checks passed
@tegnike tegnike deleted the feature/add-nijivoice branch December 10, 2024 23:16
@coderabbitai coderabbitai bot mentioned this pull request Dec 10, 2024
@coderabbitai coderabbitai bot mentioned this pull request Dec 18, 2024
terisuke pushed a commit to terisuke/aituber-kit that referenced this pull request Dec 5, 2025
にじボイスをTTSの選択肢に追加
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants