From 9aaeae2d676fcb7d4e0f580195ba3eded87f43c8 Mon Sep 17 00:00:00 2001 From: huatuoliu Date: Tue, 9 Jul 2024 15:24:27 +0800 Subject: [PATCH 1/4] Dynamically support backend JSON response or SSE response. --- src/TencentCloud/Common/AbstractClient.php | 39 ++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/TencentCloud/Common/AbstractClient.php b/src/TencentCloud/Common/AbstractClient.php index 1492176cb6..e1b1373a40 100644 --- a/src/TencentCloud/Common/AbstractClient.php +++ b/src/TencentCloud/Common/AbstractClient.php @@ -266,23 +266,36 @@ public function callJsonWithSSEResponse($callback, $action, $body, $headers = nu $contentType = $responseData->getHeaderLine('Content-Type'); if ($contentType === 'text/event-stream') { $body = $responseData->getBody(); - $buffer = ''; - while (!$body->eof()) { - $buffer .= $body->read(1024); - $delimiterPosition = strpos($buffer, "\n\n"); - while ($delimiterPosition !== false) { - $chunk = substr($buffer, 0, $delimiterPosition + 2); - $buffer = substr($buffer, $delimiterPosition + 2); - $callback($chunk); + $buffer = ''; + if (isset($callback) && is_callable($callback)) { + while (!$body->eof()) { + $buffer .= $body->read(1024); $delimiterPosition = strpos($buffer, "\n\n"); + while ($delimiterPosition !== false) { + $chunk = substr($buffer, 0, $delimiterPosition + 2); + $buffer = substr($buffer, $delimiterPosition + 2); + + $callback($chunk); + $delimiterPosition = strpos($buffer, "\n\n"); + } } - } - if (!empty($buffer)) { - $callback($buffer); + if (!empty($buffer)) { + $callback($buffer); + } + } else { + while (!$body->eof()) { + $buffer .= $body->read(1024); + } + return $buffer; } } else { - throw new TencentCloudSDKException("ServerError", "The Response content-type is not text/event-stream " . $responseData->getBody()); - } + $resp = json_decode($responseData->getBody(), true)["Response"]; + if (array_key_exists("Error", $resp)) { + throw new TencentCloudSDKException($resp["Error"]["Code"], $resp["Error"]["Message"], $resp["RequestId"]); + } + return $resp; + } + } catch (\Exception $e) { if (!($e instanceof TencentCloudSDKException)) { throw new TencentCloudSDKException("", $e->getMessage()); From b4994b250c68e3df9da0711e119d1a197ecc32d4 Mon Sep 17 00:00:00 2001 From: huatuoliu Date: Tue, 9 Jul 2024 16:49:02 +0800 Subject: [PATCH 2/4] add test case about sse response --- .../TencentCloud/Common/CommonClientTest.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/TencentCloud/Common/CommonClientTest.php b/tests/TencentCloud/Common/CommonClientTest.php index 9338b19902..a89ed5f96c 100644 --- a/tests/TencentCloud/Common/CommonClientTest.php +++ b/tests/TencentCloud/Common/CommonClientTest.php @@ -75,4 +75,28 @@ public function testCallJsonGetFail() ); } + public function testSseResponse() + { + $cred = new Credential( + getenv("TENCENTCLOUD_SECRET_ID"), + getenv("TENCENTCLOUD_SECRET_KEY") + ); + $httpProfile = new HttpProfile(); + $httpProfile->setReqMethod("GET"); + $clientProfile = new ClientProfile(); + $clientProfile->setHttpProfile($httpProfile); + $client = new CommonClient("hunyuan", "2023-09-01", $cred, "", $clientProfile); + $params = "{\"Model\":\"hunyuan-pro\",\"Messages\":[{\"Role\":\"user\",\"Content\":\"你好\"}],\"Stream\":true,\"StreamModeration\":true,\"TopP\":1,\"Temperature\":1,\"EnableEnhancement\":true}"; + $reqBody = json_decode($params, true); + $resp = $client->callJsonWithSSEResponse("","ChatCompletions", $reqBody); + if (!is_null($resp)) + { + if (is_array($resp)) { + echo json_encode($resp, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); + } else { + echo $resp; + } + } + } + } From 1a8b73be70c5be4e4e387b3c903211c548f759c0 Mon Sep 17 00:00:00 2001 From: huatuoliu Date: Mon, 17 Nov 2025 12:01:25 +0800 Subject: [PATCH 3/4] set stream --- README.md | 5 +++-- .../Common/Http/HttpConnection.php | 2 +- .../Common/Profile/HttpProfile.php | 22 +++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2ef024810d..469ee200e0 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ 安装Composer: windows环境请访问[Composer官网](https://getcomposer.org/download/)下载安装包安装。 - + unix环境在命令行中执行以下命令安装。 > curl -sS https://getcomposer.org/installer | php @@ -38,7 +38,7 @@ composer require tencentcloud/tencentcloud-sdk-php - 无法使用官方源的的用户可以设置镜像源,例如:`composer config -g repos.packagist composer https://mirrors.tencent.com/composer/` - 推荐使用固定的 SDK 版本开发测试和发布应用,例如 `composer require tencentcloud/cvm=xx.yy.zz`。如果不需要 phpunit 等开发依赖,可以指定 `--update-no-dev` 选项。 - 在代码中添加以下引用代码。注意:如下仅为示例,composer 会在项目根目录下生成 vendor 目录,`/path/to/`为项目根目录的实际绝对路径,如果是在当前目录执行,可以省略绝对路径。 - + > require '/path/to/vendor/autoload.php'; # 示例 @@ -106,6 +106,7 @@ try { // $httpProfile->setProxy("https://ip:port"); $httpProfile->setReqMethod("GET"); // post请求(默认为post请求) $httpProfile->setReqTimeout(30); // 请求超时时间,单位为秒(默认60秒) + $httpProfile->setStream(fasle); // 关闭流式传输(默认开启) $httpProfile->setEndpoint("cvm.ap-shanghai.tencentcloudapi.com"); // 指定接入地域域名(默认就近接入) // 实例化一个client选项,可选的,没有特殊需求可以跳过 diff --git a/src/TencentCloud/Common/Http/HttpConnection.php b/src/TencentCloud/Common/Http/HttpConnection.php index 14acfb2cbc..76c6cad149 100644 --- a/src/TencentCloud/Common/Http/HttpConnection.php +++ b/src/TencentCloud/Common/Http/HttpConnection.php @@ -39,7 +39,7 @@ private function getOptions() $options = ["allow_redirects" => false]; $options["timeout"] = $this->profile->getHttpProfile()->getReqTimeout(); $options["proxy"] = $this->profile->getHttpProfile()->getProxy(); - $options["stream"] = true; + $options["stream"] = $this->profile->getHttpProfile()->getStream(); return $options; } diff --git a/src/TencentCloud/Common/Profile/HttpProfile.php b/src/TencentCloud/Common/Profile/HttpProfile.php index 3c98f45c7f..be085e64db 100644 --- a/src/TencentCloud/Common/Profile/HttpProfile.php +++ b/src/TencentCloud/Common/Profile/HttpProfile.php @@ -86,6 +86,11 @@ class HttpProfile */ private $keepAlive; + /** + * @var boolean 是否使用流式传输 + */ + private $stream; + /** * HttpProfile constructor. * @param string $protocol 请求协议 @@ -101,6 +106,7 @@ public function __construct($protocol = null, $endpoint = null, $reqMethod = nul $this->protocol = $protocol ? $protocol : HttpProfile::$REQ_HTTPS; $this->rootDomain = "tencentcloudapi.com"; $this->keepAlive = false; + $this->stream = true; } /** @@ -212,4 +218,20 @@ public function setKeepAlive($flag) { public function getKeepAlive() { return $this->keepAlive; } + + /** + * 设置是否使用流式传输 + * @param boolean $stream 是否使用流式传输 + */ + public function setStream($stream) { + $this->stream = $stream; + } + + /** + * 获取是否使用流式传输 + * @return boolean 是否使用流式传输 + */ + public function getStream() { + return $this->stream; + } } From fee35aaedd29682974e8be2d8d44f5c306877da1 Mon Sep 17 00:00:00 2001 From: huatuoliu Date: Mon, 17 Nov 2025 19:39:00 +0800 Subject: [PATCH 4/4] set stream --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 469ee200e0..081b82540a 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ try { // $httpProfile->setProxy("https://ip:port"); $httpProfile->setReqMethod("GET"); // post请求(默认为post请求) $httpProfile->setReqTimeout(30); // 请求超时时间,单位为秒(默认60秒) - $httpProfile->setStream(fasle); // 关闭流式传输(默认开启) + $httpProfile->setStream(false); // 关闭流式传输(默认开启) $httpProfile->setEndpoint("cvm.ap-shanghai.tencentcloudapi.com"); // 指定接入地域域名(默认就近接入) // 实例化一个client选项,可选的,没有特殊需求可以跳过