-
-
Notifications
You must be signed in to change notification settings - Fork 143
send-messagesページとAPIの更新 #256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Walkthroughこのプルリクエストでは、 Changes
Possibly related PRs
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (5)
src/pages/api/messages.ts (2)
3-8: 型の定義が改善されていますが、さらなる改善の余地があります
ReceivedMessageインターフェースの型定義は良く整理されていますが、以下の改善を提案します:
timestampの型をDateに変更することで、日付処理の一貫性が向上しますsystemPromptとuseCurrentSystemPromptの関係性を型で表現することで、より安全な実装が可能ですinterface ReceivedMessage { - timestamp: number + timestamp: Date message: string type: 'direct_send' | 'ai_generate' | 'user_input' - systemPrompt?: string - useCurrentSystemPrompt?: boolean + systemPrompt: { + content?: string + useCurrentPrompt: boolean + } }
Line range hint
32-55: 並行処理に関する潜在的な問題があります複数のリクエストが同時に処理される場合、
messagesPerClientオブジェクトへのアクセスで競合が発生する可能性があります。以下の対策を検討してください:
- ミューテックスやセマフォを使用した同期制御
- メッセージキューの実装をRedisなどの永続化ストレージに移行
src/features/messages/messageSelectors.ts (3)
Line range hint
14-24: 音声メッセージのフィルタリング処理を最適化できます
getAudioMessagesメソッドのパフォーマンスを改善するため、以下の最適化を提案します:
- 早期リターンパターンの採用
- 型ガードの使用による型安全性の向上
getAudioMessages: (messages: Message[]): Message[] => { return messages.filter((message) => { + if (!message.role) return false + if (!message.content) return false + switch (message.role) { case 'user': return typeof message.content === 'string' case 'assistant': return message.audio !== undefined default: return false } - if (message.role === 'user') { - return typeof message.content === 'string' - } - if (message.role === 'assistant') { - return message.audio !== undefined - } - return false }) }
Line range hint
30-52: メッセージ処理のパフォーマンス最適化が必要です
getProcessedMessagesメソッドには以下の最適化ポイントがあります:
- 最後の10件のみ必要な場合は、先にスライスしてから処理を行う
- メッセージの変換処理をメモ化する
- タイムスタンプの文字列結合を最適化する
getProcessedMessages: ( messages: Message[], includeTimestamp: boolean ): Message[] => { + const lastTenMessages = messages.slice(-10) - return messages + return lastTenMessages .map((message, index) => { - const isLastMessage = index === messages.length - 1 + const isLastMessage = index === lastTenMessages.length - 1 // ... rest of the code }) - .slice(-10) }
Line range hint
102-114: 画像メッセージの変換処理を改善できます
cutImageMessageメソッドの実装について、以下の改善を提案します:
- 早期リターンによる条件分岐の簡略化
- オプショナルチェイニングの活用
cutImageMessage: (messages: Message[]): Message[] => { return messages.map((message: Message) => ({ ...message, - content: - message.content === undefined - ? '' - : typeof message.content === 'string' - ? message.content - : message.content[0].text, + content: message.content == null + ? '' + : Array.isArray(message.content) + ? message.content[0]?.text ?? '' + : message.content, })) },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (11)
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/form.tsx(1 hunks)src/components/messageReceiver.tsx(2 hunks)src/components/youtubeManager.tsx(1 hunks)src/features/chat/handlers.ts(2 hunks)src/features/messages/messageSelectors.ts(3 hunks)src/pages/api/messages.ts(4 hunks)src/pages/send-message.tsx(4 hunks)
🔇 Additional comments (11)
src/features/chat/handlers.ts (2)
11-12: 新たな依存関係の追加が適切であることを確認
i18nextとtoastStoreのインポートが追加されています。これらの新しい依存関係がビルドや動作に問題を引き起こさないことを確認しました。
333-462: handleSendChatFn関数のリファクタリングが適切
handleSendChatFn関数がリファクタリングされ、エラー処理が改善されています。コードの整理とエラーメッセージの適切な表示が確認できました。
src/components/youtubeManager.tsx (1)
6-6: エラーメッセージのローカリゼーションが適切に維持されていることを確認
useTranslationフックを削除し、handleSendChatFn()を引数なしで呼び出すように変更しています。この変更後も、エラーメッセージのローカリゼーションが適切に機能していることを確認しました。
src/components/form.tsx (1)
19-19: エラーメッセージのローカライゼーション処理の確認が必要です
handleSendChatFnの呼び出しからエラーメッセージの翻訳パラメータが削除されています。これにより、エラーメッセージのローカライゼーションが正しく機能しない可能性があります。
locales/zh/translation.json (2)
185-185: AzureTTSInfoの更新が適切に行われています。
多言語対応の説明が明確に記載されており、他の言語ファイルと一貫性が保たれています。
186-195: SendMessageセクションが適切に追加されています。
- 外部アダプター機能の説明が明確です
- メッセージ送信の3つのモード(直接発言、AI生成、ユーザー入力)が適切に説明されています
- システムプロンプトと会話履歴の使用方法が詳細に記載されています
locales/ja/translation.json (2)
186-186: AzureTTSInfoの説明文が適切です。
簡潔で分かりやすい日本語で多言語対応について説明されています。
187-196: SendMessageセクションの日本語訳が分かりやすく実装されています。
- 「AITuberKit 外部アダプター」という訳語が適切です
- 各機能の説明が詳細かつ分かりやすく記載されています
- 技術用語(システムプロンプト、会話履歴など)の訳語が統一されています
locales/ko/translation.json (2)
185-185: AzureTTSInfoの更新が他の言語ファイルと一貫しています。
韓国語での説明が明確で、多言語対応の説明が適切に翻訳されています。
186-195: SendMessageセクションが適切に韓国語化されています。
- 他の言語ファイルと同様の構造を維持しながら、自然な韓国語で記述されています
- 技術用語の翻訳が一貫しており、理解しやすい表現が使用されています
- メッセージ処理の各モードの説明が詳細に記載されています
locales/en/translation.json (1)
186-195: SendMessageセクションの実装は適切です
新しく追加されたSendMessageセクションは、以下の点で良く設計されています:
- 各機能の目的が明確に説明されています
- 処理順序や設定の依存関係が詳細に記載されています
- システムプロンプトや会話履歴の取り扱いについても適切に説明されています
src/components/messageReceiver.tsx
Outdated
| messages.forEach(async (message) => { | ||
| if (message.type === 'direct_send') { | ||
| speakMessageHandler(message.message) | ||
| } else if (message.type === 'ai_generate') { | ||
| const conversationHistory = [ | ||
| ...hs.chatLog.slice(-10), | ||
| { role: 'user', content: message.message }, | ||
| ] | ||
| .map((m) => `${m.role}: ${m.content}`) | ||
| .join('\n') | ||
| const systemPrompt = message.useCurrentSystemPrompt | ||
| ? ss.systemPrompt | ||
| : message.systemPrompt | ||
| const messages: Message[] = [ | ||
| { | ||
| role: 'system', | ||
| content: systemPrompt?.replace( | ||
| '[conversation_history]', | ||
| conversationHistory | ||
| ), | ||
| }, | ||
| { | ||
| role: 'user', | ||
| content: message.message.replace( | ||
| '[conversation_history]', | ||
| conversationHistory | ||
| ), | ||
| }, | ||
| ] | ||
| await processAIResponse(hs.chatLog, messages) | ||
| } else if (message.type === 'user_input') { | ||
| handleSendChatFn()(message.message) | ||
| } else { | ||
| console.error('Invalid message type:', message.type) | ||
| } | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
非同期処理内でのforEachループによる予期しない動作の可能性
Array.prototype.forEachに非同期コールバックを使用すると、各反復が完了する前に次の反復が開始されるため、非同期操作が完全に完了する前にループが終了する可能性があります。処理の順序や完了を確実にするために、for...ofループを使用して各反復でawaitを適切に機能させることを検討してください。
修正案:
- messages.forEach(async (message) => {
+ for (const message of messages) {Committable suggestion skipped: line range outside the PR's diff.
src/pages/send-message.tsx
Outdated
| {[...Array(aiFieldCount)].map((_, index) => ( | ||
| <div key={index} className="flex gap-4"> | ||
| <textarea | ||
| value={userInputMessages[index]} | ||
| onChange={(e) => { | ||
| const newMessages = [...userInputMessages] | ||
| newMessages[index] = e.target.value | ||
| setUserInputMessages(newMessages) | ||
| }} | ||
| onKeyDown={(e) => handleKeyDown(e)} | ||
| className="bg-surface1 hover:bg-surface1-hover focus:bg-surface1 rounded-16 w-full px-16 text-text-primary typography-16 font-bold" | ||
| rows={2} | ||
| style={{ | ||
| lineHeight: '1.5', | ||
| padding: '8px 16px', | ||
| resize: 'vertical', | ||
| }} | ||
| /> | ||
| {aiFieldCount > 1 && ( | ||
| <IconButton | ||
| iconName="24/Subtract" | ||
| onClick={() => removeField(index, 'user_input')} | ||
| className="min-w-[40px] w-[40px] h-[40px] shrink-0 ml-8" | ||
| isProcessing={false} | ||
| /> | ||
| )} | ||
| </div> | ||
| ))} | ||
| </div> | ||
| <div className="flex justify-between mt-8"> | ||
| <IconButton | ||
| iconName="24/Add" | ||
| onClick={() => addNewField('user_input')} | ||
| className="mt-2" | ||
| isProcessing={false} | ||
| /> | ||
| <IconButton | ||
| iconName="24/Send" | ||
| className="bg-secondary hover:bg-secondary-hover active:bg-secondary-press disabled:bg-secondary-disabled w-[120px] flex items-center justify-center" | ||
| disabled={ | ||
| !userInputMessages.some((msg) => msg.trim()) || | ||
| !clientId.trim() | ||
| } | ||
| type="submit" | ||
| isProcessing={false} | ||
| /> | ||
| </div> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
userInputFieldCountの誤使用
"User Input"セクションでテキストエリアをレンダリングする際に、aiFieldCountが使用されていますが、これはuserInputFieldCountを使用する必要があります。このミスにより、ユーザー入力フィールドの数が正しく管理されず、機能が期待通りに動作しない可能性があります。
修正案:
- {[...Array(aiFieldCount)].map((_, index) => (
+ {[...Array(userInputFieldCount)].map((_, index) => (また、以下の箇所でも同様にaiFieldCountをuserInputFieldCountに置き換える必要があります:
- {aiFieldCount > 1 && (
+ {userInputFieldCount > 1 && (- onClick={() => addNewField('ai_generate')}
+ onClick={() => addNewField('user_input')}Committable suggestion skipped: line range outside the PR's diff.
locales/en/translation.json
Outdated
| "directSendDescription": "You can send the message directly to the AI character. If multiple messages are sent, they are processed in order. The voice model is the one selected in the AITuberKit settings.", | ||
| "aiGenerateTitle": "Generate AI response and then speak", | ||
| "aiGenerateDescription": "The AI generates a response from the message sent and then speaks it. If multiple messages are sent, they are processed in order. The AI model and voice model are the ones selected in the AITuberKit settings. The system prompt can be selected to use the AITuberKit system prompt or a custom system prompt. If you want to load the past conversation history, include the string [conversation_history] in the system prompt or user message.", | ||
| "useCurrentSystemPrompt": "AITuberKitのシステムプロンプトを利用する", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
英語ロケールファイル内に日本語テキストが混在しています
useCurrentSystemPromptの値が日本語になっています。英語ロケールファイルの一貫性を保つため、英語に翻訳する必要があります。
以下の修正を提案します:
- "useCurrentSystemPrompt": "AITuberKitのシステムプロンプトを利用する",
+ "useCurrentSystemPrompt": "Use AITuberKit system prompt",📝 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.
| "useCurrentSystemPrompt": "AITuberKitのシステムプロンプトを利用する", | |
| "useCurrentSystemPrompt": "Use AITuberKit system prompt", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (3)
src/components/messageReceiver.tsx (1)
11-30: クラス定義の改善提案
ReceivedMessageクラスの実装は適切ですが、以下の改善を提案します:
- 型の定義を別のファイルに分離し、再利用可能にする
- メッセージタイプを
enumとして定義し、型安全性を向上させる+// types/messages.ts +export enum MessageType { + DirectSend = 'direct_send', + AIGenerate = 'ai_generate', + UserInput = 'user_input' +} +export class ReceivedMessage { + constructor( + public readonly timestamp: number, + public readonly message: string, + public readonly type: MessageType, + public readonly systemPrompt?: string, + public readonly useCurrentSystemPrompt?: boolean + ) {} +}src/pages/send-message.tsx (2)
Line range hint
44-101: エラーハンドリングの強化が必要です
handleSubmit関数のエラーハンドリングを改善し、ユーザーにより明確なフィードバックを提供することを推奨します:
- エラーメッセージの国際化
- エラー種別の詳細な分類
- リトライロジックの実装
const handleSubmit = async (e?: React.FormEvent, type: SendType = 'direct_send') => { e?.preventDefault(); try { // ... existing code ... } catch (error) { - console.error('Error:', error); - setResponse( - `エラーが発生しました: ${error instanceof Error ? error.message : String(error)}` - ); + const errorMessage = error instanceof Error ? error.message : String(error); + console.error('Error:', errorMessage); + + if (error instanceof TypeError) { + setResponse(t('Errors.networkError')); + } else if (error instanceof Response) { + setResponse(t('Errors.serverError', { status: error.status })); + } else { + setResponse(t('Errors.unexpectedError', { message: errorMessage })); + } + + // Retry logic for network errors + if (error instanceof TypeError) { + setTimeout(() => handleSubmit(e, type), 3000); + } } };
143-156: クリップボード機能の改善が必要です
copyToClipboard関数について、以下の改善を提案します:
- ブラウザ互換性の考慮
- アクセシビリティの向上
- エラーメッセージの国際化
const copyToClipboard = async (text: string, event: React.MouseEvent) => { + // ブラウザ互換性チェック + if (!navigator.clipboard) { + setResponse(t('Errors.clipboardNotSupported')); + return; + } + try { await navigator.clipboard.writeText(text); const rect = (event.target as HTMLElement).getBoundingClientRect(); setPopupPosition({ x: rect.right, y: rect.top }); - setCopySuccess(`Copied!`); + setCopySuccess(t('Common.copied')); + // スクリーンリーダー用の通知 + const announcement = document.createElement('div'); + announcement.setAttribute('role', 'alert'); + announcement.textContent = t('Common.copied'); + document.body.appendChild(announcement); + setTimeout(() => document.body.removeChild(announcement), 2000); } catch (err) { console.error('Failed to copy text: ', err); + setResponse(t('Errors.clipboardError')); } };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
locales/en/translation.json(1 hunks)src/components/messageReceiver.tsx(2 hunks)src/pages/send-message.tsx(4 hunks)
🔇 Additional comments (2)
src/components/messageReceiver.tsx (1)
37-76: 非同期処理の改善が実装されています
以前のforEachループによる問題がfor...ofループで適切に解決されており、非同期処理が正しく実装されています。エラーハンドリングも適切に実装されています。
locales/en/translation.json (1)
186-195: 翻訳の一貫性の確認が必要です
新しく追加されたSendMessageセクションの翻訳について、以下の点を確認してください:
- 他の言語ファイル(ja/ko/zh)との一貫性
- 技術用語の統一的な使用(例:AITuberKit、API、システムプロンプト)
✅ Verification successful
翻訳の一貫性が確認できました
各言語ファイル(en/ja/ko/zh)のSendMessageセクションを確認した結果:
- 技術用語(AITuberKit、システムプロンプト等)は全言語で一貫して使用されています
- 各言語の翻訳は適切に意味が保持され、自然な表現で翻訳されています
- 機能説明の重要な要素(順序処理、モデル選択、会話履歴の扱い等)が全言語で正確に反映されています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 全言語ファイルのSendMessageセクションを比較
for lang in ja ko zh; do
echo "Checking $lang translation..."
if [ -f "locales/$lang/translation.json" ]; then
jq '.SendMessage' "locales/$lang/translation.json"
fi
done
Length of output: 2764
| const [directMessages, setDirectMessages] = useState(Array(1).fill('')) | ||
| const [aiMessages, setAiMessages] = useState(Array(1).fill('')) | ||
| const [directFieldCount, setDirectFieldCount] = useState(1) | ||
| const [aiFieldCount, setAiFieldCount] = useState(1) | ||
| const [userInputMessages, setUserInputMessages] = useState(Array(1).fill('')) | ||
| const [userInputFieldCount, setUserInputFieldCount] = useState(1) | ||
| const [clientId, setClientId] = useState('') | ||
| const [response, setResponse] = useState('') | ||
| const [copySuccess, setCopySuccess] = useState<string>('') | ||
| const [popupPosition, setPopupPosition] = useState<{ | ||
| x: number | ||
| y: number | ||
| } | null>(null) | ||
| const [systemPrompt, setSystemPrompt] = useState('') | ||
| const [useCurrentSystemPrompt, setUseCurrentSystemPrompt] = useState(false) | ||
| const [baseUrl, setBaseUrl] = useState('') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
状態管理の最適化が必要です
現在の実装では、各メッセージタイプごとに個別の状態を管理していますが、以下の改善を提案します:
- カスタムフックを使用した状態管理の抽象化
- 共通のロジックの統合
// hooks/useMessageFields.ts
interface MessageField {
messages: string[];
fieldCount: number;
}
function useMessageFields(type: SendType) {
const [state, setState] = useState<MessageField>({
messages: [''],
fieldCount: 1
});
const addField = useCallback(() => {
setState(prev => ({
messages: [...prev.messages, ''],
fieldCount: prev.fieldCount + 1
}));
}, []);
const removeField = useCallback((index: number) => {
if (state.fieldCount <= 1) return;
setState(prev => ({
messages: prev.messages.filter((_, i) => i !== index),
fieldCount: prev.fieldCount - 1
}));
}, [state.fieldCount]);
return { state, addField, removeField };
}send-messagesページとAPIの更新
Summary by CodeRabbit
新機能
バグ修正
ドキュメント