Files
aurak/server/src/i18n/i18n.service.ts
T
Developer 0a9588abb7 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
2026-04-23 17:19:11 +08:00

348 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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}`;
}
}
}