KNOWLEDGE_BASE_ENHANCEMENTS.md 14 KB

ナレッジベースの強化機能設計

🎯 機能概要

今回の開発には、以下の3つのコア機能が含まれます:

  1. ナレッジベースのグループ化 - グループを作成し、ドキュメントを複数のグループに所属させ、検索時にグループを指定可能にします。
  2. 検索履歴 - 対話プロセス全体を保存し、過去の会話の閲覧や再開を可能にします。
  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 (完了)

  1. ✅ データベースのマイグレーションスクリプト
  2. ✅ グループ管理 API
  3. ✅ 履歴管理 API
  4. ✅ PDF プレビュー API
  5. ✅ チャットサービスの強化 (グループフィルタリングと履歴保存)
  6. ✅ Elasticsearch のグループフィルタリング機能

🔄 フェーズ2: フロントエンドコンポーネント開発 (進行中)

  1. ⏳ グループ管理コンポーネント (基本機能は実装済み。アクセス方法を最適化予定)
  2. ⏳ 履歴管理コンポーネント (基本機能は実装済み)
  3. ⏳ PDF プレビューコンポーネント (基本機能は実装済み)
  4. UI の刷新と設定の統合: ヘッダーとサイドバーを整理し、設定の入り口を統一。新機能のためのスペースを確保。

⏳ フェーズ3: 統合とテスト (待機中)

  1. ⏳ 機能の統合
  2. ⏳ エンドツーエンド (E2E) テスト
  3. ⏳ パフォーマンスの最適化

✅ 完了済みのバックエンド開発

データベース設計

  • ✅ 4つの新しいテーブルを作成:knowledge_groupsknowledge_base_groupssearch_historychat_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 プレビュー > 履歴管理