diff --git a/discord_bot/ai_bots/ai_bot_3/claude_bot.py b/discord_bot/ai_bots/ai_bot_3/claude_bot.py index cd1d510..26e6ed0 100644 --- a/discord_bot/ai_bots/ai_bot_3/claude_bot.py +++ b/discord_bot/ai_bots/ai_bot_3/claude_bot.py @@ -8,10 +8,10 @@ Claude Discord Bot Claude以其安全性、有用性和诚实性而闻名。 主要功能: -- /claude - 与Claude AI对话 -- /analyze - 深度分析问题(Claude的强项) -- /creative - 创意写作和头脑风暴 -- /help - 显示帮助信息 +- @mention对话 - 与Claude AI对话 +- @mention analyze - 深度分析问题(Claude的强项) +- @mention creative - 创意写作和头脑风暴 +- @mention help - 显示帮助信息 """ import discord @@ -82,65 +82,78 @@ class ClaudeBot: self.claude_client = Anthropic(api_key=api_key) logger.info("Claude客户端初始化成功") - # 同步slash commands - synced = await self.bot.tree.sync() - logger.info(f"同步了 {len(synced)} 个slash commands") - except Exception as e: logger.error(f"初始化Claude客户端失败: {e}") @self.bot.event - async def on_command_error(ctx, error): - logger.error(f"命令错误: {error}") - if isinstance(error, commands.CommandNotFound): - await ctx.send("未知命令,请使用 /help 查看可用命令") - else: - await ctx.send(f"执行命令时出错: {str(error)}") - - def setup_commands(self): - """设置slash commands""" - - @self.bot.tree.command(name="claude", description="与Claude AI对话") - async def claude_command(interaction: discord.Interaction, message: str): - """处理Claude聊天命令""" - try: - await interaction.response.defer(thinking=True) + async def on_message(message): + if message.author == self.bot.user: + return + + if self.bot.user.mentioned_in(message): + content = message.content.replace(f'<@{self.bot.user.id}>', '').replace(f'<@!{self.bot.user.id}>', '').strip() - if not self.claude_client: - await interaction.followup.send("❌ Claude客户端未初始化") + if not content: + help_text = """🎭 **Claude Bot 帮助** + +**使用方法:** +• @Calude 你的问题 - 与Claude AI对话 +• @Calude analyze 深度分析问题 - 深度分析主题 +• @Calude creative 创意写作提示 - 创意写作 +• @Calude model 模型名 - 切换模型 +• @Calude help - 显示帮助 + +**可用模型:** +• claude-3-sonnet-20240229 (默认) +• claude-3-haiku-20240307 +• claude-3-opus-20240229 + +**当前模型:** {} +**状态:** ✅ 在线""".format(self.current_model) + await message.reply(help_text) return - # 调用Claude API - response = await asyncio.to_thread( - self.claude_client.messages.create, - model=self.current_model, - max_tokens=2000, - messages=[ - {"role": "user", "content": message} - ] - ) - - ai_response = response.content[0].text - - # 分段发送长回复 - await self.send_long_response(interaction, f"🎭 **Claude ({self.current_model})**\\n\\n{ai_response}") - - except Exception as e: - logger.error(f"Claude命令错误: {e}") - await interaction.followup.send(f"❌ Claude API调用失败: {str(e)}") - - @self.bot.tree.command(name="analyze", description="使用Claude进行深度分析") - async def analyze_command(interaction: discord.Interaction, topic: str): - """处理分析命令""" - try: - await interaction.response.defer(thinking=True) - - if not self.claude_client: - await interaction.followup.send("❌ Claude客户端未初始化") + if content.lower().startswith('help'): + help_text = """🎭 **Claude Bot 帮助** + +**使用方法:** +• @Calude 你的问题 - 与Claude AI对话 +• @Calude analyze 深度分析问题 - 深度分析主题 +• @Calude creative 创意写作提示 - 创意写作 +• @Calude model 模型名 - 切换模型 +• @Calude help - 显示帮助 + +**可用模型:** +• claude-3-sonnet-20240229 (默认) +• claude-3-haiku-20240307 +• claude-3-opus-20240229 + +**当前模型:** {} +**状态:** ✅ 在线""".format(self.current_model) + await message.reply(help_text) return - # 分析提示词 - analysis_prompt = f"""请对以下主题进行深度分析: + if content.lower().startswith('model '): + model = content[6:].strip() + if model in self.available_models: + old_model = self.current_model + self.current_model = model + await message.reply(f"✅ 模型已从 `{old_model}` 切换到 `{model}`") + else: + model_list = "\n".join([f"• {m}" for m in self.available_models]) + await message.reply(f"❌ 不支持的模型。可用模型:\n{model_list}") + return + + if content.lower().startswith('analyze '): + topic = content[8:].strip() + if not topic: + await message.reply("请提供要分析的主题") + return + + try: + typing_task = asyncio.create_task(self.start_typing(message.channel)) + + analysis_prompt = f"""请对以下主题进行深度分析: {topic} @@ -152,135 +165,148 @@ class ClaudeBot: 5. 未来的发展趋势 请提供详细、有条理的分析。""" - - response = await asyncio.to_thread( - self.claude_client.messages.create, - model=self.current_model, - max_tokens=3000, - messages=[ - {"role": "user", "content": analysis_prompt} - ] - ) - - ai_response = response.content[0].text - - # 分段发送长回复 - await self.send_long_response(interaction, f"🔍 **Claude 深度分析**\\n\\n{ai_response}") - - except Exception as e: - logger.error(f"分析命令错误: {e}") - await interaction.followup.send(f"❌ Claude 分析失败: {str(e)}") - - @self.bot.tree.command(name="creative", description="使用Claude进行创意写作") - async def creative_command(interaction: discord.Interaction, prompt: str): - """处理创意写作命令""" - try: - await interaction.response.defer(thinking=True) - - if not self.claude_client: - await interaction.followup.send("❌ Claude客户端未初始化") + + response = await asyncio.wait_for( + asyncio.to_thread( + self.claude_client.messages.create, + model=self.current_model, + max_tokens=2000, + messages=[ + {"role": "user", "content": analysis_prompt} + ] + ), + timeout=30.0 + ) + + typing_task.cancel() + + ai_response = response.content[0].text + await self.send_long_message(message, f"🔍 **Claude 深度分析**\n\n{ai_response}") + + except asyncio.TimeoutError: + typing_task.cancel() + await message.reply("⏰ Claude API响应超时,请稍后重试") + return + except Exception as e: + typing_task.cancel() + logger.error(f"Claude分析调用错误: {e}") + await message.reply(f"❌ Claude 分析失败: {str(e)}") + return return - # 创意写作提示词 - creative_prompt = f"""作为一个富有创意的作家,请根据以下提示进行创意写作: + if content.lower().startswith('creative '): + prompt = content[9:].strip() + if not prompt: + await message.reply("请提供创意写作提示") + return + + try: + typing_task = asyncio.create_task(self.start_typing(message.channel)) + + creative_prompt = f"""作为一个富有创意的作家,请根据以下提示进行创意写作: {prompt} 请发挥你的想象力,创作出有趣、引人入胜的内容。可以是故事、诗歌、对话、或任何其他创意形式。注重创意性、情感表达和文学性。""" - - response = await asyncio.to_thread( - self.claude_client.messages.create, - model=self.current_model, - max_tokens=2500, - messages=[ - {"role": "user", "content": creative_prompt} - ] - ) - - ai_response = response.content[0].text - - # 分段发送长回复 - await self.send_long_response(interaction, f"✨ **Claude 创意工坊**\\n\\n{ai_response}") - - except Exception as e: - logger.error(f"创意命令错误: {e}") - await interaction.followup.send(f"❌ Claude 创意写作失败: {str(e)}") - - @self.bot.tree.command(name="model", description="切换Claude模型") - async def model_command(interaction: discord.Interaction, model: str): - """切换模型命令""" - try: - if model not in self.available_models: - model_list = "\\n".join([f"• {m}" for m in self.available_models]) - await interaction.response.send_message( - f"❌ 不支持的模型。可用模型:\\n{model_list}" - ) + + response = await asyncio.wait_for( + asyncio.to_thread( + self.claude_client.messages.create, + model=self.current_model, + max_tokens=2000, + messages=[ + {"role": "user", "content": creative_prompt} + ] + ), + timeout=30.0 + ) + + typing_task.cancel() + + ai_response = response.content[0].text + await self.send_long_message(message, f"✨ **Claude 创意工坊**\n\n{ai_response}") + + except asyncio.TimeoutError: + typing_task.cancel() + await message.reply("⏰ Claude API响应超时,请稍后重试") + return + except Exception as e: + typing_task.cancel() + logger.error(f"Claude创意调用错误: {e}") + await message.reply(f"❌ Claude 创意写作失败: {str(e)}") + return return - old_model = self.current_model - self.current_model = model - - await interaction.response.send_message( - f"✅ 模型已从 `{old_model}` 切换到 `{model}`" - ) - - except Exception as e: - logger.error(f"模型切换错误: {e}") - await interaction.response.send_message(f"❌ 切换模型失败: {str(e)}") + try: + if not self.claude_client: + await message.reply("❌ Claude客户端未初始化") + return + + typing_task = asyncio.create_task(self.start_typing(message.channel)) + + response = await asyncio.wait_for( + asyncio.to_thread( + self.claude_client.messages.create, + model=self.current_model, + max_tokens=2000, + messages=[ + {"role": "user", "content": content} + ] + ), + timeout=30.0 + ) + + typing_task.cancel() + + ai_response = response.content[0].text + await self.send_long_message(message, f"🎭 **Claude ({self.current_model})**\n\n{ai_response}") + + except asyncio.TimeoutError: + typing_task.cancel() + await message.reply("⏰ Claude API响应超时,请稍后重试") + except Exception as e: + typing_task.cancel() + logger.error(f"Claude调用错误: {e}") + await message.reply(f"❌ Claude API调用失败: {str(e)}") - @self.bot.tree.command(name="help", description="显示Claude Bot帮助信息") - async def help_command(interaction: discord.Interaction): - """显示帮助信息""" - help_text = """🎭 **Claude Bot 帮助** - -**主要命令:** -• `/claude ` - 与Claude AI对话 -• `/analyze ` - 深度分析主题 -• `/creative ` - 创意写作 -• `/model ` - 切换Claude模型 -• `/help` - 显示此帮助信息 - -**可用模型:** -• `claude-3-sonnet-20240229` (默认,平衡性能) -• `claude-3-haiku-20240307` (快速响应) -• `claude-3-opus-20240229` (最强推理) - -**Claude特色:** -• 🎭 安全、有用、诚实 -• 🔍 强大的分析能力 -• ✨ 出色的创意写作 -• 🧠 逻辑推理和问题解决 - -**使用示例:** -• `/claude 你好,请介绍一下你自己` -• `/analyze 人工智能的发展趋势` -• `/creative 写一个关于时间旅行的短故事` - -**当前模型:** `{}` -**状态:** ✅ 在线""".format(self.current_model) - - await interaction.response.send_message(help_text) + @self.bot.event + async def on_command_error(ctx, error): + logger.error(f"命令错误: {error}") + await ctx.send(f"执行命令时出错: {str(error)}") - async def send_long_response(self, interaction: discord.Interaction, response: str): - """分段发送长响应""" + async def start_typing(self, channel): + """持续显示正在输入状态""" + try: + while True: + async with channel.typing(): + await asyncio.sleep(5) + except asyncio.CancelledError: + pass + + def setup_commands(self): + """保留slash commands作为备用""" + pass + + async def send_long_message(self, message, response: str): + """分段发送长回复到消息""" max_length = 2000 if len(response) <= max_length: - await interaction.followup.send(response) + await message.reply(response) return # 分段处理 parts = [] current_part = "" - for line in response.split('\\n'): + for line in response.split('\n'): if len(current_part) + len(line) + 1 > max_length: if current_part: parts.append(current_part) current_part = line else: if current_part: - current_part += '\\n' + line + current_part += '\n' + line else: current_part = line @@ -289,9 +315,9 @@ class ClaudeBot: # 发送所有部分 if parts: - await interaction.followup.send(parts[0]) + await message.reply(parts[0]) for part in parts[1:]: - await interaction.followup.send(part) + await message.channel.send(part) async def start(self): """启动bot"""