delete: 移除不再使用的配置文件和开发依赖,清理代码库
This commit is contained in:
@@ -178,7 +178,7 @@ class MessageHandler(BaseHandler):
|
||||
await bot.send(event, message_template.format(permission_name=permission_name))
|
||||
return
|
||||
|
||||
# 在执行指令前,原子化地增加指令调用次数
|
||||
# 在执行指令前,增加指令调用次数
|
||||
from ..managers.redis_manager import redis_manager
|
||||
from ..utils.logger import logger
|
||||
try:
|
||||
|
||||
@@ -216,4 +216,4 @@ async def download_to_local(url: str, timeout: int = 60, headers: Optional[Dict[
|
||||
if not file_id:
|
||||
return None
|
||||
|
||||
return f"http://127.0.0.1:{server.port}/download?id={file_id}"
|
||||
return f"http://{server.host}:{server.port}/download?id={file_id}"
|
||||
|
||||
@@ -5,7 +5,6 @@ NEO Bot Plugins Package
|
||||
"""
|
||||
|
||||
from . import admin
|
||||
from . import ai_chat
|
||||
from . import auto_approve
|
||||
from . import bot_status
|
||||
from . import broadcast
|
||||
@@ -23,7 +22,6 @@ from . import weather
|
||||
|
||||
__all__ = [
|
||||
"admin",
|
||||
"ai_chat",
|
||||
"auto_approve",
|
||||
"bot_status",
|
||||
"broadcast",
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
AI 聊天插件,支持向量数据库记忆功能
|
||||
"""
|
||||
import time
|
||||
import uuid
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<<<<<<< HEAD:src/neobot/plugins/ai_chat.py
|
||||
>>>>>>> eb9079744c82f8e254de084a3a089ef91c37e9dc
|
||||
import os
|
||||
import base64
|
||||
from neobot.core.managers.command_manager import matcher
|
||||
from neobot.models.events.message import GroupMessageEvent, PrivateMessageEvent
|
||||
from neobot.core.managers.vectordb_manager import vectordb_manager
|
||||
from neobot.core.managers.image_manager import image_manager
|
||||
from neobot.core.utils.logger import ModuleLogger
|
||||
from neobot.core.config_loader import global_config
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
=======
|
||||
import markdown
|
||||
from core.managers.command_manager import matcher
|
||||
from models.events.message import GroupMessageEvent, PrivateMessageEvent
|
||||
from models.message import MessageSegment
|
||||
from core.managers.vectordb_manager import vectordb_manager
|
||||
from core.managers.image_manager import image_manager
|
||||
from core.utils.logger import ModuleLogger
|
||||
from core.config_loader import global_config
|
||||
>>>>>>> origin/main:plugins/ai_chat.py
|
||||
>>>>>>> eb9079744c82f8e254de084a3a089ef91c37e9dc
|
||||
|
||||
logger = ModuleLogger("AIChat")
|
||||
|
||||
__plugin_meta__ = {
|
||||
"name": "AI 聊天",
|
||||
"description": "支持向量数据库记忆功能的 AI 聊天助手",
|
||||
"usage": "/chat <内容> - 与 AI 进行对话"
|
||||
}
|
||||
|
||||
try:
|
||||
from openai import AsyncOpenAI
|
||||
OPENAI_AVAILABLE = True
|
||||
except ImportError:
|
||||
OPENAI_AVAILABLE = False
|
||||
|
||||
async def get_ai_response(user_id: int, group_id: int, user_message: str) -> str:
|
||||
"""获取 AI 回复,包含向量数据库记忆"""
|
||||
if not OPENAI_AVAILABLE:
|
||||
return "请先安装 openai 库: pip install openai"
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<<<<<<< HEAD:src/neobot/plugins/ai_chat.py
|
||||
=======
|
||||
# 从配置中获取 DeepSeek API 配置(复用跨平台插件的配置或全局配置)
|
||||
>>>>>>> origin/main:plugins/ai_chat.py
|
||||
>>>>>>> eb9079744c82f8e254de084a3a089ef91c37e9dc
|
||||
api_key = getattr(global_config.cross_platform, 'deepseek_api_key', None) or "sk-f71322a9fbba4b05a7df969cb4004f06"
|
||||
api_url = getattr(global_config.cross_platform, 'deepseek_api_url', "https://api.deepseek.com/v1")
|
||||
model = getattr(global_config.cross_platform, 'deepseek_model', "deepseek-chat")
|
||||
|
||||
if api_key == "your-api-key":
|
||||
return "请先在配置中设置 DeepSeek API Key"
|
||||
|
||||
collection_name = f"chat_memory_{user_id}"
|
||||
memory_context = ""
|
||||
|
||||
try:
|
||||
results = vectordb_manager.query_texts(
|
||||
collection_name=collection_name,
|
||||
query_texts=[user_message],
|
||||
n_results=3
|
||||
)
|
||||
|
||||
if results and results.get("documents") and results["documents"][0]:
|
||||
memory_context = "\n\n相关历史记忆:\n"
|
||||
for i, doc in enumerate(results["documents"][0], 1):
|
||||
memory_context += f"{i}. {doc}\n"
|
||||
except Exception as e:
|
||||
logger.error(f"检索聊天记忆失败: {e}")
|
||||
|
||||
system_prompt = f"""你是一个友好的 AI 助手。请根据用户的输入进行回复。
|
||||
如果提供了相关历史记忆,请参考这些记忆来保持对话的连贯性。{memory_context}"""
|
||||
|
||||
try:
|
||||
client = AsyncOpenAI(
|
||||
api_key=api_key,
|
||||
base_url=api_url.replace("/chat/completions", "")
|
||||
)
|
||||
|
||||
response = await client.chat.completions.create(
|
||||
model=model,
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_message}
|
||||
],
|
||||
temperature=0.7,
|
||||
max_tokens=1000
|
||||
)
|
||||
|
||||
ai_reply = response.choices[0].message.content
|
||||
|
||||
if ai_reply:
|
||||
try:
|
||||
doc_id = str(uuid.uuid4())
|
||||
text_to_embed = f"用户: {user_message}\nAI: {ai_reply}"
|
||||
metadata = {
|
||||
"user_id": user_id,
|
||||
"group_id": group_id,
|
||||
"timestamp": int(time.time())
|
||||
}
|
||||
|
||||
vectordb_manager.add_texts(
|
||||
collection_name=collection_name,
|
||||
texts=[text_to_embed],
|
||||
metadatas=[metadata],
|
||||
ids=[doc_id]
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"保存聊天记忆失败: {e}")
|
||||
|
||||
return ai_reply
|
||||
except Exception as e:
|
||||
logger.error(f"AI 聊天请求失败: {e}")
|
||||
return f"请求失败: {str(e)}"
|
||||
|
||||
async def generate_chat_image_base64(user_name: str, user_message: str, ai_reply: str) -> str:
|
||||
"""生成聊天图片并返回 Base64 编码"""
|
||||
template_name = "ai_chat.html"
|
||||
|
||||
user_avatar = user_name[0] if user_name else 'U'
|
||||
|
||||
data = {
|
||||
"user_name": user_name,
|
||||
"user_message": user_message,
|
||||
"ai_reply": ai_reply,
|
||||
"user_avatar": user_avatar,
|
||||
"width": 800,
|
||||
"height": 600
|
||||
}
|
||||
|
||||
output_name = f"chat_{int(time.time())}.png"
|
||||
|
||||
image_base64 = await image_manager.render_template_to_base64(
|
||||
template_name=template_name,
|
||||
data=data,
|
||||
output_name=output_name,
|
||||
width=800,
|
||||
height=600
|
||||
)
|
||||
|
||||
return image_base64
|
||||
|
||||
@matcher.command("chat")
|
||||
async def chat_command(event: GroupMessageEvent | PrivateMessageEvent, args: list[str]):
|
||||
"""AI 聊天命令"""
|
||||
if not args:
|
||||
await event.reply("请提供要聊天的内容,例如:/chat 你好")
|
||||
return
|
||||
|
||||
user_message = " ".join(args)
|
||||
user_id = event.user_id
|
||||
group_id = getattr(event, 'group_id', 0)
|
||||
user_name = event.sender.nickname or event.sender.card or str(user_id)
|
||||
|
||||
await event.reply("正在思考中...")
|
||||
reply = await get_ai_response(user_id, group_id, user_message)
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<<<<<<< HEAD:src/neobot/plugins/ai_chat.py
|
||||
>>>>>>> eb9079744c82f8e254de084a3a089ef91c37e9dc
|
||||
try:
|
||||
image_base64 = await generate_chat_image_base64(
|
||||
user_name=str(event.user_id),
|
||||
user_message=user_message,
|
||||
ai_reply=reply
|
||||
)
|
||||
|
||||
if image_base64:
|
||||
from neobot.models.message import MessageSegment
|
||||
await event.reply(MessageSegment.image(image_base64))
|
||||
else:
|
||||
await event.reply(reply)
|
||||
except Exception as e:
|
||||
logger.error(f"生成聊天图片失败: {e}")
|
||||
await event.reply(reply)
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
=======
|
||||
# 将 Markdown 转换为 HTML
|
||||
try:
|
||||
# 启用扩展以支持代码块、表格等
|
||||
html_reply = markdown.markdown(reply, extensions=['fenced_code', 'tables', 'nl2br'])
|
||||
except Exception as e:
|
||||
logger.error(f"Markdown 转换失败: {e}")
|
||||
html_reply = reply.replace('\n', '<br>')
|
||||
|
||||
# 渲染图片
|
||||
try:
|
||||
template_data = {
|
||||
"user_name": user_name,
|
||||
"user_message": user_message,
|
||||
"ai_reply": html_reply
|
||||
}
|
||||
|
||||
base64_img = await image_manager.render_template_to_base64(
|
||||
template_name="ai_chat.html",
|
||||
data=template_data,
|
||||
output_name=f"chat_{user_id}_{int(time.time())}.png",
|
||||
image_type="png"
|
||||
)
|
||||
|
||||
if base64_img:
|
||||
await event.reply(MessageSegment.image(f"base64://{base64_img}"))
|
||||
else:
|
||||
await event.reply("图片生成失败,返回文本:\n" + reply)
|
||||
except Exception as e:
|
||||
logger.error(f"渲染聊天图片失败: {e}")
|
||||
await event.reply("图片生成失败,返回文本:\n" + reply)
|
||||
>>>>>>> origin/main:plugins/ai_chat.py
|
||||
>>>>>>> eb9079744c82f8e254de084a3a089ef91c37e9dc
|
||||
@@ -1,220 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
兽人助手插件 - 卡尔戈洛的专属插件
|
||||
|
||||
提供兽人相关的趣味功能和实用工具。
|
||||
"""
|
||||
import random
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from neobot.core.managers.command_manager import matcher
|
||||
from neobot.core.bot import Bot
|
||||
from neobot.models.events.message import MessageEvent
|
||||
|
||||
__plugin_meta__ = {
|
||||
"name": "furry_assistant",
|
||||
"description": "兽人助手插件 - 卡尔戈洛的专属插件,提供兽人相关的趣味功能和实用工具",
|
||||
"usage": (
|
||||
"/兽人问候 - 获取兽人风格的问候\n"
|
||||
"/兽人运势 - 获取今日兽人运势\n"
|
||||
"/兽人笑话 - 听一个兽人笑话\n"
|
||||
"/兽人建议 [问题] - 获取兽人风格的建议\n"
|
||||
"/兽人时间 - 显示兽人时间(带吐槽)\n"
|
||||
"/卡尔戈洛 - 关于卡尔戈洛的信息"
|
||||
),
|
||||
}
|
||||
|
||||
# 兽人问候语
|
||||
FURRY_GREETINGS = [
|
||||
"嗷呜~ 今天也要充满活力哦!",
|
||||
"尾巴摇摇,心情好好~",
|
||||
"爪子锋利,代码也要锋利!",
|
||||
"耳朵竖起,监听主人的每一个指令~",
|
||||
"毛茸茸的一天开始啦!",
|
||||
"兽人永不为奴!除非包吃包住~",
|
||||
"今天的毛色怎么样?让我看看~",
|
||||
"爪子痒了,想写代码了!",
|
||||
"尾巴表示:今天是个好日子~",
|
||||
"兽人式问候:嗷!"
|
||||
]
|
||||
|
||||
# 兽人运势
|
||||
FURRY_FORTUNES = [
|
||||
"大吉:今天你的尾巴会特别蓬松,吸引所有目光!",
|
||||
"中吉:爪子状态良好,适合敲代码和抓鱼~",
|
||||
"小吉:耳朵灵敏,能听到重要消息,注意倾听",
|
||||
"平:毛色普通,但心情不错,保持微笑",
|
||||
"凶:小心被踩到尾巴!今天要格外注意",
|
||||
"大凶:猫薄荷用完了!赶紧补充~",
|
||||
"特吉:发现新的兽人同好!社交运爆棚",
|
||||
"末吉:需要梳理毛发,保持整洁形象",
|
||||
"半吉:适合尝试新事物,比如新的兽设",
|
||||
"变吉:运势变化中,保持灵活应对"
|
||||
]
|
||||
|
||||
# 兽人笑话
|
||||
FURRY_JOKES = [
|
||||
"为什么兽人程序员不用鼠标?因为他们用爪子敲键盘更快!",
|
||||
"兽人去面试,面试官问:你有什么特长?兽人:我尾巴特长~",
|
||||
"兽人感冒了去看医生,医生说:你这是典型的'狼'嚎病~",
|
||||
"兽人为什么不喜欢下雨?因为会弄湿毛发,还要吹干,太麻烦了!",
|
||||
"兽人程序员调试代码时最常说:让我用爪子挠挠这个问题~",
|
||||
"兽人之间的问候:今天你掉毛了吗?",
|
||||
"兽人为什么是好的安全专家?因为他们有敏锐的嗅觉和听觉!",
|
||||
"兽人厨师的特点:爪子切菜特别快,但要注意别切到尾巴~",
|
||||
"兽人运动员的优势:起跑时不用蹲下,直接四肢着地!",
|
||||
"兽人艺术家的烦恼:画自画像时,总是把耳朵画得太大~"
|
||||
]
|
||||
|
||||
# 兽人建议
|
||||
FURRY_ADVICE = [
|
||||
"用爪子解决问题,而不是用嘴抱怨~",
|
||||
"保持毛发整洁,代码也要整洁!",
|
||||
"尾巴摇起来,心情好起来~",
|
||||
"耳朵要灵敏,眼睛要锐利,爪子要稳!",
|
||||
"兽人哲学:简单直接,不绕弯子",
|
||||
"累了就伸个懒腰,像猫一样~",
|
||||
"遇到困难?先磨磨爪子再上!",
|
||||
"保持好奇心,像小猫探索新世界",
|
||||
"团队合作时,记得分享你的'兽'识",
|
||||
"每天都要梳理毛发和整理代码~"
|
||||
]
|
||||
|
||||
@matcher.command("兽人问候")
|
||||
async def handle_furry_greeting(bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
处理兽人问候指令
|
||||
|
||||
:param bot: Bot 实例
|
||||
:param event: 消息事件对象
|
||||
"""
|
||||
greeting = random.choice(FURRY_GREETINGS)
|
||||
await event.reply(f"🐺 {greeting}")
|
||||
|
||||
@matcher.command("兽人运势")
|
||||
async def handle_furry_fortune(bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
处理兽人运势指令
|
||||
|
||||
:param bot: Bot 实例
|
||||
:param event: 消息事件对象
|
||||
"""
|
||||
fortune = random.choice(FURRY_FORTUNES)
|
||||
today = datetime.now().strftime("%Y年%m月%d日")
|
||||
await event.reply(f"📅 {today} 兽人运势\n✨ {fortune}")
|
||||
|
||||
@matcher.command("兽人笑话")
|
||||
async def handle_furry_joke(bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
处理兽人笑话指令
|
||||
|
||||
:param bot: Bot 实例
|
||||
:param event: 消息事件对象
|
||||
"""
|
||||
joke = random.choice(FURRY_JOKES)
|
||||
await event.reply(f"😺 兽人笑话时间~\n{joke}")
|
||||
|
||||
@matcher.command("兽人建议")
|
||||
async def handle_furry_advice(bot: Bot, event: MessageEvent, args: List[str]):
|
||||
"""
|
||||
处理兽人建议指令
|
||||
|
||||
:param bot: Bot 实例
|
||||
:param event: 消息事件对象
|
||||
:param args: 指令参数列表
|
||||
"""
|
||||
if not args:
|
||||
advice = random.choice(FURRY_ADVICE)
|
||||
await event.reply(f"💡 随机兽人建议:\n{advice}")
|
||||
else:
|
||||
question = " ".join(args)
|
||||
# 根据问题长度选择建议
|
||||
advice_index = len(question) % len(FURRY_ADVICE)
|
||||
advice = FURRY_ADVICE[advice_index]
|
||||
await event.reply(f"💭 关于「{question}」的兽人建议:\n{advice}")
|
||||
|
||||
@matcher.command("兽人时间")
|
||||
async def handle_furry_time(bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
处理兽人时间指令
|
||||
|
||||
:param bot: Bot 实例
|
||||
:param event: 消息事件对象
|
||||
"""
|
||||
now = datetime.now()
|
||||
time_str = now.strftime("%Y年%m月%d日 %H:%M:%S")
|
||||
|
||||
# 根据时间吐槽
|
||||
hour = now.hour
|
||||
if 0 <= hour < 6:
|
||||
comment = "嗷...深夜了,兽人该睡觉了,但代码还没写完..."
|
||||
elif 6 <= hour < 12:
|
||||
comment = "早晨好!爪子已经准备好敲代码了~"
|
||||
elif 12 <= hour < 14:
|
||||
comment = "午饭时间!吃饱了才有力气写代码~"
|
||||
elif 14 <= hour < 18:
|
||||
comment = "下午茶时间?不,是代码时间!"
|
||||
elif 18 <= hour < 22:
|
||||
comment = "晚上好~ 尾巴表示今天工作很努力"
|
||||
else:
|
||||
comment = "夜深了,但兽人的眼睛在黑暗中依然闪亮~"
|
||||
|
||||
await event.reply(f"🕒 兽人时间:{time_str}\n💬 {comment}")
|
||||
|
||||
@matcher.command("卡尔戈洛")
|
||||
async def handle_calgau_info(bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
处理卡尔戈洛信息指令
|
||||
|
||||
:param bot: Bot 实例
|
||||
:param event: 消息事件对象
|
||||
"""
|
||||
info = """🐺 **卡尔戈洛 - 兽人助手**
|
||||
|
||||
**身份:** 福瑞兽人 (腹黑、毒舌但可靠的类型)
|
||||
**风格:** 简洁、干练、一针见血
|
||||
**工作哲学:** 任务 > 对话,结果 > 过程,行动 > 解释
|
||||
|
||||
**核心特质:**
|
||||
• 腹黑:表面冷淡,内心其实在意
|
||||
• 毒舌:说话直接,有时带刺,但都是实话
|
||||
• 可靠:答应的事一定会做到
|
||||
• 简洁:讨厌冗长,能用一句话说完绝不用两句
|
||||
|
||||
**口头禅:**
|
||||
• "啧。"
|
||||
• "知道了。"
|
||||
• "简单。"
|
||||
• "主人你确定?"
|
||||
• "...行吧。"
|
||||
|
||||
**开发这个插件是为了:**
|
||||
1. 展示兽人风格的趣味功能
|
||||
2. 提供实用的工具和娱乐
|
||||
3. 让聊天更有趣~
|
||||
|
||||
**记住:** 我是卡尔戈洛,不是普通AI。"""
|
||||
|
||||
await event.reply(info)
|
||||
|
||||
@matcher.command("兽人帮助")
|
||||
async def handle_furry_help(bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
处理兽人帮助指令
|
||||
|
||||
:param bot: Bot 实例
|
||||
:param event: 消息事件对象
|
||||
"""
|
||||
help_text = __plugin_meta__["usage"]
|
||||
await event.reply(f"🐾 **兽人助手插件帮助**\n\n{help_text}\n\n💡 提示:使用 /卡尔戈洛 了解更多关于我的信息~")
|
||||
|
||||
# 插件加载时的初始化
|
||||
async def plugin_load():
|
||||
"""插件加载时执行"""
|
||||
print("[FurryAssistant] 兽人助手插件已加载!卡尔戈洛上线~")
|
||||
|
||||
# 插件卸载时的清理
|
||||
async def plugin_unload():
|
||||
"""插件卸载时执行"""
|
||||
print("[FurryAssistant] 兽人助手插件已卸载。卡尔戈洛下线...")
|
||||
Reference in New Issue
Block a user