dashscope 1.19.2__py3-none-any.whl → 1.20.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dashscope might be problematic. Click here for more details.
- dashscope/aigc/image_synthesis.py +14 -8
- dashscope/api_entities/http_request.py +5 -17
- dashscope/app/application_response.py +4 -0
- dashscope/audio/__init__.py +2 -2
- dashscope/audio/tts_v2/__init__.py +7 -0
- dashscope/audio/tts_v2/speech_synthesizer.py +476 -0
- dashscope/common/utils.py +1 -1
- dashscope/embeddings/text_embedding.py +1 -0
- dashscope/version.py +1 -1
- {dashscope-1.19.2.dist-info → dashscope-1.20.0.dist-info}/METADATA +2 -1
- {dashscope-1.19.2.dist-info → dashscope-1.20.0.dist-info}/RECORD +15 -13
- {dashscope-1.19.2.dist-info → dashscope-1.20.0.dist-info}/LICENSE +0 -0
- {dashscope-1.19.2.dist-info → dashscope-1.20.0.dist-info}/WHEEL +0 -0
- {dashscope-1.19.2.dist-info → dashscope-1.20.0.dist-info}/entry_points.txt +0 -0
- {dashscope-1.19.2.dist-info → dashscope-1.20.0.dist-info}/top_level.txt +0 -0
|
@@ -27,6 +27,7 @@ class ImageSynthesis(BaseAsyncApi):
|
|
|
27
27
|
ref_img: str = None,
|
|
28
28
|
workspace: str = None,
|
|
29
29
|
extra_input: Dict = None,
|
|
30
|
+
task: str = None,
|
|
30
31
|
**kwargs) -> ImageSynthesisResponse:
|
|
31
32
|
"""Call image(s) synthesis service and get result.
|
|
32
33
|
|
|
@@ -41,6 +42,7 @@ class ImageSynthesis(BaseAsyncApi):
|
|
|
41
42
|
Defaults to None.
|
|
42
43
|
workspace (str): The dashscope workspace id.
|
|
43
44
|
extra_input (Dict): The extra input parameters.
|
|
45
|
+
task (str): The task of api, ref doc.
|
|
44
46
|
**kwargs:
|
|
45
47
|
n(int, `optional`): Number of images to synthesis.
|
|
46
48
|
size(str, `optional`): The output image(s) size(width*height).
|
|
@@ -67,6 +69,7 @@ class ImageSynthesis(BaseAsyncApi):
|
|
|
67
69
|
ref_img=ref_img,
|
|
68
70
|
workspace=workspace,
|
|
69
71
|
extra_input=extra_input,
|
|
72
|
+
task=task,
|
|
70
73
|
**kwargs)
|
|
71
74
|
|
|
72
75
|
@classmethod
|
|
@@ -80,6 +83,7 @@ class ImageSynthesis(BaseAsyncApi):
|
|
|
80
83
|
ref_img: str = None,
|
|
81
84
|
workspace: str = None,
|
|
82
85
|
extra_input: Dict = None,
|
|
86
|
+
task: str = None,
|
|
83
87
|
**kwargs) -> ImageSynthesisResponse:
|
|
84
88
|
"""Create a image(s) synthesis task, and return task information.
|
|
85
89
|
|
|
@@ -93,6 +97,7 @@ class ImageSynthesis(BaseAsyncApi):
|
|
|
93
97
|
Defaults to None.
|
|
94
98
|
workspace (str): The dashscope workspace id.
|
|
95
99
|
extra_input (Dict): The extra input parameters.
|
|
100
|
+
task (str): The task of api, ref doc.
|
|
96
101
|
**kwargs(wanx-v1):
|
|
97
102
|
n(int, `optional`): Number of images to synthesis.
|
|
98
103
|
size: The output image(s) size, Default 1024*1024
|
|
@@ -126,14 +131,15 @@ class ImageSynthesis(BaseAsyncApi):
|
|
|
126
131
|
if extra_input is not None and extra_input:
|
|
127
132
|
input = {**input, **extra_input}
|
|
128
133
|
|
|
129
|
-
response = super().async_call(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
response = super().async_call(
|
|
135
|
+
model=model,
|
|
136
|
+
task_group=task_group,
|
|
137
|
+
task=ImageSynthesis.task if task is None else task,
|
|
138
|
+
function=function,
|
|
139
|
+
api_key=api_key,
|
|
140
|
+
input=input,
|
|
141
|
+
workspace=workspace,
|
|
142
|
+
**kwargs)
|
|
137
143
|
return ImageSynthesisResponse.from_api_response(response)
|
|
138
144
|
|
|
139
145
|
@classmethod
|
|
@@ -130,19 +130,11 @@ class HttpRequest(AioBaseRequest):
|
|
|
130
130
|
async for rsp in self._handle_aio_response(response):
|
|
131
131
|
yield rsp
|
|
132
132
|
except aiohttp.ClientConnectorError as e:
|
|
133
|
-
logger.
|
|
134
|
-
|
|
135
|
-
'',
|
|
136
|
-
'Unknown',
|
|
137
|
-
message='Error type: %s, message: %s' %
|
|
138
|
-
(type(e), e))
|
|
133
|
+
logger.error(e)
|
|
134
|
+
raise e
|
|
139
135
|
except BaseException as e:
|
|
140
|
-
logger.
|
|
141
|
-
|
|
142
|
-
'',
|
|
143
|
-
'Unknown',
|
|
144
|
-
message='Error type: %s, message: %s' %
|
|
145
|
-
(type(e), e))
|
|
136
|
+
logger.error(e)
|
|
137
|
+
raise e
|
|
146
138
|
|
|
147
139
|
async def _handle_aio_response(self, response: aiohttp.ClientResponse):
|
|
148
140
|
request_id = ''
|
|
@@ -308,8 +300,4 @@ class HttpRequest(AioBaseRequest):
|
|
|
308
300
|
yield rsp
|
|
309
301
|
except BaseException as e:
|
|
310
302
|
logger.error(e)
|
|
311
|
-
|
|
312
|
-
'',
|
|
313
|
-
'Unknown',
|
|
314
|
-
message='Error type: %s, message: %s' %
|
|
315
|
-
(type(e), e))
|
|
303
|
+
raise e
|
|
@@ -67,6 +67,7 @@ class ApplicationDocReference(DictMixin):
|
|
|
67
67
|
doc_url: str
|
|
68
68
|
text: str
|
|
69
69
|
biz_id: str
|
|
70
|
+
images: List[str]
|
|
70
71
|
|
|
71
72
|
def __init__(self,
|
|
72
73
|
index_id: str = None,
|
|
@@ -76,6 +77,7 @@ class ApplicationDocReference(DictMixin):
|
|
|
76
77
|
doc_url: str = None,
|
|
77
78
|
text: str = None,
|
|
78
79
|
biz_id: str = None,
|
|
80
|
+
images: List[str] = None,
|
|
79
81
|
**kwargs):
|
|
80
82
|
""" Doc references for retrieval result.
|
|
81
83
|
|
|
@@ -87,6 +89,7 @@ class ApplicationDocReference(DictMixin):
|
|
|
87
89
|
doc_url (str, optional): Url of original doc that retrieved.
|
|
88
90
|
text (str, optional): Text in original doc that retrieved.
|
|
89
91
|
biz_id (str, optional): Biz id that caller is able to associated for biz logic.
|
|
92
|
+
images (list, optional): List of referenced image URLs
|
|
90
93
|
"""
|
|
91
94
|
|
|
92
95
|
super().__init__(index_id=index_id,
|
|
@@ -96,6 +99,7 @@ class ApplicationDocReference(DictMixin):
|
|
|
96
99
|
doc_url=doc_url,
|
|
97
100
|
text=text,
|
|
98
101
|
biz_id=biz_id,
|
|
102
|
+
images=images,
|
|
99
103
|
**kwargs)
|
|
100
104
|
|
|
101
105
|
|
dashscope/audio/__init__.py
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from . import asr, tts
|
|
1
|
+
from . import asr, tts, tts_v2
|
|
2
2
|
|
|
3
|
-
__all__ = [asr, tts]
|
|
3
|
+
__all__ = [asr, tts, tts_v2]
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from .speech_synthesizer import AudioFormat, ResultCallback, SpeechSynthesizer
|
|
2
|
+
|
|
3
|
+
__all__ = ['SpeechSynthesizer', 'ResultCallback', 'AudioFormat']
|
|
4
|
+
|
|
5
|
+
# from .speech_synthesizer import (SpeechSynthesizer, ResultCallback, SpeechSynthesisResult, AudioFormat)
|
|
6
|
+
|
|
7
|
+
# __all__ = ['SpeechSynthesizer', 'ResultCallback', 'SpeechSynthesisResult', 'AudioFormat']
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import platform
|
|
3
|
+
import threading
|
|
4
|
+
import time
|
|
5
|
+
import uuid
|
|
6
|
+
from enum import Enum, unique
|
|
7
|
+
|
|
8
|
+
import websocket
|
|
9
|
+
|
|
10
|
+
import dashscope
|
|
11
|
+
from dashscope.common.error import InputRequired, InvalidTask, ModelRequired
|
|
12
|
+
from dashscope.common.logging import logger
|
|
13
|
+
from dashscope.protocol.websocket import (ACTION_KEY, EVENT_KEY, HEADER,
|
|
14
|
+
TASK_ID, ActionType, EventType,
|
|
15
|
+
WebsocketStreamingMode)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ResultCallback:
|
|
19
|
+
"""
|
|
20
|
+
An interface that defines callback methods for getting speech synthesis results. # noqa E501
|
|
21
|
+
Derive from this class and implement its function to provide your own data.
|
|
22
|
+
"""
|
|
23
|
+
def on_open(self) -> None:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
def on_complete(self) -> None:
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
def on_error(self, message) -> None:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
def on_close(self) -> None:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
def on_event(self, message: str) -> None:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
def on_data(self, data: bytes) -> None:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@unique
|
|
43
|
+
class AudioFormat(Enum):
|
|
44
|
+
DEFAULT = ('Default', 0, '0', '0')
|
|
45
|
+
WAV_8000HZ_MONO_16BIT = ('wav', 8000, 'mono', '16bit')
|
|
46
|
+
WAV_16000HZ_MONO_16BIT = ('wav', 16000, 'mono', '16bit')
|
|
47
|
+
WAV_22050HZ_MONO_16BIT = ('wav', 22050, 'mono', '16bit')
|
|
48
|
+
WAV_24000HZ_MONO_16BIT = ('wav', 24000, 'mono', '16bit')
|
|
49
|
+
WAV_44100HZ_MONO_16BIT = ('wav', 44100, 'mono', '16bit')
|
|
50
|
+
WAV_48000HZ_MONO_16BIT = ('wav', 48000, 'mono', '16bit')
|
|
51
|
+
|
|
52
|
+
MP3_8000HZ_MONO_128KBPS = ('mp3', 8000, 'mono', '128kbps')
|
|
53
|
+
MP3_16000HZ_MONO_128KBPS = ('mp3', 16000, 'mono', '128kbps')
|
|
54
|
+
MP3_22050HZ_MONO_256KBPS = ('mp3', 22050, 'mono', '256kbps')
|
|
55
|
+
MP3_24000HZ_MONO_256KBPS = ('mp3', 24000, 'mono', '256kbps')
|
|
56
|
+
MP3_44100HZ_MONO_256KBPS = ('mp3', 44100, 'mono', '256kbps')
|
|
57
|
+
MP3_48000HZ_MONO_256KBPS = ('mp3', 48000, 'mono', '256kbps')
|
|
58
|
+
|
|
59
|
+
PCM_8000HZ_MONO_16BIT = ('pcm', 8000, 'mono', '16bit')
|
|
60
|
+
PCM_16000HZ_MONO_16BIT = ('pcm', 16000, 'mono', '16bit')
|
|
61
|
+
PCM_22050HZ_MONO_16BIT = ('pcm', 22050, 'mono', '16bit')
|
|
62
|
+
PCM_24000HZ_MONO_16BIT = ('pcm', 24000, 'mono', '16bit')
|
|
63
|
+
PCM_44100HZ_MONO_16BIT = ('pcm', 44100, 'mono', '16bit')
|
|
64
|
+
PCM_48000HZ_MONO_16BIT = ('pcm', 48000, 'mono', '16bit')
|
|
65
|
+
|
|
66
|
+
def __init__(self, format, sample_rate, channels, bit_rate):
|
|
67
|
+
self.format = format
|
|
68
|
+
self.sample_rate = sample_rate
|
|
69
|
+
self.channels = channels
|
|
70
|
+
self.bit_rate = bit_rate
|
|
71
|
+
|
|
72
|
+
def __str__(self):
|
|
73
|
+
return f'{self.format.upper()} with {self.sample_rate}Hz sample rate, {self.channels} channel, {self.bit_rate}'
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class Request:
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
apikey,
|
|
80
|
+
model,
|
|
81
|
+
voice,
|
|
82
|
+
format='wav',
|
|
83
|
+
sample_rate=16000,
|
|
84
|
+
volumn=50,
|
|
85
|
+
speech_rate=1.0,
|
|
86
|
+
pitch_rate=1.0,
|
|
87
|
+
):
|
|
88
|
+
self.task_id = self.genUid()
|
|
89
|
+
self.apikey = apikey
|
|
90
|
+
self.voice = voice
|
|
91
|
+
self.model = model
|
|
92
|
+
self.format = format
|
|
93
|
+
self.sample_rate = sample_rate
|
|
94
|
+
self.volumn = volumn
|
|
95
|
+
self.speech_rate = speech_rate
|
|
96
|
+
self.pitch_rate = pitch_rate
|
|
97
|
+
|
|
98
|
+
def genUid(self):
|
|
99
|
+
# 生成随机UUID
|
|
100
|
+
return uuid.uuid4().hex
|
|
101
|
+
|
|
102
|
+
def getWebsocketHeaders(self, headers, workspace):
|
|
103
|
+
ua = 'dashscope/%s; python/%s; platform/%s; processor/%s' % (
|
|
104
|
+
'1.18.0', # dashscope version
|
|
105
|
+
platform.python_version(),
|
|
106
|
+
platform.platform(),
|
|
107
|
+
platform.processor(),
|
|
108
|
+
)
|
|
109
|
+
self.headers = {
|
|
110
|
+
'user-agent': ua,
|
|
111
|
+
'Authorization': 'bearer ' + self.apikey,
|
|
112
|
+
}
|
|
113
|
+
if headers:
|
|
114
|
+
self.headers = {**self.headers, **headers}
|
|
115
|
+
if workspace:
|
|
116
|
+
self.headers = {
|
|
117
|
+
**self.headers,
|
|
118
|
+
'X-DashScope-WorkSpace': workspace,
|
|
119
|
+
}
|
|
120
|
+
return self.headers
|
|
121
|
+
|
|
122
|
+
def getStartRequest(self, additional_params=None):
|
|
123
|
+
|
|
124
|
+
cmd = {
|
|
125
|
+
HEADER: {
|
|
126
|
+
ACTION_KEY: ActionType.START,
|
|
127
|
+
TASK_ID: self.task_id,
|
|
128
|
+
'streaming': WebsocketStreamingMode.DUPLEX,
|
|
129
|
+
},
|
|
130
|
+
'payload': {
|
|
131
|
+
'model': self.model,
|
|
132
|
+
'task_group': 'audio',
|
|
133
|
+
'task': 'tts',
|
|
134
|
+
'function': 'SpeechSynthesizer',
|
|
135
|
+
'input': {
|
|
136
|
+
'text': ''
|
|
137
|
+
},
|
|
138
|
+
'parameters': {
|
|
139
|
+
'voice': self.voice,
|
|
140
|
+
'volume': self.volumn,
|
|
141
|
+
'text_type': 'PlainText',
|
|
142
|
+
'sample_rate': self.sample_rate,
|
|
143
|
+
'rate': self.speech_rate,
|
|
144
|
+
'format': self.format,
|
|
145
|
+
'pitch': self.pitch_rate,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
if additional_params:
|
|
150
|
+
cmd['payload']['parameters'].update(additional_params)
|
|
151
|
+
return json.dumps(cmd)
|
|
152
|
+
|
|
153
|
+
def getContinueRequest(self, text):
|
|
154
|
+
cmd = {
|
|
155
|
+
HEADER: {
|
|
156
|
+
ACTION_KEY: ActionType.CONTINUE,
|
|
157
|
+
TASK_ID: self.task_id,
|
|
158
|
+
'streaming': WebsocketStreamingMode.DUPLEX,
|
|
159
|
+
},
|
|
160
|
+
'payload': {
|
|
161
|
+
'model': self.model,
|
|
162
|
+
'task_group': 'audio',
|
|
163
|
+
'task': 'tts',
|
|
164
|
+
'function': 'SpeechSynthesizer',
|
|
165
|
+
'input': {
|
|
166
|
+
'text': text
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
return json.dumps(cmd)
|
|
171
|
+
|
|
172
|
+
def getFinishRequest(self):
|
|
173
|
+
cmd = {
|
|
174
|
+
HEADER: {
|
|
175
|
+
ACTION_KEY: ActionType.FINISHED,
|
|
176
|
+
TASK_ID: self.task_id,
|
|
177
|
+
'streaming': WebsocketStreamingMode.DUPLEX,
|
|
178
|
+
},
|
|
179
|
+
'payload': {
|
|
180
|
+
'input': {
|
|
181
|
+
'text': ''
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
return json.dumps(cmd)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class SpeechSynthesizer:
|
|
189
|
+
def __init__(
|
|
190
|
+
self,
|
|
191
|
+
model,
|
|
192
|
+
voice,
|
|
193
|
+
format: AudioFormat = AudioFormat.DEFAULT,
|
|
194
|
+
volumn=50,
|
|
195
|
+
speech_rate=1.0,
|
|
196
|
+
pitch_rate=1.0,
|
|
197
|
+
headers=None,
|
|
198
|
+
callback: ResultCallback = None,
|
|
199
|
+
workspace=None,
|
|
200
|
+
url=None,
|
|
201
|
+
additional_params=None,
|
|
202
|
+
):
|
|
203
|
+
"""
|
|
204
|
+
CosyVoice Speech Synthesis SDK
|
|
205
|
+
Parameters:
|
|
206
|
+
-----------
|
|
207
|
+
model: str
|
|
208
|
+
Model name.
|
|
209
|
+
voice: str
|
|
210
|
+
Voice name.
|
|
211
|
+
format: AudioFormat
|
|
212
|
+
Synthesis audio format.
|
|
213
|
+
volume: int
|
|
214
|
+
The volume of the synthesized audio, with a range from 0 to 100. Default is 50.
|
|
215
|
+
rate: float
|
|
216
|
+
The speech rate of the synthesized audio, with a range from 0.5 to 2. Default is 1.0.
|
|
217
|
+
pitch: float
|
|
218
|
+
The pitch of the synthesized audio, with a range from 0.5 to 2. Default is 1.0.
|
|
219
|
+
headers: Dict
|
|
220
|
+
User-defined headers.
|
|
221
|
+
callback: ResultCallback
|
|
222
|
+
Callback to receive real-time synthesis results.
|
|
223
|
+
workspace: str
|
|
224
|
+
Dashscope workspace ID.
|
|
225
|
+
url: str
|
|
226
|
+
Dashscope WebSocket URL.
|
|
227
|
+
additional_params: Dict
|
|
228
|
+
Additional parameters for the Dashscope API.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
if model is None:
|
|
232
|
+
raise ModelRequired('Model is required!')
|
|
233
|
+
if format is None:
|
|
234
|
+
raise InputRequired('format is required!')
|
|
235
|
+
if url is None:
|
|
236
|
+
url = dashscope.base_websocket_api_url
|
|
237
|
+
self.url = url
|
|
238
|
+
self.apikey = dashscope.api_key
|
|
239
|
+
self.headers = headers
|
|
240
|
+
self.workspace = workspace
|
|
241
|
+
self.additional_params = additional_params
|
|
242
|
+
|
|
243
|
+
self.request = Request(
|
|
244
|
+
apikey=self.apikey,
|
|
245
|
+
model=model,
|
|
246
|
+
voice=voice,
|
|
247
|
+
format=format.format,
|
|
248
|
+
sample_rate=format.sample_rate,
|
|
249
|
+
volumn=volumn,
|
|
250
|
+
speech_rate=speech_rate,
|
|
251
|
+
pitch_rate=pitch_rate,
|
|
252
|
+
)
|
|
253
|
+
self.start_event = threading.Event()
|
|
254
|
+
self.complete_event = threading.Event()
|
|
255
|
+
self._stopped = threading.Event()
|
|
256
|
+
self._audio_data: bytes = None
|
|
257
|
+
self._is_started = False
|
|
258
|
+
self._cancel = False
|
|
259
|
+
self._cancel_lock = threading.Lock()
|
|
260
|
+
self.async_call = True
|
|
261
|
+
self.callback = callback
|
|
262
|
+
self._is_first = True
|
|
263
|
+
self.async_call = True
|
|
264
|
+
# since dashscope sdk will send first text in run-task
|
|
265
|
+
if not self.callback:
|
|
266
|
+
self.async_call = False
|
|
267
|
+
|
|
268
|
+
def __send_str(self, data: str):
|
|
269
|
+
logger.debug('>>>send {}'.format(data))
|
|
270
|
+
self.ws.send(data)
|
|
271
|
+
|
|
272
|
+
def __start_stream(self, ):
|
|
273
|
+
if self.callback is None:
|
|
274
|
+
raise InputRequired('callback is required!')
|
|
275
|
+
# reset inner params
|
|
276
|
+
self._stopped.clear()
|
|
277
|
+
self._stream_data = ['']
|
|
278
|
+
self._worker = None
|
|
279
|
+
self._audio_data: bytes = None
|
|
280
|
+
|
|
281
|
+
if self._is_started:
|
|
282
|
+
raise InvalidTask('task has already started.')
|
|
283
|
+
|
|
284
|
+
self.ws = websocket.WebSocketApp(
|
|
285
|
+
self.url,
|
|
286
|
+
header=self.request.getWebsocketHeaders(headers=self.headers,
|
|
287
|
+
workspace=self.workspace),
|
|
288
|
+
on_message=self.on_message,
|
|
289
|
+
on_error=self.on_error,
|
|
290
|
+
on_close=self.on_close,
|
|
291
|
+
)
|
|
292
|
+
self.thread = threading.Thread(target=self.ws.run_forever)
|
|
293
|
+
self.thread.daemon = True
|
|
294
|
+
self.thread.start()
|
|
295
|
+
request = self.request.getStartRequest(self.additional_params)
|
|
296
|
+
# 等待连接建立
|
|
297
|
+
timeout = 5 # 最长等待时间(秒)
|
|
298
|
+
start_time = time.time()
|
|
299
|
+
while (not (self.ws.sock and self.ws.sock.connected)
|
|
300
|
+
and (time.time() - start_time) < timeout):
|
|
301
|
+
time.sleep(0.1) # 短暂休眠,避免密集轮询
|
|
302
|
+
self.__send_str(request)
|
|
303
|
+
if not self.start_event.wait(10):
|
|
304
|
+
raise TimeoutError('start speech synthesizer failed within 5s.')
|
|
305
|
+
self._is_started = True
|
|
306
|
+
if self.callback:
|
|
307
|
+
self.callback.on_open()
|
|
308
|
+
|
|
309
|
+
def __submit_text(self, text):
|
|
310
|
+
if not self._is_started:
|
|
311
|
+
raise InvalidTask('speech synthesizer has not been started.')
|
|
312
|
+
|
|
313
|
+
if self._stopped.is_set():
|
|
314
|
+
raise InvalidTask('speech synthesizer task has stopped.')
|
|
315
|
+
request = self.request.getContinueRequest(text)
|
|
316
|
+
self.__send_str(request)
|
|
317
|
+
|
|
318
|
+
def streaming_call(self, text: str):
|
|
319
|
+
"""
|
|
320
|
+
Streaming input mode: You can call the stream_call function multiple times to send text.
|
|
321
|
+
A session will be created on the first call.
|
|
322
|
+
The session ends after calling streaming_complete.
|
|
323
|
+
Parameters:
|
|
324
|
+
-----------
|
|
325
|
+
text: str
|
|
326
|
+
utf-8 encoded text
|
|
327
|
+
"""
|
|
328
|
+
if self._is_first:
|
|
329
|
+
self._is_first = False
|
|
330
|
+
self.__start_stream()
|
|
331
|
+
self.__submit_text(text)
|
|
332
|
+
return None
|
|
333
|
+
|
|
334
|
+
def streaming_complete(self, complete_timeout_millie=10000):
|
|
335
|
+
"""
|
|
336
|
+
Synchronously stop the streaming input speech synthesis task.
|
|
337
|
+
Wait for all remaining synthesized audio before returning
|
|
338
|
+
|
|
339
|
+
Parameters:
|
|
340
|
+
-----------
|
|
341
|
+
complete_timeout_millis: int
|
|
342
|
+
Throws TimeoutError exception if it times out.
|
|
343
|
+
"""
|
|
344
|
+
if not self._is_started:
|
|
345
|
+
raise InvalidTask('speech synthesizer has not been started.')
|
|
346
|
+
if self._stopped.is_set():
|
|
347
|
+
raise InvalidTask('speech synthesizer task has stopped.')
|
|
348
|
+
request = self.request.getFinishRequest()
|
|
349
|
+
self.__send_str(request)
|
|
350
|
+
if not self.complete_event.wait(timeout=complete_timeout_millie):
|
|
351
|
+
raise TimeoutError(
|
|
352
|
+
'speech synthesizer wait for complete timeout {}ms'.format(
|
|
353
|
+
complete_timeout_millie))
|
|
354
|
+
self.close()
|
|
355
|
+
self._stopped.set()
|
|
356
|
+
self._is_started = False
|
|
357
|
+
|
|
358
|
+
def __waiting_for_complete(self):
|
|
359
|
+
if not self.complete_event.wait(timeout=10000):
|
|
360
|
+
raise TimeoutError(
|
|
361
|
+
'speech synthesizer wait for complete timeout 10000ms')
|
|
362
|
+
self.close()
|
|
363
|
+
self._stopped.set()
|
|
364
|
+
self._is_started = False
|
|
365
|
+
|
|
366
|
+
def async_streaming_complete(self):
|
|
367
|
+
"""
|
|
368
|
+
Asynchronously stop the streaming input speech synthesis task, returns immediately.
|
|
369
|
+
You need to listen and handle the STREAM_INPUT_TTS_EVENT_SYNTHESIS_COMPLETE event in the on_event callback.
|
|
370
|
+
Do not destroy the object and callback before this event.
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
if not self._is_started:
|
|
374
|
+
raise InvalidTask('speech synthesizer has not been started.')
|
|
375
|
+
if self._stopped.is_set():
|
|
376
|
+
raise InvalidTask('speech synthesizer task has stopped.')
|
|
377
|
+
request = self.request.getFinishRequest()
|
|
378
|
+
self.__send_str(request)
|
|
379
|
+
thread = threading.Thread(target=self.__waiting_for_complete)
|
|
380
|
+
thread.start()
|
|
381
|
+
|
|
382
|
+
def streaming_cancel(self):
|
|
383
|
+
"""
|
|
384
|
+
Immediately terminate the streaming input speech synthesis task
|
|
385
|
+
and discard any remaining audio that is not yet delivered.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
if not self._is_started:
|
|
389
|
+
raise InvalidTask('speech synthesizer has not been started.')
|
|
390
|
+
if self._stopped.is_set():
|
|
391
|
+
return
|
|
392
|
+
request = self.request.getFinishRequest()
|
|
393
|
+
self.__send_str(request)
|
|
394
|
+
self.close()
|
|
395
|
+
|
|
396
|
+
# 监听消息的回调函数
|
|
397
|
+
def on_message(self, ws, message):
|
|
398
|
+
if isinstance(message, str):
|
|
399
|
+
logger.debug('<<<recv {}'.format(message))
|
|
400
|
+
try:
|
|
401
|
+
# 尝试将消息解析为JSON
|
|
402
|
+
json_data = json.loads(message)
|
|
403
|
+
event = json_data['header'][EVENT_KEY]
|
|
404
|
+
# 调用JSON回调
|
|
405
|
+
if EventType.STARTED == event:
|
|
406
|
+
self.start_event.set()
|
|
407
|
+
elif EventType.FINISHED == event:
|
|
408
|
+
self.complete_event.set()
|
|
409
|
+
if self.callback:
|
|
410
|
+
self.callback.on_complete()
|
|
411
|
+
self.callback.on_close()
|
|
412
|
+
elif EventType.FAILED == event:
|
|
413
|
+
self.start_event.set()
|
|
414
|
+
self.complete_event.set()
|
|
415
|
+
if self.async_call:
|
|
416
|
+
self.callback.on_error(message)
|
|
417
|
+
self.callback.on_close()
|
|
418
|
+
else:
|
|
419
|
+
logger.error(f'TaskFailed: {message}')
|
|
420
|
+
elif EventType.GENERATED == event:
|
|
421
|
+
if self.callback:
|
|
422
|
+
self.callback.on_event(message)
|
|
423
|
+
else:
|
|
424
|
+
pass
|
|
425
|
+
except json.JSONDecodeError:
|
|
426
|
+
logger.error('Failed to parse message as JSON.')
|
|
427
|
+
elif isinstance(message, (bytes, bytearray)):
|
|
428
|
+
# 如果失败,认为是二进制消息
|
|
429
|
+
logger.debug('<<<recv binary {}'.format(len(message)))
|
|
430
|
+
# 只有在非异步调用的时候保存音频
|
|
431
|
+
if not self.async_call:
|
|
432
|
+
if self._audio_data is None:
|
|
433
|
+
self._audio_data = bytes(message)
|
|
434
|
+
else:
|
|
435
|
+
self._audio_data = self._audio_data + bytes(message)
|
|
436
|
+
if self.callback:
|
|
437
|
+
self.callback.on_data(message)
|
|
438
|
+
|
|
439
|
+
def call(self, text: str):
|
|
440
|
+
"""
|
|
441
|
+
Speech synthesis.
|
|
442
|
+
If callback is set, the audio will be returned in real-time through the on_event interface.
|
|
443
|
+
Otherwise, this function blocks until all audio is received and then returns the complete audio data.
|
|
444
|
+
|
|
445
|
+
Parameters:
|
|
446
|
+
-----------
|
|
447
|
+
text: str
|
|
448
|
+
utf-8 encoded text
|
|
449
|
+
return: bytes
|
|
450
|
+
If a callback is not set during initialization, the complete audio is returned
|
|
451
|
+
as the function's return value. Otherwise, the return value is null.
|
|
452
|
+
"""
|
|
453
|
+
# print('还不支持非流式语音合成sdk调用大模型,使用流式模拟')
|
|
454
|
+
if not self.callback:
|
|
455
|
+
self.callback = ResultCallback()
|
|
456
|
+
self.__start_stream()
|
|
457
|
+
self.__submit_text(text)
|
|
458
|
+
if self.async_call:
|
|
459
|
+
self.async_streaming_complete()
|
|
460
|
+
return None
|
|
461
|
+
else:
|
|
462
|
+
self.streaming_complete()
|
|
463
|
+
return self._audio_data
|
|
464
|
+
|
|
465
|
+
# WebSocket关闭的回调函数
|
|
466
|
+
def on_close(self, ws, close_status_code, close_msg):
|
|
467
|
+
pass
|
|
468
|
+
# print("### websocket closed msg [{}]{} ###".format(close_status_code, close_msg))
|
|
469
|
+
|
|
470
|
+
# WebSocket发生错误的回调函数
|
|
471
|
+
def on_error(self, ws, error):
|
|
472
|
+
raise Exception(f'websocket closed due to {error}')
|
|
473
|
+
|
|
474
|
+
# 关闭WebSocket连接
|
|
475
|
+
def close(self):
|
|
476
|
+
self.ws.close()
|
dashscope/common/utils.py
CHANGED
|
@@ -314,7 +314,7 @@ async def _handle_aiohttp_failed_response(
|
|
|
314
314
|
flattened_output: bool = False) -> DashScopeAPIResponse:
|
|
315
315
|
request_id = ''
|
|
316
316
|
if 'application/json' in response.content_type:
|
|
317
|
-
error =
|
|
317
|
+
error = response.json()
|
|
318
318
|
return _handle_error_message(error, response.status, flattened_output)
|
|
319
319
|
elif SSE_CONTENT_TYPE in response.content_type:
|
|
320
320
|
async for _, _, data in _handle_aio_stream(response):
|
dashscope/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '1.
|
|
1
|
+
__version__ = '1.20.0'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dashscope
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.20.0
|
|
4
4
|
Summary: dashscope client sdk library
|
|
5
5
|
Home-page: https://dashscope.aliyun.com/
|
|
6
6
|
Author: Alibaba Cloud
|
|
@@ -20,6 +20,7 @@ Requires-Python: >=3.8.0
|
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
Requires-Dist: aiohttp
|
|
22
22
|
Requires-Dist: requests
|
|
23
|
+
Requires-Dist: websocket-client
|
|
23
24
|
Provides-Extra: tokenizer
|
|
24
25
|
Requires-Dist: tiktoken ; extra == 'tokenizer'
|
|
25
26
|
|
|
@@ -6,12 +6,12 @@ dashscope/files.py,sha256=QgJjwhtn9F548nCA8jD8OvE6aQEj-20hZqJgYXsUdQU,3930
|
|
|
6
6
|
dashscope/finetune.py,sha256=_tflDUvu0KagSoCzLaf0hofpG_P8NU6PylL8CPjVhrA,6243
|
|
7
7
|
dashscope/model.py,sha256=UPOn1qMYFhX-ovXi3BMxZEBk8qOK7WLJOYHMbPZwYBo,1440
|
|
8
8
|
dashscope/models.py,sha256=1-bc-Ue68zurgu_y6RhfFr9uzeQMF5AZq-C32lJGMGU,1224
|
|
9
|
-
dashscope/version.py,sha256
|
|
9
|
+
dashscope/version.py,sha256=-WF9fGbBAG3Ia-pZ8ruKLHehAzfQDko1EUE6tUtxI8M,23
|
|
10
10
|
dashscope/aigc/__init__.py,sha256=s-MCA87KYiVumYtKtJi5IMN7xelSF6TqEU3s3_7RF-Y,327
|
|
11
11
|
dashscope/aigc/code_generation.py,sha256=KAJVrGp6tiNFBBg64Ovs9RfcP5SrIhrbW3wdA89NKso,10885
|
|
12
12
|
dashscope/aigc/conversation.py,sha256=xRoJlCR-IXHjSdkDrK74a9ut1FJg0FZhTNXZAJC18MA,14231
|
|
13
13
|
dashscope/aigc/generation.py,sha256=53oMCmN5ZbqeqAsKxmdunXlRh-XP8ZtnA7hB2id4Koo,17897
|
|
14
|
-
dashscope/aigc/image_synthesis.py,sha256=
|
|
14
|
+
dashscope/aigc/image_synthesis.py,sha256=Hg2r6H7Vj4MsXwm62lHf2lTpUb6nA3xWGEYX2o-2TLQ,10419
|
|
15
15
|
dashscope/aigc/multimodal_conversation.py,sha256=SlNnnsUPV19gdx8fYJAtsMFWPNGY6vhk5IGHZ5ZczpI,5369
|
|
16
16
|
dashscope/api_entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
dashscope/api_entities/aiohttp_request.py,sha256=aE3AeWba8Ig_xHMYjrAdkq0N61l_L2VFTG6HYh912X0,10229
|
|
@@ -19,22 +19,24 @@ dashscope/api_entities/api_request_data.py,sha256=JUMcfpJjKXEZLCBSFIDpgoaeQYk5uK
|
|
|
19
19
|
dashscope/api_entities/api_request_factory.py,sha256=4p-qxMuvCA0CmUHdH19QaUCaHmlLHAM1X2Jd4YKt5c0,4661
|
|
20
20
|
dashscope/api_entities/base_request.py,sha256=cXUL7xqSV8wBr5d-1kx65AO3IsRR9A_ps6Lok-v-MKM,926
|
|
21
21
|
dashscope/api_entities/dashscope_response.py,sha256=Bp1T7HwVlkOvpMNg-AEjz-BScxhLUXMXlE8ApXTtfhQ,17872
|
|
22
|
-
dashscope/api_entities/http_request.py,sha256=
|
|
22
|
+
dashscope/api_entities/http_request.py,sha256=pYE8qRMu9CaQDiugPlXeYoaj_diBv-ZDExCD3WNhehI,13259
|
|
23
23
|
dashscope/api_entities/websocket_request.py,sha256=Xr6IJ9WqrIw5ouBQLpgoRSwL1C09jkb4u1EZdxhVQy0,15039
|
|
24
24
|
dashscope/app/__init__.py,sha256=UiN_9i--z84Dw5wUehOh_Tkk_9Gq_td_Kbz1dobBEKg,62
|
|
25
25
|
dashscope/app/application.py,sha256=AegGVsk3dDzYACoYRNNjo3eG-2wrDd0dlOjYHpF0r2Y,7949
|
|
26
|
-
dashscope/app/application_response.py,sha256=
|
|
26
|
+
dashscope/app/application_response.py,sha256=U5I8Yb1IlXzj2L5a1OAl55i0MCB3kG9Qp4aY17_73pI,6886
|
|
27
27
|
dashscope/assistants/__init__.py,sha256=i9N5OxHgY7edlOhTdPyC0N5Uc0uMCkB2vbMPDCD1zX0,383
|
|
28
28
|
dashscope/assistants/assistant_types.py,sha256=1jNL30TOlrkiYhvCaB3E8jkPLG8CnQ6I3tHpYXZCsD0,4211
|
|
29
29
|
dashscope/assistants/assistants.py,sha256=NYahIDqhtnOcQOmnhZsjc5F5jvBUQcce8-fbrJXHVnQ,10833
|
|
30
30
|
dashscope/assistants/files.py,sha256=pwLVJ_pjpRFWyfI_MRvhH7Si7FzGDj4ChzZgWTpLOhg,6699
|
|
31
|
-
dashscope/audio/__init__.py,sha256
|
|
31
|
+
dashscope/audio/__init__.py,sha256=-ZRxrK-gV4QsUtlThIT-XwqB6vmyEsnhxIxdLmhCUuc,61
|
|
32
32
|
dashscope/audio/asr/__init__.py,sha256=-s180qWn_JPSpCo1q0aDJJ5HQ3zTzD4z5yUwsRqH4aU,275
|
|
33
33
|
dashscope/audio/asr/asr_phrase_manager.py,sha256=EjtbI3zz9UQGS1qv6Yb4zzEMj4OJJVXmwkqZyIrzvEA,7642
|
|
34
34
|
dashscope/audio/asr/recognition.py,sha256=F2iz6hyXg16Z6DGlPwGpKfRNcAZIIsqXnNPtaZp4Fzo,17369
|
|
35
35
|
dashscope/audio/asr/transcription.py,sha256=e5O1U51GT-OQPu-wWN2w_T7l6IopWuGMVkheOGdNCkk,8836
|
|
36
36
|
dashscope/audio/tts/__init__.py,sha256=fbnieZX9yNFNh5BsxLpLXb63jlxzxrdCJakV3ignjlQ,194
|
|
37
37
|
dashscope/audio/tts/speech_synthesizer.py,sha256=dnKx9FDDdO_ETHAjhK8zaMVaH6SfoTtN5YxXXqgY1JA,7571
|
|
38
|
+
dashscope/audio/tts_v2/__init__.py,sha256=ve5a81qTbWDcRaSuritZtJBzryOIol2_dxzfqqdCw-k,345
|
|
39
|
+
dashscope/audio/tts_v2/speech_synthesizer.py,sha256=yxBSV14z-1XEhuwl-ziZcRnGM1ZEHl26-UdWLocNClU,16490
|
|
38
40
|
dashscope/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
41
|
dashscope/client/base_api.py,sha256=rww7uoDJtKxgiFQlBpZ8p__J0087cJWhvUxtdb3rrTE,41064
|
|
40
42
|
dashscope/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -45,7 +47,7 @@ dashscope/common/env.py,sha256=oQOZW5JyEeTSde394un2lpDJ5RBh4fMU9hBfbtrKKkc,869
|
|
|
45
47
|
dashscope/common/error.py,sha256=Q7GRhniP-7ap4HBpU69frRdKgKLwmH4ySYxCtupsr60,2638
|
|
46
48
|
dashscope/common/logging.py,sha256=ecGxylG3bWES_Xv5-BD6ep4_0Ciu7F6ZPBjiZtu9Jx4,984
|
|
47
49
|
dashscope/common/message_manager.py,sha256=i5149WzDk6nWmdFaHzYx4USXMBeX18GKSI-F4fLwbN0,1097
|
|
48
|
-
dashscope/common/utils.py,sha256=
|
|
50
|
+
dashscope/common/utils.py,sha256=yIHbbHZlK5UUGVZDizzjFENYb9S6JeJ-qqefP5IdGr4,15392
|
|
49
51
|
dashscope/customize/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
52
|
dashscope/customize/customize_types.py,sha256=ZtEwSXA4dbjIYr5vgQQNkMuXyC2BNmznGuaF6b7jwr0,4803
|
|
51
53
|
dashscope/customize/deployments.py,sha256=LIkM-hmJHcJZCKV6WJIPSXQ5CAhB5PUxnt5mqKbVbfE,5189
|
|
@@ -54,7 +56,7 @@ dashscope/embeddings/__init__.py,sha256=-dxHaoxZZVuP-wAGUIa3sNNh8CQwaeWj2UlqsDy1
|
|
|
54
56
|
dashscope/embeddings/batch_text_embedding.py,sha256=P32LFO9v7ehdJsl0c32In94hUET6K6AaGJ_pDRtFqco,8791
|
|
55
57
|
dashscope/embeddings/batch_text_embedding_response.py,sha256=WziXlQsFIkL1kPc_7lRG1HtqgkO5vVThtnNqExJggNU,2000
|
|
56
58
|
dashscope/embeddings/multimodal_embedding.py,sha256=yojtGNoT2N54g0jcAYUwNIiwzueun1ouqS0S0tvnyQc,3966
|
|
57
|
-
dashscope/embeddings/text_embedding.py,sha256=
|
|
59
|
+
dashscope/embeddings/text_embedding.py,sha256=I3zRvuT2HWcaZYH-zrtGcAQmzuLQxFswIHJMiQXfaJQ,2009
|
|
58
60
|
dashscope/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
61
|
dashscope/io/input_output.py,sha256=iZ1X1x1btdoZK2VeC9JsKkag2eaXwqfNT3Q6SrmRi2w,3941
|
|
60
62
|
dashscope/nlp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -80,9 +82,9 @@ dashscope/tokenizers/tokenizer.py,sha256=y6P91qTCYo__pEx_0VHAcj9YECfbUdRqZU1fdGT
|
|
|
80
82
|
dashscope/tokenizers/tokenizer_base.py,sha256=REDhzRyDT13iequ61-a6_KcTy0GFKlihQve5HkyoyRs,656
|
|
81
83
|
dashscope/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
82
84
|
dashscope/utils/oss_utils.py,sha256=fi8-PPsN-iR-iv5k2NS5Z8nlWkpgUhr56FRWm4BDh4A,6984
|
|
83
|
-
dashscope-1.
|
|
84
|
-
dashscope-1.
|
|
85
|
-
dashscope-1.
|
|
86
|
-
dashscope-1.
|
|
87
|
-
dashscope-1.
|
|
88
|
-
dashscope-1.
|
|
85
|
+
dashscope-1.20.0.dist-info/LICENSE,sha256=Izp5L1DF1Mbza6qojkqNNWlE_mYLnr4rmzx2EBF8YFw,11413
|
|
86
|
+
dashscope-1.20.0.dist-info/METADATA,sha256=kihsPZv9KJsRIziMd9I0kMzdmq7Al_IQFix-9xLbh68,6641
|
|
87
|
+
dashscope-1.20.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
|
88
|
+
dashscope-1.20.0.dist-info/entry_points.txt,sha256=raEp5dOuj8whJ7yqZlDM8WQ5p2RfnGrGNo0QLQEnatY,50
|
|
89
|
+
dashscope-1.20.0.dist-info/top_level.txt,sha256=woqavFJK9zas5xTqynmALqOtlafghjsk63Xk86powTU,10
|
|
90
|
+
dashscope-1.20.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|