← 返回聊天
新建
删除
Models
gpt5.php
gpt5_file.php
gpt5_mini_file.php
openai_chat.php
Tools
get_time.php
get_weather.php
global_search_messages.php
math.php
memo.php
news.php
search_arxiv.php
search_crossref.php
search_github_code.php
search_pubmed.php
search_semantic_scholar.php
stock_market.php
url.php
<?php declare(strict_types=1); return [ 'name' => 'search_semantic_scholar', 'description' => '在 Semantic Scholar 检索论文(返回标题/作者/年份/链接/开放PDF)。', 'parameters' => [ 'type' => 'object', 'properties' => [ 'query' => ['type' => 'string', 'description' => '检索关键词,例如:LLM alignment'], 'limit' => ['type' => 'integer', 'description' => '返回条数,默认 5', 'default' => 5], ], 'required' => ['query'], ], 'run' => function(array $args, array $context) { $http_get_json = function(string $url, int $timeoutSec = 10, array $headers = []): array { $ch = curl_init($url); if ($ch === false) throw new RuntimeException('curl_init failed'); $hdr = array_merge(['Accept: application/json'], $headers); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => $timeoutSec, CURLOPT_TIMEOUT => $timeoutSec, CURLOPT_HTTPHEADER => $hdr, ]); $resp = curl_exec($ch); $errno = curl_errno($ch); $err = curl_error($ch); $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($errno !== 0) throw new RuntimeException('cURL error: ' . $err); if ($status < 200 || $status >= 300) throw new RuntimeException('HTTP ' . $status); $data = json_decode((string)$resp, true); if (!is_array($data)) throw new RuntimeException('Invalid JSON'); return $data; }; $query = trim((string)($args['query'] ?? '')); $limit = (int)($args['limit'] ?? 5); if ($limit <= 0) $limit = 5; if ($query === '') throw new RuntimeException('query 不能为空'); $base = 'https://api.semanticscholar.org/graph/v1/paper/search'; $url = $base . '?' . http_build_query([ 'query' => $query, 'limit' => $limit, 'fields' => 'title,authors,year,url,abstract,openAccessPdf', ]); try { // 可选:很多 API 更喜欢带 UA(有些环境没 UA 会被拦) $data = $http_get_json($url, 12, ['User-Agent: php-tool/1.0']); } catch (Throwable $e) { return "Error fetching data from Semantic Scholar: " . $e->getMessage(); } $items = $data['data'] ?? []; if (!is_array($items) || count($items) === 0) { return "No results found on Semantic Scholar for '{$query}'."; } $resultsList = []; $citationsList = []; $emitter = $context['event_emitter'] ?? null; $canEmit = is_callable($emitter); $i = 0; foreach ($items as $item) { if (!is_array($item)) continue; $i++; $title = (string)($item['title'] ?? 'N/A'); $year = $item['year'] ?? 'N/A'; $paperUrl = (string)($item['url'] ?? '#'); $authorNames = []; $authorsArr = $item['authors'] ?? []; if (is_array($authorsArr)) { foreach ($authorsArr as $a) { if (is_array($a) && isset($a['name'])) $authorNames[] = (string)$a['name']; } } $authors = count($authorNames) ? implode(', ', $authorNames) : 'N/A'; $pdfUrl = null; if (isset($item['openAccessPdf']) && is_array($item['openAccessPdf'])) { $pdfUrl = $item['openAccessPdf']['url'] ?? null; if (is_string($pdfUrl)) $pdfUrl = trim($pdfUrl); } $line = "{$i}. {$title}\n Authors: {$authors}\n Year: {$year}\n URL: {$paperUrl}"; if (is_string($pdfUrl) && $pdfUrl !== '') $line .= "\n Open Access PDF: {$pdfUrl}"; $resultsList[] = $line; $link = (is_string($pdfUrl) && $pdfUrl !== '') ? $pdfUrl : $paperUrl; if ($link && $link !== '#') { $citationsList[] = "[{$i}] {$link}"; if ($canEmit) { $emitter([ 'type' => 'citation', 'data' => [ 'document' => [$title], 'metadata' => [['source' => $link]], 'source' => ['name' => $title], ], ]); } } if ($i >= $limit) break; } $output = implode("\n\n", $resultsList); if (count($citationsList)) { $output .= "\n\n---\n\n**Citation Links:**\n" . implode("\n", $citationsList); } return $output; }, ];
保存