├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── NOTICE.txt ├── README.md ├── composer.json ├── doc └── speech │ ├── IGR.md │ ├── ISE.md │ ├── LFASR.md │ ├── TC.md │ └── TTS.md ├── phpunit.xml.dist ├── src └── Speech │ ├── Config │ ├── IgrConfig.php │ ├── IseConfig.php │ ├── LfasrConfig.php │ ├── TcConfig.php │ └── TtsConfig.php │ ├── Constants │ ├── IgrConstants.php │ ├── IseConstants.php │ ├── LfasrConstants.php │ ├── TcConstants.php │ └── TtsConstants.php │ ├── Helper │ └── SliceIdGenerator.php │ ├── IgrClient.php │ ├── IseClient.php │ ├── LfasrClient.php │ ├── TcClient.php │ ├── Traits │ ├── IgrTrait.php │ ├── IseTrait.php │ ├── LfasrTrait.php │ ├── TcTrait.php │ └── TtsTrait.php │ └── TtsClient.php └── tests ├── Unit └── Speech │ ├── BaseClientTest.php │ ├── Config │ └── TtsConfigTest.php │ ├── Helper │ └── SliceIdGeneratorTest.php │ ├── IgrClientTest.php │ ├── IseClientTest.php │ ├── LfasrClientTest.php │ ├── TcClientTest.php │ └── TtsClientTest.php └── input ├── 1.wav ├── igr_pcm_16k.pcm └── iseTest.mp3 /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.php] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 4 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # vendor 2 | vendor/ 3 | 4 | # phplint-cache 5 | .phplint-cache 6 | 7 | # composer 8 | composer.lock 9 | 10 | # tests 11 | credentials.yml 12 | tests/output 13 | coverageOutput 14 | clover.xml 15 | *.log 16 | 17 | # vscode 18 | .vscode/ 19 | 20 | # macos 21 | .DS_Store 22 | 23 | # phpstorm 24 | .idea 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | script: 4 | - composer install 5 | - ./vendor/bin/phpunit --coverage-clover coverage.xml 6 | 7 | after_success: 8 | - bash <(curl -s https://codecov.io/bash) 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Copyright 1999-2021 2 | iFLYTEK Corporation All Rights Reserved. See LICENSE.txt for license information. 3 | 4 | NOTICES: 5 | -------- 6 | This product uses parts of source code from google-cloud-php, including those that have been modified. 7 | 8 | ----- 9 | ## PHP 10 | This product uses the PHP programming language by the PHP authors. 11 | 12 | * LICENSE: Apache-2.0 License 13 | 14 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 15 | 16 | 1. Definitions. 17 | 18 | "License" shall mean the terms and conditions for use, reproduction, 19 | and distribution as defined by Sections 1 through 9 of this document. 20 | 21 | "Licensor" shall mean the copyright owner or entity authorized by 22 | the copyright owner that is granting the License. 23 | 24 | "Legal Entity" shall mean the union of the acting entity and all 25 | other entities that control, are controlled by, or are under common 26 | control with that entity. For the purposes of this definition, 27 | "control" means (i) the power, direct or indirect, to cause the 28 | direction or management of such entity, whether by contract or 29 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 30 | outstanding shares, or (iii) beneficial ownership of such entity. 31 | 32 | "You" (or "Your") shall mean an individual or Legal Entity 33 | exercising permissions granted by this License. 34 | 35 | "Source" form shall mean the preferred form for making modifications, 36 | including but not limited to software source code, documentation 37 | source, and configuration files. 38 | 39 | "Object" form shall mean any form resulting from mechanical 40 | transformation or translation of a Source form, including but 41 | not limited to compiled object code, generated documentation, 42 | and conversions to other media types. 43 | 44 | "Work" shall mean the work of authorship, whether in Source or 45 | Object form, made available under the License, as indicated by a 46 | copyright notice that is included in or attached to the work 47 | (an example is provided in the Appendix below). 48 | 49 | "Derivative Works" shall mean any work, whether in Source or Object 50 | form, that is based on (or derived from) the Work and for which the 51 | editorial revisions, annotations, elaborations, or other modifications 52 | represent, as a whole, an original work of authorship. For the purposes 53 | of this License, Derivative Works shall not include works that remain 54 | separable from, or merely link (or bind by name) to the interfaces of, 55 | the Work and Derivative Works thereof. 56 | 57 | "Contribution" shall mean any work of authorship, including 58 | the original version of the Work and any modifications or additions 59 | to that Work or Derivative Works thereof, that is intentionally 60 | submitted to Licensor for inclusion in the Work by the copyright owner 61 | or by an individual or Legal Entity authorized to submit on behalf of 62 | the copyright owner. For the purposes of this definition, "submitted" 63 | means any form of electronic, verbal, or written communication sent 64 | to the Licensor or its representatives, including but not limited to 65 | communication on electronic mailing lists, source code control systems, 66 | and issue tracking systems that are managed by, or on behalf of, the 67 | Licensor for the purpose of discussing and improving the Work, but 68 | excluding communication that is conspicuously marked or otherwise 69 | designated in writing by the copyright owner as "Not a Contribution." 70 | 71 | "Contributor" shall mean Licensor and any individual or Legal Entity 72 | on behalf of whom a Contribution has been received by Licensor and 73 | subsequently incorporated within the Work. 74 | 75 | 2. Grant of Copyright License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | copyright license to reproduce, prepare Derivative Works of, 79 | publicly display, publicly perform, sublicense, and distribute the 80 | Work and such Derivative Works in Source or Object form. 81 | 82 | 3. Grant of Patent License. Subject to the terms and conditions of 83 | this License, each Contributor hereby grants to You a perpetual, 84 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 85 | (except as stated in this section) patent license to make, have made, 86 | use, offer to sell, sell, import, and otherwise transfer the Work, 87 | where such license applies only to those patent claims licensable 88 | by such Contributor that are necessarily infringed by their 89 | Contribution(s) alone or by combination of their Contribution(s) 90 | with the Work to which such Contribution(s) was submitted. If You 91 | institute patent litigation against any entity (including a 92 | cross-claim or counterclaim in a lawsuit) alleging that the Work 93 | or a Contribution incorporated within the Work constitutes direct 94 | or contributory patent infringement, then any patent licenses 95 | granted to You under this License for that Work shall terminate 96 | as of the date such litigation is filed. 97 | 98 | 4. Redistribution. You may reproduce and distribute copies of the 99 | Work or Derivative Works thereof in any medium, with or without 100 | modifications, and in Source or Object form, provided that You 101 | meet the following conditions: 102 | 103 | (a) You must give any other recipients of the Work or 104 | Derivative Works a copy of this License; and 105 | 106 | (b) You must cause any modified files to carry prominent notices 107 | stating that You changed the files; and 108 | 109 | (c) You must retain, in the Source form of any Derivative Works 110 | that You distribute, all copyright, patent, trademark, and 111 | attribution notices from the Source form of the Work, 112 | excluding those notices that do not pertain to any part of 113 | the Derivative Works; and 114 | 115 | (d) If the Work includes a "NOTICE" text file as part of its 116 | distribution, then any Derivative Works that You distribute must 117 | include a readable copy of the attribution notices contained 118 | within such NOTICE file, excluding those notices that do not 119 | pertain to any part of the Derivative Works, in at least one 120 | of the following places: within a NOTICE text file distributed 121 | as part of the Derivative Works; within the Source form or 122 | documentation, if provided along with the Derivative Works; or, 123 | within a display generated by the Derivative Works, if and 124 | wherever such third-party notices normally appear. The contents 125 | of the NOTICE file are for informational purposes only and 126 | do not modify the License. You may add Your own attribution 127 | notices within Derivative Works that You distribute, alongside 128 | or as an addendum to the NOTICE text from the Work, provided 129 | that such additional attribution notices cannot be construed 130 | as modifying the License. 131 | 132 | You may add Your own copyright statement to Your modifications and 133 | may provide additional or different license terms and conditions 134 | for use, reproduction, or distribution of Your modifications, or 135 | for any such Derivative Works as a whole, provided Your use, 136 | reproduction, and distribution of the Work otherwise complies with 137 | the conditions stated in this License. 138 | 139 | 5. Submission of Contributions. Unless You explicitly state otherwise, 140 | any Contribution intentionally submitted for inclusion in the Work 141 | by You to the Licensor shall be under the terms and conditions of 142 | this License, without any additional terms or conditions. 143 | Notwithstanding the above, nothing herein shall supersede or modify 144 | the terms of any separate license agreement you may have executed 145 | with Licensor regarding such Contributions. 146 | 147 | 6. Trademarks. This License does not grant permission to use the trade 148 | names, trademarks, service marks, or product names of the Licensor, 149 | except as required for reasonable and customary use in describing the 150 | origin of the Work and reproducing the content of the NOTICE file. 151 | 152 | 7. Disclaimer of Warranty. Unless required by applicable law or 153 | agreed to in writing, Licensor provides the Work (and each 154 | Contributor provides its Contributions) on an "AS IS" BASIS, 155 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 156 | implied, including, without limitation, any warranties or conditions 157 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 158 | PARTICULAR PURPOSE. You are solely responsible for determining the 159 | appropriateness of using or redistributing the Work and assume any 160 | risks associated with Your exercise of permissions under this License. 161 | 162 | 8. Limitation of Liability. In no event and under no legal theory, 163 | whether in tort (including negligence), contract, or otherwise, 164 | unless required by applicable law (such as deliberate and grossly 165 | negligent acts) or agreed to in writing, shall any Contributor be 166 | liable to You for damages, including any direct, indirect, special, 167 | incidental, or consequential damages of any character arising as a 168 | result of this License or out of the use or inability to use the 169 | Work (including but not limited to damages for loss of goodwill, 170 | work stoppage, computer failure or malfunction, or any and all 171 | other commercial damages or losses), even if such Contributor 172 | has been advised of the possibility of such damages. 173 | 174 | 9. Accepting Warranty or Additional Liability. While redistributing 175 | the Work or Derivative Works thereof, You may choose to offer, 176 | and charge a fee for, acceptance of support, warranty, indemnity, 177 | or other liability obligations and/or rights consistent with this 178 | License. However, in accepting such obligations, You may act only 179 | on Your own behalf and on Your sole responsibility, not on behalf 180 | of any other Contributor, and only if You agree to indemnify, 181 | defend, and hold each Contributor harmless for any liability 182 | incurred by, or claims asserted against, such Contributor by reason 183 | of your accepting any such warranty or additional liability. 184 | 185 | END OF TERMS AND CONDITIONS 186 | 187 | APPENDIX: How to apply the Apache License to your work. 188 | 189 | To apply the Apache License to your work, attach the following 190 | boilerplate notice, with the fields enclosed by brackets "[]" 191 | replaced with your own identifying information. (Don't include 192 | the brackets!) The text should be enclosed in the appropriate 193 | comment syntax for the file format. We also recommend that a 194 | file or class name and description of purpose be included on the 195 | same "printed page" as the copyright notice for easier 196 | identification within third-party archives. 197 | 198 | Copyright [yyyy] [name of copyright owner] 199 | 200 | Licensed under the Apache License, Version 2.0 (the "License"); 201 | you may not use this file except in compliance with the License. 202 | You may obtain a copy of the License at 203 | 204 | http://www.apache.org/licenses/LICENSE-2.0 205 | 206 | Unless required by applicable law or agreed to in writing, software 207 | distributed under the License is distributed on an "AS IS" BASIS, 208 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 209 | See the License for the specific language governing permissions and 210 | limitations under the License. 211 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 讯飞开放平台AI能力SDK 2 | 3 | [comment]: <> ([![Build Status](https://www.travis-ci.com/iFLYTEK-OP/websdk-php-speech.svg?branch=master)](https://www.travis-ci.com/iFLYTEK-OP/websdk-php-speech)[![codecov](https://codecov.io/gh/iFLYTEK-OP/websdk-php-speech/branch/master/graph/badge.svg?token=KrohBqwVKb)](https://codecov.io/gh/iFLYTEK-OP/websdk-php-speech)) 4 | 5 | 提供各种AI能力的PHPSDK。 6 | 7 | ### 安装 8 | ```sh 9 | composer require iflytekop/xfyun-sdk 10 | ``` 11 | 如果下载失败,请使用如下命令更换国内源 12 | 13 | `composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/` 14 | 15 | ### 使用 16 | - 语音能力: 17 | - [语音合成](https://github.com/iFLYTEK-OP/websdk-php-speech/blob/master/doc/speech/TTS.md) 18 | - [语音转写](https://github.com/iFLYTEK-OP/websdk-php-speech/blob/master/doc/speech/LFASR.md) 19 | - [语音评测](https://github.com/iFLYTEK-OP/websdk-php-speech/blob/master/doc/speech/ISE.md) 20 | - [性别年龄识别](https://github.com/iFLYTEK-OP/websdk-php-speech/blob/master/doc/speech/IGR.md) 21 | - [文本纠错](https://github.com/iFLYTEK-OP/websdk-php-speech/blob/master/doc/speech/TC.md) 22 | 23 | ### Demo 24 | [Demo](https://github.com/iFLYTEK-OP/websdk-php-demo) 25 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iflytekop/xfyun-sdk", 3 | "type": "library", 4 | "description": "Xfyun Sdk Library", 5 | "license": "Apache-2.0", 6 | "keywords": [], 7 | "require": { 8 | "php": ">=7.0", 9 | "guzzlehttp/guzzle": "^6.0|^7.0", 10 | "guzzlehttp/psr7": "^1.2", 11 | "psr/http-message": "1.0.*", 12 | "psr/log": "^1 | ^2 | ^3", 13 | "iflytekop/xfyun-core": "^1", 14 | "monolog/monolog": "^2.6", 15 | "ext-json": "*" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "^6.5", 19 | "wowo-zz/php-cc": "^1.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "IFlytek\\Xfyun\\Speech\\": "src/Speech" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "IFlytek\\Xfyun\\Speech\\Tests\\": "tests" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /doc/speech/IGR.md: -------------------------------------------------------------------------------- 1 | #### 性别年龄识别 2 | ##### 示例代码 3 | ```php 4 | 'raw', 10 | 'rate' => 16000 11 | //... 12 | ]; 13 | 14 | // 这里的$app_id、$api_key、$api_secret是在开放平台控制台获得 15 | $client = new IFlytek\Xfyun\Speech\IgrClient($app_id, $api_key, $api_secret, $ttsConfig); 16 | 17 | // 返回识别结果 18 | $content = $client->request('./test.pcm'); 19 | ``` 20 | 更详细请参见[Demo](https://github.com/iFLYTEK-OP/websdk-php-demo/blob/master/src/IgrDemo.php) 21 | ##### 合成参数 22 | |参数名|类型|必传|描述| 23 | |:-------------|:-------------|:-------------|:-------------| 24 | |ent|string|是|引擎类型,目前仅支持igr| 25 | |aue|string|是|音频格式
raw:原生音频数据pcm格式
speex:speex格式(rate需设置为8000)
speex-wb:宽频speex格式(rate需设置为16000)
amr:amr格式(rate需设置为8000)
amr-wb:宽频amr格式(rate需设置为16000) 26 | |rate|int|是|音频采样率 16000/8000| 27 | -------------------------------------------------------------------------------- /doc/speech/ISE.md: -------------------------------------------------------------------------------- 1 | #### 语音评测识别 2 | ##### 示例代码 3 | ```php 4 | 'cn_vip' 10 | //... 11 | ]; 12 | 13 | // 这里的$app_id、$api_key、$api_secret是在开放平台控制台获得 14 | $client = new IFlytek\Xfyun\Speech\IseClient($app_id, $api_key, $api_secret, $ttsConfig); 15 | 16 | // 返回识别结果 17 | $content = $client->request('欢迎使用科大讯飞语音能力', './test.pcm'); 18 | ``` 19 | 更详细请参见[Demo](https://github.com/iFLYTEK-OP/websdk-php-demo/blob/master/src/IseDemo.php) 20 | ##### 合成参数 21 | |参数|类型|必须|说明|示例| 22 | |:-------------|:-------------|:-------------|:-------------|:-------------| 23 | |aue|string|是|音频编码
raw(未压缩的 pcm 格式音频)
speex(标准开源speex)|raw| 24 | |speex_size|string|否|标准speex解码帧的大小
当aue=speex时,若传此参数,表明音频格式为标准speex
解码帧大小请参考[这里](#speex编码);|70| 25 | |result_level|string|否|评测结果等级
entirety(默认值)
simple|entirety| 26 | |language|string|是|评测语种
en_us(英语)
zh_cn(汉语)|zh_cn| 27 | |category|string|是|评测题型
read_syllable(单字朗读,汉语专有)
read_word(词语朗读)
read_sentence(句子朗读)
read_chapter(篇章朗读)|read_sentence| 28 | |extra_ability|string|否|拓展能力
multi_dimension([全维度](#全维度说明) )|multi_dimension| 29 | -------------------------------------------------------------------------------- /doc/speech/LFASR.md: -------------------------------------------------------------------------------- 1 | #### 语音转写 2 | ##### 示例代码 3 | ```php 4 | 'true' 10 | //... 11 | ]; 12 | 13 | // 这里的$app_id、$secret_key是在开放平台控制台获得 14 | $client = new IFlytek\Xfyun\Speech\LfasrClient($app_id, $secret_key, $lfasrConfig); 15 | 16 | // $filePath为待转写的本地文件路径,返回taskId作为后续查询进度、获取结果操作的参数 17 | $taskId = $client->combineUpload($filePath); 18 | 19 | // 查询进度,json格式 20 | $progress = $client->getProgress($taskId)->getBody()->getContents(); 21 | 22 | // 获取结果,json格式 23 | $result = $client->getResult($taskId)->getBody()->getContents(); 24 | ``` 25 | 更详细请参见[Demo](https://github.com/iFLYTEK-OP/websdk-php-demo/blob/master/src/LfasrDemo.php) 26 | ##### 合成参数 27 | |参数|类型|必须|说明|示例| 28 | |:-------------|:-------------|:-------------|:-------------|:-------------| 29 | |lfasrType|string|否|转写类型,默认 0
0: (标准版,格式: wav,flac,opus,mp3,m4a)
2: (电话版,已取消)|0| 30 | |hasParticiple|string|否|转写结果是否包含分词信息|false或true, 默认false| 31 | |maxAlternatives|string|否|转写结果中最大的候选词个数|默认:0,最大不超过5| 32 | |speakerNumber|string|否|发音人个数,可选值:0-10,0表示盲分
*注*:发音人分离目前还是测试效果达不到商用标准,如测试无法满足您的需求,请慎用该功能。|默认:2(适用通话时两个人对话的场景)| 33 | |hasSeperate|string|否|转写结果中是否包含发音人分离信息|false或true,默认为false| 34 | |roleType|string|否|支持两种参数
1: 通用角色分离
2: 电话信道角色分离(适用于speaker_number为2的说话场景)|该字段只有在开通了角色分离功能的前提下才会生效,正确传入该参数后角色分离效果会有所提升。 如果该字段不传,默认采用 1 类型| 35 | |language|string|否|语种
cn:中英文&中文(默认)
en:英文(英文不支持热词)|cn| 36 | |pd|string|否|垂直领域个性化参数:
法院: court
教育: edu
金融: finance
医疗: medical
科技: tech|设置示例:prepareParam.put("pd", "edu")
pd为非必须设置参数,不设置参数默认为通用| 37 | -------------------------------------------------------------------------------- /doc/speech/TC.md: -------------------------------------------------------------------------------- 1 | #### 文本纠错 2 | ##### 示例代码 3 | ```php 4 | request('历史上有很多注明的人物,其中唐太宗李世民就是一位。')->getBody()->getContents(); 14 | 15 | // 黑白名单上传请求,成功返回true,失败返回false(失败请检查uid、res_id是否设置) 16 | $client = new IFlytek\Xfyun\Speech\TcClient($app_id, $api_key, $api_secret, $uid, $res_id); 17 | $client->listUpload($white_list, $black_list); 18 | ``` 19 | 20 | ##### 合成参数 21 | 暂无可配置的参数 22 | -------------------------------------------------------------------------------- /doc/speech/TTS.md: -------------------------------------------------------------------------------- 1 | #### 语音合成 2 | ##### 示例代码 3 | ```php 4 | 'lame' 14 | //... 15 | ]; 16 | 17 | // $logger是psr3的日志实例,需要打印日志可以传入,缺省为null,此项为v2.0.1之后可用 18 | $logger = new Logger('TTSLOG'); 19 | $logger->pushHandler(new StreamHandler(__DIR__.'/tts.log', Logger::DEBUG)); 20 | 21 | // 这里的$app_id、$api_key、$api_secret是在开放平台控制台获得 22 | $client = new IFlytek\Xfyun\Speech\TtsClient($app_id, $api_key, $api_secret, $ttsConfig, $logger); 23 | 24 | // 返回格式为音频文件的二进制数组,可以直接通过file_put_contents存入本地文件 25 | $content = $client->request('欢迎使用科大讯飞语音能力,让我们一起用人工智能改变世界')->getBody()->getContents(); 26 | ``` 27 | 更详细请参见[Demo](https://github.com/iFLYTEK-OP/websdk-php-demo/blob/master/src/TtsDemo.php) 28 | ##### 合成参数 29 | |参数名|类型|必传|描述|示例| 30 | |---|---|---|---|---| 31 | |aue|string|是|音频编码,可选值:
raw:未压缩的pcm
lame:mp3 **(当aue=lame时需传参sfl=1)**
speex-org-wb;7: 标准开源speex(for speex_wideband,即16k)数字代表指定压缩等级(默认等级为8)
speex-org-nb;7: 标准开源speex(for speex_narrowband,即8k)数字代表指定压缩等级(默认等级为8)
speex;7:压缩格式,压缩等级1-10,默认为7(8k讯飞定制speex)
speex-wb;7:压缩格式,压缩等级1-10,默认为7(16k讯飞定制speex)
|"raw"
"speex-org-wb;7" 数字代表指定压缩等级(默认等级为8),数字必传
标准开源speex编码以及讯飞定制speex说明请参考[音频格式说明](https://www.xfyun.cn/doc/asr/voicedictation/Audio.html#speex%E7%BC%96%E7%A0%81)| 32 | |sfl|int|否|需要配合aue=lame使用,开启流式返回
mp3格式音频
取值:1 开启|1| 33 | |auf|string|否|音频采样率,可选值:
audio/L16;rate=8000:合成8K 的音频
audio/L16;rate=16000:合成16K 的音频
auf不传值:合成16K 的音频|"audio/L16;rate=16000"| 34 | |vcn|string|是|发音人,可选值:请到控制台添加试用或购买发音人,添加后即显示发音人参数值|"xiaoyan"| 35 | |speed|int|否|语速,可选值:[0-100],默认为50|50| 36 | |volume|int|否|音量,可选值:[0-100],默认为50|50| 37 | |pitch|int|否|音高,可选值:[0-100],默认为50|50| 38 | |bgs|int|否|合成音频的背景音
0:无背景音(默认值)
1:有背景音|0| 39 | |tte|string|否|文本编码格式
GB2312
GBK
BIG5
UNICODE(小语种必须使用UNICODE编码,合成的文本需使用utf16小端的编码方式
GB18030
UTF8|"UTF8"| 40 | |reg|string|否|设置英文发音方式:
0:自动判断处理,如果不确定将按照英文词语拼写处理(缺省)
1:所有英文按字母发音
2:自动判断处理,如果不确定将按照字母朗读
默认按英文单词发音|"2"| 41 | |rdn|string|否|合成音频数字发音方式
0:自动判断(默认值)
1:完全数值
2:完全字符串
3:字符串优先|"0"| 42 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UnitTest 6 | tests/Unit 7 | 8 | 9 | 10 | 11 | src 12 | 13 | src/V[!a-zA-Z]* 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Speech/Config/IgrConfig.php: -------------------------------------------------------------------------------- 1 | 'raw', 63 | 'rate' => 16000 64 | ]; 65 | 66 | $this->ent = 'igr'; 67 | $this->aue = $config['aue']; 68 | $this->rate = $config['rate']; 69 | } 70 | 71 | /** 72 | * 去除null项后返回数组形式 73 | * 74 | * @return array 75 | */ 76 | public function toArray() 77 | { 78 | return $this->removeNull([ 79 | 'ent' => $this->ent, 80 | 'aue' => $this->aue, 81 | 'rate' => $this->rate 82 | ]); 83 | } 84 | 85 | /** 86 | * 返回toArray的Json格式 87 | * 88 | * @return string 89 | */ 90 | public function toJson() 91 | { 92 | return $this->jsonEncode($this->toArray()); 93 | } 94 | 95 | /** 96 | * @return string 97 | */ 98 | public function getAue() 99 | { 100 | return $this->aue; 101 | } 102 | 103 | /** 104 | * @return int 105 | */ 106 | public function getRate() 107 | { 108 | return $this->rate; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Speech/Config/IseConfig.php: -------------------------------------------------------------------------------- 1 | 'cn_vip', 187 | 'category' => 'read_sentence', 188 | 'aus' => 1, 189 | 'cmd' => 'ssb', 190 | 'text' => '', 191 | 'tte' => 'utf-8', 192 | 'ttp_skip' => true, 193 | 'extra_ability' => null, 194 | 'aue' => 'raw', 195 | 'rstcd' => 'utf8', 196 | 'group' => 'adult', 197 | 'check_type' => 'common', 198 | 'grade' => 'middle', 199 | 'rst' => 'entirety', 200 | 'ise_unite' => '0', 201 | 'plev' => '0' 202 | ]; 203 | 204 | $this->sub = 'ise'; 205 | $this->ent = $config['ent']; 206 | $this->category = $config['category']; 207 | $this->aus = $config['aus']; 208 | $this->cmd = $config['cmd']; 209 | $this->text = chr(239) . chr(187) . chr(191) . $config['text']; 210 | $this->tte = $config['tte']; 211 | $this->ttpSkip = $config['ttp_skip']; 212 | $this->extraAbility = $config['extra_ability']; 213 | $this->aue = $config['aue']; 214 | $this->rstcd = $config['rstcd']; 215 | $this->group = $config['group']; 216 | $this->checkType = $config['check_type']; 217 | $this->grade = $config['grade']; 218 | $this->rst = $config['rst']; 219 | $this->iseUnite = $config['ise_unite']; 220 | $this->plev = $config['plev']; 221 | } 222 | 223 | /** 224 | * 去除null项后返回数组形式 225 | * 226 | * @return array 227 | */ 228 | public function toArray() 229 | { 230 | return $this->removeNull([ 231 | 'sub' => $this->sub, 232 | 'ent' => $this->ent, 233 | 'category' => $this->category, 234 | 'aus' => $this->aus, 235 | 'cmd' => $this->cmd, 236 | 'text' => $this->text, 237 | 'tte' => $this->tte, 238 | 'ttp_skip' => $this->ttpSkip, 239 | 'extra_ability' => $this->extraAbility, 240 | 'aue' => $this->aue, 241 | 'rstcd' => $this->rstcd, 242 | 'group' => $this->group, 243 | 'check_type' => $this->checkType, 244 | 'grade' => $this->grade, 245 | 'rst' => $this->rst, 246 | 'ise_unite' => $this->iseUnite, 247 | 'plev' => $this->plev 248 | ]); 249 | } 250 | 251 | /** 252 | * 返回toArray的Json格式 253 | * 254 | * @return string 255 | */ 256 | public function toJson() 257 | { 258 | return $this->jsonEncode($this->toArray()); 259 | } 260 | 261 | public function setText($text) 262 | { 263 | $this->text = chr(239) . chr(187) . chr(191) . $text; 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/Speech/Config/LfasrConfig.php: -------------------------------------------------------------------------------- 1 | '0', 95 | 'has_participle' => 'false', 96 | 'max_alternatives' => '0', 97 | 'speaker_number' => '2', 98 | 'has_seperate' => 'false', 99 | 'role_type' => '1', 100 | 'language' => 'cn', 101 | 'pd' => null 102 | ]; 103 | 104 | $this->lfasrType = $config['lfasr_type']; 105 | $this->hasParticiple = $config['has_participle']; 106 | $this->maxAlternatives = $config['max_alternatives']; 107 | $this->speakerNumber = $config['speaker_number']; 108 | $this->hasSeperate = $config['has_seperate']; 109 | $this->roleType = $config['role_type']; 110 | $this->language = $config['language']; 111 | $this->pd = $config['pd']; 112 | } 113 | 114 | /** 115 | * 去除null项后返回数组形式 116 | * 117 | * @return array 118 | */ 119 | public function toArray() 120 | { 121 | return $this->removeNull([ 122 | 'lfasr_type' => $this->lfasrType, 123 | 'has_participle' => $this->hasParticiple, 124 | 'max_alternatives' => $this->maxAlternatives, 125 | 'speaker_number' => $this->speakerNumber, 126 | 'has_seperate' => $this->hasSeperate, 127 | 'role_type' => $this->roleType, 128 | 'language' => $this->language, 129 | 'pd' => $this->pd 130 | ]); 131 | } 132 | 133 | /** 134 | * 返回toArray的Json格式 135 | * 136 | * @return string 137 | */ 138 | public function toJson() 139 | { 140 | return $this->jsonEncode($this->toArray()); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Speech/Config/TcConfig.php: -------------------------------------------------------------------------------- 1 | 'utf8', 45 | 'resultCompress' => 'raw', 46 | 'resultFormat' => 'json', 47 | 'inputEncoding' => 'utf8', 48 | 'inputCompress' => 'raw', 49 | 'inputFormat' => 'json' 50 | ]; 51 | 52 | $this->resultEncoding = $config['resultEncoding']; 53 | $this->resultCompress = $config['resultCompress']; 54 | $this->resultFormat = $config['resultFormat']; 55 | $this->inputEncoding = $config['inputEncoding']; 56 | $this->inputCompress = $config['inputCompress']; 57 | $this->inputFormat = $config['inputFormat']; 58 | } 59 | 60 | public function toJson() 61 | { 62 | // TODO: Implement toJson() method. 63 | } 64 | 65 | public function toArray() 66 | { 67 | return self::removeNull([ 68 | 'resultEncoding' => $this->resultEncoding, 69 | 'resultCompress' => $this->resultCompress, 70 | 'resultFormat' => $this->resultFormat, 71 | 'inputEncoding' => $this->inputEncoding, 72 | 'inputCompress' => $this->inputCompress, 73 | 'inputFormat' => $this->inputFormat 74 | ]); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Speech/Config/TtsConfig.php: -------------------------------------------------------------------------------- 1 | 'lame', 132 | 'sfl' => 1, 133 | 'auf' => null, 134 | 'vcn' => 'xiaoyan', 135 | 'speed' => 50, 136 | 'volume' => 50, 137 | 'pitch' => 50, 138 | 'bgs' => 0, 139 | 'tte' => 'UTF8', 140 | 'reg' => '2', 141 | 'rdn' => '0', 142 | 'ent' => '' 143 | ]; 144 | 145 | $this->aue = $config['aue']; 146 | $this->sfl = $config['sfl']; 147 | $this->auf = $config['auf']; 148 | $this->vcn = $config['vcn']; 149 | $this->speed = $config['speed']; 150 | $this->volume = $config['volume']; 151 | $this->pitch = $config['pitch']; 152 | $this->bgs = $config['bgs']; 153 | $this->tte = $config['tte']; 154 | $this->reg = $config['reg']; 155 | $this->rdn = $config['rdn']; 156 | $this->ent = $config['ent']; 157 | } 158 | 159 | /** 160 | * 去除null项后返回数组形式 161 | * 162 | * @return array 163 | */ 164 | public function toArray() 165 | { 166 | return $this->removeNull([ 167 | 'aue' => $this->aue, 168 | 'sfl' => $this->sfl, 169 | 'auf' => $this->auf, 170 | 'vcn' => $this->vcn, 171 | 'speed' => $this->speed, 172 | 'volume' => $this->volume, 173 | 'pitch' => $this->pitch, 174 | 'bgs' => $this->bgs, 175 | 'tte' => $this->tte, 176 | 'reg' => $this->reg, 177 | 'rdn' => $this->rdn, 178 | 'ent' => $this->ent 179 | ]); 180 | } 181 | 182 | /** 183 | * 返回toArray的Json格式 184 | * 185 | * @return string 186 | */ 187 | public function toJson() 188 | { 189 | return $this->jsonEncode($this->toArray()); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/Speech/Constants/IgrConstants.php: -------------------------------------------------------------------------------- 1 | id = LfasrConstants::ORIGIN_SLICE_ID; 37 | } 38 | 39 | /** 40 | * 返回当前切片ID,并生成下一个切片ID,赋值给对象的当前ID 41 | * 42 | * @return string 43 | */ 44 | public function getId() 45 | { 46 | $currentId = $this->id; 47 | $nextId = $currentId; 48 | $pos = strlen($currentId) - 1; 49 | while ($pos >= 0) { 50 | $charAtPos = $nextId[$pos]; 51 | if ($charAtPos != 'z') { 52 | $nextId = substr($nextId, 0, $pos) . chr((ord($charAtPos) + 1)) . substr($nextId, $pos + 1); 53 | break; 54 | } else { 55 | $nextId = substr($nextId, 0, $pos) . 'a'; 56 | $pos = $pos - 1; 57 | } 58 | } 59 | $this->id = $nextId; 60 | return $currentId; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Speech/IgrClient.php: -------------------------------------------------------------------------------- 1 | appId = $appId; 62 | $this->apiKey = $apiKey; 63 | $this->apiSecret = $apiSecret; 64 | $this->requestConfig = new IgrConfig($requestConfig); 65 | } 66 | 67 | /** 68 | * 请求并返回结果 69 | * 70 | * @param string $audioPath 待识别音频路径 71 | * @return string 72 | * @throws Exception 73 | */ 74 | public function request($audioPath) 75 | { 76 | $ttsHandler = new WsHandler( 77 | $this->signUriV1(IgrConstants::URI, [ 78 | 'appId' => $this->appId, 79 | 'apiKey' => $this->apiKey, 80 | 'apiSecret' => $this->apiSecret, 81 | 'host' => IgrConstants::HOST, 82 | 'requestLine' => IgrConstants::REQUEST_LINE, 83 | ]), 84 | null 85 | ); 86 | $client = new WsClient([ 87 | 'handler' => $ttsHandler 88 | ]); 89 | 90 | // 音频上传 91 | $frameNum = ceil(fileSize($audioPath) / IgrConstants::FRAME_SIZE); 92 | $fileStream = new Stream(fopen($audioPath, 'r')); 93 | // 发送第一帧 94 | $client->send($this->generateAudioInput($fileStream->read(IgrConstants::FRAME_SIZE), true, false)); 95 | 96 | // 发送中间帧 97 | for ($i = 1; $i < $frameNum; $i++) { 98 | $client->send($this->generateAudioInput($fileStream->read(IgrConstants::FRAME_SIZE), false, false)); 99 | usleep(4000); 100 | } 101 | // 发送最后一帧 102 | $client->send($this->generateAudioInput('', false, true)); 103 | 104 | // 接受数据 105 | $message = $this->jsonDecode($client->receive(), true); 106 | if ($message['code'] !== 0) { 107 | throw new Exception(json_encode($message)); 108 | } 109 | return $message['data']; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Speech/IseClient.php: -------------------------------------------------------------------------------- 1 | appId = $appId; 61 | $this->apiKey = $apiKey; 62 | $this->apiSecret = $apiSecret; 63 | $this->requestConfig = new IseConfig($requestConfig); 64 | } 65 | 66 | /** 67 | * 请求评测,并返回结果(xml格式) 68 | * 69 | * @param string $audioPath 待评测音频路径 70 | * @param string $text 待评测文本 71 | * @return string 72 | */ 73 | public function request($audioPath, $text = null) 74 | { 75 | $ttsHandler = new WsHandler( 76 | $this->signUriV1(IseConstants::URI, [ 77 | 'appId' => $this->appId, 78 | 'apiKey' => $this->apiKey, 79 | 'apiSecret' => $this->apiSecret, 80 | 'host' => IseConstants::HOST, 81 | 'requestLine' => IseConstants::REQUEST_LINE, 82 | ]), 83 | null 84 | ); 85 | $client = new WsClient([ 86 | 'handler' => $ttsHandler 87 | ]); 88 | 89 | // 参数上传 90 | if (!empty($text)) { 91 | $this->requestConfig->setText($text); 92 | } 93 | $client->send($this->generateParamsInput($this->appId, $this->requestConfig->toArray())); 94 | 95 | // 音频上传 96 | $frameSize = ceil(fileSize($audioPath) / IseConstants::FRAME_SIZE); 97 | $fileStream = new Stream(fopen($audioPath, 'r')); 98 | // 发送第一帧 99 | $result = $client->send($this->generateAudioInput($fileStream->read(IseConstants::FRAME_SIZE), true, false)); 100 | // 发送中间帧 101 | for ($i = 1; $i < $frameSize - 1; $i++) { 102 | $client->send($this->generateAudioInput($fileStream->read(IseConstants::FRAME_SIZE), false, false)); 103 | usleep(4000); 104 | } 105 | // 发送最后一帧 106 | $client->send($this->generateAudioInput($fileStream->read(IseConstants::FRAME_SIZE), false, true)); 107 | 108 | // 接受数据 109 | $result = ''; 110 | while (true) { 111 | $message = $this->jsonDecode($client->receive()); 112 | if ($message->code !== 0) { 113 | throw new \Exception(json_encode($message)); 114 | } 115 | switch ($message->data->status) { 116 | case 1: 117 | $result .= base64_decode($message->data->data); 118 | break; 119 | case 2: 120 | $result .= base64_decode($message->data->data); 121 | break 2; 122 | } 123 | } 124 | return $result; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Speech/LfasrClient.php: -------------------------------------------------------------------------------- 1 | appId = $appId; 69 | $this->secretKey = $secretKey; 70 | $this->requestConfig = new LfasrConfig($requestConfig); 71 | $this->client = new HttpClient([]); 72 | $timestamp = time(); 73 | $this->requestBody = [ 74 | 'app_id' => $this->appId, 75 | 'signa' => $this->signV1($this->appId, $this->secretKey, $timestamp), 76 | 'ts' => $timestamp, 77 | ]; 78 | } 79 | 80 | /** 81 | * 打包上传接口,封装了准备、分片上传和合并三个接口,并返回task_id 82 | * 83 | * @param string $filePath 文件路径 84 | * @return string 85 | * @throws Exception 86 | */ 87 | public function combineUpload($filePath) 88 | { 89 | $prepareResponse = $this->prepare($filePath); 90 | $prepareContent = $this->jsonDecode($prepareResponse->getBody()->getContents(), true); 91 | $taskId = $prepareContent['data']; 92 | $this->upload($taskId, $filePath); 93 | $this->merge($taskId); 94 | return $taskId; 95 | } 96 | 97 | /** 98 | * 准备接口 99 | * 100 | * @param $file_path 101 | * @return Response 102 | * @throws Exception 103 | */ 104 | public function prepare($file_path) 105 | { 106 | $this->requestBody += $this->fileInfo($file_path); 107 | $this->requestBody += $this->sliceInfo($file_path); 108 | $this->requestBody += $this->requestConfig->toArray(); 109 | 110 | return $this->client->sendAndReceive( 111 | new Request( 112 | 'POST', 113 | LfasrConstants::URI_PREPARE, 114 | ['Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'], 115 | Query::build($this->requestBody) 116 | ) 117 | ); 118 | } 119 | 120 | /** 121 | * 分片上传接口 122 | * 123 | * @param string $taskId task_id 124 | * @param string $filePath 文件路径 125 | * @return Response 126 | * @throws Exception 127 | */ 128 | public function upload($taskId, $filePath) 129 | { 130 | $sliceIdGenerator = new SliceIdGenerator(); 131 | $sliceInfo = $this->sliceInfo($filePath); 132 | $fileStream = new Stream(fopen($filePath, 'r')); 133 | 134 | $this->requestBody += [ 135 | 'task_id' => $taskId 136 | ]; 137 | 138 | $request = new Request( 139 | 'POST', 140 | LfasrConstants::URI_UPLOAD 141 | ); 142 | 143 | for ($i = 0; $i < $sliceInfo['slice_num']; $i++) { 144 | $multipartStream = new MultipartStream([ 145 | [ 146 | 'name' => 'app_id', 147 | 'contents' => $this->requestBody['app_id'] 148 | ], 149 | [ 150 | 'name' => 'signa', 151 | 'contents' => $this->requestBody['signa'] 152 | ], 153 | [ 154 | 'name' => 'ts', 155 | 'contents' => $this->requestBody['ts'] 156 | ], 157 | [ 158 | 'name' => 'task_id', 159 | 'contents' => $taskId, 160 | ], 161 | [ 162 | 'name' => 'slice_id', 163 | 'contents' => $sliceIdGenerator->getId() 164 | ], 165 | [ 166 | 'name' => 'content', 167 | 'contents' => $fileStream->read(LfasrConstants::SLICE_PIECE_SIZE), 168 | 'filename' => '1.pcm' 169 | ] 170 | ]); 171 | 172 | $this->client->sendAndReceive( 173 | $request->withBody($multipartStream) 174 | ); 175 | } 176 | return new Response(200); 177 | } 178 | 179 | /** 180 | * 合并接口 181 | * 182 | * @param string $taskId task_id 183 | * @return Response 184 | */ 185 | public function merge($taskId) 186 | { 187 | return $this->process(LfasrConstants::URI_MERGE, $taskId); 188 | } 189 | 190 | /** 191 | * 查询进度接口 192 | * 193 | * @param string $taskId task_id 194 | * @return Response 195 | */ 196 | public function getProgress($taskId) 197 | { 198 | return $this->process(LfasrConstants::URI_GET_PROGRESS, $taskId); 199 | } 200 | 201 | /** 202 | * 获取结果接口 203 | * 204 | * @param string $taskId task_id 205 | * @return Response 206 | */ 207 | public function getResult($taskId) 208 | { 209 | return $this->process(LfasrConstants::URI_GET_RESULT, $taskId); 210 | } 211 | 212 | /** 213 | * 封装操作 214 | * 215 | * @param string $task 操作 216 | * @param string $taskId task_id 217 | * @return Response 218 | */ 219 | private function process($task, $taskId) 220 | { 221 | $this->requestBody += ['task_id' => $taskId]; 222 | return $this->client->sendAndReceive( 223 | new Request( 224 | 'POST', 225 | $task, 226 | ['Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'], 227 | Query::build($this->requestBody) 228 | ) 229 | ); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/Speech/TcClient.php: -------------------------------------------------------------------------------- 1 | appId = $appId; 48 | $this->apiKey = $apiKey; 49 | $this->apiSecret = $apiSecret; 50 | $this->uid = $uid; 51 | $this->resId = $resId; 52 | $this->requestConfig = new TcConfig($requestConfig); 53 | $this->client = new HttpClient([]); 54 | } 55 | 56 | public function request($text) 57 | { 58 | $uri = self::signUriV1(TcConstants::URI, [ 59 | 'apiKey' => $this->apiKey, 60 | 'apiSecret' => $this->apiSecret, 61 | 'host' => TcConstants::HOST, 62 | 'requestLine' => TcConstants::REQUEST_LINE 63 | ]); 64 | $body = self::generateInput($text, $this->appId, $this->uid, $this->resId, $this->requestConfig->toArray()); 65 | return $this->client->sendAndReceive( 66 | new Request( 67 | 'POST', 68 | $uri, 69 | ['Content-Type' => 'application/json;charset=UTF-8'], 70 | $body 71 | ) 72 | ); 73 | } 74 | 75 | public function listUpload($whiteList, $blackList) 76 | { 77 | if (empty($this->uid) || empty($this->resId)) { 78 | return false; 79 | } 80 | $response = $this->client->sendAndReceive( 81 | new Request( 82 | 'POST', 83 | TcConstants::LIST_UPLOAD_URI, 84 | ['Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'], 85 | self::jsonEncode([ 86 | 'common' => [ 87 | 'app_id' => $this->appId, 88 | 'uid' => $this->uid, 89 | 90 | ], 91 | 'business' => [ 92 | 'res_id' => $this->resId 93 | ], 94 | 'data' => base64_encode(self::jsonEncode([ 95 | 'white_list' => $whiteList, 96 | 'black_list' => $blackList 97 | ])) 98 | ]) 99 | ) 100 | ); 101 | $content = json_decode($response->getBody()->getContents(), true); 102 | return $content['message'] == 'success'; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Speech/Traits/IgrTrait.php: -------------------------------------------------------------------------------- 1 | !$isFirstFrame ? null : [ 46 | "app_id" => $this->appId 47 | ], 48 | 'business' => !$isFirstFrame ? null : [ 49 | "aue" => $this->requestConfig->getAue(), 50 | "rate" => $this->requestConfig->getRate() 51 | ], 52 | 'data' => [ 53 | 'status' => $isFirstFrame ? 0 : ($isLastFrame ? 2 : 1), 54 | 'audio' => base64_encode($frameData) 55 | ] 56 | ]) 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Speech/Traits/IseTrait.php: -------------------------------------------------------------------------------- 1 | [ 45 | 'app_id' => $appId 46 | ], 47 | 'business' => $iseConfigArray, 48 | 'data' => [ 49 | 'status' => 0 50 | ] 51 | ]) 52 | ); 53 | } 54 | 55 | /** 56 | * 根据音频数据、是否是第一帧、最后一帧,生成音频上传请求体 57 | * 58 | * @param string $frameData 音频数据 59 | * @param boolean $isFirstFrame 是否是第一帧 60 | * @param boolean $isLastFrame 是否是最后一帧 61 | * @return string 62 | */ 63 | public static function generateAudioInput($frameData, $isFirstFrame = false, $isLastFrame = false) 64 | { 65 | return self::jsonEncode( 66 | self::removeNull([ 67 | 'business' => [ 68 | "cmd" => "auw", 69 | "aus" => $isFirstFrame ? 1 : ($isLastFrame ? 4 : 2) 70 | ], 71 | 'data' => [ 72 | 'status' => $isLastFrame ? 2 : 1, 73 | 'data' => base64_encode($frameData) 74 | ] 75 | ]) 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Speech/Traits/LfasrTrait.php: -------------------------------------------------------------------------------- 1 | basename($filePath), 39 | 'file_len' => filesize($filePath) 40 | ]; 41 | } 42 | 43 | /** 44 | * 根据文件大小和SDK默认分片大小,获取文件分片数目信息 45 | * 46 | * @param string $filePath 文件路径 47 | * @return array 48 | */ 49 | public static function sliceInfo($filePath) 50 | { 51 | $fileSize = filesize($filePath); 52 | return [ 53 | 'slice_num' => ceil($fileSize / LfasrConstants::SLICE_PIECE_SIZE) 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Speech/Traits/TcTrait.php: -------------------------------------------------------------------------------- 1 | [ 38 | 'app_id' => $appId, 39 | 'uid' => $uid, 40 | 'status' => 3 41 | ], 42 | 'parameter' => [ 43 | 's9a87e3ec' => [ 44 | 'res_id' => $resId, 45 | 'result' => [ 46 | 'encoding' => $tcConfigArray['resultEncoding'], 47 | 'compress' => $tcConfigArray['resultCompress'], 48 | 'format' => $tcConfigArray['resultFormat'], 49 | ] 50 | ] 51 | ], 52 | 'payload' => [ 53 | 'input' => [ 54 | 'encoding' => $tcConfigArray['inputEncoding'], 55 | 'compress' => $tcConfigArray['inputCompress'], 56 | 'format' => $tcConfigArray['inputFormat'], 57 | 'status' => 3, 58 | 'text' => base64_encode($text) 59 | ] 60 | ] 61 | ]) 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Speech/Traits/TtsTrait.php: -------------------------------------------------------------------------------- 1 | [ 46 | 'app_id' => $appId 47 | ], 48 | 'business' => $ttsConfigArray, 49 | 'data' => [ 50 | 'text' => base64_encode($text), 51 | 'status' => 2 52 | ] 53 | ]) 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Speech/TtsClient.php: -------------------------------------------------------------------------------- 1 | appId = $appId; 67 | $this->apiKey = $apiKey; 68 | $this->apiSecret = $apiSecret; 69 | $this->requestConfig = new TtsConfig($requestConfig); 70 | $this->logger = $logger; 71 | } 72 | 73 | /** 74 | * 合成文本,并返回结果(字节数组)在Response->getBody()->getContents() 75 | * 76 | * @param string $text 待合成的文本 77 | * @return \GuzzleHttp\Psr7\Response 78 | * @throws Exception 79 | */ 80 | public function request($text) 81 | { 82 | $ttsHandler = new WsHandler( 83 | $this->signUriV1(TtsConstants::URI, [ 84 | 'appId' => $this->appId, 85 | 'apiKey' => $this->apiKey, 86 | 'apiSecret' => $this->apiSecret, 87 | 'host' => TtsConstants::HOST, 88 | 'requestLine' => TtsConstants::REQUEST_LINE, 89 | ]), 90 | $this->generateInput($text, $this->appId, $this->requestConfig->toArray()) 91 | ); 92 | if ($this->logger) { 93 | $ttsHandler->setLogger($this->logger); 94 | } 95 | $client = new WsClient([ 96 | 'handler' => $ttsHandler 97 | ]); 98 | return $client->sendAndReceive(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/Unit/Speech/BaseClientTest.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'appId' => getenv('PHPSDK_SPEECH_TTS_APPID'), 19 | 'apiKey' => getenv('PHPSDK_SPEECH_TTS_APIKEY'), 20 | 'apiSecret' => getenv('PHPSDK_SPEECH_TTS_APISECRET') 21 | ], 22 | 'lfasr' => [ 23 | 'appId' => getenv('PHPSDK_SPEECH_LFASR_APPID'), 24 | 'secretKey' => getenv('PHPSDK_SPEECH_LFASR_SECRETKEY'), 25 | 'taskId' => getenv('PHPSDK_SPEECH_LFASR_TASKID') 26 | ] 27 | ]; 28 | $this->config = $credentials[$this->ability]; 29 | } 30 | 31 | public function testSuccessGetEnv() 32 | { 33 | $this->assertNotNull($this->config['appId']); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Unit/Speech/Config/TtsConfigTest.php: -------------------------------------------------------------------------------- 1 | jsonDecode($config->toJson(), true); 19 | $this->assertEquals('lame', $config['aue']); 20 | $this->assertEquals(1, $config['sfl']); 21 | $this->assertEquals('xiaoyan', $config['vcn']); 22 | $this->assertEquals(50, $config['speed']); 23 | $this->assertEquals(50, $config['volume']); 24 | $this->assertEquals(50, $config['pitch']); 25 | $this->assertEquals(0, $config['bgs']); 26 | $this->assertEquals('UTF8', $config['tte']); 27 | $this->assertEquals('2', $config['reg']); 28 | $this->assertEquals('0', $config['rdn']); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/Unit/Speech/Helper/SliceIdGeneratorTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('aaaaaaaaaa', $generator->getId()); 14 | $this->assertEquals('aaaaaaaaab', $generator->getId()); 15 | $this->assertEquals('aaaaaaaaac', $generator->getId()); 16 | for ($i = 0; $i < 23; $i++) { 17 | $generator->getId(); 18 | } 19 | $this->assertEquals('aaaaaaaaba', $generator->getId()); 20 | for ($i = 0; $i < 25; $i++) { 21 | $generator->getId(); 22 | } 23 | $this->assertEquals('aaaaaaaaca', $generator->getId()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Unit/Speech/IgrClientTest.php: -------------------------------------------------------------------------------- 1 | ability = 'common'; 13 | } 14 | 15 | public function testSuccessfullyRequest() 16 | { 17 | $client = new IgrClient( 18 | $this->config['appId'], 19 | $this->config['apiKey'], 20 | $this->config['apiSecret'] 21 | ); 22 | $result = $client->request(__DIR__ . '/../../input/igr_pcm_16k.pcm'); 23 | $this->assertArrayHasKey('appId', $this->config); 24 | $this->assertArrayHasKey('result', $result); 25 | $this->assertArrayHasKey('age', $result['result']); 26 | $this->assertArrayHasKey('age_type', $result['result']['age']); 27 | $this->assertEquals(2, $result['status']); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Unit/Speech/IseClientTest.php: -------------------------------------------------------------------------------- 1 | ability = 'common'; 13 | } 14 | 15 | public function testSuccessfullyRequest() 16 | { 17 | $client = new IseClient( 18 | $this->config['appId'], 19 | $this->config['apiKey'], 20 | $this->config['apiSecret'], 21 | [ 22 | 'aue' => 'lame' 23 | ] 24 | ); 25 | $result = $client->request(__DIR__ . '/../../input/iseTest.mp3', '欢迎使用科大讯飞语音能力,让我们用人工智能改变世界'); 26 | $this->assertArrayHasKey('appId', $this->config); 27 | $this->assertEquals('2104d20080a4f9087780ee40b4e6155c', md5($result)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Unit/Speech/LfasrClientTest.php: -------------------------------------------------------------------------------- 1 | ability = 'lfasr'; 20 | } 21 | 22 | public function setUp() 23 | { 24 | parent::setUp(); 25 | $this->client = new LfasrClient($this->config['appId'], $this->config['secretKey']); 26 | } 27 | 28 | public function testSuccessfullyPrepare() 29 | { 30 | $this->assertInstanceOf(LfasrClient::class, $this->client); 31 | $response = $this->client->prepare(__DIR__ . '/../../input/1.wav'); 32 | $this->assertEquals(200, $response->getStatusCode()); 33 | $result = $this->jsonDecode($response->getBody()->getContents(), true); 34 | putenv('PHPSDK_SPEECH_LFASR_TASKID=' . $result['data']); 35 | $this->assertEquals(0, $result['err_no']); 36 | } 37 | 38 | public function testSuccessfullyUpload() 39 | { 40 | $this->assertEquals(200, $this->client->upload($this->config['taskId'], __DIR__ . '/../../input/1.wav')->getStatusCode()); 41 | } 42 | 43 | public function testSuccessfullyMerge() 44 | { 45 | $this->assertEquals(200, $this->client->merge($this->config['taskId'])->getStatusCode()); 46 | } 47 | 48 | public function testSuccessfullyGetProgress() 49 | { 50 | $response = $this->client->getProgress($this->config['taskId']); 51 | $this->assertEquals(200, $response->getStatusCode()); 52 | $this->assertEquals(200, $this->client->getProgress($this->config['taskId'])->getStatusCode()); 53 | } 54 | 55 | public function testSuccessfullyGetResult() 56 | { 57 | $response = $this->client->getResult($this->config['taskId']); 58 | $this->assertEquals(200, $response->getStatusCode()); 59 | $this->assertEquals(200, $this->client->getProgress($this->config['taskId'])->getStatusCode()); 60 | } 61 | 62 | public function testSuccessfullyCombileUpload() 63 | { 64 | $taskId = $this->client->combineUpload(__DIR__ . '/../../input/1.wav'); 65 | $this->assertNotNull($taskId); 66 | if (file_exists($credentialsFile = __DIR__ . '/../credentials.yml')) { 67 | $credentials = Yaml::parseFile($credentialsFile); 68 | $credentials['lfasr']['taskId'] = $taskId; 69 | file_put_contents($credentialsFile, Yaml::dump($credentials)); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/Unit/Speech/TcClientTest.php: -------------------------------------------------------------------------------- 1 | ability = 'common'; 15 | } 16 | 17 | public function testSuccessfullyRequest() 18 | { 19 | $client = new TcClient( 20 | $this->config['appId'], 21 | $this->config['apiKey'], 22 | $this->config['apiSecret'] 23 | ); 24 | 25 | $result = $client->request('历史上有很多注明的人物,其中唐太宗李世民就是一位。'); 26 | $data = json_decode($result->getBody()->getContents(), true); 27 | $content = $data['payload']['result']['text']; 28 | $this->assertArrayHasKey('appId', $this->config); 29 | $this->assertInstanceOf(TcClient::class, $client); 30 | $this->assertEquals(200, $result->getStatusCode()); 31 | $this->assertEquals('b513941b0424175564a1275f0f543b3b', md5($content)); 32 | } 33 | 34 | public function testSuccessfullyListUploadAndRequest() { 35 | $client = new TcClient( 36 | $this->config['appId'], 37 | $this->config['apiKey'], 38 | $this->config['apiSecret'], 39 | '1001', 40 | '2002' 41 | ); 42 | 43 | $this->assertTrue($client->listUpload("注明", "世民 市民,人物 任务")); 44 | 45 | $result = $client->request('历史上有很多注明的人物,其中唐太宗李世民就是一位。'); 46 | $data = json_decode($result->getBody()->getContents(), true); 47 | $content = $data['payload']['result']['text']; 48 | $this->assertArrayHasKey('appId', $this->config); 49 | $this->assertInstanceOf(TcClient::class, $client); 50 | $this->assertEquals(200, $result->getStatusCode()); 51 | $this->assertEquals('2db635360fb910c74da8acbb02250062', md5($content)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/Unit/Speech/TtsClientTest.php: -------------------------------------------------------------------------------- 1 | ability = 'common'; 15 | } 16 | 17 | public function testSuccessfullyRequest() 18 | { 19 | 20 | $logger = new Logger('my_logger'); 21 | $logger->pushHandler(new StreamHandler(__DIR__.'/unit.test.log', Logger::DEBUG)); 22 | $client = new TtsClient( 23 | $this->config['appId'], 24 | $this->config['apiKey'], 25 | $this->config['apiSecret'], 26 | [], 27 | $logger 28 | ); 29 | $result = $client->request('爱我中华'); 30 | $this->assertArrayHasKey('appId', $this->config); 31 | $this->assertInstanceOf(TtsClient::class, $client); 32 | $this->assertEquals(200, $result->getStatusCode()); 33 | $this->assertEquals('58173aacf1dabcb66fcd3fb7c54c0d68', md5($result->getBody())); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/input/1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iFLYTEK-OP/websdk-php/6aaa00af1717384f09a5635199d32ffdc44e671b/tests/input/1.wav -------------------------------------------------------------------------------- /tests/input/igr_pcm_16k.pcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iFLYTEK-OP/websdk-php/6aaa00af1717384f09a5635199d32ffdc44e671b/tests/input/igr_pcm_16k.pcm -------------------------------------------------------------------------------- /tests/input/iseTest.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iFLYTEK-OP/websdk-php/6aaa00af1717384f09a5635199d32ffdc44e671b/tests/input/iseTest.mp3 --------------------------------------------------------------------------------