初始化仓库及v1.0.0提交

This commit is contained in:
2026-05-05 03:21:58 +08:00
commit 813bb02672
67 changed files with 5263 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
<?php
namespace App\Controllers;
use App\Models\Config;
use App\Services\AIService;
class ChatController
{
public static function completions(): void
{
$input = json_decode(file_get_contents('php://input'), true);
$provider = $input['provider'] ?? '';
$model = $input['model'] ?? '';
$messages = $input['messages'] ?? [];
$stream = $input['stream'] ?? true;
$systemPrompt = $input['systemPrompt'] ?? '';
$thinkingMode = $input['thinkingMode'] ?? false;
if (!$provider || !$model || !$messages) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => '缺少必要参数provider、model、messages']);
return;
}
if (!is_array($messages) || empty($messages)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'messages 必须是非空数组']);
return;
}
// 获取供应商配置
$configRow = Config::getByKey('providers');
if (!$configRow) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => '未找到供应商配置']);
return;
}
$providers = json_decode($configRow['config_value'], true);
if (!is_array($providers)) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => '供应商配置格式错误']);
return;
}
$providerKey = $provider;
if (!isset($providers[$providerKey])) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => '供应商不存在: ' . $providerKey]);
return;
}
$providerConfig = $providers[$providerKey];
if (empty($providerConfig['enabled'])) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => '供应商已禁用: ' . $providerKey]);
return;
}
$models = $providerConfig['models'] ?? [];
if (!empty($models) && !in_array($model, $models)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => '模型不在供应商支持列表中: ' . $model]);
return;
}
// 非流式模式暂不支持
if (!$stream) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => '当前仅支持流式响应']);
return;
}
// 设置 SSE 响应头
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no');
// 关闭输出缓冲
while (ob_get_level()) {
ob_end_flush();
}
$options = [
'provider' => $providerConfig,
'systemPrompt' => $systemPrompt,
'thinkingMode' => (bool) $thinkingMode
];
try {
AIService::streamChat($providerKey, $model, $messages, $options, function ($chunk, $type = 'content') {
if ($type === 'thinking') {
self::sendSSE(['thinking' => $chunk]);
} else {
self::sendSSE(['content' => $chunk]);
}
});
self::sendSSE('[DONE]');
} catch (\Throwable $e) {
self::sendSSE(['type' => 'error', 'message' => $e->getMessage()]);
}
}
private static function sendSSE($data): void
{
if (is_string($data)) {
echo "data: " . $data . "\n\n";
} else {
echo "data: " . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n\n";
}
flush();
}
}