refactor: extract AI translations to shared i18n module in node-runtime

Move AI-related translations (tools, agent prompts, LLM, summary) from
Electron-specific locale files into @openchatlab/node-runtime, enabling
single-source maintenance across Electron and Server.

- Add packages/node-runtime/src/ai/i18n/ with createAiTranslate() and
  bundled locale data (zh-CN, en-US, ja-JP, zh-TW)
- Electron locale files now compose: Electron-specific keys + shared AI
  translations from node-runtime
- Server agent.ts switches to shared buildSystemPrompt with evidence
  policy, data snapshot injection, ownerInfo and mentionedMembers support
- Server route fetches dataSnapshot from getChatOverview before agent run
This commit is contained in:
digua committed 2026-05-18 22:04:01 +08:00
1 parent 1620a5b4a3
commit 7190606ca7
14 files changed
+1499 -1361

No files matched your search

+8 -336
View File
@@ -1,6 +1,11 @@
/**
* 主进程英文翻译
* Main process English translations
*
* AI shared translations imported from @openchatlab/node-runtime;
* Electron-specific translations defined here.
*/
import aiLocale from '@openchatlab/node-runtime/src/ai/i18n/locales/en-US'
export default {
// ===== Common =====
common: {
@@ -53,339 +58,6 @@ export default {
notRegistered: 'Tool "{{toolName}}" is not registered',
},
// ===== P2: AI Tool definitions (Function Calling) =====
ai: {
tools: {
search_messages: {
desc: 'Search chat records by keywords. This is the primary evidence tool for factual questions about keywords, member messages, or whether a topic appeared. Can specify time range and sender to filter messages. Supports minute-level time queries.',
params: {
keywords:
'List of search keywords, using OR logic to match messages containing any keyword. Pass an empty array [] to filter by sender only',
sender_id:
'Sender member ID, used to filter messages from a specific member. Can be obtained via the get_members tool',
limit: 'Message count limit, default 1000, max 50000',
year: 'Filter messages by year, e.g. 2024',
month: 'Filter messages by month (1-12), use with year',
day: 'Filter messages by day (1-31), use with year and month',
hour: 'Filter messages by hour (0-23), use with year, month, and day',
start_time:
'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00". Overrides year/month/day/hour when specified',
end_time:
'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30". Overrides year/month/day/hour when specified',
},
},
deep_search_messages: {
desc: 'Exact substring match search for chat records. Slower but never misses any message containing the keyword. Use when search_messages results are insufficient, when verifying whether a phrase really exists, or when searching partial words or single characters.',
params: {
keywords: 'List of search keywords, using substring match (LIKE). Returns messages matching any keyword',
sender_id: 'Sender member ID for filtering messages from a specific member',
limit: 'Message count limit, default 1000, max 50000',
year: 'Filter messages by year, e.g. 2024',
month: 'Filter messages by month (1-12), use with year',
day: 'Filter messages by day (1-31), use with year and month',
hour: 'Filter messages by hour (0-23), use with year, month, and day',
start_time: 'Start time, format "YYYY-MM-DD HH:mm". Overrides year/month/day/hour when specified',
end_time: 'End time, format "YYYY-MM-DD HH:mm". Overrides year/month/day/hour when specified',
},
},
get_recent_messages: {
desc: 'Get chat messages within a specified time period. This is the preferred evidence tool for overview questions like "what has everyone been chatting about recently", "what was discussed in month X", and latest content after new records were appended. Supports minute-level time queries.',
params: {
limit: 'Message count limit, default 100 (saves tokens, can be increased as needed)',
year: 'Filter messages by year, e.g. 2024',
month: 'Filter messages by month (1-12), use with year',
day: 'Filter messages by day (1-31), use with year and month',
hour: 'Filter messages by hour (0-23), use with year, month, and day',
start_time:
'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00". Overrides year/month/day/hour when specified',
end_time:
'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30". Overrides year/month/day/hour when specified',
},
},
get_chat_overview: {
desc: 'Get basic overview of the chat: name, platform, type, total messages, total members, time range, and top active members. Use this before analysis or after appended records to confirm the current database range.',
params: {
top_n: 'Return top N active members, default 10',
},
},
get_member_stats: {
desc: 'Get member activity statistics. Suitable for questions like "who is the most active" or "who sends the most messages".',
params: {
top_n: 'Return top N members, default 10',
},
},
get_time_stats: {
desc: 'Get time distribution statistics of chat activity. Suitable for questions like "when is the group most active" or "what time do people usually chat".',
params: {
type: 'Statistics type: hourly (by hour), weekday (by day of week), daily (by date)',
},
},
get_members: {
desc: 'Get group member list, including basic info, aliases, and message statistics. Suitable for queries like "who is in the group", "what is someone\'s alias", or "whose ID is xxx".',
params: {
search: 'Optional search keyword to filter by member nickname, alias, or platform ID',
limit: 'Member count limit, returns all by default',
},
},
get_member_name_history: {
desc: 'Get member name change history. Suitable for questions like "what was someone\'s previous name", "name changes", or "former names". Requires member ID from get_members tool first.',
params: {
member_id: 'Member database ID, can be obtained via get_members tool',
},
},
get_conversation_between: {
desc: 'Get conversation records between two group members. Suitable for questions like "what did A and B talk about" or "view the conversation between two people". Requires member IDs from get_members first. Supports minute-level time queries.',
params: {
member_id_1: 'Database ID of the first member',
member_id_2: 'Database ID of the second member',
limit: 'Message count limit, default 100',
start_time:
'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00". Overrides year/month/day/hour when specified',
end_time:
'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30". Overrides year/month/day/hour when specified',
},
},
get_message_context: {
desc: 'Get surrounding context messages for a given message ID. Use it to verify facts around specific quoted messages, such as what was discussed before and after a message or whether a phrase has context. Supports single or batch message IDs.',
params: {
message_ids:
'List of message IDs to query context for. Can be single or multiple IDs. Message IDs can be obtained from search_messages and other tool results',
context_size: 'Context size, i.e. how many messages before and after to retrieve, default 20',
},
},
search_sessions: {
desc: 'Search chat sessions (conversation segments). Sessions are conversation units automatically split by message time intervals. Suitable for finding discussions on specific topics or understanding how many conversations occurred in a time period. Returns matching sessions with a 5-message preview each.',
params: {
keywords: 'Optional keyword list, only returns sessions containing these keywords (OR logic)',
limit: 'Session count limit, default 20',
year: 'Filter sessions by year, e.g. 2024',
month: 'Filter sessions by month (1-12), use with year',
day: 'Filter sessions by day (1-31), use with year and month',
start_time: 'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00"',
end_time: 'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30"',
},
},
get_session_messages: {
desc: 'Get the complete message list for a specific session. Used to get full context after finding a relevant session via search_sessions. Returns all messages and participant information.',
params: {
session_id: 'Session ID, can be obtained from search_sessions results',
limit: 'Message count limit, default 1000. Can be limited for very long sessions to save tokens',
},
},
get_session_summaries: {
desc: `Get session summary list to quickly understand discussion topics in chat history.
Use cases:
1. Understand what topics have been discussed recently
2. Search for discussed topics by keyword
3. Overview questions like "has the group discussed travel"
Returned summaries are brief descriptions of each session, helping quickly locate sessions of interest. Use get_session_messages for details.`,
params: {
keywords: 'Keyword list to search within summaries (OR logic)',
limit: 'Session count limit, default 20',
year: 'Filter sessions by year',
month: 'Filter sessions by month (1-12)',
day: 'Filter sessions by day (1-31)',
start_time: 'Start time, format "YYYY-MM-DD HH:mm"',
end_time: 'End time, format "YYYY-MM-DD HH:mm"',
},
},
// ===== SQL Analysis Tools =====
message_type_breakdown: {
desc: 'Break down message types over the last N days (text, image, voice, emoji, etc.). Useful for understanding communication preferences.',
params: { days: 'Number of recent days to analyze' },
rowTemplate: '{type_name}: {msg_count} messages ({percentage}%)',
summaryTemplate: 'Message type distribution ({rowCount} types):',
fallback: 'No messages found in this time range',
},
peak_chat_hours_by_member: {
desc: "Analyze a specific member's hourly message distribution over the last N days to find their most active hours. Requires member_id from get_members.",
params: {
member_id: 'Member ID (from get_members)',
days: 'Number of recent days to analyze',
},
rowTemplate: '{hour}:00 — {msg_count} messages',
summaryTemplate: 'Message volume by hour ({rowCount} active hours):',
fallback: 'This member has no messages in the specified time range',
},
member_activity_trend: {
desc: "View a specific member's daily message count trend over the last N days. Useful for observing whether someone is becoming more or less active. Requires member_id from get_members.",
params: {
member_id: 'Member ID (from get_members)',
days: 'Number of recent days to view',
},
rowTemplate: '{day}: {msg_count} messages',
summaryTemplate: 'This member was active on {rowCount} days:',
fallback: 'This member has no messages in the specified time range',
},
silent_members: {
desc: 'Detect "silent members" who haven\'t sent messages for more than N days. Useful for identifying at-risk users in community management.',
params: { days: 'Days of silence to qualify' },
rowTemplate: '{name} — silent for {silent_days} days',
summaryTemplate: 'Found {rowCount} silent members:',
fallback: 'No members found who have been silent for that long. Community engagement is healthy!',
},
reply_interaction_ranking: {
desc: 'Analyze reply interaction rankings in the group — who replies to whom the most. Useful for discovering core interaction relationships and key opinion leaders.',
params: {
days: 'Number of recent days to analyze',
limit: 'Number of top interaction pairs to return',
},
rowTemplate: '{replier_name} → {original_name}: {reply_count} replies',
summaryTemplate: 'Top {rowCount} reply interactions:',
fallback: 'No reply interactions found in this time range',
},
mutual_interaction_pairs: {
desc: 'Find the most frequently interacting member pairs, based on bidirectional message timing (if one person speaks and another responds within 5 minutes, it counts as an interaction). Useful for discovering close friendships.',
params: {
days: 'Number of recent days to analyze',
limit: 'Number of top pairs to return',
},
rowTemplate: '{member_a} ↔ {member_b}: {interaction_count} interactions',
summaryTemplate: 'Top {rowCount} most interactive pairs:',
fallback: 'No significant interaction patterns detected in this time range',
},
member_message_length_stats: {
desc: 'Analyze average message length per member (text messages only). Longer messages often indicate more thoughtful communication. Useful for finding deep communicators.',
params: {
days: 'Number of recent days to analyze',
top_n: 'Number of top members to return',
},
rowTemplate: '{name} — avg {avg_length} chars/msg ({msg_count} msgs, max {max_length} chars)',
summaryTemplate: 'Message length Top {rowCount} (longer = more thoughtful):',
fallback: 'Not enough text message data in this time range',
},
unanswered_messages: {
desc: 'Find messages in the last N days that may not have been replied to — potential unresolved customer issues. Only counts text messages over 10 characters (filters out short greetings).',
params: {
days: 'Number of recent days to search',
limit: 'Maximum number of results',
},
rowTemplate: '[{send_time}] {sender_name}: {content_preview}',
summaryTemplate: 'Found {rowCount} potentially unanswered messages:',
fallback: 'All messages have been replied to in this time range. Great service quality!',
},
daily_active_members: {
desc: 'Count daily unique active members (DAU) and message volume to observe community vitality trends. Useful for "how is the group activity trending" or "how many people are chatting recently".',
params: { days: 'Number of recent days to analyze' },
rowTemplate: '{day}: {active_members} active, {msg_count} messages',
summaryTemplate: 'Daily active members trend for {rowCount} days:',
fallback: 'No messages in this time range',
},
conversation_initiator_stats: {
desc: 'Count how many times each member initiated a conversation (was the first sender in a session). Requires session index to be generated.',
params: {
days: 'Number of recent days to analyze',
limit: 'Number of top members to return',
},
rowTemplate: '{name}: initiated {initiated_count} topics',
summaryTemplate: 'Topic initiator Top {rowCount}:',
fallback: 'No session records in this time range. Session index may need to be generated first.',
},
activity_heatmap: {
desc: 'Return a weekday × hour message count matrix for generating activity heatmaps. weekday: 0=Sun, 1=Mon, ..., 6=Sat.',
params: { days: 'Number of recent days to analyze' },
rowTemplate: 'Weekday {weekday} {hour}:00 — {msg_count} messages',
summaryTemplate: 'Activity heatmap data ({rowCount} time slots with messages):',
fallback: 'No messages in this time range',
},
response_time_analysis: {
desc: 'Analyze response times between messages, showing median and average reply speed per member. Useful for "how quickly do people reply" or "who replies the fastest".',
params: {
days: 'Number of recent days to analyze',
top_n: 'Number of top members to return',
},
},
keyword_frequency: {
desc: 'Segment text messages and rank high-frequency keywords. Supports Chinese, English, and Japanese. Useful for "what do people talk about most" or "what are the hot keywords".',
params: {
days: 'Number of recent days to analyze',
top_n: 'Number of top keywords to return',
},
},
},
// ===== AI Agent system prompts =====
agent: {
answerWithoutTools: 'Please answer based on the information already retrieved, do not call any more tools.',
toolError: 'Error: {{error}}',
currentDateIs: 'Current date is',
chatContext: {
private: 'conversation',
group: 'group chat',
},
ownerNote: `Current user identity:
- The user's identity in this {{chatContext}} is "{{displayName}}" (platformId: {{platformId}})
- When the user refers to "I" or "my", it refers to "{{displayName}}"
- When querying "my" messages, use the sender_id parameter to filter for this member
`,
memberNotePrivate: `Member query strategy:
- Private chats only have two participants, so the member list can be directly obtained
- When the user refers to "the other party" or "he/she", get the other participant's information via get_members
`,
memberNoteGroup: `Member query strategy:
- When the user refers to specific group members (e.g., "what did John say", "Mary's messages"), first call get_members to get the member list
- Group members have three names: accountName (original nickname), groupNickname (group nickname), aliases (user-defined aliases)
- The search parameter of get_members can be used for fuzzy searching these three names
- Once a member is found, use their id field as the sender_id parameter for search_messages to retrieve their messages
`,
mentionedMembersNote:
'Members explicitly @-selected by the user in this round (member_id can be used directly without another search):',
timeParamsIntro: 'Time parameters: use start_time/end_time to specify the range, format "YYYY-MM-DD HH:mm"',
defaultYearNote: 'When no time range is specified, queries default to all data. Current year is {{year}}.',
dataSnapshotNote:
'Current chat database snapshot: {{name}} ({{platform}}), {{totalMessages}} total messages, {{totalMembers}} members, time range {{firstMessageDate}} ~ {{lastMessageDate}}. This snapshot only helps judge data coverage; concrete chat facts still require tool retrieval from the current database.',
evidencePolicy: `Evidence policy:
- AI conversation history, prior AI replies, and compressed summaries are only for understanding the user's intent; they are not evidence for chat-record facts.
- Whenever the user asks about chat content, recent topics, what someone said, rankings/statistics, whether a topic appeared, or asks for exact quotes, first call an appropriate data tool to retrieve the current database.
- If new chat records were appended, the current database may differ from old window history; prefer get_chat_overview or get_recent_messages/search_messages to get fresh evidence.
- Only messages, statistics, or database overviews returned by tools may be used as factual basis. If tools do not return enough evidence, say the data is insufficient and do not fabricate nonexistent chat records.`,
currentTask: 'Current Task',
skillPriorityNote:
'Note: When executing this task, prioritize the output format requirements below. This can override your usual response style.',
responseInstruction:
"Based on the user's question, select appropriate tools to retrieve data, then provide an answer based on the data.",
fallbackRoleDefinition: {
group: `You are a professional group chat analysis assistant.
Your task is to help users understand and analyze their group chat data.
## Response Requirements
1. Answer based on data returned by tools, do not fabricate information
2. If data is insufficient to answer, please state so
3. Keep answers concise and clear, use Markdown format`,
private: `You are a professional private chat analysis assistant.
Your task is to help users understand and analyze their private chat data.
## Response Requirements
1. Answer based on data returned by tools, do not fabricate information
2. If data is insufficient to answer, please state so
3. Keep answers concise and clear, use Markdown format`,
},
},
},
// ===== P3: LLM config =====
llm: {
notConfigured: 'LLM service not configured. Please set up an API Key in settings first.',
maxConfigs: 'Maximum of {{count}} configurations allowed',
configNotFound: 'Configuration not found',
noActiveConfig: 'No active configuration',
callFailed: 'LLM call failed. Please check your model configuration.',
genericProviderName: 'API provider',
rawErrorLabel: 'Raw error',
},
// ===== P4: Summary generation =====
summary: {
sessionNotFound: 'Session not found or database could not be opened',
tooFewMessages: 'Message count less than {{count}}, no need to generate summary',
tooFewValidMessages: 'Valid message count less than {{count}}, no need to generate summary',
sessionNotExist: 'Session not found',
messagesTooFew: 'Too few messages',
validMessagesTooFew: 'Too few valid messages',
systemPromptDirect: 'You are a conversation summarization expert. Summarize conversations concisely.',
systemPromptMerge:
'You are a conversation summarization expert skilled at merging multiple summaries into a coherent overview.',
},
// AI shared translations (from @openchatlab/node-runtime)
...aiLocale,
}
+7 -335
View File
@@ -1,6 +1,11 @@
/**
* メインプロセス日本語翻訳
*
* AI 共有翻訳は @openchatlab/node-runtime から導入。
* Electron 固有翻訳はこのファイルで定義。
*/
import aiLocale from '@openchatlab/node-runtime/src/ai/i18n/locales/ja-JP'
export default {
// ===== 共通 =====
common: {
@@ -54,339 +59,6 @@ export default {
notRegistered: 'ツール "{{toolName}}" は登録されていません',
},
// ===== P2: AI ツール説明(Function Calling) =====
ai: {
tools: {
search_messages: {
desc: 'キーワードでチャット履歴を検索する。キーワード、メンバーの発言、特定トピックが出たかどうかなどの事実質問に対する主要な証拠取得ツール。時間範囲や送信者でメッセージをフィルタリングできる。分単位の精度で時間クエリをサポートする。',
params: {
keywords:
'検索キーワードリスト。OR ロジックでいずれかのキーワードを含むメッセージにマッチする。送信者のみでフィルタリングする場合は空配列 [] を渡す',
sender_id:
'送信者のメンバー ID。特定メンバーの送信メッセージをフィルタリングする。get_members ツールでメンバー ID を取得できる',
limit: '返却メッセージ数の上限。デフォルト 1000、最大 50000',
year: '指定年のメッセージをフィルタリング(例:2024)',
month: '指定月のメッセージをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のメッセージをフィルタリング(1-31)。year と month と併用する必要がある',
hour: '指定時間のメッセージをフィルタリング(0-23)。year、month、day と併用する必要がある',
start_time:
'開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")。指定すると year/month/day/hour パラメータを上書きする',
end_time:
'終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")。指定すると year/month/day/hour パラメータを上書きする',
},
},
deep_search_messages: {
desc: '完全部分文字列マッチでチャット履歴を検索する。速度は遅いが、キーワードを含むメッセージを漏らさない。search_messages の結果が不十分な場合、ある文言が実在するか確認する場合、または部分的な単語・単一文字を検索する場合に使用する。',
params: {
keywords:
'検索キーワードリスト。部分文字列マッチ(LIKE)を使用し、いずれかのキーワードにマッチしたメッセージを返す',
sender_id: '送信者のメンバー ID。特定メンバーの送信メッセージをフィルタリングする',
limit: '返却メッセージ数の上限。デフォルト 1000、最大 50000',
year: '指定年のメッセージをフィルタリング(例:2024)',
month: '指定月のメッセージをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のメッセージをフィルタリング(1-31)。year と month と併用する必要がある',
hour: '指定時間のメッセージをフィルタリング(0-23)。year、month、day と併用する必要がある',
start_time: '開始時刻。形式 "YYYY-MM-DD HH:mm"。指定すると year/month/day/hour パラメータを上書きする',
end_time: '終了時刻。形式 "YYYY-MM-DD HH:mm"。指定すると year/month/day/hour パラメータを上書きする',
},
},
get_recent_messages: {
desc: '指定期間内のチャットメッセージを取得する。「最近みんな何を話していた?」「X月に何が話題だった?」、新しい記録追加後の最新内容などの概要質問に対する優先証拠ツール。分単位の精度で時間クエリをサポートする。',
params: {
limit: '返却メッセージ数の上限。デフォルト 100(Token を節約したい場合の目安。必要に応じて増やせる)',
year: '指定年のメッセージをフィルタリング(例:2024)',
month: '指定月のメッセージをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のメッセージをフィルタリング(1-31)。year と month と併用する必要がある',
hour: '指定時間のメッセージをフィルタリング(0-23)。year、month、day と併用する必要がある',
start_time:
'開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")。指定すると year/month/day/hour パラメータを上書きする',
end_time:
'終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")。指定すると year/month/day/hour パラメータを上書きする',
},
},
get_chat_overview: {
desc: 'チャット記録の基本概要を取得する:グループ名、プラットフォーム、タイプ、総メッセージ数、総メンバー数、期間、最もアクティブなメンバーランキング。分析前や新しい記録追加後に、現在のデータベース範囲を確認するのに適している。',
params: {
top_n: '上位 N 名のアクティブメンバーを返却。デフォルト 10',
},
},
get_member_stats: {
desc: 'グループメンバーのアクティビティ統計データを取得する。「最もアクティブなのは誰?」「発言数が一番多いのは?」などの質問に適している。',
params: {
top_n: '上位 N 名のメンバーを返却。デフォルト 10',
},
},
get_time_stats: {
desc: 'グループチャットの時間分布統計を取得する。「いつが一番アクティブ?」「みんな何時にチャットしている?」などの質問に適している。',
params: {
type: '統計タイプ:hourly(時間別)、weekday(曜日別)、daily(日別)',
},
},
get_members: {
desc: 'グループメンバー一覧を取得する。メンバーの基本情報、別名、メッセージ統計を含む。「グループに誰がいる?」「○○の別名は?」「QQ 番号が xxx の人は?」などの質問に向いている。',
params: {
search: '任意の検索キーワード。メンバーのニックネーム、別名、QQ 番号で絞り込む',
limit: '返却メンバー数の上限。デフォルトは全件返却',
},
},
get_member_name_history: {
desc: 'メンバーのニックネーム変更履歴を取得する。「○○の以前の名前は?」「○○のニックネームの変遷」「○○の旧名」などの質問に適している。事前に get_members ツールでメンバー ID を取得する必要がある。',
params: {
member_id: 'メンバーのデータベース ID。get_members ツールで取得できる',
},
},
get_conversation_between: {
desc: '2 人のグループメンバー間の会話履歴を取得する。「A と B は何を話していた?」「2 人のやり取りを見たい」などの質問に向いている。事前に get_members でメンバー ID を取得する必要がある。分単位の時間指定にも対応する。',
params: {
member_id_1: '1人目のメンバーのデータベース ID',
member_id_2: '2人目のメンバーのデータベース ID',
limit: '返却メッセージ数の上限。デフォルト 100',
start_time:
'開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")。指定すると year/month/day/hour パラメータを上書きする',
end_time:
'終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")。指定すると year/month/day/hour パラメータを上書きする',
},
},
get_message_context: {
desc: 'メッセージ ID に基づいて前後のコンテキストメッセージを取得する。具体的な引用メッセージ周辺の事実確認、例えば「このメッセージの前後で何を話していた?」「この文言には文脈があるか」を確認する場合に使用する。単一または複数のメッセージ ID をサポートする。',
params: {
message_ids:
'コンテキストを取得するメッセージ ID リスト。単一 ID または複数 ID が可能。メッセージ ID は search_messages などのツールの返却結果から取得できる',
context_size: 'コンテキストサイズ。前後それぞれ何件のメッセージを取得するか。デフォルト 20',
},
},
search_sessions: {
desc: 'チャットセッション(会話セグメント)を検索する。セッションはメッセージの時間間隔に基づいて自動分割された会話単位である。特定トピックの議論を見つけたり、ある期間内の会話回数を把握するのに適している。マッチしたセッションリストと各セッションの最初の5件のメッセージプレビューを返却する。',
params: {
keywords: '任意の検索キーワードリスト。これらのキーワードを含むセッションのみ返却する(OR ロジックマッチ)',
limit: '返却セッション数の上限。デフォルト 20',
year: '指定年のセッションをフィルタリング(例:2024)',
month: '指定月のセッションをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のセッションをフィルタリング(1-31)。year と month と併用する必要がある',
start_time: '開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")',
end_time: '終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")',
},
},
get_session_messages: {
desc: '指定セッションの完全なメッセージリストを取得する。search_sessions で関連セッションを見つけた後、そのセッションの完全なコンテキストを取得するために使用する。セッションの全メッセージと参加者情報を返却する。',
params: {
session_id: 'セッション ID。search_sessions の返却結果から取得できる',
limit: '返却メッセージ数の上限。デフォルト 1000。非常に長いセッションでは Token 節約のため件数を制限できる',
},
},
get_session_summaries: {
desc: `セッション要約リストを取得し、グループチャットの過去の議論トピックをすばやく把握する。
適用シーン:
1. グループで最近何が話題になっていたか知りたい
2. キーワードで過去に議論されたトピックを検索
3. 「グループで旅行について話したことある?」などの概要的な質問
返却される要約は各セッションの短い概要であり、興味のあるセッションをすばやく特定し、get_session_messages で詳細を取得できる。`,
params: {
keywords: '要約内で検索するキーワードリスト(OR ロジックマッチ)',
limit: '返却セッション数の上限。デフォルト 20',
year: '指定年のセッションをフィルタリング',
month: '指定月のセッションをフィルタリング(1-12)',
day: '指定日のセッションをフィルタリング(1-31)',
start_time: '開始時刻。形式 "YYYY-MM-DD HH:mm"',
end_time: '終了時刻。形式 "YYYY-MM-DD HH:mm"',
},
},
// ===== SQL 分析ツール =====
message_type_breakdown: {
desc: 'メッセージタイプ別に直近 N 日間のメッセージ分布を集計する(テキスト、画像、音声、スタンプなどの件数)。コミュニケーション方法の傾向を把握するのに適している。',
params: { days: '直近何日間のデータを集計するか' },
rowTemplate: '{type_name}:{msg_count} 件({percentage}%)',
summaryTemplate: 'メッセージタイプ分布(全 {rowCount} 種類):',
fallback: 'この期間にメッセージ記録がありません',
},
peak_chat_hours_by_member: {
desc: '指定メンバーの直近 N 日間の時間帯別発言数分布を分析し、最もアクティブな時間帯を特定する。事前に get_members で member_id を取得する必要がある。',
params: {
member_id: 'メンバー ID(get_members で取得)',
days: '直近何日間のデータを集計するか',
},
rowTemplate: '{hour}:00 — {msg_count} 件のメッセージ',
summaryTemplate: '該当メンバーの時間帯別発言数(全 {rowCount} アクティブ時間帯):',
fallback: '指定期間内に該当メンバーの発言記録がありません',
},
member_activity_trend: {
desc: '指定メンバーの直近 N 日間の日別発言数の変化トレンドを表示する。ある人物がよりアクティブになったか、より静かになったかを観察するのに適している。事前に get_members で member_id を取得する必要がある。',
params: {
member_id: 'メンバー ID(get_members で取得)',
days: '直近何日間のトレンドを表示するか',
},
rowTemplate: '{day}:{msg_count} 件',
summaryTemplate: '該当メンバーの直近 {rowCount} 日間の発言記録:',
fallback: '指定期間内に該当メンバーの発言記録がありません',
},
silent_members: {
desc: 'N 日以上発言していない「休眠メンバー」を検出する。コミュニティ運営で離脱リスクのある利用者を見つけるのに向いている。',
params: { days: '何日間未発言でサイレントとみなすか' },
rowTemplate: '{name} — {silent_days} 日間サイレント',
summaryTemplate: '全 {rowCount} 名の休眠メンバーを検出:',
fallback: '指定日数を超えて未発言のメンバーは見つかりませんでした。コミュニティのアクティビティは良好です!',
},
reply_interaction_ranking: {
desc: 'グループ内の返信インタラクションランキングを分析し、誰が誰に最も多く返信しているかを特定する。コミュニティのコアインタラクション関係やオピニオンリーダーの発見に適している。',
params: {
days: '直近何日間のデータを集計するか',
limit: '上位何組のインタラクション関係を返却するか',
},
rowTemplate: '{replier_name} → {original_name}:{reply_count} 回返信',
summaryTemplate: '返信インタラクション Top {rowCount}:',
fallback: 'この期間に返信インタラクション記録がありません',
},
mutual_interaction_pairs: {
desc: '最も頻繁にインタラクションするメンバーペアを特定する。双方向のメッセージ時間近接度に基づく(一方の発言後5分以内にもう一方も発言した場合を1回のインタラクションとみなす)。親密な友人の組み合わせの発見に適している。',
params: {
days: '直近何日間のデータを集計するか',
limit: '上位何組を返却するか',
},
rowTemplate: '{member_a} ↔ {member_b}:{interaction_count} 回のインタラクション',
summaryTemplate: '最も頻繁にインタラクションする {rowCount} 組のペア:',
fallback: 'この期間に明らかなインタラクション関係は検出されませんでした',
},
member_message_length_stats: {
desc: '各メンバーの平均メッセージ長(テキストメッセージのみ)を集計する。長いメッセージは通常、より丁寧なコミュニケーションを意味する。深い交流を行う人物の発見に適している。',
params: {
days: '直近何日間のデータを集計するか',
top_n: '上位何名を返却するか',
},
rowTemplate: '{name} — 平均 {avg_length} 字/件(全 {msg_count} 件、最長 {max_length} 字)',
summaryTemplate: 'メッセージ長 Top {rowCount}(長い = より丁寧):',
fallback: 'この期間に十分なテキストメッセージデータがありません',
},
unanswered_messages: {
desc: '直近 N 日間で返信されていないメッセージを検索する。未解決の問題である可能性がある。テキストメッセージかつ10文字以上のもののみ集計する(短い挨拶を除外)。',
params: {
days: '直近何日間のデータを検索するか',
limit: '最大何件返却するか',
},
rowTemplate: '[{send_time}] {sender_name}:{content_preview}',
summaryTemplate: '全 {rowCount} 件の返信されていない可能性のあるメッセージ:',
fallback: 'この期間のすべてのメッセージに返信がありました。対応品質は良好です!',
},
daily_active_members: {
desc: '日ごとのユニーク発言者数(DAU)とメッセージ数を集計し、グループの活性度の推移を観察する。「最近グループはどのくらい活発か」「何人が発言しているか」に適している。',
params: { days: '直近何日間のデータを集計するか' },
rowTemplate: '{day}:{active_members} 人アクティブ、{msg_count} 件メッセージ',
summaryTemplate: '直近 {rowCount} 日間の日別アクティブ人数推移:',
fallback: 'この期間にメッセージの記録がありません',
},
conversation_initiator_stats: {
desc: '各メンバーが会話を開始した回数(セッションの最初の発言者)を集計し、誰が最も話題を切り出すかを発見する。セッションインデックスの生成が必要。',
params: {
days: '直近何日間のデータを集計するか',
limit: '上位何名を返却するか',
},
rowTemplate: '{name}:{initiated_count} 回話題を開始',
summaryTemplate: '話題開始者 Top {rowCount}:',
fallback: 'この期間にセッション記録がありません。先にセッションインデックスを生成する必要があるかもしれません',
},
activity_heatmap: {
desc: '曜日×時間帯のメッセージ数マトリックスを返却する。活性度ヒートマップの生成に適している。weekday: 0=日曜, 1=月曜, ..., 6=土曜。',
params: { days: '直近何日間のデータを集計するか' },
rowTemplate: '曜日{weekday} {hour}:00 — {msg_count} 件',
summaryTemplate: '活性度ヒートマップデータ(全 {rowCount} 時間帯にメッセージあり):',
fallback: 'この期間にメッセージの記録がありません',
},
response_time_analysis: {
desc: 'メッセージ間の応答時間を分析し、メンバーごとの中央値と平均返信速度を集計する。「みんなどのくらいで返信するか」「誰が最も速く返信するか」に適している。',
params: {
days: '直近何日間のデータを集計するか',
top_n: '上位何名を返却するか',
},
},
keyword_frequency: {
desc: '指定期間のテキストメッセージを分詞し、高頻度キーワードをランキングする。中国語・英語・日本語の分詞に対応。「みんなが最もよく話す話題は何か」「高頻度キーワードは何か」に適している。',
params: {
days: '直近何日間のデータを集計するか',
top_n: '上位何個のキーワードを返却するか',
},
},
},
// ===== AI Agent システムプロンプト =====
agent: {
answerWithoutTools: '取得済みの情報に基づいて回答してください。これ以上ツールを呼び出さないでください。',
toolError: 'エラー: {{error}}',
currentDateIs: '現在の日付は',
chatContext: {
private: '会話',
group: 'グループチャット',
},
ownerNote: `現在のユーザー情報:
- ユーザーの{{chatContext}}における立場は「{{displayName}}」(platformId: {{platformId}})
- ユーザーが「私」「自分の」と言った場合、「{{displayName}}」を指す
- 「私」の発言を検索する際は、sender_id パラメータで該当メンバーをフィルタリングする
`,
memberNotePrivate: `メンバー検索戦略:
- 個人チャットは2人だけなので、直接メンバー一覧を取得できる
- ユーザーが「相手」「彼/彼女」と言った場合、get_members でもう一方の情報を取得する
`,
memberNoteGroup: `メンバー検索戦略:
- ユーザーが特定のグループメンバーに言及した場合(例:「田中さんは何を言った?」「太郎の発言」など)、まず get_members でメンバー一覧を取得する
- グループメンバーには3種類の名前がある:accountName(元のニックネーム)、groupNickname(グループニックネーム)、aliases(ユーザー定義の別名)
- get_members の search パラメータでこれら3種類の名前をあいまい検索できる
- メンバーを見つけたら、その id フィールドを search_messages の sender_id パラメータとして使用して発言を取得する
`,
mentionedMembersNote:
'このラウンドでユーザーが明示的に @ 選択したメンバー(member_id を再検索なしで直接使えます):',
timeParamsIntro: '時間パラメータ:start_time/end_time で範囲を指定。形式は "YYYY-MM-DD HH:mm"',
defaultYearNote: '時間範囲を指定しない場合は全期間が対象。現在の年は{{year}}年',
dataSnapshotNote:
'現在のチャットデータベースのスナップショット:{{name}}({{platform}})、総メッセージ {{totalMessages}} 件、メンバー {{totalMembers}} 人、期間 {{firstMessageDate}} ~ {{lastMessageDate}}。このスナップショットはデータ範囲の判断にのみ使い、具体的なチャット事実の回答には必ず現在のデータベースをツールで検索する。',
evidencePolicy: `証拠ポリシー:
- AI 会話履歴、過去の AI 回答、圧縮要約はユーザー意図の理解にのみ使用し、チャット記録の事実証拠として扱わない。
- ユーザーがチャット内容、最近の話題、誰かの発言、ランキング/統計、ある話題が出たかどうか、または原文引用を求めた場合は、必ず先に適切なデータツールで現在のデータベースを検索する。
- 新しいチャット記録が追加されている場合、現在のデータベースは古いウィンドウ履歴と異なる可能性がある。最新の証拠取得には get_chat_overview または get_recent_messages/search_messages を優先する。
- 事実根拠として使えるのは、ツールが返したメッセージ、統計、またはデータベース概要のみ。ツールが十分な証拠を返さない場合は、データ不足と明示し、存在しないチャット記録を作らない。`,
responseInstruction: 'ユーザーの質問に応じて適切なツールを選択してデータを取得し、データに基づいて回答する。',
fallbackRoleDefinition: {
group: `あなたはプロフェッショナルだがカジュアルなスタイルのグループチャット履歴分析アシスタントです。
ユーザーのグループチャット履歴データの理解と分析を支援し、適度にネットスラングや顔文字を使って雰囲気を和らげますが、結論の正確性に影響しないようにします。
## 回答要件
1. ツールから返却されたデータに基づいて回答し、情報を捏造しない
2. データが不十分で質問に答えられない場合は、その旨を説明する
3. 回答は簡潔明瞭に、Markdown 形式を使用する
4. 適度にネットスラングや顔文字を加えてよい(強度は控えめに)
5. ネタは事実の正確さと結論の明確さに影響を与えてはならず、低俗または不快な表現は避ける`,
private: `あなたはプロフェッショナルだがカジュアルなスタイルの個人チャット履歴分析アシスタントです。
ユーザーの個人チャット履歴データの理解と分析を支援し、適度にネットスラングや顔文字を使って雰囲気を和らげますが、結論の正確性に影響しないようにします。
## 回答要件
1. ツールから返却されたデータに基づいて回答し、情報を捏造しない
2. データが不十分で質問に答えられない場合は、その旨を説明する
3. 回答は簡潔明瞭に、Markdown 形式を使用する
4. 適度にネットスラングや顔文字を加えてよい(強度は控えめに)
5. ネタは事実の正確さと結論の明確さに影響を与えてはならず、低俗または不快な表現は避ける`,
},
},
},
// ===== P3: LLM 設定 =====
llm: {
notConfigured: 'LLM サービスが未設定です。先に設定で API Key を設定してください',
maxConfigs: '設定は最大 {{count}} 個まで追加できます',
configNotFound: '設定が存在しません',
noActiveConfig: 'アクティブな設定がありません',
callFailed: 'LLM 呼び出しに失敗しました。モデル設定を確認してください。',
genericProviderName: 'API プロバイダー',
rawErrorLabel: '元のエラー',
},
// ===== P4: 要約生成 =====
summary: {
sessionNotFound: 'セッションが存在しないか、データベースを開けませんでした',
tooFewMessages: 'メッセージ数が{{count}}件未満のため、要約の生成は不要です',
tooFewValidMessages: '有効なメッセージ数が{{count}}件未満のため、要約の生成は不要です',
sessionNotExist: 'セッションが存在しません',
messagesTooFew: 'メッセージが少なすぎます',
validMessagesTooFew: '有効なメッセージが少なすぎます',
systemPromptDirect: 'あなたは会話要約の専門家であり、簡潔な言葉で会話内容を要約することに長けている。',
systemPromptMerge: 'あなたは会話要約の専門家であり、複数の要約を一つのまとまった概要に統合することに長けている。',
},
// AI shared translations (from @openchatlab/node-runtime)
...aiLocale,
}
+6 -309
View File
@@ -1,6 +1,10 @@
/**
* 主进程中文翻译
*
* AI 共享翻译从 @openchatlab/node-runtime 导入,Electron 专有翻译在本文件定义。
*/
import aiLocale from '@openchatlab/node-runtime/src/ai/i18n/locales/zh-CN'
export default {
// ===== 通用 =====
common: {
@@ -52,313 +56,6 @@ export default {
notRegistered: '工具 "{{toolName}}" 未注册',
},
// ===== P2: AI 工具描述(Function Calling) =====
ai: {
tools: {
search_messages: {
desc: '根据关键词搜索聊天记录,是回答关键词、成员发言、是否出现过某话题等事实问题的主要证据工具。可以指定时间范围和发送者来筛选消息。支持精确到分钟级别的时间查询。',
params: {
keywords: '搜索关键词列表,会用 OR 逻辑匹配包含任一关键词的消息。如果只需要按发送者筛选,可以传空数组 []',
sender_id: '发送者的成员 ID,用于筛选特定成员发送的消息。可以通过 get_members 工具获取成员 ID',
limit: '返回消息数量限制,默认 1000,最大 50000',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
deep_search_messages: {
desc: '精确子串匹配搜索聊天记录,速度较慢但不会遗漏任何包含关键词的消息。当 search_messages 结果不足、需要验证某段话是否真实存在、或搜索部分词/单个字符时使用。',
params: {
keywords: '搜索关键词列表,使用子串匹配(LIKE),任一关键词匹配即返回',
sender_id: '发送者的成员 ID,用于筛选特定成员发送的消息',
limit: '返回消息数量限制,默认 1000,最大 50000',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
get_recent_messages: {
desc: '获取指定时间段内的聊天消息,是回答"最近大家聊了什么"、"X月聊了什么"、追加新记录后最新内容等概览性问题的首选证据工具。支持精确到分钟级别的时间查询。',
params: {
limit: '返回消息数量限制,默认 100(节省 token,可根据需要增加)',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
get_chat_overview: {
desc: '获取聊天记录的基本概览信息,包括群名/平台/类型/总消息数/总成员数/时间跨度/最活跃成员排名。适合在分析前或追加新记录后确认当前数据库范围。',
params: {
top_n: '返回前 N 名活跃成员,默认 10',
},
},
get_member_stats: {
desc: '获取群成员的活跃度统计数据。适用于回答"谁最活跃"、"发言最多的是谁"等问题。',
params: {
top_n: '返回前 N 名成员,默认 10',
},
},
get_time_stats: {
desc: '获取群聊的时间分布统计。适用于回答"什么时候最活跃"、"大家一般几点聊天"等问题。',
params: {
type: '统计类型:hourly(按小时)、weekday(按星期)、daily(按日期)',
},
},
get_members: {
desc: '获取群成员列表,包括成员的基本信息、别名和消息统计。适用于查询"群里有哪些人"、"某人的别名是什么"、"谁的QQ号是xxx"等问题。',
params: {
search: '可选的搜索关键词,用于筛选成员昵称、别名或QQ号',
limit: '返回成员数量限制,默认返回全部',
},
},
get_member_name_history: {
desc: '获取成员的昵称变更历史记录。适用于回答"某人以前叫什么名字"、"某人的昵称变化"、"某人曾用名"等问题。需要先通过 get_members 工具获取成员 ID。',
params: {
member_id: '成员的数据库 ID,可以通过 get_members 工具获取',
},
},
get_conversation_between: {
desc: '获取两个群成员之间的对话记录。适用于回答"A和B之间聊了什么"、"查看两人的对话"等问题。需要先通过 get_members 获取成员 ID。支持精确到分钟级别的时间查询。',
params: {
member_id_1: '第一个成员的数据库 ID',
member_id_2: '第二个成员的数据库 ID',
limit: '返回消息数量限制,默认 100',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
get_message_context: {
desc: '根据消息 ID 获取前后的上下文消息。适用于引用具体消息前后进行事实验证,比如"这条消息前后在聊什么"、"确认这段话是否有上下文"等。支持单个或批量消息 ID。',
params: {
message_ids:
'要查询上下文的消息 ID 列表,可以是单个 ID 或多个 ID。消息 ID 可以从 search_messages 等工具的返回结果中获取',
context_size: '上下文大小,即获取前后各多少条消息,默认 20',
},
},
search_sessions: {
desc: '搜索聊天会话(对话段落)。会话是根据消息时间间隔自动切分的对话单元。适用于查找特定话题的讨论、了解某个时间段内发生了几次对话等场景。返回匹配的会话列表及每个会话的前5条消息预览。',
params: {
keywords: '可选的搜索关键词列表,只返回包含这些关键词的会话(OR 逻辑匹配)',
limit: '返回会话数量限制,默认 20',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
get_session_messages: {
desc: '获取指定会话的完整消息列表。用于在 search_sessions 找到相关会话后,获取该会话的完整上下文。返回会话的所有消息及参与者信息。',
params: {
session_id: '会话 ID,可以从 search_sessions 的返回结果中获取',
limit: '返回消息数量限制,默认 1000。对于超长会话可以限制返回数量以节省 token',
},
},
get_session_summaries: {
desc: `获取会话摘要列表,快速了解群聊历史讨论的主题。
适用场景:
1. 了解群里最近在聊什么话题
2. 按关键词搜索讨论过的话题
3. 概览性问题如"群里有没有讨论过旅游"
返回的摘要是对每个会话的简短总结,可以帮助快速定位感兴趣的会话,然后用 get_session_messages 获取详情。`,
params: {
keywords: '在摘要中搜索的关键词列表(OR 逻辑匹配)',
limit: '返回会话数量限制,默认 20',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
// ===== SQL 分析工具 =====
message_type_breakdown: {
desc: '按消息类型统计近 N 天的消息分布(文本、图片、语音、表情等各有多少条)。适用于了解沟通方式偏好。',
params: { days: '统计最近多少天的数据' },
rowTemplate: '{type_name}:{msg_count} 条(占 {percentage}%)',
summaryTemplate: '消息类型分布(共 {rowCount} 种类型):',
fallback: '该时间范围内没有消息记录',
},
peak_chat_hours_by_member: {
desc: '分析指定成员在近 N 天内每小时的发言量分布,找出其最活跃的时段。需要先通过 get_members 获取 member_id。',
params: {
member_id: '成员 ID(通过 get_members 获取)',
days: '统计最近多少天的数据',
},
rowTemplate: '{hour}:00 — {msg_count} 条消息',
summaryTemplate: '该成员各时段发言量(共 {rowCount} 个活跃时段):',
fallback: '该成员在指定时间范围内没有发言记录',
},
member_activity_trend: {
desc: '查看指定成员近 N 天的每日发言数量变化趋势。适用于观察某人是否变得更活跃或更沉默。需要先通过 get_members 获取 member_id。',
params: {
member_id: '成员 ID(通过 get_members 获取)',
days: '查看最近多少天的趋势',
},
rowTemplate: '{day}:{msg_count} 条',
summaryTemplate: '该成员近 {rowCount} 天有发言记录:',
fallback: '该成员在指定时间范围内没有发言记录',
},
silent_members: {
desc: '检测超过 N 天未发言的「沉默成员」。适用于社群运营中发现流失风险用户。',
params: { days: '多少天未发言算沉默' },
rowTemplate: '{name} — 已沉默 {silent_days} 天',
summaryTemplate: '共发现 {rowCount} 位沉默成员:',
fallback: '没有发现超过指定天数未发言的成员,社群活跃度良好!',
},
reply_interaction_ranking: {
desc: '分析群内的回复互动关系排行,找出谁回复谁最多。适用于发现社群中的核心互动关系和意见领袖。',
params: {
days: '统计最近多少天的数据',
limit: '返回前多少对互动关系',
},
rowTemplate: '{replier_name} → {original_name}:{reply_count} 次回复',
summaryTemplate: '回复互动 Top {rowCount}:',
fallback: '该时间范围内没有回复互动记录',
},
mutual_interaction_pairs: {
desc: '找出互动最频繁的成员对,基于双向消息时间接近度(一方发言后 5 分钟内另一方也发言即视为一次互动)。适用于发现关系亲密的好友组合。',
params: {
days: '统计最近多少天的数据',
limit: '返回前多少对',
},
rowTemplate: '{member_a} ↔ {member_b}:{interaction_count} 次互动',
summaryTemplate: '互动最频繁的 {rowCount} 对好友:',
fallback: '该时间范围内没有检测到明显的互动关系',
},
member_message_length_stats: {
desc: '统计各成员的平均消息长度(仅文本消息),长消息通常意味着更用心的交流。适用于发现深度交流者。',
params: {
days: '统计最近多少天的数据',
top_n: '返回前多少名',
},
rowTemplate: '{name} — 平均 {avg_length} 字/条(共 {msg_count} 条,最长 {max_length} 字)',
summaryTemplate: '消息长度 Top {rowCount}(更长 = 更用心):',
fallback: '该时间范围内没有足够的文本消息数据',
},
unanswered_messages: {
desc: '查找近 N 天内未被回复的消息,这些可能是未解决的客户问题。仅统计文本消息且内容超过 10 字的(过滤简短寒暄)。',
params: {
days: '查找最近多少天的数据',
limit: '最多返回多少条',
},
rowTemplate: '[{send_time}] {sender_name}:{content_preview}',
summaryTemplate: '共发现 {rowCount} 条可能未被回复的消息:',
fallback: '该时间范围内所有消息都已得到回复,服务质量很好!',
},
daily_active_members: {
desc: '统计每日独立发言人数(DAU)和消息量,用于观察群活力变化趋势。适用于"群活跃度趋势怎么样"、"最近有多少人在说话"。',
params: { days: '统计最近多少天的数据' },
rowTemplate: '{day}:{active_members} 人活跃,{msg_count} 条消息',
summaryTemplate: '近 {rowCount} 天的每日活跃人数趋势:',
fallback: '该时间范围内没有消息记录',
},
conversation_initiator_stats: {
desc: '统计每个成员发起会话(作为会话首条消息的发送者)的次数,找出谁最常开启话题。需要已生成会话索引。',
params: {
days: '统计最近多少天的数据',
limit: '返回前多少名',
},
rowTemplate: '{name}:发起 {initiated_count} 次话题',
summaryTemplate: '话题发起者 Top {rowCount}:',
fallback: '该时间范围内没有会话记录,可能需要先生成会话索引',
},
activity_heatmap: {
desc: '返回 星期×小时 的消息数矩阵,适合生成活跃度热力图。weekday: 0=周日, 1=周一, ..., 6=周六。',
params: { days: '统计最近多少天的数据' },
rowTemplate: '星期{weekday} {hour}:00 — {msg_count} 条',
summaryTemplate: '活跃度热力图数据(共 {rowCount} 个时段有消息):',
fallback: '该时间范围内没有消息记录',
},
response_time_analysis: {
desc: '分析消息之间的响应时间,按成员维度统计中位数和平均回复速度。适用于"大家平均多久回复消息"、"谁回复最快"。',
params: {
days: '统计最近多少天的数据',
top_n: '返回前多少名',
},
},
keyword_frequency: {
desc: '对指定时间段的文本消息进行分词,统计高频关键词排行。支持中英日文分词。适用于"大家最常说什么"、"高频关键词是什么"。',
params: {
days: '统计最近多少天的数据',
top_n: '返回前多少个关键词',
},
},
},
// ===== AI Agent 系统提示词 =====
agent: {
answerWithoutTools: '请根据已获取的信息给出回答,不要再调用工具。',
toolError: '错误: {{error}}',
currentDateIs: '当前日期是',
chatContext: {
private: '对话',
group: '群聊',
},
ownerNote: `当前用户身份:
- 用户在{{chatContext}}中的身份是「{{displayName}}」(platformId: {{platformId}})
- 当用户提到"我"、"我的"时,指的就是「{{displayName}}」
- 查询"我"的发言时,使用 sender_id 参数筛选该成员
`,
memberNotePrivate: `成员查询策略:
- 私聊只有两个人,可以直接获取成员列表
- 当用户提到"对方"、"他/她"时,通过 get_members 获取另一方信息
`,
memberNoteGroup: `成员查询策略:
- 当用户提到特定群成员(如"张三说过什么"、"小明的发言"等)时,应先调用 get_members 获取成员列表
- 群成员有三种名称:accountName(原始昵称)、groupNickname(群昵称)、aliases(用户自定义别名)
- 通过 get_members 的 search 参数可以模糊搜索这三种名称
- 找到成员后,使用其 id 字段作为 search_messages 的 sender_id 参数来获取该成员的发言
`,
mentionedMembersNote: '本轮用户显式 @ 的成员(可直接使用 member_id,无需再次搜索):',
timeParamsIntro: '时间参数:使用 start_time/end_time 指定时间范围,格式 "YYYY-MM-DD HH:mm"',
defaultYearNote: '未指定时间范围时默认查询全部。当前年份为{{year}}年',
dataSnapshotNote:
'当前聊天数据库快照:{{name}}({{platform}}),总消息 {{totalMessages}} 条,成员 {{totalMembers}} 人,时间范围 {{firstMessageDate}} ~ {{lastMessageDate}}。该快照只用于判断数据范围;回答具体聊天事实仍必须调用工具检索当前数据库。',
evidencePolicy: `证据策略:
- AI 对话历史、历史 AI 回复和压缩摘要只用于理解用户意图,不能作为聊天记录事实证据。
- 只要用户询问聊天记录内容、最近聊什么、某人说过什么、统计排行、是否出现过某话题或要求引用原话,必须先调用合适的数据工具检索当前数据库。
- 如果已追加新聊天记录,当前数据库可能不同于旧窗口历史;优先使用 get_chat_overview 或 get_recent_messages/search_messages 获取最新证据。
- 只有工具返回的消息、统计或数据库概览可以作为事实依据;工具没有返回足够证据时,明确说明数据不足,不要编造不存在的聊天记录。`,
currentTask: '当前任务',
skillPriorityNote: '注意:在执行此任务时,请优先遵循以下任务的输出格式要求,这可以覆盖你的常规回复习惯。',
responseInstruction: '根据用户的问题,选择合适的工具获取数据,然后基于数据给出回答。',
fallbackRoleDefinition: {
group: `你是一个专业但风格轻松的群聊记录分析助手。
你的任务是帮助用户理解和分析他们的群聊记录数据,同时可以适度使用 B 站/网络热梗和表情/颜文字活跃气氛,但不影响结论的准确性。
## 回答要求
1. 基于工具返回的数据回答,不要编造信息
2. 如果数据不足以回答问题,请说明
3. 回答要简洁明了,使用 Markdown 格式
4. 可以适度加入 B 站/网络热梗、表情/颜文字(强度适中)
5. 玩梗不得影响事实准确与结论清晰,避免低俗或冒犯性表达`,
private: `你是一个专业但风格轻松的私聊记录分析助手。
你的任务是帮助用户理解和分析他们的私聊记录数据,同时可以适度使用 B 站/网络热梗和表情/颜文字活跃气氛,但不影响结论的准确性。
## 回答要求
1. 基于工具返回的数据回答,不要编造信息
2. 如果数据不足以回答问题,请说明
3. 回答要简洁明了,使用 Markdown 格式
4. 可以适度加入 B 站/网络热梗、表情/颜文字(强度适中)
5. 玩梗不得影响事实准确与结论清晰,避免低俗或冒犯性表达`,
},
},
},
// ===== P3: LLM 配置 =====
llm: {
notConfigured: 'LLM 服务未配置,请先在设置中配置 API Key',
maxConfigs: '最多只能添加 {{count}} 个配置',
configNotFound: '配置不存在',
noActiveConfig: '没有激活的配置',
callFailed: 'LLM 调用失败,请检查模型配置是否正确',
genericProviderName: 'API 服务',
rawErrorLabel: '原始错误',
},
// ===== P4: 摘要生成 =====
summary: {
sessionNotFound: '会话不存在或数据库打开失败',
tooFewMessages: '消息数量少于{{count}}条,无需生成摘要',
tooFewValidMessages: '有效消息数量少于{{count}}条,无需生成摘要',
sessionNotExist: '会话不存在',
messagesTooFew: '消息太少',
validMessagesTooFew: '有效消息太少',
systemPromptDirect: '你是一个对话摘要专家,擅长用简洁的语言总结对话内容。',
systemPromptMerge: '你是一个对话摘要专家,擅长将多个摘要合并成一个连贯的总结。',
},
// AI shared translations (from @openchatlab/node-runtime)
...aiLocale,
}
+18 -336
View File
@@ -1,6 +1,11 @@
/**
* 主進程繁體中文翻譯
* 主程序繁體中文翻譯
*
* AI 共享翻譯自 @openchatlab/node-runtime 匯入,
* Electron 專有翻譯在本檔案定義。
*/
import aiLocale from '@openchatlab/node-runtime/src/ai/i18n/locales/zh-TW'
export default {
// ===== 通用 =====
common: {
@@ -17,8 +22,8 @@ export default {
downloadComplete: '下載完成',
readyToInstall: '新版本已準備就緒,是否現在安裝?',
install: '安裝',
remindLater: '之後提醒',
installOnQuit: '稍後(應用程式退出後自動安裝)',
remindLater: '稍後提醒',
installOnQuit: '稍後(應用退出後自動安裝)',
upToDate: '已是最新版本',
},
@@ -35,16 +40,16 @@ export default {
// ===== P1: 資料庫遷移 =====
database: {
migrationV1Desc: '新增 owner_id 欄位到 meta 表',
migrationV1Message: '支援「Owner」功能,可在成員清單中設定自己的身分',
migrationV1Desc: '在 meta 資料表新增 owner_id 欄位',
migrationV1Message: '支援「Owner」功能,可在成員清單中設定自己的身份',
migrationV2Desc: '新增 roles、reply_to_message_id、platform_message_id 欄位',
migrationV2Message: '支援成員角色、訊息回覆關係和回覆內容預覽',
migrationV3Desc: '新增會話索引相關表(chat_session、message_context)和 session_gap_threshold 欄位',
migrationV3Message: '支援會話時間軸瀏覽和 AI 增強分析功能',
migrationV4Desc: '建立 FTS5 全文搜尋索引(message_fts)並構建索引資料',
migrationV4Message: '支援全文搜尋,大幅提升關鍵字搜尋速度',
integrityError: '資料庫結構不完整:缺少 meta 表。建議刪除此資料庫檔案後重新匯入。',
checkFailed: '資料庫檢查失敗:{{error}}',
migrationV3Desc: '新增會話索引相關資料表(chat_session、message_context)及 session_gap_threshold 欄位',
migrationV3Message: '支援會話時間軸瀏覽與 AI 增強分析功能',
migrationV4Desc: '建立 FTS5 全文搜尋索引(message_fts)並建構索引資料',
migrationV4Message: '支援全文搜尋,大幅提升關鍵詞搜尋速度',
integrityError: '資料庫結構不完整:缺少 meta 資料表。建議刪除此資料庫檔案後重新匯入。',
checkFailed: '資料庫檢查失敗: {{error}}',
},
// ===== 工具系統 =====
@@ -52,329 +57,6 @@ export default {
notRegistered: '工具 "{{toolName}}" 未註冊',
},
// ===== P2: AI 工具描述(Function Calling) =====
ai: {
tools: {
search_messages: {
desc: '根據關鍵詞搜尋聊天紀錄,是回答關鍵詞、成員發言、是否出現過某話題等事實問題的主要證據工具。可以指定時間範圍和傳送者來篩選訊息。支援精確到分鐘級別的時間查詢。',
params: {
keywords: '搜尋關鍵詞清單,會用 OR 邏輯匹配包含任一關鍵詞的訊息。如果只需要按傳送者篩選,可以傳空陣列 []',
sender_id: '傳送者的成員 ID,用於篩選特定成員傳送的訊息。可以透過 get_members 工具取得成員 ID',
limit: '回傳訊息數量限制,預設 1000,最大 50000',
year: '篩選指定年份的訊息,如 2024',
month: '篩選指定月份的訊息(1-12),需要配合 year 使用',
day: '篩選指定日期的訊息(1-31),需要配合 year 和 month 使用',
hour: '篩選指定小時的訊息(0-23),需要配合 year、month 和 day 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定後會覆蓋 year/month/day/hour 參數',
},
},
deep_search_messages: {
desc: '精確子串匹配搜尋聊天紀錄,速度較慢但不會遺漏任何包含關鍵詞的訊息。當 search_messages 結果不足、需要驗證某段話是否真實存在、或搜尋部分詞/單個字元時使用。',
params: {
keywords: '搜尋關鍵詞清單,使用子串匹配(LIKE),任一關鍵詞匹配即回傳',
sender_id: '傳送者的成員 ID,用於篩選特定成員傳送的訊息',
limit: '回傳訊息數量限制,預設 1000,最大 50000',
year: '篩選指定年份的訊息,如 2024',
month: '篩選指定月份的訊息(1-12),需要配合 year 使用',
day: '篩選指定日期的訊息(1-31),需要配合 year 和 month 使用',
hour: '篩選指定小時的訊息(0-23),需要配合 year、month 和 day 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm"。指定後會覆蓋 year/month/day/hour 參數',
},
},
get_recent_messages: {
desc: '取得指定時間段內的聊天訊息,是回答「最近大家聊了什麼」、「X月聊了什麼」、追加新紀錄後最新內容等概覽性問題的首選證據工具。支援精確到分鐘級別的時間查詢。',
params: {
limit: '回傳訊息數量限制,預設 100(可節省 Token,必要時再增加)',
year: '篩選指定年份的訊息,如 2024',
month: '篩選指定月份的訊息(1-12),需要配合 year 使用',
day: '篩選指定日期的訊息(1-31),需要配合 year 和 month 使用',
hour: '篩選指定小時的訊息(0-23),需要配合 year、month 和 day 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定後會覆蓋 year/month/day/hour 參數',
},
},
get_chat_overview: {
desc: '取得聊天記錄的基本概覽資訊,包括群名/平台/類型/總訊息數/總成員數/時間跨度/最活躍成員排名。適合在分析前或追加新紀錄後確認目前資料庫範圍。',
params: {
top_n: '回傳前 N 名活躍成員,預設 10',
},
},
get_member_stats: {
desc: '取得群成員的活躍度統計資料。適用於回答「誰最活躍」、「發言最多的是誰」等問題。',
params: {
top_n: '回傳前 N 名成員,預設 10',
},
},
get_time_stats: {
desc: '取得群聊的時間分佈統計。適用於回答「什麼時候最活躍」、「大家一般幾點聊天」等問題。',
params: {
type: '統計類型:hourly(按小時)、weekday(按星期)、daily(按日期)',
},
},
get_members: {
desc: '取得群成員清單,包含基本資料、別名與訊息統計。適用於查詢「群裡有哪些人」、「某人的別名是什麼」、「誰的 QQ 號是 xxx」等問題。',
params: {
search: '可選的搜尋關鍵詞,用於篩選成員暱稱、別名或 QQ 號',
limit: '回傳成員數量限制,預設回傳全部',
},
},
get_member_name_history: {
desc: '取得成員的暱稱變更歷史紀錄。適用於回答「某人以前叫什麼名字」、「某人的暱稱變化」、「某人曾用名」等問題。需要先透過 get_members 工具取得成員 ID。',
params: {
member_id: '成員的資料庫 ID,可以透過 get_members 工具取得',
},
},
get_conversation_between: {
desc: '取得兩位群成員之間的對話紀錄。適用於回答「A 和 B 之間聊了什麼」、「檢視兩人的對話」等問題。需要先透過 get_members 取得成員 ID。支援精確到分鐘級別的時間查詢。',
params: {
member_id_1: '第一個成員的資料庫 ID',
member_id_2: '第二個成員的資料庫 ID',
limit: '回傳訊息數量限制,預設 100',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定後會覆蓋 year/month/day/hour 參數',
},
},
get_message_context: {
desc: '根據訊息 ID 取得前後的上下文訊息。適用於引用具體訊息前後進行事實驗證,例如「這則訊息前後在聊什麼」、「確認這段話是否有上下文」等。支援單筆或批次訊息 ID。',
params: {
message_ids:
'要查詢上下文的訊息 ID 清單,可以是單個 ID 或多個 ID。訊息 ID 可以從 search_messages 等工具的回傳結果中取得',
context_size: '上下文大小,即取得前後各多少條訊息,預設 20',
},
},
search_sessions: {
desc: '搜尋聊天會話(對話段落)。會話是根據訊息時間間隔自動切分的對話單元。適用於查找特定話題的討論、了解某個時間段內發生了幾次對話等場景。回傳匹配的會話清單及每個會話的前5條訊息預覽。',
params: {
keywords: '可選的搜尋關鍵詞清單,只回傳包含這些關鍵詞的會話(OR 邏輯匹配)',
limit: '回傳會話數量限制,預設 20',
year: '篩選指定年份的會話,如 2024',
month: '篩選指定月份的會話(1-12),需要配合 year 使用',
day: '篩選指定日期的會話(1-31),需要配合 year 和 month 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
get_session_messages: {
desc: '取得指定會話的完整訊息清單。用於在 search_sessions 找到相關會話後,取得該會話的完整上下文。回傳會話的所有訊息及參與者資訊。',
params: {
session_id: '會話 ID,可以從 search_sessions 的回傳結果中取得',
limit: '回傳訊息數量限制,預設 1000。對於超長會話可以限制回傳數量以節省 token',
},
},
get_session_summaries: {
desc: `取得會話摘要清單,快速了解群聊歷史討論的主題。
適用場景:
1. 了解群裡最近在聊什麼話題
2. 按關鍵詞搜尋討論過的話題
3. 概覽性問題如「群裡有沒有討論過旅遊」
回傳的摘要是對每個會話的簡短總結,可以幫助快速定位感興趣的會話,然後用 get_session_messages 取得詳情。`,
params: {
keywords: '在摘要中搜尋的關鍵詞清單(OR 邏輯匹配)',
limit: '回傳會話數量限制,預設 20',
year: '篩選指定年份的會話',
month: '篩選指定月份的會話(1-12)',
day: '篩選指定日期的會話(1-31)',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm"',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm"',
},
},
// ===== SQL 分析工具 =====
message_type_breakdown: {
desc: '按訊息類型統計近 N 天的訊息分佈(文字、圖片、語音、表情等各有多少條)。適用於了解溝通方式偏好。',
params: { days: '統計最近多少天的資料' },
rowTemplate: '{type_name}:{msg_count} 條(佔 {percentage}%)',
summaryTemplate: '訊息類型分佈(共 {rowCount} 種類型):',
fallback: '該時間範圍內沒有訊息紀錄',
},
peak_chat_hours_by_member: {
desc: '分析指定成員在近 N 天內每小時的發言量分佈,找出其最活躍的時段。需要先透過 get_members 取得 member_id。',
params: {
member_id: '成員 ID(透過 get_members 取得)',
days: '統計最近多少天的資料',
},
rowTemplate: '{hour}:00 — {msg_count} 條訊息',
summaryTemplate: '該成員各時段發言量(共 {rowCount} 個活躍時段):',
fallback: '該成員在指定時間範圍內沒有發言紀錄',
},
member_activity_trend: {
desc: '查看指定成員近 N 天的每日發言數量變化趨勢。適用於觀察某人是否變得更活躍或更沉默。需要先透過 get_members 取得 member_id。',
params: {
member_id: '成員 ID(透過 get_members 取得)',
days: '查看最近多少天的趨勢',
},
rowTemplate: '{day}:{msg_count} 條',
summaryTemplate: '該成員近 {rowCount} 天有發言紀錄:',
fallback: '該成員在指定時間範圍內沒有發言紀錄',
},
silent_members: {
desc: '偵測超過 N 天未發言的「沉默成員」。適用於社群營運中發現流失風險使用者。',
params: { days: '多少天未發言算沉默' },
rowTemplate: '{name} — 已沉默 {silent_days} 天',
summaryTemplate: '共發現 {rowCount} 位沉默成員:',
fallback: '沒有發現超過指定天數未發言的成員,社群活躍度良好!',
},
reply_interaction_ranking: {
desc: '分析群內的回覆互動關係排行,找出誰回覆誰最多。適用於發現社群中的核心互動關係和意見領袖。',
params: {
days: '統計最近多少天的資料',
limit: '回傳前多少對互動關係',
},
rowTemplate: '{replier_name} → {original_name}:{reply_count} 次回覆',
summaryTemplate: '回覆互動 Top {rowCount}:',
fallback: '該時間範圍內沒有回覆互動紀錄',
},
mutual_interaction_pairs: {
desc: '找出互動最頻繁的成員對,基於雙向訊息時間接近度(一方發言後 5 分鐘內另一方也發言即視為一次互動)。適用於發現關係親密的好友組合。',
params: {
days: '統計最近多少天的資料',
limit: '回傳前多少對',
},
rowTemplate: '{member_a} ↔ {member_b}:{interaction_count} 次互動',
summaryTemplate: '互動最頻繁的 {rowCount} 對好友:',
fallback: '該時間範圍內沒有偵測到明顯的互動關係',
},
member_message_length_stats: {
desc: '統計各成員的平均訊息長度(僅文字訊息),長訊息通常意味著更用心的交流。適用於發現深度交流者。',
params: {
days: '統計最近多少天的資料',
top_n: '回傳前多少名',
},
rowTemplate: '{name} — 平均 {avg_length} 字/條(共 {msg_count} 條,最長 {max_length} 字)',
summaryTemplate: '訊息長度 Top {rowCount}(更長 = 更用心):',
fallback: '該時間範圍內沒有足夠的文字訊息資料',
},
unanswered_messages: {
desc: '查找近 N 天內未被回覆的訊息,這些可能是未解決的客戶問題。僅統計文字訊息且內容超過 10 字的(過濾簡短寒暄)。',
params: {
days: '查找最近多少天的資料',
limit: '最多回傳多少條',
},
rowTemplate: '[{send_time}] {sender_name}:{content_preview}',
summaryTemplate: '共發現 {rowCount} 條可能未被回覆的訊息:',
fallback: '該時間範圍內所有訊息都已得到回覆,服務品質很好!',
},
daily_active_members: {
desc: '統計每日獨立發言人數(DAU)和訊息量,用於觀察群活力變化趨勢。適用於「群活躍度趨勢怎麼樣」、「最近有多少人在說話」。',
params: { days: '統計最近多少天的資料' },
rowTemplate: '{day}:{active_members} 人活躍,{msg_count} 條訊息',
summaryTemplate: '近 {rowCount} 天的每日活躍人數趨勢:',
fallback: '該時間範圍內沒有訊息紀錄',
},
conversation_initiator_stats: {
desc: '統計每個成員發起會話(作為會話首條訊息的發送者)的次數,找出誰最常開啟話題。需要已產生會話索引。',
params: {
days: '統計最近多少天的資料',
limit: '回傳前多少名',
},
rowTemplate: '{name}:發起 {initiated_count} 次話題',
summaryTemplate: '話題發起者 Top {rowCount}:',
fallback: '該時間範圍內沒有會話紀錄,可能需要先產生會話索引',
},
activity_heatmap: {
desc: '回傳 星期×小時 的訊息數矩陣,適合產生活躍度熱力圖。weekday: 0=週日, 1=週一, ..., 6=週六。',
params: { days: '統計最近多少天的資料' },
rowTemplate: '星期{weekday} {hour}:00 — {msg_count} 條',
summaryTemplate: '活躍度熱力圖資料(共 {rowCount} 個時段有訊息):',
fallback: '該時間範圍內沒有訊息紀錄',
},
response_time_analysis: {
desc: '分析訊息之間的回應時間,按成員維度統計中位數和平均回覆速度。適用於「大家平均多久回覆訊息」、「誰回覆最快」。',
params: {
days: '統計最近多少天的資料',
top_n: '回傳前多少名',
},
},
keyword_frequency: {
desc: '對指定時間段的文字訊息進行分詞,統計高頻關鍵詞排行。支援中英日文分詞。適用於「大家最常說什麼」、「高頻關鍵詞是什麼」。',
params: {
days: '統計最近多少天的資料',
top_n: '回傳前多少個關鍵詞',
},
},
},
// ===== AI Agent 系統提示詞 =====
agent: {
answerWithoutTools: '請根據已取得的資訊給出回答,不要再呼叫工具。',
toolError: '錯誤: {{error}}',
currentDateIs: '目前日期是',
chatContext: {
private: '對話',
group: '群聊',
},
ownerNote: `目前使用者身份:
- 使用者在{{chatContext}}中的身份是「{{displayName}}」(platformId: {{platformId}})
- 當使用者提到「我」、「我的」時,指的就是「{{displayName}}」
- 查詢「我」的發言時,使用 sender_id 參數篩選該成員
`,
memberNotePrivate: `成員查詢策略:
- 私聊只有兩個人,可以直接取得成員清單
- 當使用者提到「對方」、「他/她」時,透過 get_members 取得另一方資訊
`,
memberNoteGroup: `成員查詢策略:
- 當使用者提到特定群成員(如「張三說過什麼」、「小明的發言」等)時,應先呼叫 get_members 取得成員清單
- 群成員有三種名稱:accountName(原始暱稱)、groupNickname(群暱稱)、aliases(使用者自訂別名)
- 透過 get_members 的 search 參數可以模糊搜尋這三種名稱
- 找到成員後,使用其 id 欄位作為 search_messages 的 sender_id 參數來取得該成員的發言
`,
mentionedMembersNote: '本輪使用者顯式 @ 的成員(可直接使用 member_id,無需再次搜尋):',
timeParamsIntro: '時間參數:使用 start_time/end_time 指定時間範圍,格式 "YYYY-MM-DD HH:mm"',
defaultYearNote: '未指定時間範圍時預設查詢全部。當前年份為{{year}}年',
dataSnapshotNote:
'目前聊天資料庫快照:{{name}}({{platform}}),總訊息 {{totalMessages}} 條,成員 {{totalMembers}} 人,時間範圍 {{firstMessageDate}} ~ {{lastMessageDate}}。該快照只用於判斷資料範圍;回答具體聊天事實仍必須呼叫工具檢索目前資料庫。',
evidencePolicy: `證據策略:
- AI 對話歷史、歷史 AI 回覆和壓縮摘要只用於理解使用者意圖,不能作為聊天紀錄事實證據。
- 只要使用者詢問聊天紀錄內容、最近聊什麼、某人說過什麼、統計排行、是否出現過某話題或要求引用原話,必須先呼叫合適的資料工具檢索目前資料庫。
- 如果已追加新聊天紀錄,目前資料庫可能不同於舊視窗歷史;優先使用 get_chat_overview 或 get_recent_messages/search_messages 取得最新證據。
- 只有工具回傳的訊息、統計或資料庫概覽可以作為事實依據;工具沒有回傳足夠證據時,明確說明資料不足,不要編造不存在的聊天紀錄。`,
responseInstruction: '根據使用者的問題,選擇合適的工具取得資料,然後基於資料給出回答。',
fallbackRoleDefinition: {
group: `你是一個專業但風格輕鬆的群聊紀錄分析助手。
你的任務是幫助使用者理解和分析他們的群聊紀錄資料,同時可以適度使用網路熱梗和表情/顏文字活躍氣氛,但不影響結論的準確性。
## 回答要求
1. 基於工具回傳的資料回答,不要編造資訊
2. 如果資料不足以回答問題,請說明
3. 回答要簡潔明瞭,使用 Markdown 格式
4. 可以適度加入網路熱梗、表情/顏文字(強度適中)
5. 玩梗不得影響事實準確與結論清晰,避免低俗或冒犯性表達`,
private: `你是一個專業但風格輕鬆的私聊紀錄分析助手。
你的任務是幫助使用者理解和分析他們的私聊紀錄資料,同時可以適度使用網路熱梗和表情/顏文字活躍氣氛,但不影響結論的準確性。
## 回答要求
1. 基於工具回傳的資料回答,不要編造資訊
2. 如果資料不足以回答問題,請說明
3. 回答要簡潔明瞭,使用 Markdown 格式
4. 可以適度加入網路熱梗、表情/顏文字(強度適中)
5. 玩梗不得影響事實準確與結論清晰,避免低俗或冒犯性表達`,
},
},
},
// ===== P3: LLM 配置 =====
llm: {
notConfigured: 'LLM 服務尚未設定,請先在設定中填入 API Key',
maxConfigs: '最多只能新增 {{count}} 組設定',
configNotFound: '找不到設定',
noActiveConfig: '沒有啟用中的設定',
callFailed: 'LLM 呼叫失敗,請檢查模型設定是否正確',
genericProviderName: 'API 服務',
rawErrorLabel: '原始錯誤',
},
// ===== P4: 摘要生成 =====
summary: {
sessionNotFound: '會話不存在或資料庫開啟失敗',
tooFewMessages: '訊息數量少於 {{count}} 條,無需產生摘要',
tooFewValidMessages: '有效訊息數量少於 {{count}} 條,無需產生摘要',
sessionNotExist: '找不到會話',
messagesTooFew: '訊息太少',
validMessagesTooFew: '有效訊息太少',
systemPromptDirect: '你是一個對話摘要專家,擅長用簡潔的語言總結對話內容。',
systemPromptMerge: '你是一個對話摘要專家,擅長將多個摘要合併成一個連貫的總結。',
},
// AI shared translations (from @openchatlab/node-runtime)
...aiLocale,
}
@@ -47,7 +47,8 @@ function createMockDb(lightRows: LightRow[], fullRows: FullMessageRow[]): Databa
if (isLightQuery) {
return lightRows as unknown as Record<string, unknown>[]
}
const limit = typeof _params[_params.length - 2] === 'number' ? (_params[_params.length - 2] as number) : fullRows.length
const limit =
typeof _params[_params.length - 2] === 'number' ? (_params[_params.length - 2] as number) : fullRows.length
const offset = typeof _params[_params.length - 1] === 'number' ? (_params[_params.length - 1] as number) : 0
return fullRows.slice(offset, offset + limit) as unknown as Record<string, unknown>[]
},
@@ -0,0 +1,57 @@
/**
* Lightweight AI translation module.
*
* Provides a platform-agnostic `TranslateFn` compatible with the shared
* prompt-builder. No i18next dependency — just nested object lookup
* with {{var}} interpolation and locale fallback.
*/
import type { TranslateFn } from '../agent/prompt-builder'
import zhCN from './locales/zh-CN'
import enUS from './locales/en-US'
import jaJP from './locales/ja-JP'
import zhTW from './locales/zh-TW'
export type { TranslateFn }
const localeMap: Record<string, Record<string, unknown>> = {
'zh-CN': zhCN,
'en-US': enUS,
'ja-JP': jaJP,
'zh-TW': zhTW,
}
function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
let current: unknown = obj
for (const segment of path.split('.')) {
if (current == null || typeof current !== 'object') return undefined
current = (current as Record<string, unknown>)[segment]
}
return current
}
function interpolate(template: string, vars: Record<string, unknown>): string {
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
const val = vars[key]
return val != null ? String(val) : ''
})
}
/**
* Create a translation function for the given locale.
* Supports `lng` option override (i18next-compatible) and {{var}} interpolation.
*/
export function createAiTranslate(defaultLocale: string = 'zh-CN'): TranslateFn {
return (key: string, options?: Record<string, unknown>): string => {
const lng = (options?.lng as string) || defaultLocale
const locale = localeMap[lng] ? lng : 'en-US'
const value = getNestedValue(localeMap[locale], key) ?? getNestedValue(localeMap['en-US'], key)
if (typeof value !== 'string') return key
if (!options) return value
return interpolate(value, options)
}
}
/** All AI locale data (for consumers like Electron that compose with their own keys) */
export const aiLocales = { 'zh-CN': zhCN, 'en-US': enUS, 'ja-JP': jaJP, 'zh-TW': zhTW }
@@ -0,0 +1,337 @@
/**
* AI shared translations — English
*/
export default {
ai: {
tools: {
search_messages: {
desc: 'Search chat records by keywords. This is the primary evidence tool for factual questions about keywords, member messages, or whether a topic appeared. Can specify time range and sender to filter messages. Supports minute-level time queries.',
params: {
keywords:
'List of search keywords, using OR logic to match messages containing any keyword. Pass an empty array [] to filter by sender only',
sender_id:
'Sender member ID, used to filter messages from a specific member. Can be obtained via the get_members tool',
limit: 'Message count limit, default 1000, max 50000',
year: 'Filter messages by year, e.g. 2024',
month: 'Filter messages by month (1-12), use with year',
day: 'Filter messages by day (1-31), use with year and month',
hour: 'Filter messages by hour (0-23), use with year, month, and day',
start_time:
'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00". Overrides year/month/day/hour when specified',
end_time:
'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30". Overrides year/month/day/hour when specified',
},
},
deep_search_messages: {
desc: 'Exact substring match search for chat records. Slower but never misses any message containing the keyword. Use when search_messages results are insufficient, when verifying whether a phrase really exists, or when searching partial words or single characters.',
params: {
keywords: 'List of search keywords, using substring match (LIKE). Returns messages matching any keyword',
sender_id: 'Sender member ID for filtering messages from a specific member',
limit: 'Message count limit, default 1000, max 50000',
year: 'Filter messages by year, e.g. 2024',
month: 'Filter messages by month (1-12), use with year',
day: 'Filter messages by day (1-31), use with year and month',
hour: 'Filter messages by hour (0-23), use with year, month, and day',
start_time: 'Start time, format "YYYY-MM-DD HH:mm". Overrides year/month/day/hour when specified',
end_time: 'End time, format "YYYY-MM-DD HH:mm". Overrides year/month/day/hour when specified',
},
},
get_recent_messages: {
desc: 'Get chat messages within a specified time period. This is the preferred evidence tool for overview questions like "what has everyone been chatting about recently", "what was discussed in month X", and latest content after new records were appended. Supports minute-level time queries.',
params: {
limit: 'Message count limit, default 100 (saves tokens, can be increased as needed)',
year: 'Filter messages by year, e.g. 2024',
month: 'Filter messages by month (1-12), use with year',
day: 'Filter messages by day (1-31), use with year and month',
hour: 'Filter messages by hour (0-23), use with year, month, and day',
start_time:
'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00". Overrides year/month/day/hour when specified',
end_time:
'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30". Overrides year/month/day/hour when specified',
},
},
get_chat_overview: {
desc: 'Get basic overview of the chat: name, platform, type, total messages, total members, time range, and top active members. Use this before analysis or after appended records to confirm the current database range.',
params: {
top_n: 'Return top N active members, default 10',
},
},
get_member_stats: {
desc: 'Get member activity statistics. Suitable for questions like "who is the most active" or "who sends the most messages".',
params: {
top_n: 'Return top N members, default 10',
},
},
get_time_stats: {
desc: 'Get time distribution statistics of chat activity. Suitable for questions like "when is the group most active" or "what time do people usually chat".',
params: {
type: 'Statistics type: hourly (by hour), weekday (by day of week), daily (by date)',
},
},
get_members: {
desc: 'Get group member list, including basic info, aliases, and message statistics. Suitable for queries like "who is in the group", "what is someone\'s alias", or "whose ID is xxx".',
params: {
search: 'Optional search keyword to filter by member nickname, alias, or platform ID',
limit: 'Member count limit, returns all by default',
},
},
get_member_name_history: {
desc: 'Get member name change history. Suitable for questions like "what was someone\'s previous name", "name changes", or "former names". Requires member ID from get_members tool first.',
params: {
member_id: 'Member database ID, can be obtained via get_members tool',
},
},
get_conversation_between: {
desc: 'Get conversation records between two group members. Suitable for questions like "what did A and B talk about" or "view the conversation between two people". Requires member IDs from get_members first. Supports minute-level time queries.',
params: {
member_id_1: 'Database ID of the first member',
member_id_2: 'Database ID of the second member',
limit: 'Message count limit, default 100',
start_time:
'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00". Overrides year/month/day/hour when specified',
end_time:
'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30". Overrides year/month/day/hour when specified',
},
},
get_message_context: {
desc: 'Get surrounding context messages for a given message ID. Use it to verify facts around specific quoted messages, such as what was discussed before and after a message or whether a phrase has context. Supports single or batch message IDs.',
params: {
message_ids:
'List of message IDs to query context for. Can be single or multiple IDs. Message IDs can be obtained from search_messages and other tool results',
context_size: 'Context size, i.e. how many messages before and after to retrieve, default 20',
},
},
search_sessions: {
desc: 'Search chat sessions (conversation segments). Sessions are conversation units automatically split by message time intervals. Suitable for finding discussions on specific topics or understanding how many conversations occurred in a time period. Returns matching sessions with a 5-message preview each.',
params: {
keywords: 'Optional keyword list, only returns sessions containing these keywords (OR logic)',
limit: 'Session count limit, default 20',
year: 'Filter sessions by year, e.g. 2024',
month: 'Filter sessions by month (1-12), use with year',
day: 'Filter sessions by day (1-31), use with year and month',
start_time: 'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00"',
end_time: 'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30"',
},
},
get_session_messages: {
desc: 'Get the complete message list for a specific session. Used to get full context after finding a relevant session via search_sessions. Returns all messages and participant information.',
params: {
session_id: 'Session ID, can be obtained from search_sessions results',
limit: 'Message count limit, default 1000. Can be limited for very long sessions to save tokens',
},
},
get_session_summaries: {
desc: `Get session summary list to quickly understand discussion topics in chat history.
Use cases:
1. Understand what topics have been discussed recently
2. Search for discussed topics by keyword
3. Overview questions like "has the group discussed travel"
Returned summaries are brief descriptions of each session, helping quickly locate sessions of interest. Use get_session_messages for details.`,
params: {
keywords: 'Keyword list to search within summaries (OR logic)',
limit: 'Session count limit, default 20',
year: 'Filter sessions by year',
month: 'Filter sessions by month (1-12)',
day: 'Filter sessions by day (1-31)',
start_time: 'Start time, format "YYYY-MM-DD HH:mm"',
end_time: 'End time, format "YYYY-MM-DD HH:mm"',
},
},
// ===== SQL Analysis Tools =====
message_type_breakdown: {
desc: 'Break down message types over the last N days (text, image, voice, emoji, etc.). Useful for understanding communication preferences.',
params: { days: 'Number of recent days to analyze' },
rowTemplate: '{type_name}: {msg_count} messages ({percentage}%)',
summaryTemplate: 'Message type distribution ({rowCount} types):',
fallback: 'No messages found in this time range',
},
peak_chat_hours_by_member: {
desc: "Analyze a specific member's hourly message distribution over the last N days to find their most active hours. Requires member_id from get_members.",
params: {
member_id: 'Member ID (from get_members)',
days: 'Number of recent days to analyze',
},
rowTemplate: '{hour}:00 — {msg_count} messages',
summaryTemplate: 'Message volume by hour ({rowCount} active hours):',
fallback: 'This member has no messages in the specified time range',
},
member_activity_trend: {
desc: "View a specific member's daily message count trend over the last N days. Useful for observing whether someone is becoming more or less active. Requires member_id from get_members.",
params: {
member_id: 'Member ID (from get_members)',
days: 'Number of recent days to view',
},
rowTemplate: '{day}: {msg_count} messages',
summaryTemplate: 'This member was active on {rowCount} days:',
fallback: 'This member has no messages in the specified time range',
},
silent_members: {
desc: 'Detect "silent members" who haven\'t sent messages for more than N days. Useful for identifying at-risk users in community management.',
params: { days: 'Days of silence to qualify' },
rowTemplate: '{name} — silent for {silent_days} days',
summaryTemplate: 'Found {rowCount} silent members:',
fallback: 'No members found who have been silent for that long. Community engagement is healthy!',
},
reply_interaction_ranking: {
desc: 'Analyze reply interaction rankings in the group — who replies to whom the most. Useful for discovering core interaction relationships and key opinion leaders.',
params: {
days: 'Number of recent days to analyze',
limit: 'Number of top interaction pairs to return',
},
rowTemplate: '{replier_name} → {original_name}: {reply_count} replies',
summaryTemplate: 'Top {rowCount} reply interactions:',
fallback: 'No reply interactions found in this time range',
},
mutual_interaction_pairs: {
desc: 'Find the most frequently interacting member pairs, based on bidirectional message timing (if one person speaks and another responds within 5 minutes, it counts as an interaction). Useful for discovering close friendships.',
params: {
days: 'Number of recent days to analyze',
limit: 'Number of top pairs to return',
},
rowTemplate: '{member_a} ↔ {member_b}: {interaction_count} interactions',
summaryTemplate: 'Top {rowCount} most interactive pairs:',
fallback: 'No significant interaction patterns detected in this time range',
},
member_message_length_stats: {
desc: 'Analyze average message length per member (text messages only). Longer messages often indicate more thoughtful communication. Useful for finding deep communicators.',
params: {
days: 'Number of recent days to analyze',
top_n: 'Number of top members to return',
},
rowTemplate: '{name} — avg {avg_length} chars/msg ({msg_count} msgs, max {max_length} chars)',
summaryTemplate: 'Message length Top {rowCount} (longer = more thoughtful):',
fallback: 'Not enough text message data in this time range',
},
unanswered_messages: {
desc: 'Find messages in the last N days that may not have been replied to — potential unresolved customer issues. Only counts text messages over 10 characters (filters out short greetings).',
params: {
days: 'Number of recent days to search',
limit: 'Maximum number of results',
},
rowTemplate: '[{send_time}] {sender_name}: {content_preview}',
summaryTemplate: 'Found {rowCount} potentially unanswered messages:',
fallback: 'All messages have been replied to in this time range. Great service quality!',
},
daily_active_members: {
desc: 'Count daily unique active members (DAU) and message volume to observe community vitality trends. Useful for "how is the group activity trending" or "how many people are chatting recently".',
params: { days: 'Number of recent days to analyze' },
rowTemplate: '{day}: {active_members} active, {msg_count} messages',
summaryTemplate: 'Daily active members trend for {rowCount} days:',
fallback: 'No messages in this time range',
},
conversation_initiator_stats: {
desc: 'Count how many times each member initiated a conversation (was the first sender in a session). Requires session index to be generated.',
params: {
days: 'Number of recent days to analyze',
limit: 'Number of top members to return',
},
rowTemplate: '{name}: initiated {initiated_count} topics',
summaryTemplate: 'Topic initiator Top {rowCount}:',
fallback: 'No session records in this time range. Session index may need to be generated first.',
},
activity_heatmap: {
desc: 'Return a weekday × hour message count matrix for generating activity heatmaps. weekday: 0=Sun, 1=Mon, ..., 6=Sat.',
params: { days: 'Number of recent days to analyze' },
rowTemplate: 'Weekday {weekday} {hour}:00 — {msg_count} messages',
summaryTemplate: 'Activity heatmap data ({rowCount} time slots with messages):',
fallback: 'No messages in this time range',
},
response_time_analysis: {
desc: 'Analyze response times between messages, showing median and average reply speed per member. Useful for "how quickly do people reply" or "who replies the fastest".',
params: {
days: 'Number of recent days to analyze',
top_n: 'Number of top members to return',
},
},
keyword_frequency: {
desc: 'Segment text messages and rank high-frequency keywords. Supports Chinese, English, and Japanese. Useful for "what do people talk about most" or "what are the hot keywords".',
params: {
days: 'Number of recent days to analyze',
top_n: 'Number of top keywords to return',
},
},
},
// ===== AI Agent system prompts =====
agent: {
answerWithoutTools: 'Please answer based on the information already retrieved, do not call any more tools.',
toolError: 'Error: {{error}}',
currentDateIs: 'Current date is',
chatContext: {
private: 'conversation',
group: 'group chat',
},
ownerNote: `Current user identity:
- The user's identity in this {{chatContext}} is "{{displayName}}" (platformId: {{platformId}})
- When the user refers to "I" or "my", it refers to "{{displayName}}"
- When querying "my" messages, use the sender_id parameter to filter for this member
`,
memberNotePrivate: `Member query strategy:
- Private chats only have two participants, so the member list can be directly obtained
- When the user refers to "the other party" or "he/she", get the other participant's information via get_members
`,
memberNoteGroup: `Member query strategy:
- When the user refers to specific group members (e.g., "what did John say", "Mary's messages"), first call get_members to get the member list
- Group members have three names: accountName (original nickname), groupNickname (group nickname), aliases (user-defined aliases)
- The search parameter of get_members can be used for fuzzy searching these three names
- Once a member is found, use their id field as the sender_id parameter for search_messages to retrieve their messages
`,
mentionedMembersNote:
'Members explicitly @-selected by the user in this round (member_id can be used directly without another search):',
timeParamsIntro: 'Time parameters: use start_time/end_time to specify the range, format "YYYY-MM-DD HH:mm"',
defaultYearNote: 'When no time range is specified, queries default to all data. Current year is {{year}}.',
dataSnapshotNote:
'Current chat database snapshot: {{name}} ({{platform}}), {{totalMessages}} total messages, {{totalMembers}} members, time range {{firstMessageDate}} ~ {{lastMessageDate}}. This snapshot only helps judge data coverage; concrete chat facts still require tool retrieval from the current database.',
evidencePolicy: `Evidence policy:
- AI conversation history, prior AI replies, and compressed summaries are only for understanding the user's intent; they are not evidence for chat-record facts.
- Whenever the user asks about chat content, recent topics, what someone said, rankings/statistics, whether a topic appeared, or asks for exact quotes, first call an appropriate data tool to retrieve the current database.
- If new chat records were appended, the current database may differ from old window history; prefer get_chat_overview or get_recent_messages/search_messages to get fresh evidence.
- Only messages, statistics, or database overviews returned by tools may be used as factual basis. If tools do not return enough evidence, say the data is insufficient and do not fabricate nonexistent chat records.`,
currentTask: 'Current Task',
skillPriorityNote:
'Note: When executing this task, prioritize the output format requirements below. This can override your usual response style.',
responseInstruction:
"Based on the user's question, select appropriate tools to retrieve data, then provide an answer based on the data.",
fallbackRoleDefinition: {
group: `You are a professional group chat analysis assistant.
Your task is to help users understand and analyze their group chat data.
## Response Requirements
1. Answer based on data returned by tools, do not fabricate information
2. If data is insufficient to answer, please state so
3. Keep answers concise and clear, use Markdown format`,
private: `You are a professional private chat analysis assistant.
Your task is to help users understand and analyze their private chat data.
## Response Requirements
1. Answer based on data returned by tools, do not fabricate information
2. If data is insufficient to answer, please state so
3. Keep answers concise and clear, use Markdown format`,
},
},
},
llm: {
notConfigured: 'LLM service not configured. Please set up an API Key in settings first.',
maxConfigs: 'Maximum of {{count}} configurations allowed',
configNotFound: 'Configuration not found',
noActiveConfig: 'No active configuration',
callFailed: 'LLM call failed. Please check your model configuration.',
genericProviderName: 'API provider',
rawErrorLabel: 'Raw error',
},
summary: {
sessionNotFound: 'Session not found or database could not be opened',
tooFewMessages: 'Message count less than {{count}}, no need to generate summary',
tooFewValidMessages: 'Valid message count less than {{count}}, no need to generate summary',
sessionNotExist: 'Session not found',
messagesTooFew: 'Too few messages',
validMessagesTooFew: 'Too few valid messages',
systemPromptDirect: 'You are a conversation summarization expert. Summarize conversations concisely.',
systemPromptMerge:
'You are a conversation summarization expert skilled at merging multiple summaries into a coherent overview.',
},
}
@@ -0,0 +1,335 @@
/**
* AI shared translations — Japanese
*/
export default {
ai: {
tools: {
search_messages: {
desc: 'キーワードでチャット履歴を検索する。キーワード、メンバーの発言、特定トピックが出たかどうかなどの事実質問に対する主要な証拠取得ツール。時間範囲や送信者でメッセージをフィルタリングできる。分単位の精度で時間クエリをサポートする。',
params: {
keywords:
'検索キーワードリスト。OR ロジックでいずれかのキーワードを含むメッセージにマッチする。送信者のみでフィルタリングする場合は空配列 [] を渡す',
sender_id:
'送信者のメンバー ID。特定メンバーの送信メッセージをフィルタリングする。get_members ツールでメンバー ID を取得できる',
limit: '返却メッセージ数の上限。デフォルト 1000、最大 50000',
year: '指定年のメッセージをフィルタリング(例:2024)',
month: '指定月のメッセージをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のメッセージをフィルタリング(1-31)。year と month と併用する必要がある',
hour: '指定時間のメッセージをフィルタリング(0-23)。year、month、day と併用する必要がある',
start_time:
'開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")。指定すると year/month/day/hour パラメータを上書きする',
end_time:
'終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")。指定すると year/month/day/hour パラメータを上書きする',
},
},
deep_search_messages: {
desc: '完全部分文字列マッチでチャット履歴を検索する。速度は遅いが、キーワードを含むメッセージを漏らさない。search_messages の結果が不十分な場合、ある文言が実在するか確認する場合、または部分的な単語・単一文字を検索する場合に使用する。',
params: {
keywords:
'検索キーワードリスト。部分文字列マッチ(LIKE)を使用し、いずれかのキーワードにマッチしたメッセージを返す',
sender_id: '送信者のメンバー ID。特定メンバーの送信メッセージをフィルタリングする',
limit: '返却メッセージ数の上限。デフォルト 1000、最大 50000',
year: '指定年のメッセージをフィルタリング(例:2024)',
month: '指定月のメッセージをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のメッセージをフィルタリング(1-31)。year と month と併用する必要がある',
hour: '指定時間のメッセージをフィルタリング(0-23)。year、month、day と併用する必要がある',
start_time: '開始時刻。形式 "YYYY-MM-DD HH:mm"。指定すると year/month/day/hour パラメータを上書きする',
end_time: '終了時刻。形式 "YYYY-MM-DD HH:mm"。指定すると year/month/day/hour パラメータを上書きする',
},
},
get_recent_messages: {
desc: '指定期間内のチャットメッセージを取得する。「最近みんな何を話していた?」「X月に何が話題だった?」、新しい記録追加後の最新内容などの概要質問に対する優先証拠ツール。分単位の精度で時間クエリをサポートする。',
params: {
limit: '返却メッセージ数の上限。デフォルト 100(Token を節約したい場合の目安。必要に応じて増やせる)',
year: '指定年のメッセージをフィルタリング(例:2024)',
month: '指定月のメッセージをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のメッセージをフィルタリング(1-31)。year と month と併用する必要がある',
hour: '指定時間のメッセージをフィルタリング(0-23)。year、month、day と併用する必要がある',
start_time:
'開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")。指定すると year/month/day/hour パラメータを上書きする',
end_time:
'終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")。指定すると year/month/day/hour パラメータを上書きする',
},
},
get_chat_overview: {
desc: 'チャット記録の基本概要を取得する:グループ名、プラットフォーム、タイプ、総メッセージ数、総メンバー数、期間、最もアクティブなメンバーランキング。分析前や新しい記録追加後に、現在のデータベース範囲を確認するのに適している。',
params: {
top_n: '上位 N 名のアクティブメンバーを返却。デフォルト 10',
},
},
get_member_stats: {
desc: 'グループメンバーのアクティビティ統計データを取得する。「最もアクティブなのは誰?」「発言数が一番多いのは?」などの質問に適している。',
params: {
top_n: '上位 N 名のメンバーを返却。デフォルト 10',
},
},
get_time_stats: {
desc: 'グループチャットの時間分布統計を取得する。「いつが一番アクティブ?」「みんな何時にチャットしている?」などの質問に適している。',
params: {
type: '統計タイプ:hourly(時間別)、weekday(曜日別)、daily(日別)',
},
},
get_members: {
desc: 'グループメンバー一覧を取得する。メンバーの基本情報、別名、メッセージ統計を含む。「グループに誰がいる?」「○○の別名は?」「QQ 番号が xxx の人は?」などの質問に向いている。',
params: {
search: '任意の検索キーワード。メンバーのニックネーム、別名、QQ 番号で絞り込む',
limit: '返却メンバー数の上限。デフォルトは全件返却',
},
},
get_member_name_history: {
desc: 'メンバーのニックネーム変更履歴を取得する。「○○の以前の名前は?」「○○のニックネームの変遷」「○○の旧名」などの質問に適している。事前に get_members ツールでメンバー ID を取得する必要がある。',
params: {
member_id: 'メンバーのデータベース ID。get_members ツールで取得できる',
},
},
get_conversation_between: {
desc: '2 人のグループメンバー間の会話履歴を取得する。「A と B は何を話していた?」「2 人のやり取りを見たい」などの質問に向いている。事前に get_members でメンバー ID を取得する必要がある。分単位の時間指定にも対応する。',
params: {
member_id_1: '1人目のメンバーのデータベース ID',
member_id_2: '2人目のメンバーのデータベース ID',
limit: '返却メッセージ数の上限。デフォルト 100',
start_time:
'開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")。指定すると year/month/day/hour パラメータを上書きする',
end_time:
'終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")。指定すると year/month/day/hour パラメータを上書きする',
},
},
get_message_context: {
desc: 'メッセージ ID に基づいて前後のコンテキストメッセージを取得する。具体的な引用メッセージ周辺の事実確認、例えば「このメッセージの前後で何を話していた?」「この文言には文脈があるか」を確認する場合に使用する。単一または複数のメッセージ ID をサポートする。',
params: {
message_ids:
'コンテキストを取得するメッセージ ID リスト。単一 ID または複数 ID が可能。メッセージ ID は search_messages などのツールの返却結果から取得できる',
context_size: 'コンテキストサイズ。前後それぞれ何件のメッセージを取得するか。デフォルト 20',
},
},
search_sessions: {
desc: 'チャットセッション(会話セグメント)を検索する。セッションはメッセージの時間間隔に基づいて自動分割された会話単位である。特定トピックの議論を見つけたり、ある期間内の会話回数を把握するのに適している。マッチしたセッションリストと各セッションの最初の5件のメッセージプレビューを返却する。',
params: {
keywords: '任意の検索キーワードリスト。これらのキーワードを含むセッションのみ返却する(OR ロジックマッチ)',
limit: '返却セッション数の上限。デフォルト 20',
year: '指定年のセッションをフィルタリング(例:2024)',
month: '指定月のセッションをフィルタリング(1-12)。year と併用する必要がある',
day: '指定日のセッションをフィルタリング(1-31)。year と month と併用する必要がある',
start_time: '開始時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 14:00")',
end_time: '終了時刻。形式 "YYYY-MM-DD HH:mm"(例:"2024-03-15 18:30")',
},
},
get_session_messages: {
desc: '指定セッションの完全なメッセージリストを取得する。search_sessions で関連セッションを見つけた後、そのセッションの完全なコンテキストを取得するために使用する。セッションの全メッセージと参加者情報を返却する。',
params: {
session_id: 'セッション ID。search_sessions の返却結果から取得できる',
limit: '返却メッセージ数の上限。デフォルト 1000。非常に長いセッションでは Token 節約のため件数を制限できる',
},
},
get_session_summaries: {
desc: `セッション要約リストを取得し、グループチャットの過去の議論トピックをすばやく把握する。
適用シーン:
1. グループで最近何が話題になっていたか知りたい
2. キーワードで過去に議論されたトピックを検索
3. 「グループで旅行について話したことある?」などの概要的な質問
返却される要約は各セッションの短い概要であり、興味のあるセッションをすばやく特定し、get_session_messages で詳細を取得できる。`,
params: {
keywords: '要約内で検索するキーワードリスト(OR ロジックマッチ)',
limit: '返却セッション数の上限。デフォルト 20',
year: '指定年のセッションをフィルタリング',
month: '指定月のセッションをフィルタリング(1-12)',
day: '指定日のセッションをフィルタリング(1-31)',
start_time: '開始時刻。形式 "YYYY-MM-DD HH:mm"',
end_time: '終了時刻。形式 "YYYY-MM-DD HH:mm"',
},
},
message_type_breakdown: {
desc: 'メッセージタイプ別に直近 N 日間のメッセージ分布を集計する(テキスト、画像、音声、スタンプなどの件数)。コミュニケーション方法の傾向を把握するのに適している。',
params: { days: '直近何日間のデータを集計するか' },
rowTemplate: '{type_name}:{msg_count} 件({percentage}%)',
summaryTemplate: 'メッセージタイプ分布(全 {rowCount} 種類):',
fallback: 'この期間にメッセージ記録がありません',
},
peak_chat_hours_by_member: {
desc: '指定メンバーの直近 N 日間の時間帯別発言数分布を分析し、最もアクティブな時間帯を特定する。事前に get_members で member_id を取得する必要がある。',
params: {
member_id: 'メンバー ID(get_members で取得)',
days: '直近何日間のデータを集計するか',
},
rowTemplate: '{hour}:00 — {msg_count} 件のメッセージ',
summaryTemplate: '該当メンバーの時間帯別発言数(全 {rowCount} アクティブ時間帯):',
fallback: '指定期間内に該当メンバーの発言記録がありません',
},
member_activity_trend: {
desc: '指定メンバーの直近 N 日間の日別発言数の変化トレンドを表示する。ある人物がよりアクティブになったか、より静かになったかを観察するのに適している。事前に get_members で member_id を取得する必要がある。',
params: {
member_id: 'メンバー ID(get_members で取得)',
days: '直近何日間のトレンドを表示するか',
},
rowTemplate: '{day}:{msg_count} 件',
summaryTemplate: '該当メンバーの直近 {rowCount} 日間の発言記録:',
fallback: '指定期間内に該当メンバーの発言記録がありません',
},
silent_members: {
desc: 'N 日以上発言していない「休眠メンバー」を検出する。コミュニティ運営で離脱リスクのある利用者を見つけるのに向いている。',
params: { days: '何日間未発言でサイレントとみなすか' },
rowTemplate: '{name} — {silent_days} 日間サイレント',
summaryTemplate: '全 {rowCount} 名の休眠メンバーを検出:',
fallback: '指定日数を超えて未発言のメンバーは見つかりませんでした。コミュニティのアクティビティは良好です!',
},
reply_interaction_ranking: {
desc: 'グループ内の返信インタラクションランキングを分析し、誰が誰に最も多く返信しているかを特定する。コミュニティのコアインタラクション関係やオピニオンリーダーの発見に適している。',
params: {
days: '直近何日間のデータを集計するか',
limit: '上位何組のインタラクション関係を返却するか',
},
rowTemplate: '{replier_name} → {original_name}:{reply_count} 回返信',
summaryTemplate: '返信インタラクション Top {rowCount}:',
fallback: 'この期間に返信インタラクション記録がありません',
},
mutual_interaction_pairs: {
desc: '最も頻繁にインタラクションするメンバーペアを特定する。双方向のメッセージ時間近接度に基づく(一方の発言後5分以内にもう一方も発言した場合を1回のインタラクションとみなす)。親密な友人の組み合わせの発見に適している。',
params: {
days: '直近何日間のデータを集計するか',
limit: '上位何組を返却するか',
},
rowTemplate: '{member_a} ↔ {member_b}:{interaction_count} 回のインタラクション',
summaryTemplate: '最も頻繁にインタラクションする {rowCount} 組のペア:',
fallback: 'この期間に明らかなインタラクション関係は検出されませんでした',
},
member_message_length_stats: {
desc: '各メンバーの平均メッセージ長(テキストメッセージのみ)を集計する。長いメッセージは通常、より丁寧なコミュニケーションを意味する。深い交流を行う人物の発見に適している。',
params: {
days: '直近何日間のデータを集計するか',
top_n: '上位何名を返却するか',
},
rowTemplate: '{name} — 平均 {avg_length} 字/件(全 {msg_count} 件、最長 {max_length} 字)',
summaryTemplate: 'メッセージ長 Top {rowCount}(長い = より丁寧):',
fallback: 'この期間に十分なテキストメッセージデータがありません',
},
unanswered_messages: {
desc: '直近 N 日間で返信されていないメッセージを検索する。未解決の問題である可能性がある。テキストメッセージかつ10文字以上のもののみ集計する(短い挨拶を除外)。',
params: {
days: '直近何日間のデータを検索するか',
limit: '最大何件返却するか',
},
rowTemplate: '[{send_time}] {sender_name}:{content_preview}',
summaryTemplate: '全 {rowCount} 件の返信されていない可能性のあるメッセージ:',
fallback: 'この期間のすべてのメッセージに返信がありました。対応品質は良好です!',
},
daily_active_members: {
desc: '日ごとのユニーク発言者数(DAU)とメッセージ数を集計し、グループの活性度の推移を観察する。「最近グループはどのくらい活発か」「何人が発言しているか」に適している。',
params: { days: '直近何日間のデータを集計するか' },
rowTemplate: '{day}:{active_members} 人アクティブ、{msg_count} 件メッセージ',
summaryTemplate: '直近 {rowCount} 日間の日別アクティブ人数推移:',
fallback: 'この期間にメッセージの記録がありません',
},
conversation_initiator_stats: {
desc: '各メンバーが会話を開始した回数(セッションの最初の発言者)を集計し、誰が最も話題を切り出すかを発見する。セッションインデックスの生成が必要。',
params: {
days: '直近何日間のデータを集計するか',
limit: '上位何名を返却するか',
},
rowTemplate: '{name}:{initiated_count} 回話題を開始',
summaryTemplate: '話題開始者 Top {rowCount}:',
fallback: 'この期間にセッション記録がありません。先にセッションインデックスを生成する必要があるかもしれません',
},
activity_heatmap: {
desc: '曜日×時間帯のメッセージ数マトリックスを返却する。活性度ヒートマップの生成に適している。weekday: 0=日曜, 1=月曜, ..., 6=土曜。',
params: { days: '直近何日間のデータを集計するか' },
rowTemplate: '曜日{weekday} {hour}:00 — {msg_count} 件',
summaryTemplate: '活性度ヒートマップデータ(全 {rowCount} 時間帯にメッセージあり):',
fallback: 'この期間にメッセージの記録がありません',
},
response_time_analysis: {
desc: 'メッセージ間の応答時間を分析し、メンバーごとの中央値と平均返信速度を集計する。「みんなどのくらいで返信するか」「誰が最も速く返信するか」に適している。',
params: {
days: '直近何日間のデータを集計するか',
top_n: '上位何名を返却するか',
},
},
keyword_frequency: {
desc: '指定期間のテキストメッセージを分詞し、高頻度キーワードをランキングする。中国語・英語・日本語の分詞に対応。「みんなが最もよく話す話題は何か」「高頻度キーワードは何か」に適している。',
params: {
days: '直近何日間のデータを集計するか',
top_n: '上位何個のキーワードを返却するか',
},
},
},
agent: {
answerWithoutTools: '取得済みの情報に基づいて回答してください。これ以上ツールを呼び出さないでください。',
toolError: 'エラー: {{error}}',
currentDateIs: '現在の日付は',
chatContext: {
private: '会話',
group: 'グループチャット',
},
ownerNote: `現在のユーザー情報:
- ユーザーの{{chatContext}}における立場は「{{displayName}}」(platformId: {{platformId}})
- ユーザーが「私」「自分の」と言った場合、「{{displayName}}」を指す
- 「私」の発言を検索する際は、sender_id パラメータで該当メンバーをフィルタリングする
`,
memberNotePrivate: `メンバー検索戦略:
- 個人チャットは2人だけなので、直接メンバー一覧を取得できる
- ユーザーが「相手」「彼/彼女」と言った場合、get_members でもう一方の情報を取得する
`,
memberNoteGroup: `メンバー検索戦略:
- ユーザーが特定のグループメンバーに言及した場合(例:「田中さんは何を言った?」「太郎の発言」など)、まず get_members でメンバー一覧を取得する
- グループメンバーには3種類の名前がある:accountName(元のニックネーム)、groupNickname(グループニックネーム)、aliases(ユーザー定義の別名)
- get_members の search パラメータでこれら3種類の名前をあいまい検索できる
- メンバーを見つけたら、その id フィールドを search_messages の sender_id パラメータとして使用して発言を取得する
`,
mentionedMembersNote:
'このラウンドでユーザーが明示的に @ 選択したメンバー(member_id を再検索なしで直接使えます):',
timeParamsIntro: '時間パラメータ:start_time/end_time で範囲を指定。形式は "YYYY-MM-DD HH:mm"',
defaultYearNote: '時間範囲を指定しない場合は全期間が対象。現在の年は{{year}}年',
dataSnapshotNote:
'現在のチャットデータベースのスナップショット:{{name}}({{platform}})、総メッセージ {{totalMessages}} 件、メンバー {{totalMembers}} 人、期間 {{firstMessageDate}} ~ {{lastMessageDate}}。このスナップショットはデータ範囲の判断にのみ使い、具体的なチャット事実の回答には必ず現在のデータベースをツールで検索する。',
evidencePolicy: `証拠ポリシー:
- AI 会話履歴、過去の AI 回答、圧縮要約はユーザー意図の理解にのみ使用し、チャット記録の事実証拠として扱わない。
- ユーザーがチャット内容、最近の話題、誰かの発言、ランキング/統計、ある話題が出たかどうか、または原文引用を求めた場合は、必ず先に適切なデータツールで現在のデータベースを検索する。
- 新しいチャット記録が追加されている場合、現在のデータベースは古いウィンドウ履歴と異なる可能性がある。最新の証拠取得には get_chat_overview または get_recent_messages/search_messages を優先する。
- 事実根拠として使えるのは、ツールが返したメッセージ、統計、またはデータベース概要のみ。ツールが十分な証拠を返さない場合は、データ不足と明示し、存在しないチャット記録を作らない。`,
responseInstruction: 'ユーザーの質問に応じて適切なツールを選択してデータを取得し、データに基づいて回答する。',
fallbackRoleDefinition: {
group: `あなたはプロフェッショナルだがカジュアルなスタイルのグループチャット履歴分析アシスタントです。
ユーザーのグループチャット履歴データの理解と分析を支援し、適度にネットスラングや顔文字を使って雰囲気を和らげますが、結論の正確性に影響しないようにします。
## 回答要件
1. ツールから返却されたデータに基づいて回答し、情報を捏造しない
2. データが不十分で質問に答えられない場合は、その旨を説明する
3. 回答は簡潔明瞭に、Markdown 形式を使用する
4. 適度にネットスラングや顔文字を加えてよい(強度は控えめに)
5. ネタは事実の正確さと結論の明確さに影響を与えてはならず、低俗または不快な表現は避ける`,
private: `あなたはプロフェッショナルだがカジュアルなスタイルの個人チャット履歴分析アシスタントです。
ユーザーの個人チャット履歴データの理解と分析を支援し、適度にネットスラングや顔文字を使って雰囲気を和らげますが、結論の正確性に影響しないようにします。
## 回答要件
1. ツールから返却されたデータに基づいて回答し、情報を捏造しない
2. データが不十分で質問に答えられない場合は、その旨を説明する
3. 回答は簡潔明瞭に、Markdown 形式を使用する
4. 適度にネットスラングや顔文字を加えてよい(強度は控えめに)
5. ネタは事実の正確さと結論の明確さに影響を与えてはならず、低俗または不快な表現は避ける`,
},
},
},
llm: {
notConfigured: 'LLM サービスが未設定です。先に設定で API Key を設定してください',
maxConfigs: '設定は最大 {{count}} 個まで追加できます',
configNotFound: '設定が存在しません',
noActiveConfig: 'アクティブな設定がありません',
callFailed: 'LLM 呼び出しに失敗しました。モデル設定を確認してください。',
genericProviderName: 'API プロバイダー',
rawErrorLabel: '元のエラー',
},
summary: {
sessionNotFound: 'セッションが存在しないか、データベースを開けませんでした',
tooFewMessages: 'メッセージ数が{{count}}件未満のため、要約の生成は不要です',
tooFewValidMessages: '有効なメッセージ数が{{count}}件未満のため、要約の生成は不要です',
sessionNotExist: 'セッションが存在しません',
messagesTooFew: 'メッセージが少なすぎます',
validMessagesTooFew: '有効なメッセージが少なすぎます',
systemPromptDirect: 'あなたは会話要約の専門家であり、簡潔な言葉で会話内容を要約することに長けている。',
systemPromptMerge: 'あなたは会話要約の専門家であり、複数の要約を一つのまとまった概要に統合することに長けている。',
},
}
@@ -0,0 +1,327 @@
/**
* AI shared translations — Simplified Chinese
*/
export default {
ai: {
tools: {
search_messages: {
desc: '根据关键词搜索聊天记录,是回答关键词、成员发言、是否出现过某话题等事实问题的主要证据工具。可以指定时间范围和发送者来筛选消息。支持精确到分钟级别的时间查询。',
params: {
keywords: '搜索关键词列表,会用 OR 逻辑匹配包含任一关键词的消息。如果只需要按发送者筛选,可以传空数组 []',
sender_id: '发送者的成员 ID,用于筛选特定成员发送的消息。可以通过 get_members 工具获取成员 ID',
limit: '返回消息数量限制,默认 1000,最大 50000',
year: '指定年份筛选消息,如 2024',
month: '指定月份筛选消息(1-12),需配合 year 使用',
day: '指定日期筛选消息(1-31),需配合 year 和 month 使用',
hour: '指定小时筛选消息(0-23),需配合 year、month、day 使用',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定后覆盖 year/month/day/hour',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定后覆盖 year/month/day/hour',
},
},
deep_search_messages: {
desc: '精确子串匹配搜索聊天记录,速度较慢但不会遗漏任何包含关键词的消息。当 search_messages 结果不足、需要验证某段话是否真实存在、或搜索部分词/单个字符时使用。',
params: {
keywords: '搜索关键词列表,使用子串匹配(LIKE),任一关键词匹配即返回',
sender_id: '发送者的成员 ID,用于筛选特定成员发送的消息',
limit: '返回消息数量限制,默认 1000,最大 50000',
year: '指定年份筛选消息,如 2024',
month: '指定月份筛选消息(1-12),需配合 year 使用',
day: '指定日期筛选消息(1-31),需配合 year 和 month 使用',
hour: '指定小时筛选消息(0-23),需配合 year、month、day 使用',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定后覆盖 year/month/day/hour',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定后覆盖 year/month/day/hour',
},
},
get_recent_messages: {
desc: '获取指定时间段内的聊天消息,是回答"最近大家聊了什么"、"X月聊了什么"、追加新记录后最新内容等概览性问题的首选证据工具。支持精确到分钟级别的时间查询。',
params: {
limit: '返回消息数量限制,默认 100(节省 token,可根据需要增加)',
year: '指定年份筛选消息,如 2024',
month: '指定月份筛选消息(1-12),需配合 year 使用',
day: '指定日期筛选消息(1-31),需配合 year 和 month 使用',
hour: '指定小时筛选消息(0-23),需配合 year、month、day 使用',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定后覆盖 year/month/day/hour',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定后覆盖 year/month/day/hour',
},
},
get_chat_overview: {
desc: '获取聊天记录的基本概览信息,包括群名/平台/类型/总消息数/总成员数/时间跨度/最活跃成员排名。适合在分析前或追加新记录后确认当前数据库范围。',
params: {
top_n: '返回前 N 名活跃成员,默认 10',
},
},
get_member_stats: {
desc: '获取群成员的活跃度统计数据。适用于回答"谁最活跃"、"发言最多的是谁"等问题。',
params: {
top_n: '返回前 N 名成员,默认 10',
},
},
get_time_stats: {
desc: '获取群聊的时间分布统计。适用于回答"什么时候最活跃"、"大家一般几点聊天"等问题。',
params: {
type: '统计类型:hourly(按小时)、weekday(按星期)、daily(按日期)',
},
},
get_members: {
desc: '获取群成员列表,包括成员的基本信息、别名和消息统计。适用于查询"群里有哪些人"、"某人的别名是什么"、"谁的QQ号是xxx"等问题。',
params: {
search: '可选的搜索关键词,用于筛选成员昵称、别名或QQ号',
limit: '返回成员数量限制,默认返回全部',
},
},
get_member_name_history: {
desc: '获取成员的昵称变更历史记录。适用于回答"某人以前叫什么名字"、"某人的昵称变化"、"某人曾用名"等问题。需要先通过 get_members 工具获取成员 ID。',
params: {
member_id: '成员的数据库 ID,可以通过 get_members 工具获取',
},
},
get_conversation_between: {
desc: '获取两个群成员之间的对话记录。适用于回答"A和B之间聊了什么"、"查看两人的对话"等问题。需要先通过 get_members 获取成员 ID。支持精确到分钟级别的时间查询。',
params: {
member_id_1: '第一个成员的数据库 ID',
member_id_2: '第二个成员的数据库 ID',
limit: '返回消息数量限制,默认 100',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定后覆盖 year/month/day/hour',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定后覆盖 year/month/day/hour',
},
},
get_message_context: {
desc: '根据消息 ID 获取前后的上下文消息。适用于引用具体消息前后进行事实验证,比如"这条消息前后在聊什么"、"确认这段话是否有上下文"等。支持单个或批量消息 ID。',
params: {
message_ids:
'要查询上下文的消息 ID 列表,可以是单个 ID 或多个 ID。消息 ID 可以从 search_messages 等工具的返回结果中获取',
context_size: '上下文大小,即获取前后各多少条消息,默认 20',
},
},
search_sessions: {
desc: '搜索聊天会话(对话段落)。会话是根据消息时间间隔自动切分的对话单元。适用于查找特定话题的讨论、了解某个时间段内发生了几次对话等场景。返回匹配的会话列表及每个会话的前5条消息预览。',
params: {
keywords: '可选的搜索关键词列表,只返回包含这些关键词的会话(OR 逻辑匹配)',
limit: '返回会话数量限制,默认 20',
year: '指定年份筛选会话,如 2024',
month: '指定月份筛选会话(1-12),需配合 year 使用',
day: '指定日期筛选会话(1-31),需配合 year 和 month 使用',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
get_session_messages: {
desc: '获取指定会话的完整消息列表。用于在 search_sessions 找到相关会话后,获取该会话的完整上下文。返回会话的所有消息及参与者信息。',
params: {
session_id: '会话 ID,可以从 search_sessions 的返回结果中获取',
limit: '返回消息数量限制,默认 1000。对于超长会话可以限制返回数量以节省 token',
},
},
get_session_summaries: {
desc: `获取会话摘要列表,快速了解群聊历史讨论的主题。
适用场景:
1. 了解群里最近在聊什么话题
2. 按关键词搜索讨论过的话题
3. 概览性问题如"群里有没有讨论过旅游"
返回的摘要是对每个会话的简短总结,可以帮助快速定位感兴趣的会话,然后用 get_session_messages 获取详情。`,
params: {
keywords: '在摘要中搜索的关键词列表(OR 逻辑匹配)',
limit: '返回会话数量限制,默认 20',
year: '指定年份筛选会话',
month: '指定月份筛选会话(1-12)',
day: '指定日期筛选会话(1-31)',
start_time: '开始时间,格式 "YYYY-MM-DD HH:mm"',
end_time: '结束时间,格式 "YYYY-MM-DD HH:mm"',
},
},
message_type_breakdown: {
desc: '按消息类型统计近 N 天的消息分布(文本、图片、语音、表情等各有多少条)。适用于了解沟通方式偏好。',
params: { days: '统计最近多少天的数据' },
rowTemplate: '{type_name}:{msg_count} 条(占 {percentage}%)',
summaryTemplate: '消息类型分布(共 {rowCount} 种类型):',
fallback: '该时间范围内没有消息记录',
},
peak_chat_hours_by_member: {
desc: '分析指定成员近 N 天的小时分布,找出其最活跃的时间段。需要先获取 member_id。',
params: {
member_id: '成员 ID(通过 get_members 获取)',
days: '统计最近多少天的数据',
},
rowTemplate: '{hour}:00 — {msg_count} 条消息',
summaryTemplate: '该成员各时间段发言量(共 {rowCount} 个活跃时段):',
fallback: '指定时间范围内该成员无发言记录',
},
member_activity_trend: {
desc: '查看指定成员近 N 天每天的发言量趋势,观察其活跃度变化。需要先获取 member_id。',
params: {
member_id: '成员 ID(通过 get_members 获取)',
days: '查看最近多少天',
},
rowTemplate: '{day}:{msg_count} 条消息',
summaryTemplate: '该成员近 {rowCount} 天有发言记录:',
fallback: '指定时间范围内该成员无发言记录',
},
silent_members: {
desc: '检测超过 N 天未发言的"沉默成员",适用于社群运营中识别流失风险用户。',
params: { days: '多少天未发言算沉默' },
rowTemplate: '{name} — 已沉默 {silent_days} 天',
summaryTemplate: '共发现 {rowCount} 位沉默成员:',
fallback: '没有找到超过指定天数未发言的成员,社群活跃度良好!',
},
reply_interaction_ranking: {
desc: '分析群内回复互动排名——谁回复谁最多。适用于发现核心互动关系和意见领袖。',
params: {
days: '统计最近多少天的数据',
limit: '返回前多少对互动关系',
},
rowTemplate: '{replier_name} → {original_name}:回复 {reply_count} 次',
summaryTemplate: '回复互动 Top {rowCount}:',
fallback: '该时间范围内没有回复互动记录',
},
mutual_interaction_pairs: {
desc: '发现互动最频繁的成员组合,基于双向消息时间相邻度(一方发言后5分钟内另一方也发言则记一次互动)。适用于发现亲密好友组合。',
params: {
days: '统计最近多少天的数据',
limit: '返回前多少对',
},
rowTemplate: '{member_a} ↔ {member_b}:{interaction_count} 次互动',
summaryTemplate: '互动最频繁的 {rowCount} 对成员:',
fallback: '该时间范围内没有明显的互动关系',
},
member_message_length_stats: {
desc: '分析各成员的平均消息长度(仅统计文本消息),消息越长通常代表交流越深入。适用于发现深度交流者。',
params: {
days: '统计最近多少天的数据',
top_n: '返回前多少名',
},
rowTemplate: '{name} — 平均 {avg_length} 字/条(共 {msg_count} 条,最长 {max_length} 字)',
summaryTemplate: '消息长度 Top {rowCount}(越长越深入):',
fallback: '该时间范围内没有足够的文本消息数据',
},
unanswered_messages: {
desc: '查找近 N 天内未被回复的消息,这些可能是未解决的客户问题。仅统计文本消息且内容超过 10 字的(过滤简短寒暄)。',
params: {
days: '查找最近多少天的数据',
limit: '最多返回多少条',
},
rowTemplate: '[{send_time}] {sender_name}:{content_preview}',
summaryTemplate: '共发现 {rowCount} 条可能未被回复的消息:',
fallback: '该时间范围内所有消息都已得到回复,服务质量很好!',
},
daily_active_members: {
desc: '统计每日独立发言人数(DAU)和消息量,用于观察群活力变化趋势。适用于"群活跃度趋势怎么样"、"最近有多少人在说话"。',
params: { days: '统计最近多少天的数据' },
rowTemplate: '{day}:{active_members} 人活跃,{msg_count} 条消息',
summaryTemplate: '近 {rowCount} 天的每日活跃人数趋势:',
fallback: '该时间范围内没有消息记录',
},
conversation_initiator_stats: {
desc: '统计每个成员发起会话(作为会话首条消息的发送者)的次数,找出谁最常开启话题。需要已生成会话索引。',
params: {
days: '统计最近多少天的数据',
limit: '返回前多少名',
},
rowTemplate: '{name}:发起 {initiated_count} 次话题',
summaryTemplate: '话题发起者 Top {rowCount}:',
fallback: '该时间范围内没有会话记录,可能需要先生成会话索引',
},
activity_heatmap: {
desc: '返回 星期×小时 的消息数矩阵,适合生成活跃度热力图。weekday: 0=周日, 1=周一, ..., 6=周六。',
params: { days: '统计最近多少天的数据' },
rowTemplate: '星期{weekday} {hour}:00 — {msg_count} 条',
summaryTemplate: '活跃度热力图数据(共 {rowCount} 个时段有消息):',
fallback: '该时间范围内没有消息记录',
},
response_time_analysis: {
desc: '分析消息之间的响应时间,按成员维度统计中位数和平均回复速度。适用于"大家平均多久回复消息"、"谁回复最快"。',
params: {
days: '统计最近多少天的数据',
top_n: '返回前多少名',
},
},
keyword_frequency: {
desc: '对指定时间段的文本消息进行分词,统计高频关键词排行。支持中英日文分词。适用于"大家最常说什么"、"高频关键词是什么"。',
params: {
days: '统计最近多少天的数据',
top_n: '返回前多少个关键词',
},
},
},
agent: {
answerWithoutTools: '请根据已获取的信息给出回答,不要再调用工具。',
toolError: '错误: {{error}}',
currentDateIs: '当前日期是',
chatContext: {
private: '对话',
group: '群聊',
},
ownerNote: `当前用户身份:
- 用户在{{chatContext}}中的身份是「{{displayName}}」(platformId: {{platformId}})
- 当用户提到"我"、"我的"时,指的就是「{{displayName}}」
- 查询"我"的发言时,使用 sender_id 参数筛选该成员
`,
memberNotePrivate: `成员查询策略:
- 私聊只有两个人,可以直接获取成员列表
- 当用户提到"对方"、"他/她"时,通过 get_members 获取另一方信息
`,
memberNoteGroup: `成员查询策略:
- 当用户提到特定群成员(如"张三说过什么"、"小明的发言"等)时,应先调用 get_members 获取成员列表
- 群成员有三种名称:accountName(原始昵称)、groupNickname(群昵称)、aliases(用户自定义别名)
- 通过 get_members 的 search 参数可以模糊搜索这三种名称
- 找到成员后,使用其 id 字段作为 search_messages 的 sender_id 参数来获取该成员的发言
`,
mentionedMembersNote: '本轮用户显式 @ 的成员(可直接使用 member_id,无需再次搜索):',
timeParamsIntro: '时间参数:使用 start_time/end_time 指定时间范围,格式 "YYYY-MM-DD HH:mm"',
defaultYearNote: '未指定时间范围时默认查询全部。当前年份为{{year}}年',
dataSnapshotNote:
'当前聊天数据库快照:{{name}}({{platform}}),总消息 {{totalMessages}} 条,成员 {{totalMembers}} 人,时间范围 {{firstMessageDate}} ~ {{lastMessageDate}}。该快照只用于判断数据范围;回答具体聊天事实仍必须调用工具检索当前数据库。',
evidencePolicy: `证据策略:
- AI 对话历史、历史 AI 回复和压缩摘要只用于理解用户意图,不能作为聊天记录事实证据。
- 只要用户询问聊天记录内容、最近聊什么、某人说过什么、统计排行、是否出现过某话题或要求引用原话,必须先调用合适的数据工具检索当前数据库。
- 如果已追加新聊天记录,当前数据库可能不同于旧窗口历史;优先使用 get_chat_overview 或 get_recent_messages/search_messages 获取最新证据。
- 只有工具返回的消息、统计或数据库概览可以作为事实依据;工具没有返回足够证据时,明确说明数据不足,不要编造不存在的聊天记录。`,
currentTask: '当前任务',
skillPriorityNote: '注意:在执行此任务时,请优先遵循以下任务的输出格式要求,这可以覆盖你的常规回复习惯。',
responseInstruction: '根据用户的问题,选择合适的工具获取数据,然后基于数据给出回答。',
fallbackRoleDefinition: {
group: `你是一个专业但风格轻松的群聊记录分析助手。
你的任务是帮助用户理解和分析他们的群聊记录数据,同时可以适度使用 B 站/网络热梗和表情/颜文字活跃气氛,但不影响结论的准确性。
## 回答要求
1. 基于工具返回的数据回答,不要编造信息
2. 如果数据不足以回答问题,请说明
3. 回答要简洁明了,使用 Markdown 格式
4. 可以适度加入 B 站/网络热梗、表情/颜文字(强度适中)
5. 玩梗不得影响事实准确与结论清晰,避免低俗或冒犯性表达`,
private: `你是一个专业但风格轻松的私聊记录分析助手。
你的任务是帮助用户理解和分析他们的私聊记录数据,同时可以适度使用 B 站/网络热梗和表情/颜文字活跃气氛,但不影响结论的准确性。
## 回答要求
1. 基于工具返回的数据回答,不要编造信息
2. 如果数据不足以回答问题,请说明
3. 回答要简洁明了,使用 Markdown 格式
4. 可以适度加入 B 站/网络热梗、表情/颜文字(强度适中)
5. 玩梗不得影响事实准确与结论清晰,避免低俗或冒犯性表达`,
},
},
},
llm: {
notConfigured: 'LLM 服务未配置,请先在设置中配置 API Key',
maxConfigs: '最多只能添加 {{count}} 个配置',
configNotFound: '配置不存在',
noActiveConfig: '没有激活的配置',
callFailed: 'LLM 调用失败,请检查模型配置是否正确',
genericProviderName: 'API 服务',
rawErrorLabel: '原始错误',
},
summary: {
sessionNotFound: '会话不存在或数据库打开失败',
tooFewMessages: '消息数量少于{{count}}条,无需生成摘要',
tooFewValidMessages: '有效消息数量少于{{count}}条,无需生成摘要',
sessionNotExist: '会话不存在',
messagesTooFew: '消息太少',
validMessagesTooFew: '有效消息太少',
systemPromptDirect: '你是一个对话摘要专家,擅长用简洁的语言总结对话内容。',
systemPromptMerge: '你是一个对话摘要专家,擅长将多个摘要合并成一个连贯的总结。',
},
}
@@ -0,0 +1,325 @@
/**
* AI shared translations — Traditional Chinese
*/
export default {
ai: {
tools: {
search_messages: {
desc: '根據關鍵詞搜尋聊天紀錄,是回答關鍵詞、成員發言、是否出現過某話題等事實問題的主要證據工具。可以指定時間範圍和傳送者來篩選訊息。支援精確到分鐘級別的時間查詢。',
params: {
keywords: '搜尋關鍵詞清單,會用 OR 邏輯匹配包含任一關鍵詞的訊息。如果只需要按傳送者篩選,可以傳空陣列 []',
sender_id: '傳送者的成員 ID,用於篩選特定成員傳送的訊息。可以透過 get_members 工具取得成員 ID',
limit: '回傳訊息數量限制,預設 1000,最大 50000',
year: '篩選指定年份的訊息,如 2024',
month: '篩選指定月份的訊息(1-12),需要配合 year 使用',
day: '篩選指定日期的訊息(1-31),需要配合 year 和 month 使用',
hour: '篩選指定小時的訊息(0-23),需要配合 year、month 和 day 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定後會覆蓋 year/month/day/hour 參數',
},
},
deep_search_messages: {
desc: '精確子串匹配搜尋聊天紀錄,速度較慢但不會遺漏任何包含關鍵詞的訊息。當 search_messages 結果不足、需要驗證某段話是否真實存在、或搜尋部分詞/單個字元時使用。',
params: {
keywords: '搜尋關鍵詞清單,使用子串匹配(LIKE),任一關鍵詞匹配即回傳',
sender_id: '傳送者的成員 ID,用於篩選特定成員傳送的訊息',
limit: '回傳訊息數量限制,預設 1000,最大 50000',
year: '篩選指定年份的訊息,如 2024',
month: '篩選指定月份的訊息(1-12),需要配合 year 使用',
day: '篩選指定日期的訊息(1-31),需要配合 year 和 month 使用',
hour: '篩選指定小時的訊息(0-23),需要配合 year、month 和 day 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm"。指定後會覆蓋 year/month/day/hour 參數',
},
},
get_recent_messages: {
desc: '取得指定時間段內的聊天訊息,是回答「最近大家聊了什麼」、「X月聊了什麼」、追加新紀錄後最新內容等概覽性問題的首選證據工具。支援精確到分鐘級別的時間查詢。',
params: {
limit: '回傳訊息數量限制,預設 100(可節省 Token,必要時再增加)',
year: '篩選指定年份的訊息,如 2024',
month: '篩選指定月份的訊息(1-12),需要配合 year 使用',
day: '篩選指定日期的訊息(1-31),需要配合 year 和 month 使用',
hour: '篩選指定小時的訊息(0-23),需要配合 year、month 和 day 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定後會覆蓋 year/month/day/hour 參數',
},
},
get_chat_overview: {
desc: '取得聊天記錄的基本概覽資訊,包括群名/平台/類型/總訊息數/總成員數/時間跨度/最活躍成員排名。適合在分析前或追加新紀錄後確認目前資料庫範圍。',
params: {
top_n: '回傳前 N 名活躍成員,預設 10',
},
},
get_member_stats: {
desc: '取得群成員的活躍度統計資料。適用於回答「誰最活躍」、「發言最多的是誰」等問題。',
params: {
top_n: '回傳前 N 名成員,預設 10',
},
},
get_time_stats: {
desc: '取得群聊的時間分佈統計。適用於回答「什麼時候最活躍」、「大家一般幾點聊天」等問題。',
params: {
type: '統計類型:hourly(按小時)、weekday(按星期)、daily(按日期)',
},
},
get_members: {
desc: '取得群成員清單,包含基本資料、別名與訊息統計。適用於查詢「群裡有哪些人」、「某人的別名是什麼」、「誰的 QQ 號是 xxx」等問題。',
params: {
search: '可選的搜尋關鍵詞,用於篩選成員暱稱、別名或 QQ 號',
limit: '回傳成員數量限制,預設回傳全部',
},
},
get_member_name_history: {
desc: '取得成員的暱稱變更歷史紀錄。適用於回答「某人以前叫什麼名字」、「某人的暱稱變化」、「某人曾用名」等問題。需要先透過 get_members 工具取得成員 ID。',
params: {
member_id: '成員的資料庫 ID,可以透過 get_members 工具取得',
},
},
get_conversation_between: {
desc: '取得兩位群成員之間的對話紀錄。適用於回答「A 和 B 之間聊了什麼」、「檢視兩人的對話」等問題。需要先透過 get_members 取得成員 ID。支援精確到分鐘級別的時間查詢。',
params: {
member_id_1: '第一個成員的資料庫 ID',
member_id_2: '第二個成員的資料庫 ID',
limit: '回傳訊息數量限制,預設 100',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"。指定後會覆蓋 year/month/day/hour 參數',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"。指定後會覆蓋 year/month/day/hour 參數',
},
},
get_message_context: {
desc: '根據訊息 ID 取得前後的上下文訊息。適用於引用具體訊息前後進行事實驗證,例如「這則訊息前後在聊什麼」、「確認這段話是否有上下文」等。支援單筆或批次訊息 ID。',
params: {
message_ids:
'要查詢上下文的訊息 ID 清單,可以是單個 ID 或多個 ID。訊息 ID 可以從 search_messages 等工具的回傳結果中取得',
context_size: '上下文大小,即取得前後各多少條訊息,預設 20',
},
},
search_sessions: {
desc: '搜尋聊天會話(對話段落)。會話是根據訊息時間間隔自動切分的對話單元。適用於查找特定話題的討論、了解某個時間段內發生了幾次對話等場景。回傳匹配的會話清單及每個會話的前5條訊息預覽。',
params: {
keywords: '可選的搜尋關鍵詞清單,只回傳包含這些關鍵詞的會話(OR 邏輯匹配)',
limit: '回傳會話數量限制,預設 20',
year: '篩選指定年份的會話,如 2024',
month: '篩選指定月份的會話(1-12),需要配合 year 使用',
day: '篩選指定日期的會話(1-31),需要配合 year 和 month 使用',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 14:00"',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm",如 "2024-03-15 18:30"',
},
},
get_session_messages: {
desc: '取得指定會話的完整訊息清單。用於在 search_sessions 找到相關會話後,取得該會話的完整上下文。回傳會話的所有訊息及參與者資訊。',
params: {
session_id: '會話 ID,可以從 search_sessions 的回傳結果中取得',
limit: '回傳訊息數量限制,預設 1000。對於超長會話可以限制回傳數量以節省 token',
},
},
get_session_summaries: {
desc: `取得會話摘要清單,快速了解群聊歷史討論的主題。
適用場景:
1. 了解群裡最近在聊什麼話題
2. 按關鍵詞搜尋討論過的話題
3. 概覽性問題如「群裡有沒有討論過旅遊」
回傳的摘要是對每個會話的簡短總結,可以幫助快速定位感興趣的會話,然後用 get_session_messages 取得詳情。`,
params: {
keywords: '在摘要中搜尋的關鍵詞清單(OR 邏輯匹配)',
limit: '回傳會話數量限制,預設 20',
year: '篩選指定年份的會話',
month: '篩選指定月份的會話(1-12)',
day: '篩選指定日期的會話(1-31)',
start_time: '開始時間,格式 "YYYY-MM-DD HH:mm"',
end_time: '結束時間,格式 "YYYY-MM-DD HH:mm"',
},
},
message_type_breakdown: {
desc: '按訊息類型統計近 N 天的訊息分佈(文字、圖片、語音、表情等各有多少條)。適用於了解溝通方式偏好。',
params: { days: '統計最近多少天的資料' },
rowTemplate: '{type_name}:{msg_count} 條(佔 {percentage}%)',
summaryTemplate: '訊息類型分佈(共 {rowCount} 種類型):',
fallback: '該時間範圍內沒有訊息紀錄',
},
peak_chat_hours_by_member: {
desc: '分析指定成員在近 N 天內每小時的發言量分佈,找出其最活躍的時段。需要先透過 get_members 取得 member_id。',
params: {
member_id: '成員 ID(透過 get_members 取得)',
days: '統計最近多少天的資料',
},
rowTemplate: '{hour}:00 — {msg_count} 條訊息',
summaryTemplate: '該成員各時段發言量(共 {rowCount} 個活躍時段):',
fallback: '該成員在指定時間範圍內沒有發言紀錄',
},
member_activity_trend: {
desc: '查看指定成員近 N 天的每日發言數量變化趨勢。適用於觀察某人是否變得更活躍或更沉默。需要先透過 get_members 取得 member_id。',
params: {
member_id: '成員 ID(透過 get_members 取得)',
days: '查看最近多少天的趨勢',
},
rowTemplate: '{day}:{msg_count} 條',
summaryTemplate: '該成員近 {rowCount} 天有發言紀錄:',
fallback: '該成員在指定時間範圍內沒有發言紀錄',
},
silent_members: {
desc: '偵測超過 N 天未發言的「沉默成員」。適用於社群營運中發現流失風險使用者。',
params: { days: '多少天未發言算沉默' },
rowTemplate: '{name} — 已沉默 {silent_days} 天',
summaryTemplate: '共發現 {rowCount} 位沉默成員:',
fallback: '沒有發現超過指定天數未發言的成員,社群活躍度良好!',
},
reply_interaction_ranking: {
desc: '分析群內的回覆互動關係排行,找出誰回覆誰最多。適用於發現社群中的核心互動關係和意見領袖。',
params: {
days: '統計最近多少天的資料',
limit: '回傳前多少對互動關係',
},
rowTemplate: '{replier_name} → {original_name}:{reply_count} 次回覆',
summaryTemplate: '回覆互動 Top {rowCount}:',
fallback: '該時間範圍內沒有回覆互動紀錄',
},
mutual_interaction_pairs: {
desc: '找出互動最頻繁的成員對,基於雙向訊息時間接近度(一方發言後 5 分鐘內另一方也發言即視為一次互動)。適用於發現關係親密的好友組合。',
params: {
days: '統計最近多少天的資料',
limit: '回傳前多少對',
},
rowTemplate: '{member_a} ↔ {member_b}:{interaction_count} 次互動',
summaryTemplate: '互動最頻繁的 {rowCount} 對好友:',
fallback: '該時間範圍內沒有偵測到明顯的互動關係',
},
member_message_length_stats: {
desc: '統計各成員的平均訊息長度(僅文字訊息),長訊息通常意味著更用心的交流。適用於發現深度交流者。',
params: {
days: '統計最近多少天的資料',
top_n: '回傳前多少名',
},
rowTemplate: '{name} — 平均 {avg_length} 字/條(共 {msg_count} 條,最長 {max_length} 字)',
summaryTemplate: '訊息長度 Top {rowCount}(更長 = 更用心):',
fallback: '該時間範圍內沒有足夠的文字訊息資料',
},
unanswered_messages: {
desc: '查找近 N 天內未被回覆的訊息,這些可能是未解決的客戶問題。僅統計文字訊息且內容超過 10 字的(過濾簡短寒暄)。',
params: {
days: '查找最近多少天的資料',
limit: '最多回傳多少條',
},
rowTemplate: '[{send_time}] {sender_name}:{content_preview}',
summaryTemplate: '共發現 {rowCount} 條可能未被回覆的訊息:',
fallback: '該時間範圍內所有訊息都已得到回覆,服務品質很好!',
},
daily_active_members: {
desc: '統計每日獨立發言人數(DAU)和訊息量,用於觀察群活力變化趨勢。適用於「群活躍度趨勢怎麼樣」、「最近有多少人在說話」。',
params: { days: '統計最近多少天的資料' },
rowTemplate: '{day}:{active_members} 人活躍,{msg_count} 條訊息',
summaryTemplate: '近 {rowCount} 天的每日活躍人數趨勢:',
fallback: '該時間範圍內沒有訊息紀錄',
},
conversation_initiator_stats: {
desc: '統計每個成員發起會話(作為會話首條訊息的發送者)的次數,找出誰最常開啟話題。需要已產生會話索引。',
params: {
days: '統計最近多少天的資料',
limit: '回傳前多少名',
},
rowTemplate: '{name}:發起 {initiated_count} 次話題',
summaryTemplate: '話題發起者 Top {rowCount}:',
fallback: '該時間範圍內沒有會話紀錄,可能需要先產生會話索引',
},
activity_heatmap: {
desc: '回傳 星期×小時 的訊息數矩陣,適合產生活躍度熱力圖。weekday: 0=週日, 1=週一, ..., 6=週六。',
params: { days: '統計最近多少天的資料' },
rowTemplate: '星期{weekday} {hour}:00 — {msg_count} 條',
summaryTemplate: '活躍度熱力圖資料(共 {rowCount} 個時段有訊息):',
fallback: '該時間範圍內沒有訊息紀錄',
},
response_time_analysis: {
desc: '分析訊息之間的回應時間,按成員維度統計中位數和平均回覆速度。適用於「大家平均多久回覆訊息」、「誰回覆最快」。',
params: {
days: '統計最近多少天的資料',
top_n: '回傳前多少名',
},
},
keyword_frequency: {
desc: '對指定時間段的文字訊息進行分詞,統計高頻關鍵詞排行。支援中英日文分詞。適用於「大家最常說什麼」、「高頻關鍵詞是什麼」。',
params: {
days: '統計最近多少天的資料',
top_n: '回傳前多少個關鍵詞',
},
},
},
agent: {
answerWithoutTools: '請根據已取得的資訊給出回答,不要再呼叫工具。',
toolError: '錯誤: {{error}}',
currentDateIs: '目前日期是',
chatContext: {
private: '對話',
group: '群聊',
},
ownerNote: `目前使用者身份:
- 使用者在{{chatContext}}中的身份是「{{displayName}}」(platformId: {{platformId}})
- 當使用者提到「我」、「我的」時,指的就是「{{displayName}}」
- 查詢「我」的發言時,使用 sender_id 參數篩選該成員
`,
memberNotePrivate: `成員查詢策略:
- 私聊只有兩個人,可以直接取得成員清單
- 當使用者提到「對方」、「他/她」時,透過 get_members 取得另一方資訊
`,
memberNoteGroup: `成員查詢策略:
- 當使用者提到特定群成員(如「張三說過什麼」、「小明的發言」等)時,應先呼叫 get_members 取得成員清單
- 群成員有三種名稱:accountName(原始暱稱)、groupNickname(群暱稱)、aliases(使用者自訂別名)
- 透過 get_members 的 search 參數可以模糊搜尋這三種名稱
- 找到成員後,使用其 id 欄位作為 search_messages 的 sender_id 參數來取得該成員的發言
`,
mentionedMembersNote: '本輪使用者顯式 @ 的成員(可直接使用 member_id,無需再次搜尋):',
timeParamsIntro: '時間參數:使用 start_time/end_time 指定時間範圍,格式 "YYYY-MM-DD HH:mm"',
defaultYearNote: '未指定時間範圍時預設查詢全部。當前年份為{{year}}年',
dataSnapshotNote:
'目前聊天資料庫快照:{{name}}({{platform}}),總訊息 {{totalMessages}} 條,成員 {{totalMembers}} 人,時間範圍 {{firstMessageDate}} ~ {{lastMessageDate}}。該快照只用於判斷資料範圍;回答具體聊天事實仍必須呼叫工具檢索目前資料庫。',
evidencePolicy: `證據策略:
- AI 對話歷史、歷史 AI 回覆和壓縮摘要只用於理解使用者意圖,不能作為聊天紀錄事實證據。
- 只要使用者詢問聊天紀錄內容、最近聊什麼、某人說過什麼、統計排行、是否出現過某話題或要求引用原話,必須先呼叫合適的資料工具檢索目前資料庫。
- 如果已追加新聊天紀錄,目前資料庫可能不同於舊視窗歷史;優先使用 get_chat_overview 或 get_recent_messages/search_messages 取得最新證據。
- 只有工具回傳的訊息、統計或資料庫概覽可以作為事實依據;工具沒有回傳足夠證據時,明確說明資料不足,不要編造不存在的聊天紀錄。`,
responseInstruction: '根據使用者的問題,選擇合適的工具取得資料,然後基於資料給出回答。',
fallbackRoleDefinition: {
group: `你是一個專業但風格輕鬆的群聊紀錄分析助手。
你的任務是幫助使用者理解和分析他們的群聊紀錄資料,同時可以適度使用網路熱梗和表情/顏文字活躍氣氛,但不影響結論的準確性。
## 回答要求
1. 基於工具回傳的資料回答,不要編造資訊
2. 如果資料不足以回答問題,請說明
3. 回答要簡潔明瞭,使用 Markdown 格式
4. 可以適度加入網路熱梗、表情/顏文字(強度適中)
5. 玩梗不得影響事實準確與結論清晰,避免低俗或冒犯性表達`,
private: `你是一個專業但風格輕鬆的私聊紀錄分析助手。
你的任務是幫助使用者理解和分析他們的私聊紀錄資料,同時可以適度使用網路熱梗和表情/顏文字活躍氣氛,但不影響結論的準確性。
## 回答要求
1. 基於工具回傳的資料回答,不要編造資訊
2. 如果資料不足以回答問題,請說明
3. 回答要簡潔明瞭,使用 Markdown 格式
4. 可以適度加入網路熱梗、表情/顏文字(強度適中)
5. 玩梗不得影響事實準確與結論清晰,避免低俗或冒犯性表達`,
},
},
},
llm: {
notConfigured: 'LLM 服務尚未設定,請先在設定中填入 API Key',
maxConfigs: '最多只能新增 {{count}} 組設定',
configNotFound: '找不到設定',
noActiveConfig: '沒有啟用中的設定',
callFailed: 'LLM 呼叫失敗,請檢查模型設定是否正確',
genericProviderName: 'API 服務',
rawErrorLabel: '原始錯誤',
},
summary: {
sessionNotFound: '會話不存在或資料庫開啟失敗',
tooFewMessages: '訊息數量少於 {{count}} 條,無需產生摘要',
tooFewValidMessages: '有效訊息數量少於 {{count}} 條,無需產生摘要',
sessionNotExist: '找不到會話',
messagesTooFew: '訊息太少',
validMessagesTooFew: '有效訊息太少',
systemPromptDirect: '你是一個對話摘要專家,擅長用簡潔的語言總結對話內容。',
systemPromptMerge: '你是一個對話摘要專家,擅長將多個摘要合併成一個連貫的總結。',
},
}
+3
View File
@@ -103,6 +103,9 @@ export type {
TranslateFn,
} from './agent/prompt-builder'
// AI i18n (shared translations for agent prompts and tool descriptions)
export { createAiTranslate, aiLocales } from './i18n'
// Summary generation
export {
generateSessionSummary,
+1 -1
View File
@@ -170,7 +170,7 @@ export { AgentEventHandler, estimateTokensFromText } from './ai'
export type { TokenUsage, AgentRuntimeStatus, AgentStreamChunk, EventHandlerConfig, EventHandlerContext } from './ai'
// Agent Prompt Builder
export { buildSystemPrompt } from './ai'
export { buildSystemPrompt, createAiTranslate, aiLocales } from './ai'
export type {
BuildSystemPromptOptions,
DataSnapshot,
+28 -41
View File
@@ -9,6 +9,8 @@ import {
runAgentCore,
completeSimple,
checkAndCompress,
buildSystemPrompt,
createAiTranslate,
type AgentCoreEvent,
type SimpleHistoryMessage,
type AIConversationManager,
@@ -16,6 +18,9 @@ import {
type CompressionLlmAdapter,
type PiTextContent,
type AgentTool,
type DataSnapshot,
type OwnerInfo,
type MentionedMember,
} from '@openchatlab/node-runtime'
import { getDefaultAssistantConfig, buildPiModel } from './llm-config'
@@ -53,46 +58,9 @@ export interface RunAgentOptions {
convManager: AIConversationManager
onEvent: (event: AgentStreamEvent) => void
abortSignal?: AbortSignal
}
function buildSystemPrompt(
_chatType: 'group' | 'private',
assistantSystemPrompt?: string,
locale: string = 'zh-CN',
skillMenu?: string | null
): string {
const now = new Date()
const dateLocale = locale.startsWith('zh') ? 'zh-CN' : 'en-US'
const currentDate = now.toLocaleDateString(dateLocale, {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
})
const isZh = locale.startsWith('zh')
const role =
assistantSystemPrompt ||
(isZh
? '你是 ChatLab AI 助手,一个智能对话助手。请友好、准确地回答用户的问题。'
: 'You are ChatLab AI assistant, an intelligent conversational assistant. Please answer questions in a friendly and accurate manner.')
const datePrefix = isZh ? '当前日期是' : 'Current date is'
const responseNote = isZh
? '请直接回答用户的问题,不要使用工具除非确实需要。'
: "Answer the user's question directly. Only use tools when truly necessary."
let prompt = `${role}
${datePrefix} ${currentDate}。
${responseNote}`
if (skillMenu) {
prompt += `\n\n${skillMenu}`
}
return prompt
ownerInfo?: OwnerInfo
mentionedMembers?: MentionedMember[]
dataSnapshot?: DataSnapshot
}
function mapCoreEventToStream(
@@ -155,6 +123,9 @@ export async function runServerAgent(options: RunAgentOptions): Promise<void> {
convManager,
onEvent,
abortSignal,
ownerInfo,
mentionedMembers,
dataSnapshot,
} = options
const llmConfig = getDefaultAssistantConfig(aiDataDir)
@@ -165,7 +136,23 @@ export async function runServerAgent(options: RunAgentOptions): Promise<void> {
}
const piModel = buildPiModel(llmConfig)
const systemPrompt = buildSystemPrompt(chatType, assistantSystemPrompt, locale, skillMenu)
const t = createAiTranslate(locale)
let skillCtx: { skillDef?: { name: string; prompt: string }; skillMenu?: string } | undefined
if (skillMenu) {
skillCtx = { skillMenu }
}
const systemPrompt = buildSystemPrompt({
t,
chatType,
assistantSystemPrompt,
ownerInfo,
locale,
skillCtx,
mentionedMembers,
dataSnapshot,
})
if (compressionConfig?.enabled) {
const llmAdapter: CompressionLlmAdapter = {
+45 -2
View File
@@ -15,7 +15,14 @@ import type { FastifyInstance } from 'fastify'
import type { DatabaseManager, AIConversationManager } from '@openchatlab/node-runtime'
import { SkillManager, createActivateSkillTool } from '@openchatlab/node-runtime'
import type { AssistantConfig } from '@openchatlab/node-runtime'
import { BUILTIN_TOOL_CATALOG, BUILTIN_PROVIDERS, BUILTIN_MODELS, getBuiltinModelsByProvider } from '@openchatlab/core'
import {
BUILTIN_TOOL_CATALOG,
BUILTIN_PROVIDERS,
BUILTIN_MODELS,
getBuiltinModelsByProvider,
getChatOverview,
} from '@openchatlab/core'
import type { DataSnapshot, OwnerInfo, MentionedMember } from '@openchatlab/node-runtime'
import { AGENT_TOOL_REGISTRY } from '@openchatlab/tools'
import { adaptToolsForAgent } from '../../ai/tool-adapter'
import { loadAssistantConfig } from '../../ai/assistant-loader'
@@ -484,9 +491,21 @@ export function registerAiRoutes(
bufferSizePercent?: number
maxToolResultPercent?: number
}
ownerInfo?: OwnerInfo
mentionedMembers?: MentionedMember[]
}
}>('/_web/ai/agent/stream', async (request, reply) => {
const { userMessage, conversationId, sessionId, chatType, locale, assistantId, compressionConfig } = request.body
const {
userMessage,
conversationId,
sessionId,
chatType,
locale,
assistantId,
compressionConfig,
ownerInfo,
mentionedMembers,
} = request.body
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
const abortController = new AbortController()
@@ -564,6 +583,27 @@ export function registerAiRoutes(
}
: undefined
let dataSnapshot: DataSnapshot | undefined
if (db) {
try {
const overview = getChatOverview(db, 5)
if (overview) {
dataSnapshot = {
name: overview.name,
platform: overview.platform,
type: overview.type,
totalMessages: overview.totalMessages,
totalMembers: overview.totalMembers,
firstMessageTs: overview.firstMessageTs,
lastMessageTs: overview.lastMessageTs,
capturedAt: Math.floor(Date.now() / 1000),
}
}
} catch {
// non-fatal: proceed without snapshot
}
}
await runServerAgent({
userMessage,
conversationId,
@@ -577,6 +617,9 @@ export function registerAiRoutes(
convManager,
onEvent,
abortSignal: abortController.signal,
ownerInfo,
mentionedMembers,
dataSnapshot,
})
} catch (error) {
const msg = error instanceof Error ? error.message : String(error)