@@ -3,36 +3,99 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
33import { Badge } from "@/components/ui/badge"
44import { Button } from "@/components/ui/button"
55import { Input } from "@/components/ui/input"
6- import { Copy , Check } from "lucide-react"
6+ import { Copy , Check , ChevronDown , ChevronRight } from "lucide-react"
77
88interface Endpoint {
99 method : string
1010 path : string
1111 description : string
1212 auth : boolean
13+ body ?: BodyExample
14+ }
15+
16+ interface BodyExample {
17+ description : string
18+ json : unknown
19+ }
20+
21+ const PROVIDER_BODY : BodyExample = {
22+ description : "创建/更新渠道" ,
23+ json : {
24+ channelName : "my-openai" ,
25+ type : "openai" ,
26+ targetBaseUrl : "https://api.openai.com/v1" ,
27+ systemPrompt : null ,
28+ models : [ "gpt-4o" , "gpt-4o-mini" ] ,
29+ priority : 100 ,
30+ auth : {
31+ header : "authorization" ,
32+ value : "sk-xxxx"
33+ } ,
34+ responsesMode : "native" ,
35+ extraFields : null
36+ }
37+ }
38+
39+ const PROVIDER_ENABLED_BODY : BodyExample = {
40+ description : "启用/禁用渠道" ,
41+ json : {
42+ enabled : true
43+ }
44+ }
45+
46+ const KEY_NAME_BODY : BodyExample = {
47+ description : "创建/重命名 API Key" ,
48+ json : {
49+ name : "my-key"
50+ }
51+ }
52+
53+ const KEY_MODELS_BODY : BodyExample = {
54+ description : "设置允许模型列表" ,
55+ json : {
56+ models : [ "gpt-4o" , "gpt-4o-mini" ]
57+ }
58+ }
59+
60+ const ALIAS_BODY : BodyExample = {
61+ description : "创建/更新模型别名" ,
62+ json : {
63+ alias : "gpt-4o" ,
64+ provider : "my-openai" ,
65+ model : "gpt-4o-2024-08-06" ,
66+ description : "GPT-4o 主力模型" ,
67+ enabled : true
68+ }
69+ }
70+
71+ const ALIAS_ENABLED_BODY : BodyExample = {
72+ description : "启用/禁用模型别名" ,
73+ json : {
74+ enabled : true
75+ }
1376}
1477
1578const ENDPOINTS : Endpoint [ ] = [
1679 { method : "GET" , path : "/api/v1/health" , description : "健康检查" , auth : false } ,
1780 { method : "GET" , path : "/api/v1/providers" , description : "获取所有渠道" , auth : true } ,
1881 { method : "GET" , path : "/api/v1/providers/:channelName" , description : "获取单个渠道详情" , auth : true } ,
19- { method : "POST" , path : "/api/v1/providers" , description : "创建渠道" , auth : true } ,
20- { method : "PATCH" , path : "/api/v1/providers/:channelName" , description : "更新渠道" , auth : true } ,
82+ { method : "POST" , path : "/api/v1/providers" , description : "创建渠道" , auth : true , body : PROVIDER_BODY } ,
83+ { method : "PATCH" , path : "/api/v1/providers/:channelName" , description : "更新渠道" , auth : true , body : PROVIDER_BODY } ,
2184 { method : "DELETE" , path : "/api/v1/providers/:channelName" , description : "删除渠道" , auth : true } ,
22- { method : "PATCH" , path : "/api/v1/providers/:channelName/enabled" , description : "启用/禁用渠道" , auth : true } ,
85+ { method : "PATCH" , path : "/api/v1/providers/:channelName/enabled" , description : "启用/禁用渠道" , auth : true , body : PROVIDER_ENABLED_BODY } ,
2386 { method : "GET" , path : "/api/v1/requests" , description : "获取请求日志列表" , auth : true } ,
2487 { method : "GET" , path : "/api/v1/requests/:requestId" , description : "获取单个请求详情" , auth : true } ,
2588 { method : "GET" , path : "/api/v1/stats" , description : "获取统计数据" , auth : true } ,
2689 { method : "GET" , path : "/api/v1/keys" , description : "获取所有 API Keys" , auth : true } ,
2790 { method : "GET" , path : "/api/v1/keys/:id" , description : "获取单个 API Key" , auth : true } ,
28- { method : "POST" , path : "/api/v1/keys" , description : "创建 API Key" , auth : true } ,
29- { method : "PATCH" , path : "/api/v1/keys/:id" , description : "重命名 API Key" , auth : true } ,
91+ { method : "POST" , path : "/api/v1/keys" , description : "创建 API Key" , auth : true , body : KEY_NAME_BODY } ,
92+ { method : "PATCH" , path : "/api/v1/keys/:id" , description : "重命名 API Key" , auth : true , body : KEY_NAME_BODY } ,
3093 { method : "DELETE" , path : "/api/v1/keys/:id" , description : "删除 API Key" , auth : true } ,
31- { method : "PATCH" , path : "/api/v1/keys/:id/allowed-models" , description : "设置 API Key 允许模型" , auth : true } ,
94+ { method : "PATCH" , path : "/api/v1/keys/:id/allowed-models" , description : "设置 API Key 允许模型" , auth : true , body : KEY_MODELS_BODY } ,
3295 { method : "GET" , path : "/api/v1/aliases" , description : "获取所有模型别名" , auth : true } ,
33- { method : "POST" , path : "/api/v1/aliases" , description : "创建模型别名" , auth : true } ,
34- { method : "PATCH" , path : "/api/v1/aliases/:id" , description : "更新模型别名" , auth : true } ,
35- { method : "PATCH" , path : "/api/v1/aliases/:id/enabled" , description : "启用/禁用模型别名" , auth : true } ,
96+ { method : "POST" , path : "/api/v1/aliases" , description : "创建模型别名" , auth : true , body : ALIAS_BODY } ,
97+ { method : "PATCH" , path : "/api/v1/aliases/:id" , description : "更新模型别名" , auth : true , body : ALIAS_BODY } ,
98+ { method : "PATCH" , path : "/api/v1/aliases/:id/enabled" , description : "启用/禁用模型别名" , auth : true , body : ALIAS_ENABLED_BODY } ,
3699 { method : "DELETE" , path : "/api/v1/aliases/:id" , description : "删除模型别名" , auth : true } ,
37100]
38101
@@ -64,6 +127,41 @@ function CopyButton({ text }: { text: string }) {
64127 )
65128}
66129
130+ function EndpointItem ( { ep } : { ep : Endpoint } ) {
131+ const [ expanded , setExpanded ] = useState ( false )
132+
133+ return (
134+ < div className = "rounded-md border" >
135+ < div
136+ className = "flex items-center gap-3 p-3 hover:bg-muted/50 cursor-pointer select-none"
137+ onClick = { ( ) => ep . body && setExpanded ( ( v ) => ! v ) }
138+ >
139+ < MethodBadge method = { ep . method } />
140+ < code className = "flex-1 text-sm font-mono" > { ep . path } </ code >
141+ < span className = "text-sm text-muted-foreground" > { ep . description } </ span >
142+ { ep . auth && < Badge variant = "outline" className = "text-xs" > 需认证</ Badge > }
143+ { ep . body && (
144+ expanded
145+ ? < ChevronDown className = "h-4 w-4 text-muted-foreground" />
146+ : < ChevronRight className = "h-4 w-4 text-muted-foreground" />
147+ ) }
148+ </ div >
149+
150+ { expanded && ep . body && (
151+ < div className = "border-t px-3 py-3 space-y-2" >
152+ < div className = "flex items-center justify-between" >
153+ < span className = "text-xs text-muted-foreground" > { ep . body . description } - Request Body</ span >
154+ < CopyButton text = { JSON . stringify ( ep . body . json , null , 2 ) } />
155+ </ div >
156+ < pre className = "rounded-md bg-muted p-3 text-xs font-mono overflow-x-auto" >
157+ < code > { JSON . stringify ( ep . body . json , null , 2 ) } </ code >
158+ </ pre >
159+ </ div >
160+ ) }
161+ </ div >
162+ )
163+ }
164+
67165export function ApiDocsPage ( ) {
68166 const [ filter , setFilter ] = useState ( "" )
69167
@@ -117,15 +215,7 @@ export function ApiDocsPage() {
117215 < CardContent >
118216 < div className = "flex flex-col gap-2" >
119217 { filtered . map ( ( ep ) => (
120- < div
121- key = { ep . path + ep . method }
122- className = "flex items-center gap-3 rounded-md border p-3 hover:bg-muted/50"
123- >
124- < MethodBadge method = { ep . method } />
125- < code className = "flex-1 text-sm font-mono" > { ep . path } </ code >
126- < span className = "text-sm text-muted-foreground" > { ep . description } </ span >
127- { ep . auth && < Badge variant = "outline" className = "text-xs" > 需认证</ Badge > }
128- </ div >
218+ < EndpointItem key = { ep . path + ep . method } ep = { ep } />
129219 ) ) }
130220 </ div >
131221 </ CardContent >
0 commit comments