Skip to content

Conversation

@tegnike
Copy link
Owner

@tegnike tegnike commented Dec 9, 2024

Summary by CodeRabbit

  • 新機能

    • AITuberKitに関連するメッセージ送信機能を強化しました。
    • ユーザーがAIキャラクターと対話するための新しいオプションを追加しました。
    • メッセージ送信の方法を明確に説明する新しいローカライズされたテキストを追加しました。
  • バグ修正

    • メッセージ処理のロジックを改善し、エラーメッセージの翻訳機能を削除しました。
  • ドキュメント

    • 新しいメソッドやインターフェースに関するコメントを追加しました。

@vercel
Copy link

vercel bot commented Dec 9, 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 9, 2024 11:49pm

@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2024

Walkthrough

このプルリクエストでは、localesディレクトリ内の複数の言語ファイルと、メッセージ処理に関連するコンポーネントに対する変更が行われています。主な変更点は、locales/en/translation.jsonlocales/ja/translation.jsonlocales/ko/translation.jsonlocales/zh/translation.jsonに新しいセクション「SendMessage」が追加され、AIキャラクターとのメッセージ送信に関する詳細な説明が含まれています。また、src/componentssrc/features内のコンポーネントにおいて、メッセージ処理のロジックが整理され、メッセージの構造が強化されています。

Changes

ファイル 変更概要
locales/en/translation.json 新しい「SendMessage」セクションが追加され、メッセージ送信に関する複数のキーが追加された。
locales/ja/translation.json 新しい「SendMessage」セクションが追加され、メッセージ送信に関する複数のキーが追加された。
locales/ko/translation.json 新しい「SendMessage」セクションが追加され、メッセージ送信に関する複数のキーが追加された。
locales/zh/translation.json 新しい「SendMessage」セクションが追加され、メッセージ送信に関する複数のキーが追加された。
src/components/form.tsx handleSendChat関数の翻訳依存を削除し、シンプルにした。
src/components/messageReceiver.tsx MessageクラスをReceivedMessageにリネームし、メッセージのタイプを管理するための新しいパラメータを追加した。
src/components/youtubeManager.tsx handleSendChat関数の翻訳依存を削除し、シンプルにした。
src/features/chat/handlers.ts handleSendChatFnのシグネチャを簡素化し、エラーハンドリングを改善した。
src/features/messages/messageSelectors.ts 新しいメソッドgetAudioMessagesgetProcessedMessagescutImageMessageを追加した。
src/pages/api/messages.ts MessageインターフェースをReceivedMessageにリネームし、新しいプロパティを追加した。
src/pages/send-message.tsx メッセージの送信タイプを管理するための新しい型SendTypeとインターフェースRequestBodyを追加した。

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: 3

🧹 Outside diff range and nitpick comments (5)
src/pages/api/messages.ts (2)

3-8: 型の定義が改善されていますが、さらなる改善の余地があります

ReceivedMessageインターフェースの型定義は良く整理されていますが、以下の改善を提案します:

  1. timestampの型をDateに変更することで、日付処理の一貫性が向上します
  2. systemPromptuseCurrentSystemPromptの関係性を型で表現することで、より安全な実装が可能です
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オブジェクトへのアクセスで競合が発生する可能性があります。以下の対策を検討してください:

  1. ミューテックスやセマフォを使用した同期制御
  2. メッセージキューの実装をRedisなどの永続化ストレージに移行
src/features/messages/messageSelectors.ts (3)

Line range hint 14-24: 音声メッセージのフィルタリング処理を最適化できます

getAudioMessagesメソッドのパフォーマンスを改善するため、以下の最適化を提案します:

  1. 早期リターンパターンの採用
  2. 型ガードの使用による型安全性の向上
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メソッドには以下の最適化ポイントがあります:

  1. 最後の10件のみ必要な場合は、先にスライスしてから処理を行う
  2. メッセージの変換処理をメモ化する
  3. タイムスタンプの文字列結合を最適化する
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メソッドの実装について、以下の改善を提案します:

  1. 早期リターンによる条件分岐の簡略化
  2. オプショナルチェイニングの活用
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

📥 Commits

Reviewing files that changed from the base of the PR and between 6da9db8 and a7dffc6.

📒 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: 新たな依存関係の追加が適切であることを確認

i18nexttoastStoreのインポートが追加されています。これらの新しい依存関係がビルドや動作に問題を引き起こさないことを確認しました。


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セクションは、以下の点で良く設計されています:

  • 各機能の目的が明確に説明されています
  • 処理順序や設定の依存関係が詳細に記載されています
  • システムプロンプトや会話履歴の取り扱いについても適切に説明されています

Comment on lines 41 to 76
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)
}
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

非同期処理内での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.

Comment on lines 454 to 501
{[...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>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

userInputFieldCountの誤使用

"User Input"セクションでテキストエリアをレンダリングする際に、aiFieldCountが使用されていますが、これはuserInputFieldCountを使用する必要があります。このミスにより、ユーザー入力フィールドの数が正しく管理されず、機能が期待通りに動作しない可能性があります。

修正案:

- {[...Array(aiFieldCount)].map((_, index) => (
+ {[...Array(userInputFieldCount)].map((_, index) => (

また、以下の箇所でも同様にaiFieldCountuserInputFieldCountに置き換える必要があります:

- {aiFieldCount > 1 && (
+ {userInputFieldCount > 1 && (
- onClick={() => addNewField('ai_generate')}
+ onClick={() => addNewField('user_input')}

Committable suggestion skipped: line range outside the PR's diff.

"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のシステムプロンプトを利用する",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

英語ロケールファイル内に日本語テキストが混在しています

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.

Suggested change
"useCurrentSystemPrompt": "AITuberKitのシステムプロンプトを利用する",
"useCurrentSystemPrompt": "Use AITuberKit system prompt",

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: 1

🧹 Outside diff range and nitpick comments (3)
src/components/messageReceiver.tsx (1)

11-30: クラス定義の改善提案

ReceivedMessageクラスの実装は適切ですが、以下の改善を提案します:

  1. 型の定義を別のファイルに分離し、再利用可能にする
  2. メッセージタイプを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関数のエラーハンドリングを改善し、ユーザーにより明確なフィードバックを提供することを推奨します:

  1. エラーメッセージの国際化
  2. エラー種別の詳細な分類
  3. リトライロジックの実装
 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関数について、以下の改善を提案します:

  1. ブラウザ互換性の考慮
  2. アクセシビリティの向上
  3. エラーメッセージの国際化
 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

📥 Commits

Reviewing files that changed from the base of the PR and between a7dffc6 and f6cbd2a.

📒 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セクションの翻訳について、以下の点を確認してください:

  1. 他の言語ファイル(ja/ko/zh)との一貫性
  2. 技術用語の統一的な使用(例:AITuberKit、API、システムプロンプト)
✅ Verification successful

翻訳の一貫性が確認できました

各言語ファイル(en/ja/ko/zh)のSendMessageセクションを確認した結果:

  1. 技術用語(AITuberKit、システムプロンプト等)は全言語で一貫して使用されています
  2. 各言語の翻訳は適切に意味が保持され、自然な表現で翻訳されています
  3. 機能説明の重要な要素(順序処理、モデル選択、会話履歴の扱い等)が全言語で正確に反映されています
🏁 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

Comment on lines +15 to +30
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('')
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

状態管理の最適化が必要です

現在の実装では、各メッセージタイプごとに個別の状態を管理していますが、以下の改善を提案します:

  1. カスタムフックを使用した状態管理の抽象化
  2. 共通のロジックの統合
// 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 };
}

@tegnike tegnike merged commit 49973ad into develop Dec 9, 2024
3 checks passed
@tegnike tegnike deleted the update-send-messages-api branch December 9, 2024 23:50
This was referenced Dec 10, 2024
terisuke pushed a commit to terisuke/aituber-kit that referenced this pull request Dec 5, 2025
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