perplexity

This commit is contained in:
zihanjian
2025-09-25 21:50:09 +08:00
parent db63ebfb6e
commit f45abe125c
3 changed files with 113 additions and 30 deletions

View File

@@ -14,7 +14,17 @@ from openai import OpenAI
class PerplexityThread(Thread):
"""处理Perplexity请求的线程"""
def __init__(self, perplexity_instance, prompt, chat_id, send_text_func, receiver, at_user=None, on_finish: Optional[Callable[[], None]] = None):
def __init__(
self,
perplexity_instance,
prompt,
chat_id,
send_text_func,
receiver,
at_user=None,
on_finish: Optional[Callable[[], None]] = None,
enable_full_research: bool = False,
):
"""初始化Perplexity处理线程
Args:
@@ -34,13 +44,12 @@ class PerplexityThread(Thread):
self.at_user = at_user
self.LOG = logging.getLogger("PerplexityThread")
self.on_finish = on_finish
self.enable_full_research = enable_full_research
# 检查是否使用reasoning模型
self.is_reasoning_model = False
if hasattr(self.perplexity, 'config'):
model_name = self.perplexity.config.get('model', 'sonar').lower()
self.is_reasoning_model = 'reasoning' in model_name
self.LOG.info(f"Perplexity使用模型: {model_name}, 是否为reasoning模型: {self.is_reasoning_model}")
self.is_reasoning_model = bool(self.enable_full_research and getattr(self.perplexity, 'has_reasoning_model', False))
if self.is_reasoning_model:
self.LOG.info("Perplexity将启用推理模型处理此次请求")
def run(self):
"""线程执行函数"""
@@ -48,7 +57,11 @@ class PerplexityThread(Thread):
self.LOG.info(f"开始处理Perplexity请求: {self.prompt[:30]}...")
# 获取回答
response = self.perplexity.get_answer(self.prompt, self.chat_id)
response = self.perplexity.get_answer(
self.prompt,
self.chat_id,
deep_research=self.enable_full_research
)
# 处理sonar-reasoning和sonar-reasoning-pro模型的<think>标签
if response:
@@ -184,7 +197,16 @@ class PerplexityManager:
self.lock = Lock()
self.LOG = logging.getLogger("PerplexityManager")
def start_request(self, perplexity_instance, prompt, chat_id, send_text_func, receiver, at_user=None):
def start_request(
self,
perplexity_instance,
prompt,
chat_id,
send_text_func,
receiver,
at_user=None,
enable_full_research: bool = False,
):
"""启动Perplexity请求线程
Args:
@@ -194,12 +216,14 @@ class PerplexityManager:
send_text_func: 发送消息的函数
receiver: 接收消息的ID
at_user: 被@的用户ID
enable_full_research: 是否启用深度研究模式
Returns:
bool: 是否成功启动线程
"""
thread_key = f"{receiver}_{chat_id}"
full_research_available = enable_full_research and getattr(perplexity_instance, 'has_reasoning_model', False)
with self.lock:
# 检查是否已有正在处理的相同请求
if thread_key in self.threads and self.threads[thread_key].is_alive():
@@ -207,7 +231,10 @@ class PerplexityManager:
return False
# 发送等待消息
send_text_func("正在联网查询,请稍候...", record_message=False)
wait_msg = "正在启用满血模式研究中...." if full_research_available else "正在联网查询,请稍候..."
if enable_full_research and not full_research_available:
self.LOG.warning("收到满血模式请求,但未配置推理模型,退回普通模式。")
send_text_func(wait_msg, at_list=at_user or "", record_message=False)
# 添加线程完成回调,自动清理线程
def thread_finished_callback():
@@ -224,7 +251,8 @@ class PerplexityManager:
send_text_func=send_text_func,
receiver=receiver,
at_user=at_user,
on_finish=thread_finished_callback
on_finish=thread_finished_callback,
enable_full_research=full_research_available
)
# 保存线程引用
@@ -276,6 +304,11 @@ class Perplexity:
self.trigger_keyword = config.get('trigger_keyword', 'ask')
self.fallback_prompt = config.get('fallback_prompt', "请像 Perplexity 一样以专业、客观、信息丰富的方式回答问题。不要使用任何tex或者md格式,纯文本输出。")
self.LOG = logging.getLogger('Perplexity')
self.model_flash = config.get('model_flash') or config.get('model', 'sonar')
self.model_reasoning = config.get('model_reasoning')
if self.model_reasoning and self.model_reasoning.lower() == (self.model_flash or '').lower():
self.model_reasoning = None
self.has_reasoning_model = bool(self.model_reasoning)
# 权限控制 - 允许使用Perplexity的群聊和个人ID
self.allowed_groups = config.get('allowed_groups', [])
@@ -346,7 +379,7 @@ class Perplexity:
return all(value is not None for key, value in args.items() if key != 'proxy')
return False
def get_answer(self, prompt, session_id=None):
def get_answer(self, prompt, session_id=None, deep_research: bool = False):
"""获取Perplexity回答
Args:
@@ -367,7 +400,9 @@ class Perplexity:
]
# 获取模型
model = self.config.get('model', 'sonar')
model = self.model_reasoning if (deep_research and self.has_reasoning_model) else self.model_flash or self.config.get('model', 'sonar')
if deep_research and self.has_reasoning_model:
self.LOG.info(f"Perplexity启动深度研究模式使用模型: {model}")
# 使用json序列化确保正确处理Unicode
self.LOG.info(f"发送到Perplexity的消息: {json.dumps(messages, ensure_ascii=False)}")
@@ -385,7 +420,16 @@ class Perplexity:
self.LOG.error(f"调用Perplexity API时发生错误: {str(e)}")
return f"发生错误: {str(e)}"
def process_message(self, content, chat_id, sender, roomid, from_group, send_text_func):
def process_message(
self,
content,
chat_id,
sender,
roomid,
from_group,
send_text_func,
enable_full_research: bool = False,
):
"""处理可能包含Perplexity触发词的消息
Args:
@@ -395,6 +439,7 @@ class Perplexity:
roomid: 群聊ID如果是群聊
from_group: 是否来自群聊
send_text_func: 发送消息的函数
enable_full_research: 是否启用深度研究模式
Returns:
tuple[bool, Optional[str]]:
@@ -414,9 +459,11 @@ class Perplexity:
return False, self.fallback_prompt # 返回 False 表示未处理,并带上备选 prompt
else:
# 如果只有触发词没有问题,还是按原逻辑处理(发送提示消息)
send_text_func(f"请在{self.trigger_keyword}后面添加您的问题",
roomid if from_group else sender,
sender if from_group else None)
send_text_func(
f"请在{self.trigger_keyword}后面添加您的问题",
at_list=sender if from_group else "",
record_message=False
)
return True, None # 已处理(发送了错误提示)
prompt = content[len(self.trigger_keyword):].strip()
@@ -432,14 +479,17 @@ class Perplexity:
chat_id=chat_id,
send_text_func=send_text_func,
receiver=receiver,
at_user=at_user
at_user=at_user,
enable_full_research=enable_full_research
)
return request_started, None # 返回启动结果无备选prompt
else:
# 触发词后没有内容
send_text_func(f"请在{self.trigger_keyword}后面添加您的问题",
roomid if from_group else sender,
sender if from_group else None)
send_text_func(
f"请在{self.trigger_keyword}后面添加您的问题",
at_list=sender if from_group else "",
record_message=False
)
return True, None # 已处理(发送了错误提示)
# 不包含触发词

View File

@@ -72,36 +72,65 @@ def ai_handle_reminder_delete(ctx: MessageContext, params: str) -> bool:
@ai_router.register(
name="perplexity_search",
description="在网络上搜索任何问题",
examples=["搜索Python最新特性", "查查机器学习教程","深圳天气怎么样"],
params_description="搜索内容"
examples=[
"搜索Python最新特性",
"查查机器学习教程",
'{"query":"量子计算发展", "deep_research": false}'
],
params_description="可直接填写搜索内容;若问题极其复杂且需要长时间深度研究,能接收花费大量时间和费用,请传 JSON{\"query\":\"主题\", \"deep_research\": true}\n只有当问题确实十分复杂、需要长时间联网深度研究时,才在 params 中加入 JSON 字段 \"deep_research\": true否则保持默认以节省时间和费用。"
)
def ai_handle_perplexity(ctx: MessageContext, params: str) -> bool:
"""AI路由的Perplexity搜索处理"""
if not params.strip():
import json
params = params.strip()
if not params:
at_list = ctx.msg.sender if ctx.is_group else ""
ctx.send_text("请告诉我你想搜索什么内容", at_list)
return True
deep_research = False
query = params
if params.startswith("{"):
try:
parsed = json.loads(params)
if isinstance(parsed, dict):
query = parsed.get("query") or parsed.get("q") or ""
mode = parsed.get("mode") or parsed.get("research_mode")
deep_research = bool(parsed.get("deep_research") or parsed.get("full_research") or (isinstance(mode, str) and mode.lower() in {"deep", "full", "research"}))
except json.JSONDecodeError:
query = params
if not isinstance(query, str):
query = str(query or "")
query = query.strip()
if not query:
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 {params}"
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
send_text_func=ctx.send_text,
enable_full_research=deep_research
)
# 如果Perplexity无法处理使用默认AI

View File

@@ -69,7 +69,11 @@ class AIRouter:
if func.examples:
prompt += f"\n 示例: {', '.join(func.examples[:3])}"
prompt += "\n"
prompt += """
对于 perplexity_search只有当问题确实十分复杂、需要长时间联网深度研究时才在 params 中加入 JSON 字段 "deep_research": true否则保持默认以节省时间和费用。
"""
prompt += """
请你分析用户输入严格按照以下格式返回JSON