801 lines
31 KiB
Python
801 lines
31 KiB
Python
import time
|
||
from http import HTTPStatus
|
||
from typing import List, Union
|
||
|
||
import dashscope
|
||
import requests
|
||
from dashscope.api_entities.api_request_factory import _build_api_request
|
||
from dashscope.api_entities.dashscope_response import DashScopeAPIResponse
|
||
from dashscope.common.api_key import get_default_api_key
|
||
from dashscope.common.constants import (DEFAULT_REQUEST_TIMEOUT_SECONDS,
|
||
REPEATABLE_STATUS,
|
||
REQUEST_TIMEOUT_KEYWORD,
|
||
SSE_CONTENT_TYPE, TaskStatus)
|
||
from dashscope.common.error import InvalidParameter, InvalidTask, ModelRequired
|
||
from dashscope.common.logging import logger
|
||
from dashscope.common.utils import (_handle_http_failed_response,
|
||
_handle_http_response, default_headers,
|
||
join_url)
|
||
|
||
|
||
def _normalization_url(*args):
|
||
url = dashscope.base_http_api_url
|
||
return join_url(url, *args)
|
||
|
||
|
||
class BaseAioApi():
|
||
"""BaseApi, internal use only.
|
||
|
||
"""
|
||
@classmethod
|
||
def _validate_params(cls, api_key, model):
|
||
if api_key is None:
|
||
api_key = get_default_api_key()
|
||
if model is None or not model:
|
||
raise ModelRequired('Model is required!')
|
||
return api_key, model
|
||
|
||
@classmethod
|
||
def aio_call(cls,
|
||
model: str,
|
||
input: object,
|
||
task_group: str,
|
||
task: str = None,
|
||
function: str = None,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Call service and get result.
|
||
|
||
Args:
|
||
model (str): The requested model, such as gpt3-v2
|
||
input (object): The api input data, cannot be None.
|
||
task_group (str, optional): The api task group.
|
||
task (str, optional): The task name. Defaults to None.
|
||
function (str, optional): The function of the task.
|
||
Defaults to None.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
api_protocol (str, optional): Api protocol websocket or http.
|
||
Defaults to None.
|
||
ws_stream_mode (str, optional): websocket stream mode,
|
||
[none, in, out, duplex]. Defaults to out.
|
||
is_binary_input (bool, optional): Is input data binary.
|
||
Defaults to False.
|
||
http_method (str, optional): If api protocol is http, specifies
|
||
method[GET, POST]. Defaults to POST.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The service response.
|
||
"""
|
||
api_key, model = BaseAioApi._validate_params(api_key, model)
|
||
request = _build_api_request(model=model,
|
||
input=input,
|
||
task_group=task_group,
|
||
task=task,
|
||
function=function,
|
||
api_key=api_key,
|
||
**kwargs)
|
||
# call request service.
|
||
return request.aio_call()
|
||
|
||
|
||
class BaseApi():
|
||
"""BaseApi, internal use only.
|
||
|
||
"""
|
||
@classmethod
|
||
def _validate_params(cls, api_key, model):
|
||
if api_key is None:
|
||
api_key = get_default_api_key()
|
||
if model is None or not model:
|
||
raise ModelRequired('Model is required!')
|
||
return api_key, model
|
||
|
||
@classmethod
|
||
def call(cls,
|
||
model: str,
|
||
input: object,
|
||
task_group: str,
|
||
task: str = None,
|
||
function: str = None,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Call service and get result.
|
||
|
||
Args:
|
||
model (str): The requested model, such as gpt3-v2
|
||
input (object): The api input data, cannot be None.
|
||
task_group (str, optional): The api task group.
|
||
task (str, optional): The task name. Defaults to None.
|
||
function (str, optional): The function of the task.
|
||
Defaults to None.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
api_protocol (str, optional): Api protocol websocket or http.
|
||
Defaults to None.
|
||
ws_stream_mode (str, optional): websocket stream mode,
|
||
[none, in, out, duplex]. Defaults to out.
|
||
is_binary_input (bool, optional): Is input data binary.
|
||
Defaults to False.
|
||
http_method (str, optional): If api protocol is http, specifies
|
||
method[GET, POST]. Defaults to POST.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The service response.
|
||
"""
|
||
api_key, model = BaseApi._validate_params(api_key, model)
|
||
request = _build_api_request(model=model,
|
||
input=input,
|
||
task_group=task_group,
|
||
task=task,
|
||
function=function,
|
||
api_key=api_key,
|
||
**kwargs)
|
||
# call request service.
|
||
return request.call()
|
||
|
||
|
||
class AsyncTaskGetMixin():
|
||
@classmethod
|
||
def _get(cls, task_id: str, api_key: str = None) -> DashScopeAPIResponse:
|
||
status_url = _normalization_url('tasks', task_id)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % status_url)
|
||
response = session.get(status_url,
|
||
headers={
|
||
**default_headers(api_key),
|
||
},
|
||
timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
logger.debug('Starting processing response: %s' % status_url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class BaseAsyncApi(AsyncTaskGetMixin):
|
||
"""BaseAsyncApi,for async task, internal use only.
|
||
|
||
"""
|
||
@classmethod
|
||
def _validate_params(cls, api_key, model):
|
||
if api_key is None:
|
||
api_key = get_default_api_key()
|
||
if model is None or not model:
|
||
raise ModelRequired('Model is required!')
|
||
return api_key, model
|
||
|
||
@classmethod
|
||
def call(cls, *args, api_key: None, **kwargs) -> DashScopeAPIResponse:
|
||
"""Call service and get result.
|
||
"""
|
||
task_response = cls.async_call(*args, api_key=api_key, **kwargs)
|
||
response = cls.wait(task_response, api_key=api_key)
|
||
return response
|
||
|
||
@classmethod
|
||
def _get_task_id(cls, task):
|
||
if isinstance(task, str):
|
||
task_id = task
|
||
elif isinstance(task, DashScopeAPIResponse):
|
||
if task.status_code == HTTPStatus.OK:
|
||
task_id = task.output['task_id']
|
||
else:
|
||
raise InvalidTask('Invalid task, task create failed: %s' %
|
||
task)
|
||
else:
|
||
raise InvalidParameter('Task invalid!')
|
||
if task_id is None or task_id == '':
|
||
raise InvalidParameter('Task id required!')
|
||
return task_id
|
||
|
||
@classmethod
|
||
def cancel(
|
||
cls,
|
||
task: Union[str, DashScopeAPIResponse],
|
||
api_key: str = None,
|
||
) -> DashScopeAPIResponse:
|
||
"""Cancel PENDING task.
|
||
|
||
Args:
|
||
task (Union[str, DashScopeAPIResponse]): The task_id, or
|
||
async_call response.
|
||
api_key (str, optional): The api-key. Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The cancel result.
|
||
"""
|
||
task_id = cls._get_task_id(task)
|
||
url = _normalization_url('tasks', task_id, 'cancel')
|
||
with requests.Session() as session:
|
||
response = session.post(url,
|
||
headers={
|
||
**default_headers(api_key),
|
||
})
|
||
return _handle_http_response(response)
|
||
|
||
@classmethod
|
||
def list(cls,
|
||
start_time: str = None,
|
||
end_time: str = None,
|
||
model_name: str = None,
|
||
api_key_id: str = None,
|
||
region: str = None,
|
||
status: str = None,
|
||
page_no: int = 1,
|
||
page_size: int = 10,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""List async tasks.
|
||
|
||
Args:
|
||
start_time (str, optional): The tasks start time,
|
||
for example: 20230420000000. Defaults to None.
|
||
end_time (str, optional): The tasks end time,
|
||
for example: 20230420000000. Defaults to None.
|
||
model_name (str, optional): The tasks model name.
|
||
Defaults to None.
|
||
api_key_id (str, optional): The tasks api-key-id.
|
||
Defaults to None.
|
||
region (str, optional): The service region,
|
||
for example: cn-beijing. Defaults to None.
|
||
status (str, optional): The status of tasks[PENDING,
|
||
RUNNING, SUCCEEDED, FAILED, CANCELED]. Defaults to None.
|
||
page_no (int, optional): The page number. Defaults to 1.
|
||
page_size (int, optional): The page size. Defaults to 10.
|
||
api_key (str, optional): The user api-key. Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The response data.
|
||
"""
|
||
url = _normalization_url('tasks')
|
||
params = {'page_no': page_no, 'page_size': page_size}
|
||
if start_time is not None:
|
||
params['start_time'] = start_time
|
||
if end_time is not None:
|
||
params['end_time'] = end_time
|
||
if model_name is not None:
|
||
params['model_name'] = model_name
|
||
if api_key_id is not None:
|
||
params['api_key_id'] = api_key_id
|
||
if region is not None:
|
||
params['region'] = region
|
||
if status is not None:
|
||
params['status'] = status
|
||
|
||
with requests.Session() as session:
|
||
response = session.get(url,
|
||
params=params,
|
||
headers={
|
||
**default_headers(api_key),
|
||
})
|
||
if response.status_code == HTTPStatus.OK:
|
||
json_content = response.json()
|
||
request_id = ''
|
||
if 'request_id' in json_content:
|
||
request_id = json_content['request_id']
|
||
json_content.pop('request_id')
|
||
return DashScopeAPIResponse(request_id=request_id,
|
||
status_code=response.status_code,
|
||
code=None,
|
||
output=json_content,
|
||
usage=None,
|
||
message='')
|
||
else:
|
||
return _handle_http_failed_response(response)
|
||
|
||
@classmethod
|
||
def fetch(
|
||
cls,
|
||
task: Union[str, DashScopeAPIResponse],
|
||
api_key: str = None,
|
||
) -> DashScopeAPIResponse:
|
||
"""Query async task status.
|
||
|
||
Args:
|
||
task (Union[str, DashScopeAPIResponse]): The task_id, or
|
||
async_call response.
|
||
api_key (str, optional): The api_key. Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The async task information.
|
||
"""
|
||
task_id = cls._get_task_id(task)
|
||
return cls._get(task_id, api_key)
|
||
|
||
@classmethod
|
||
def wait(cls,
|
||
task: Union[str, DashScopeAPIResponse],
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Wait for async task completion and return task result.
|
||
|
||
Args:
|
||
task (Union[str, DashScopeAPIResponse]): The task_id, or
|
||
async_call response.
|
||
api_key (str, optional): The api_key. Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The async task information.
|
||
"""
|
||
task_id = cls._get_task_id(task)
|
||
wait_seconds = 1
|
||
max_wait_seconds = 5
|
||
increment_steps = 3
|
||
step = 0
|
||
while True:
|
||
step += 1
|
||
# we start by querying once every second, and double
|
||
# the query interval after every 3(increment_steps)
|
||
# intervals, until we hit the max waiting interval
|
||
# of 5(seconds)
|
||
# TODO: investigate if we can use long-poll
|
||
# (server side return immediately when ready)
|
||
if wait_seconds < max_wait_seconds and step % increment_steps == 0:
|
||
wait_seconds = min(wait_seconds * 2, max_wait_seconds)
|
||
rsp = cls._get(task_id, api_key)
|
||
if rsp.status_code == HTTPStatus.OK:
|
||
if rsp.output is None:
|
||
return rsp
|
||
|
||
task_status = rsp.output['task_status']
|
||
if task_status in [
|
||
TaskStatus.FAILED, TaskStatus.CANCELED,
|
||
TaskStatus.SUCCEEDED, TaskStatus.UNKNOWN
|
||
]:
|
||
return rsp
|
||
else:
|
||
logger.info('The task %s is %s' % (task_id, task_status))
|
||
time.sleep(wait_seconds)
|
||
elif rsp.status_code in REPEATABLE_STATUS:
|
||
logger.warn(
|
||
('Get task: %s temporary failure, \
|
||
status_code: %s, code: %s message: %s, will try again.'
|
||
) % (task_id, rsp.status_code, rsp.code, rsp.message))
|
||
time.sleep(wait_seconds)
|
||
else:
|
||
return rsp
|
||
|
||
@classmethod
|
||
def async_call(cls,
|
||
model: str,
|
||
input: object,
|
||
task_group: str,
|
||
task: str = None,
|
||
function: str = None,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Call async service return async task information.
|
||
|
||
Args:
|
||
model (str): The requested model, such as gpt3-v2
|
||
input (object): The api input data, cannot be None.
|
||
task_group (str, optional): The api task group.
|
||
task (str, optional): The task name. Defaults to None.
|
||
function (str, optional): The function of the task.
|
||
Defaults to None.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The async task information,
|
||
which contains the task id, you can use the task id
|
||
to query the task status.
|
||
"""
|
||
is_stream = kwargs.pop('stream', None) # async api not support stream.
|
||
if is_stream:
|
||
logger.warn('async_call do not support stream argument')
|
||
api_key, model = BaseApi._validate_params(api_key, model)
|
||
request = _build_api_request(model=model,
|
||
input=input,
|
||
task_group=task_group,
|
||
task=task,
|
||
function=function,
|
||
api_key=api_key,
|
||
async_request=True,
|
||
query=False,
|
||
**kwargs)
|
||
return request.call()
|
||
|
||
|
||
def _get(url, params={}, api_key=None, **kwargs) -> DashScopeAPIResponse:
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.get(url,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
params=params,
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class ListMixin():
|
||
@classmethod
|
||
def list(cls,
|
||
page_no=1,
|
||
page_size=10,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""list objects
|
||
|
||
Args:
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
page_no (int, optional): Page number. Defaults to 1.
|
||
page_size (int, optional): Items per page. Defaults to 10.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The object list in output.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower())
|
||
params = {'page_no': page_no, 'page_size': page_size}
|
||
return _get(url, params=params, api_key=api_key, **kwargs)
|
||
|
||
|
||
class LogMixin():
|
||
@classmethod
|
||
def logs(cls,
|
||
job_id: str,
|
||
offset=1,
|
||
line=1000,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Get log of the job.
|
||
|
||
Args:
|
||
job_id (str): The job id(used for fine-tune)
|
||
offset (int, optional): start log line. Defaults to 1.
|
||
line (int, optional): total line return. Defaults to 1000.
|
||
api_key (str, optional): The api key. Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The response
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
job_id, 'logs')
|
||
params = {'offset': offset, 'line': line}
|
||
return _get(url, params=params, api_key=api_key, **kwargs)
|
||
|
||
|
||
class GetMixin():
|
||
@classmethod
|
||
def get(cls,
|
||
target,
|
||
api_key: str = None,
|
||
params: dict = {},
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Get object information.
|
||
|
||
Args:
|
||
target (str): The target to get, such as model_id.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The object information in output.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target)
|
||
return _get(url, api_key=api_key, params=params, **kwargs)
|
||
|
||
|
||
class GetStatusMixin():
|
||
@classmethod
|
||
def get(cls,
|
||
target,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Get object information.
|
||
|
||
Args:
|
||
target (str): The target to get, such as model_id.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The object information in output.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target)
|
||
return _get(url, api_key, **kwargs)
|
||
|
||
|
||
class DeleteMixin():
|
||
@classmethod
|
||
def delete(cls,
|
||
target: str,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Delete object.
|
||
|
||
Args:
|
||
target (str): The object to delete, .
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The delete result.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target)
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.delete(url,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class CreateMixin():
|
||
@classmethod
|
||
def call(cls,
|
||
data: object,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Create a object
|
||
|
||
Args:
|
||
data (object): The create request json body.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The created object in output.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower())
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.post(url,
|
||
json=data,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class UpdateMixin():
|
||
@classmethod
|
||
def update(cls,
|
||
target: str,
|
||
json: object,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Async update a object
|
||
|
||
Args:
|
||
target (str): The target to update.
|
||
json (object): The create request json body.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The updated object information in output.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target)
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.patch(url,
|
||
json=json,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class PutMixin():
|
||
@classmethod
|
||
def put(cls,
|
||
target: str,
|
||
json: object,
|
||
extra_path: str = None,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Async update a object
|
||
|
||
Args:
|
||
target (str): The target to update.
|
||
json (object): The create request json body.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The updated object information in output.
|
||
"""
|
||
if extra_path is None:
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target)
|
||
else:
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target, extra_path)
|
||
print(url)
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.put(url,
|
||
json=json,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class FileUploadMixin():
|
||
@classmethod
|
||
def upload(cls,
|
||
files: list,
|
||
descriptions: List[str] = None,
|
||
params: dict = None,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Upload files
|
||
|
||
Args:
|
||
files (list): List of (name, opened file, file_name).
|
||
descriptions (list[str]): The file description messages.
|
||
params (dict): The parameters
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The uploaded file information in the output.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower())
|
||
js = None
|
||
if descriptions:
|
||
js = {'descriptions': descriptions}
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.post(url,
|
||
data=js,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
files=files,
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class CancelMixin():
|
||
@classmethod
|
||
def cancel(cls,
|
||
target: str,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Cancel a job.
|
||
|
||
Args:
|
||
target (str): The request params, key/value map.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The cancel result.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target, 'cancel')
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.post(url,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
return _handle_http_response(response)
|
||
|
||
|
||
class StreamEventMixin():
|
||
@classmethod
|
||
def _handle_stream(cls, response: requests.Response):
|
||
# TODO define done message.
|
||
is_error = False
|
||
status_code = HTTPStatus.INTERNAL_SERVER_ERROR
|
||
for line in response.iter_lines():
|
||
if line:
|
||
line = line.decode('utf8')
|
||
line = line.rstrip('\n').rstrip('\r')
|
||
if line.startswith('event:error'):
|
||
is_error = True
|
||
elif line.startswith('status:'):
|
||
status_code = line[len('status:'):]
|
||
status_code = int(status_code.strip())
|
||
elif line.startswith('data:'):
|
||
line = line[len('data:'):]
|
||
yield (is_error, status_code, line)
|
||
if is_error:
|
||
break
|
||
else:
|
||
continue # ignore heartbeat...
|
||
|
||
@classmethod
|
||
def _handle_response(cls, response: requests.Response):
|
||
request_id = ''
|
||
if (response.status_code == HTTPStatus.OK
|
||
and SSE_CONTENT_TYPE in response.headers.get(
|
||
'content-type', '')):
|
||
for is_error, status_code, data in cls._handle_stream(response):
|
||
if is_error:
|
||
yield DashScopeAPIResponse(request_id=request_id,
|
||
status_code=status_code,
|
||
output=None,
|
||
code='',
|
||
message='') # noqa E501
|
||
else:
|
||
yield DashScopeAPIResponse(request_id=request_id,
|
||
status_code=HTTPStatus.OK,
|
||
output=data,
|
||
usage=None)
|
||
elif response.status_code == HTTPStatus.OK:
|
||
json_content = response.json()
|
||
request_id = ''
|
||
if 'request_id' in json_content:
|
||
request_id = json_content['request_id']
|
||
yield DashScopeAPIResponse(request_id=request_id,
|
||
status_code=HTTPStatus.OK,
|
||
output=json_content,
|
||
usage=None)
|
||
else:
|
||
_handle_http_failed_response(response)
|
||
|
||
@classmethod
|
||
def stream_events(cls,
|
||
target,
|
||
api_key: str = None,
|
||
**kwargs) -> DashScopeAPIResponse:
|
||
"""Get job log.
|
||
|
||
Args:
|
||
target (str): The target to get, such as model_id.
|
||
api_key (str, optional): The api api_key, if not present,
|
||
will get by default rule(TODO: api key doc). Defaults to None.
|
||
|
||
Returns:
|
||
DashScopeAPIResponse: The target outputs.
|
||
"""
|
||
url = join_url(dashscope.base_http_api_url, cls.SUB_PATH.lower(),
|
||
target, 'stream')
|
||
timeout = kwargs.pop(REQUEST_TIMEOUT_KEYWORD,
|
||
DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||
with requests.Session() as session:
|
||
logger.debug('Starting request: %s' % url)
|
||
response = session.get(url,
|
||
headers={
|
||
**default_headers(api_key),
|
||
**kwargs.pop('headers', {})
|
||
},
|
||
stream=True,
|
||
timeout=timeout)
|
||
logger.debug('Starting processing response: %s' % url)
|
||
for rsp in cls._handle_response(response):
|
||
yield rsp
|