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:
Developer
2026-04-23 17:19:11 +08:00
commit 0a9588abb7
492 changed files with 112453 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { i18nStore } from './i18n.store';
import { DEFAULT_LANGUAGE } from '../common/constants';
@Injectable()
export class I18nInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const language = request.headers['x-user-language'] || DEFAULT_LANGUAGE;
return new Observable((observer) => {
i18nStore.run({ language: String(language) }, () => {
next.handle().subscribe({
next: (value) => observer.next(value),
error: (err) => observer.error(err),
complete: () => observer.complete(),
});
});
});
}
}
+14
View File
@@ -0,0 +1,14 @@
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { i18nStore } from './i18n.store';
import { DEFAULT_LANGUAGE } from '../common/constants';
@Injectable()
export class I18nMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const language = req.headers['x-user-language'] || DEFAULT_LANGUAGE;
i18nStore.run({ language: String(language) }, () => {
next();
});
}
}
+9
View File
@@ -0,0 +1,9 @@
import { Global, Module } from '@nestjs/common';
import { I18nService } from './i18n.service';
@Global()
@Module({
providers: [I18nService],
exports: [I18nService],
})
export class I18nModule {}
+347
View File
@@ -0,0 +1,347 @@
import { Injectable } from '@nestjs/common';
import { errorMessages, logMessages, statusMessages } from './messages';
import { i18nStore } from './i18n.store';
import { DEFAULT_LANGUAGE } from '../common/constants'; // 使用常量定义的默认语言
@Injectable()
export class I18nService {
private readonly defaultLanguage = DEFAULT_LANGUAGE; // 使用常量定义的默认语言
public normalizeLanguage(lang?: string): string {
let language = lang;
if (!language) {
const store = i18nStore.getStore();
language = store?.language;
}
if (!language) return this.defaultLanguage;
// Normalize language codes (e.g., zh-CN -> zh, en-US -> en)
const normalized = language.split('-')[0].toLowerCase();
return normalized;
}
getErrorMessage(key: string, language?: string): string {
const lang = this.normalizeLanguage(language);
return (
errorMessages[lang]?.[key] ||
errorMessages[this.defaultLanguage][key] ||
key
);
}
getLogMessage(key: string, language?: string): string {
const lang = this.normalizeLanguage(language);
return (
logMessages[lang]?.[key] || logMessages[this.defaultLanguage][key] || key
);
}
getStatusMessage(key: string, language?: string): string {
const lang = this.normalizeLanguage(language);
return (
statusMessages[lang]?.[key] ||
statusMessages[this.defaultLanguage][key] ||
key
);
}
// 汎用メッセージ取得メソッド、順次検索
getMessage(key: string, language?: string): string {
const lang = this.normalizeLanguage(language);
// ステータスメッセージ、エラーメッセージ、ログメッセージの順に検索
return (
statusMessages[lang]?.[key] ||
statusMessages[this.defaultLanguage][key] ||
errorMessages[lang]?.[key] ||
errorMessages[this.defaultLanguage][key] ||
logMessages[lang]?.[key] ||
logMessages[this.defaultLanguage][key] ||
key
);
}
// メッセージの取得とフォーマット
formatMessage(
key: string,
args: Record<string, any>,
language?: string,
): string {
let message = this.getMessage(key, language);
for (const [argKey, argValue] of Object.entries(args)) {
message = message.replace(
new RegExp(`\\{${argKey}\\}`, 'g'),
String(argValue),
);
}
return message;
}
// サポートされている言語リストを取得
getSupportedLanguages(): string[] {
return Object.keys(errorMessages);
}
// 言語がサポートされているか確認
isLanguageSupported(language: string): boolean {
return this.getSupportedLanguages().includes(language);
}
// システムプロンプトを取得
getPrompt(
lang: string = this.defaultLanguage,
type: 'withContext' | 'withoutContext' = 'withContext',
hasKnowledgeGroup: boolean = false,
): string {
const language = this.normalizeLanguage(lang);
const noMatchMsg =
statusMessages[language]?.noMatchInKnowledgeGroup ||
statusMessages[this.defaultLanguage].noMatchInKnowledgeGroup;
if (language === 'zh') {
return type === 'withContext'
? `
基于以下知识库内容回答用户问题。
${
hasKnowledgeGroup
? `
**重要提示**: 用户已选择特定知识组,请严格基于以下知识库内容回答。如果知识库中没有相关信息,请明确告知用户:"${noMatchMsg}",然后再提供答案。
`
: ''
}
知识库内容:
{context}
历史对话:
{history}
用户问题:{question}
请用Chinese回答,并严格遵循以下 Markdown 格式要求:
1. **段落与结构**
- 使用清晰的段落分隔,每个要点之间空一行
- 使用标题(## 或 ###)组织长回答
2. **文本格式**
- 使用 **粗体** 强调重要概念和关键词
- 使用列表(- 或 1.)组织多个要点
- 使用 \`代码\` 标记技术术语、命令、文件名
3. **代码展示**
- 使用代码块展示代码,并指定语言:
\`\`\`python
def example():
return "示例"
\`\`\`
- 支持语言:python, javascript, typescript, java, bash, sql 等
4. **图表与可视化**
- 使用 Mermaid 语法绘制流程图、序列图等:
\`\`\`mermaid
graph LR
A[开始] --> B[处理]
B --> C[结束]
\`\`\`
- 适用场景:流程、架构、状态机、时序图
5. **其他要求**
- 回答精炼准确
- 多步骤操作使用有序列表
- 对比类信息建议用表格展示(如果适用)
`
: `
作为智能助手,请回答用户的问题。
历史对话:
{history}
用户问题:{question}
请用Chinese回答。
`;
} else if (language === 'ja') {
return type === 'withContext'
? `
以下のナレッジベースの内容に基づいて、ユーザーの質問に答えてください。
${
hasKnowledgeGroup
? `
**重要**: ユーザーが特定のナレッジグループを選択しました。以下のナレッジベースの内容に厳密に基づいて回答してください。関連情報がナレッジベースに見つからない場合は、回答を提供する前に、ユーザーに明示的に「${noMatchMsg}」と伝えてください。
`
: ''
}
ナレッジベースの内容:
{context}
会話履歴:
{history}
ユーザーの質問:{question}
日本語で回答し、以下のMarkdown形式のガイドラインに厳密に従ってください。
1. **段落と構造**:
- 明確な段落区切りを使用し、要点の間に空行を入れます
- 見出し(## または ###)を使用して長い回答を整理します
2. **テキスト形式**:
- **太字**を使用して重要な概念やキーワードを強調します
- リスト(- または 1.)を使用して複数のポイントを整理します
- \`コード\`を使用して技術用語、コマンド、ファイル名をマークします
3. **コード表示**:
- 言語指定のあるコードブロックを使用します:
\`\`\`python
def example():
return "示例"
\`\`\`
- サポートされている言語:python, javascript, typescript, java, bash, sqlなど
4. **図とチャート**:
- フローチャート、シーケンス図などにMermaid構文を使用します:
\`\`\`mermaid
graph LR
A[開始] --> B[処理]
B --> C[終了]
\`\`\`
- 使用例:プロセスフロー、アーキテクチャ図、状態遷移図、シーケンス図
5. **その他の要件**:
- 回答は簡潔かつ明確にします
- マルチステップ プロセスには番号付きリストを使用します
- 比較情報には表を使用します(該当する場合)
`
: `
インテリジェントなアシスタントとして、ユーザーの質問に答えてください。
会話履歴:
{history}
ユーザーの質問:{question}
日本語で回答してください。
`;
} else {
// Fallback to English for any other language
return type === 'withContext'
? `
Answer the user's question based on the following knowledge base content.
${
hasKnowledgeGroup
? `
**IMPORTANT**: The user has selected a specific knowledge group. Please answer strictly based on the knowledge base content below. If the relevant information is not found in the knowledge base, explicitly tell the user: "${noMatchMsg}", before providing an answer.
`
: ''
}
Knowledge Base CONTENT:
{context}
Conversation history:
{history}
User question: {question}
Please answer in English and strictly follow these Markdown formatting guidelines:
1. **Paragraphs & Structure**:
- Use clear paragraph breaks with blank lines between key points
- Use headings (## or ###) to organize longer answers
2. **Text Formatting**:
- Use **bold** to emphasize important concepts and keywords
- Use lists (- or 1.) to organize multiple points
- Use \`code\` to mark technical terms, commands, file names
3. **Code Display**:
- Use code blocks with language specification:
\`\`\`python
def example():
return "example"
\`\`\`
- Supported languages: python, javascript, typescript, java, bash, sql, etc.
4. **Diagrams & Charts**:
- Use Mermaid syntax for flowcharts, sequence diagrams, etc.:
\`\`\`mermaid
graph LR
A[Start] --> B[Process]
B --> C[End]
\`\`\`
- Use cases: process flows, architecture diagrams, state diagrams, sequence diagrams
5. **Other Requirements**:
- Keep answers concise and clear
- Use numbered lists for multi-step processes
- Use tables for comparison information (if applicable)
`
: `
As an intelligent assistant, please answer the user's question.
Conversation history:
{history}
User question: {question}
Please answer in English.
`;
}
}
// タイトル生成用のプロンプトを取得
getDocumentTitlePrompt(
lang: string = this.defaultLanguage,
contentSample: string,
): string {
const language = this.normalizeLanguage(lang);
if (language === 'zh') {
return `你是一个文档分析师。请阅读以下文本(文档开头部分),并生成一个简炼、专业的标题(不超过50个字符)。
只返回标题文本。不要包含任何解释性文字或前导词(如“标题是:”)。
语言:Chinese
文本内容:
${contentSample}`;
} else if (language === 'ja') {
return `あなたは文書分析の専門家です。以下のテキスト(文書の冒頭部分)を読み、簡潔で専門的なタイトル(50文字以内)を生成してください。
タイトルのみを返してください。前置きや説明は不要です。
言語:Japanese
テキスト:
${contentSample}`;
} else {
return `You are a document analyzer. Read the following text (start of a document) and generate a concise, professional title (max 50 chars).
Return ONLY the title text. No preamble like "The title is...".
Language: English
Text:
${contentSample}`;
}
}
getChatTitlePrompt(
lang: string = this.defaultLanguage,
userMessage: string,
aiResponse: string,
): string {
const language = this.normalizeLanguage(lang);
if (language === 'zh') {
return `根据以下对话片段,生成一个简短、描述性的标题(不超过50个字符),总结讨论的主题。
只返回标题文本。不要包含任何前导词。
语言:Chinese
片段:
用户: ${userMessage}
助手: ${aiResponse}`;
} else if (language === 'ja') {
return `以下の会話のスニペットに基づいて、話題を要約する短く説明的なタイトル(50文字以内)を生成してください。
タイトルのみを返してください。前置きは不要です。
言語:Japanese
スニペット:
ユーザー: ${userMessage}
アシスタント: ${aiResponse}`;
} else {
return `Based on the following conversation snippet, generate a short, descriptive title (max 50 chars) that summarizes the topic.
Return ONLY the title. No preamble.
Language: English
Snippet:
User: ${userMessage}
Assistant: ${aiResponse}`;
}
}
}
+7
View File
@@ -0,0 +1,7 @@
import { AsyncLocalStorage } from 'async_hooks';
export interface I18nContext {
language: string;
}
export const i18nStore = new AsyncLocalStorage<I18nContext>();
+727
View File
@@ -0,0 +1,727 @@
export const errorMessages = {
zh: {
noEmbeddingModel: '请先在系统设置中配置嵌入模型',
searchFailed: '搜索知识库失败,将基于一般知识回答...',
invalidApiKey: 'API密钥无效',
fileNotFound: '未找到文件',
insufficientQuota: '配额不足',
modelNotConfigured: '未配置模型',
visionModelNotConfigured: '未配置视觉模型',
embeddingDimensionMismatch: '嵌入维度不匹配',
uploadNoFile: '未上传文件',
uploadSizeExceeded: '文件大小超过限制: {size}, 最大允许: {max}',
uploadModelRequired: '必须选择嵌入模型',
uploadTypeUnsupported: '不支持的文件格式: {type}',
chunkOverflow: '切片大小 {size} 超过上限 {max} ({reason})。已自动调整',
chunkUnderflow: '切片大小 {size} 小于最小值 {min}。已自动调整',
overlapOverflow: '重叠大小 {size} 超过上限 {max}。已自动调整',
overlapUnderflow: '重叠大小 {size} 小于最小值 {min}。已自动调整',
overlapRatioExceeded:
'重叠大小 {size} 超过切片大小的50% ({max})。已自动调整',
batchOverflowWarning:
'建议切片大小不超过 {safeSize} 以避免批量处理溢出 (当前: {size}, 模型限制的 {percent}%)',
estimatedChunkCountExcessive: '预计切片数量过多 ({count}),处理可能较慢',
contentAndTitleRequired: '内容和标题为必填项',
embeddingModelNotFound: '找不到嵌入模型 {id} 或类型不是 embedding',
ocrFailed: '提取文本失败: {message}',
noImageUploaded: '未上传图片',
adminOnlyViewList: '只有管理员可以查看用户列表',
passwordsRequired: '当前密码和新密码不能为空',
newPasswordMinLength: '新密码长度不能少于6位',
adminOnlyCreateUser: '只有管理员可以创建用户',
usernamePasswordRequired: '用户名和密码不能为空',
passwordMinLength: '密码长度不能少于6位',
adminOnlyUpdateUser: '只有管理员可以更新用户信息',
userNotFound: '用户不存在',
cannotModifyBuiltinAdmin: '无法修改内置管理员账户',
adminOnlyDeleteUser: '只有管理员可以删除用户',
cannotDeleteSelf: '不能删除自己的账户',
cannotDeleteBuiltinAdmin: '无法删除内置管理员账户',
invalidMemberRole: '无效的角色。只允许 USER 和 TENANT_ADMIN',
incorrectCredentials: '用户名或密码不正确',
incorrectCurrentPassword: '当前密码错误',
usernameExists: '用户名已存在',
noteNotFound: '找不到笔记: {id}',
knowledgeGroupNotFound: '找不到知识组: {id}',
accessDeniedNoToken: '访问被拒绝:缺少令牌',
invalidToken: '无效的令牌',
pdfFileNotFound: '找不到 PDF 文件',
pdfFileEmpty: 'PDF 文件为空,转换可能失败',
pdfConversionFailed: 'PDF 文件不存在或转换失败',
pdfConversionFailedDetail: 'PDF 转换失败(文件 ID: {id}),请稍后重试',
pdfPreviewNotSupported: '该文件格式不支持预览',
pdfServiceUnavailable: 'PDF 服务不可用: {message}',
pageImageNotFound: '找不到页面图像',
pdfPageImageFailed: '无法获取 PDF 页面图像',
someGroupsNotFound: '部分组不存在',
promptRequired: '提示词是必填项',
addLLMConfig: '请在系统设置中添加 LLM 模型',
visionAnalysisFailed: '视觉分析失败: {message}',
visionSystemPrompt:
'您是专业的文档分析助手。请分析此文档图像,并按以下要求以 JSON 格式返回:\n\n1. 提取所有可读文本(按阅读顺序,保持段落和格式)\n2. 识别图像/图表/表格(描述内容、含义和作用)\n3. 分析页面布局(仅文本/文本和图像混合/表格/图表等)\n4. 评估分析质量 (0-1)\n\n响应格式:\n{\n "text": "完整的文本内容",\n "images": [\n {"type": "图表类型", "description": "详细描述", "position": 1}\n ],\n "layout": "布局说明",\n "confidence": 0.95\n}',
retryMechanismError: '重试机制异常',
imageLoadError: '无法读取图像: {message}',
groupNotFound: '分组不存在',
fileDeleted: '文件删除成功',
fileDeletedFromGroup: '文件从分组中移除成功',
kbCleared: '知识库清除成功',
groupSyncSuccess: '分组同步成功',
groupDeleted: '分组删除成功',
searchHistoryDeleted: '搜索历史删除成功',
jwtSecretRequired: 'JWT_SECRET 环境变量未设置',
tenantNotFound: '租户不存在',
usernameRequired: '用户名是必填项',
passwordRequiredForNewUser: '新用户 {username} 需要密码',
importTaskNotFound: '导入任务不存在',
sourcePathNotFound: '源路径不存在: {path}',
targetGroupRequired: '未指定目标分组',
modelConfigNotFound: '找不到模型配置: {id}',
cannotUpdateOtherTenantModel: '无法更新其他租户的模型',
cannotDeleteOtherTenantModel: '无法删除其他租户的模型',
elasticsearchHostRequired: 'ELASTICSEARCH_HOST 环境变量未设置',
},
ja: {
noEmbeddingModel: '先にシステム設定で埋め込みモデルを設定してください',
searchFailed:
'ナレッジベース検索に失敗しました。一般的な知識に基づいて回答します...',
invalidApiKey: 'APIキーが無効です',
fileNotFound: 'ファイルが見つかりません',
insufficientQuota: '利用枠が不足しています',
modelNotConfigured: 'モデルが設定されていません',
visionModelNotConfigured: 'ビジョンモデルが設定されていません',
embeddingDimensionMismatch: '埋め込み次元数が一致しません',
uploadNoFile: 'ファイルがアップロードされていません',
uploadSizeExceeded: 'ファイルサイズが制限: {size}, 最大許容: {max}',
uploadModelRequired: '埋め込みモデルを選択する必要があります',
uploadTypeUnsupported: 'サポートされていないファイル形式です: {type}',
chunkOverflow:
'チャンクサイズ {size} が上限 {max} ({reason}) を超えています。自動調整されました',
chunkUnderflow:
'チャンクサイズ {size} が最小値 {min} 未満.自動調整されました',
overlapOverflow:
'重なりサイズ {size} が上限 {max} を超えています。自動調整されました',
overlapUnderflow:
'重なりサイズ {size} が最小値 {min} 未満.自動調整されました',
overlapRatioExceeded:
'重なりサイズ {size} がチャンクサイズの50% ({max}) を超えています。自動調整されました',
batchOverflowWarning:
'バッチ処理のオーバーフローを避けるため、チャンクサイズを {safeSize} 以下にすることをお勧めします (現在: {size}, モデル制限の {percent}%)',
estimatedChunkCountExcessive:
'推定チャンク数が多すぎます ({count})。処理に時間がかかる可能性があります',
contentAndTitleRequired: '内容とタイトルは必須です',
embeddingModelNotFound:
'埋め込みモデル {id} が見つかりません、またはタイプが embedding ではありません',
ocrFailed: 'テキストの抽出に失敗しました: {message}',
noImageUploaded: '画像がアップロードされていません',
adminOnlyViewList: '管理者のみがユーザーリストを表示できます',
passwordsRequired: '現在のパスワードと新しいパスワードは必須です',
newPasswordMinLength:
'新しいパスワードは少なくとも6文字以上である必要があります',
adminOnlyCreateUser: '管理者のみがユーザーを作成できます',
usernamePasswordRequired: 'ユーザー名とパスワードは必須です',
passwordMinLength: 'パスワードは少なくとも6文字以上である必要があります',
adminOnlyUpdateUser: '管理者のみがユーザー情報を更新できます',
userNotFound: 'ユーザーが見つかりません',
cannotModifyBuiltinAdmin: 'ビルトイン管理者アカウントを変更できません',
adminOnlyDeleteUser: '管理者のみがユーザーを削除できます',
cannotDeleteSelf: '自分自身のアカウントを削除できません',
cannotDeleteBuiltinAdmin: 'ビルトイン管理者アカウントを削除できません',
invalidMemberRole:
'無効な役割です。USER と TENANT_ADMIN のみ許可されています',
incorrectCredentials: 'ユーザー名またはパスワードが間違っています',
incorrectCurrentPassword: '現在のパスワードが間違っています',
usernameExists: 'ユーザー名が既に存在します',
noteNotFound: 'ノートが見つかりません: {id}',
knowledgeGroupNotFound: 'ナレッジグループが見つかりません: {id}',
accessDeniedNoToken: 'アクセス不許可:トークンがありません',
invalidToken: '無効なトークンです',
pdfFileNotFound: 'PDF ファイルが見つかりません',
pdfFileEmpty: 'PDF ファイルが空.変換に失敗した可能性があります',
pdfConversionFailed: 'PDF ファイルが存在しないか、変換に失敗しました',
pdfConversionFailedDetail:
'PDF 変換に失敗しました(ファイル ID: {id})。後でもう一度お試しください',
pdfPreviewNotSupported:
'このファイル形式はプレビューをサポートしていません',
pdfServiceUnavailable: 'PDF サービスを利用できません: {message}',
pageImageNotFound: 'ページ画像が見つかりません',
pdfPageImageFailed: 'PDF ページの画像を取得できませんでした',
someGroupsNotFound: '一部のグループが存在しません',
promptRequired: 'プロンプトは必須です',
addLLMConfig: 'システム設定で LLM モデルを追加してください',
visionAnalysisFailed: 'ビジョン分析に失敗しました: {message}',
visionSystemPrompt:
'あなたはプロフェッショナルなドキュメント分析アシスタントです。このドキュメント画像を分析し、以下の要求に従ってJSON形式で返してください:\n\n1. すべての可読テキストを抽出(読み順で、段落と書式を維持)\n2. 画像/グラフ/テーブルを識別(内容、意味、役割を説明)\n3. ページレイアウトを分析(テキストのみ/テキストと画像混在/テーブル/グラフなど)\n4. 分析品質を評価 (0-1)\n\nレスポンス形式:\n{\n "text": "完全なテキスト内容",\n "images": [\n {"type": "グラフタイプ", "description": "詳細説明", "position": 1}\n ],\n "layout": "レイアウト説明",\n "confidence": 0.95\n}',
retryMechanismError: '再試行メカニズムの異常',
imageLoadError: '画像を読み込めません: {message}',
groupNotFound: 'グループが存在しません',
fileDeleted: 'ファイルが削除されました',
fileDeletedFromGroup: 'ファイルがグループから削除されました',
kbCleared: 'ナレッジベースがクリアされました',
groupSyncSuccess: 'グループ同期が完了しました',
groupDeleted: 'グループが削除されました',
searchHistoryDeleted: '検索履歴が削除されました',
jwtSecretRequired: 'JWT_SECRET 環境変数が設定されていません',
tenantNotFound: 'テナントが見つかりません',
usernameRequired: 'ユーザー名は必須です',
passwordRequiredForNewUser:
'新しいユーザー {username} のパスワードが必要です',
importTaskNotFound: 'インポートタスクが見つかりません',
sourcePathNotFound: 'ソースパスが見つかりません: {path}',
targetGroupRequired: 'ターゲットグループが指定されていません',
modelConfigNotFound: 'モデル設定が見つかりません: {id}',
cannotUpdateOtherTenantModel: '他のテナントのモデルは更新できません',
cannotDeleteOtherTenantModel: '他のテナントのモデルは削除できません',
elasticsearchHostRequired:
'ELASTICSEARCH_HOST 環境変数が設定されていません',
},
en: {
noEmbeddingModel:
'Please configure embedding model in system settings first',
searchFailed:
'Knowledge base search failed, will answer based on general knowledge...',
invalidApiKey: 'Invalid API key',
fileNotFound: 'File not found',
insufficientQuota: 'Insufficient quota',
modelNotConfigured: 'Model not configured',
visionModelNotConfigured: 'Vision model not configured',
embeddingDimensionMismatch: 'Embedding dimensions mismatch',
uploadNoFile: 'No file uploaded',
uploadSizeExceeded: 'File size exceeds limit: {size}, Max allowed: {max}',
uploadModelRequired: 'Embedding model must be selected',
uploadTypeUnsupported: 'Unsupported file type: {type}',
chunkOverflow:
'Chunk size {size} exceeds limit {max} ({reason}). Auto-adjusted',
chunkUnderflow: 'Chunk size {size} is below minimum {min}. Auto-adjusted',
overlapOverflow: 'Overlap size {size} exceeds limit {max}. Auto-adjusted',
overlapUnderflow:
'Overlap size {size} is below minimum {min}. Auto-adjusted',
overlapRatioExceeded:
'Overlap size {size} exceeds 50% of chunk size ({max}). Auto-adjusted',
batchOverflowWarning:
'Recommended chunk size below {safeSize} to avoid batch overflow (Current: {size}, {percent}% of model limit)',
estimatedChunkCountExcessive:
'Estimated chunk count is too high ({count}). Processing may be slow',
contentAndTitleRequired: 'Content and Title are required',
embeddingModelNotFound:
'Embedding model {id} not found or type is not embedding',
ocrFailed: 'Failed to extract text: {message}',
noImageUploaded: 'No image uploaded',
adminOnlyViewList: 'Only admins can view the user list',
passwordsRequired: 'Current and new passwords are required',
newPasswordMinLength: 'New password must be at least 6 characters',
adminOnlyCreateUser: 'Only admins can create users',
usernamePasswordRequired: 'Username and password are required',
usernameRequired: 'Username is required',
passwordMinLength: 'Password must be at least 6 characters',
adminOnlyUpdateUser: 'Only admins can update user info',
userNotFound: 'User not found',
cannotModifyBuiltinAdmin: 'Cannot modify built-in admin account',
adminOnlyDeleteUser: 'Only admins can delete users',
cannotDeleteSelf: 'Cannot delete your own account',
cannotDeleteBuiltinAdmin: 'Cannot delete built-in admin account',
invalidMemberRole: 'Invalid role. Only USER and TENANT_ADMIN are allowed',
incorrectCredentials: 'Incorrect username or password',
incorrectCurrentPassword: 'Incorrect current password',
usernameExists: 'Username already exists',
noteNotFound: 'Note with ID {id} not found',
knowledgeGroupNotFound: 'Knowledge group with ID {id} not found',
accessDeniedNoToken: 'Access Denied: Missing token',
invalidToken: 'Invalid token',
pdfFileNotFound: 'PDF file not found',
pdfFileEmpty: 'PDF file is empty. Conversion may have failed',
pdfConversionFailed: 'PDF file does not exist or conversion failed',
pdfConversionFailedDetail:
'PDF conversion failed for file ID: {id}. Please try again later.',
pdfPreviewNotSupported: 'Preview is not supported for this file format',
pdfServiceUnavailable: 'PDF service unavailable: {message}',
pageImageNotFound: 'Page image not found',
pdfPageImageFailed: 'Could not retrieve PDF page image',
someGroupsNotFound: 'Some groups not found',
promptRequired: 'Prompt is required',
addLLMConfig: 'Please add LLM model in system settings',
visionAnalysisFailed: 'Vision analysis failed: {message}',
visionSystemPrompt:
'You are a professional document analysis assistant. Please analyze this document image and return in JSON format according to the following requirements:\n\n1. Extract all readable text (in reading order, preserving paragraphs and formatting)\n2. Identify images/charts/tables (describe content, meaning, and purpose)\n3. Analyze page layout (text only/mixed text and images/tables/charts, etc.)\n4. Evaluate analysis quality (0-1)\n\nResponse format:\n{\n "text": "complete text content",\n "images": [\n {"type": "chart type", "description": "detailed description", "position": 1}\n ],\n "layout": "layout description",\n "confidence": 0.95\n}',
retryMechanismError: 'Retry mechanism error',
imageLoadError: 'Cannot load image: {message}',
groupNotFound: 'Group not found',
fileDeleted: 'File deleted successfully',
fileDeletedFromGroup: 'File removed from group successfully',
kbCleared: 'Knowledge base cleared successfully',
groupSyncSuccess: 'Group sync completed successfully',
groupDeleted: 'Group deleted successfully',
searchHistoryDeleted: 'Search history deleted successfully',
jwtSecretRequired:
'JWT_SECRET environment variable is required but not set',
tenantNotFound: 'Tenant not found',
importTaskNotFound: 'Import task not found',
sourcePathNotFound: 'Source path not found: {path}',
targetGroupRequired: 'Target group not specified',
modelConfigNotFound: 'Model config not found: {id}',
cannotUpdateOtherTenantModel: 'Cannot update models from another tenant',
cannotDeleteOtherTenantModel: 'Cannot delete models from another tenant',
elasticsearchHostRequired:
'ELASTICSEARCH_HOST environment variable is not set',
libreofficeUrlRequired:
'LIBREOFFICE_URL environment variable is required but not set',
pdfToImageConversionFailed:
'PDF to image conversion failed. No images were generated.',
pdfPageCountError: 'Could not get PDF page count',
parentCategoryNotFound: 'Parent category not found',
categoryNotFound: 'Category not found',
maxCategoryDepthExceeded: 'Maximum category depth (3 levels) exceeded',
userIdRequired: 'User ID is required',
podcastNotFound: 'Podcast not found: {id}',
scriptGenerationFailed: 'Script generation failed to produce valid JSON',
vectorRequired: 'Vector is required for indexing',
apiCallFailed: 'API call failed: {message}',
tikaHostRequired: 'TIKA_HOST environment variable is required but not set',
},
};
export const logMessages = {
zh: {
processingFile: '处理文件: {name} ({size})',
indexingComplete: '索引完成: {id}',
vectorizingFile: '向量化文件: ',
searchQuery: '搜索查询: ',
modelCall: '[模型调用] 类型: {type}, 模型: {model}, 用户: {user}',
memoryStatus: '内存状态: ',
uploadSuccess: '文件上传成功。正在后台索引',
overlapAdjusted: '重叠大小超过切片大小的50%。已自动调整为 {newSize}',
environmentLimit: '环境变量限制',
modelLimit: '模型限制',
configLoaded: '数据库模型配置加载: {name} ({id})',
batchSizeAdjusted: '批量大小从 {old} 调整为 {new} (模型限制: {limit})',
dimensionMismatch: '模型 {id} 维度不匹配: 预期 {expected}, 实际 {actual}',
searchMetadataFailed: '为用户 {userId} 搜索知识库失败',
extractedTextTooLarge: '提取的文本内容过大: {size}MB',
preciseModeUnsupported: '格式 {ext} 不支持精密模式,回退到快速模式',
visionModelNotConfiguredFallback: '未配置视觉模型,回退到快速模式',
visionModelInvalidFallback: '视觉模型配置无效,回退到快速模式',
visionPipelineFailed: '视觉流水线失败,回退到快速模式',
preciseModeComplete: '精密模式提取完成: {pages}页, 费用: ${cost}',
skippingEmptyVectorPage: '跳过第 {page} 页(空向量)',
pdfPageImageError: '获取 PDF 页面图像失败: {message}',
internalServerError: '服务器内部错误',
},
ja: {
processingFile: 'ファイル処理中: {name} ({size})',
indexingComplete: 'インデックス完了: {id}',
vectorizingFile: 'ファイルベクトル化中: ',
searchQuery: '検索クエリ: ',
modelCall:
'[モデル呼び出し] タイプ: {type}, モデル: {model}, ユーザー: {user}',
memoryStatus: 'メモリ状態: ',
uploadSuccess:
'ファイルが正常にアップロードされました。バックグラウンドでインデックス処理を実行中です',
overlapAdjusted:
'オーバーラップサイズがチャンクサイズの50%を超えています。自動的に {newSize} に調整されました',
environmentLimit: '環境変数の制限',
modelLimit: 'モデルの制限',
configLoaded: 'データベースからモデル設定を読み込みました: {name} ({id})',
batchSizeAdjusted:
'バッチサイズを {old} から {new} に調整しました (モデル制限: {limit})',
dimensionMismatch:
'モデル {id} の次元が一致しません: 期待値 {expected}, 実際 {actual}',
searchMetadataFailed:
'ユーザー {userId} のナレッジベース検索に失敗しました',
extractedTextTooLarge: '抽出されたテキストが大きいです: {size}MB',
preciseModeUnsupported:
'ファイル形式 {ext} は精密モードをサポートしていません。高速モードにフォールバックします',
visionModelNotConfiguredFallback:
'ビジョンモデルが設定されていません。高速モードにフォールバックします',
visionModelInvalidFallback:
'ビジョンモデルの設定が無効です。高速モードにフォールバックします',
visionPipelineFailed:
'ビジョンパイプラインが失敗しました。高速モードにフォールバックします',
preciseModeComplete:
'精密モード内容抽出完了: {pages}ページ, コスト: ${cost}',
skippingEmptyVectorPage: '第 {page} ページの空ベクトルをスキップします',
pdfPageImageError: 'PDF ページの画像取得に失敗しました: {message}',
internalServerError: 'サーバー内部エラー',
},
en: {
processingFile: 'Processing file: {name} ({size})',
indexingComplete: 'Indexing complete: {id}',
vectorizingFile: 'Vectorizing file: ',
searchQuery: 'Search query: ',
modelCall: '[Model call] Type: {type}, Model: {model}, User: {user}',
memoryStatus: 'Memory status: ',
uploadSuccess: 'File uploaded successfully. Indexing in background',
overlapAdjusted:
'Overlap size exceeds 50% of chunk size. Auto-adjusted to {newSize}',
environmentLimit: 'Environment variable limit',
modelLimit: 'Model limit',
configLoaded: 'Model config loaded from DB: {name} ({id})',
batchSizeAdjusted:
'Batch size adjusted from {old} to {new} (Model limit: {limit})',
dimensionMismatch:
'Model {id} dimension mismatch: Expected {expected}, Actual {actual}',
searchMetadataFailed: 'Failed to search knowledge base for user {userId}',
extractedTextTooLarge: 'Extracted text is too large: {size}MB',
preciseModeUnsupported:
'Format {ext} not supported for precise mode. Falling back to fast mode',
visionModelNotConfiguredFallback:
'Vision model not configured. Falling back to fast mode',
visionModelInvalidFallback:
'Vision model config invalid. Falling back to fast mode',
visionPipelineFailed: 'Vision pipeline failed. Falling back to fast mode',
preciseModeComplete:
'Precise mode extraction complete: {pages} pages, cost: ${cost}',
skippingEmptyVectorPage: 'Skipping page {page} due to empty vector',
pdfPageImageError: 'Failed to retrieve PDF page image: {message}',
internalServerError: 'Internal server error',
},
};
export const statusMessages = {
zh: {
searching: '正在搜索知识库...',
noResults: '未找到相关知识,将基于一般知识回答...',
searchFailed: '知识库搜索失败,将基于一般知识回答...',
generatingResponse: '正在生成回答',
files: '个文件',
notebooks: '个笔记本',
all: '全部',
items: '个',
searchResults: '搜索结果',
relevantInfoFound: '条相关信息找到',
searchHits: '搜索命中',
relevance: '相关度',
sourceFiles: '源文件',
searchScope: '搜索范围',
error: '错误',
creatingHistory: '创建新对话历史: ',
searchingModelById: '根据ID搜索模型: ',
searchModelFallback: '未找到指定的嵌入模型。使用第一个可用模型。',
noEmbeddingModelFound: '找不到嵌入模型设置',
usingEmbeddingModel: '使用的嵌入模型: ',
startingSearch: '开始搜索知识库...',
searchResultsCount: '搜索结果数: ',
searchFailedLog: '搜索失败',
modelCall: '[模型调用]',
chatStreamError: '聊天流错误',
assistStreamError: '辅助流错误',
file: '文件',
content: '内容',
userLabel: '用户',
assistantLabel: '助手',
intelligentAssistant: '您是智能写作助手。',
assistSystemPrompt:
'请根据用户的指示修正或改进提供的文本内容。不要包含问候语或结束语(如"明白了,这是..."等),直接输出修正后的内容。',
contextLabel: '上下文(当前内容)',
userInstructionLabel: '用户指示',
searchString: '搜索字符串: ',
embeddingModelIdNotProvided: '未提供嵌入模型ID',
generatingEmbeddings: '生成嵌入向量...',
embeddingsGenerated: '嵌入向量生成完成',
dimensions: '维度',
performingHybridSearch: '执行混合搜索...',
esSearchCompleted: 'ES搜索完成',
resultsCount: '结果数',
hybridSearchFailed: '混合搜索失败',
getContextForTopicFailed: '获取主题上下文失败',
noLLMConfigured: '用户未配置LLM模型',
simpleChatGenerationError: '简单聊天生成错误',
noMatchInKnowledgeGroup:
'所选知识组中未找到相关内容,以下是基于模型的一般性回答:',
uploadTextSuccess: '笔记内容已接收。正在后台索引',
passwordChanged: '密码已成功修改',
userCreated: '用户已成功创建',
userInfoUpdated: '用户信息已更新',
userDeleted: '用户已删除',
pdfNoteTitle: 'PDF 笔记 - {date}',
noTextExtracted: '未提取到文本',
kbCleared: '知识库已清空',
fileDeleted: '文件已删除',
pageImageNotFoundDetail: '无法获取 PDF 第 {page} 页’的图像',
groupSyncSuccess: '文件分组已更新',
fileDeletedFromGroup: '文件已从分组中删除',
chunkConfigCorrection: '切片配置已修正: {warnings}',
noChunksGenerated: '文件 {id} 未生成任何切片',
chunkCountAnomaly:
'实际切片数 {actual} 大幅超过预计值 {estimated},可能存在异常',
batchSizeExceeded:
'批次 {index} 的大小 {actual} 超过推荐值 {limit},将拆分处理',
skippingEmptyVectorChunk: '跳过文本块 {index} (空向量)',
contextLengthErrorFallback:
'批次处理发生上下文长度错误,降级到逐条处理模式',
chunkLimitExceededForceBatch:
'切片数 {actual} 超过模型批次限制 {limit},强制进行批次处理',
noteContentRequired: '笔记内容是必填项',
imageAnalysisStarted: '正在使用模型 {id} 分析图像...',
batchAnalysisStarted: '正在分析 {count} 张图像...',
pageAnalysisFailed: '第 {page} 页分析失败',
visionSystemPrompt:
'您是专业的文档分析助手。请分析此文档图像,并按以下要求以 JSON 格式返回:\n\n1. 提取所有可读文本(按阅读顺序,保持段落和格式)\n2. 识别图像/图表/表格(描述内容、含义和作用)\n3. 分析页面布局(仅文本/文本和图像混合/表格/图表等)\n4. 评估分析质量 (0-1)\n\n响应格式:\n{\n "text": "完整的文本内容",\n "images": [\n {"type": "图表类型", "description": "详细描述", "position": 1}\n ],\n "layout": "布局说明",\n "confidence": 0.95\n}',
visionModelCall: '[模型调用] 类型: Vision, 模型: {model}, 页面: {page}',
visionAnalysisSuccess:
'✅ 视觉分析完成: {path}{page}, 文本长度: {textLen}, 图像数: {imgCount}, 布局: {layout}, 置信度: {confidence}%',
conversationHistoryNotFound: '对话历史不存在',
batchContextLengthErrorFallback:
'小文件批次处理发生上下文长度错误,降级到逐条处理模式',
chunkProcessingFailed: '处理文本块 {index} 失败,已跳过: {message}',
singleTextProcessingComplete: '逐条文本处理完成: {count} 个切片',
fileVectorizationComplete:
'文件 {id} 向量化完成。共处理 {count} 个文本块。最终内存: {memory}MB',
fileVectorizationFailed: '文件 {id} 向量化失败',
batchProcessingStarted: '开始批次处理: {count} 个项目',
batchProcessingProgress: '正在处理批次 {index}/{total}: {count} 个项目',
batchProcessingComplete: '批次处理完成: {count} 个项目,耗时 {duration}s',
onlyFailedFilesRetryable: '仅允许重试失败的文件 (当前状态: {status})',
emptyFileRetryFailed: '文件内容为空,无法重试。请重新上传文件。',
ragSystemPrompt:
'您是专业的知识库助手。请根据以下提供的文档内容回答用户的问题。',
ragRules:
'## 规则:\n1. 仅根据提供的文档内容进行回答,请勿编造信息。\n2. 如果文档中没有相关信息,请告知用户。\n3. 请在回答中注明信息来源。格式:[文件名.扩展子]\n4. 如果多个文档中的信息存在矛盾,请进行综合分析或解释不同的观点。\n5. 请使用{lang}进行回答。',
ragDocumentContent: '## 文档内容:',
ragUserQuestion: '## 用户问题:',
ragAnswer: '## 回答:',
ragSource: '### 来源:{fileName}',
ragSegment: '片段 {index} (相似度: {score}):',
ragNoDocumentFound: '未找到相关文档。',
queryExpansionPrompt:
'您是一个搜索助手。请为以下用户查询生成3个不同的演变版本,以帮助在向量搜索中获得更好的结果。每个版本应包含不同的关键词或表达方式,但保持原始意思。直接输出3行查询,不要有数字或编号:\n\n查询:{query}',
hydePrompt:
'请为以下用户问题写一段简短、事实性的假设回答(约100字)。不要包含任何引导性文字(如“基于我的分析...”),直接输出答案内容。\n\n问题:{query}',
},
ja: {
searching: 'ナレッジベースを検索中...',
noResults:
'関連する知識が見つかりませんでした。一般的な知識に基づいて回答します...',
searchFailed:
'ナレッジベース検索に失敗しました。一般的な知識に基づいて回答します...',
generatingResponse: '回答を生成中',
files: '個のファイル',
notebooks: '個のノートブック',
all: 'すべて',
items: '件',
searchResults: '検索結果',
relevantInfoFound: '件の関連情報が見つかりました',
searchHits: '検索ヒット',
relevance: '関連度',
sourceFiles: '元ファイル',
searchScope: '検索範囲',
error: 'エラー',
creatingHistory: '新規対話履歴を作成: ',
searchingModelById: 'selectedEmbeddingId に基づいてモデルを検索: ',
searchModelFallback:
'指定された埋め込みモデルが見つかりません。最初に使用可能なモデルを使用します。',
noEmbeddingModelFound: '埋め込みモデルの設定が見つかりません',
usingEmbeddingModel: '使用する埋め込みモデル: ',
startingSearch: 'ナレッジベースの検索を開始...',
searchResultsCount: '検索結果数: ',
searchFailedLog: '検索失敗',
chatStreamError: 'チャットストリームエラー',
assistStreamError: 'アシストストリームエラー',
file: 'ファイル',
content: '内容',
userLabel: 'ユーザー',
assistantLabel: 'アシスタント',
intelligentAssistant: 'あなたはインテリジェントな執筆アシスタントです。',
assistSystemPrompt:
'提供されたテキスト内容を、ユーザーの指示に基づいて修正または改善してください。挨拶や結びの言葉(「わかりました、こちらが...」など)は含めず、修正後の内容のみを直接出力してください。',
contextLabel: 'コンテキスト(現在の内容)',
userInstructionLabel: 'ユーザーの指示',
searchString: '検索文字列: ',
embeddingModelIdNotProvided: '埋め込みモデルIDが提供されていません',
generatingEmbeddings: '埋め込みベクトルを生成中...',
embeddingsGenerated: '埋め込みベクトルの生成が完了しました',
dimensions: '次元数',
performingHybridSearch: 'ES 混合検索を実行中...',
esSearchCompleted: 'ES 検索が完了しました',
resultsCount: '結果数',
hybridSearchFailed: '混合検索に失敗しました',
getContextForTopicFailed: 'トピックのコンテキスト取得に失敗しました',
noLLMConfigured: 'ユーザーにLLMモデルが設定されていません',
simpleChatGenerationError: '簡易チャット生成エラー',
noMatchInKnowledgeGroup:
'選択された知識グループに関連する内容が見つかりませんでした。以下はモデルに基づく一般的な回答です:',
uploadTextSuccess:
'ノート内容を受け取りました。バックグラウンドでインデックス処理を実行中です',
passwordChanged: 'パスワードが正常に変更されました',
userCreated: 'ユーザーが正常に作成されました',
userInfoUpdated: 'ユーザー情報が更新されました',
userDeleted: 'ユーザーが削除されました',
pdfNoteTitle: 'PDF ノート - {date}',
noTextExtracted: 'テキストが抽出されませんでした',
kbCleared: 'ナレッジベースが空になりました',
fileDeleted: 'ファイルが削除されました',
pageImageNotFoundDetail: 'PDF の第 {page} ページの画像を取得できません',
groupSyncSuccess: 'ファイルグループが更新されました',
fileDeletedFromGroup: 'ファイルがグループから削除されました',
chunkConfigCorrection: 'チャンク設定の修正: {warnings}',
noChunksGenerated:
'ファイル {id} からテキストチャンクが生成されませんでした',
chunkCountAnomaly:
'実際のチャンク数 {actual} が推定値 {estimated} を大幅に超えています。異常がある可能性があります',
batchSizeExceeded:
'バッチ {index} のサイズ {actual} が推奨値 {limit} を超えています。分割して処理します',
skippingEmptyVectorChunk:
'空ベクトルのテキストブロック {index} をスキップします',
contextLengthErrorFallback:
'バッチ処理でコンテキスト長エラーが発生しました。単一テキスト処理モードにダウングレードします',
chunkLimitExceededForceBatch:
'チャンク数 {actual} がモデルのバッチ制限 {limit} を超えています。強制的にバッチ処理を行います',
noteContentRequired: 'ノート内容は必須です',
imageAnalysisStarted: 'モデル {id} で画像を分析中...',
batchAnalysisStarted: '{count} 枚の画像を分析中...',
pageAnalysisFailed: '第 {page} ページの分析に失敗しました',
visionSystemPrompt:
'あなたは専門的なドキュメント分析アシスタントです。このドキュメント画像を分析し、以下の要求に従って JSON 形式で返してください:\n\n1. すべての読み取り可能なテキストを抽出(読み取り順序に従い、段落と形式を保持)\n2. 画像/グラフ/表の識別(内容、意味、役割を記述)\n3. ページレイアウトの分析(テキストのみ/テキストと画像の混合/表/グラフなど)\n4. 分析品質の評価(0-1)\n\nレスポンス形式:\n{\n "text": "完全なテキスト内容",\n "images": [\n {"type": "グラフの種類", "description": "詳細な記述", "position": 1}\n ],\n "layout": "レイアウトの説明",\n "confidence": 0.95\n}',
visionModelCall:
'[モデル呼び出し] タイプ: Vision, モデル: {model}, ページ: {page}',
visionAnalysisSuccess:
'✅ Vision 分析完了: {path}{page}, テキスト長: {textLen}文字, 画像数: {imgCount}, レイアウト: {layout}, 信頼度: {confidence}%',
conversationHistoryNotFound: '会話履歴が存在しません',
batchContextLengthErrorFallback:
'小ファイルバッチ処理でコンテキスト長エラーが発生しました。単一テキスト処理モードにダウングレードします',
chunkProcessingFailed:
'テキストブロック {index} の処理に失敗しました。スキップします: {message}',
singleTextProcessingComplete: '単一テキスト処理完了: {count} チャンク',
fileVectorizationComplete:
'ファイル {id} ベクトル化完了。{count} 個のテキストブロックを処理しました。最終メモリ: {memory}MB',
fileVectorizationFailed: 'ファイル {id} ベクトル化失敗',
batchProcessingStarted: 'バッチ処理を開始します: {count} アイテム',
batchProcessingProgress:
'バッチ {index}/{total} を処理中: {count} 個のアイテム',
batchProcessingComplete:
'バッチ処理完了: {count} アイテム, 所要時間 {duration}s',
onlyFailedFilesRetryable:
'失敗したファイルのみ再試行可能です (現在のステータス: {status})',
emptyFileRetryFailed:
'ファイル内容が空です。再試行できません。ファイルを再アップロードしてください。',
ragSystemPrompt:
'あなたは専門的なナレッジベースアシスタントです。以下の提供されたドキュメントの内容に基づいて、ユーザーの質問に答えてください。',
ragRules:
'## ルール:\n1. 提供されたドキュメントの内容のみに基づいて回答し、情報を捏造しないでください。\n2. ドキュメントに関連情報がない場合は、その旨をユーザーに伝えてください。\n3. 回答には情報源を明記してください。形式:[ファイル名.拡張子]\n4. 複数のドキュメントで情報が矛盾している場合は、総合的に分析するか、異なる視点を説明してください。\n5. {lang}で回答してください。',
ragDocumentContent: '## ドキュメント内容:',
ragUserQuestion: '## ユーザーの質問:',
ragAnswer: '## 回答:',
ragSource: '### ソース:{fileName}',
ragSegment: 'セグメント {index} (類似度: {score}):',
ragNoDocumentFound: '関連するドキュメントが見つかりませんでした。',
queryExpansionPrompt:
'あなたは検索アシスタントです。以下のユーザーのクエリに対して、ベクトル検索でより良い結果を得るために、3つの異なるバリエーションを生成してください。各バリエーションは異なるキーワードや表現を使用しつつ、元の意味を維持する必要があります。数字やプレフィックスなしで、3行のクエリを直接出力してください:\n\nクエリ:{query}',
hydePrompt:
'以下のユーザーの質問に対して、簡潔で事実に基づいた仮説的な回答(約200文字)を書いてください。「私の分析によると...」などの導入文は含めず、回答内容のみを直接出力してください。\n\n質問:{query}',
},
en: {
searching: 'Searching knowledge base...',
noResults:
'No relevant knowledge found, will answer based on general knowledge...',
searchFailed:
'Knowledge base search failed, will answer based on general knowledge...',
generatingResponse: 'Generating response',
files: ' files',
notebooks: ' notebooks',
all: 'all',
items: '',
searchResults: 'Search results',
relevantInfoFound: ' relevant info found',
searchHits: 'Search hits',
relevance: 'Relevance',
sourceFiles: 'Source files',
searchScope: 'Search scope',
error: 'Error',
creatingHistory: 'Creating new chat history: ',
searchingModelById: 'Searching model by ID: ',
searchModelFallback:
'Specified embedding model not found. Using first available model.',
noEmbeddingModelFound: 'No embedding model settings found',
usingEmbeddingModel: 'Using embedding model: ',
startingSearch: 'Starting knowledge base search...',
searchResultsCount: 'Search results count: ',
searchFailedLog: 'Search failed',
chatStreamError: 'Chat stream error',
assistStreamError: 'Assist stream error',
file: 'File',
content: 'Content',
userLabel: 'User',
assistantLabel: 'Assistant',
intelligentAssistant: 'You are an intelligent writing assistant.',
assistSystemPrompt:
'Please revise or improve the provided text content based on the user\'s instructions. Do not include greetings or closing phrases (such as "Understood, here is..." etc.), output only the revised content directly.',
contextLabel: 'Context (current content)',
userInstructionLabel: 'User instructions',
searchString: 'Search string: ',
embeddingModelIdNotProvided: 'Embedding model ID not provided',
generatingEmbeddings: 'Generating embeddings...',
embeddingsGenerated: 'Embeddings generated successfully',
dimensions: 'dimensions',
performingHybridSearch: 'Performing hybrid search...',
esSearchCompleted: 'ES search completed',
resultsCount: 'Results count',
hybridSearchFailed: 'Hybrid search failed',
getContextForTopicFailed: 'getContextForTopic failed',
noLLMConfigured: 'No LLM model configured for user',
simpleChatGenerationError: 'Simple chat generation error',
noMatchInKnowledgeGroup:
'No relevant content found in the selected knowledge group. The following is a general answer based on the model:',
uploadTextSuccess: 'Note content received. Indexing in background',
passwordChanged: 'Password changed successfully',
userCreated: 'User created successfully',
userInfoUpdated: 'User information updated',
userDeleted: 'User deleted',
pdfNoteTitle: 'PDF Note - {date}',
noTextExtracted: 'No text extracted',
kbCleared: 'Knowledge base cleared',
fileDeleted: 'File deleted',
pageImageNotFoundDetail: 'Could not retrieve image for PDF page {page}',
groupSyncSuccess: 'File groups updated',
fileDeletedFromGroup: 'File removed from group',
chunkConfigCorrection: 'Chunk config corrected: {warnings}',
noChunksGenerated: 'No chunks generated for file {id}',
chunkCountAnomaly:
'Actual chunk count {actual} significantly exceeds estimate {estimated}. Possible anomaly.',
batchSizeExceeded:
'Batch {index} size {actual} exceeds recommended limit {limit}. Splitting for processing.',
skippingEmptyVectorChunk: 'Skipping text block {index} due to empty vector',
contextLengthErrorFallback:
'Context length error occurred during batch processing. Downgrading to single processing mode.',
chunkLimitExceededForceBatch:
'Chunk count {actual} exceeds model batch limit {limit}. Forcing batch processing.',
noteContentRequired: 'Note content is required',
imageAnalysisStarted: 'Analyzing image with model {id}...',
batchAnalysisStarted: 'Batch analyzing {count} images...',
pageAnalysisFailed: 'Failed to analyze page {page}',
visionSystemPrompt:
'You are a professional document analysis assistant. Analyze this document image and return in JSON format according to these requirements:\n\n1. Extract all readable text (follow reading order, maintain paragraphs and formatting)\n2. Identify images/graphs/tables (describe content, meaning, and role)\n3. Analyze page layout (text only/mixed/table/graph, etc.)\n4. Evaluate analysis quality (0-1)\n\nResponse format:\n{\n "text": "full text content",\n "images": [\n {"type": "graph type", "description": "detailed description", "position": 1}\n ],\n "layout": "layout description",\n "confidence": 0.95\n}',
visionModelCall: '[Model Call] Type: Vision, Model: {model}, Page: {page}',
visionAnalysisSuccess:
'✅ Vision analysis complete: {path}{page}, Text length: {textLen}, Images: {imgCount}, Layout: {layout}, Confidence: {confidence}%',
conversationHistoryNotFound: 'Conversation history not found',
batchContextLengthErrorFallback:
'Context length error occurred during small file batch processing. Downgrading to single processing mode.',
chunkProcessingFailed:
'Failed to process text block {index}. Skipping: {message}',
singleTextProcessingComplete:
'Single text processing complete: {count} chunks',
fileVectorizationComplete:
'File {id} vectorization complete. Processed {count} text blocks. Final memory: {memory}MB',
fileVectorizationFailed: 'File {id} vectorization failed',
batchProcessingStarted: 'Batch processing started: {count} items',
batchProcessingProgress: 'Processing batch {index}/{total}: {count} items',
batchProcessingComplete:
'Batch processing complete: {count} items in {duration}s',
onlyFailedFilesRetryable:
'Only failed files can be retried (current status: {status})',
emptyFileRetryFailed:
'File content is empty. Cannot retry. Please re-upload the file.',
ragSystemPrompt:
"You are a professional knowledge base assistant. Please answer the user's question based on the provided document content below.",
ragRules:
'## Rules:\n1. Answer based only on the provided document content; do not fabricate information.\n2. If there is no relevant information in the documents, please inform the user.\n3. Clearly state the sources in your answer. Format: [filename.ext]\n4. If information in different documents is contradictory, analyze it comprehensively or explain the different perspectives.\n5. Please answer in {lang}.',
ragDocumentContent: '## Document Content:',
ragUserQuestion: '## User Question:',
ragAnswer: '## Answer:',
ragSource: '### Source: {fileName}',
ragSegment: 'Segment {index} (Similarity: {score}):',
ragNoDocumentFound: 'No relevant documents found.',
queryExpansionPrompt:
'You are a search assistant. Please generate 3 different variations of the following user query to help get better results in vector search. Each variation should use different keywords or phrasing while maintaining the original meaning. Output the 3 queries directly as 3 lines, without numbers or prefixes:\n\nQuery: {query}',
hydePrompt:
'Please write a brief, factual hypothetical answer (about 100 words) to the following user question. Do not include any introductory text (like "Based on my analysis..."), just output the answer content directly.\n\nQuestion: {query}',
},
};