-
-
Notifications
You must be signed in to change notification settings - Fork 145
v23.4.0をベースにDifyの複数ユーザーに対応する機能を追加 #395
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
Sequence Diagram(s)sequenceDiagram
participant User
participant CameraMonitor
participant PersonDetector
participant MessageInputContainer
participant VoiceRecognition
participant userHistory
participant AIChat
User->>CameraMonitor: カメラ映像を通じて存在を検知
CameraMonitor->>PersonDetector: onUserDetected(userId, isNewUser) または onUserDisappeared()
PersonDetector->>userHistory: addUserToHistory(userId) / isNewUser(userId)
PersonDetector->>MessageInputContainer: onUserDetected/onUserDisappearedコールバック
MessageInputContainer->>VoiceRecognition: startListening()/stopListening()
PersonDetector->>AIChat: ユーザーIDをグローバル状態にセット
AIChat->>AIChat: getAIChatResponseStream(messages, ..., userId)
AIChat->>DifyAPI: userId付きでAPIリクエスト
sequenceDiagram
participant Frontend
participant Camera API
participant userHistory
participant AIChat
participant DifyAPI
loop 定期ポーリング
Frontend->>Camera API: ユーザーID取得リクエスト
Camera API-->>Frontend: ユーザーID or null
alt ユーザー検知
Frontend->>userHistory: isNewUser(userId), addUserToHistory(userId)
Frontend->>AIChat: ユーザーIDをセット
else ユーザー消失
Frontend->>AIChat: ユーザーIDクリア
end
end
Frontend->>DifyAPI: userId付きでチャットリクエスト
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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: 8
🧹 Nitpick comments (10)
src/utils/userHistory.ts (1)
1-19: 履歴サイズの制限を検討現在の実装では履歴の最大サイズに制限がないため、時間の経過とともに履歴が無限に増加する可能性があります。
最大履歴サイズを定義し、古いエントリを削除する機能を追加することを検討してください:
const HISTORY_KEY = 'user_history'; +const MAX_HISTORY_SIZE = 100; // 適切な上限値を設定 export const addUserToHistory = (userId: string) => { try { const history = getUserHistory(); if (!history.includes(userId)) { history.push(userId); + // 履歴サイズが上限を超えた場合、古いエントリを削除 + if (history.length > MAX_HISTORY_SIZE) { + history.shift(); + } localStorage.setItem(HISTORY_KEY, JSON.stringify(history)); } } catch (error) { console.error('ユーザー履歴の追加に失敗しました:', error); } };src/features/chat/aiChatFactory.ts (1)
33-39: 未定義の可能性があるユーザーIDの処理
ss.userIdがundefinedの場合の処理が明示されていません。他のパラメータでは|| ''のようなフォールバック値が設定されていますが、userIdには設定されていません。以下のように
userIdにもフォールバック値を設定することを検討してください:return getDifyChatResponseStream( messages, ss.difyKey || '', ss.difyUrl || '', ss.difyConversationId, - ss.userId + ss.userId || 'default-user' )src/pages/api/difyChat.ts (1)
21-69: リクエスト検証の改善
userIdパラメータの検証が行われていません。悪意のあるリクエストによる潜在的なセキュリティリスクを減らすため、入力値の検証を追加することが望ましいです。以下のようにユーザーIDの基本的な検証を追加することを検討してください:
// for multi-user support const { query, apiKey, url, conversationId, stream, userId } = await req.json() +// ユーザーIDの検証(例:空文字列や特殊文字の確認) +const sanitizedUserId = userId && typeof userId === 'string' && /^[a-zA-Z0-9_-]+$/.test(userId) + ? userId + : 'aituber-kit';そして69行目を以下のように更新します:
-user: userId || 'aituber-kit', // for multi-user support +user: sanitizedUserId, // for multi-user supportsrc/components/messageInputContainer.tsx (2)
48-49: デバッグログについて本番環境ではデバッグログを最小限に抑えるか、適切なログレベルで管理することが望ましいです。
本番環境での不要なログ出力を避けるため、以下のようにログレベルを管理することを検討してください:
-console.log(`messageInputContainer:ユーザー検出: ${userId}, 新規ユーザー: ${isNewUser}`, Date.now()) +if (process.env.NODE_ENV !== 'production') { + console.log(`messageInputContainer:ユーザー検出: ${userId}, 新規ユーザー: ${isNewUser}`, Date.now()) +}
57-57: デバッグログについて本番環境ではデバッグログを最小限に抑えるか、適切なログレベルで管理することが望ましいです。
本番環境での不要なログ出力を避けるため、以下のように修正することを検討してください:
-console.log('ユーザーが消失') +if (process.env.NODE_ENV !== 'production') { + console.log('ユーザーが消失') +}src/features/chat/difyChat.ts (1)
38-42: 機密情報を含むconsole.logの削除を検討
本番環境に渡る可能性のあるquery(ユーザー入力)やuserIdをそのまま出力しています。PII・ログ肥大化・パフォーマンスの面から、NODE_ENV !== 'production'条件で囲むか、完全に削除する方が安全です。-// for debugging -console.log('difyChat request:', { query: messages[messages.length - 1].content, conversationId, userId }); +if (process.env.NODE_ENV !== 'production') { + /* eslint-disable no-console */ + console.log('[difyChat debug]', { query: messages[messages.length - 1].content, userId }); + /* eslint-enable no-console */ +}src/features/chat/handlers.ts (1)
708-724:updateUserIdの競合更新を防ぐため atomic-update を推奨
settingsStore.setStateを複数非同期呼び出しが行うと、まれに古い値で上書きされる可能性があります。関数形式のsetStateで直前の値を参照する形にすると安全です。- settingsStore.setState({ userId: userId }) + settingsStore.setState(prev => ({ ...prev, userId }))src/components/cameraMonitor.tsx (2)
48-56: ユーザー消失時にpreviousUserIdRefをリセットすると再検出が動作しやすくなります
現在の実装では同一ユーザーが一度離脱 → 再検出された際、previousUserIdRef.currentが以前の値のままなのでonUserDetectedが発火しません。離脱検知時にpreviousUserIdRef.current = nullとすると、次の検出で再度コールバックが呼ばれます。if (onUserDisappeared) { onUserDisappeared() } -//previousUserIdRef.current = null +previousUserIdRef.current = null
63-74: 初回検出を遅延させないために即時実行を推奨
ポーリング開始から最初の検出までpollInterval分待つ設計になっています。UX を向上させるにはstartMonitoring内でcheckForUserChanges()を即時実行し、その後setIntervalを開始すると良いでしょう。-// 即時に1回実行 -//checkForUserChanges() +checkForUserChanges().catch(console.error)src/components/personDetector.tsx (1)
6-8: モジュールスコープのグローバル変数は Fast-Refresh でリセットされない点に注意
開発中のホットリロードで値が残り、デバッグが困難になることがあります。useRefでルートに保持するか、reset()API を用意する方法も検討してください。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/components/cameraMonitor.tsx(1 hunks)src/components/messageInputContainer.tsx(2 hunks)src/components/personDetector.tsx(1 hunks)src/features/chat/aiChatFactory.ts(1 hunks)src/features/chat/difyChat.ts(2 hunks)src/features/chat/handlers.ts(1 hunks)src/pages/api/difyChat.ts(2 hunks)src/utils/userHistory.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/personDetector.tsx (2)
src/utils/userHistory.ts (1)
isNewUser(11-14)src/components/cameraMonitor.tsx (1)
CameraMonitor(12-101)
🪛 Biome (1.9.4)
src/components/messageInputContainer.tsx
[error] 56-56: Unexpected constant condition.
(lint/correctness/noConstantCondition)
🔇 Additional comments (5)
src/features/chat/aiChatFactory.ts (1)
33-39: DifyチャットへのユーザーID追加について
getDifyChatResponseStream関数にss.userIdパラメータを追加することで、複数ユーザーのサポートを実現しています。これは適切な修正です。src/pages/api/difyChat.ts (2)
21-22: 複数ユーザーサポートのためのリクエスト処理リクエストから
userIdパラメータを抽出する変更は適切です。これにより複数ユーザーのサポートが可能になります。
69-69: ユーザーIDのフォールバックロジックユーザーIDがない場合に'aituber-kit'をデフォルト値として使用する実装は適切です。
src/components/messageInputContainer.tsx (1)
46-60: PersonDetectorコンポーネントの統合カメラを使用したユーザー検出機能の追加は優れた機能拡張です。ユーザーの出現/消失に基づいて音声認識を自動的に制御することで、ユーザーエクスペリエンスが向上します。
🧰 Tools
🪛 Biome (1.9.4)
[error] 56-56: Unexpected constant condition.
(lint/correctness/noConstantCondition)
src/components/personDetector.tsx (1)
30-33:userId.endsWith('null')での null チェックは TypeError の恐れ
userIdが''やundefinedの場合でも安全に判定できるよう、先に型・長さを確認してください。
| const userConversationId = ss.difyConversationMap[userId] || ''; | ||
|
|
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
difyConversationMap が未定義の場合の NPE 対策
settingsStore.getState().difyConversationMap が初期化前だと undefined になり得ます。オプショナルチェーンかデフォルト値で保護しないと実行時例外のリスクがあります。
-const userConversationId = ss.difyConversationMap[userId] || '';
+const userConversationId = ss.difyConversationMap?.[userId] ?? '';Also applies to: 32-33
🤖 Prompt for AI Agents
In src/features/chat/difyChat.ts around lines 20-21 and 32-33, the code accesses
difyConversationMap without checking if it is defined, risking a null pointer
exception if it is undefined. To fix this, use optional chaining or provide a
default empty object when accessing difyConversationMap, ensuring the code
safely handles cases where difyConversationMap is not yet initialized.
| conversationId: string, | ||
| userId: string | ||
| ): Promise<ReadableStream<string>> { |
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
未使用の conversationId パラメータを削除してください
conversationId を受け取っていますが、関数内で一切参照されていません。型チェック/IDE 上は「未使用引数」として警告が出るため、保守性の観点でも削除を推奨します。もしデバッグ用途で残している場合はコメントアウトまたは /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ 等で意図を明示してください。
-export async function getDifyChatResponseStream(
- messages: Message[],
- apiKey: string,
- url: string,
- conversationId: string,
- userId: string
+export async function getDifyChatResponseStream(
+ messages: Message[],
+ apiKey: string,
+ url: string,
+ userId: string
) : Promise<ReadableStream<string>> {📝 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.
| conversationId: string, | |
| userId: string | |
| ): Promise<ReadableStream<string>> { | |
| export async function getDifyChatResponseStream( | |
| messages: Message[], | |
| apiKey: string, | |
| url: string, | |
| userId: string | |
| ): Promise<ReadableStream<string>> { | |
| // … | |
| } |
🤖 Prompt for AI Agents
In src/features/chat/difyChat.ts around lines 16 to 18, the function accepts a
conversationId parameter that is not used anywhere in the function body. To
improve code clarity and maintainability, remove the unused conversationId
parameter from the function signature. If you need to keep it for debugging
purposes, either comment it out or add an eslint directive to explicitly disable
the unused variable warning.
| import { useEffect, useRef, useState, useCallback } from 'react' | ||
| import { fetchUserIdFromCamera, updateUserId } from '@/features/chat/handlers' | ||
| import { isNewUser, addUserToHistory } from '@/utils/userHistory' | ||
| import settingsStore from '@/features/stores/settings' |
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.
未使用インポート settingsStore
settingsStore を参照していないためビルド時に lint エラーになります。削除してください。
-import settingsStore from '@/features/stores/settings'📝 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.
| import settingsStore from '@/features/stores/settings' |
🤖 Prompt for AI Agents
In src/components/cameraMonitor.tsx at line 4, the import statement for
`settingsStore` is unused and causes a lint error. Remove the entire line
importing `settingsStore` since it is not referenced anywhere in the file.
| if (currentUserIdRef.current !== userId) { | ||
| // Use prevUserIdRef for comparison, not currentUserIdRef | ||
| const isNewUserDetection = prevUserIdRef.current === null && currentUserIdRef.current === null; | ||
| const isUserChanged = prevUserIdRef.current !== userId && currentUserIdRef.current !== null; | ||
|
|
||
| // Update references - save previous user before updating current | ||
| prevUserIdRef.current = currentUserIdRef.current; | ||
| currentUserIdRef.current = userId; | ||
|
|
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
isNewUserDetection 判定ロジックの誤判定リスク
prevUserIdRef.current === null && currentUserIdRef.current === null は「これまでユーザーが全くいなかった場合」しか true にならず、同一ユーザーが再入室したケースは isNewUser として扱われません。isNewUserDetection は prevUserIdRef.current !== userId に簡略化すると意図どおりに機能します。
-const isNewUserDetection = prevUserIdRef.current === null && currentUserIdRef.current === null;
+const isNewUserDetection = prevUserIdRef.current !== userId;📝 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.
| if (currentUserIdRef.current !== userId) { | |
| // Use prevUserIdRef for comparison, not currentUserIdRef | |
| const isNewUserDetection = prevUserIdRef.current === null && currentUserIdRef.current === null; | |
| const isUserChanged = prevUserIdRef.current !== userId && currentUserIdRef.current !== null; | |
| // Update references - save previous user before updating current | |
| prevUserIdRef.current = currentUserIdRef.current; | |
| currentUserIdRef.current = userId; | |
| if (currentUserIdRef.current !== userId) { | |
| // Use prevUserIdRef for comparison, not currentUserIdRef | |
| - const isNewUserDetection = prevUserIdRef.current === null && currentUserIdRef.current === null; | |
| + const isNewUserDetection = prevUserIdRef.current !== userId; | |
| const isUserChanged = prevUserIdRef.current !== userId && currentUserIdRef.current !== null; | |
| // Update references - save previous user before updating current | |
| prevUserIdRef.current = currentUserIdRef.current; | |
| currentUserIdRef.current = userId; | |
| … | |
| } |
🤖 Prompt for AI Agents
In src/components/personDetector.tsx around lines 58 to 66, the
isNewUserDetection logic incorrectly only returns true when both
prevUserIdRef.current and currentUserIdRef.current are null, missing cases where
the same user re-enters. Simplify isNewUserDetection to check if
prevUserIdRef.current is not equal to userId to correctly detect new user
entries. Update the condition accordingly to fix the detection logic.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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: 0
🧹 Nitpick comments (1)
src/features/stores/settings.ts (1)
196-202: UserInfo インターフェースの設計について再検討を推奨
UserInfoインターフェースにdifyConversationMapが含まれていますが、これは既にIntegrationsインターフェース(122行目)にも定義されています。この重複は混乱を招く可能性があります。次のようなリファクタリングを検討してください:
// settings for multi user interface UserInfo { userId: string - difyConversationMap: { - [userId: string]: string - } }
difyConversationMapはIntegrationsインターフェースのみで定義し、UserInfoはuserIdのみを管理することで、責任の分離が明確になります。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)
📒 Files selected for processing (2)
src/features/chat/handlers.ts(2 hunks)src/features/stores/settings.ts(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/features/chat/handlers.ts
🔇 Additional comments (4)
src/features/stores/settings.ts (4)
122-122: Difyの複数ユーザー対応のためのマッピング追加ユーザーIDから会話IDへのマッピングを追加することで、複数ユーザーのDify会話を個別に管理できるようになります。これは複数ユーザー対応機能の重要な基盤となります。
210-210: SettingsStateへのUserInfo追加
UserInfoインターフェースをSettingsState型に追加することで、ユーザー情報を状態に統合できています。
307-309: 初期状態の設定
difyConversationMapを空のオブジェクトとして、userIdを空の文字列として初期化しています。これにより、アプリケーション起動時に適切な初期状態が確保されます。
516-518: 永続化設定の更新ユーザーIDと会話マッピングの情報が永続化対象に追加されているため、ブラウザを再読み込みしても複数ユーザーの会話状態が保持されます。コメントも追加されており、変更の意図が明確です。
|
@RimgO こちらのPRですが、プッシュ先あっていますか? |
|
@tegnike |
Summary by CodeRabbit
新機能
改善