Browse Source

Merge branch 'refs/heads/dev' into R1

peterguo 2 weeks ago
parent
commit
5b5c11bdab

+ 43 - 0
app/Http/Controllers/API/DeepSeekChatController.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Http\Controllers\API;
+
+use App\Http\Controllers\Controller;
+use App\Services\LLM\DeepSeekService;
+use Illuminate\Http\Request;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+
+class DeepSeekChatController extends Controller
+{
+    public function handleStream(Request $request): StreamedResponse
+    {
+        // 一个session进行多轮对话
+        $sessionId = $request->input("session_id");
+        // 获取该session的历史对话记录
+        $history = [];
+        if ($sessionId) {
+            // 从缓存中获取该session的历史对话记录
+        }
+
+        return new StreamedResponse(function () use ($request) {
+            // 1. 设置SSE头
+            header('Content-Type: text/event-stream');
+            header('Cache-Control: no-cache');
+            header('Connection: keep-alive');
+            header('X-Accel-Buffering: no');
+
+            // 2. 获取请求参数
+            $prompt = $request->input('prompt', '');
+            // 追加该会话上下文
+            $message = [
+                ['role' => 'user', 'content' => $prompt],
+            ];
+            DeepSeekService::streamedResponseChat($message);
+        }, 200, [
+            'Content-Type' => 'text/event-stream',
+            'Access-Control-Allow-Origin' => '*'
+        ]);
+    }
+
+
+}

+ 0 - 11
app/Http/Controllers/API/TeamMemberController.php

@@ -74,17 +74,6 @@ class TeamMemberController extends Controller
 
 
     public function manageMembers(Request $request, string $projectId)
     public function manageMembers(Request $request, string $projectId)
     {
     {
-        foreach ($request->all() as $item) {
-            if (! isset($item['user_id'])) {
-                continue;
-            }
-
-            $user = User::query()->findOrFail($item['user_id']);
-            if ($user->company_id != Auth::user()->company_id) {
-                return $this->badRequest("User {$user['name']} does not belong to the current company");
-            }
-        }
-
         DB::transaction(function () use ($request, $projectId) {
         DB::transaction(function () use ($request, $projectId) {
             $project = Project::query()->findOrFail($projectId);
             $project = Project::query()->findOrFail($projectId);
 
 

+ 5 - 1
app/Libraries/BIM/Glendale/Glendale.php

@@ -10,6 +10,7 @@ use App\Models\Enums\BimFileConvertStatus;
 use App\Models\Enums\BimFileModelType;
 use App\Models\Enums\BimFileModelType;
 use Illuminate\Http\UploadedFile;
 use Illuminate\Http\UploadedFile;
 use Illuminate\Support\Arr;
 use Illuminate\Support\Arr;
+use Illuminate\Support\Facades\Log;
 
 
 class Glendale extends BIMAbstract
 class Glendale extends BIMAbstract
 {
 {
@@ -96,8 +97,11 @@ class Glendale extends BIMAbstract
     {
     {
         $append = ['modelDownloadUrl' => $bimFileBO->modelDownloadUrl];
         $append = ['modelDownloadUrl' => $bimFileBO->modelDownloadUrl];
 
 
+        $query = $this->buildQueryParams($bimFileBO, $append);
+        Log::info('Glendale uploadModelByUrl', $query);
+
         return Client::getInstance()->post('/api/app/model/transcode-file', [
         return Client::getInstance()->post('/api/app/model/transcode-file', [
-            'query' => $this->buildQueryParams($bimFileBO, $append)
+            'query' => $query
         ]);
         ]);
     }
     }
 
 

+ 78 - 0
app/Services/LLM/DeepSeekService.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace App\Services\LLM;
+
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Log;
+
+class DeepSeekService
+{
+    public static function streamedResponseChat($message): void
+    {
+        $headers = [
+            'Authorization' => 'Bearer ' . config('llm.deepseek.key'),
+            'Content-Type' => 'application/json',
+        ];
+        $body = [
+            'model' => 'deepseek-chat',
+            'messages' => $message,
+            'stream' => true,
+        ];
+
+        // 3. 调用DeepSeek流式API
+        $response = Http::withHeaders($headers)->timeout(300)->send('POST', 'https://api.deepseek.com/chat/completions', [
+            'json' => $body
+        ]);
+
+        // 4. 流式转发数据
+        $body = $response->toPsrResponse()->getBody();
+
+        while (true) {
+            if ($body->eof() || !$body->isReadable()) {
+                break;
+            }
+            $chunk = $body->getContents();
+
+            // 分割完整的JSON行
+            $lines = explode("\n\n", $chunk);
+            foreach ($lines as $line) {
+                $line = trim($line);
+                if ($line === '') {
+                    continue; // 跳过空行
+                }
+                // 处理单条事件
+                if (str_starts_with($line, 'data: ')) {
+                    // 去除 "data: " 前缀
+                    $jsonStr = substr($line, 6);
+                    self::processEvent($jsonStr);
+                }
+            }
+
+            // 检测连接是否中断
+            if (connection_aborted()) {
+                break;
+            }
+        }
+    }
+
+    // 处理单个事件的方法
+    protected static function processEvent(string $jsonStr): void
+    {
+        if ($jsonStr === '[DONE]') {
+            echo "event: end\n\n";
+            ob_flush();
+            flush();
+            return;
+        }
+
+        try {
+            $data = json_decode($jsonStr, true, 512, JSON_THROW_ON_ERROR);
+            $content = $data['choices'][0]['delta']['content'] ?? '';
+            echo "data: " . json_encode(['content' => $content], JSON_UNESCAPED_UNICODE) . "\n\n";
+            ob_flush();
+            flush();
+        } catch (\JsonException $e) {
+            Log::error('JSON 解析失败: ' . $e->getMessage());
+        }
+    }
+}

+ 6 - 0
config/llm.php

@@ -0,0 +1,6 @@
+<?php
+return [
+    'deepseek' => [
+        'key' => env('DEEPSEEK_API_SECRET', ''),
+    ]
+];

+ 2 - 0
routes/api.php

@@ -41,6 +41,8 @@ Route::middleware((function() {
     Route::post("bim/preview-image", [API\BimController::class, "setPreviewImage"]);
     Route::post("bim/preview-image", [API\BimController::class, "setPreviewImage"]);
 
 
     Route::middleware(['auth:sanctum','account.limit'])->group(function () {
     Route::middleware(['auth:sanctum','account.limit'])->group(function () {
+        Route::post('deepseek-chat', [API\DeepSeekChatController::class, 'handleStream']);
+
         //公共权限
         //公共权限
         Route::post("/logout", [API\AuthController::class, "logout"]);
         Route::post("/logout", [API\AuthController::class, "logout"]);
         Route::get("user/details", [API\UserController::class, 'details']);
         Route::get("user/details", [API\UserController::class, 'details']);