This commit is contained in:
Jethro Lin 2024-12-09 15:12:07 +08:00
parent 15ad765e2c
commit cc482df902
4 changed files with 56 additions and 339 deletions

View file

@ -40,6 +40,7 @@ class Kernel extends HttpKernel
'api' => [
\App\Http\Middleware\ValidateHeaders::class,
\App\Http\Middleware\CustomCors::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],

View file

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CustomCors
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
if (!$response instanceof Response) {
return $response;
}
// 處理 OPTIONS 請求
if ($request->getMethod() === 'OPTIONS') {
$response->headers->set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE, PATCH');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, X-API-Version, X-Client-ID, Authorization, X-Requested-With, Accept');
$response->headers->set('Access-Control-Max-Age', '86400');
}
// 允許所有域名
$response->headers->set('Access-Control-Allow-Origin', '*');
// 當允許所有域名時,不能設置 credentials
// $response->headers->set('Access-Control-Allow-Credentials', 'true');
return $response;
}
}

19
config/cors.php Normal file
View file

@ -0,0 +1,19 @@
<?php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => [
'Content-Type',
'X-Requested-With',
'Authorization',
'X-API-Version',
'X-Client-ID',
'Accept',
],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];

View file

@ -1,339 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LLM API Documentation v2</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
pre {
background-color: #f6f8fa;
border-radius: 6px;
padding: 16px;
overflow: auto;
}
code {
font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
font-size: 85%;
background-color: #f6f8fa;
padding: 0.2em 0.4em;
border-radius: 3px;
}
h1, h2, h3, h4 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: 600;
line-height: 1.25;
}
h1 { font-size: 2em; border-bottom: 1px solid #eaecef; }
h2 { font-size: 1.5em; border-bottom: 1px solid #eaecef; }
h3 { font-size: 1.25em; }
h4 { font-size: 1em; }
.endpoint {
margin: 20px 0;
padding: 20px;
border: 1px solid #ddd;
border-radius: 6px;
}
.method {
font-weight: bold;
color: #fff;
padding: 4px 8px;
border-radius: 4px;
margin-right: 8px;
}
.get { background-color: #61affe; }
.post { background-color: #49cc90; }
.put { background-color: #fca130; }
.delete { background-color: #f93e3e; }
</style>
</head>
<body>
<h1>LLM API Documentation v2</h1>
<h2>Overview</h2>
<p>This document describes the API endpoints for the LLM service.</p>
<h2>Base URL</h2>
<pre><code>https://llmbackend.local:7890</code></pre>
<h2>Authentication</h2>
<ul>
<li>Admin endpoints require Bearer token authentication obtained from <code>/api/admin/login</code></li>
<li>Client endpoints require access token obtained from <code>/api/auth/token</code></li>
</ul>
<h2>Required Headers</h2>
<p>All API requests must include:</p>
<pre><code>Content-Type: application/json
Accept: application/json
X-API-Version: 1.0
X-Client-ID: your-client-id</code></pre>
<h2>Endpoints</h2>
<h3>Public Routes</h3>
<div class="endpoint">
<h4><span class="method get">GET</span> /</h4>
<p>Root endpoint that returns the API status.</p>
<h5>Response:</h5>
<pre><code>{
"success": true,
"data": {
"status": "ok",
"version": "1.0"
}
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method get">GET</span> /api/test</h4>
<p>Simple test endpoint to verify API connectivity.</p>
</div>
<div class="endpoint">
<h4><span class="method post">POST</span> /api/auth/token</h4>
<p>Exchange auth token for an access token.</p>
<h5>Request Body:</h5>
<pre><code>{
"auth_token": "64-character-auth-token"
}</code></pre>
<h5>Response:</h5>
<pre><code>{
"success": true,
"data": {
"access_token": "generated-access-token",
"expires_in": 3600
}
}</code></pre>
</div>
<h3>Protected Client Routes</h3>
<div class="endpoint">
<h4><span class="method post">POST</span> /api/llm/request</h4>
<p>Make a request to the LLM service.</p>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {access_token}</code></pre>
<h5>Request Body:</h5>
<pre><code>{
"prompt": "Your prompt text here",
"max_tokens": 100,
"temperature": 0.7,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
}</code></pre>
<h5>Response:</h5>
<pre><code>{
"success": true,
"data": {
"response": "LLM generated response"
}
}</code></pre>
</div>
<h3>Admin Authentication</h3>
<div class="endpoint">
<h4><span class="method post">POST</span> /api/admin/login</h4>
<h5>Request Body:</h5>
<pre><code>{
"email": "your-email",
"password": "your-password"
}</code></pre>
<h5>Response:</h5>
<pre><code>{
"success": true,
"data": {
"token": "admin-bearer-token",
"admin": {
"id": 1,
"email": "your-email"
}
}
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method post">POST</span> /api/admin/logout</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method put">PUT</span> /api/admin/change-password</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Request Body:</h5>
<pre><code>{
"current_password": "current-password",
"new_password": "new-password",
"new_password_confirmation": "new-password"
}</code></pre>
</div>
<h3>Client Management</h3>
<div class="endpoint">
<h4><span class="method get">GET</span> /api/admin/clients</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Response:</h5>
<pre><code>{
"success": true,
"data": {
"items": [
{
"id": 1,
"name": "Client Name",
"llm_provider_id": 1,
"created_at": "2024-12-05T00:00:00Z"
}
]
}
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method post">POST</span> /api/admin/clients</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Request Body:</h5>
<pre><code>{
"name": "New Client Name",
"llm_provider_id": 1
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method get">GET</span> /api/admin/clients/{client_id}</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method put">PUT</span> /api/admin/clients/{client_id}</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Request Body:</h5>
<pre><code>{
"name": "Updated Client Name",
"llm_provider_id": 1
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method delete">DELETE</span> /api/admin/clients/{client_id}</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method post">POST</span> /api/admin/clients/{client_id}/auth-token</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Response:</h5>
<pre><code>{
"success": true,
"data": {
"client_id": 1,
"auth_token": "generated-auth-token",
"created_at": "2024-12-05T00:00:00Z"
}
}</code></pre>
</div>
<h3>LLM Provider Management</h3>
<div class="endpoint">
<h4><span class="method get">GET</span> /api/admin/llm-providers</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Response:</h5>
<pre><code>{
"success": true,
"data": {
"items": [
{
"id": 1,
"name": "OpenAI",
"service_name": "openai",
"api_url": "https://api.openai.com/v1",
"status": "active",
"created_at": "2024-12-05T00:00:00Z"
}
]
}
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method post">POST</span> /api/admin/llm-providers</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Request Body:</h5>
<pre><code>{
"name": "OpenAI",
"service_name": "openai",
"api_url": "https://api.openai.com/v1",
"api_token": "your-api-token",
"status": "active"
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method get">GET</span> /api/admin/llm-providers/{provider_id}</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method put">PUT</span> /api/admin/llm-providers/{provider_id}</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
<h5>Request Body:</h5>
<pre><code>{
"name": "Updated OpenAI",
"service_name": "openai",
"api_url": "https://api.openai.com/v1",
"api_token": "your-api-token",
"status": "active"
}</code></pre>
</div>
<div class="endpoint">
<h4><span class="method delete">DELETE</span> /api/admin/llm-providers/{provider_id}</h4>
<h5>Headers:</h5>
<pre><code>Authorization: Bearer {admin_token}</code></pre>
</div>
<h2>Error Responses</h2>
<p>All endpoints return standardized error responses:</p>
<pre><code>{
"success": false,
"error": "error_code",
"message": "Error message",
"errors": {
"field": ["Error details"]
}
}</code></pre>
<h2>Success Responses</h2>
<p>All successful responses follow the format:</p>
<pre><code>{
"success": true,
"data": {
// Response data
}
}</code></pre>
</body>
</html>