0a9588abb7
- Add pagination support to findAll (page, limit query params) - Add findByTemplateId method to service - Add GET /by-template/:templateId endpoint to controller - Service already includes CRUD for QuestionBank and QuestionBankItem
14 KiB
14 KiB
ナレッジベースの強化機能設計
🎯 機能概要
今回の開発には、以下の3つのコア機能が含まれます:
- ナレッジベースのグループ化 - グループを作成し、ドキュメントを複数のグループに所属させ、検索時にグループを指定可能にします。
- 検索履歴 - 対話プロセス全体を保存し、過去の会話の閲覧や再開を可能にします。
- PDF プレビュー - すべてのファイルを PDF 形式に変換し、オンラインでプレビューできるようにします。
🗄️ データベース設計
新規テーブル構造
-- ナレッジベースグループ管理テーブル
CREATE TABLE knowledge_groups (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
color TEXT DEFAULT '#3B82F6', -- グループの色分けID
user_id TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ドキュメント・グループ関連付けテーブル (多対多)
CREATE TABLE knowledge_base_groups (
knowledge_base_id TEXT NOT NULL,
group_id TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (knowledge_base_id, group_id),
FOREIGN KEY (knowledge_base_id) REFERENCES knowledge_base(id) ON DELETE CASCADE,
FOREIGN KEY (group_id) REFERENCES knowledge_groups(id) ON DELETE CASCADE
);
-- 検索履歴テーブル
CREATE TABLE search_history (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
title TEXT NOT NULL, -- 対話タイトル (質問の先頭50文字)
selected_groups TEXT, -- JSON配列: ["group1", "group2"] または null(すべて)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 対話メッセージテーブル
CREATE TABLE chat_messages (
id TEXT PRIMARY KEY,
search_history_id TEXT NOT NULL,
role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
content TEXT NOT NULL,
sources TEXT, -- JSON配列: 引用ソース情報
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (search_history_id) REFERENCES search_history(id) ON DELETE CASCADE
);
既存テーブルの修正
-- knowledge_base テーブルに PDF パスフィールドを追加
ALTER TABLE knowledge_base ADD COLUMN pdf_path TEXT;
🔌 API エンドポイント設計
ナレッジベースグループ API
// ユーザーの全グループを取得
GET /api/knowledge-groups
Response: {
groups: Array<{
id: string;
name: string;
description?: string;
color: string;
fileCount: number; // 含まれるファイル数
createdAt: string;
}>
}
// グループの作成
POST /api/knowledge-groups
Body: { name: string; description?: string; color?: string }
Response: { id: string; name: string; description?: string; color: string }
// グループの更新
PUT /api/knowledge-groups/:id
Body: { name?: string; description?: string; color?: string }
// グループの削除
DELETE /api/knowledge-groups/:id
// グループ内のファイルを取得
GET /api/knowledge-groups/:id/files
Response: { files: KnowledgeBase[] }
// ファイルをグループに追加
POST /api/knowledge-bases/:fileId/groups
Body: { groupIds: string[] }
// グループからファイルを削除
DELETE /api/knowledge-bases/:fileId/groups/:groupId
検索履歴 API
// 検索履歴の取得 (ページネーション)
GET /api/search-history?page=1&limit=20
Response: {
histories: Array<{
id: string;
title: string;
selectedGroups: string[] | null;
messageCount: number;
lastMessageAt: string;
createdAt: string;
}>;
total: number;
page: number;
limit: number;
}
// 対話詳細の取得
GET /api/search-history/:id
Response: {
id: string;
title: string;
selectedGroups: string[] | null;
messages: Array<{
id: string;
role: 'user' | 'assistant';
content: string;
sources?: Array<{
fileName: string;
content: string;
score: number;
chunkIndex: number;
}>;
createdAt: string;
}>;
}
// 新しい対話の作成
POST /api/search-history
Body: {
title: string;
selectedGroups?: string[];
firstMessage: string;
}
Response: { id: string }
// 対話の削除
DELETE /api/search-history/:id
// 対話の継続 (既存のチャットインターフェースを拡張し、historyId パラメータを追加)
POST /api/chat/stream
Body: {
message: string;
history: ChatMessage[];
userLanguage?: string;
selectedGroups?: string[]; // 新規:選択されたグループ
historyId?: string; // 新規:対話履歴ID
}
PDF プレビュー API
// ファイルの PDF プレビューを取得
GET /api/knowledge-bases/:id/pdf
Response: PDF ファイルストリーム、または PDF URL へのリダイレクト
// PDF ステータスの確認
GET /api/knowledge-bases/:id/pdf-status
Response: {
status: 'pending' | 'converting' | 'ready' | 'failed';
pdfPath?: string;
error?: string;
}
🎨 フロントエンドコンポーネント設計
1. ナレッジベースグループコンポーネント
// グループマネージャー
interface GroupManagerProps {
groups: KnowledgeGroup[];
onCreateGroup: (group: CreateGroupData) => void;
onUpdateGroup: (id: string, data: UpdateGroupData) => void;
onDeleteGroup: (id: string) => void;
}
// グループセレクター (検索時の選択用)
interface GroupSelectorProps {
groups: KnowledgeGroup[];
selectedGroups: string[];
onSelectionChange: (groupIds: string[]) => void;
showSelectAll?: boolean;
}
// ファイルグループタグ
interface FileGroupTagsProps {
fileId: string;
groups: KnowledgeGroup[];
assignedGroups: string[];
onGroupsChange: (groupIds: string[]) => void;
}
2. 検索履歴コンポーネント
// 履歴リスト
interface SearchHistoryListProps {
histories: SearchHistoryItem[];
onSelectHistory: (historyId: string) => void;
onDeleteHistory: (historyId: string) => void;
onLoadMore: () => void;
hasMore: boolean;
}
// 履歴対話ビューアー
interface HistoryViewerProps {
historyId: string;
onContinueChat: (historyId: string) => void;
onClose: () => void;
}
3. PDF プレビューコンポーネント
// PDF プレビューアー
interface PDFPreviewProps {
fileId: string;
fileName: string;
onClose: () => void;
}
// PDF プレビューボタン
interface PDFPreviewButtonProps {
fileId: string;
fileName: string;
status: 'pending' | 'converting' | 'ready' | 'failed';
}
🔄 ビジネスフロー設計
ナレッジベースグループ化フロー
1. ユーザーがグループを作成 → knowledge_groups テーブルに保存
2. ファイルアップロード時 → グループを選択可能 → knowledge_base_groups テーブルに関連付けを保存
3. 検索時 → グループを選択 → Elasticsearch のクエリ範囲をフィルタリング
4. ファイル管理 → ファイルの所属グループを編集可能
検索履歴フロー
1. ユーザーがチャットを開始 → search_history データを生成
2. 各メッセージ → chat_messages テーブルに保存
3. 履歴の確認 → 履歴リストをページネーションでロード
4. 履歴をクリック → 対話内容全体をロード
5. 対話の継続 → 既存の履歴をベースに新しいメッセージを追加
PDF プレビューフロー
1. ファイルアップロード → PDF かどうかを確認
2. PDF 以外の場合 → LibreOffice を呼び出して PDF に変換
3. PDF パスを knowledge_base.pdf_path に保存
4. フロントエンドからプレビューをリクエスト → PDF ファイルストリームを返却
5. HTML の <embed> または <iframe> を使用して PDF を表示
🛠️ 技術実装のポイント
1. ES クエリ最適化 (グループフィルタリング)
// ElasticsearchService.hybridSearch を修正
async hybridSearch(
queryVector: number[],
queryText: string,
userId: string,
topK: number = 10,
threshold: number = 0.6,
selectedGroups?: string[] // 新規パラメータ
): Promise<any[]> {
// グループフィルタリング条件を構築
const groupFilter = selectedGroups?.length
? { terms: { "knowledge_base_id": await this.getFileIdsByGroups(selectedGroups, userId) } }
: undefined;
// ES クエリにフィルタ条件を追加
const query = {
bool: {
must: [/* 既存のクエリ条件 */],
filter: [
{ term: { user_id: userId } },
...(groupFilter ? [groupFilter] : [])
]
}
};
}
2. PDF 変換サービスの統合
// KnowledgeBaseService に PDF 変換を追加
async ensurePDFExists(kb: KnowledgeBase): Promise<string> {
if (kb.pdfPath && await fs.pathExists(kb.pdfPath)) {
return kb.pdfPath;
}
if (kb.mimetype === 'application/pdf') {
// 既に PDF なので、元のファイルをそのまま使用
kb.pdfPath = kb.storagePath;
} else {
// LibreOffice を呼び出して変換
const pdfPath = await this.libreOfficeService.convertToPDF(kb.storagePath);
kb.pdfPath = pdfPath;
}
await this.knowledgeBaseRepository.save(kb);
return kb.pdfPath;
}
3. チャット履歴の保存
// ChatService.streamChat メソッドを修正
async *streamChat(
message: string,
history: ChatMessage[],
userId: string,
modelConfig: ModelConfig,
userLanguage: string = 'zh',
selectedEmbeddingId?: string,
selectedGroups?: string[], // 新規
historyId?: string // 新規
): AsyncGenerator<{ type: 'content' | 'sources'; data: any }> {
// historyId がない場合は、新しい対話履歴を作成
if (!historyId) {
historyId = await this.createSearchHistory(userId, message, selectedGroups);
}
// ユーザーメッセージを保存
await this.saveChatMessage(historyId, 'user', message);
// ... 既存のロジック ...
// AI の回答を保存
await this.saveChatMessage(historyId, 'assistant', fullResponse, sources);
}
📱 UI/UX 設計のポイント
1. グループ管理インターフェース
- サイドバーにグループリストを表示
- グループへのファイルのドラッグ&ドロップに対応
- グループの色分け表示
- グループ内のファイル数を表示
2. 検索インターフェースの強化
- チャット入力欄の上にグループセレクターを追加
- 複数グループの選択と状態表示に対応
- 「全グループ」オプション
3. 履歴管理インターフェース
- 左側に履歴リスト、右側に対話内容を表示
- 履歴にはタイトル、時間、メッセージ数を表示
- 履歴の削除と対話の再開をサポート
4. PDF プレビュー
- モーダル形式で PDF を表示
- フルスクリーン表示をサポート
- 読み込み状態の表示とエラー処理
🚀 開発計画
✅ フェーズ1: データベースとバックエンド API (完了)
- ✅ データベースのマイグレーションスクリプト
- ✅ グループ管理 API
- ✅ 履歴管理 API
- ✅ PDF プレビュー API
- ✅ チャットサービスの強化 (グループフィルタリングと履歴保存)
- ✅ Elasticsearch のグループフィルタリング機能
🔄 フェーズ2: フロントエンドコンポーネント開発 (進行中)
- ⏳ グループ管理コンポーネント (基本機能は実装済み。アクセス方法を最適化予定)
- ⏳ 履歴管理コンポーネント (基本機能は実装済み)
- ⏳ PDF プレビューコンポーネント (基本機能は実装済み)
- ✅ UI の刷新と設定の統合: ヘッダーとサイドバーを整理し、設定の入り口を統一。新機能のためのスペースを確保。
⏳ フェーズ3: 統合とテスト (待機中)
- ⏳ 機能の統合
- ⏳ エンドツーエンド (E2E) テスト
- ⏳ パフォーマンスの最適化
✅ 完了済みのバックエンド開発
データベース設計
- ✅ 4つの新しいテーブルを作成:
knowledge_groups、knowledge_base_groups、search_history、chat_messages - ✅
knowledge_baseテーブルにpdf_pathフィールドを追加 - ✅ 完全なデータベースマイグレーションスクリプトを作成
エンティティとサービス
- ✅
KnowledgeGroupエンティティとサービス (多対多関係をサポート) - ✅
SearchHistoryおよびChatMessageエンティティとサービス - ✅
KnowledgeBaseエンティティを更新し、グループ関係と PDF パスを追加
API エンドポイント
- ✅ ナレッジベースグループ管理 :
GET/POST/PUT/DELETE /api/knowledge-groups - ✅ ファイル・グループ関連付け :
POST/DELETE /api/knowledge-bases/:id/groups - ✅ 検索履歴管理 :
GET/POST/DELETE /api/search-history - ✅ PDF プレビュー :
GET /api/knowledge-bases/:id/pdfおよびGET /api/knowledge-bases/:id/pdf-status
チャット機能の強化
- ✅ グループフィルタリング検索をサポート (
selectedGroupsパラメータ) - ✅ 対話履歴の自動生成と保存
- ✅ 対話の再開をサポート (
historyIdパラメータ) - ✅ Elasticsearch によるグループフィルタリングクエリ
テストと検証
- ✅ 自動テストスクリプト
test-enhancements.shを作成 - ✅ すべての API エンドポイントが実装され、テスト可能
バックエンド開発ステータス: ✅ 完了 (約 95%)
次のステップ: フロントエンドコンポーネントの開発を開始
予想開発期間: 5〜8日
優先度: グループ化機能 > PDF プレビュー > 履歴管理