Skip to content

Commit 4565d97

Browse files
authored
feat(oss): reuse upload certificate (#73)
1 parent 0d86f8c commit 4565d97

File tree

7 files changed

+154
-65
lines changed

7 files changed

+154
-65
lines changed

dashscope/aigc/image_synthesis.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,26 +136,28 @@ def _get_input(cls,
136136
raise InputRequired('prompt is required!')
137137
inputs = {PROMPT: prompt}
138138
has_upload = False
139+
upload_certificate = None
140+
139141
if negative_prompt is not None:
140142
inputs[NEGATIVE_PROMPT] = negative_prompt
141143
if images is not None and images and len(images) > 0:
142144
new_images = []
143145
for image in images:
144-
is_upload, new_image = check_and_upload_local(
145-
model, image, api_key)
146+
is_upload, new_image, upload_certificate = check_and_upload_local(
147+
model, image, api_key, upload_certificate)
146148
if is_upload:
147149
has_upload = True
148150
new_images.append(new_image)
149151
inputs[IMAGES] = new_images
150152
if sketch_image_url is not None and sketch_image_url:
151-
is_upload, sketch_image_url = check_and_upload_local(
152-
model, sketch_image_url, api_key)
153+
is_upload, sketch_image_url, upload_certificate = check_and_upload_local(
154+
model, sketch_image_url, api_key, upload_certificate)
153155
if is_upload:
154156
has_upload = True
155157
inputs['sketch_image_url'] = sketch_image_url
156158
if ref_img is not None and ref_img:
157-
is_upload, ref_img = check_and_upload_local(
158-
model, ref_img, api_key)
159+
is_upload, ref_img, upload_certificate = check_and_upload_local(
160+
model, ref_img, api_key, upload_certificate)
159161
if is_upload:
160162
has_upload = True
161163
inputs['ref_img'] = ref_img
@@ -164,15 +166,15 @@ def _get_input(cls,
164166
inputs['function'] = function
165167

166168
if mask_image_url is not None and mask_image_url:
167-
is_upload, res_mask_image_url = check_and_upload_local(
168-
model, mask_image_url, api_key)
169+
is_upload, res_mask_image_url, upload_certificate = check_and_upload_local(
170+
model, mask_image_url, api_key, upload_certificate)
169171
if is_upload:
170172
has_upload = True
171173
inputs['mask_image_url'] = res_mask_image_url
172174

173175
if base_image_url is not None and base_image_url:
174-
is_upload, res_base_image_url = check_and_upload_local(
175-
model, base_image_url, api_key)
176+
is_upload, res_base_image_url, upload_certificate = check_and_upload_local(
177+
model, base_image_url, api_key, upload_certificate)
176178
if is_upload:
177179
has_upload = True
178180
inputs['base_image_url'] = res_base_image_url

dashscope/aigc/multimodal_conversation.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,15 @@ def _preprocess_messages(cls, model: str, messages: List[dict],
160160
]
161161
"""
162162
has_upload = False
163+
upload_certificate = None
164+
163165
for message in messages:
164166
content = message['content']
165167
for elem in content:
166168
if not isinstance(elem,
167169
(int, float, bool, str, bytes, bytearray)):
168-
is_upload = preprocess_message_element(
169-
model, elem, api_key)
170+
is_upload, upload_certificate = preprocess_message_element(
171+
model, elem, api_key, upload_certificate)
170172
if is_upload and not has_upload:
171173
has_upload = True
172174
return has_upload
@@ -335,13 +337,15 @@ def _preprocess_messages(cls, model: str, messages: List[dict],
335337
]
336338
"""
337339
has_upload = False
340+
upload_certificate = None
341+
338342
for message in messages:
339343
content = message['content']
340344
for elem in content:
341345
if not isinstance(elem,
342346
(int, float, bool, str, bytes, bytearray)):
343-
is_upload = preprocess_message_element(
344-
model, elem, api_key)
347+
is_upload, upload_certificate = preprocess_message_element(
348+
model, elem, api_key, upload_certificate)
345349
if is_upload and not has_upload:
346350
has_upload = True
347351
return has_upload

dashscope/aigc/video_synthesis.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,45 +121,46 @@ def _get_input(cls,
121121
inputs['function'] = function
122122

123123
has_upload = False
124+
upload_certificate = None
124125

125126
if img_url is not None and img_url:
126-
is_upload, res_img_url = check_and_upload_local(
127-
model, img_url, api_key)
127+
is_upload, res_img_url, upload_certificate = check_and_upload_local(
128+
model, img_url, api_key, upload_certificate)
128129
if is_upload:
129130
has_upload = True
130131
inputs['img_url'] = res_img_url
131132

132133
if audio_url is not None and audio_url:
133-
is_upload, res_audio_url = check_and_upload_local(
134-
model, audio_url, api_key)
134+
is_upload, res_audio_url, upload_certificate = check_and_upload_local(
135+
model, audio_url, api_key, upload_certificate)
135136
if is_upload:
136137
has_upload = True
137138
inputs['audio_url'] = res_audio_url
138139

139140
if head_frame is not None and head_frame:
140-
is_upload, res_head_frame = check_and_upload_local(
141-
model, head_frame, api_key)
141+
is_upload, res_head_frame, upload_certificate = check_and_upload_local(
142+
model, head_frame, api_key, upload_certificate)
142143
if is_upload:
143144
has_upload = True
144145
inputs['head_frame'] = res_head_frame
145146

146147
if tail_frame is not None and tail_frame:
147-
is_upload, res_tail_frame = check_and_upload_local(
148-
model, tail_frame, api_key)
148+
is_upload, res_tail_frame, upload_certificate = check_and_upload_local(
149+
model, tail_frame, api_key, upload_certificate)
149150
if is_upload:
150151
has_upload = True
151152
inputs['tail_frame'] = res_tail_frame
152153

153154
if first_frame_url is not None and first_frame_url:
154-
is_upload, res_first_frame_url = check_and_upload_local(
155-
model, first_frame_url, api_key)
155+
is_upload, res_first_frame_url, upload_certificate = check_and_upload_local(
156+
model, first_frame_url, api_key, upload_certificate)
156157
if is_upload:
157158
has_upload = True
158159
inputs['first_frame_url'] = res_first_frame_url
159160

160161
if last_frame_url is not None and last_frame_url:
161-
is_upload, res_last_frame_url = check_and_upload_local(
162-
model, last_frame_url, api_key)
162+
is_upload, res_last_frame_url, upload_certificate = check_and_upload_local(
163+
model, last_frame_url, api_key, upload_certificate)
163164
if is_upload:
164165
has_upload = True
165166
inputs['last_frame_url'] = res_last_frame_url

dashscope/cli.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ def upload(cls, args):
215215
'DASHSCOPE_API_KEY or pass it as argument by -k/--api_key')
216216
return
217217

218-
oss_url = OssUtils.upload(model=args.model,
219-
file_path=file_path,
220-
api_key=api_key,
221-
base_address=args.base_url)
218+
oss_url, _ = OssUtils.upload(model=args.model,
219+
file_path=file_path,
220+
api_key=api_key,
221+
base_address=args.base_url)
222222

223223
if not oss_url:
224224
print('Failed to upload file: %s' % file_path)

dashscope/embeddings/multimodal_embedding.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,11 @@ def _preprocess_message_inputs(cls, model: str, input: List[dict],
105105
{'factor': 3, 'image': ''}]
106106
"""
107107
has_upload = False
108+
upload_certificate = None
108109
for elem in input:
109110
if not isinstance(elem, (int, float, bool, str, bytes, bytearray)):
110-
is_upload = preprocess_message_element(model, elem, api_key)
111+
is_upload, upload_certificate = preprocess_message_element(
112+
model, elem, api_key, upload_certificate)
111113
if is_upload and not has_upload:
112114
has_upload = True
113115
return has_upload
@@ -174,9 +176,11 @@ def _preprocess_message_inputs(cls, model: str, input: List[dict],
174176
{'factor': 3, 'image': ''}]
175177
"""
176178
has_upload = False
179+
upload_certificate = None
177180
for elem in input:
178181
if not isinstance(elem, (int, float, bool, str, bytes, bytearray)):
179-
is_upload = preprocess_message_element(model, elem, api_key)
182+
is_upload, upload_certificate = preprocess_message_element(
183+
model, elem, api_key, upload_certificate)
180184
if is_upload and not has_upload:
181185
has_upload = True
182186
return has_upload

dashscope/utils/oss_utils.py

Lines changed: 82 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,33 @@ def upload(cls,
3535
model: str,
3636
file_path: str,
3737
api_key: str = None,
38-
**kwargs) -> DashScopeAPIResponse:
38+
upload_certificate: dict = None,
39+
**kwargs):
3940
"""Upload file for model fine-tune or other tasks.
4041
4142
Args:
4243
file_path (str): The local file name to upload.
4344
purpose (str): The purpose of the file[fine-tune|inference]
4445
description (str, optional): The file description message.
4546
api_key (str, optional): The api key. Defaults to None.
47+
upload_certificate (dict, optional): Reusable upload
48+
certificate. Defaults to None.
4649
4750
Returns:
48-
DashScopeAPIResponse: The upload information
51+
tuple: (file_url, upload_certificate) where file_url is the
52+
OSS URL and upload_certificate is the certificate used
4953
"""
50-
upload_info = cls.get_upload_certificate(model=model, api_key=api_key, **kwargs)
51-
if upload_info.status_code != HTTPStatus.OK:
52-
raise UploadFileException(
53-
'Get upload certificate failed, code: %s, message: %s' %
54-
(upload_info.code, upload_info.message))
55-
upload_info = upload_info.output
54+
if upload_certificate is None:
55+
upload_info = cls.get_upload_certificate(model=model,
56+
api_key=api_key,
57+
**kwargs)
58+
if upload_info.status_code != HTTPStatus.OK:
59+
raise UploadFileException(
60+
'Get upload certificate failed, code: %s, message: %s' %
61+
(upload_info.code, upload_info.message))
62+
upload_info = upload_info.output
63+
else:
64+
upload_info = upload_certificate
5665
headers = {}
5766
headers = {'user-agent': get_user_agent()}
5867
headers['Accept'] = 'application/json'
@@ -77,7 +86,7 @@ def upload(cls,
7786
headers=headers,
7887
timeout=3600)
7988
if response.status_code == HTTPStatus.OK:
80-
return 'oss://' + form_data['key']
89+
return 'oss://' + form_data['key'], upload_info
8190
else:
8291
msg = (
8392
'Uploading file: %s to oss failed, error: %s' %
@@ -103,17 +112,19 @@ def get_upload_certificate(cls,
103112
return super().get(None, api_key, params=params, **kwargs)
104113

105114

106-
def upload_file(model: str, upload_path: str, api_key: str):
115+
def upload_file(model: str, upload_path: str, api_key: str,
116+
upload_certificate: dict = None):
107117
if upload_path.startswith(FILE_PATH_SCHEMA):
108118
parse_result = urlparse(upload_path)
109119
if parse_result.netloc:
110120
file_path = parse_result.netloc + unquote_plus(parse_result.path)
111121
else:
112122
file_path = unquote_plus(parse_result.path)
113123
if os.path.exists(file_path):
114-
file_url = OssUtils.upload(model=model,
115-
file_path=file_path,
116-
api_key=api_key)
124+
file_url, _ = OssUtils.upload(model=model,
125+
file_path=file_path,
126+
api_key=api_key,
127+
upload_certificate=upload_certificate)
117128
if file_url is None:
118129
raise UploadFileException('Uploading file: %s failed' %
119130
upload_path)
@@ -123,20 +134,26 @@ def upload_file(model: str, upload_path: str, api_key: str):
123134
return None
124135

125136

126-
def check_and_upload_local(model: str, content: str, api_key: str):
137+
def check_and_upload_local(model: str, content: str, api_key: str,
138+
upload_certificate: dict = None):
127139
"""Check the content is local file path, upload and return the url
128140
129141
Args:
130142
model (str): Which model to upload.
131143
content (str): The content.
132144
api_key (_type_): The api key.
145+
upload_certificate (dict, optional): Reusable upload certificate.
146+
Defaults to None.
133147
134148
Raises:
135149
UploadFileException: Upload failed.
136150
InvalidInput: The input is invalid
137151
138152
Returns:
139-
_type_: if upload return True and file_url otherwise False, origin content.
153+
tuple: (is_upload, file_url_or_content, upload_certificate)
154+
where is_upload indicates if file was uploaded, file_url_or_content
155+
is the result URL or original content, and upload_certificate
156+
is the certificate (newly obtained or passed in)
140157
"""
141158
if content.startswith(FILE_PATH_SCHEMA):
142159
parse_result = urlparse(content)
@@ -145,49 +162,82 @@ def check_and_upload_local(model: str, content: str, api_key: str):
145162
else:
146163
file_path = unquote_plus(parse_result.path)
147164
if os.path.isfile(file_path):
148-
file_url = OssUtils.upload(model=model,
149-
file_path=file_path,
150-
api_key=api_key)
165+
file_url, cert = OssUtils.upload(model=model,
166+
file_path=file_path,
167+
api_key=api_key,
168+
upload_certificate=upload_certificate)
151169
if file_url is None:
152170
raise UploadFileException('Uploading file: %s failed' %
153171
content)
154-
return True, file_url
172+
return True, file_url, cert
155173
else:
156174
raise InvalidInput('The file: %s is not exists!' % file_path)
157175
elif content.startswith('oss://'):
158-
return True, content
176+
return True, content, upload_certificate
159177
elif not content.startswith('http'):
160178
content = os.path.expanduser(content)
161179
if os.path.isfile(content):
162-
file_url = OssUtils.upload(model=model,
163-
file_path=content,
164-
api_key=api_key)
180+
file_url, cert = OssUtils.upload(model=model,
181+
file_path=content,
182+
api_key=api_key,
183+
upload_certificate=upload_certificate)
165184
if file_url is None:
166185
raise UploadFileException('Uploading file: %s failed' %
167186
content)
168-
return True, file_url
169-
return False, content
187+
return True, file_url, cert
188+
return False, content, upload_certificate
189+
190+
191+
def check_and_upload(model, elem: dict, api_key,
192+
upload_certificate: dict = None):
193+
"""Check and upload files in element.
170194
195+
Args:
196+
model: Model name
197+
elem: Element dict containing file references
198+
api_key: API key
199+
upload_certificate: Optional upload certificate to reuse
171200
172-
def check_and_upload(model, elem: dict, api_key):
201+
Returns:
202+
tuple: (has_upload, upload_certificate) where has_upload is bool
203+
indicating if any file was uploaded, and upload_certificate
204+
is the certificate (newly obtained or passed in)
205+
"""
173206
has_upload = False
207+
obtained_certificate = upload_certificate
208+
174209
for key, content in elem.items():
175210
# support video:[images] for qwen2-vl
176211
is_list = isinstance(content, list)
177212
contents = content if is_list else [content]
178213

179214
if key in ['image', 'video', 'audio', 'text']:
180215
for i, content in enumerate(contents):
181-
is_upload, file_url = check_and_upload_local(
182-
model, content, api_key)
216+
is_upload, file_url, obtained_certificate = check_and_upload_local(
217+
model, content, api_key, obtained_certificate)
183218
if is_upload:
184219
contents[i] = file_url
185220
has_upload = True
186221
elem[key] = contents if is_list else contents[0]
187222

188-
return has_upload
223+
return has_upload, obtained_certificate
224+
225+
226+
def preprocess_message_element(model: str, elem: dict, api_key: str,
227+
upload_certificate: dict = None):
228+
"""Preprocess message element and upload files if needed.
189229
230+
Args:
231+
model: Model name
232+
elem: Element dict containing file references
233+
api_key: API key
234+
upload_certificate: Optional upload certificate to reuse
190235
191-
def preprocess_message_element(model: str, elem: dict, api_key: str):
192-
is_upload = check_and_upload(model, elem, api_key)
193-
return is_upload
236+
Returns:
237+
tuple: (is_upload, upload_certificate) where is_upload is bool
238+
indicating if any file was uploaded, and upload_certificate
239+
is the certificate (newly obtained or passed in)
240+
"""
241+
is_upload, cert = check_and_upload(model, elem, api_key,
242+
upload_certificate)
243+
return is_upload, cert

0 commit comments

Comments
 (0)