i18n.service.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import { Injectable } from '@nestjs/common';
  2. import { errorMessages, logMessages, statusMessages } from './messages';
  3. import { i18nStore } from './i18n.store';
  4. import { DEFAULT_LANGUAGE } from '../common/constants'; // 使用常量定义的默认语言
  5. @Injectable()
  6. export class I18nService {
  7. private readonly defaultLanguage = DEFAULT_LANGUAGE; // 使用常量定义的默认语言
  8. private getLanguage(lang?: string): string {
  9. if (lang) return lang;
  10. const store = i18nStore.getStore();
  11. return store?.language || this.defaultLanguage;
  12. }
  13. getErrorMessage(key: string, language?: string): string {
  14. const lang = this.getLanguage(language);
  15. return errorMessages[lang]?.[key] || errorMessages[this.defaultLanguage][key] || key;
  16. }
  17. getLogMessage(key: string, language?: string): string {
  18. const lang = this.getLanguage(language);
  19. return logMessages[lang]?.[key] || logMessages[this.defaultLanguage][key] || key;
  20. }
  21. getStatusMessage(key: string, language?: string): string {
  22. const lang = this.getLanguage(language);
  23. return statusMessages[lang]?.[key] || statusMessages[this.defaultLanguage][key] || key;
  24. }
  25. // 汎用メッセージ取得メソッド、順次検索
  26. getMessage(key: string, language?: string): string {
  27. const lang = this.getLanguage(language);
  28. // ステータスメッセージ、エラーメッセージ、ログメッセージの順に検索
  29. return statusMessages[lang]?.[key] ||
  30. statusMessages[this.defaultLanguage][key] ||
  31. errorMessages[lang]?.[key] ||
  32. errorMessages[this.defaultLanguage][key] ||
  33. logMessages[lang]?.[key] ||
  34. logMessages[this.defaultLanguage][key] ||
  35. key;
  36. }
  37. // メッセージの取得とフォーマット
  38. formatMessage(key: string, args: Record<string, any>, language?: string): string {
  39. let message = this.getMessage(key, language);
  40. for (const [argKey, argValue] of Object.entries(args)) {
  41. message = message.replace(new RegExp(`\\{${argKey}\\}`, 'g'), String(argValue));
  42. }
  43. return message;
  44. }
  45. // サポートされている言語リストを取得
  46. getSupportedLanguages(): string[] {
  47. return Object.keys(errorMessages);
  48. }
  49. // 言語がサポートされているか確認
  50. isLanguageSupported(language: string): boolean {
  51. return this.getSupportedLanguages().includes(language);
  52. }
  53. // システムプロンプトを取得
  54. getPrompt(lang: string = this.defaultLanguage, type: 'withContext' | 'withoutContext' = 'withContext', hasKnowledgeGroup: boolean = false): string {
  55. const language = this.getLanguage(lang);
  56. const noMatchMsg = statusMessages[language]?.noMatchInKnowledgeGroup || statusMessages[this.defaultLanguage].noMatchInKnowledgeGroup;
  57. if (language === 'zh') {
  58. return type === 'withContext' ? `
  59. 基于以下知识库内容回答用户问题。
  60. ${hasKnowledgeGroup ? `
  61. **重要提示**: 用户已选择特定知识组,请严格基于以下知识库内容回答。如果知识库中没有相关信息,请明确告知用户:"${noMatchMsg}",然后再提供答案。
  62. ` : ''}
  63. 知识库内容:
  64. {context}
  65. 历史对话:
  66. {history}
  67. 用户问题:{question}
  68. 请用中文回答,并严格遵循以下 Markdown 格式要求:
  69. 1. **段落与结构**:
  70. - 使用清晰的段落分隔,每个要点之间空一行
  71. - 使用标题(## 或 ###)组织长回答
  72. 2. **文本格式**:
  73. - 使用 **粗体** 强调重要概念和关键词
  74. - 使用列表(- 或 1.)组织多个要点
  75. - 使用 \`代码\` 标记技术术语、命令、文件名
  76. 3. **代码展示**:
  77. - 使用代码块展示代码,并指定语言:
  78. \`\`\`python
  79. def example():
  80. return "示例"
  81. \`\`\`
  82. - 支持语言:python, javascript, typescript, java, bash, sql 等
  83. 4. **图表与可视化**:
  84. - 使用 Mermaid 语法绘制流程图、序列图等:
  85. \`\`\`mermaid
  86. graph LR
  87. A[开始] --> B[处理]
  88. B --> C[结束]
  89. \`\`\`
  90. - 适用场景:流程、架构、状态机、时序图
  91. 5. **其他要求**:
  92. - 回答精炼准确
  93. - 多步骤操作使用有序列表
  94. - 对比类信息建议用表格展示(如果适用)
  95. ` : `
  96. 作为智能助手,请回答用户的问题。
  97. 历史对话:
  98. {history}
  99. 用户问题:{question}
  100. 请用中文回答。
  101. `;
  102. } else if (language === 'en') {
  103. return type === 'withContext' ? `
  104. Answer the user's question based on the following knowledge base content.
  105. ${hasKnowledgeGroup ? `
  106. **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.
  107. ` : ''}
  108. Knowledge Base CONTENT:
  109. {context}
  110. Conversation history:
  111. {history}
  112. User question: {question}
  113. Please answer in English and strictly follow these Markdown formatting guidelines:
  114. 1. **Paragraphs & Structure**:
  115. - Use clear paragraph breaks with blank lines between key points
  116. - Use headings (## or ###) to organize longer answers
  117. 2. **Text Formatting**:
  118. - Use **bold** to emphasize important concepts and keywords
  119. - Use lists (- or 1.) to organize multiple points
  120. - Use \`code\` to mark technical terms, commands, file names
  121. 3. **Code Display**:
  122. - Use code blocks with language specification:
  123. \`\`\`python
  124. def example():
  125. return "example"
  126. \`\`\`
  127. - Supported languages: python, javascript, typescript, java, bash, sql, etc.
  128. 4. **Diagrams & Charts**:
  129. - Use Mermaid syntax for flowcharts, sequence diagrams, etc.:
  130. \`\`\`mermaid
  131. graph LR
  132. A[Start] --> B[Process]
  133. B --> C[End]
  134. \`\`\`
  135. - Use cases: process flows, architecture diagrams, state diagrams, sequence diagrams
  136. 5. **Other Requirements**:
  137. - Keep answers concise and clear
  138. - Use numbered lists for multi-step processes
  139. - Use tables for comparison information (if applicable)
  140. ` : `
  141. As an intelligent assistant, please answer the user's question.
  142. Conversation history:
  143. {history}
  144. User question: {question}
  145. Please answer in English.
  146. `;
  147. } else { // 默认为日语,符合项目要求
  148. return type === 'withContext' ? `
  149. 以下のナレッジベースの内容に基づいてユーザーの質問に答えてくplease。
  150. ${hasKnowledgeGroup ? `
  151. **重要**: ユーザーが特定の知識グループを選択しました。以下のナレッジベースの内容に厳密に基づいて回答please。ナレッジベースに関連情報がない場合は、「${noMatchMsg}」とユーザーに明示的に伝えてfrom、回答を提供please。
  152. ` : ''}
  153. ナレッジベースの内容:
  154. {context}
  155. 会話履歴:
  156. {history}
  157. ユーザーの質問:{question}
  158. 日本語で回答please。以下の Markdown 書式要件に厳密に従ってくplease:
  159. 1. **段落と構造**:
  160. - 明確な段落分けを使用し、要点間に空行を入れる
  161. - 長い回答には見出し(## または ###)を使用
  162. 2. **テキスト書式**:
  163. - 重要な概念やキーワードを強調するために **太字** を使用
  164. - 複数のポイントを整理するためにリスト(- または 1.)を使用
  165. - 技術用語、コマンド、ファイル名をマークするために \`コード\` を使用
  166. 3. **コード表示**:
  167. - 言語を指定してコードブロックを使用:
  168. \`\`\`python
  169. def example():
  170. return "例"
  171. \`\`\`
  172. - 対応言語:python, javascript, typescript, java, bash, sql etc.
  173. 4. **図表とチャート**:
  174. - フローチャート、シーケンス図etc.に Mermaid 構文を使用:
  175. \`\`\`mermaid
  176. graph LR
  177. A[開始] --> B[処理]
  178. B --> C[終了]
  179. \`\`\`
  180. - 使用例:プロセスフロー、アーキテクチャ図、状態図、シーケンス図
  181. 5. **その他の要件**:
  182. - 簡潔で明確な回答を心がける
  183. - 複数のステップがある場合は番号付きリストを使用
  184. - 比較情報には表を使用(該当する場合)
  185. ` : `
  186. インテリジェントアシスタントとして、ユーザーの質問に答えてくplease。
  187. 会話履歴:
  188. {history}
  189. ユーザーの質問:{question}
  190. 日本語で回答please。
  191. `;
  192. }
  193. }
  194. // タイトル生成用のプロンプトを取得
  195. getDocumentTitlePrompt(lang: string = this.defaultLanguage, contentSample: string): string {
  196. const language = this.getLanguage(lang);
  197. if (language === 'zh') {
  198. return `你是一个文档分析师。请阅读以下文本(文档开头部分),并生成一个简炼、专业的标题(不超过50个字符)。
  199. 只返回标题文本。不要包含任何解释性文字或前导词(如“标题是:”)。
  200. 语言:中文
  201. 文本内容:
  202. ${contentSample}`;
  203. } else if (language === 'en') {
  204. return `You are a document analyzer. Read the following text (start of a document) and generate a concise, professional title (max 50 chars).
  205. Return ONLY the title text. No preamble like "The title is...".
  206. Language: English
  207. Text:
  208. ${contentSample}`;
  209. } else {
  210. return `あなたはドキュメントアナライザー.以下のテキスト(ドキュメントの冒頭部分)を読み、簡潔でプロフェッショナルなタイトル(最大50文字)を生成please。
  211. タイトルテキストのみを返please。説明文や前置き(例:「タイトルは:」)は含めないでくplease。
  212. 言語:日本語
  213. テキスト:
  214. ${contentSample}`;
  215. }
  216. }
  217. getChatTitlePrompt(lang: string = this.defaultLanguage, userMessage: string, aiResponse: string): string {
  218. const language = this.getLanguage(lang);
  219. if (language === 'zh') {
  220. return `根据以下对话片段,生成一个简短、描述性的标题(不超过50个字符),总结讨论的主题。
  221. 只返回标题文本。不要包含任何前导词。
  222. 语言:中文
  223. 片段:
  224. 用户: ${userMessage}
  225. 助手: ${aiResponse}`;
  226. } else if (language === 'en') {
  227. return `Based on the following conversation snippet, generate a short, descriptive title (max 50 chars) that summarizes the topic.
  228. Return ONLY the title. No preamble.
  229. Language: English
  230. Snippet:
  231. User: ${userMessage}
  232. Assistant: ${aiResponse}`;
  233. } else {
  234. return `以下の会話スニペットに基づいて、トピックを要約する短く説明的なタイトル(最大50文字)を生成please。
  235. タイトルのみを返please。前置きは不要.
  236. 言語:日本語
  237. スニペット:
  238. ユーザー: ${userMessage}
  239. アシスタント: ${aiResponse}`;
  240. }
  241. }
  242. }