|
|
@@ -0,0 +1,415 @@
|
|
|
+import * as React from 'react';
|
|
|
+import { Drawer, Button, Tabs, Tag, Space, message } from 'antd';
|
|
|
+import { CopyOutlined, CheckOutlined } from '@ant-design/icons';
|
|
|
+import './ApiDoc.scss';
|
|
|
+
|
|
|
+const { TabPane } = Tabs;
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ open: boolean;
|
|
|
+ onClose: () => void;
|
|
|
+}
|
|
|
+
|
|
|
+// 代码块组件
|
|
|
+const CodeBlock: React.FC<{ code: string; language?: string }> = ({ code, language = 'bash' }) => {
|
|
|
+ const [copied, setCopied] = React.useState(false);
|
|
|
+
|
|
|
+ const handleCopy = async () => {
|
|
|
+ try {
|
|
|
+ await navigator.clipboard.writeText(code);
|
|
|
+ setCopied(true);
|
|
|
+ message.success('已复制到剪贴板');
|
|
|
+ setTimeout(() => setCopied(false), 2000);
|
|
|
+ } catch (err) {
|
|
|
+ message.error('复制失败');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className='code-block'>
|
|
|
+ <div className='code-header'>
|
|
|
+ <span className='code-language'>{language}</span>
|
|
|
+ <Button
|
|
|
+ type='text'
|
|
|
+ size='small'
|
|
|
+ icon={copied ? <CheckOutlined /> : <CopyOutlined />}
|
|
|
+ onClick={handleCopy}
|
|
|
+ >
|
|
|
+ {copied ? '已复制' : '复制'}
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ <pre className='code-content'>
|
|
|
+ <code>{code}</code>
|
|
|
+ </pre>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+// 参数表格组件
|
|
|
+const ParamsTable: React.FC<{ params: { name: string; type: string; required: boolean; description: string }[] }> = ({ params }) => (
|
|
|
+ <div className='params-table'>
|
|
|
+ <table>
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th>参数</th>
|
|
|
+ <th>类型</th>
|
|
|
+ <th>必填</th>
|
|
|
+ <th>说明</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ {params.map((param, index) => (
|
|
|
+ <tr key={index}>
|
|
|
+ <td><code>{param.name}</code></td>
|
|
|
+ <td><span className='param-type'>{param.type}</span></td>
|
|
|
+ <td>
|
|
|
+ {param.required ? (
|
|
|
+ <Tag color='red' style={{ fontSize: 12 }}>必填</Tag>
|
|
|
+ ) : (
|
|
|
+ <Tag color='default' style={{ fontSize: 12 }}>可选</Tag>
|
|
|
+ )}
|
|
|
+ </td>
|
|
|
+ <td>{param.description}</td>
|
|
|
+ </tr>
|
|
|
+ ))}
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+);
|
|
|
+
|
|
|
+// 响应示例组件
|
|
|
+const ResponseExample: React.FC<{ example: string }> = ({ example }) => (
|
|
|
+ <div className='response-example'>
|
|
|
+ <div className='example-header'>响应示例</div>
|
|
|
+ <pre className='example-content'>
|
|
|
+ <code>{example}</code>
|
|
|
+ </pre>
|
|
|
+ </div>
|
|
|
+);
|
|
|
+
|
|
|
+const ApiDoc: React.FC<Props> = ({ open, onClose }) => {
|
|
|
+ const baseUrl = window.location.origin;
|
|
|
+ const apiKey = localStorage.getItem('api_key_demo') || 'your_api_key_here';
|
|
|
+
|
|
|
+ // 通用问答接口
|
|
|
+ const chatCompletionCode = `curl -X POST ${baseUrl}/api/v1/chat/completions \\
|
|
|
+ -H "Content-Type: application/json" \\
|
|
|
+ -H "Authorization: Bearer ${apiKey}" \\
|
|
|
+ -d '{
|
|
|
+ "model": "qwen-plus",
|
|
|
+ "messages": [
|
|
|
+ {
|
|
|
+ "role": "user",
|
|
|
+ "content": "你好,请介绍一下你自己"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "stream": false
|
|
|
+ }'`;
|
|
|
+
|
|
|
+ const chatCompletionPython = `import requests
|
|
|
+
|
|
|
+url = "${baseUrl}/api/v1/chat/completions"
|
|
|
+headers = {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ "Authorization": "Bearer ${apiKey}"
|
|
|
+}
|
|
|
+
|
|
|
+data = {
|
|
|
+ "model": "qwen-plus",
|
|
|
+ "messages": [
|
|
|
+ {
|
|
|
+ "role": "user",
|
|
|
+ "content": "你好,请介绍一下你自己"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "stream": False
|
|
|
+}
|
|
|
+
|
|
|
+response = requests.post(url, headers=headers, json=data)
|
|
|
+print(response.json())`;
|
|
|
+
|
|
|
+ // RAG 问答接口
|
|
|
+ const ragChatCode = `curl -X POST ${baseUrl}/api/v1/rag/chat \\
|
|
|
+ -H "Content-Type: application/json" \\
|
|
|
+ -H "Authorization: Bearer ${apiKey}" \\
|
|
|
+ -d '{
|
|
|
+ "knowledge_base_id": "kb_xxxxxxxxx",
|
|
|
+ "query": "公司的年假政策是什么?",
|
|
|
+ "top_k": 3,
|
|
|
+ "score_threshold": 0.7
|
|
|
+ }'`;
|
|
|
+
|
|
|
+ const ragChatPython = `import requests
|
|
|
+
|
|
|
+url = "${baseUrl}/api/v1/rag/chat"
|
|
|
+headers = {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ "Authorization": "Bearer ${apiKey}"
|
|
|
+}
|
|
|
+
|
|
|
+data = {
|
|
|
+ "knowledge_base_id": "kb_xxxxxxxxx",
|
|
|
+ "query": "公司的年假政策是什么?",
|
|
|
+ "top_k": 3,
|
|
|
+ "score_threshold": 0.7
|
|
|
+}
|
|
|
+
|
|
|
+response = requests.post(url, headers=headers, json=data)
|
|
|
+print(response.json())`;
|
|
|
+
|
|
|
+ // 知识库检索接口
|
|
|
+ const knowledgeSearchCode = `curl -X POST ${baseUrl}/api/v1/knowledge/search \\
|
|
|
+ -H "Content-Type: application/json" \\
|
|
|
+ -H "Authorization: Bearer ${apiKey}" \\
|
|
|
+ -d '{
|
|
|
+ "knowledge_base_id": "kb_xxxxxxxxx",
|
|
|
+ "query": "人工智能技术发展趋势",
|
|
|
+ "top_k": 5,
|
|
|
+ "score_threshold": 0.6
|
|
|
+ }'`;
|
|
|
+
|
|
|
+ const knowledgeSearchPython = `import requests
|
|
|
+
|
|
|
+url = "${baseUrl}/api/v1/knowledge/search"
|
|
|
+headers = {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ "Authorization": "Bearer ${apiKey}"
|
|
|
+}
|
|
|
+
|
|
|
+data = {
|
|
|
+ "knowledge_base_id": "kb_xxxxxxxxx",
|
|
|
+ "query": "人工智能技术发展趋势",
|
|
|
+ "top_k": 5,
|
|
|
+ "score_threshold": 0.6
|
|
|
+}
|
|
|
+
|
|
|
+response = requests.post(url, headers=headers, json=data)
|
|
|
+print(response.json())`;
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Drawer
|
|
|
+ title="API 文档"
|
|
|
+ placement="right"
|
|
|
+ width={900}
|
|
|
+ open={open}
|
|
|
+ onClose={onClose}
|
|
|
+ className='api-doc-drawer'
|
|
|
+ >
|
|
|
+ <div className='api-doc-content'>
|
|
|
+ {/* 接口概览 */}
|
|
|
+ <div className='api-section'>
|
|
|
+ <h3 className='section-title'>接口说明</h3>
|
|
|
+ <div className='section-content'>
|
|
|
+ <p>本文档提供了建科小智 RAG 平台的 API 接口说明,所有接口均采用 RESTful 风格设计。</p>
|
|
|
+ <div className='info-cards'>
|
|
|
+ <div className='info-card'>
|
|
|
+ <div className='card-label'>基础 URL</div>
|
|
|
+ <div className='card-value'><code>{baseUrl}/api/v1</code></div>
|
|
|
+ </div>
|
|
|
+ <div className='info-card'>
|
|
|
+ <div className='card-label'>认证方式</div>
|
|
|
+ <div className='card-value'><code>Bearer Token</code></div>
|
|
|
+ </div>
|
|
|
+ <div className='info-card'>
|
|
|
+ <div className='card-label'>数据格式</div>
|
|
|
+ <div className='card-value'><code>application/json</code></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <Tabs defaultActiveKey="1" className='api-tabs'>
|
|
|
+ {/* 通用问答接口 */}
|
|
|
+ <TabPane tab="通用问答" key="1">
|
|
|
+ <div className='api-item'>
|
|
|
+ <div className='api-header'>
|
|
|
+ <span className='api-method method-post'>POST</span>
|
|
|
+ <span className='api-path'>/api/v1/chat/completions</span>
|
|
|
+ </div>
|
|
|
+ <p className='api-description'>
|
|
|
+ 兼容 OpenAI 格式的通用对话接口,支持多轮对话和流式输出。
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <h4>请求参数</h4>
|
|
|
+ <ParamsTable params={[
|
|
|
+ { name: 'model', type: 'string', required: true, description: '模型名称,如 qwen-plus、qwen-turbo 等' },
|
|
|
+ { name: 'messages', type: 'array', required: true, description: '对话消息列表,包含 role 和 content' },
|
|
|
+ { name: 'stream', type: 'boolean', required: false, description: '是否使用流式输出,默认 false' },
|
|
|
+ { name: 'temperature', type: 'number', required: false, description: '温度参数,控制输出随机性,范围 0-2' },
|
|
|
+ { name: 'max_tokens', type: 'integer', required: false, description: '最大输出 token 数' },
|
|
|
+ ]} />
|
|
|
+
|
|
|
+ <h4>代码示例</h4>
|
|
|
+ <Tabs type='card' size='small' className='code-tabs'>
|
|
|
+ <TabPane tab="cURL" key="curl">
|
|
|
+ <CodeBlock code={chatCompletionCode} language='bash' />
|
|
|
+ </TabPane>
|
|
|
+ <TabPane tab="Python" key="python">
|
|
|
+ <CodeBlock code={chatCompletionPython} language='python' />
|
|
|
+ </TabPane>
|
|
|
+ </Tabs>
|
|
|
+
|
|
|
+ <ResponseExample example={`{
|
|
|
+ "id": "chatcmpl-xxxxxxxx",
|
|
|
+ "object": "chat.completion",
|
|
|
+ "created": 1234567890,
|
|
|
+ "model": "qwen-plus",
|
|
|
+ "choices": [
|
|
|
+ {
|
|
|
+ "index": 0,
|
|
|
+ "message": {
|
|
|
+ "role": "assistant",
|
|
|
+ "content": "你好!我是建科小智,是一个基于大语言模型的智能助手..."
|
|
|
+ },
|
|
|
+ "finish_reason": "stop"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "usage": {
|
|
|
+ "prompt_tokens": 10,
|
|
|
+ "completion_tokens": 50,
|
|
|
+ "total_tokens": 60
|
|
|
+ }
|
|
|
+}`} />
|
|
|
+ </div>
|
|
|
+ </TabPane>
|
|
|
+
|
|
|
+ {/* RAG 问答接口 */}
|
|
|
+ <TabPane tab="RAG 问答" key="2">
|
|
|
+ <div className='api-item'>
|
|
|
+ <div className='api-header'>
|
|
|
+ <span className='api-method method-post'>POST</span>
|
|
|
+ <span className='api-path'>/api/v1/rag/chat</span>
|
|
|
+ </div>
|
|
|
+ <p className='api-description'>
|
|
|
+ 基于知识库的 RAG(检索增强生成)问答接口,结合检索结果生成准确回答。
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <h4>请求参数</h4>
|
|
|
+ <ParamsTable params={[
|
|
|
+ { name: 'knowledge_base_id', type: 'string', required: true, description: '知识库 ID' },
|
|
|
+ { name: 'query', type: 'string', required: true, description: '用户问题' },
|
|
|
+ { name: 'top_k', type: 'integer', required: false, description: '返回最相关的 K 条结果,默认 3' },
|
|
|
+ { name: 'score_threshold', type: 'number', required: false, description: '相似度阈值,低于此值的结果将被过滤,默认 0.5' },
|
|
|
+ { name: 'stream', type: 'boolean', required: false, description: '是否使用流式输出,默认 false' },
|
|
|
+ ]} />
|
|
|
+
|
|
|
+ <h4>代码示例</h4>
|
|
|
+ <Tabs type='card' size='small' className='code-tabs'>
|
|
|
+ <TabPane tab="cURL" key="curl">
|
|
|
+ <CodeBlock code={ragChatCode} language='bash' />
|
|
|
+ </TabPane>
|
|
|
+ <TabPane tab="Python" key="python">
|
|
|
+ <CodeBlock code={ragChatPython} language='python' />
|
|
|
+ </TabPane>
|
|
|
+ </Tabs>
|
|
|
+
|
|
|
+ <ResponseExample example={`{
|
|
|
+ "id": "rag-chat-xxxxxxxx",
|
|
|
+ "object": "rag.completion",
|
|
|
+ "created": 1234567890,
|
|
|
+ "model": "qwen-plus",
|
|
|
+ "choices": [
|
|
|
+ {
|
|
|
+ "index": 0,
|
|
|
+ "message": {
|
|
|
+ "role": "assistant",
|
|
|
+ "content": "根据公司的考勤管理制度,员工年假标准如下:\\n1. 累计工作已满 1 年不满 10 年的,年休假 5 天..."
|
|
|
+ },
|
|
|
+ "finish_reason": "stop"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "retrieved_chunks": [
|
|
|
+ {
|
|
|
+ "content": "员工累计工作已满 1 年不满 10 年的,年休假 5 天;已满 10 年不满 20 年的,年休假 10 天...",
|
|
|
+ "score": 0.89,
|
|
|
+ "source": "公司考勤管理制度.pdf"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "usage": {
|
|
|
+ "prompt_tokens": 150,
|
|
|
+ "completion_tokens": 80,
|
|
|
+ "total_tokens": 230
|
|
|
+ }
|
|
|
+}`} />
|
|
|
+ </div>
|
|
|
+ </TabPane>
|
|
|
+
|
|
|
+ {/* 知识库检索接口 */}
|
|
|
+ <TabPane tab="知识库检索" key="3">
|
|
|
+ <div className='api-item'>
|
|
|
+ <div className='api-header'>
|
|
|
+ <span className='api-method method-post'>POST</span>
|
|
|
+ <span className='api-path'>/api/v1/knowledge/search</span>
|
|
|
+ </div>
|
|
|
+ <p className='api-description'>
|
|
|
+ 纯检索接口,仅从知识库中检索相关内容,不进行生成。适用于需要自行处理检索结果的场景。
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <h4>请求参数</h4>
|
|
|
+ <ParamsTable params={[
|
|
|
+ { name: 'knowledge_base_id', type: 'string', required: true, description: '知识库 ID' },
|
|
|
+ { name: 'query', type: 'string', required: true, description: '检索关键词' },
|
|
|
+ { name: 'top_k', type: 'integer', required: false, description: '返回最相关的 K 条结果,默认 5' },
|
|
|
+ { name: 'score_threshold', type: 'number', required: false, description: '相似度阈值,默认 0.5' },
|
|
|
+ ]} />
|
|
|
+
|
|
|
+ <h4>代码示例</h4>
|
|
|
+ <Tabs type='card' size='small' className='code-tabs'>
|
|
|
+ <TabPane tab="cURL" key="curl">
|
|
|
+ <CodeBlock code={knowledgeSearchCode} language='bash' />
|
|
|
+ </TabPane>
|
|
|
+ <TabPane tab="Python" key="python">
|
|
|
+ <CodeBlock code={knowledgeSearchPython} language='python' />
|
|
|
+ </TabPane>
|
|
|
+ </Tabs>
|
|
|
+
|
|
|
+ <ResponseExample example={`{
|
|
|
+ "object": "knowledge.search.result",
|
|
|
+ "knowledge_base_id": "kb_xxxxxxxxx",
|
|
|
+ "query": "人工智能技术发展趋势",
|
|
|
+ "results": [
|
|
|
+ {
|
|
|
+ "id": "chunk_001",
|
|
|
+ "content": "人工智能技术发展趋势:1. 大模型持续进化,多模态能力成为标配...",
|
|
|
+ "score": 0.92,
|
|
|
+ "metadata": {
|
|
|
+ "source": "AI 行业研究报告.docx",
|
|
|
+ "page": 15
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "id": "chunk_002",
|
|
|
+ "content": "生成式 AI 市场规模预计 2025 年将达到 xxx 亿元...",
|
|
|
+ "score": 0.85,
|
|
|
+ "metadata": {
|
|
|
+ "source": "AI 行业研究报告.docx",
|
|
|
+ "page": 23
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "total": 2
|
|
|
+}`} />
|
|
|
+ </div>
|
|
|
+ </TabPane>
|
|
|
+ </Tabs>
|
|
|
+
|
|
|
+ {/* 错误码说明 */}
|
|
|
+ <div className='api-section'>
|
|
|
+ <h3 className='section-title'>错误码说明</h3>
|
|
|
+ <div className='section-content'>
|
|
|
+ <ParamsTable params={[
|
|
|
+ { name: '400', type: '', required: false, description: '请求参数错误' },
|
|
|
+ { name: '401', type: '', required: false, description: '未授权,请检查 API Key 是否正确' },
|
|
|
+ { name: '403', type: '', required: false, description: '权限不足' },
|
|
|
+ { name: '404', type: '', required: false, description: '资源不存在' },
|
|
|
+ { name: '429', type: '', required: false, description: '请求过于频繁,请稍后重试' },
|
|
|
+ { name: '500', type: '', required: false, description: '服务器内部错误' },
|
|
|
+ ]} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Drawer>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default ApiDoc;
|