Files
Bubbles/commands/ai_functions.py
2025-09-24 08:34:34 +08:00

411 lines
13 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
AI路由功能注册
将需要通过AI路由的功能在这里注册
"""
import re
import json
import os
from typing import Optional, Match
from datetime import datetime
from .ai_router import ai_router
from .context import MessageContext
# ======== 天气功能 ========
@ai_router.register(
name="weather_query",
description="查询城市未来五天的简要天气预报",
parameters={
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "要查询天气的城市名称,如:北京、上海、深圳"
}
},
"required": ["city"]
}
)
def ai_handle_weather(ctx: MessageContext, city: str, **kwargs) -> bool:
"""AI路由的天气查询处理"""
city_name = city.strip()
if not city_name:
ctx.send_text("🤔 请告诉我你想查询哪个城市的天气")
return True
# 加载城市代码
city_codes = {}
city_code_path = os.path.join(os.path.dirname(__file__), '..', 'function', 'main_city.json')
try:
with open(city_code_path, 'r', encoding='utf-8') as f:
city_codes = json.load(f)
except Exception as e:
if ctx.logger:
ctx.logger.error(f"加载城市代码文件失败: {e}")
ctx.send_text("⚠️ 抱歉,天气功能暂时不可用")
return True
# 查找城市代码
city_code = city_codes.get(city_name)
if not city_code:
# 尝试模糊匹配
for name, code in city_codes.items():
if city_name in name:
city_code = code
city_name = name
break
if not city_code:
ctx.send_text(f"😕 找不到城市 '{city_name}' 的天气信息")
return True
# 获取天气信息
try:
from function.func_weather import Weather
weather_info = Weather(city_code).get_weather(include_forecast=True)
ctx.send_text(weather_info)
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"获取天气信息失败: {e}")
ctx.send_text(f"😥 获取 {city_name} 天气时遇到问题")
return True
# ======== 新闻功能 ========
@ai_router.register(
name="news_query",
description="获取今日重要新闻和要闻",
parameters={
"type": "object",
"properties": {},
"required": []
}
)
def ai_handle_news(ctx: MessageContext, **kwargs) -> bool:
"""AI路由的新闻查询处理"""
try:
from function.func_news import News
news_instance = News()
is_today, news_content = news_instance.get_important_news()
if is_today:
ctx.send_text(f"📰 今日要闻来啦:\n{news_content}")
else:
if news_content:
ctx.send_text(f" 今日新闻暂未发布,为您找到最近的一条新闻:\n{news_content}")
else:
ctx.send_text("❌ 获取新闻失败,请稍后重试")
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"获取新闻失败: {e}")
ctx.send_text("❌ 获取新闻时发生错误")
return True
# ======== 提醒功能 ========
@ai_router.register(
name="reminder_set",
description="为用户设置一个新的提醒",
parameters={
"type": "object",
"properties": {
"content": {
"type": "string",
"description": "提醒的具体内容和时间明天下午3点开会、每天早上8点吃早餐"
}
},
"required": ["content"]
}
)
def ai_handle_reminder_set(ctx: MessageContext, content: str, **kwargs) -> bool:
"""AI路由的提醒设置处理"""
if not content.strip():
at_list = ctx.msg.sender if ctx.is_group else ""
ctx.send_text("请告诉我需要提醒什么内容和时间呀~", at_list)
return True
# 调用原有的提醒处理逻辑
from .handlers import handle_reminder
# 临时修改消息内容以适配原有处理器
original_content = ctx.msg.content
ctx.msg.content = f"提醒我{content}"
# handle_reminder不使用match参数直接传None
result = handle_reminder(ctx, None)
# 恢复原始内容
ctx.msg.content = original_content
return result
@ai_router.register(
name="reminder_list",
description="查看用户已经设置的所有提醒列表",
parameters={
"type": "object",
"properties": {},
"required": []
}
)
def ai_handle_reminder_list(ctx: MessageContext, **kwargs) -> bool:
"""AI路由的提醒列表查看处理"""
from .handlers import handle_list_reminders
return handle_list_reminders(ctx, None)
@ai_router.register(
name="reminder_delete",
description="删除指定的提醒",
parameters={
"type": "object",
"properties": {
"description": {
"type": "string",
"description": "要删除的提醒的描述或关键词,如:开会、早餐、明天的提醒"
}
},
"required": ["description"]
}
)
def ai_handle_reminder_delete(ctx: MessageContext, description: str, **kwargs) -> bool:
"""AI路由的提醒删除处理"""
# 调用原有的删除提醒逻辑
from .handlers import handle_delete_reminder
# 临时修改消息内容
original_content = ctx.msg.content
ctx.msg.content = f"删除提醒 {description}"
# handle_delete_reminder不使用match参数直接传None
result = handle_delete_reminder(ctx, None)
# 恢复原始内容
ctx.msg.content = original_content
return result
# ======== 帮助功能 ========
@ai_router.register(
name="help",
description="显示机器人的帮助信息和可用指令列表",
parameters={
"type": "object",
"properties": {},
"required": []
}
)
def ai_handle_help(ctx: MessageContext, **kwargs) -> bool:
"""AI路由的帮助处理"""
help_text = [
"🤖 泡泡智能助手 🤖",
"",
"🌟 我现在支持自然语言交互!你可以用平常说话的方式和我对话:",
"",
"【天气查询】",
"💬 \"北京今天天气怎么样\"",
"💬 \"上海明天会下雨吗\"",
"💬 \"查一下深圳的天气预报\"",
"",
"【新闻资讯】",
"💬 \"看看今天的新闻\"",
"💬 \"有什么重要新闻吗\"",
"",
"【智能提醒】",
"💬 \"提醒我明天下午3点开会\"",
"💬 \"每天早上8点提醒我吃早餐\"",
"💬 \"查看我的提醒\"",
"💬 \"删掉开会的提醒\"",
"",
"【智能搜索】",
"💬 \"搜索Python最新特性\"",
"💬 \"查一下机器学习教程\"",
"",
"【群聊管理】",
"💬 \"总结一下最近的聊天\" (仅群聊)",
"💬 \"清除聊天历史\" (仅群聊)",
"💬 \"查看我的装备\" (仅群聊)",
"",
"【娱乐功能】",
"💬 \"骂一下@张三\" (仅群聊)",
"",
"✨ 直接用自然语言告诉我你想做什么,我会智能理解你的意图!",
"🔧 在群聊中需要@我才能使用功能哦~"
]
help_message = "\n".join(help_text)
# 发送消息
ctx.send_text(help_message)
return True
# ======== 消息管理功能 ========
@ai_router.register(
name="summary",
description="总结群聊中最近的聊天消息内容",
parameters={
"type": "object",
"properties": {},
"required": []
}
)
def ai_handle_summary(ctx: MessageContext, **kwargs) -> bool:
"""AI路由的消息总结处理"""
if not ctx.is_group:
ctx.send_text("⚠️ 消息总结功能仅支持群聊")
return True
from .handlers import handle_summary
return handle_summary(ctx, None)
@ai_router.register(
name="clear_messages",
description="清除当前群聊的历史消息记录",
parameters={
"type": "object",
"properties": {},
"required": []
}
)
def ai_handle_clear_messages(ctx: MessageContext, **kwargs) -> bool:
"""AI路由的消息历史清除处理"""
if not ctx.is_group:
ctx.send_text("⚠️ 消息历史管理功能仅支持群聊")
return True
from .handlers import handle_clear_messages
return handle_clear_messages(ctx, None)
# ======== 决斗功能 ========
@ai_router.register(
name="check_equipment",
description="查看玩家在决斗游戏中的魔法装备和道具",
parameters={
"type": "object",
"properties": {},
"required": []
}
)
def ai_handle_check_equipment(ctx: MessageContext, **kwargs) -> bool:
"""AI路由的装备查看处理"""
if not ctx.is_group:
ctx.send_text("❌ 装备查看功能只支持群聊")
return True
from .handlers import handle_check_equipment
return handle_check_equipment(ctx, None)
# ======== 娱乐功能 ========
@ai_router.register(
name="insult_user",
description="骂指定的用户(娱乐功能,无恶意)",
parameters={
"type": "object",
"properties": {
"target_user": {
"type": "string",
"description": "要骂的目标用户的名称或昵称"
}
},
"required": ["target_user"]
}
)
def ai_handle_insult(ctx: MessageContext, target_user: str, **kwargs) -> bool:
"""AI路由的骂人处理"""
if not ctx.is_group:
ctx.send_text("❌ 骂人功能只支持群聊")
return True
# 解析参数,提取用户名
user_name = target_user.strip()
if not user_name:
ctx.send_text("🤔 请告诉我要骂谁")
return True
# 移除@符号
user_name = user_name.replace("@", "").strip()
# 创建一个假的match对象因为原始处理器需要
fake_match = type('MockMatch', (), {
'group': lambda self, n: user_name if n == 1 else None
})()
from .handlers import handle_insult
# 临时修改消息内容以适配原有处理器
original_content = ctx.msg.content
ctx.msg.content = f"骂一下@{user_name}"
result = handle_insult(ctx, fake_match)
# 恢复原始内容
ctx.msg.content = original_content
return result
# ======== Perplexity搜索功能 ========
@ai_router.register(
name="perplexity_search",
description="使用Perplexity搜索查询资料并深度研究某个专业问题",
parameters={
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "要搜索的关键词或问题Python最新特性、机器学习教程"
}
},
"required": ["query"]
}
)
def ai_handle_perplexity(ctx: MessageContext, query: str, **kwargs) -> bool:
"""AI路由的Perplexity搜索处理"""
if not query.strip():
at_list = ctx.msg.sender if ctx.is_group else ""
ctx.send_text("请告诉我你想搜索什么内容", at_list)
return True
# 获取Perplexity实例
perplexity_instance = getattr(ctx.robot, 'perplexity', None)
if not perplexity_instance:
ctx.send_text("❌ Perplexity搜索功能当前不可用")
return True
# 调用Perplexity处理
content_for_perplexity = f"ask {query}"
chat_id = ctx.get_receiver()
sender_wxid = ctx.msg.sender
room_id = ctx.msg.roomid if ctx.is_group else None
is_group = ctx.is_group
was_handled, fallback_prompt = perplexity_instance.process_message(
content=content_for_perplexity,
chat_id=chat_id,
sender=sender_wxid,
roomid=room_id,
from_group=is_group,
send_text_func=ctx.send_text
)
# 如果Perplexity无法处理使用默认AI
if not was_handled and fallback_prompt:
chat_model = getattr(ctx, 'chat', None) or (getattr(ctx.robot, 'chat', None) if ctx.robot else None)
if chat_model:
try:
import time
current_time = time.strftime("%H:%M", time.localtime())
q_with_info = f"[{current_time}] {ctx.sender_name}: {query}"
rsp = chat_model.get_answer(
question=q_with_info,
wxid=ctx.get_receiver(),
system_prompt_override=fallback_prompt
)
if rsp:
at_list = ctx.msg.sender if ctx.is_group else ""
ctx.send_text(rsp, at_list)
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"默认AI处理失败: {e}")
return was_handled