diff --git a/atall/atall.ts b/atall/atall.ts
new file mode 100644
index 00000000..fca8e756
--- /dev/null
+++ b/atall/atall.ts
@@ -0,0 +1,195 @@
+import { Plugin } from "@utils/pluginBase";
+import { Api } from "telegram";
+import { getGlobalClient } from "@utils/globalClient";
+import { getPrefixes } from "@utils/pluginManager";
+
+// HTML转义函数
+const htmlEscape = (text: string): string =>
+ text.replace(/[&<>"']/g, m => ({
+ '&': '&', '<': '<', '>': '>',
+ '"': '"', "'": '''
+ }[m] || m));
+
+// 消息分割函数(限制调整为4000字符)
+const splitMessagesByMention = (mentions: string[], maxLength = 4000): string[] => {
+ const messages: string[] = [];
+ let currentMessage = "";
+
+ for (const mention of mentions) {
+ // 如果当前消息为空,直接添加第一个mention
+ if (currentMessage === "") {
+ currentMessage = mention;
+ }
+ // 如果添加下一个mention后不会超过限制,则添加空格和mention
+ else if (currentMessage.length + 1 + mention.length <= maxLength) {
+ currentMessage += " " + mention;
+ }
+ // 否则保存当前消息,开始新消息
+ else {
+ messages.push(currentMessage);
+ currentMessage = mention;
+ }
+ }
+
+ // 添加最后一个消息
+ if (currentMessage) {
+ messages.push(currentMessage);
+ }
+
+ return messages;
+};
+
+// 帮助文本
+const help_text = `📢 AtAll
+
+📝 功能描述:
+• 一键@群组中的所有成员
+• 自动处理无用户名用户
+• 智能消息分割
+
+🔧 使用方法:
+• ${getPrefixes()[0]}atall - @群组中的所有成员
+
+⚠️ 注意事项:
+• 极大封号风险,后果自负
+• 大群组中可能会生成很多条消息
+• 一般来说你可以通过置顶消息来提醒所有人的`;
+
+class AtAllPlugin extends Plugin {
+ description = help_text;
+
+ cmdHandlers = {
+ atall: async (msg: Api.Message) => {
+ try {
+ const client = await getGlobalClient();
+ if (!client) {
+ await msg.edit({ text: "❌ 无法获取客户端", parseMode: "html" });
+ return;
+ }
+
+ // 获取当前聊天
+ const chat = await msg.getChat();
+ if (!chat || !("id" in chat)) {
+ await msg.edit({ text: "❌ 此命令只能在群组中使用", parseMode: "html" });
+ return;
+ }
+
+ const chatId = chat.id;
+
+ // 显示处理中
+ const processingMsg = await msg.edit({
+ text: "🔄 正在获取群组成员列表...",
+ parseMode: "html"
+ });
+
+ // 获取所有群组成员
+ const participants = await client.getParticipants(chatId, {});
+
+ if (!participants || participants.length === 0) {
+ await processingMsg.edit({
+ text: "❌ 无法获取群组成员或群组为空",
+ parseMode: "html"
+ });
+ return;
+ }
+
+ // 生成@列表
+ let mentionList: string[] = [];
+
+ for (const participant of participants) {
+ // 跳过机器人自身
+ if (participant.bot) continue;
+
+ // 尝试获取用户实体
+ let userEntity;
+ try {
+ userEntity = await client.getEntity(participant.id);
+ } catch {
+ continue; // 跳过无法获取实体的用户
+ }
+
+ if (userEntity && "username" in userEntity && userEntity.username) {
+ // 有用户名的情况 - 直接使用@username
+ mentionList.push(`@${userEntity.username}`);
+ } else {
+ // 无用户名,使用mention链接
+ let displayName = "";
+ if ("firstName" in participant && participant.firstName) {
+ displayName = participant.firstName;
+ if ("lastName" in participant && participant.lastName) {
+ displayName += ` ${participant.lastName}`;
+ }
+ } else if ("title" in participant && participant.title) {
+ displayName = participant.title;
+ } else {
+ displayName = "";
+ }
+
+ // 使用Telegram mention链接
+ mentionList.push(`${htmlEscape(displayName)}`);
+ }
+ }
+
+ if (mentionList.length === 0) {
+ await processingMsg.edit({
+ text: "❌ 没有可@的成员",
+ parseMode: "html"
+ });
+ return;
+ }
+
+ // 更新处理状态
+ await processingMsg.edit({
+ text: `🔄 正在生成@列表... (${mentionList.length} 个成员)`,
+ parseMode: "html"
+ });
+
+ // 分割消息(基于mention单位),限制调整为4000
+ const messageParts = splitMessagesByMention(mentionList, 4000);
+
+ // 删除处理中消息
+ await processingMsg.delete({ revoke: true }).catch(() => {});
+
+ // 发送所有消息部分
+ for (let i = 0; i < messageParts.length; i++) {
+ const part = messageParts[i];
+
+ // 在每条消息开头加上"@所有人:"标题
+ const messageContent = `@所有人:\n${part}`;
+
+ await client.sendMessage(chatId, {
+ message: messageContent,
+ parseMode: "html",
+ replyTo: i === 0 ? msg.id : undefined
+ });
+
+ // 为避免消息发送过快,添加短暂延迟
+ if (i < messageParts.length - 1) {
+ await new Promise(resolve => setTimeout(resolve, 500));
+ }
+ }
+
+ } catch (error: any) {
+ console.error("[AtAll Plugin] Error:", error);
+
+ let errorMessage = "❌ 发生错误: ";
+ if (error.message?.includes("CHAT_ADMIN_REQUIRED")) {
+ errorMessage += "需要管理员权限来获取成员列表";
+ } else if (error.message?.includes("USER_NOT_PARTICIPANT")) {
+ errorMessage += "不是群组成员";
+ } else if (error.message?.includes("CHANNEL_PRIVATE")) {
+ errorMessage += "无法访问私有频道";
+ } else {
+ errorMessage += htmlEscape(error.message || "未知错误");
+ }
+
+ await msg.edit({
+ text: errorMessage,
+ parseMode: "html"
+ });
+ }
+ }
+ };
+}
+
+export default new AtAllPlugin();
\ No newline at end of file
diff --git a/clean/clean.ts b/clean/clean.ts
index 2288bc0f..a6aa959b 100644
--- a/clean/clean.ts
+++ b/clean/clean.ts
@@ -61,10 +61,14 @@ class CleanPlugin extends Plugin {
// 插件配置
private readonly PLUGIN_NAME = "clean";
private readonly PLUGIN_VERSION = "2.0.0";
+ public description: string = "";
// 清理进度状态
private cleanupStartTime: number = 0;
private blockedCleanupStartTime: number = 0;
+
+ // 命令处理器
+ private cmdHandlers: { [key: string]: (msg: Api.Message) => Promise };
constructor() {
super();
@@ -410,7 +414,7 @@ class CleanPlugin extends Plugin {
let bannedUsers = await getBannedUsers(client, chatEntity);
if (!includeAll) {
- bannedUsers = bannedUsers.filter(u => u.kickedBy === myId);
+ bannedUsers = bannedUsers.filter((u: any) => u.kickedBy === myId);
}
if (bannedUsers.length === 0) {
@@ -423,7 +427,7 @@ class CleanPlugin extends Plugin {
await this.editMessage(msg, `⚡ 正在解封 ${bannedUsers.length} 个实体...`);
const entityStats = { users: 0, channels: 0, chats: 0 };
- bannedUsers.forEach(entity => {
+ bannedUsers.forEach((entity: any) => {
if (entity.type === 'user') entityStats.users++;
else if (entity.type === 'channel') entityStats.channels++;
else if (entity.type === 'chat') entityStats.chats++;
diff --git a/diss/diss.ts b/diss/diss.ts
index 048abd65..fa324716 100644
--- a/diss/diss.ts
+++ b/diss/diss.ts
@@ -42,7 +42,8 @@ class DissPlugin extends Plugin {
}
}
} catch (error) {
- console.warn(`[diss] 第${attempt}次尝试失败:`, error.message);
+ const errorMessage = error instanceof Error ? error.message : String(error);
+ console.warn(`[diss] 第${attempt}次尝试失败:`, errorMessage);
// 如果不是最后一次尝试,等待一下再重试
if (attempt < 5) {
diff --git a/komari/komari.ts b/komari/komari.ts
index 6c662cb8..b1a341e7 100644
--- a/komari/komari.ts
+++ b/komari/komari.ts
@@ -575,6 +575,7 @@ async function handleKomariRequest(msg: Api.Message): Promise {
return;
}
+ displayName = "Komari URL";
ConfigManager.set(CONFIG_KEYS.KOMARI_URL, configValue);
const displayValue = configValue;
diff --git a/listusernames/listusernames.ts b/listusernames/listusernames.ts
index f9d4b3f7..acd15747 100644
--- a/listusernames/listusernames.ts
+++ b/listusernames/listusernames.ts
@@ -41,7 +41,7 @@ class ListUsernamesPlugin extends Plugin {
// 调用Telegram API获取公开频道
const result = await client.invoke(
- new Api.channels.GetAdminedPublicChannels()
+ new Api.channels.GetAdminedPublicChannels({})
);
if (!result.chats || result.chats.length === 0) {
diff --git a/lu_bs/lu_bs.ts b/lu_bs/lu_bs.ts
index daab90dd..376a8a31 100644
--- a/lu_bs/lu_bs.ts
+++ b/lu_bs/lu_bs.ts
@@ -154,8 +154,8 @@ class LuBsPlugin extends Plugin {
console.error(`[${this.PLUGIN_NAME}] 发送失败到 ${chatId}:`, error);
// 如果发送失败,可能是聊天不存在或没有权限,移除订阅
- if (error.message?.includes("CHAT_WRITE_FORBIDDEN") ||
- error.message?.includes("CHAT_NOT_FOUND")) {
+ if ((error as any).message?.includes("CHAT_WRITE_FORBIDDEN") ||
+ (error as any).message?.includes("CHAT_NOT_FOUND")) {
this.db.data.subscriptions = this.db.data.subscriptions.filter((id: string) => id !== chatId);
delete this.db.data.lastMessages[chatId];
await this.db.write();
@@ -174,6 +174,9 @@ class LuBsPlugin extends Plugin {
const chat = await msg.getChat();
const sender = await msg.getSender();
+ // 检查chat和sender是否存在
+ if (!chat || !sender) return false;
+
// 私聊总是允许
if (chat.className === "User") {
return true;
diff --git a/oxost/oxost.ts b/oxost/oxost.ts
index 98537b76..a4b8e49e 100644
--- a/oxost/oxost.ts
+++ b/oxost/oxost.ts
@@ -5,6 +5,7 @@ import { getPrefixes } from "@utils/pluginManager";
import { Plugin } from "@utils/pluginBase";
import { Api } from "telegram";
import { getGlobalClient } from "@utils/globalClient";
+import { Buffer } from "buffer";
// HTML转义
const htmlEscape = (text: string): string =>
@@ -141,7 +142,7 @@ class Ox0Plugin extends Plugin {
// 使用 Node.js 原生 FormData(无需 form-data 依赖)
const form = new globalThis.FormData();
- form.append("file", new Blob([buffer], { type: "application/octet-stream" }), filename);
+ form.append("file", new Blob([new Uint8Array(buffer)], { type: "application/octet-stream" }), filename);
if (expires) form.append("expires", expires);
if (secret) form.append("secret", "1");
const headers = { 'User-Agent': 'curl/8.0.1' };
diff --git a/plugins.json b/plugins.json
index b6e8b70d..0dc37e76 100644
--- a/plugins.json
+++ b/plugins.json
@@ -23,6 +23,10 @@
"url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/annualreport/annualreport.ts?raw=true",
"desc": "年度报告"
},
+ "atadmins": {
+ "url": "https://github.com/TeleBoxDev/TeleBox_Plugins/blob/main/atall/atall.ts?raw=true",
+ "desc": "一键艾特全部成员"
+ },
"atadmins": {
"url": "https://github.com/TeleBoxDev/TeleBox_Plugins/blob/main/atadmins/atadmins.ts?raw=true",
"desc": "一键艾特全部管理员"
diff --git a/premium/premium.ts b/premium/premium.ts
index 794cf8bc..94aaa198 100644
--- a/premium/premium.ts
+++ b/premium/premium.ts
@@ -108,7 +108,10 @@ class PremiumPlugin extends Plugin {
// 处理不同类型的participant
if (participant instanceof Api.ChannelParticipant) {
- user = participant.user as Api.User;
+ if ((participant as any).user) {
+ user = (participant as any).user as Api.User;
+ }
+ continue;
} else if (participant instanceof Api.ChatParticipant) {
user = participant.userId as unknown as Api.User;
} else if (participant instanceof Api.User) {
diff --git a/restore_pin/restore_pin.ts b/restore_pin/restore_pin.ts
index 386d2078..1143360d 100644
--- a/restore_pin/restore_pin.ts
+++ b/restore_pin/restore_pin.ts
@@ -1,5 +1,5 @@
import { Plugin } from "@utils/pluginBase";
-import { Api } from "telegram";
+import { Api, types } from "telegram";
import { getGlobalClient } from "@utils/globalClient";
// HTML转义函数(必需)
@@ -41,8 +41,8 @@ class RestorePinPlugin extends Plugin {
new Api.channels.GetAdminLog({
channel: chatId,
q: "",
- maxId: BigInt(0),
- minId: BigInt(0),
+ maxId: 0,
+ minId: 0,
limit: 100,
eventsFilter: new Api.ChannelAdminLogEventsFilter({
pinned: true
@@ -62,7 +62,7 @@ class RestorePinPlugin extends Plugin {
for (const event of events.events) {
// 检查是否为取消置顶事件
if (event.action instanceof Api.ChannelAdminLogEventActionUpdatePinned) {
- if (!event.action.message.pinned) { // 取消置顶
+ if (!(event.action.message instanceof Api.MessageEmpty) && !event.action.message.pinned) { // 取消置顶
const messageId = event.action.message.id;
messageIds.push(messageId);
}
@@ -173,10 +173,16 @@ class RestorePinPlugin extends Plugin {
}
// 检查管理员权限
+ const sender = await msg.getSender();
+ if (!sender) {
+ await msg.edit({ text: "❌ 无法获取发送者信息", parseMode: "html" });
+ return;
+ }
+
const participant = await client.invoke(
new Api.channels.GetParticipant({
channel: chat.id,
- participant: await msg.getSender() as Api.InputUser
+ participant: sender as unknown as Api.InputUser
})
);
diff --git a/subinfo/subinfo.ts b/subinfo/subinfo.ts
index 961af585..860ad887 100644
--- a/subinfo/subinfo.ts
+++ b/subinfo/subinfo.ts
@@ -170,7 +170,7 @@ async function getNodeInfo(url: string): Promise<{ node_count: number | string,
let identified = 0;
const protocols = ['vmess://', 'trojan://', 'ss://', 'ssr://', 'vless://', 'hy2://', 'hysteria://', 'hy://', 'tuic://', 'wireguard://', 'socks5://', 'http://', 'https://', 'shadowtls://', 'naive://'];
- decoded.split('\n').forEach(line => {
+ decoded.split('\n').forEach((line: string) => {
if (!line.trim()) return;
for (const pattern of protocols) {
if (line.startsWith(pattern)) {
@@ -373,7 +373,7 @@ class SubinfoPlugin extends Plugin {
expireTs: number;
startTs: number;
websiteInfo: { website: string | null; websiteName: string | null };
- nodeInfo: Awaited> | null;
+ nodeInfo: { node_count: string | number; type_count: Record; regions: Record } | null;
errorMessage: string | null;
}> {
const websiteInfo = await getWebsiteInfo(url);
@@ -382,12 +382,12 @@ class SubinfoPlugin extends Plugin {
configName: '未知',
status: '失败',
statusEmoji: '❓',
- profileUrl: null,
+ profileUrl: null as string | null,
used: 0, upload: 0, download: 0, total: 0, remain: 0, percent: 0,
expireTs: 0, startTs: 0,
websiteInfo,
- nodeInfo: null,
- errorMessage: null,
+ nodeInfo: null as { node_count: string | number; type_count: Record; regions: Record } | null,
+ errorMessage: null as string | null,
};
try {
@@ -414,7 +414,7 @@ class SubinfoPlugin extends Plugin {
result.configName = configName || '未知';
const userInfoHeader = response.headers['subscription-userinfo'];
- result.profileUrl = response.headers['profile-web-page-url'] as string || null;
+ result.profileUrl = (response.headers['profile-web-page-url'] as string | null) || null;
if (!userInfoHeader) {
result.errorMessage = "无流量统计信息";
@@ -423,7 +423,7 @@ class SubinfoPlugin extends Plugin {
// 解析用户信息
const userInfoParts: Record = {};
- userInfoHeader.split(';').forEach(part => {
+ userInfoHeader.split(';').forEach((part: string) => {
const equalsIndex = part.indexOf('=');
if (equalsIndex > 0) userInfoParts[part.substring(0, equalsIndex).trim().toLowerCase()] = part.substring(equalsIndex + 1).trim();
});
diff --git a/teletype/teletype.ts b/teletype/teletype.ts
index efd4738a..5f724b9d 100644
--- a/teletype/teletype.ts
+++ b/teletype/teletype.ts
@@ -199,12 +199,7 @@ class TeletypePlugin extends Plugin {
}
private async getPrefixes(): Promise {
- try {
- const { getPrefixes } = await import("@utils/pluginManager");
- return getPrefixes();
- } catch (error) {
- return [".", "。", "!"];
- }
+ return [".", "。", "!"];
}
private async executeTeletype(msg: Api.Message, text: string): Promise {
@@ -217,6 +212,8 @@ class TeletypePlugin extends Plugin {
parseMode: "html"
});
+ if (!currentMsg) return;
+
await this.sleep(interval);
for (const character of text) {
@@ -224,18 +221,22 @@ class TeletypePlugin extends Plugin {
const bufferWithCursor = `${htmlEscape(buffer)}${cursor}`;
try {
- currentMsg = await currentMsg.edit({
+ currentMsg = await currentMsg?.edit({
text: bufferWithCursor,
parseMode: "html"
});
+ if (!currentMsg) return;
+
await this.sleep(interval);
- if (buffer.length > 0) {
+ if (buffer.length > 0 && currentMsg) {
currentMsg = await currentMsg.edit({
text: htmlEscape(buffer),
parseMode: "html"
});
+
+ if (!currentMsg) return;
}
} catch (error: any) {
@@ -250,10 +251,12 @@ class TeletypePlugin extends Plugin {
const finalText = htmlEscape(text);
try {
- await currentMsg.edit({
- text: finalText,
- parseMode: "html"
- });
+ if (currentMsg) {
+ await currentMsg.edit({
+ text: finalText,
+ parseMode: "html"
+ });
+ }
} catch (error: any) {
if (!error.message?.includes("MESSAGE_NOT_MODIFIED")) {
throw error;
diff --git a/uai/uai.ts b/uai/uai.ts
index aeb4adbd..9415e9d5 100644
--- a/uai/uai.ts
+++ b/uai/uai.ts
@@ -1,6 +1,7 @@
/**
* UAI 插件 - 引用消息 AI 分析
* 引用某用户/频道的消息,回复 .uai zj/fx 进行总结/分析
+ * 支持消息折叠显示,保持AI回答中的HTML格式
*/
import { Plugin } from "@utils/pluginBase";
import { getPrefixes } from "@utils/pluginManager";
@@ -32,6 +33,7 @@ type UAIConfig = {
default_provider?: string;
prompts: Record;
timeout: number;
+ collapse: boolean; // 新增:折叠开关
};
// ========== 常量 ==========
@@ -48,7 +50,8 @@ const DEFAULT_CONFIG: UAIConfig = {
providers: {},
default_provider: undefined,
prompts: {},
- timeout: DEFAULT_TIMEOUT
+ timeout: DEFAULT_TIMEOUT,
+ collapse: true // 默认折叠
};
// ========== 工具函数 ==========
@@ -61,7 +64,22 @@ function htmlEscape(t: string): string {
.replace(/'/g, "'");
}
-// Markdown 转 Telegram HTML
+// HTML转义函数(确保用户输入安全)
+const escapeHtml = (text: string): string =>
+ text.replace(/[&<>"']/g, m => ({
+ '&': '&', '<': '<', '>': '>',
+ '"': '"', "'": '''
+ }[m] || m));
+
+// 应用折叠功能
+const applyWrap = (s: string, collapse?: boolean): string => {
+ if (!collapse) return s;
+ // 检查是否已经是块引用
+ if (/|\/)\/?>/i.test(s)) return s;
+ return `${s}
`;
+};
+
+// Markdown 转 Telegram HTML,保留特殊格式
function markdownToHtml(text: string): string {
return text
// 粗体 **text** 或 __text__
@@ -73,7 +91,11 @@ function markdownToHtml(text: string): string {
// 代码 `code`
.replace(/`([^`]+)`/g, "$1")
// 删除线 ~~text~~
- .replace(/~~(.+?)~~/g, "$1");
+ .replace(/~~(.+?)~~/g, "$1")
+ // 保留已有的HTML标签
+ .replace(/<(.+?)>/g, "<$1>")
+ // 处理块引用 > text
+ .replace(/^>\s?(.+)$/gm, "$1
");
}
function trimBase(url: string): string {
@@ -109,9 +131,11 @@ function parseTimeLimit(s: string): number | null {
// ========== 数据库 ==========
async function getDB() {
const db = await JSONFilePreset(DB_PATH, DEFAULT_CONFIG);
+ // 确保所有字段都存在
if (!db.data.providers) db.data.providers = {};
if (!db.data.prompts) db.data.prompts = {};
if (!db.data.timeout) db.data.timeout = DEFAULT_TIMEOUT;
+ if (typeof db.data.collapse !== "boolean") db.data.collapse = false;
return db;
}
@@ -281,18 +305,23 @@ function formatMessagesForAI(messages: MessageData[]): string {
}
// ========== 帮助文本 ==========
-const getHelpText = () => `⚙️ UAI
+const getHelpText = () => `⚙️ UAI - 用户消息AI分析
📝 功能描述:
-• 引用消息,AI 自动收集并分析/总结目标用户的历史消息
+• 引用用户消息,AI自动收集并分析/总结目标用户的历史消息
+• 支持折叠显示AI回答,保持格式完整
-🔧 使用方法:
+🔧 核心功能:
• ${mainPrefix}uai zj - 总结(当天消息)
• ${mainPrefix}uai fx - 分析(当天消息)
-• ${mainPrefix}uai zj 50 - 总结最近 50 条
-• ${mainPrefix}uai fx 2h - 分析最近 2 小时
+• ${mainPrefix}uai zj 50 - 总结最近50条
+• ${mainPrefix}uai fx 2h - 分析最近2小时
• ${mainPrefix}uai 自定义名 - 使用自定义提示词
+⚙️ 折叠显示:
+• ${mainPrefix}uai collapse on - 开启AI回答折叠
+• ${mainPrefix}uai collapse off - 关闭AI回答折叠
+
🔌 供应商配置:
• ${mainPrefix}uai add <名称> <url> <key> <type> - 添加供应商
• ${mainPrefix}uai set <名称> - 设置默认供应商
@@ -301,13 +330,23 @@ const getHelpText = () => `⚙️ UAI
• ${mainPrefix}uai model <名称> <模型> - 修改模型
📝 提示词配置:
-• ${mainPrefix}uai prompt add <名称> <内容> - 添加
-• ${mainPrefix}uai prompt del <名称> - 删除
-• ${mainPrefix}uai prompt list - 列表
+• ${mainPrefix}uai prompt add <名称> <内容> - 添加自定义提示词
+• ${mainPrefix}uai prompt del <名称> - 删除自定义提示词
+• ${mainPrefix}uai prompt list - 列出所有提示词
+
+💡 内置提示词:
+• zj - 总结(提取关键信息)
+• fx - 分析(观点、态度分析)
-💡 参数说明:
+📋 参数说明:
• type: openai / gemini
-• 内置提示词: zj(总结) fx(分析)`;
+• 时间格式: 2h(2小时), 30m(30分钟)
+• 数量格式: 50(最近50条)
+
+🔍 使用示例:
+1. 引用用户消息,回复: .uai zj - 总结当天消息
+2. 引用用户消息,回复: .uai fx 100 - 分析最近100条
+3. 引用频道消息,回复: .uai zj - 总结频道消息`;
// ========== 插件类 ==========
class UAIPlugin extends Plugin {
@@ -328,6 +367,34 @@ class UAIPlugin extends Plugin {
return;
}
+ // 折叠开关配置
+ if (subCmd === "collapse") {
+ const action = parts[1]?.toLowerCase();
+ if (action === "on") {
+ db.data.collapse = true;
+ await db.write();
+ await msg.edit({
+ text: "✅ 已开启AI回答折叠显示\n\nAI回答将显示在可折叠的块引用中",
+ parseMode: "html"
+ });
+ return;
+ } else if (action === "off") {
+ db.data.collapse = false;
+ await db.write();
+ await msg.edit({
+ text: "✅ 已关闭AI回答折叠显示\n\nAI回答将正常显示",
+ parseMode: "html"
+ });
+ return;
+ } else {
+ await msg.edit({
+ text: `📊 当前折叠状态: ${db.data.collapse ? "开启" : "关闭"}\n\n使用: ${mainPrefix}uai collapse on/off`,
+ parseMode: "html"
+ });
+ return;
+ }
+ }
+
// 配置命令
if (subCmd === "add" && parts.length >= 5) {
const [, name, baseUrl, apiKey, typeStr] = parts;
@@ -382,7 +449,11 @@ class UAIPlugin extends Plugin {
const isDefault = db.data.default_provider === p.name ? " ⭐" : "";
return `• ${htmlEscape(p.name)}${isDefault} (${p.type}, ${p.model})`;
}).join("\n");
- await msg.edit({ text: `📋 供应商列表\n\n${list}`, parseMode: "html" });
+ const collapseStatus = `折叠显示: ${db.data.collapse ? "✅ 开启" : "❌ 关闭"}`;
+ await msg.edit({
+ text: `📋 供应商列表\n\n${list}\n\n${collapseStatus}`,
+ parseMode: "html"
+ });
return;
}
@@ -527,7 +598,13 @@ class UAIPlugin extends Plugin {
const userInfo = `来源: ${channelName}${channelUsername ? ` (@${channelUsername})` : ""}`;
const result = await callAI(provider, prompt, `${userInfo}\n\n${content}`, db.data.timeout);
- const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${markdownToHtml(result)}`;
+
+ // 处理AI回答,保留格式并应用折叠
+ const aiContent = markdownToHtml(result);
+ const foldedContent = applyWrap(aiContent, db.data.collapse);
+
+ const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${foldedContent}`;
+
await msg.delete({ revoke: true });
await client.sendMessage(chatPeerId, { message: resultText, parseMode: "html" });
return;
@@ -572,7 +649,13 @@ class UAIPlugin extends Plugin {
const provider = db.data.providers[db.data.default_provider!];
const result = await callAI(provider, prompt, `${userInfo}\n\n${content}`, db.data.timeout);
- const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${markdownToHtml(result)}`;
+
+ // 处理AI回答,保留格式并应用折叠
+ const aiContent = markdownToHtml(result);
+ const foldedContent = applyWrap(aiContent, db.data.collapse);
+
+ const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${foldedContent}`;
+
await msg.delete({ revoke: true });
await client.sendMessage(chatPeerId, { message: resultText, parseMode: "html" });