chore: 添加虚拟环境到仓库

- 添加 backend_service/venv 虚拟环境
- 包含所有Python依赖包
- 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
2025-12-03 10:19:25 +08:00
parent a6c2027caa
commit c4f851d387
12655 changed files with 3009376 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
# yapf: disable
from dashscope.threads.messages.messages import Messages
from dashscope.threads.runs.runs import Runs
from dashscope.threads.runs.steps import Steps
from dashscope.threads.thread_types import (MessageFile, Run, RunList, RunStep,
RunStepList, Thread, ThreadMessage,
ThreadMessageList)
from dashscope.threads.threads import Threads
__all__ = [
MessageFile,
Messages,
Run,
Runs,
RunList,
Steps,
RunStep,
RunStepList,
Threads,
Thread,
ThreadMessage,
ThreadMessageList,
]

View File

@@ -0,0 +1,113 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
from dashscope.client.base_api import GetStatusMixin, ListObjectMixin
from dashscope.common.error import InputRequired
from dashscope.threads.thread_types import MessageFile, MessageFileList
__all__ = ['Files']
class Files(ListObjectMixin, GetStatusMixin):
SUB_PATH = 'messages' # useless
@classmethod
def retrieve(cls,
file_id: str,
*,
thread_id: str,
message_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> MessageFile:
"""Retrieve the `MessageFile`.
Args:
thread_id (str): The thread id.
message_id (str): The message id.
file_id (str): The file id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
MessageFile: The `MessageFile` object.
"""
return cls.get(file_id,
thread_id=thread_id,
message_id=message_id,
workspace=workspace,
api_key=api_key,
**kwargs)
@classmethod
def get(cls,
file_id: str,
*,
message_id: str,
thread_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> MessageFile:
"""Retrieve the `MessageFile`.
Args:
assistant_id (str): The assistant id.
message_id (str): The message id.
file_id (str): The file id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
MessageFile: The `MessageFile` object.
"""
if not thread_id or not message_id or not file_id:
raise InputRequired(
'thread id, message id and file id are required!')
response = super().get(
message_id,
path=f'threads/{thread_id}/messages/{message_id}/files/{file_id}',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return MessageFile(**response)
@classmethod
def list(cls,
message_id: str,
*,
thread_id: str,
limit: int = None,
order: str = None,
after: str = None,
before: str = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> MessageFileList:
"""List message files.
Args:
thread_id (str): The thread id.
message_id (str): The message_id.
limit (int, optional): How many assistant to retrieve. Defaults to None.
order (str, optional): Sort order by created_at. Defaults to None.
after (str, optional): Assistant id after. Defaults to None.
before (str, optional): Assistant id before. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
MessageFileList: The `MessageFileList`.
"""
if not thread_id or not message_id:
raise InputRequired('thread id, message id are required!')
response = super().list(
limit=limit,
order=order,
after=after,
before=before,
path=f'threads/{thread_id}/messages/{message_id}/files',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return MessageFileList(**response)

View File

@@ -0,0 +1,220 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
from typing import Dict, List, Optional
from dashscope.client.base_api import (CreateMixin, GetStatusMixin,
ListObjectMixin, UpdateMixin)
from dashscope.common.error import InputRequired
from dashscope.threads.thread_types import ThreadMessage, ThreadMessageList
__all__ = ['Messages']
class Messages(CreateMixin, ListObjectMixin, GetStatusMixin, UpdateMixin):
SUB_PATH = 'messages' # useless
@classmethod
def call(cls,
thread_id: str,
*,
content: str,
role: str = 'user',
file_ids: List[str] = [],
metadata: Optional[object] = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> ThreadMessage:
"""Create message of thread.
Args:
thread_id (str): The thread id.
content (str): The message content.
role (str, optional): The message role. Defaults to 'user'.
file_ids (List[str], optional): The file_ids include in message. Defaults to [].
metadata (Optional[object], optional): The custom key/value pairs. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): The DashScope api key. Defaults to None.
Returns:
ThreadMessage: The `ThreadMessage` object.
"""
return cls.create(thread_id,
content=content,
role=role,
file_ids=file_ids,
metadata=metadata,
workspace=workspace,
**kwargs)
@classmethod
def create(cls,
thread_id: str,
*,
content: str,
role: str = 'user',
file_ids: List[str] = [],
metadata: Optional[object] = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> ThreadMessage:
"""Create message of thread.
Args:
thread_id (str): The thread id.
content (str): The message content.
role (str, optional): The message role. Defaults to 'user'.
file_ids (List[str], optional): The file_ids include in message. Defaults to [].
metadata (Optional[object], optional): The custom key/value pairs. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): The DashScope api key. Defaults to None.
Returns:
ThreadMessage: The `ThreadMessage` object.
"""
cls.SUB_PATH = '%s/messages' % thread_id
data = {}
if not thread_id or not content:
raise InputRequired('thread_id and content are required!')
data['content'] = content
data['role'] = role
if metadata:
data['metadata'] = metadata
if file_ids:
data['file_ids'] = file_ids
response = super().call(data=data,
path=f'threads/{thread_id}/messages',
api_key=api_key,
flattened_output=True,
workspace=workspace,
**kwargs)
return ThreadMessage(**response)
@classmethod
def retrieve(cls,
message_id: str,
*,
thread_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> ThreadMessage:
"""Get the `ThreadMessage`.
Args:
thread_id (str): The thread id.
message_id (str): The message id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
ThreadMessage: The `ThreadMessage` object.
"""
return cls.get(message_id,
thread_id=thread_id,
workspace=workspace,
api_key=api_key,
**kwargs)
@classmethod
def get(cls,
message_id: str,
*,
thread_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> ThreadMessage:
"""Get the `ThreadMessage`.
Args:
thread_id (str): The thread id.
message_id (str): The message id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
ThreadMessage: The `ThreadMessage` object.
"""
if not message_id or not thread_id:
raise InputRequired('thread id, message id are required!')
response = super().get(
message_id,
path=f'threads/{thread_id}/messages/{message_id}',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return ThreadMessage(**response)
@classmethod
def list(cls,
thread_id: str,
*,
limit: int = None,
order: str = None,
after: str = None,
before: str = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> ThreadMessageList:
"""List message of the thread.
Args:
thread_id (str): The thread id.
limit (int, optional): How many assistant to retrieve. Defaults to None.
order (str, optional): Sort order by created_at. Defaults to None.
after (str, optional): Assistant id after. Defaults to None.
before (str, optional): Assistant id before. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
ThreadMessageList: The `ThreadMessageList` object.
"""
if not thread_id:
raise InputRequired('thread id is required!')
response = super().list(limit=limit,
order=order,
after=after,
before=before,
path=f'threads/{thread_id}/messages',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return ThreadMessageList(**response)
@classmethod
def update(cls,
message_id: str,
*,
thread_id: str,
metadata: Dict = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> ThreadMessage:
"""Update an message of the thread.
Args:
thread_id (str): The thread id.
message_id (str): The message id.
content (str): The message content.
role (str, optional): The message role. Defaults to 'user'.
file_ids (List[str], optional): The file_ids include in message. Defaults to [].
metadata (Optional[object], optional): The custom key/value pairs. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): The DashScope api key. Defaults to None.
Returns:
ThreadMessage: The `ThreadMessage` object.
"""
if not thread_id or not message_id:
raise InputRequired('thread id and message id are required!')
response = super().update(target=message_id,
json={'metadata': metadata},
path='threads/%s/messages/%s' %
(thread_id, message_id),
api_key=api_key,
workspace=workspace,
flattened_output=True,
method='post',
**kwargs)
return ThreadMessage(**response)

View File

@@ -0,0 +1,501 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
import time
from http import HTTPStatus
from typing import Dict, List, Optional
from dashscope.client.base_api import (CancelMixin, CreateMixin,
GetStatusMixin, ListObjectMixin,
UpdateMixin)
from dashscope.common.error import (AssistantError, InputRequired,
TimeoutException)
from dashscope.common.logging import logger
from dashscope.threads.thread_types import (Run, RunList, RunStep,
RunStepDelta, Thread,
ThreadMessage, ThreadMessageDelta)
__all__ = ['Runs']
class Runs(CreateMixin, CancelMixin, ListObjectMixin, GetStatusMixin,
UpdateMixin):
SUB_PATH = 'RUNS' # useless
@classmethod
def create_thread_and_run(cls,
*,
assistant_id: str,
thread: Optional[Dict] = None,
model: Optional[str] = None,
instructions: Optional[str] = None,
additional_instructions: Optional[str] = None,
tools: Optional[List[Dict]] = None,
stream: Optional[bool] = False,
metadata: Optional[Dict] = None,
workspace: str = None,
extra_body: Optional[Dict] = None,
api_key: str = None,
**kwargs) -> Run:
if not assistant_id:
raise InputRequired('assistant_id is required')
data = {'assistant_id': assistant_id}
if thread:
data['thread'] = thread
if model:
data['model'] = model
if instructions:
data['instructions'] = instructions
if additional_instructions:
data['additional_instructions'] = additional_instructions
if tools:
data['tools'] = tools
if metadata:
data['metadata'] = metadata
data['stream'] = stream
if extra_body is not None and extra_body:
data = {**data, **extra_body}
response = super().call(data=data,
path='threads/runs',
api_key=api_key,
flattened_output=True,
stream=stream,
workspace=workspace,
**kwargs)
if stream:
return ((event_type, cls.convert_stream_object(event_type, item))
for event_type, item in response)
else:
return Run(**response)
@classmethod
def create(cls,
thread_id: str,
*,
assistant_id: str,
model: Optional[str] = None,
instructions: Optional[str] = None,
additional_instructions: Optional[str] = None,
tools: Optional[List[Dict]] = None,
metadata: Optional[Dict] = None,
stream: Optional[bool] = False,
workspace: str = None,
extra_body: Optional[Dict] = None,
api_key: str = None,
top_p: Optional[float] = None,
top_k: Optional[int] = None,
temperature: Optional[float] = None,
max_tokens: Optional[int] = None,
**kwargs) -> Run:
"""Create a run.
Args:
thread_id (str): The thread to run.
assistant_id (str): The assistant id to run.
model (str): The model to use.
instructions (str, optional): The system instructions this assistant uses. Defaults to None.
additional_instructions (Optional[str], optional): Appends additional
instructions at the end of the instructions for the run. This is
useful for modifying the behavior on a per-run basis without
overriding other instructions.. Defaults to None.
tools (Optional[str], optional): List of tools to use.. Defaults to [].
metadata (Dict, optional): Custom key-value pairs associate with run. Defaults to None.
workspace (str): The DashScope workspace id.
api_key (str, optional): The DashScope workspace id. Defaults to None.
Raises:
InputRequired: thread and assistant is required.
Returns:
Run: The `Run` object.
"""
if not thread_id or not assistant_id:
raise InputRequired('thread_id and assistant_id is required')
data = {'assistant_id': assistant_id}
if model:
data['model'] = model
if instructions:
data['instructions'] = instructions
if additional_instructions:
data['additional_instructions'] = additional_instructions
if tools:
data['tools'] = tools
if metadata:
data['metadata'] = metadata
data['stream'] = stream
if extra_body is not None and extra_body:
data = {**data, **extra_body}
if top_p is not None:
data['top_p'] = top_p
if top_k is not None:
data['top_k'] = top_k
if temperature is not None:
data['temperature'] = temperature
if max_tokens is not None:
data['max_tokens'] = max_tokens
response = super().call(data=data,
path=f'threads/{thread_id}/runs',
api_key=api_key,
flattened_output=True,
stream=stream,
workspace=workspace,
**kwargs)
if stream:
return ((event_type, cls.convert_stream_object(event_type, item))
for event_type, item in response)
else:
return Run(**response)
@classmethod
def convert_stream_object(cls, event, item):
event_object_map = {
'thread.created': Thread,
'thread.run.created': Run,
'thread.run.queued': Run,
'thread.run.in_progress': Run,
'thread.run.requires_action': Run,
'thread.run.completed': Run,
'thread.run.failed': Run,
'thread.run.cancelled': Run,
'thread.run.expired': Run,
'thread.run.step.created': RunStep,
'thread.run.step.in_progress': RunStep,
'thread.run.step.delta': RunStepDelta,
'thread.run.step.completed': RunStep,
'thread.run.step.failed': RunStep,
'thread.run.step.cancelled': RunStep,
'thread.run.step.expired': RunStep,
'thread.message.created': ThreadMessage,
'thread.message.in_progress': ThreadMessage,
'thread.message.delta': ThreadMessageDelta,
'thread.message.completed': ThreadMessage,
'thread.message.incomplete': ThreadMessage,
'error': AssistantError,
}
if (event in event_object_map):
return event_object_map[event](**item)
else:
return item
@classmethod
def call(cls,
thread_id: str,
*,
assistant_id: str,
model: Optional[str] = None,
instructions: Optional[str] = None,
additional_instructions: Optional[str] = None,
tools: Optional[List[Dict]] = None,
stream: Optional[bool] = False,
metadata: Optional[Dict] = None,
workspace: str = None,
extra_body: Optional[Dict] = None,
api_key: str = None,
top_p: Optional[float] = None,
top_k: Optional[int] = None,
temperature: Optional[float] = None,
max_tokens: Optional[int] = None,
**kwargs) -> Run:
"""Create a run.
Args:
thread_id (str): The thread to run.
assistant_id (str): The assistant id to run.
model (str): The model to use.
instructions (str, optional): The system instructions this assistant uses. Defaults to None.
additional_instructions (Optional[str], optional): Appends additional
instructions at the end of the instructions for the run. This is
useful for modifying the behavior on a per-run basis without
overriding other instructions.. Defaults to None.
tools (Optional[str], optional): List of tools to use.. Defaults to [].
metadata (Dict, optional): Custom key-value pairs associate with run. Defaults to None.
workspace (str): The DashScope workspace id.
api_key (str, optional): The DashScope workspace id. Defaults to None.
Raises:
InputRequired: thread and assistant is required.
Returns:
Run: The `Run` object.
"""
return cls.create(thread_id,
assistant_id=assistant_id,
model=model,
instructions=instructions,
additional_instructions=additional_instructions,
tools=tools,
stream=stream,
metadata=metadata,
workspace=workspace,
extra_body=extra_body,
api_key=api_key,
top_p=top_p,
top_k=top_k,
temperature=temperature,
max_tokens=max_tokens,
**kwargs)
@classmethod
def list(cls,
thread_id: str,
*,
limit: int = None,
order: str = None,
after: str = None,
before: str = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> RunList:
"""List `Run`.
Args:
thread_id (str): The thread id.
limit (int, optional): How many assistant to retrieve. Defaults to None.
order (str, optional): Sort order by created_at. Defaults to None.
after (str, optional): Assistant id after. Defaults to None.
before (str, optional): Assistant id before. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
RunList: The list of runs.
"""
if not thread_id:
raise InputRequired('thread_id is required!')
response = super().list(limit=limit,
order=order,
after=after,
before=before,
path=f'threads/{thread_id}/runs',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return RunList(**response)
@classmethod
def retrieve(cls,
run_id: str,
*,
thread_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> Run:
"""Retrieve the `Run`.
Args:
thread_id (str): The thread id.
run_id (str): The run id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
Run: The `Run` object.
"""
if not thread_id or not run_id:
raise InputRequired('thread_id and run_id are required!')
response = super().get(run_id,
path=f'threads/{thread_id}/runs/{run_id}',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return Run(**response)
@classmethod
def get(cls,
run_id: str,
*,
thread_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> Run:
"""Retrieve the `Run`.
Args:
thread_id (str): The thread id.
run_id (str): The run id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
Run: The `Run` object.
"""
return cls.retrieve(run_id,
thread_id=thread_id,
workspace=workspace,
api_key=api_key,
**kwargs)
@classmethod
def submit_tool_outputs(cls,
run_id: str,
*,
thread_id: str,
tool_outputs: List[Dict],
stream: Optional[bool] = False,
workspace: str = None,
extra_body: Optional[Dict] = None,
api_key: str = None,
**kwargs) -> Run:
"""_summary_
Args:
thread_id (str): The thread id.
run_id (str): The run id.
tool_outputs (List[Dict]): The tool outputs.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Raises:
InputRequired: The tool output thread id run id
are required.
Returns:
Run: The 'Run`.
"""
if not tool_outputs:
raise InputRequired('tool_outputs is required!')
if not thread_id or not run_id:
raise InputRequired('thread_id and run_id are required!')
data = {'tool_outputs': tool_outputs}
data['stream'] = stream
if extra_body is not None and extra_body:
data = {**data, **extra_body}
response = super().call(
data,
path=f'threads/{thread_id}/runs/{run_id}/submit_tool_outputs',
workspace=workspace,
api_key=api_key,
stream=stream,
flattened_output=True,
**kwargs)
if stream:
return ((event_type, cls.convert_stream_object(event_type, item))
for event_type, item in response)
else:
return Run(**response)
@classmethod
def wait(cls,
run_id: str,
*,
thread_id: str,
timeout_seconds: float = float('inf'),
workspace: str = None,
api_key: str = None,
**kwargs) -> Run:
"""Wait for run to complete.
Args:
thread_id (str): The thread id.
run_id (str): The run id.
timeout_seconds (int): The timeout seconds. Defaults inf.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
Run: The run final status.
"""
if not run_id or not thread_id:
raise InputRequired('run_id and thread_id are required!')
start_time = time.perf_counter()
while True:
run = cls.get(run_id,
thread_id=thread_id,
workspace=workspace,
api_key=api_key)
if run.status_code == HTTPStatus.OK:
if hasattr(run, 'status'):
if run.status in [
'cancelled', 'failed', 'completed', 'expired',
'requires_action'
]:
break
else:
time_eclipsed = time.perf_counter() - start_time
if time_eclipsed > timeout_seconds:
raise TimeoutException('Wait run complete timeout')
time.sleep(1)
else:
logger.error('run has no status')
break
else:
logger.error(
'Get run thread_id: %s, run_id: %s failed, message: %s' %
(thread_id, run_id, run.message))
break
return run
@classmethod
def update(cls,
run_id: str,
*,
thread_id: str,
metadata: Optional[Dict] = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> Run:
"""Create a run.
Args:
thread_id (str): The thread of the run id to be updated.
run_id (str): The run id to update.
model (str): The model to use.
metadata (Dict, optional): Custom key-value pairs associate with run. Defaults to None.
workspace (str): The DashScope workspace id.
api_key (str, optional): The DashScope workspace id. Defaults to None.
Raises:
InputRequired: thread id and run is required.
Returns:
Run: The `Run` object.
"""
if not thread_id or not run_id:
raise InputRequired('thread id and run id are required!')
response = super().update(run_id,
json={'metadata': metadata},
path='threads/%s/runs/%s' %
(thread_id, run_id),
api_key=api_key,
workspace=workspace,
flattened_output=True,
method='post',
**kwargs)
return Run(**response)
@classmethod
def cancel(cls,
run_id: str,
*,
thread_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> Run:
"""Cancel the `Run`.
Args:
thread_id (str): The thread id.
run_id (str): The run id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
Run: The `Run` object.
"""
if not thread_id or not run_id:
raise InputRequired('thread id and run id are required!')
response = super().cancel(run_id,
path='threads/%s/runs/%s/cancel' %
(thread_id, run_id),
api_key=api_key,
workspace=workspace,
flattened_output=True,
**kwargs)
return Run(**response)

View File

@@ -0,0 +1,112 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
from dashscope.client.base_api import GetStatusMixin, ListObjectMixin
from dashscope.common.error import InputRequired
from dashscope.threads.thread_types import RunStep, RunStepList
__all__ = ['Steps']
class Steps(ListObjectMixin, GetStatusMixin):
SUB_PATH = 'RUNS' # useless
@classmethod
def list(cls,
run_id: str,
*,
thread_id: str,
limit: int = None,
order: str = None,
after: str = None,
before: str = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> RunStepList:
"""List `RunStep` of `Run`.
Args:
thread_id (str): The thread id.
run_id (str): The run id.
limit (int, optional): How many assistant to retrieve. Defaults to None.
order (str, optional): Sort order by created_at. Defaults to None.
after (str, optional): Assistant id after. Defaults to None.
before (str, optional): Assistant id before. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
RunList: The list of runs.
"""
if not run_id:
raise InputRequired('run_id is required!')
response = super().list(
limit=limit,
order=order,
after=after,
before=before,
path=f'threads/{thread_id}/runs/{run_id}/steps',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return RunStepList(**response)
@classmethod
def retrieve(cls,
step_id: str,
*,
thread_id: str,
run_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> RunStep:
"""Retrieve the `RunStep`.
Args:
thread_id (str): The thread id.
run_id (str): The run id.
step_id (str): The step id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
RunStep: The `RunStep` object.
"""
if not thread_id or not run_id or not step_id:
raise InputRequired('thread_id, run_id and step_id are required!')
response = super().get(
run_id,
path=f'threads/{thread_id}/runs/{run_id}/steps/{step_id}',
workspace=workspace,
api_key=api_key,
flattened_output=True,
**kwargs)
return RunStep(**response)
@classmethod
def get(cls,
step_id: str,
*,
thread_id: str,
run_id: str,
workspace: str = None,
api_key: str = None,
**kwargs) -> RunStep:
"""Retrieve the `RunStep`.
Args:
thread_id (str): The thread id.
run_id (str): The run id.
step_id (str): The step id.
workspace (str): The dashscope workspace id.
api_key (str, optional): The api key. Defaults to None.
Returns:
RunStep: The `RunStep` object.
"""
return cls.retrieve(thread_id,
run_id,
step_id,
workspace=workspace,
api_key=api_key,
**kwargs)

View File

@@ -0,0 +1,665 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
# adapter from openai sdk
# yapf: disable
from dataclasses import dataclass
from typing import Dict, List, Literal, Optional, Union
from dashscope.assistants.assistant_types import (
Tool, convert_tools_dict_to_objects)
from dashscope.common.base_type import BaseList, BaseObjectMixin
__all__ = [
'MessageFile', 'MessageFileList', 'Usage', 'ImageFile',
'MessageContentImageFile', 'Text', 'MessageContentText', 'ThreadMessage',
'ThreadMessageList', 'Thread', 'Function',
'RequiredActionFunctionToolCall', 'RequiredActionSubmitToolOutputs',
'RequiredAction', 'LastError', 'Run', 'RunList', 'MessageCreation',
'MessageCreationStepDetails', 'CodeInterpreterOutputLogs',
'CodeInterpreterOutputImageImage', 'CodeInterpreterOutputImage',
'CodeInterpreter', 'CodeToolCall', 'RetrievalToolCall', 'FunctionToolCall',
'ToolCallsStepDetails', 'RunStep', 'RunStepList'
]
@dataclass(init=False)
class MessageFile(BaseObjectMixin):
id: str
message_id: str
created_at: int
object: str
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class MessageFileList(BaseList):
data: List[MessageFile]
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class Usage(BaseObjectMixin):
completion_tokens: int
"""Number of completion tokens used over the course of the run."""
prompt_tokens: int
"""Number of prompt tokens used over the course of the run."""
total_tokens: int
"""Total number of tokens used (prompt + completion)."""
input_tokens: int
"""Input tokens used (prompt)."""
output_tokens: int
"""Output tokens used (completion)."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class ImageFile(BaseObjectMixin):
file_id: str
def __init__(self, file_id, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class MessageContentImageFile(BaseObjectMixin):
type: str = 'image_file'
image_file: ImageFile
def __init__(self, **kwargs):
self.image_file = ImageFile(**kwargs.pop(self.type, {}))
super().__init__(**kwargs)
TextAnnotation = Union[Dict]
@dataclass(init=False)
class Text(BaseObjectMixin):
annotations: List[TextAnnotation]
value: str
def __init__(self, **kwargs):
annotations = kwargs.pop('annotations', None)
if annotations:
self.annotations = []
for annotation in annotations:
self.annotations.append(annotation)
else:
self.annotations = annotations
super().__init__(**kwargs)
@dataclass(init=False)
class MessageContentText(BaseObjectMixin):
text: Text
type: str = 'text'
def __init__(self, **kwargs):
input_text = kwargs.pop('text', {})
if input_text:
self.text = Text(**input_text)
super().__init__(**kwargs)
MESSAGE_SUPPORT_CONTENT = {
'text': MessageContentText,
'image_file': MessageContentImageFile,
}
Content = Union[MessageContentImageFile, MessageContentText]
@dataclass(init=False)
class ThreadMessageDeltaContent(BaseObjectMixin):
content: Content
role: str
def __init__(self, **kwargs):
contents = kwargs.pop('content', None)
if contents:
for item in contents:
if item['type'] == 'text':
self.content = MessageContentText(**item)
elif item['type'] == 'image_file':
self.content = MessageContentImageFile(**item)
else:
self.content = item
else:
self.content = contents
super().__init__(**kwargs)
@dataclass(init=False)
class ThreadMessageDelta(BaseObjectMixin):
status_code: int
id: str
object: str = 'thread.message.delta'
delta: ThreadMessageDeltaContent
def __init__(self, **kwargs):
content = kwargs.pop('delta', None)
if content:
self.delta = ThreadMessageDeltaContent(**content)
else:
self.delta = None
super().__init__(**kwargs)
@dataclass(init=False)
class ThreadMessage(BaseObjectMixin):
status_code: int
id: str
created_at: int
thread_id: str
role: str
content: List[Content]
metadata: Optional[object] = None
object: str = 'thread.message'
assistant_id: Optional[str] = None
file_ids: List[str] = None
run_id: Optional[str] = None
def __init__(self, **kwargs):
input_content = kwargs.pop('content', None)
if input_content:
content_list = []
for content in input_content:
if 'type' in content:
content_type = MESSAGE_SUPPORT_CONTENT.get(
content['type'], None)
if content_type:
content_list.append(content_type(**content))
else:
content_list.append(content)
else:
content_list.append(content)
self.content = content_list
else:
self.content = input_content
super().__init__(**kwargs)
@dataclass(init=False)
class ThreadMessageList(BaseList):
data: List[ThreadMessage]
def __init__(self,
has_more: bool = None,
last_id: Optional[str] = None,
first_id: Optional[str] = None,
data: List[ThreadMessage] = [],
**kwargs):
super().__init__(has_more=has_more,
last_id=last_id,
first_id=first_id,
data=data,
**kwargs)
@dataclass(init=False)
class Thread(BaseObjectMixin):
status_code: int
id: str
created_at: int
metadata: Optional[object] = None
object: str = 'thread'
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class Function(BaseObjectMixin):
arguments: str
name: str
output: Optional[str] = None
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class RequiredActionFunctionToolCall(BaseObjectMixin):
id: str
function: Function
type: str = 'function'
def __init__(self, **kwargs):
self.function = Function(**kwargs.pop('function', {}))
super().__init__(**kwargs)
@dataclass(init=False)
class RequiredActionSubmitToolOutputs(BaseObjectMixin):
tool_calls: List[RequiredActionFunctionToolCall]
def __init__(self, **kwargs):
tcs = kwargs.pop('tool_calls', [])
if tcs:
self.tool_calls = []
for tc in tcs:
self.tool_calls.append(RequiredActionFunctionToolCall(**tc))
else:
self.tool_calls = tcs
super().__init__(**kwargs)
@dataclass(init=False)
class RequiredAction(BaseObjectMixin):
submit_tool_outputs: RequiredActionSubmitToolOutputs
type: Literal['submit_tool_outputs']
def __init__(self, **kwargs):
self.submit_tool_outputs = RequiredActionSubmitToolOutputs(
**kwargs.pop('submit_tool_outputs', {}))
super().__init__(**kwargs)
@dataclass(init=False)
class LastError(BaseObjectMixin):
code: Literal['server_error', 'rate_limit_exceeded']
message: str
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class Run(BaseObjectMixin):
status_code: int
id: str
assistant_id: str
cancelled_at: Optional[int] = None
completed_at: Optional[int] = None
created_at: int = None
expires_at: int = None
failed_at: Optional[int] = None
file_ids: List[str] = None
instructions: str = None
metadata: Optional[object] = None
last_error: Optional[LastError] = None
model: str = None
object: str = 'thread.run'
required_action: Optional[RequiredAction] = None
started_at: Optional[int] = None
status: Literal['queued', 'in_progress', 'requires_action', 'cancelling',
'cancelled', 'failed', 'completed', 'expired']
thread_id: str
tools: List[Tool]
top_p: Optional[float] = None
top_k: Optional[int] = None
temperature: Optional[float] = None
max_tokens: Optional[int] = None
usage: Optional[Usage] = None
def __init__(self, **kwargs):
self.tools = convert_tools_dict_to_objects(kwargs.pop('tools', []))
actions = kwargs.pop('required_action', None)
if actions:
self.required_action = RequiredAction(**actions)
else:
self.required_action = actions
super().__init__(**kwargs)
@dataclass(init=False)
class RunList(BaseObjectMixin):
data: List[Run]
def __init__(self,
has_more: bool = None,
last_id: Optional[str] = None,
first_id: Optional[str] = None,
data: List[Run] = [],
**kwargs):
super().__init__(has_more=has_more,
last_id=last_id,
first_id=first_id,
data=data,
**kwargs)
@dataclass(init=False)
class MessageCreation(BaseObjectMixin):
message_id: str
"""The ID of the message that was created by this run step."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class MessageCreationStepDetails(BaseObjectMixin):
message_creation: MessageCreation
type: Literal['message_creation']
"""Always `message_creation`."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class CodeInterpreterOutputLogs(BaseObjectMixin):
logs: str
"""The text output from the Code Interpreter tool call."""
type: Literal['logs']
"""Always `logs`."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class CodeInterpreterOutputImageImage(BaseObjectMixin):
file_id: str
"""
The [file](https://platform.openai.com/docs/api-reference/files) ID of the
image.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class CodeInterpreterOutputImage(BaseObjectMixin):
image: CodeInterpreterOutputImageImage
type: Literal['image']
"""Always `image`."""
def __init__(self, **kwargs):
self.image = CodeInterpreterOutputImageImage(**kwargs.pop('image', {}))
super().__init__(**kwargs)
CodeInterpreterOutput = Union[CodeInterpreterOutputLogs,
CodeInterpreterOutputImage]
@dataclass(init=False)
class CodeInterpreter(BaseObjectMixin):
input: str
"""The input to the Code Interpreter tool call."""
outputs: List[CodeInterpreterOutput]
"""The outputs from the Code Interpreter tool call.
Code Interpreter can output one or more items, including text (`logs`) or images
(`image`). Each of these are represented by a different object type.
"""
def __init__(self, **kwargs):
self.outputs = []
for output in kwargs.pop('outputs', []):
self.outputs.append(CodeInterpreterOutput(**output))
super().__init__(**kwargs)
@dataclass(init=False)
class CodeToolCall(BaseObjectMixin):
id: str
"""The ID of the tool call."""
code_interpreter: CodeInterpreter
"""The Code Interpreter tool call definition."""
type: Literal['code_interpreter']
"""The type of tool call.
This is always going to be `code_interpreter` for this type of tool call.
"""
def __init__(self, **kwargs):
self.code_interpreter = CodeInterpreter(
**kwargs.pop('code_interpreter', {}))
super().__init__(**kwargs)
@dataclass(init=False)
class RetrievalToolCall(BaseObjectMixin):
id: str
"""The ID of the tool call object."""
retrieval: object
"""For now, this is always going to be an empty object."""
type: Literal['quark_search']
"""The type of tool call.
This is always going to be `quark_search` for this type of tool call.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
@dataclass(init=False)
class FunctionToolCall(BaseObjectMixin):
id: str
"""The ID of the tool call object."""
function: Function
"""The definition of the function that was called."""
type: Literal['function']
"""The type of tool call.
This is always going to be `function` for this type of tool call.
"""
def __init__(self, **kwargs):
self.function = Function(**kwargs.pop('function', {}))
super().__init__(**kwargs)
ToolCall = Union[CodeToolCall, RetrievalToolCall, FunctionToolCall]
TOOL_CALL_TYPES = {
'function': FunctionToolCall,
'code_interpreter': CodeToolCall,
'retrieval': RetrievalToolCall,
}
def convert_tool_calls_dict_to_object(tool_calls):
tool_calls_object = []
for tool_call in tool_calls:
if 'type' in tool_call:
tool_call_type = TOOL_CALL_TYPES.get(tool_call['type'], None)
if tool_call_type:
tool_calls_object.append(tool_call_type(**tool_call))
else:
tool_calls_object.append(tool_call)
else:
tool_calls_object.append(tool_call)
return tool_calls_object
@dataclass(init=False)
class ToolCallsStepDetails(BaseObjectMixin):
tool_calls: List[ToolCall]
"""An array of tool calls the run step was involved in.
These can be associated with one of three types of tools: `code_interpreter`,
`retrieval`, or `function`.
"""
type: Literal['tool_calls']
"""Always `tool_calls`."""
def __init__(self, **kwargs):
self.tool_calls = convert_tool_calls_dict_to_object(
kwargs.pop('tool_calls', []))
super().__init__(**kwargs)
StepDetails = Union[MessageCreationStepDetails, ToolCallsStepDetails]
STEP_TYPES = {
'tool_calls': ToolCallsStepDetails,
'message_creation': MessageCreationStepDetails,
}
def convert_step_details_dict_to_objects(step_details):
if 'type' in step_details:
tool_type = STEP_TYPES.get(step_details['type'], None)
if tool_type:
return tool_type(**step_details)
return step_details
@dataclass(init=False)
class RunStepDeltaContent(BaseObjectMixin):
step_details: StepDetails
def __init__(self, **kwargs):
self.step_details = convert_step_details_dict_to_objects(
kwargs.pop('step_details', {}))
super().__init__(**kwargs)
@dataclass(init=False)
class RunStepDelta(BaseObjectMixin):
id: str
object: str = 'thread.run.step.delta'
delta: RunStepDeltaContent
def __init__(self, **kwargs):
delta = kwargs.pop('delta', None)
if delta:
self.delta = RunStepDeltaContent(**delta)
else:
self.delta = delta
super().__init__(**kwargs)
@dataclass(init=False)
class RunStep(BaseObjectMixin):
status_code: int = None
id: str
"""The identifier of the run step, which can be referenced in API endpoints."""
assistant_id: str
"""
The ID of the
[assistant](https://platform.openai.com/docs/api-reference/assistants)
associated with the run step.
"""
cancelled_at: Optional[int] = None
"""The Unix timestamp (in seconds) for when the run step was cancelled."""
completed_at: Optional[int] = None
"""The Unix timestamp (in seconds) for when the run step completed."""
created_at: int
"""The Unix timestamp (in seconds) for when the run step was created."""
expired_at: Optional[int] = None
"""The Unix timestamp (in seconds) for when the run step expired.
A step is considered expired if the parent run is expired.
"""
failed_at: Optional[int] = None
"""The Unix timestamp (in seconds) for when the run step failed."""
last_error: Optional[LastError] = None
"""The last error associated with this run step.
Will be `null` if there are no errors.
"""
metadata: Optional[object] = None
"""Set of 16 key-value pairs that can be attached to an object.
This can be useful for storing additional information about the object in a
structured format. Keys can be a maximum of 64 characters long and values can be
a maxium of 512 characters long.
"""
object: Literal['thread.run.step']
"""The object type, which is always `thread.run.step`."""
run_id: str
"""
The ID of the [run](https://platform.openai.com/docs/api-reference/runs) that
this run step is a part of.
"""
status: Literal['in_progress', 'cancelled', 'failed', 'completed',
'expired']
"""
The status of the run step, which can be either `in_progress`, `cancelled`,
`failed`, `completed`, or `expired`.
"""
step_details: StepDetails
"""The details of the run step."""
thread_id: str
"""
The ID of the [thread](https://platform.openai.com/docs/api-reference/threads)
that was run.
"""
type: Literal['message_creation', 'tool_calls']
"""The type of run step, which can be either `message_creation` or `tool_calls`."""
usage: Optional[Usage] = None
def __init__(self, **kwargs):
self.step_details = convert_step_details_dict_to_objects(
kwargs.pop('step_details', {}))
if 'usage' in kwargs and kwargs['usage'] is not None and kwargs['usage']:
self.usage = Usage(**kwargs.pop('usage', {}))
else:
self.usage = None
last_error = kwargs.pop('last_error', None)
if last_error:
self.last_error = LastError(**last_error)
else:
last_error = last_error
super().__init__(**kwargs)
@dataclass(init=False)
class RunStepList(BaseList):
data: List[RunStep]
def __init__(self,
has_more: bool = None,
last_id: Optional[str] = None,
first_id: Optional[str] = None,
data: List[RunStep] = [],
**kwargs):
if data:
steps = []
for step in data:
steps.append(RunStep(**step))
self.data = steps
else:
self.data = []
super().__init__(has_more=has_more,
last_id=last_id,
first_id=first_id,
**kwargs)

View File

@@ -0,0 +1,212 @@
# Copyright (c) Alibaba, Inc. and its affiliates.
from typing import Dict, List, Optional
from dashscope.assistants.assistant_types import DeleteResponse
from dashscope.client.base_api import (CreateMixin, DeleteMixin,
GetStatusMixin, UpdateMixin)
from dashscope.common.error import InputRequired
from dashscope.threads.thread_types import Run, Thread
__all__ = ['Threads']
class Threads(CreateMixin, DeleteMixin, GetStatusMixin, UpdateMixin):
SUB_PATH = 'threads'
@classmethod
def call(cls,
*,
messages: List[Dict] = None,
metadata: Dict = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> Thread:
"""Create a thread.
Args:
messages (List[Dict], optional): List of messages to start thread. Defaults to None.
metadata (Dict, optional): The key-value information associate with thread. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
Thread: The thread object.
"""
return cls.create(messages=messages,
metadata=metadata,
workspace=workspace,
api_key=api_key,
**kwargs)
@classmethod
def create(cls,
*,
messages: List[Dict] = None,
metadata: Dict = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> Thread:
"""Create a thread.
Args:
messages (List[Dict], optional): List of messages to start thread. Defaults to None.
metadata (Dict, optional): The key-value information associate with thread. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
Thread: The thread object.
"""
data = {}
if messages:
data['messages'] = messages
if metadata:
data['metadata'] = metadata
response = super().call(data=data if data else '',
api_key=api_key,
flattened_output=True,
workspace=workspace,
**kwargs)
return Thread(**response)
@classmethod
def get(cls,
thread_id: str,
*,
workspace: str = None,
api_key: str = None,
**kwargs) -> Thread:
"""Retrieve the thread.
Args:
thread_id (str): The target thread.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
Thread: The `Thread` information.
"""
return cls.retrieve(thread_id,
workspace=workspace,
api_key=api_key,
**kwargs)
@classmethod
def retrieve(cls,
thread_id: str,
*,
workspace: str = None,
api_key: str = None,
**kwargs) -> Thread:
"""Retrieve the thread.
Args:
thread_id (str): The target thread.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
Thread: The `Thread` information.
"""
if not thread_id:
raise InputRequired('thread_id is required!')
response = super().get(thread_id,
api_key=api_key,
flattened_output=True,
workspace=workspace,
**kwargs)
return Thread(**response)
@classmethod
def update(cls,
thread_id: str,
*,
metadata: Dict = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> Thread:
"""Update thread information.
Args:
thread_id (str): The thread id.
metadata (Dict, optional): The thread key-value information. Defaults to None.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
Thread: The `Thread` information.
"""
if not thread_id:
raise InputRequired('thread_id is required!')
response = super().update(thread_id,
json={'metadata': metadata},
api_key=api_key,
workspace=workspace,
flattened_output=True,
method='post',
**kwargs)
return Thread(**response)
@classmethod
def delete(cls,
thread_id,
*,
workspace: str = None,
api_key: str = None,
**kwargs) -> DeleteResponse:
"""Delete thread.
Args:
thread_id (str): The thread id to delete.
workspace (str, optional): The DashScope workspace id. Defaults to None.
api_key (str, optional): Your DashScope api key. Defaults to None.
Returns:
AssistantsDeleteResponse: The deleted information.
"""
if not thread_id:
raise InputRequired('thread_id is required!')
response = super().delete(thread_id,
api_key=api_key,
workspace=workspace,
flattened_output=True,
**kwargs)
return DeleteResponse(**response)
@classmethod
def create_and_run(cls,
*,
assistant_id: str,
thread: Optional[Dict] = None,
model: Optional[str] = None,
instructions: Optional[str] = None,
additional_instructions: Optional[str] = None,
tools: Optional[List[Dict]] = None,
metadata: Optional[Dict] = None,
workspace: str = None,
api_key: str = None,
**kwargs) -> Run:
if not assistant_id:
raise InputRequired('assistant_id is required')
data = {'assistant_id': assistant_id}
if thread:
data['thread'] = thread
if model:
data['model'] = model
if instructions:
data['instructions'] = instructions
if additional_instructions:
data['additional_instructions'] = additional_instructions
if tools:
data['tools'] = tools
if metadata:
data['metadata'] = metadata
response = super().call(data=data,
path='threads/runs',
api_key=api_key,
flattened_output=True,
workspace=workspace,
**kwargs)
return Run(**response)