register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax');
}
public function handle_ajax(Doku_Event $event) {
// 新增:处理 ragasker_widget=1 的 POST 请求(前端小部件调用)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['ragasker_widget']) && !empty($_POST['prompt'])) {
$prompt = trim($_POST['prompt']);
$step = isset($_POST['step']) ? intval($_POST['step']) : 1;
// 多语言文本获取函数
$L = function($key) { return $this->getLang($key); };
$serverUrl = $this->getConf('server_url');
$apiKey = $this->getConf('apikey');
if (empty($apiKey)) {
$this->sendJson(['ragasker_response' => '' . hsc($L('no_apikey')) . '', 'step' => $step]);
exit;
}
$model = $this->getConf('model');
$maxTokens = (int)$this->getConf('max_tokens');
$temperature = (float)$this->getConf('temperature');
$client = new OpenAIHttpClient($serverUrl, $apiKey);
// 步骤1:关键词提取
if ($step === 1) {
$keywordPrompt = $L('keyword_prompt') . "\n" . $prompt;
$requestData1 = [
'model' => $model,
'messages' => [
['role' => 'system', 'content' => $L('keyword_system')],
['role' => 'user', 'content' => $keywordPrompt]
],
'max_tokens' => $maxTokens,
'temperature' => 0.2
];
$response1 = $client->chatCompletion($requestData1);
$keywords = '';
if (isset($response1['choices'][0]['message']['content'])) {
$keywords = trim($response1['choices'][0]['message']['content']);
} else {
$this->sendJson(['ragasker_response' => '' . hsc($L('error_api')) . '', 'step' => 1]);
exit;
}
$step1msg = "" . hsc(sprintf($L('step_title'), 1, $L('step_extracting'))) . "
"
. hsc(sprintf($L('user_question'), $prompt)) . "
"
. hsc(sprintf($L('result'), $keywords)) . "
";
$this->sendJson(['ragasker_response' => $step1msg, 'step' => 1, 'keywords' => $keywords]);
exit;
}
// 步骤2:关键词搜索
if ($step === 2 && !empty($_POST['keywords'])) {
$keywords = trim($_POST['keywords']);
$highlight = false;
$searchResults = ft_pageSearch($keywords, $highlight);
$processor = new SearchHelper();
while ((!is_array($searchResults) || count($searchResults) === 0) && strpos($keywords, ' ') !== false) {
$keywordArr = explode(' ', $keywords);
array_pop($keywordArr);
$keywords = trim(implode(' ', $keywordArr));
if ($keywords === '') break;
$searchResults = ft_pageSearch($keywords, $highlight);
}
if ((!is_array($searchResults) || count($searchResults) === 0) && strpos($keywords, ' ') !== false) {
$keywordArr = explode(' ', $keywords);
while (count($keywordArr) > 1) {
array_shift($keywordArr); // 去掉第一个关键词
$keywords = trim(implode(' ', $keywordArr));
if ($keywords === '') break;
$searchResults = ft_pageSearch($keywords, $highlight);
if (is_array($searchResults) && count($searchResults) > 0) break;
}
}
if ((!is_array($searchResults) || count($searchResults) === 0) && strpos($keywords, ' ') !== false) {
$keywordArr = explode(' ', trim($_POST['keywords'])); // 用原始关键词
$mergedResults = [];
foreach ($keywordArr as $singleKeyword) {
$singleKeyword = trim($singleKeyword);
if ($singleKeyword === '') continue;
$result = ft_pageSearch($singleKeyword, $highlight);
if (is_array($result) && count($result) > 0) {
foreach ($result as $item) {
// 用页面ID去重
if (!isset($mergedResults[$item['id']])) {
$mergedResults[$item['id']] = $item;
}
}
}
}
if (count($mergedResults) > 0) {
$searchResults = array_values($mergedResults);
$keywords = implode(' ', $keywordArr); // 保持原始关键词
}
}
$lists = $processor->extractLists($searchResults, 0);
$linkList = $lists['links'];
$contentList = $lists['contents'];
$searchList = '';
if (is_array($searchResults) && count($searchResults) > 0) {
$searchList = '
" . hsc($summaryPrompt) . "
$1', $text);
$text = nl2br($text);
return $text;
}
private function validateRequest() {
global $INPUT;
// CSRF 保护
$sess = $INPUT->server->str('REMOTE_USER');
if(empty($sess)) return false;
// 检查权限
return auth_isadmin();
}
}