Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions src/AI/AI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ export interface Privilege {
counter: number,
timer: number,
prob: number,
standby: boolean
standby: boolean,
activeTimeInfo: {
start: number,
end: number,
segs: number
}
}

export class AI {
Expand Down Expand Up @@ -51,7 +56,12 @@ export class AI {
counter: -1,
timer: -1,
prob: -1,
standby: false
standby: false,
activeTimeInfo: {
start: 0,
end: 0,
segs: 0
}
};
this.stream = {
id: '',
Expand Down Expand Up @@ -309,6 +319,43 @@ export class AI {
await this.stopCurrentChatStream();
}

// 若不在活动时间范围内,返回-1
getCurSegIndex(): number {
const now = new Date();
const cur = now.getHours() * 60 + now.getMinutes();
const { start, end, segs } = this.privilege.activeTimeInfo;
const endReal = end >= start ? end : end + 24 * 60;
const curReal = cur >= start ? cur : cur + 24 * 60;

if (curReal >= endReal) return -1;

const segLen = (endReal - start) / segs;
const index = Math.floor((curReal - start) / segLen);
return Math.min(index, segs - 1);
}

// 若没有下一个活跃时间点,返回-1
getNextTimePoint(curSegIndex: number): number {
const { start, end, segs } = this.privilege.activeTimeInfo;

if (start === 0 && end === 0) return -1;

const endReal = end >= start ? end : end + 24 * 60;
const segLen = (endReal - start) / segs;
const nextSegIndex = (curSegIndex + 1) % segs;
const todayMin = Math.floor(start + nextSegIndex * segLen + Math.random() * segLen) % (24 * 60);

const nextTime = new Date();
nextTime.setHours(Math.floor(todayMin / 60), todayMin % 60, Math.floor(Math.random() * 60), 0);

// 如果时间已过,设置为明天
if (nextTime.getTime() <= Date.now()) {
nextTime.setDate(nextTime.getDate() + 1);
}

return Math.floor(nextTime.getTime() / 1000);
}

async stopCurrentChatStream(): Promise<void> {
const { id, reply, toolCallStatus } = this.stream;
this.stream = {
Expand All @@ -329,7 +376,7 @@ export class AI {
}

export class AIManager {
static version = "1.0.0";
static version = "1.0.1";
static cache: { [key: string]: AI } = {};
static usageMap: {
[key: string]: { // 模型名
Expand Down
58 changes: 36 additions & 22 deletions src/AI/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@ import { AI, AIManager } from "./AI";
import { logger } from "../logger";
import { transformMsgId } from "../utils/utils";

export interface MessageInfo {
msgId: string;
time: number; // 秒
content: string;
}

export interface Message {
role: string;
tool_calls?: ToolCall[];
tool_call_id?: string;

uid: string;
name: string;
contentArray: string[];
msgIdArray: string[];
images: Image[];
msgArray: MessageInfo[];
}

export class Context {
Expand Down Expand Up @@ -114,18 +119,23 @@ export class Context {
const uid = role == 'user' ? ctx.player.userId : ctx.endPoint.userId;
const length = messages.length;
if (length !== 0 && messages[length - 1].uid === uid && !/<function(?:_call)?>/.test(s)) {
messages[length - 1].contentArray.push(s);
messages[length - 1].msgIdArray.push(msgId);
messages[length - 1].images.push(...images);
messages[length - 1].msgArray.push({
msgId: msgId,
time: Math.floor(Date.now() / 1000),
content: s
});
} else {
const message = {
const message: Message = {
role: role,
content: '',
uid: uid,
name: name,
contentArray: [s],
msgIdArray: [msgId],
images: images
images: images,
msgArray: [{
msgId: msgId,
time: Math.floor(Date.now() / 1000),
content: s
}]
};
messages.push(message);

Expand All @@ -149,27 +159,29 @@ export class Context {
}

async addToolCallsMessage(tool_calls: ToolCall[]) {
const message = {
const message: Message = {
role: 'assistant',
tool_calls: tool_calls,
uid: '',
name: '',
contentArray: [],
msgIdArray: [],
images: []
images: [],
msgArray: []
};
this.messages.push(message);
}

async addToolMessage(tool_call_id: string, s: string) {
const message = {
const message: Message = {
role: 'tool',
tool_call_id: tool_call_id,
uid: '',
name: '',
contentArray: [s],
msgIdArray: [''],
images: []
images: [],
msgArray: [{
msgId: '',
time: Math.floor(Date.now() / 1000),
content: s
}]
};

for (let i = this.messages.length - 1; i >= 0; i--) {
Expand All @@ -183,14 +195,16 @@ export class Context {
}

async addSystemUserMessage(name: string, s: string, images: Image[]) {
const message = {
const message: Message = {
role: 'user',
content: s,
uid: '',
name: `_${name}`,
contentArray: [s],
msgIdArray: [''],
images: images
images: images,
msgArray: [{
msgId: '',
time: Math.floor(Date.now() / 1000),
content: s
}]
};
this.messages.push(message);
}
Expand Down
20 changes: 8 additions & 12 deletions src/AI/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { Context } from "./context";
import { generateId } from "../utils/utils";
import { logger } from "../logger";
import { fetchData } from "../service";
import { parseBody } from "../utils/utils_message";
import { buildContent, parseBody } from "../utils/utils_message";
import { ToolManager } from "../tool/tool";
import { fmtTime } from "../utils/utils_string";

export interface MemoryInfo {
id: string;
Expand Down Expand Up @@ -75,7 +76,7 @@ export class Memory {
groupId: ctx.group.groupId,
groupName: ctx.group.groupName
},
time: new Date().toLocaleString(),
time: fmtTime(Math.floor(Date.now() / 1000)),
createTime: Math.floor(Date.now() / 1000),
lastMentionTime: Math.floor(Date.now() / 1000),
keywords: kws || [],
Expand Down Expand Up @@ -152,7 +153,7 @@ export class Memory {
}

const { url: chatUrl, apiKey: chatApiKey } = ConfigManager.request;
const { roleSettingTemplate, isPrefix, showNumber, showMsgId } = ConfigManager.message;
const { roleSettingTemplate, isPrefix, showNumber, showMsgId, showTime } = ConfigManager.message;
const { shortMemorySummaryRound, memoryUrl, memoryApiKey, memoryBodyTemplate, memoryPromptTemplate } = ConfigManager.memory;

const messages = ai.context.messages;
Expand Down Expand Up @@ -195,18 +196,13 @@ export class Memory {
"群聊号码": ctx.group.groupId.replace(/^.+:/, ''),
"添加前缀": isPrefix,
"展示消息ID": showMsgId,
"展示时间": showTime,
"对话内容": isPrefix ? sumMessages.map(message => {
if (message.role === 'assistant' && message?.tool_calls && message?.tool_calls.length > 0) {
return `\n[function_call]: ${message.tool_calls.map((tool_call, index) => `${index + 1}. ${JSON.stringify(tool_call.function, null, 2)}`).join('\n')}`;
}
const prefix = (isPrefix && message.name) ? (
message.name.startsWith('_') ?
`<|${message.name}|>` :
`<|from:${message.name}${showNumber ? `(${message.uid.replace(/^.+:/, '')})` : ``}|>`
) : '';
const content = message.msgIdArray.map((msgId, index) => (showMsgId && msgId ? `<|msg_id:${msgId}|>` : '') + message.contentArray[index]).join('\f');

return `[${message.role}]: ${prefix}${content}`;

return `[${message.role}]: ${buildContent(message)}`;
}).join('\n') : JSON.stringify(sumMessages)
})

Expand Down Expand Up @@ -361,7 +357,7 @@ export class Memory {

buildMemoryPrompt(ctx: seal.MsgContext, context: Context): string {
const userMessages = context.messages.filter(msg => msg.role === 'user' && !msg.name.startsWith('_'));
const lastMsg = userMessages.length > 0 ? userMessages[userMessages.length - 1].contentArray.join('') : '';
const lastMsg = userMessages.length > 0 ? userMessages[userMessages.length - 1].msgArray.map(mi => mi.content).join('') : '';

const ai = AIManager.getAI(ctx.endPoint.userId);
let s = ai.memory.buildMemory(true, seal.formatTmpl(ctx, "核心:骰子名字"), ctx.endPoint.userId, '', '', lastMsg);
Expand Down
3 changes: 3 additions & 0 deletions src/config/config_memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export class MemoryConfig {
{{#if 展示消息ID}}
- <|msg_id:xxx|>表示消息ID,仅用于调用函数时使用,不要在生成的回复中提及或使用
- <|quote:xxx|>表示引用消息,xxx为对应的消息ID
{{/if}}
{{#if 展示时间}}
- <|time:xxxx-xx-xx xx:xx:xx|>表示消息发送时间,不要在生成的回复中提及或使用
{{/if}}
- \\f用于分割多条消息

Expand Down
5 changes: 5 additions & 0 deletions src/config/config_message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ export class MessageConfig {
{{#if 展示消息ID}}
- <|msg_id:xxx|>表示消息ID,仅用于调用函数时使用,不要在生成的回复中提及或使用
- <|quote:xxx|>表示引用消息,xxx为对应的消息ID
{{/if}}
{{#if 展示时间}}
- <|time:xxxx-xx-xx xx:xx:xx|>表示消息发送时间,不要在生成的回复中提及或使用
{{/if}}
- \\f用于分割多条消息
{{#if 接收图片}}
Expand Down Expand Up @@ -143,6 +146,7 @@ export class MessageConfig {
seal.ext.registerBoolConfig(MessageConfig.ext, "是否在消息内添加前缀", true, "可用于辨别不同用户");
seal.ext.registerBoolConfig(MessageConfig.ext, "是否给AI展示数字号码", true, "例如QQ号和群号,能力较弱模型可能会出现幻觉");
seal.ext.registerBoolConfig(MessageConfig.ext, "是否在消息内添加消息ID", false, "可用于撤回等情况");
seal.ext.registerBoolConfig(MessageConfig.ext, "是否在消息内添加发送时间", false, "将消息发送时间添加到上下文中");
seal.ext.registerBoolConfig(MessageConfig.ext, "是否合并user content", false, "在不支持连续多个role为user的情况下开启,可用于适配deepseek-reasoner");
seal.ext.registerIntConfig(MessageConfig.ext, "存储上下文对话限制轮数", 15, "出现一次user视作一轮");
seal.ext.registerIntConfig(MessageConfig.ext, "上下文插入system message间隔轮数", 0, "需要小于限制轮数的二分之一才能生效,为0时不生效,示例对话不计入轮数");
Expand All @@ -156,6 +160,7 @@ export class MessageConfig {
isPrefix: seal.ext.getBoolConfig(MessageConfig.ext, "是否在消息内添加前缀"),
showNumber: seal.ext.getBoolConfig(MessageConfig.ext, "是否给AI展示数字号码"),
showMsgId: seal.ext.getBoolConfig(MessageConfig.ext, "是否在消息内添加消息ID"),
showTime: seal.ext.getBoolConfig(MessageConfig.ext, "是否在消息内添加发送时间"),
isMerge: seal.ext.getBoolConfig(MessageConfig.ext, "是否合并user content"),
maxRounds: seal.ext.getIntConfig(MessageConfig.ext, "存储上下文对话限制轮数"),
insertCount: seal.ext.getIntConfig(MessageConfig.ext, "上下文插入system message间隔轮数")
Expand Down
Loading