feat: implement QuestionBank CRUD with pagination and template query
- 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
This commit is contained in:
+265
@@ -0,0 +1,265 @@
|
||||
console.log('Final LLM model used (default):', llmModel ? llmModel.name : '无');
|
||||
`data: ${JSON.stringify({ type: 'error', data: '请在模型管理中添加LLM模型并配置API密钥' })}\n\n`,
|
||||
`data: ${JSON.stringify({ type: 'error', data: error.message || '服务器错误' })}\n\n`,
|
||||
`data: ${JSON.stringify({ type: 'error', data: '未找到LLM模型配置' })}\n\n`,
|
||||
console.log('ユーザーID:', userId);
|
||||
console.log('API Key プレフィックス:', modelConfig.apiKey?.substring(0, 10) + '...');
|
||||
提供されたテキスト内容を、ユーザーの指示に基づいて修正または改善してください。
|
||||
挨拶や結びの言葉(「わかりました、こちらが...」など)は含めず、修正後の内容のみを直接出力してください。
|
||||
コンテキスト(現在の内容):
|
||||
ユーザーの指示:
|
||||
* 対話内容に基づいてチャットのタイトルを自動生成する
|
||||
* アプリケーション全体で使用される定数定義
|
||||
* Elasticsearch スコアを 0-1 の範囲に正規化する
|
||||
* Elasticsearch のスコアは 1.0 を超える可能性があるため、正規化が必要
|
||||
* ただし、kNN検索の類似度スコアは既に0-1の範囲にある(cosine similarity)ので、
|
||||
* 特別な正規化は不要。必要に応じて最小値保護のみ行う。
|
||||
* 指定されたファイルのすべてのチャンクを取得
|
||||
基于以下知识库内容回答用户问题。
|
||||
**重要提示**: 用户已选择特定知识组,请严格基于以下知识库内容回答。如果知识库中没有相关信息,请明确告知用户:"${noMatchMsg}",然后再提供答案。
|
||||
知识库内容:
|
||||
历史对话:
|
||||
用户问题:{question}
|
||||
请用Chinese回答,并严格遵循以下 Markdown 格式要求:
|
||||
1. **段落与结构**:
|
||||
- 使用清晰的段落分隔,每个要点之间空一行
|
||||
- 使用标题(## 或 ###)组织长回答
|
||||
2. **文本格式**:
|
||||
- 使用 **粗体** 强调重要概念和关键词
|
||||
- 使用列表(- 或 1.)组织多个要点
|
||||
- 使用 \`代码\` 标记技术术语、命令、文件名
|
||||
3. **代码展示**:
|
||||
- 使用代码块展示代码,并指定语言:
|
||||
return "示例"
|
||||
- 支持语言:python, javascript, typescript, java, bash, sql 等
|
||||
4. **图表与可视化**:
|
||||
- 使用 Mermaid 语法绘制流程图、序列图等:
|
||||
A[开始] --> B[处理]
|
||||
B --> C[结束]
|
||||
- 适用场景:流程、架构、状态机、时序图
|
||||
5. **其他要求**:
|
||||
- 回答精炼准确
|
||||
- 多步骤操作使用有序列表
|
||||
- 对比类信息建议用表格展示(如果适用)
|
||||
作为智能助手,请回答用户的问题。
|
||||
请用Chinese回答。
|
||||
以下のナレッジベースの内容に基づいてユーザーの質問に答えてください。
|
||||
**重要**: ユーザーが特定の知識グループを選択しました。以下のナレッジベースの内容に厳密に基づいて回答してください。ナレッジベースに関連情報がない場合は、「${noMatchMsg}」とユーザーに明示的に伝えてから、回答を提供してください。
|
||||
ナレッジベースの内容:
|
||||
会話履歴:
|
||||
ユーザーの質問:{question}
|
||||
Japaneseで回答してください。以下の Markdown 書式要件に厳密に従ってください:
|
||||
1. **段落と構造**:
|
||||
- 明確な段落分けを使用し、要点間に空行を入れる
|
||||
- 長い回答には見出し(## または ###)を使用
|
||||
2. **テキスト書式**:
|
||||
- 重要な概念やキーワードを強調するために **太字** を使用
|
||||
- 複数のポイントを整理するためにリスト(- または 1.)を使用
|
||||
- 技術用語、コマンド、ファイル名をマークするために \`コード\` を使用
|
||||
3. **コード表示**:
|
||||
- 言語を指定してコードブロックを使用:
|
||||
return "例"
|
||||
- 対応言語:python, javascript, typescript, java, bash, sql など
|
||||
4. **図表とチャート**:
|
||||
- フローチャート、シーケンス図などに Mermaid 構文を使用:
|
||||
A[開始] --> B[処理]
|
||||
B --> C[終了]
|
||||
- 使用例:プロセスフロー、アーキテクチャ図、状態図、シーケンス図
|
||||
5. **その他の要件**:
|
||||
- 簡潔で明確な回答を心がける
|
||||
- 複数のステップがある場合は番号付きリストを使用
|
||||
- 比較情報には表を使用(該当する場合)
|
||||
インテリジェントアシスタントとして、ユーザーの質問に答えてください。
|
||||
Japaneseで回答してください。
|
||||
return `你是一个文档分析师。请阅读以下文本(文档开Header分),并生成一个简炼、专业的标题(不超过50个字符)。
|
||||
只返回标题文本。不要包含任何解释性文字或前导词(如“标题是:”)。
|
||||
语言:Chinese
|
||||
文本内容:
|
||||
return `あなたはドキュメントアナライザーです。以下のテキスト(ドキュメントの冒頭部分)を読み、簡潔でプロフェッショナルなタイトル(最大50文字)を生成してください。
|
||||
タイトルテキストのみを返してください。説明文や前置き(例:「タイトルは:」)は含めないでください。
|
||||
言語:Japanese
|
||||
テキスト:
|
||||
return `根据以下对话片段,生成一个简短、描述性的标题(不超过50个字符),总结讨论的主题。
|
||||
只返回标题文本。不要包含任何前导词。
|
||||
片段:
|
||||
用户: ${userMessage}
|
||||
助手: ${aiResponse}`;
|
||||
return `以下の会話スニペットに基づいて、トピックを要約する短く説明的なタイトル(最大50文字)を生成してください。
|
||||
タイトルのみを返してください。前置きは不要です。
|
||||
スニペット:
|
||||
ユーザー: ${userMessage}
|
||||
アシスタント: ${aiResponse}`;
|
||||
* Chunk configurationサービス
|
||||
* チャンクパラメータの検証と管理を担当し、モデルの制限や環境変数の設定に適合していることを確認します
|
||||
* 制限の優先順位:
|
||||
* 1. 環境変数 (MAX_CHUNK_SIZE, MAX_OVERLAP_SIZE)
|
||||
* 2. データベース内のモデル設定 (maxInputTokens, maxBatchSize)
|
||||
* 3. デフォルト値
|
||||
* モデルの制限設定を取得(データベースから読み込み)
|
||||
const providerName = modelConfig.providerName || '不明';
|
||||
` - プロバイダー: ${providerName}\n` +
|
||||
` - Token制限: ${maxInputTokens}\n` +
|
||||
` - ベクトルモデルか: ${isVectorModel}`,
|
||||
* Chunk configurationを検証および修正
|
||||
* 優先順位: 環境変数の上限 > モデルの制限 > ユーザー設定
|
||||
* 推奨されるバッチサイズを取得
|
||||
* チャンク数を推定
|
||||
* ベクトル次元の検証
|
||||
* 設定概要を取得(ログ用)
|
||||
`Chunk size: ${chunkSize} tokens (制限: ${limits.maxInputTokens})`,
|
||||
`重なりサイズ: ${chunkOverlap} tokens`,
|
||||
`バッチサイズ: ${limits.maxBatchSize}`,
|
||||
* フロントエンド用のConfig limitsを取得
|
||||
* フロントエンドのスライダーの上限設定に使用
|
||||
throw new Error(`埋め込みモデル設定 ${embeddingModelConfigId} が見つかりません`);
|
||||
throw new Error(`モデル ${modelConfig.name} は無効化されているため、埋め込みベクトルを生成できません`);
|
||||
throw new Error(`モデル ${modelConfig.name} に baseUrl が設定されていません`);
|
||||
* モデルIDに基づいて最大バッチサイズを決定
|
||||
* 単一バッチの埋め込み処理
|
||||
`総計 ${totalLength} 文字、平均 ${Math.round(avgLength)} 文字、` +
|
||||
`モデル制限: ${modelConfig.maxInputTokens || 8192} tokens`
|
||||
`テキスト長がモデルの制限。` +
|
||||
`現在: ${texts.length} 個のテキストで計 ${totalLength} 文字、` +
|
||||
`モデル制限: ${modelConfig.maxInputTokens || 8192} tokens。` +
|
||||
`アドバイス: Chunk sizeまたはバッチサイズを小さくしてください`
|
||||
this.logger.error(`リクエストパラメータ: model=${modelConfig.modelId}, inputLength=${texts[0]?.length}`);
|
||||
throw new Error(`埋め込み API の呼び出しに失敗しました: ${response.statusText} - ${errorText}`);
|
||||
* Fetch chunk configuration limits(フロントエンドのスライダー設定用)
|
||||
* クエリパラメータ: embeddingModelId - Embedding model ID
|
||||
* Fast Mode処理(既存フロー)
|
||||
* Precise Mode処理(新規フロー)
|
||||
* Precise Modeの結果をインデックス
|
||||
* PDF の特定ページの画像を取得
|
||||
if (error.message && (error.message.includes('context length') || error.message.includes('コンテキスト長 exceeds limit ') || error.message.includes('コンテキスト長 exceeds limit '))) {
|
||||
* バッチ処理、メモリ制御付き
|
||||
* 失敗したファイルのベクトル化を再試行
|
||||
throw new NotFoundException('ファイルが存在しません');
|
||||
* ファイルのすべてのチャンク情報を取得
|
||||
* モデルの実際の次元数を取得(キャッシュ確認とプローブロジック付き)
|
||||
* AIを使用して文書のタイトルを自動生成する
|
||||
* 現在のメモリ使用状況を取得
|
||||
* メモリ exceeds limit に近づいているかチェック
|
||||
* メモリが利用可能になるまで待機(タイムアウトあり)
|
||||
throw new Error(`メモリ待機がタイムアウトしました: 現在 ${this.getMemoryUsage().heapUsed}MB > ${this.MAX_MEMORY_MB * 0.85}MB`);
|
||||
* ガベージコレクションを強制実行(可能な場合)
|
||||
* バッチサイズを動的に調整
|
||||
* 大規模データの処理:自動バッチングとメモリ制御
|
||||
* 処理に必要なメモリを見積もる
|
||||
* バッチ処理を使用すべきかチェック
|
||||
* LibreOffice サービスインターフェース定義
|
||||
* LibreOffice サービスの状態をチェック
|
||||
* ドキュメントを PDF に変換
|
||||
* @param filePath 変換するファイルのパス
|
||||
* @returns PDF ファイルのパス
|
||||
throw new Error(`ファイルが存在しません: ${filePath}`);
|
||||
throw new Error('変換がタイムアウトしました。ファイルが大きすぎる可能性があります');
|
||||
throw new Error(`変換に失敗しました: ${detail}`);
|
||||
throw new Error(`変換に失敗しました: ${lastError.message}`);
|
||||
throw new Error('LibreOffice サービスが実行されていません。サービスの状態を確認してください');
|
||||
throw new Error('LibreOffice サービスとの接続が切断されました。サービスが不安定である可能性があります');
|
||||
* ファイルの一括変換
|
||||
* サービスのバージョン情報を取得
|
||||
@Min(1, { message: 'ベクトル次元の最小値は 1 です' })
|
||||
@Max(4096, { message: 'ベクトル次元の最大値は 4096 です(Elasticsearch の制限)' })
|
||||
* モデルの入力トークン制限(embedding/rerank にのみ有効)
|
||||
* バッチ処理の制限(embedding/rerank にのみ有効)
|
||||
* ベトルモデルかどうか
|
||||
* モデルプロバイダー名
|
||||
* このモデルを有効にするかどうか
|
||||
* このモデルをデフォルトとして使用するかどうか
|
||||
* モデルの入力トークン制限
|
||||
* 例: OpenAI=8191, Gemini=2048
|
||||
* 一括処理制限(1回のリクエストあたりの最大入力数)
|
||||
* 例: OpenAI=2048, Gemini=100
|
||||
* ベトルモデルかどうか(システム設定での識別用)
|
||||
* ユーザーは使用しないモデルを無効にして、誤選択を防ぐことができます
|
||||
* 各タイプ(llm, embedding, rerank)ごとに1つのみデフォルトにできます
|
||||
* モデルプロバイダー名(表示および識別用)
|
||||
* 例: "OpenAI", "Google Gemini", "Custom"
|
||||
* 指定されたモデルをデフォルトに設定
|
||||
* 指定されたタイプのデフォルトモデルを取得
|
||||
* 厳密なルール:Index Chat Configで指定されたモデルのみを返し、なければエラーを投げる
|
||||
* PDF 转图片接口定义
|
||||
* PDF を画像リストに変換します
|
||||
* ImageMagick の convert コマンドを使用します
|
||||
throw new Error(`PDF ファイルが存在しません: ${pdfPath}`);
|
||||
throw new Error('PDF のページ数を取得できません');
|
||||
throw new Error(`Python での変換に失敗しました: ${result.error}`);
|
||||
throw new Error(`PDF から画像への変換に失敗しました: ${error.message}`);
|
||||
* 複数の PDF を一括変換
|
||||
* 画像ファイルのクリーンアップ
|
||||
* ディレクトリのクリーンアップ
|
||||
* 画像品質が妥当か確認
|
||||
throw new Error('Embedding model IDが提供されていません');
|
||||
* Search resultsの重複排除
|
||||
* クエリを拡張してバリエーションを生成
|
||||
* 仮想的なドキュメント(HyDE)を生成
|
||||
* 内部タスク用の LLM インスタンスを取得
|
||||
* リランクの実行
|
||||
* @param query ユーザーのクエリ
|
||||
* @param documents 候補ドキュメントリスト
|
||||
* @param userId ユーザーID
|
||||
* @param rerankModelId 選択された Rerank モデル設定ID
|
||||
* @param topN 返す結果の数 (上位 N 個)
|
||||
return { message: '对话历史删除成功' };
|
||||
`ユーザー ${req.user.id} がファイルをアップロードしました: ${file.originalname} (${this.formatBytes(file.size)})`,
|
||||
console.log('パスワード:', randomPassword);
|
||||
console.log('=== updateLanguage デバッグ ===');
|
||||
console.log('=== getLanguage デバッグ ===');
|
||||
* システム全体のグローバル設定を取得する
|
||||
* システム全体のグローバル設定を更新する
|
||||
* Vision 服务接口定义
|
||||
* 単一画像の分析(ドキュメントページ)
|
||||
* 実際の画像分析を実行
|
||||
page: pageIndex ? ` (第 ${pageIndex} ページ)` : '',
|
||||
* 再試行可能なエラーかどうかを判断
|
||||
if (errorCode === 429 || errorMessage.includes('rate limit') || errorMessage.includes('リクエストが多すぎます')) {
|
||||
* 遅延関数
|
||||
* 複数画像の一括分析
|
||||
* 画像品質のチェック
|
||||
return { isGood: false, reason: `ファイルが小さすぎます (${sizeKB.toFixed(2)}KB)`, score: 0 };
|
||||
return { isGood: false, reason: `ファイルが大きすぎます (${sizeKB.toFixed(2)}KB)`, score: 0 };
|
||||
* サポートされている画像ファイルかどうかを確認
|
||||
* MIME タイプを取得
|
||||
* 旧インターフェース互換:単一画像の内容を抽出
|
||||
* コスト制御およびクォータ管理サービス
|
||||
* Vision Pipeline の API 呼び出しコストを管理するために使用されます
|
||||
* 処理コストの推定
|
||||
* ユーザーのクォータをチェック
|
||||
reason: `クォータ不足: 残り $${quota.remaining.toFixed(2)}, 必要 $${estimatedCost.toFixed(2)}`,
|
||||
* クォータの差し引き
|
||||
* ユーザーのクォータを取得
|
||||
throw new Error(`ユーザー ${userId} は存在しません`);
|
||||
* 月間クォータのチェックとリセット
|
||||
* ユーザーのクォータ制限を設定
|
||||
* コストレポートの取得
|
||||
* コスト警告閾値のチェック
|
||||
message: `⚠️ クォータ使用率が ${usagePercent.toFixed(1)}% に達しました。残り $${quota.remaining.toFixed(2)}`,
|
||||
message: `💡 クォータ使用率 ${usagePercent.toFixed(1)}%。コストの管理に注意してください`,
|
||||
* コスト表示のフォーマット
|
||||
* 時間表示のフォーマット
|
||||
return `${seconds.toFixed(0)}秒`;
|
||||
return `${minutes}分${remainingSeconds.toFixed(0)}秒`;
|
||||
* Vision Pipeline サービス(コスト制御付き)
|
||||
* これは vision-pipeline.service.ts の拡張版であり、コスト制御が統合されています
|
||||
* メイン処理フロー:Precise Mode(コスト制御付き)
|
||||
this.updateStatus('converting', 10, 'ドキュメント形式を変換中...');
|
||||
this.updateStatus('splitting', 30, 'PDF を画像に変換中...');
|
||||
throw new Error('PDF から画像への変換に失敗しました。画像が生成されませんでした');
|
||||
this.updateStatus('checking', 40, 'クォータを確認し、コストを見積もり中...');
|
||||
this.updateStatus('analyzing', 50, 'ビジョンモデルを使用してページをAnalyzing...');
|
||||
this.updateStatus('completed', 100, '処理が完了しました。一時ファイルをクリーンアップ中...');
|
||||
* Vision モデル設定の取得
|
||||
throw new Error(`モデル設定が見つかりません: ${modelId}`);
|
||||
* PDF への変換
|
||||
* 形式検出とモードの推奨(コスト見積もり付き)
|
||||
reason: `サポートされていないファイル形式です: ${ext}`,
|
||||
warnings: ['Fast Mode(テキスト抽出のみ)を使用します'],
|
||||
reason: `形式 ${ext} はPrecise Modeをサポートしていません`,
|
||||
reason: 'ファイルが大きいため、完全な情報を保持するためにPrecise Modeを推奨します',
|
||||
warnings: ['処理時間が長くなる可能性があります', 'API 費用が発生します'],
|
||||
reason: 'Precise Modeが利用可能です。テキストと画像の混合コンテンツを保持できます',
|
||||
warnings: ['API 費用が発生します'],
|
||||
* ユーザーのクォータ情報を取得
|
||||
* 処理状態の更新(リアルタイムフィードバック用)
|
||||
* Vision Pipeline 接口定义
|
||||
Reference in New Issue
Block a user