1 line
27 KiB
JSON
1 line
27 KiB
JSON
{"repo": "aron555/pbuexpert.ru", "files": {"local/modules/local.main/lib/Service/DeepSeek/DeepSeekService.php": {"53dd8edbbc3c9c051002a39dd1a79a7218821950": {"t": 1785745789.2485821, "n": 12266, "h": "25b91d66c5008350", "c": "<?php\ndeclare(strict_types=1);\n\nnamespace Local\\Main\\Service\\DeepSeek;\n\nuse Bitrix\\Main\\ArgumentException;\nuse Bitrix\\Main\\Error;\nuse Bitrix\\Main\\Result;\nuse Bitrix\\Main\\Web\\HttpClient;\nuse Bitrix\\Main\\Web\\Json;\nuse Exception;\n\nclass DeepSeekService\n{\n private string $apiKey;\n private string $host;\n private HttpClient $httpClient;\n private ?Result $result = null;\n\n // Константы для методов API\n public const string METHOD_COMPLETIONS = 'chat/completions';\n public const string METHOD_EMBEDDINGS = 'embeddings';\n public const string METHOD_MODELS = 'models';\n\n // Константы для моделей DeepSeek\n public const string MODEL_DEEPSEEK_CHAT = 'deepseek-chat';\n public const string MODEL_DEEPSEEK_CODER = 'deepseek-coder';\n public const string MODEL_DEEPSEEK_REASONER = 'deepseek-reasoner';\n public const string MODEL_DEEPSEEK_R1 = 'deepseek-r1';\n\n // Константы для ролей\n public const string ROLE_SYSTEM = 'system';\n public const string ROLE_USER = 'user';\n public const string ROLE_ASSISTANT = 'assistant';\n\n public function __construct()\n {\n $this->apiKey = $_ENV['DEEPSEEK_API_KEY'] ?? '';\n $this->host = 'https://api.deepseek.com/';\n $this->httpClient = new HttpClient();\n }\n\n public function getResult(): ?Result\n {\n return $this->result;\n }\n\n /**\n * Выполняет запрос к DeepSeek API\n *\n * @param string $method Метод API\n * @param array $parameters Параметры запроса\n * @param string $httpMethod HTTP-метод\n * @param array $headers Дополнительные заголовки\n * @return Result Результат запроса\n */\n private function query(\n string $method,\n array $parameters = [],\n string $httpMethod = HttpClient::HTTP_POST,\n array $headers = []\n ): Result\n {\n $result = new Result();\n\n if (empty($this->apiKey)) {\n $result->addError(new Error('DeepSeek API key is not configured'));\n $this->result = $result;\n return $result;\n }\n\n // Настраиваем HttpClient\n $this->httpClient->setHeader('Authorization', 'Bearer ' . $this->apiKey);\n $this->httpClient->setHeader('Content-Type', 'application/json');\n $this->httpClient->setHeader('Accept', 'application/json');\n $this->httpClient->setHeader('User-Agent', 'Mozilla/5.0 (compatible; DeepSeekAPI/1.0)');\n $this->httpClient->setTimeout(60);\n $this->httpClient->setStreamTimeout(120);\n\n // Добавляем дополнительные заголовки\n foreach ($headers as $header => $value) {\n $this->httpClient->setHeader($header, $value);\n }\n\n $url = $this->host . $method;\n\n try {\n if ($httpMethod === HttpClient::HTTP_POST) {\n $this->httpClient->post($url, Json::encode($parameters));\n } elseif ($httpMethod === HttpClient::HTTP_GET) {\n if (!empty($parameters)) {\n $url .= '?' . http_build_query($parameters);\n }\n $this->httpClient->get($url);\n }\n\n // Проверяем ошибки\n $errors = $this->httpClient->getError();\n if (!empty($errors)) {\n $result->addError(new Error('Network error: ' . implode(', ', $errors)));\n $this->result = $result;\n return $result;\n }\n\n $responseContent = $this->httpClient->getResult();\n $statusCode = $this->httpClient->getStatus();\n\n if ($statusCode !== 200) {\n $result->addError(new Error(\"HTTP error {$statusCode}\"));\n }\n\n if (empty($responseContent)) {\n $result->addError(new Error('Empty response from API'));\n $this->result = $result;\n return $result;\n }\n\n $data = Json::decode($responseContent);\n\n // Проверяем наличие ошибок в ответе\n if (isset($data['error'])) {\n $errorMessage = $data['error']['message'] ?? 'Unknown API error';\n $result->addError(new Error($errorMessage));\n } elseif (isset($data['choices']) || isset($data['data'])) {\n $result->setData($data);\n } else {\n $result->setData($data);\n }\n\n } catch (ArgumentException $e) {\n $result->addError(new Error('JSON decode error: ' . $e->getMessage()));\n } catch (Exception $e) {\n $result->addError(new Error('Request error: ' . $e->getMessage()));\n }\n\n $this->result = $result;\n return $result;\n }\n\n /**\n * Отправляет запрос на генерацию текста\n *\n * @param string|array $messages Сообщения для модели\n * @param array $options Дополнительные параметры\n * @return Result Результат запроса\n */\n public function chat($messages, array $options = []): Result\n {\n // Если передан простой текст, преобразуем в массив сообщений\n if (is_string($messages)) {\n $messages = [\n [\n 'role' => self::ROLE_USER,\n 'content' => $messages\n ]\n ];\n }\n\n $parameters = array_merge([\n 'model' => self::MODEL_DEEPSEEK_CHAT,\n 'messages' => $messages,\n 'temperature' => 0.7,\n 'max_tokens' => 2000, // DeepSeek поддерживает большие контексты\n 'stream' => false,\n ], $options);\n\n return $this->query(self::METHOD_COMPLETIONS, $parameters);\n }\n\n /**\n * Получает ответ от модели в виде текста\n *\n * @param string|array $messages Сообщения для модели\n * @param array $options Дополнительные параметры\n * @return string|null Ответ модели или null при ошибке\n */\n public function getTextResponse($messages, array $options = []): ?string\n {\n $result = $this->chat($messages, $options);\n\n if ($result->isSuccess()) {\n $data = $result->getData();\n if (isset($data['choices'][0]['message']['content'])) {\n return $data['choices'][0]['message']['content'];\n }\n }\n\n // Логируем ошибки\n if (!$result->isSuccess()) {\n $errors = $result->getErrorMessages();\n error_log('DeepSeek API error: ' . implode(', ', $errors));\n }\n\n return null;\n }\n\n /**\n * Создает эмбеддинги для текста\n *\n * @param string|array $input Текст или массив текстов\n * @param string $model Модель для создания эмбеддингов\n * @return Result Результат запроса\n */\n public function embeddings($input, string $model = 'text-embedding'): Result\n {\n $parameters = [\n 'model' => $model,\n 'input' => $input\n ];\n\n return $this->query(self::METHOD_EMBEDDINGS, $parameters);\n }\n\n /**\n * Получает список доступных моделей\n *\n * @return Result Результат запроса\n */\n public function getModels(): Result\n {\n return $this->query(self::METHOD_MODELS, [], HttpClient::HTTP_GET);\n }\n\n /**\n * Простая проверка соединения\n *\n * @return Result Результат проверки\n */\n public function testConnection(): Result\n {\n $result = new Result();\n\n // Проверяем наличие ключа\n if (empty($this->apiKey)) {\n $result->addError(new Error('DeepSeek API key is not configured'));\n return $result;\n }\n\n // Пытаемся получить список моделей\n $modelsResult = $this->getModels();\n\n if ($modelsResult->isSuccess()) {\n $result->setData(['status' => 'connected', 'message' => 'API доступен']);\n } else {\n $result->addError(new Error('Failed to connect to DeepSeek API'));\n }\n\n return $result;\n }\n\n /**\n * Потоковая генерация (базовая реализация)\n *\n * @param array|string $messages Сообщения для модели\n * @param callable $callback Функция обратного вызова\n * @param array $options Дополнительные параметры\n * @return bool Успешность выполнения\n */\n public function streamChat(array|string $messages, callable $callback, array $options = []): bool\n {\n // Если передан простой текст, преобразуем в массив сообщений\n if (is_string($messages)) {\n $messages = [\n [\n 'role' => self::ROLE_USER,\n 'content' => $messages\n ]\n ];\n }\n\n $parameters = array_merge([\n 'model' => self::MODEL_DEEPSEEK_CHAT,\n 'messages' => $messages,\n 'temperature' => 0.7,\n 'max_tokens' => 2000,\n 'stream' => true,\n ], $options);\n\n if (empty($this->apiKey)) {\n return false;\n }\n\n $url = $this->host . self::METHOD_COMPLETIONS;\n\n $streamClient = new HttpClient();\n $streamClient->setHeader('Authorization', 'Bearer ' . $this->apiKey);\n $streamClient->setHeader('Content-Type', 'application/json');\n $streamClient->setHeader('Accept', 'text/event-stream');\n $streamClient->setHeader('User-Agent', 'Mozilla/5.0 (compatible; DeepSeekAPI/1.0)');\n $streamClient->setTimeout(300);\n\n try {\n $streamClient->post($url, Json::encode($parameters));\n\n $errors = $streamClient->getError();\n if (!empty($errors)) {\n error_log('DeepSeek stream error: ' . print_r($errors, true));\n return false;\n }\n\n $streamContent = $streamClient->getResult();\n\n if (empty($streamContent)) {\n return false;\n }\n\n $lines = explode(\"\\n\", $streamContent);\n\n foreach ($lines as $line) {\n if (str_starts_with($line, 'data: ')) {\n $data = substr($line, 6);\n\n if ($data === '[DONE]') {\n break;\n }\n\n if (!empty($data)) {\n try {\n $chunk = Json::decode($data);\n\n if (isset($chunk['choices'][0]['delta']['content'])) {\n $content = $chunk['choices'][0]['delta']['content'];\n call_user_func($callback, $content, $chunk);\n }\n } catch (Exception $e) {\n continue;\n }\n }\n }\n }\n\n return true;\n } catch (Exception $e) {\n error_log('DeepSeek stream exception: ' . $e->getMessage());\n return false;\n }\n }\n\n /**\n * Создает системное сообщение\n */\n public static function createSystemMessage(string $content): array\n {\n return [\n 'role' => self::ROLE_SYSTEM,\n 'content' => $content\n ];\n }\n\n /**\n * Создает пользовательское сообщение\n */\n public static function createUserMessage(string $content): array\n {\n return [\n 'role' => self::ROLE_USER,\n 'content' => $content\n ];\n }\n\n /**\n * Создает сообщение ассистента\n */\n public static function createAssistantMessage(string $content): array\n {\n return [\n 'role' => self::ROLE_ASSISTANT,\n 'content' => $content\n ];\n }\n\n /**\n * Устанавливает API ключ\n */\n public function setApiKey(string $apiKey): void\n {\n $this->apiKey = $apiKey;\n }\n\n /**\n * Получает информацию о стоимости запроса\n */\n public function getUsageInfo(): array\n {\n return [\n 'deepseek-chat' => [\n 'input' => '$0.14 per 1M tokens',\n 'output' => '$0.28 per 1M tokens',\n 'context' => '128K tokens',\n 'free_credit' => '$1 on registration'\n ],\n 'deepseek-coder' => [\n 'input' => '$0.28 per 1M tokens',\n 'output' => '$0.56 per 1M tokens',\n 'context' => '128K tokens',\n 'free_credit' => '$1 on registration'\n ]\n ];\n }\n}\n"}, "860f399543eefa65b50c4ec4106ea4a6d3e583f9": {"t": 1785756516.2796898, "n": 12266, "h": "25b91d66c5008350", "c": "<?php\ndeclare(strict_types=1);\n\nnamespace Local\\Main\\Service\\DeepSeek;\n\nuse Bitrix\\Main\\ArgumentException;\nuse Bitrix\\Main\\Error;\nuse Bitrix\\Main\\Result;\nuse Bitrix\\Main\\Web\\HttpClient;\nuse Bitrix\\Main\\Web\\Json;\nuse Exception;\n\nclass DeepSeekService\n{\n private string $apiKey;\n private string $host;\n private HttpClient $httpClient;\n private ?Result $result = null;\n\n // Константы для методов API\n public const string METHOD_COMPLETIONS = 'chat/completions';\n public const string METHOD_EMBEDDINGS = 'embeddings';\n public const string METHOD_MODELS = 'models';\n\n // Константы для моделей DeepSeek\n public const string MODEL_DEEPSEEK_CHAT = 'deepseek-chat';\n public const string MODEL_DEEPSEEK_CODER = 'deepseek-coder';\n public const string MODEL_DEEPSEEK_REASONER = 'deepseek-reasoner';\n public const string MODEL_DEEPSEEK_R1 = 'deepseek-r1';\n\n // Константы для ролей\n public const string ROLE_SYSTEM = 'system';\n public const string ROLE_USER = 'user';\n public const string ROLE_ASSISTANT = 'assistant';\n\n public function __construct()\n {\n $this->apiKey = $_ENV['DEEPSEEK_API_KEY'] ?? '';\n $this->host = 'https://api.deepseek.com/';\n $this->httpClient = new HttpClient();\n }\n\n public function getResult(): ?Result\n {\n return $this->result;\n }\n\n /**\n * Выполняет запрос к DeepSeek API\n *\n * @param string $method Метод API\n * @param array $parameters Параметры запроса\n * @param string $httpMethod HTTP-метод\n * @param array $headers Дополнительные заголовки\n * @return Result Результат запроса\n */\n private function query(\n string $method,\n array $parameters = [],\n string $httpMethod = HttpClient::HTTP_POST,\n array $headers = []\n ): Result\n {\n $result = new Result();\n\n if (empty($this->apiKey)) {\n $result->addError(new Error('DeepSeek API key is not configured'));\n $this->result = $result;\n return $result;\n }\n\n // Настраиваем HttpClient\n $this->httpClient->setHeader('Authorization', 'Bearer ' . $this->apiKey);\n $this->httpClient->setHeader('Content-Type', 'application/json');\n $this->httpClient->setHeader('Accept', 'application/json');\n $this->httpClient->setHeader('User-Agent', 'Mozilla/5.0 (compatible; DeepSeekAPI/1.0)');\n $this->httpClient->setTimeout(60);\n $this->httpClient->setStreamTimeout(120);\n\n // Добавляем дополнительные заголовки\n foreach ($headers as $header => $value) {\n $this->httpClient->setHeader($header, $value);\n }\n\n $url = $this->host . $method;\n\n try {\n if ($httpMethod === HttpClient::HTTP_POST) {\n $this->httpClient->post($url, Json::encode($parameters));\n } elseif ($httpMethod === HttpClient::HTTP_GET) {\n if (!empty($parameters)) {\n $url .= '?' . http_build_query($parameters);\n }\n $this->httpClient->get($url);\n }\n\n // Проверяем ошибки\n $errors = $this->httpClient->getError();\n if (!empty($errors)) {\n $result->addError(new Error('Network error: ' . implode(', ', $errors)));\n $this->result = $result;\n return $result;\n }\n\n $responseContent = $this->httpClient->getResult();\n $statusCode = $this->httpClient->getStatus();\n\n if ($statusCode !== 200) {\n $result->addError(new Error(\"HTTP error {$statusCode}\"));\n }\n\n if (empty($responseContent)) {\n $result->addError(new Error('Empty response from API'));\n $this->result = $result;\n return $result;\n }\n\n $data = Json::decode($responseContent);\n\n // Проверяем наличие ошибок в ответе\n if (isset($data['error'])) {\n $errorMessage = $data['error']['message'] ?? 'Unknown API error';\n $result->addError(new Error($errorMessage));\n } elseif (isset($data['choices']) || isset($data['data'])) {\n $result->setData($data);\n } else {\n $result->setData($data);\n }\n\n } catch (ArgumentException $e) {\n $result->addError(new Error('JSON decode error: ' . $e->getMessage()));\n } catch (Exception $e) {\n $result->addError(new Error('Request error: ' . $e->getMessage()));\n }\n\n $this->result = $result;\n return $result;\n }\n\n /**\n * Отправляет запрос на генерацию текста\n *\n * @param string|array $messages Сообщения для модели\n * @param array $options Дополнительные параметры\n * @return Result Результат запроса\n */\n public function chat($messages, array $options = []): Result\n {\n // Если передан простой текст, преобразуем в массив сообщений\n if (is_string($messages)) {\n $messages = [\n [\n 'role' => self::ROLE_USER,\n 'content' => $messages\n ]\n ];\n }\n\n $parameters = array_merge([\n 'model' => self::MODEL_DEEPSEEK_CHAT,\n 'messages' => $messages,\n 'temperature' => 0.7,\n 'max_tokens' => 2000, // DeepSeek поддерживает большие контексты\n 'stream' => false,\n ], $options);\n\n return $this->query(self::METHOD_COMPLETIONS, $parameters);\n }\n\n /**\n * Получает ответ от модели в виде текста\n *\n * @param string|array $messages Сообщения для модели\n * @param array $options Дополнительные параметры\n * @return string|null Ответ модели или null при ошибке\n */\n public function getTextResponse($messages, array $options = []): ?string\n {\n $result = $this->chat($messages, $options);\n\n if ($result->isSuccess()) {\n $data = $result->getData();\n if (isset($data['choices'][0]['message']['content'])) {\n return $data['choices'][0]['message']['content'];\n }\n }\n\n // Логируем ошибки\n if (!$result->isSuccess()) {\n $errors = $result->getErrorMessages();\n error_log('DeepSeek API error: ' . implode(', ', $errors));\n }\n\n return null;\n }\n\n /**\n * Создает эмбеддинги для текста\n *\n * @param string|array $input Текст или массив текстов\n * @param string $model Модель для создания эмбеддингов\n * @return Result Результат запроса\n */\n public function embeddings($input, string $model = 'text-embedding'): Result\n {\n $parameters = [\n 'model' => $model,\n 'input' => $input\n ];\n\n return $this->query(self::METHOD_EMBEDDINGS, $parameters);\n }\n\n /**\n * Получает список доступных моделей\n *\n * @return Result Результат запроса\n */\n public function getModels(): Result\n {\n return $this->query(self::METHOD_MODELS, [], HttpClient::HTTP_GET);\n }\n\n /**\n * Простая проверка соединения\n *\n * @return Result Результат проверки\n */\n public function testConnection(): Result\n {\n $result = new Result();\n\n // Проверяем наличие ключа\n if (empty($this->apiKey)) {\n $result->addError(new Error('DeepSeek API key is not configured'));\n return $result;\n }\n\n // Пытаемся получить список моделей\n $modelsResult = $this->getModels();\n\n if ($modelsResult->isSuccess()) {\n $result->setData(['status' => 'connected', 'message' => 'API доступен']);\n } else {\n $result->addError(new Error('Failed to connect to DeepSeek API'));\n }\n\n return $result;\n }\n\n /**\n * Потоковая генерация (базовая реализация)\n *\n * @param array|string $messages Сообщения для модели\n * @param callable $callback Функция обратного вызова\n * @param array $options Дополнительные параметры\n * @return bool Успешность выполнения\n */\n public function streamChat(array|string $messages, callable $callback, array $options = []): bool\n {\n // Если передан простой текст, преобразуем в массив сообщений\n if (is_string($messages)) {\n $messages = [\n [\n 'role' => self::ROLE_USER,\n 'content' => $messages\n ]\n ];\n }\n\n $parameters = array_merge([\n 'model' => self::MODEL_DEEPSEEK_CHAT,\n 'messages' => $messages,\n 'temperature' => 0.7,\n 'max_tokens' => 2000,\n 'stream' => true,\n ], $options);\n\n if (empty($this->apiKey)) {\n return false;\n }\n\n $url = $this->host . self::METHOD_COMPLETIONS;\n\n $streamClient = new HttpClient();\n $streamClient->setHeader('Authorization', 'Bearer ' . $this->apiKey);\n $streamClient->setHeader('Content-Type', 'application/json');\n $streamClient->setHeader('Accept', 'text/event-stream');\n $streamClient->setHeader('User-Agent', 'Mozilla/5.0 (compatible; DeepSeekAPI/1.0)');\n $streamClient->setTimeout(300);\n\n try {\n $streamClient->post($url, Json::encode($parameters));\n\n $errors = $streamClient->getError();\n if (!empty($errors)) {\n error_log('DeepSeek stream error: ' . print_r($errors, true));\n return false;\n }\n\n $streamContent = $streamClient->getResult();\n\n if (empty($streamContent)) {\n return false;\n }\n\n $lines = explode(\"\\n\", $streamContent);\n\n foreach ($lines as $line) {\n if (str_starts_with($line, 'data: ')) {\n $data = substr($line, 6);\n\n if ($data === '[DONE]') {\n break;\n }\n\n if (!empty($data)) {\n try {\n $chunk = Json::decode($data);\n\n if (isset($chunk['choices'][0]['delta']['content'])) {\n $content = $chunk['choices'][0]['delta']['content'];\n call_user_func($callback, $content, $chunk);\n }\n } catch (Exception $e) {\n continue;\n }\n }\n }\n }\n\n return true;\n } catch (Exception $e) {\n error_log('DeepSeek stream exception: ' . $e->getMessage());\n return false;\n }\n }\n\n /**\n * Создает системное сообщение\n */\n public static function createSystemMessage(string $content): array\n {\n return [\n 'role' => self::ROLE_SYSTEM,\n 'content' => $content\n ];\n }\n\n /**\n * Создает пользовательское сообщение\n */\n public static function createUserMessage(string $content): array\n {\n return [\n 'role' => self::ROLE_USER,\n 'content' => $content\n ];\n }\n\n /**\n * Создает сообщение ассистента\n */\n public static function createAssistantMessage(string $content): array\n {\n return [\n 'role' => self::ROLE_ASSISTANT,\n 'content' => $content\n ];\n }\n\n /**\n * Устанавливает API ключ\n */\n public function setApiKey(string $apiKey): void\n {\n $this->apiKey = $apiKey;\n }\n\n /**\n * Получает информацию о стоимости запроса\n */\n public function getUsageInfo(): array\n {\n return [\n 'deepseek-chat' => [\n 'input' => '$0.14 per 1M tokens',\n 'output' => '$0.28 per 1M tokens',\n 'context' => '128K tokens',\n 'free_credit' => '$1 on registration'\n ],\n 'deepseek-coder' => [\n 'input' => '$0.28 per 1M tokens',\n 'output' => '$0.56 per 1M tokens',\n 'context' => '128K tokens',\n 'free_credit' => '$1 on registration'\n ]\n ];\n }\n}\n"}}}} |