├── .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]: <> ([](https://www.travis-ci.com/iFLYTEK-OP/websdk-php-speech)[](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
--------------------------------------------------------------------------------