Skip to content

Conversation

@tegnike
Copy link
Owner

@tegnike tegnike commented Dec 6, 2024

Summary by CodeRabbit

リリースノート

  • 新機能

    • ローカルLLMに関連する新しいエラーメッセージを追加しました。これにより、エラー処理が強化され、ユーザーにより具体的なフィードバックが提供されます。
    • 新しいAPIハンドラーを追加し、ローカルLLMサーバーとのインタラクションが可能になりました。
    • Supabaseを統合し、チャットログとセッション管理の機能が向上しました。
  • バグ修正

    • エラーハンドリングの改善により、さまざまなエラーシナリオに対する具体的なエラーメッセージが提供されます。
  • ドキュメント

    • エラーメッセージの日本語翻訳を追加しました。
  • 依存関係の更新

    • 新しい依存関係「@supabase/supabase-js」を追加しました。

@vercel
Copy link

vercel bot commented Dec 6, 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 6, 2024 10:56pm

@coderabbitai
Copy link

coderabbitai bot commented Dec 6, 2024

Walkthrough

このプルリクエストでは、ローカルLLM機能に関連する新しいエラーメッセージが複数の言語の翻訳ファイルに追加されました。具体的には、英語、日本語、韓国語、中国語の各ファイルに5つの新しいエラーキーが追加され、エラーメッセージの詳細が強化されました。また、package.jsonに新しい依存関係が追加され、いくつかのコンポーネントやAPIハンドラーの機能が拡張されました。これにより、エラーハンドリングとローカライズの機能が向上しました。

Changes

ファイル 変更内容概要
locales/en/translation.json 5つの新しいエラーキー(LocalLLMError, LocalLLMStreamError, LocalLLMConnectionError, LocalLLMNotFound, LocalLLMAPIError)が追加され、既存のUnexpectedErrorは変更なし。
locales/ja/translation.json 上記と同様の5つの新しいエラーキーが追加され、既存のUnexpectedErrorは変更なし。
locales/ko/translation.json 上記と同様の5つの新しいエラーキーが追加され、既存のUnexpectedErrorは変更なし。
locales/zh/translation.json 上記と同様の5つの新しいエラーキーが追加され、既存のUnexpectedErrorは変更なし。
package.json 新しい依存関係"@supabase/supabase-js": "^2.46.2"が追加され、他の部分は変更なし。
src/components/settings/modelProvider.tsx "Local LLM"用の新しい入力フィールドが追加され、既存の機能は変更なし。
src/features/chat/localLLMChat.ts getLocalLLMChatResponseStream関数がAxiosからFetch APIに変更され、エラーハンドリングが強化された。
src/pages/api/local-llm.ts 新しいAPIハンドラーが追加され、POSTリクエストを処理する機能が実装された。
src/pages/api/save-chat-log.ts Supabaseを使用したセッション管理とメッセージ保存の機能が追加され、エラーハンドリングが強化された。
tsconfig.json compilerOptions"plugins": [{ "name": "next" }]が追加され、include配列が更新された。

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

🧹 Outside diff range and nitpick comments (3)
src/features/chat/localLLMChat.ts (1)

6-10: グローバルな言語設定の変更を避け、特定の言語でメッセージを取得してください

エラー処理中に i18next.changeLanguage を使用すると、アプリ全体の言語設定が変更されてしまいます。代わりに、i18next.t に言語オプションを指定して、グローバルな言語設定を変更せずに翻訳を取得することをお勧めします。

以下のように修正できます:

function handleApiError(errorCode: string): string {
  const languageCode = settingsStore.getState().selectLanguage
- i18next.changeLanguage(languageCode)
- return i18next.t(`Errors.${errorCode || 'LocalLLMError'}`)
+ return i18next.t(`Errors.${errorCode || 'LocalLLMError'}`, { lng: languageCode })
}
locales/en/translation.json (1)

147-152: 全言語間での翻訳の一貫性が優れています

以下の点で高品質な翻訳が実現されています:

  • 技術用語(「Local LLM」「ローカルLLM」「로컬 LLM」)の一貫した使用
  • エラーメッセージの構造的な統一性
  • 各言語の言語特性に応じた適切な表現の選択

今後のローカライゼーション拡張時にも、この翻訳スタイルを参考にすることを推奨します。

Also applies to: 147-151, 147-151

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

Line range hint 1-1000: コンポーネントの分割とリファクタリングを推奨

現在のコンポーネントは非常に大きく、保守性に課題があります。以下の改善を提案します:

  1. 各AIサービスを個別のコンポーネントに分割
  2. 共通の入力フィールドをコンポーネント化
  3. 設定の検証ロジックを独立したユーティリティに分離

以下のような構造を提案します:

// components/settings/providers/LocalLLMProvider.tsx
export const LocalLLMProvider = () => {
  // LocalLLM固有の実装
};

// components/settings/providers/OpenAIProvider.tsx
export const OpenAIProvider = () => {
  // OpenAI固有の実装
};

// components/settings/common/APIKeyInput.tsx
export const APIKeyInput = ({ 
  value, 
  onChange, 
  label, 
  linkUrl 
}: APIKeyInputProps) => {
  // 共通のAPI入力UI
};

このリファクタリングにより:

  • コードの可読性が向上
  • テストが容易になる
  • 機能追加や変更が簡単になる
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 38a1250 and 43509b0.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • locales/en/translation.json (1 hunks)
  • locales/ja/translation.json (1 hunks)
  • locales/ko/translation.json (1 hunks)
  • locales/zh/translation.json (1 hunks)
  • package.json (1 hunks)
  • src/components/settings/modelProvider.tsx (1 hunks)
  • src/features/chat/localLLMChat.ts (1 hunks)
  • src/pages/api/local-llm.ts (1 hunks)
  • src/pages/api/save-chat-log.ts (3 hunks)
  • tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • package.json
🔇 Additional comments (6)
tsconfig.json (2)

20-24: Next.jsのプラグイン設定の追加を確認しました

"plugins" セクションに Next.js のプラグインを追加しており、適切な設定です。


26-26: 型定義のパスを include に追加したことを確認しました

.next/types/**/*.tsinclude に追加しており、コンパイル時に Next.js の型定義が正しく認識されるようになります。

locales/zh/translation.json (1)

147-151: エラーメッセージの追加を確認しました

新しいエラーメッセージキーが適切に追加されています。これにより、ローカルLLMに関連するエラーがユーザーに明確に伝えられます。

locales/ja/translation.json (1)

148-152: エラーメッセージの翻訳が適切です

エラーメッセージの日本語訳が明確で、技術用語の一貫性が保たれています。

locales/ko/translation.json (1)

147-151: 日本語版との一貫性が確保されています

韓国語版のエラーメッセージが日本語版と同様の構造を保ち、技術用語の翻訳も適切に対応しています。

locales/en/translation.json (1)

147-151: 英語版と日本語版で適切な言語適応がされています

英語版は簡潔な表現を使用しつつ、日本語版では必要な説明的な要素が追加されており、各言語の特性に合わせた適切な翻訳となっています。

Comment on lines +56 to +64
const trimmedChunks = accumulatedChunks.trimStart()
const data = JSON.parse(trimmedChunks.slice(6))

if (data.choices && data.choices.length > 0) {
const content = data.choices[0].delta.content
controller.enqueue(content)
accumulatedChunks = ''
}
} catch (error) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

JSONパース時のデータ処理をより堅牢にしてください

trimmedChunks.slice(6) で先頭6文字を削除していますが、固定の文字数を切り取る方法はデータ形式の変更に弱く、エラーを引き起こす可能性があります。データの先頭に余分な文字が含まれる理由を確認し、必要であれば正規表現やプロトコルに基づいて不要な部分を安全に除去する方法を検討してください。

修正の提案:

  • データの先頭にある不要なプレフィックスがある場合、そのプレフィックスを明示的に検出して削除する。
  • 可能であれば、サーバー側のレスポンス形式を調整し、クライアント側での追加処理を不要にする。

Comment on lines +96 to +105
const lastMessage = processedMessages[processedMessages.length - 1]
const messageToSave = {
session_id: sessionId,
role: lastMessage.role,
content: Array.isArray(lastMessage.content)
? JSON.stringify(lastMessage.content)
: lastMessage.content,
created_at: created_at,
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

メッセージが存在しない場合の処理を追加してください

processedMessages が空の場合、processedMessages[processedMessages.length - 1]undefined となり、エラーが発生します。メッセージが存在するか確認し、適切なエラーハンドリングを行ってください。

以下のように修正できます:

const lastMessage = processedMessages[processedMessages.length - 1]

+ if (!lastMessage) {
+   throw new Error('メッセージが存在しません')
+ }

const messageToSave = {
  session_id: sessionId,
  role: lastMessage.role,
  content: Array.isArray(lastMessage.content)
    ? JSON.stringify(lastMessage.content)
    : lastMessage.content,
  created_at: created_at,
}
📝 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 lastMessage = processedMessages[processedMessages.length - 1]
const messageToSave = {
session_id: sessionId,
role: lastMessage.role,
content: Array.isArray(lastMessage.content)
? JSON.stringify(lastMessage.content)
: lastMessage.content,
created_at: created_at,
}
const lastMessage = processedMessages[processedMessages.length - 1]
if (!lastMessage) {
throw new Error('メッセージが存在しません')
}
const messageToSave = {
session_id: sessionId,
role: lastMessage.role,
content: Array.isArray(lastMessage.content)
? JSON.stringify(lastMessage.content)
: lastMessage.content,
created_at: created_at,
}

Comment on lines +62 to +79
const { data: existingSession } = await supabase
.from('local_chat_sessions')
.select()
.eq('title', fileName)
.single()

let sessionId

if (existingSession) {
// 既存のセッションが見つかった場合
sessionId = existingSession.id

// updated_at のみ更新
await supabase
.from('local_chat_sessions')
.update({ updated_at: created_at })
.eq('id', sessionId)
} else {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Supabase操作のエラーチェックを追加してください

select および update 操作でエラーが発生した場合、現在のコードではエラーが検出されず、予期しない動作につながる可能性があります。各操作の結果から error オブジェクトを取得し、エラーチェックを行うことをお勧めします。

以下のように修正できます:

// 既存のセッションを検索
- const { data: existingSession } = await supabase
+ const { data: existingSession, error: selectError } = await supabase
  .from('local_chat_sessions')
  .select()
  .eq('title', fileName)
  .single()

+ if (selectError) throw selectError

...

// updated_at のみ更新
- await supabase
+ const { error: updateError } = await supabase
    .from('local_chat_sessions')
    .update({ updated_at: created_at })
    .eq('id', sessionId)

+ if (updateError) throw updateError
📝 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 { data: existingSession } = await supabase
.from('local_chat_sessions')
.select()
.eq('title', fileName)
.single()
let sessionId
if (existingSession) {
// 既存のセッションが見つかった場合
sessionId = existingSession.id
// updated_at のみ更新
await supabase
.from('local_chat_sessions')
.update({ updated_at: created_at })
.eq('id', sessionId)
} else {
const { data: existingSession, error: selectError } = await supabase
.from('local_chat_sessions')
.select()
.eq('title', fileName)
.single()
if (selectError) throw selectError
let sessionId
if (existingSession) {
// 既存のセッションが見つかった場合
sessionId = existingSession.id
// updated_at のみ更新
const { error: updateError } = await supabase
.from('local_chat_sessions')
.update({ updated_at: created_at })
.eq('id', sessionId)
if (updateError) throw updateError
} else {

Comment on lines +22 to +35
const response = await axios.post(
body.localLlmUrl.replace(/\/$/, ''),
{
model: body.model,
messages: body.messages,
stream: true,
},
{
headers: {
'Content-Type': 'application/json',
},
responseType: 'stream',
}
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

ユーザー提供のURLへのリクエストに対するセキュリティ対策を実施してください

ユーザーから提供された localLlmUrl に対してサーバー側でリクエストを行うと、SSRF(サーバーサイドリクエストフォージェリ)の脆弱性を生む可能性があります。localLlmUrl の値を適切にバリデーションし、許可されたドメインやIPアドレスに限定するなどのセキュリティ対策を講じてください。

修正の提案:

  • localLlmUrl を許可リストに基づいて検証し、信頼できるURLのみを許可する。
  • URL オブジェクトを使用してパースし、プロトコルやホスト名をチェックする。

Comment on lines +831 to +832
<br />
ex. LM Studio: http://localhost:1234/v1/chat/completions
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

URLの検証とセキュリティ強化が必要です

ローカルLLMのURL入力において、以下の改善が推奨されます:

  • URLの形式検証
  • プロトコルの制限(http/httpsのみ許可)
  • ローカルホストのアドレス検証

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

+ const validateLocalLlmUrl = (url: string): boolean => {
+   try {
+     const parsedUrl = new URL(url);
+     return (
+       (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:') &&
+       (parsedUrl.hostname === 'localhost' || parsedUrl.hostname === '127.0.0.1')
+     );
+   } catch {
+     return false;
+   }
+ };

  <input
    className="text-ellipsis px-16 py-8 w-col-span-2 bg-surface1 hover:bg-surface1-hover rounded-8"
    type="text"
    placeholder="..."
    value={localLlmUrl}
-   onChange={(e) =>
-     settingsStore.setState({ localLlmUrl: e.target.value })
-   }
+   onChange={(e) => {
+     const newUrl = e.target.value;
+     if (newUrl === '' || validateLocalLlmUrl(newUrl)) {
+       settingsStore.setState({ localLlmUrl: newUrl });
+     }
+   }}
  />

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

@tegnike tegnike changed the title 会話履歴更新時にSupabaseにデータを保存 会話履歴更新時にSupabaseにデータを保存 & ローカルLLM修正 Dec 6, 2024
@tegnike tegnike merged commit f54e7ac into develop Dec 6, 2024
3 checks passed
@tegnike tegnike deleted the feature/add-supabase-connection branch December 6, 2024 22:58
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 (2)
src/pages/api/save-chat-log.ts (2)

8-13: 環境変数の検証を強化することを推奨します

環境変数の存在チェックは行われていますが、より堅牢な実装が可能です。

以下のような実装を推奨します:

-if (process.env.SUPABASE_URL && process.env.SUPABASE_SERVICE_ROLE_KEY) {
+const supabaseUrl = process.env.SUPABASE_URL
+const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY
+
+if (!supabaseUrl || !supabaseKey) {
+  console.warn('Supabase credentials are not configured. Chat logs will only be saved locally.')
+} else {
   supabase = createClient(
-    process.env.SUPABASE_URL!,
-    process.env.SUPABASE_SERVICE_ROLE_KEY!
+    supabaseUrl,
+    supabaseKey
   )
 }

60-61: TODOコメントの詳細化または削除を検討してください

「標準化する」というTODOコメントが曖昧です。具体的な課題や目標を記載することで、将来の開発者がより理解しやすくなります。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 43509b0 and b908f35.

📒 Files selected for processing (1)
  • src/pages/api/save-chat-log.ts (3 hunks)
🔇 Additional comments (2)
src/pages/api/save-chat-log.ts (2)

63-80: Supabase操作のエラーチェックを追加してください

selectおよびupdate操作のエラーハンドリングが不足しています。


97-106: ⚠️ Potential issue

メッセージのバリデーションを追加してください

メッセージの処理前に適切なバリデーションを行うことで、より安全な実装になります。

以下のような実装を推奨します:

+interface Message {
+  role: string;
+  content: string | Array<{type: string; image?: string; text?: string}>;
+}
+
+function validateMessage(message: Message): void {
+  if (!message.role) {
+    throw new Error('メッセージにroleが含まれていません')
+  }
+  if (!message.content) {
+    throw new Error('メッセージにcontentが含まれていません')
+  }
+}

 const lastMessage = processedMessages[processedMessages.length - 1]
+if (!lastMessage) {
+  throw new Error('メッセージが存在しません')
+}
+validateMessage(lastMessage)

Likely invalid or redundant comment.


try {
const { messages, isNewFile } = req.body
const created_at = new Date().toISOString()
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 created_at = new Date().toISOString()
+let created_at: string
+try {
+  created_at = new Date().toISOString()
+} catch (error) {
+  console.error('タイムスタンプの生成に失敗しました:', error)
+  throw new Error('タイムスタンプの生成に失敗しました')
+}

// ... 

-const fileName = isNewFile
-  ? `log_${created_at.replace(/[:.]/g, '-')}.json`
-  : getLatestLogFile(logsDir)
+let fileName: string
+try {
+  fileName = isNewFile
+    ? `log_${created_at.replace(/[:.]/g, '-')}.json`
+    : getLatestLogFile(logsDir)
+} catch (error) {
+  console.error('ファイル名の生成に失敗しました:', error)
+  throw new Error('ファイル名の生成に失敗しました')
+}

Also applies to: 54-54

terisuke pushed a commit to terisuke/aituber-kit that referenced this pull request Dec 5, 2025
…ection

会話履歴更新時にSupabaseにデータを保存 & ローカルLLM修正
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