f试ssefahah可能卡卡卡马卡卡计算机视觉事实上事实上飒飒飒gj◐◐◐◐hfkttkgdgkmcuocucocucoc顶顶顶顶顶顶顶顶顶顶顶顶uco朵朵可可放2巍峨2555555666369🌹 �����ѩ�����һ����dddf2qevf2fv69666 ? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!AssistantService.php000064400000042307152666216710010571 0ustar00apiKey = ApiHelper::setOpenAiKey(); $this->client = new Client; $this->openai = OpenAI::factory() ->withApiKey($this->apiKey) ->withHttpHeader('OpenAI-Beta', 'assistants=v2') ->make(); } /** * @throws GuzzleException|Exception */ public function createFile($file) { $filePath = 'assistant/' . Str::random(20) . '.' . $file->guessExtension(); Storage::disk('public')->put($filePath, file_get_contents($file)); $fullPath = Storage::disk('public')->path($filePath); if (! file_exists($fullPath)) { throw new RuntimeException('File could not be saved or found: ' . $fullPath); } try { return $this->openai->files()->upload([ 'purpose' => 'assistants', 'file' => fopen($fullPath, 'rb'), ])->toArray(); } catch (Exception $e) { return [ 'status' => 'error', 'message' => $e->getMessage(), ]; } } /** * @throws GuzzleException|JsonException */ public function createVectorStoreFiles($vectorStoreId, $fileId) { try { $response = $this->client->post(self::BASE_URL . str_replace('{vector_store_id}', $vectorStoreId, self::VECTOR_STORE_FILE), [ 'headers' => $this->getHeaders(), 'json' => ['file_id' => $fileId], ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } catch (ClientException $e) { $errorResponse = $e->getResponse(); $errorBody = $errorResponse->getBody()->getContents(); $errorData = json_decode($errorBody, true, 512, JSON_THROW_ON_ERROR); return [ 'status' => 'error', 'message' => $errorData['error']['message'] ?? 'vector upload files error', ]; } } /** * @throws GuzzleException|JsonException */ public function listVectorStoreFiles($vectorStoreId): array { $response = $this->client->get(self::BASE_URL . str_replace('{vector_store_id}', $vectorStoreId, self::VECTOR_STORE_FILE), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function deleteVectorStoreFiles($vectorStoreId, $fileId): array { $url = str_replace( ['{vector_store_id}', '{file_id}'], [$vectorStoreId, $fileId], self::BASE_URL . self::VECTOR_STORE_FILE_DELETE ); $response = $this->client->delete($url, [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function createVectorStore(): array { $response = $this->client->post(Helper::parseUrl(self::BASE_URL, self::VECTOR_STORE), [ 'headers' => $this->getHeaders(), 'json' => ['name' => 'AI Assistant'], ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function showVectorStore($vectorId): array { $response = $this->client->get(Helper::parseUrl(self::BASE_URL, self::VECTOR_STORE_FILE, $vectorId), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function listVectorStore(): array { $response = $this->client->get(Helper::parseUrl(self::BASE_URL, self::VECTOR_STORE), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function deleteVectorStore($vectorId): array { $response = $this->client->delete(Helper::parseUrl(self::BASE_URL, self::VECTOR_STORE, $vectorId), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function listFiles(): array { $response = $this->client->get(Helper::parseUrl(self::BASE_URL, self::FILES), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function showFiles($fileId): array { $response = $this->client->get(Helper::parseUrl(self::BASE_URL, self::FILES, $fileId), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException|JsonException */ public function deleteFile($fileId): array { $response = $this->client->delete(Helper::parseUrl(self::BASE_URL, self::FILES, $fileId), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException */ public function createAssistant($instructions, $assistantName, $model, $resources = null, $tools = null, $description = null, $temperature = null, $topP = null) { $array = [ 'name' => $assistantName, 'instructions' => $instructions, 'model' => $model, ]; if (! is_null($description)) { $array['description'] = $description; } if (! is_null($resources)) { $array['tool_resources'] = $resources; } if (! is_null($tools)) { $array['tools'] = $tools; } if (! is_null($temperature)) { $array['temperature'] = (float) $temperature; } if (! is_null($topP)) { $array['top_p'] = (float) $topP; } try { $response = $this->client->post(Helper::parseUrl(self::BASE_URL, self::ASSISTANT_URL), [ 'headers' => $this->getHeaders(), 'json' => $array, ]); return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR); } catch (ClientException|JsonException $e) { $errorResponse = $e->getResponse(); $errorBody = $errorResponse->getBody()->getContents(); $errorData = json_decode($errorBody, true, 512, JSON_THROW_ON_ERROR); return [ 'status' => 'error', 'message' => $errorData['error']['message'] ?? 'api error', ]; } } /** * @throws GuzzleException|JsonException */ public function updateAssistant($assistantId, $instructions, $assistantName, $model, $resources = null, $tools = null, $description = null, $temperature = null, $topP = null) { $array = [ 'name' => $assistantName, 'instructions' => $instructions, 'model' => $model, ]; if (! is_null($description)) { $array['description'] = $description; } if (! empty($resources)) { $array['tool_resources'] = $resources; } if (! is_null($tools)) { $array['tools'] = $tools; } if (! is_null($temperature)) { $array['temperature'] = (float) $temperature; } if (! is_null($topP)) { $array['top_p'] = (float) $topP; } try { $response = $this->client->post(Helper::parseUrl(self::BASE_URL, self::ASSISTANT_URL, $assistantId), [ 'headers' => $this->getHeaders(), 'json' => $array, ]); return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR); } catch (ClientException $e) { $errorResponse = $e->getResponse(); $errorBody = $errorResponse->getBody()->getContents(); $errorData = json_decode($errorBody, true, 512, JSON_THROW_ON_ERROR); return [ 'status' => 'error', 'message' => $errorData['error']['message'] ?? 'api error', ]; } } /** * @throws GuzzleException */ public function listModels(): array|Collection { try { $response = $this->client->get(Helper::parseUrl(self::BASE_URL . self::MODELS), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); $models = json_decode($response, true, 512, JSON_THROW_ON_ERROR)['data']; return collect($models)->filter(function ($model) { return str_starts_with($model['id'], 'gpt'); })->reject(function ($model) { return str_starts_with($model['id'], 'gpt-5-') || $model['id'] === 'gpt-5' || $model['id'] === 'gpt-image-1'; }); } catch (Exception $e) { return []; } } /** * @throws GuzzleException */ public function listAssistant() { try { $response = $this->client->get(Helper::parseUrl(self::BASE_URL, self::ASSISTANT_URL), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } catch (Exception $e) { return [ 'status' => 'error', 'message' => 'openai api key error', ]; } } /** * @throws GuzzleException */ public function deleteAssistant($assistantId): string { return $this->client->delete(Helper::parseUrl(self::BASE_URL, self::ASSISTANT_URL, $assistantId), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); } /** * @throws GuzzleException * @throws JsonException */ public function showAssistant($assistantId): array { $response = $this->client->get(Helper::parseUrl(self::BASE_URL, self::ASSISTANT_URL, $assistantId), [ 'headers' => $this->getHeaders(), ])->getBody()->getContents(); return json_decode($response, true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException * @throws JsonException */ public function createThread(): array { $response = $this->client->post(Helper::parseUrl(self::BASE_URL, self::THREAD_URL), [ 'headers' => $this->getHeaders(), ]); return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException * @throws JsonException */ public function createMessage($threadId, $message): array { if (count($message) >= 2 || $message[0]['role'] === 'system') { $message = end($message); } $message['content'] = collect($message['content'])->map(function ($item) { if (isset($item['type']) && ($item['type'] === 'image_url') && str_starts_with($item['image_url']['url'], '/uploads')) { $item['image_url']['url'] = config('app.url') . $item['image_url']['url']; } return $item; })->toArray(); if (! isset($message['content'][0]['type'])) { $message['content'] = $message['content'][0]; } $response = $this->client->post(self::BASE_URL . str_replace('{thread_id}', $threadId, self::MESSAGE_URL), [ 'headers' => $this->getHeaders(), 'json' => $message, ]); return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR); } /** * @throws GuzzleException */ public function createRun($chat_bot, $assistantId, $threadId, $main_message, BaseDriver $driver): ?StreamedResponse { $total_used_tokens = 0; $output = ''; $responsedText = ''; return response()->stream(function () use ($assistantId, $threadId, $main_message, &$total_used_tokens, &$output, &$responsedText, $driver) { $chat = UserOpenaiChat::query()->where('id', $main_message->user_openai_chat_id)->first(); echo "event: message\n"; echo 'data: ' . $main_message->id . "\n\n"; if (! $driver->hasCreditBalance()) { echo PHP_EOL; echo "event: data\n"; echo 'data: ' . __('You have no credits left. Please buy more credits to continue.'); echo "\n\n"; flush(); echo "event: stop\n"; echo 'data: [DONE]'; echo "\n\n"; flush(); return null; } $stream = $this->client->post(self::BASE_URL . str_replace('{thread_id}', $threadId, self::RUN_URL), [ 'headers' => $this->getHeaders(), 'json' => [ 'assistant_id' => $assistantId, 'stream' => true, ], 'stream' => true, ]); $data = $stream->getBody()->getContents(); $events = explode("\n\n", $data); foreach ($events as $event) { if (str_contains($event, 'thread.message.delta')) { $dataStart = strpos($event, '{'); if ($dataStart !== false) { $jsonData = substr($event, $dataStart); $eventData = json_decode($jsonData, true); if (isset($eventData['delta']['content'])) { foreach ($eventData['delta']['content'] as $content) { if ($content['type'] === 'text') { $value = $content['text']['value']; $text = str_replace(["\r\n", "\r", "\n"], '
', $value); $output .= $text; $responsedText .= $value; $total_used_tokens += countWords($value); if (connection_aborted()) { break 2; } echo PHP_EOL; echo "event: data\n"; echo 'data: ' . $text; echo "\n\n"; flush(); } } } } } } echo "event: stop\n"; echo 'data: [DONE]'; echo "\n\n"; flush(); $main_message->response = $responsedText; $main_message->output = $output; $main_message->credits = $total_used_tokens; $main_message->words = $total_used_tokens; $main_message->save(); $driver->input($responsedText)->calculateCredit()->decreaseCredit(); Usage::getSingle()->updateWordCounts($driver->calculate()); $chat->total_credits += $total_used_tokens; $chat->save(); }, 200, [ 'Cache-Control' => 'no-cache', 'X-Accel-Buffering' => 'no', 'Content-Type' => 'text/event-stream', ]); } private function getHeaders(): array { return [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $this->apiKey, 'OpenAI-Beta' => 'assistants=v2', ]; } }