877 行
42 KiB
PHP
877 行
42 KiB
PHP
<?php
|
||
|
||
/**
|
||
* 本地AI模型,用于回答用户关于Parlz的问题
|
||
* 不需要依赖外部API,基于规则和关键词匹配,具有自己的思考能力
|
||
* 数据存储在JSON文件中
|
||
*/
|
||
|
||
class LocalAI {
|
||
// 关于Parlz的资料
|
||
private $parlzInfo;
|
||
|
||
// 常见问题和回答
|
||
private $faq;
|
||
|
||
// 上下文信息,用于保持对话连贯性
|
||
private $context = [];
|
||
|
||
/**
|
||
* 构造函数,从JSON文件中加载数据
|
||
*/
|
||
public function __construct() {
|
||
// 加载JSON文件
|
||
$jsonFilePath = __DIR__ . '/../data/parlz_info.json';
|
||
|
||
if (file_exists($jsonFilePath)) {
|
||
$jsonContent = file_get_contents($jsonFilePath);
|
||
$data = json_decode($jsonContent, true);
|
||
|
||
if ($data) {
|
||
$this->parlzInfo = $data;
|
||
$this->faq = $data['常见问题和回答'];
|
||
} else {
|
||
// 如果JSON文件解析失败,使用默认数据
|
||
$this->loadDefaultData();
|
||
}
|
||
} else {
|
||
// 如果JSON文件不存在,使用默认数据
|
||
$this->loadDefaultData();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 加载默认数据
|
||
*/
|
||
private function loadDefaultData() {
|
||
$this->parlzInfo = [
|
||
'功能介绍' => [
|
||
'消息发送' => 'Parlz支持发送文本消息、图片消息、引用消息等多种类型的消息。',
|
||
'群组聊天' => 'Parlz支持创建和加入群组,与多个好友同时聊天。',
|
||
'语音通话' => 'Parlz支持语音通话功能,让您与好友随时随地保持联系。',
|
||
'视频通话' => 'Parlz支持视频通话功能,让您与好友面对面交流。',
|
||
'消息撤回' => 'Parlz支持消息撤回功能,您可以撤回发送的消息。',
|
||
'消息引用' => 'Parlz支持消息引用功能,您可以引用之前的消息进行回复。',
|
||
'消息编辑' => 'Parlz支持消息编辑功能,您可以编辑发送的消息。',
|
||
'消息转发' => 'Parlz支持消息转发功能,您可以将消息转发给其他好友或群组。',
|
||
'消息收藏' => 'Parlz支持消息收藏功能,您可以收藏重要的消息。',
|
||
'消息搜索' => 'Parlz支持消息搜索功能,您可以搜索聊天记录中的关键词。',
|
||
'好友管理' => 'Parlz支持好友管理功能,您可以添加、删除、拉黑好友。',
|
||
'群组管理' => 'Parlz支持群组管理功能,您可以添加、删除群成员,设置群公告等。',
|
||
'个人资料' => 'Parlz支持个人资料编辑功能,您可以修改头像、昵称、个性签名等。',
|
||
'深色模式' => 'Parlz支持深色模式,保护您的眼睛。',
|
||
'消息通知' => 'Parlz支持消息通知功能,及时提醒您收到的消息。',
|
||
'消息已读' => 'Parlz支持消息已读功能,让您知道对方是否已读您的消息。',
|
||
'消息已送达' => 'Parlz支持消息已送达功能,让您知道消息是否已送达对方。',
|
||
'多设备登录' => 'Parlz支持多设备登录,让您在不同设备上同步聊天记录。',
|
||
'聊天记录备份' => 'Parlz支持聊天记录备份功能,保护您的聊天数据。',
|
||
'聊天记录恢复' => 'Parlz支持聊天记录恢复功能,让您在需要时恢复聊天记录。',
|
||
'安全加密' => 'Parlz使用端到端加密技术,保护您的聊天数据安全。'
|
||
],
|
||
'账号与安全' => [
|
||
'注册账号' => '您可以使用手机号或邮箱注册Parlz账号。',
|
||
'登录账号' => '您可以使用手机号或邮箱和密码登录Parlz账号。',
|
||
'找回密码' => '如果您忘记了密码,可以通过手机号或邮箱找回密码。',
|
||
'修改密码' => '您可以在个人设置中修改密码,建议定期修改密码以保护账号安全。',
|
||
'账号绑定' => '您可以绑定手机号、邮箱、微信、QQ等账号,提高账号安全性。',
|
||
'账号注销' => '如果您不再使用Parlz,可以在个人设置中注销账号。',
|
||
'账号封禁' => '如果您违反了Parlz的使用条款,您的账号可能会被封禁。',
|
||
'隐私设置' => '您可以在个人设置中调整隐私设置,控制谁可以添加您为好友,谁可以查看您的个人资料等。'
|
||
],
|
||
'使用帮助' => [
|
||
'新手教程' => 'Parlz提供新手教程,帮助您快速了解如何使用Parlz。',
|
||
'消息发送失败' => '如果消息发送失败,可能是网络问题或对方账号异常。请检查网络连接,或稍后再试。',
|
||
'消息接收不到' => '如果消息接收不到,可能是网络问题或对方账号异常。请检查网络连接,或稍后再试。',
|
||
'无法添加好友' => '如果无法添加好友,可能是对方设置了添加好友验证,或对方账号异常。',
|
||
'无法创建群组' => '如果无法创建群组,可能是您的账号权限不足,或群组数量达到上限。',
|
||
'无法加入群组' => '如果无法加入群组,可能是群组设置了加入验证,或群组已满。',
|
||
'语音通话失败' => '如果语音通话失败,可能是网络问题或对方账号异常。请检查网络连接,或稍后再试。',
|
||
'视频通话失败' => '如果视频通话失败,可能是网络问题或对方账号异常。请检查网络连接,或稍后再试。',
|
||
'聊天记录丢失' => '如果聊天记录丢失,可能是您清除了缓存,或账号在其他设备上登录。您可以尝试使用聊天记录恢复功能。',
|
||
'头像无法修改' => '如果头像无法修改,可能是网络问题或图片格式不正确。请检查网络连接,或使用符合要求的图片格式。',
|
||
'昵称无法修改' => '如果昵称无法修改,可能是网络问题或昵称不符合要求。请检查网络连接,或使用符合要求的昵称。',
|
||
'个性签名无法修改' => '如果个性签名无法修改,可能是网络问题或个性签名不符合要求。请检查网络连接,或使用符合要求的个性签名。',
|
||
'深色模式不生效' => '如果深色模式不生效,可能是您的设备系统版本过低,或应用版本过低。请更新设备系统或应用版本。',
|
||
'消息通知不生效' => '如果消息通知不生效,可能是您关闭了消息通知,或设备系统设置了通知限制。请检查消息通知设置,或设备系统通知设置。'
|
||
],
|
||
'常见问题' => [
|
||
'Parlz是什么' => 'Parlz是一款功能强大的聊天应用,支持文本、图片、语音、视频等多种消息类型,以及群组聊天、好友管理等功能。',
|
||
'Parlz收费吗' => 'Parlz是一款免费应用,您可以免费使用所有基本功能。',
|
||
'Parlz安全吗' => 'Parlz使用端到端加密技术,保护您的聊天数据安全。同时,我们也会定期更新应用,修复安全漏洞。',
|
||
'Parlz支持哪些设备' => 'Parlz支持iOS、Android、Windows、macOS等多种设备。',
|
||
'Parlz如何同步聊天记录' => 'Parlz支持多设备登录,您可以在不同设备上同步聊天记录。同时,您也可以使用聊天记录备份功能,将聊天记录备份到云端。',
|
||
'Parlz如何举报不良信息' => '如果您收到不良信息,可以长按消息,选择举报选项,提交举报信息。我们会尽快处理您的举报。',
|
||
'Parlz如何联系客服' => '如果您有任何问题或建议,可以在应用中通过设置-关于我们-联系客服选项,提交您的问题或建议。我们会尽快回复您。'
|
||
],
|
||
'常见问题和回答' => [
|
||
'你好' => '您好!我是Parlz官方助手。很高兴为您服务!请问您想了解关于Parlz的哪方面信息?',
|
||
'再见' => '再见!如果您还有其他问题,随时可以问我。',
|
||
'谢谢' => '不客气!如果您还有其他问题,随时可以问我。'
|
||
]
|
||
];
|
||
|
||
$this->faq = $this->parlzInfo['常见问题和回答'];
|
||
}
|
||
|
||
/**
|
||
* 添加到上下文
|
||
* @param string $userInput 用户输入
|
||
* @param string $response 机器人回复
|
||
*/
|
||
private function addToContext($userInput, $response) {
|
||
$this->context[] = [
|
||
'user' => $userInput,
|
||
'bot' => $response
|
||
];
|
||
|
||
// 限制上下文长度,只保留最近的5轮对话
|
||
if (count($this->context) > 10) {
|
||
array_shift($this->context);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 从上下文获取相关信息
|
||
* @param string $currentInput 当前用户输入
|
||
* @return array 相关的上下文信息
|
||
*/
|
||
private function getRelevantContext($currentInput) {
|
||
$relevantContext = [];
|
||
$lowerInput = strtolower($currentInput);
|
||
|
||
// 关键词提取
|
||
$inputKeywords = $this->extractKeywords($lowerInput);
|
||
|
||
foreach ($this->context as $i => $item) {
|
||
$lowerUser = strtolower($item['user']);
|
||
$lowerBot = strtolower($item['bot']);
|
||
|
||
// 提取上下文中的关键词
|
||
$userKeywords = $this->extractKeywords($lowerUser);
|
||
$botKeywords = $this->extractKeywords($lowerBot);
|
||
|
||
// 检查当前输入是否与上下文相关
|
||
$isRelevant = false;
|
||
|
||
// 方法1:直接字符串匹配
|
||
if (strpos($lowerInput, $lowerUser) !== false || strpos($lowerUser, $lowerInput) !== false ||
|
||
strpos($lowerInput, $lowerBot) !== false || strpos($lowerBot, $lowerInput) !== false) {
|
||
$isRelevant = true;
|
||
}
|
||
|
||
// 方法2:关键词匹配
|
||
if (!$isRelevant && !empty($inputKeywords)) {
|
||
foreach ($inputKeywords as $keyword) {
|
||
if (in_array($keyword, $userKeywords) || in_array($keyword, $botKeywords)) {
|
||
$isRelevant = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 方法3:两字连续匹配
|
||
if (!$isRelevant) {
|
||
if ($this->hasTwoCharMatch($lowerInput, $lowerUser) || $this->hasTwoCharMatch($lowerInput, $lowerBot)) {
|
||
$isRelevant = true;
|
||
}
|
||
}
|
||
|
||
if ($isRelevant) {
|
||
$relevantContext[] = $item;
|
||
}
|
||
}
|
||
|
||
// 按时间倒序排序,最近的对话优先
|
||
return array_reverse($relevantContext);
|
||
}
|
||
|
||
/**
|
||
* 提取关键词
|
||
* @param string $text 文本
|
||
* @return array 关键词数组
|
||
*/
|
||
private function extractKeywords($text) {
|
||
$keywords = [];
|
||
|
||
// 移除标点符号
|
||
$text = preg_replace('/[\p{P}\p{S}]/u', ' ', $text);
|
||
|
||
// 分割成单词
|
||
$words = preg_split('/\s+/', $text);
|
||
|
||
// 过滤掉短词和常见词
|
||
$stopWords = ['的', '了', '是', '在', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这'];
|
||
|
||
foreach ($words as $word) {
|
||
$word = trim($word);
|
||
if (strlen($word) >= 2 && !in_array($word, $stopWords)) {
|
||
$keywords[] = $word;
|
||
}
|
||
}
|
||
|
||
return $keywords;
|
||
}
|
||
|
||
/**
|
||
* 识别用户意图
|
||
* @param string $content 用户输入内容
|
||
* @return string 用户意图
|
||
*/
|
||
private function identifyIntent($content) {
|
||
$lowerContent = strtolower($content);
|
||
|
||
// 优先识别关于AI自身的问题
|
||
$aboutAiPatterns = ['你是谁', '什么是助手', '关于你', '你是什么', '你是', '什么是'];
|
||
foreach ($aboutAiPatterns as $pattern) {
|
||
if (strpos($lowerContent, $pattern) !== false) {
|
||
// 特殊处理"什么是",确保它后面跟着"助手"才识别为about_ai
|
||
if ($pattern == '什么是' && strpos($lowerContent, '什么是助手') === false) {
|
||
continue;
|
||
}
|
||
return 'about_ai';
|
||
}
|
||
}
|
||
|
||
// 意图模式匹配
|
||
$intentPatterns = [
|
||
'greeting' => ['你好', '您好', 'hi', 'hello'],
|
||
'farewell' => ['再见', 'bye', 'goodbye'],
|
||
'thank' => ['谢谢', 'thank'],
|
||
'feature' => ['功能', '介绍', '特性', '能力'],
|
||
'account' => ['账号', '安全', '注册', '登录', '密码'],
|
||
'help' => ['帮助', '使用', '问题', '怎么', '如何'],
|
||
'faq' => ['常见问题', '问题', 'faq'],
|
||
'parlz' => ['parlz', '聊天', '消息', '群聊']
|
||
];
|
||
|
||
// 识别意图
|
||
foreach ($intentPatterns as $intent => $patterns) {
|
||
foreach ($patterns as $pattern) {
|
||
if (strpos($lowerContent, $pattern) !== false) {
|
||
return $intent;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果没有匹配到特定意图,尝试通过关键词识别
|
||
$keywords = $this->extractKeywords($lowerContent);
|
||
|
||
if (!empty($keywords)) {
|
||
$intentScores = [
|
||
'feature' => 0,
|
||
'account' => 0,
|
||
'help' => 0,
|
||
'faq' => 0
|
||
];
|
||
|
||
// 关键词权重
|
||
$keywordWeights = [
|
||
'功能' => ['feature' => 3],
|
||
'介绍' => ['feature' => 2],
|
||
'特性' => ['feature' => 3],
|
||
'能力' => ['feature' => 2],
|
||
'账号' => ['account' => 3],
|
||
'安全' => ['account' => 3],
|
||
'注册' => ['account' => 3],
|
||
'登录' => ['account' => 3],
|
||
'密码' => ['account' => 3],
|
||
'帮助' => ['help' => 3],
|
||
'使用' => ['help' => 3],
|
||
'问题' => ['help' => 2, 'faq' => 2],
|
||
'怎么' => ['help' => 3],
|
||
'如何' => ['help' => 3],
|
||
'常见' => ['faq' => 3],
|
||
'faq' => ['faq' => 3]
|
||
];
|
||
|
||
// 计算意图得分
|
||
foreach ($keywords as $keyword) {
|
||
if (isset($keywordWeights[$keyword])) {
|
||
foreach ($keywordWeights[$keyword] as $intent => $weight) {
|
||
$intentScores[$intent] += $weight;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 选择得分最高的意图
|
||
arsort($intentScores);
|
||
$topIntent = key($intentScores);
|
||
|
||
if ($intentScores[$topIntent] > 0) {
|
||
return $topIntent;
|
||
}
|
||
}
|
||
|
||
// 默认意图
|
||
return 'general';
|
||
}
|
||
|
||
/**
|
||
* 检查两个字符串是否有两个连续的字匹配
|
||
* @param string $input 用户输入的字符串
|
||
* @param string $target 要匹配的目标字符串
|
||
* @return bool 是否有两个连续的字匹配
|
||
*/
|
||
private function hasTwoCharMatch($input, $target) {
|
||
// 确保两个字符串长度都至少为2
|
||
if (strlen($input) < 2 || strlen($target) < 2) {
|
||
return false;
|
||
}
|
||
|
||
// 遍历输入字符串,检查是否有两个连续的字在目标字符串中
|
||
for ($i = 0; $i < strlen($input) - 1; $i++) {
|
||
// 提取两个连续的字
|
||
$twoChars = substr($input, $i, 2);
|
||
// 检查这两个字是否在目标字符串中
|
||
if (strpos($target, $twoChars) !== false) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 计算两个字符串的编辑距离(Levenshtein距离)
|
||
* @param string $str1 第一个字符串
|
||
* @param string $str2 第二个字符串
|
||
* @return int 编辑距离
|
||
*/
|
||
private function levenshteinDistance($str1, $str2) {
|
||
$len1 = strlen($str1);
|
||
$len2 = strlen($str2);
|
||
|
||
// 创建距离矩阵
|
||
$matrix = array();
|
||
|
||
// 初始化第一行和第一列
|
||
for ($i = 0; $i <= $len1; $i++) {
|
||
$matrix[$i][0] = $i;
|
||
}
|
||
for ($j = 0; $j <= $len2; $j++) {
|
||
$matrix[0][$j] = $j;
|
||
}
|
||
|
||
// 填充矩阵
|
||
for ($i = 1; $i <= $len1; $i++) {
|
||
for ($j = 1; $j <= $len2; $j++) {
|
||
$cost = ($str1[$i-1] == $str2[$j-1]) ? 0 : 1;
|
||
$matrix[$i][$j] = min(
|
||
$matrix[$i-1][$j] + 1, // 删除
|
||
$matrix[$i][$j-1] + 1, // 插入
|
||
$matrix[$i-1][$j-1] + $cost // 替换
|
||
);
|
||
}
|
||
}
|
||
|
||
return $matrix[$len1][$len2];
|
||
}
|
||
|
||
/**
|
||
* 检查字符串是否模糊匹配
|
||
* @param string $input 用户输入的字符串
|
||
* @param string $target 要匹配的目标字符串
|
||
* @return bool 是否模糊匹配
|
||
*/
|
||
private function isFuzzyMatch($input, $target) {
|
||
// 转换为小写
|
||
$input = strtolower($input);
|
||
$target = strtolower($target);
|
||
|
||
// 方法1:两字连续匹配
|
||
if ($this->hasTwoCharMatch($input, $target)) {
|
||
return true;
|
||
}
|
||
|
||
// 方法2:编辑距离匹配(适用于拼写错误)
|
||
$distance = $this->levenshteinDistance($input, $target);
|
||
$maxLength = max(strlen($input), strlen($target));
|
||
$similarity = 1 - ($distance / $maxLength);
|
||
|
||
// 如果相似度大于0.6,则认为匹配
|
||
if ($similarity > 0.6) {
|
||
return true;
|
||
}
|
||
|
||
// 方法3:关键词包含匹配
|
||
$inputKeywords = $this->extractKeywords($input);
|
||
$targetKeywords = $this->extractKeywords($target);
|
||
|
||
foreach ($inputKeywords as $keyword) {
|
||
foreach ($targetKeywords as $targetKeyword) {
|
||
if (strpos($targetKeyword, $keyword) !== false || strpos($keyword, $targetKeyword) !== false) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 生成AI思考过程
|
||
* @param string $content 用户输入内容
|
||
* @param array $relevantContext 相关上下文
|
||
* @return string 思考过程
|
||
*/
|
||
private function generateThinking($content, $relevantContext) {
|
||
$lowerContent = strtolower($content);
|
||
$thinking = [];
|
||
|
||
// 识别用户意图
|
||
$intent = $this->identifyIntent($content);
|
||
|
||
// 基于用户意图生成不同的思考过程
|
||
switch ($intent) {
|
||
case 'greeting':
|
||
$thinking[] = "用户向我打招呼,我应该礼貌地回应并引导用户提问。";
|
||
break;
|
||
case 'farewell':
|
||
$thinking[] = "用户向我告别,我应该礼貌地回应并表示随时可以提供帮助。";
|
||
break;
|
||
case 'thank':
|
||
$thinking[] = "用户向我表示感谢,我应该礼貌地回应并表示随时可以提供帮助。";
|
||
break;
|
||
case 'feature':
|
||
$thinking[] = "用户询问功能相关的问题,我需要提供详细的功能介绍。";
|
||
$thinking[] = "用户提到了功能,我需要从知识库中找到相关的功能信息并详细解答。";
|
||
break;
|
||
case 'account':
|
||
$thinking[] = "用户询问账号与安全相关的问题,我需要提供详细的账号安全信息。";
|
||
$thinking[] = "用户提到了账号或安全,我需要从知识库中找到相关的账号安全信息并详细解答。";
|
||
break;
|
||
case 'help':
|
||
$thinking[] = "用户询问使用帮助相关的问题,我需要提供详细的使用指导。";
|
||
$thinking[] = "用户提到了帮助或使用,我需要从知识库中找到相关的使用帮助信息并详细解答。";
|
||
break;
|
||
case 'faq':
|
||
$thinking[] = "用户询问常见问题相关的信息,我需要提供详细的常见问题解答。";
|
||
$thinking[] = "用户提到了问题,我需要从知识库中找到相关的常见问题信息并详细解答。";
|
||
break;
|
||
case 'parlz':
|
||
$thinking[] = "用户询问了关于Parlz的一般性问题,我需要提供一个全面的介绍。";
|
||
$thinking[] = "用户提到了Parlz,我需要从知识库中找到相关的Parlz信息并详细解答。";
|
||
break;
|
||
case 'about_ai':
|
||
$thinking[] = "用户询问了关于我自己的问题,我需要介绍自己并引导用户询问Parlz相关的问题。";
|
||
break;
|
||
default:
|
||
$thinking[] = "用户提到了'{$content}',我需要分析其意图并找到相关信息。";
|
||
$thinking[] = "用户的问题比较一般,我需要从知识库中找到可能相关的信息并提供解答。";
|
||
break;
|
||
}
|
||
|
||
// 基于上下文生成思考过程
|
||
if (!empty($relevantContext)) {
|
||
$thinking[] = "根据之前的对话,用户可能对某些特定方面更感兴趣,我需要保持回答的连贯性。";
|
||
|
||
// 分析上下文,提取用户可能感兴趣的主题
|
||
$contextTopics = [];
|
||
foreach ($relevantContext as $item) {
|
||
$contextContent = strtolower($item['user'] . ' ' . $item['bot']);
|
||
if (strpos($contextContent, '功能') !== false) {
|
||
$contextTopics[] = '功能';
|
||
} elseif (strpos($contextContent, '账号') !== false || strpos($contextContent, '安全') !== false) {
|
||
$contextTopics[] = '账号与安全';
|
||
} elseif (strpos($contextContent, '帮助') !== false || strpos($contextContent, '使用') !== false) {
|
||
$contextTopics[] = '使用帮助';
|
||
} elseif (strpos($contextContent, '问题') !== false || strpos($contextContent, '常见') !== false) {
|
||
$contextTopics[] = '常见问题';
|
||
}
|
||
}
|
||
|
||
// 去重并添加到思考过程
|
||
$contextTopics = array_unique($contextTopics);
|
||
if (!empty($contextTopics)) {
|
||
$thinking[] = "用户之前关注过" . implode('、', $contextTopics) . "等方面的内容,我需要参考这些信息。";
|
||
}
|
||
}
|
||
|
||
// 随机选择一个思考过程
|
||
return $thinking[array_rand($thinking)];
|
||
}
|
||
|
||
/**
|
||
* 生成回复
|
||
* @param string $content 用户输入的内容
|
||
* @return string 生成的回复内容
|
||
*/
|
||
public function generateReply($content) {
|
||
// 获取相关的上下文信息
|
||
$relevantContext = $this->getRelevantContext($content);
|
||
|
||
// 转换为小写,方便匹配
|
||
$lowerContent = strtolower($content);
|
||
|
||
// 识别用户意图
|
||
$intent = $this->identifyIntent($content);
|
||
|
||
// 生成思考过程
|
||
$thinking = $this->generateThinking($content, $relevantContext);
|
||
|
||
// 检查是否是问候语或礼貌用语
|
||
if (strpos($lowerContent, '你好') !== false || strpos($lowerContent, '您好') !== false || strpos($lowerContent, 'hi') !== false || strpos($lowerContent, 'hello') !== false) {
|
||
// 构建个性化回复
|
||
$greetings = [
|
||
"您好!我是Parlz官方助手。很高兴为您服务!请问您想了解关于Parlz的哪方面信息?",
|
||
"你好!欢迎使用Parlz官方助手。我可以回答您关于Parlz的任何问题,请问有什么可以帮到您的?",
|
||
"嗨!我是Parlz的智能助手。很高兴认识您!请问您想了解Parlz的哪些功能或信息?",
|
||
"您好!欢迎来到Parlz官方助手。我随时为您解答关于Parlz的问题,请问今天有什么可以帮到您的?",
|
||
"你好!我是Parlz的智能客服。很高兴为您服务!请问您对Parlz的哪些功能感兴趣?",
|
||
"嗨!欢迎使用Parlz官方助手。我可以为您提供关于功能介绍、账号安全、使用帮助等方面的信息,请问您需要了解什么?"
|
||
];
|
||
|
||
$reply = $greetings[array_rand($greetings)];
|
||
$this->addToContext($content, $reply);
|
||
return $reply;
|
||
}
|
||
|
||
if (strpos($lowerContent, '再见') !== false || strpos($lowerContent, 'bye') !== false || strpos($lowerContent, 'goodbye') !== false) {
|
||
// 构建个性化回复
|
||
$farewells = [
|
||
"再见!如果您还有其他问题,随时可以问我。",
|
||
"拜拜!期待下次为您服务。如果您有任何关于Parlz的问题,随时可以回来咨询我。",
|
||
"再见!祝您一天愉快!如果您需要了解更多关于Parlz的信息,随时可以告诉我。",
|
||
"再见!很高兴为您服务。如果您有任何关于Parlz的问题,随时可以联系我。",
|
||
"拜拜!希望我的回答对您有所帮助。如果您还有其他问题,随时可以咨询我。",
|
||
"再见!祝您生活愉快!如果您需要了解Parlz的更多信息,随时可以告诉我。"
|
||
];
|
||
|
||
$reply = $farewells[array_rand($farewells)];
|
||
$this->addToContext($content, $reply);
|
||
return $reply;
|
||
}
|
||
|
||
if (strpos($lowerContent, '谢谢') !== false || strpos($lowerContent, 'thank') !== false) {
|
||
// 构建个性化回复
|
||
$thanks = [
|
||
"不客气!如果您还有其他问题,随时可以问我。",
|
||
"不用谢!能帮到您我很高兴。如果您有任何关于Parlz的问题,随时可以咨询我。",
|
||
"别客气!这是我应该做的。如果您需要了解更多关于Parlz的信息,随时可以告诉我。",
|
||
"不客气!很高兴能够帮到您。如果您还有其他关于Parlz的问题,随时可以向我咨询。",
|
||
"不用谢!为您服务是我的荣幸。如果您需要了解更多Parlz的功能或信息,随时可以告诉我。",
|
||
"别客气!希望我的回答对您有所帮助。如果您还有其他问题,随时可以问我。"
|
||
];
|
||
|
||
$reply = $thanks[array_rand($thanks)];
|
||
$this->addToContext($content, $reply);
|
||
return $reply;
|
||
}
|
||
|
||
// 检查是否是总类别请求(支持模糊匹配)
|
||
if (strpos($lowerContent, '功能') !== false) {
|
||
// 构建回复
|
||
$reply = "您好!以下是Parlz的功能介绍:\n\n";
|
||
|
||
foreach ($this->parlzInfo['功能介绍'] as $feature => $description) {
|
||
$reply .= "**{$feature}**:{$description}\n\n";
|
||
}
|
||
|
||
$reply .= "请问您对哪个功能特别感兴趣,需要更详细的介绍吗?";
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
if (strpos($lowerContent, '账号') !== false || strpos($lowerContent, '安全') !== false) {
|
||
// 构建回复
|
||
$reply = "您好!以下是Parlz的账号与安全相关信息:\n\n";
|
||
|
||
foreach ($this->parlzInfo['账号与安全'] as $topic => $description) {
|
||
$reply .= "**{$topic}**:{$description}\n\n";
|
||
}
|
||
|
||
$reply .= "请问您对哪个安全问题特别关注,需要更详细的解答吗?";
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
if (strpos($lowerContent, '帮助') !== false || strpos($lowerContent, '使用') !== false) {
|
||
// 构建回复
|
||
$reply = "您好!以下是Parlz的使用帮助相关信息:\n\n";
|
||
|
||
foreach ($this->parlzInfo['使用帮助'] as $topic => $description) {
|
||
$reply .= "**{$topic}**:{$description}\n\n";
|
||
}
|
||
|
||
$reply .= "请问您遇到了什么具体的使用问题,需要更详细的帮助吗?";
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
if (strpos($lowerContent, '问题') !== false || strpos($lowerContent, '常见') !== false) {
|
||
// 构建回复
|
||
$reply = "您好!以下是Parlz的常见问题解答:\n\n";
|
||
|
||
foreach ($this->parlzInfo['常见问题'] as $question => $answer) {
|
||
$reply .= "**{$question}**:{$answer}\n\n";
|
||
}
|
||
|
||
$reply .= "请问您对哪个问题特别感兴趣,需要更详细的解答吗?";
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
// 检查是否是关于AI自身的问题
|
||
if (strpos($lowerContent, '你是谁') !== false || (strpos($lowerContent, '什么是') !== false && strpos($lowerContent, '助手') !== false) || $intent === 'about_ai') {
|
||
$reply = "您好!我是Parlz官方助手,是一个基于本地AI模型的智能助手。我可以回答您关于Parlz的任何问题,包括功能介绍、账号安全、使用帮助和常见问题等。\n\n我与DeepSeek类似,能够按照自己的思路回答问题,理解上下文,提供连贯的对话体验。请问您有什么关于Parlz的问题需要我解答吗?";
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
// 收集相关信息(优先匹配完整功能名称,然后使用两字关键词匹配)
|
||
$relevantInfo = [];
|
||
$fullMatchFound = false;
|
||
|
||
// 优先检查是否是完整的功能名称
|
||
foreach ($this->parlzInfo['功能介绍'] as $feature => $description) {
|
||
$lowerFeature = strtolower($feature);
|
||
// 检查是否是完整的功能名称匹配
|
||
if ($lowerContent === $lowerFeature) {
|
||
$relevantInfo['功能介绍'][] = [
|
||
'feature' => $feature,
|
||
'description' => $description
|
||
];
|
||
$fullMatchFound = true;
|
||
break; // 找到完整匹配后,停止搜索
|
||
}
|
||
}
|
||
|
||
// 检查是否是完整的账号与安全相关名称
|
||
if (!$fullMatchFound) {
|
||
foreach ($this->parlzInfo['账号与安全'] as $topic => $description) {
|
||
$lowerTopic = strtolower($topic);
|
||
if ($lowerContent === $lowerTopic) {
|
||
$relevantInfo['账号与安全'][] = [
|
||
'topic' => $topic,
|
||
'description' => $description
|
||
];
|
||
$fullMatchFound = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查是否是完整的使用帮助相关名称
|
||
if (!$fullMatchFound) {
|
||
foreach ($this->parlzInfo['使用帮助'] as $topic => $description) {
|
||
$lowerTopic = strtolower($topic);
|
||
if ($lowerContent === $lowerTopic) {
|
||
$relevantInfo['使用帮助'][] = [
|
||
'topic' => $topic,
|
||
'description' => $description
|
||
];
|
||
$fullMatchFound = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查是否是完整的常见问题相关名称
|
||
if (!$fullMatchFound) {
|
||
foreach ($this->parlzInfo['常见问题'] as $question => $answer) {
|
||
$lowerQuestion = strtolower($question);
|
||
if ($lowerContent === $lowerQuestion) {
|
||
$relevantInfo['常见问题'][] = [
|
||
'question' => $question,
|
||
'answer' => $answer
|
||
];
|
||
$fullMatchFound = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果没有找到完整的名称匹配,再使用模糊匹配
|
||
if (!$fullMatchFound) {
|
||
// 检查是否是功能介绍相关问题(支持模糊匹配)
|
||
foreach ($this->parlzInfo['功能介绍'] as $feature => $description) {
|
||
// 检查是否模糊匹配
|
||
if ($this->isFuzzyMatch($content, $feature)) {
|
||
$relevantInfo['功能介绍'][] = [
|
||
'feature' => $feature,
|
||
'description' => $description
|
||
];
|
||
}
|
||
}
|
||
|
||
// 检查是否是账号与安全相关问题(支持模糊匹配)
|
||
foreach ($this->chattersInfo['账号与安全'] as $topic => $description) {
|
||
// 检查是否模糊匹配
|
||
if ($this->isFuzzyMatch($content, $topic)) {
|
||
$relevantInfo['账号与安全'][] = [
|
||
'topic' => $topic,
|
||
'description' => $description
|
||
];
|
||
}
|
||
}
|
||
|
||
// 检查是否是使用帮助相关问题(支持模糊匹配)
|
||
foreach ($this->parlzInfo['使用帮助'] as $topic => $description) {
|
||
// 检查是否模糊匹配
|
||
if ($this->isFuzzyMatch($content, $topic)) {
|
||
$relevantInfo['使用帮助'][] = [
|
||
'topic' => $topic,
|
||
'description' => $description
|
||
];
|
||
}
|
||
}
|
||
|
||
// 检查是否是常见问题相关问题(支持模糊匹配)
|
||
foreach ($this->parlzInfo['常见问题'] as $question => $answer) {
|
||
// 检查是否模糊匹配
|
||
if ($this->isFuzzyMatch($content, $question)) {
|
||
$relevantInfo['常见问题'][] = [
|
||
'question' => $question,
|
||
'answer' => $answer
|
||
];
|
||
}
|
||
}
|
||
}
|
||
|
||
// 根据收集到的相关信息生成回复
|
||
if (!empty($relevantInfo)) {
|
||
// 构建个性化回复开头
|
||
$openers = [
|
||
"您好!关于您提到的'{$content}',我为您整理了以下信息:\n\n",
|
||
"你好!针对'{$content}',我找到了以下相关信息:\n\n",
|
||
"您好!关于'{$content}',以下是我为您准备的详细信息:\n\n",
|
||
"你好!关于'{$content}',我来为您详细解答:\n\n",
|
||
"您好!针对'{$content}'这个问题,我为您收集了以下信息:\n\n",
|
||
"你好!关于'{$content}',以下是我的解答:\n\n"
|
||
];
|
||
|
||
$reply = $openers[array_rand($openers)];
|
||
|
||
// 处理相关信息,按类别分组并添加过渡语句
|
||
$categories = [
|
||
'功能介绍' => '功能介绍',
|
||
'账号与安全' => '账号与安全',
|
||
'使用帮助' => '使用帮助',
|
||
'常见问题' => '常见问题'
|
||
];
|
||
|
||
$categoryCount = 0;
|
||
$totalInfoCount = 0;
|
||
|
||
// 计算总信息数量
|
||
foreach ($categories as $category => $name) {
|
||
if (isset($relevantInfo[$category]) && !empty($relevantInfo[$category])) {
|
||
$categoryCount++;
|
||
$totalInfoCount += count($relevantInfo[$category]);
|
||
}
|
||
}
|
||
|
||
// 根据信息数量添加不同的过渡语句
|
||
if ($totalInfoCount > 3) {
|
||
$reply .= "我为您整理了以下几个方面的信息:\n\n";
|
||
}
|
||
|
||
// 处理各个类别的信息
|
||
foreach ($categories as $category => $name) {
|
||
if (isset($relevantInfo[$category]) && !empty($relevantInfo[$category])) {
|
||
// 如果有多个类别,添加类别标题
|
||
if ($categoryCount > 1) {
|
||
$reply .= "### {$name}\n\n";
|
||
}
|
||
|
||
// 添加类别内的信息
|
||
foreach ($relevantInfo[$category] as $info) {
|
||
if ($category == '功能介绍') {
|
||
$reply .= "**{$info['feature']}**:{$info['description']}\n\n";
|
||
} elseif ($category == '常见问题') {
|
||
$reply .= "**{$info['question']}**:{$info['answer']}\n\n";
|
||
} else {
|
||
$reply .= "**{$info['topic']}**:{$info['description']}\n\n";
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加个性化结尾
|
||
$endings = [
|
||
"请问您对以上信息还有其他疑问,或者想了解Parlz的其他方面吗?",
|
||
"希望以上信息对您有所帮助!如果您还有其他问题,随时可以告诉我。",
|
||
"如果您需要了解更多关于Parlz的信息,请随时告诉我具体的需求。",
|
||
"以上是关于您问题的解答,还有其他方面需要了解吗?",
|
||
"请问您对这个功能还有其他疑问,或者想了解Parlz的其他功能吗?",
|
||
"希望我的回答能够解决您的问题!如果您有任何其他疑问,随时可以咨询我。",
|
||
"请问您还需要了解Parlz的其他功能或信息吗?",
|
||
"以上就是关于'{$content}'的详细信息,希望对您有所帮助!",
|
||
"如果您对Parlz还有其他问题,随时可以告诉我,我会为您提供详细的解答。",
|
||
"请问您对我的回答满意吗?如果还有其他问题,随时可以向我咨询。"
|
||
];
|
||
|
||
$reply .= $endings[array_rand($endings)];
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
// 检查是否是关于Parlz的一般性问题
|
||
if (strpos($lowerContent, 'parlz') !== false || strpos($lowerContent, '聊天') !== false || strpos($lowerContent, '消息') !== false || strpos($lowerContent, '群聊') !== false) {
|
||
$reply = "您好!Parlz是一款功能强大的聊天应用,支持文本、图片、语音、视频等多种消息类型,以及群组聊天、好友管理等功能。\n\n如果您有具体的问题,比如关于功能使用、账号安全或者其他方面的疑问,请随时告诉我,我会为您提供详细的解答。";
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
// 检查是否是关于AI自身的问题
|
||
if (strpos($lowerContent, '你是谁') !== false || (strpos($lowerContent, '什么是') !== false && strpos($lowerContent, '助手') !== false) || $intent === 'about_ai') {
|
||
$reply = "您好!我是Parlz官方助手,是一个基于本地AI模型的智能助手。我可以回答您关于Parlz的任何问题,包括功能介绍、账号安全、使用帮助和常见问题等。\n\n我与DeepSeek类似,能够按照自己的思路回答问题,理解上下文,提供连贯的对话体验。请问您有什么关于Parlz的问题需要我解答吗?";
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
|
||
// 如果没有匹配到任何问题,生成一个更智能的默认回复
|
||
// 生成默认回复
|
||
$openers = [
|
||
"您好!我是Parlz官方助手。\n\n感谢您的提问:'{$content}'。\n\n虽然我没有找到与您问题直接相关的信息,但我很乐意为您解答关于Parlz的任何问题。",
|
||
"您好!关于'{$content}',我可能无法提供直接的答案,但我是Parlz的官方助手,很乐意为您解答关于Parlz的任何问题。",
|
||
"感谢您的提问!虽然'{$content}'不是我直接能回答的问题,但我是Parlz的官方助手,专注于解答与Parlz相关的疑问。"
|
||
];
|
||
|
||
$topics = [
|
||
"• 功能介绍(如消息发送、群组聊天、语音通话等)",
|
||
"• 账号与安全(如注册登录、密码管理、隐私设置等)",
|
||
"• 使用帮助(如解决连接问题、消息发送失败等)",
|
||
"• 常见问题(如Parlz是什么、是否收费、安全性等)"
|
||
];
|
||
|
||
$closers = [
|
||
"请随时告诉我您的具体需求,我会为您提供详细的解答!",
|
||
"如果您有任何关于Parlz的问题,随时可以向我咨询。",
|
||
"希望我能帮到您!请告诉我您想了解Parlz的哪方面信息。"
|
||
];
|
||
|
||
$reply = $openers[array_rand($openers)] . "\n\n您可以询问关于以下方面的信息:\n\n" . implode("\n", $topics) . "\n\n" . $closers[array_rand($closers)];
|
||
|
||
// 添加到上下文
|
||
$this->addToContext($content, $reply);
|
||
|
||
return $reply;
|
||
}
|
||
}
|
||
|
||
?>
|