初始化仓库及v1.0.0提交
This commit is contained in:
117
app/Controllers/ChatController.php
Normal file
117
app/Controllers/ChatController.php
Normal 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user