diff --git a/.env b/.env index 45848dd..267a197 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring -ZAI_API_KEY={your apikey} +ZAI_API_KEY={your apikey} \ No newline at end of file diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 2e3b4bd..11f00fc 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -180,11 +180,12 @@ def ofZhipu(): if __name__ == '__main__': # completion() - # completion_with_websearch() - # multi_modal_chat() - # role_play() - # assistant_conversation() - # video_generation() - ofZai() - ofZhipu() + # completion_with_stream() + # completion_with_websearch() + multi_modal_chat() + # role_play() + # assistant_conversation() + # video_generation() + # ofZai() + # ofZhipu() diff --git a/examples/function_call_example.py b/examples/function_call_example.py new file mode 100644 index 0000000..0257baa --- /dev/null +++ b/examples/function_call_example.py @@ -0,0 +1,120 @@ +from zai import ZhipuAiClient +import json +client = ZhipuAiClient() + +def get_flight_number(date: str, departure: str, destination: str): + flight_number = { + "Beijing": { + "Shanghai": "1234", + "Guangzhou": "5678", + }, + "Shanghai": { + "Beijing": "4321", + "Guangzhou": "8765", + } + } + return {"flight_number": flight_number[departure][destination]} + +def get_ticket_price(date: str, flight_number: str): + return {"ticket_price": "1000"} + +def parse_function_call(model_response, messages): + # Handle function call results. According to the model's returned parameters, call the corresponding function. + # After getting the function result, construct a tool message and call the model again, passing the function result as input. + # The model will return the function result to the user in natural language. + if model_response.choices[0].message.tool_calls: + tool_call = model_response.choices[0].message.tool_calls[0] + args = tool_call.function.arguments + function_result = {} + if tool_call.function.name == "get_flight_number": + function_result = get_flight_number(**json.loads(args)) + if tool_call.function.name == "get_ticket_price": + function_result = get_ticket_price(**json.loads(args)) + messages.append({ + "role": "tool", + "content": f"{json.dumps(function_result)}", + "tool_call_id": tool_call.id + }) + response = client.chat.completions.create( + model="glm-4", # Specify the model name to use + messages=messages, + tools=tools, + ) + print(response.choices[0].message) + messages.append(response.choices[0].message.model_dump()) + +messages = [] +tools = [ + { + "type": "function", + "function": { + "name": "get_flight_number", + "description": "Query the flight number for a given date, departure, and destination", + "parameters": { + "type": "object", + "properties": { + "departure": { + "description": "Departure city", + "type": "string" + }, + "destination": { + "description": "Destination city", + "type": "string" + }, + "date": { + "description": "Date", + "type": "string", + } + }, + "required": ["departure", "destination", "date"] + }, + } + }, + { + "type": "function", + "function": { + "name": "get_ticket_price", + "description": "Query the ticket price for a specific flight on a specific date", + "parameters": { + "type": "object", + "properties": { + "flight_number": { + "description": "Flight number", + "type": "string" + }, + "date": { + "description": "Date", + "type": "string", + } + }, + "required": ["flight_number", "date"] + }, + } + }, +] + +# Clear conversation +messages = [] +messages.append({"role": "system", "content": "Do not assume or guess the values of function parameters. If the user's description is unclear, ask the user to provide the necessary information."}) +messages.append({"role": "user", "content": "Help me check the flights from Beijing to Guangzhou on January 23."}) + +response = client.chat.completions.create( + model="glm-4", # Specify the model name to use + messages=messages, + tools=tools, +) +print(response.choices[0].message) +messages.append(response.choices[0].message.model_dump()) + +parse_function_call(response, messages) + +messages.append({"role": "user", "content": "What is the price of flight 8321?"}) +response = client.chat.completions.create( + model="glm-4", # Specify the model name to use + messages=messages, + tools=tools, +) +print(response.choices[0].message) +messages.append(response.choices[0].message.model_dump()) + +parse_function_call(response, messages) \ No newline at end of file diff --git a/examples/glm4_example.py b/examples/glm4_example.py index 66db70a..e0dabc5 100644 --- a/examples/glm4_example.py +++ b/examples/glm4_example.py @@ -29,7 +29,7 @@ def stream_web_search_example(): stream=True ) for chunk in response: - print(chunk.choices[0].delta) + print(chunk.choices[0].delta.content, end="", flush=True) def sync_example(): print("=== GLM-4 Synchronous Example ===") diff --git a/pyproject.toml b/pyproject.toml index 6916735..7fcde2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "zai-sdk" -version = "0.0.1b3" +version = "0.0.1b4" description = "A SDK library for accessing big model apis from Z.ai" authors = ["Z.ai"] readme = "README.md" diff --git a/src/zai/_client.py b/src/zai/_client.py index 5f911bb..390efaa 100644 --- a/src/zai/_client.py +++ b/src/zai/_client.py @@ -16,9 +16,7 @@ from zai.api_resource.chat import Chat from zai.api_resource.embeddings import Embeddings from zai.api_resource.files import Files - from zai.api_resource.fine_tuning import FineTuning from zai.api_resource.images import Images - from zai.api_resource.knowledge import Knowledge from zai.api_resource.moderations import Moderations from zai.api_resource.tools import Tools from zai.api_resource.videos import Videos @@ -132,24 +130,12 @@ def embeddings(self) -> Embeddings: return Embeddings(self) - @cached_property - def fine_tuning(self) -> FineTuning: - from zai.api_resource.fine_tuning import FineTuning - - return FineTuning(self) - @cached_property def batches(self) -> Batches: from zai.api_resource.batch import Batches return Batches(self) - @cached_property - def knowledge(self) -> Knowledge: - from zai.api_resource.knowledge import Knowledge - - return Knowledge(self) - @cached_property def tools(self) -> Tools: from zai.api_resource.tools import Tools diff --git a/src/zai/_version.py b/src/zai/_version.py index 0fecd85..cf1554a 100644 --- a/src/zai/_version.py +++ b/src/zai/_version.py @@ -1,2 +1,2 @@ __title__ = 'Z.ai' -__version__ = '0.0.1b2' +__version__ = '0.0.1b4' diff --git a/src/zai/api_resource/__init__.py b/src/zai/api_resource/__init__.py index 7a46247..a49a808 100644 --- a/src/zai/api_resource/__init__.py +++ b/src/zai/api_resource/__init__.py @@ -11,9 +11,7 @@ ) from .embeddings import Embeddings from .files import Files, FilesWithRawResponse -from .fine_tuning import FineTuning from .images import Images -from .knowledge import Knowledge from .moderations import Moderations from .tools import Tools from .videos import ( @@ -30,9 +28,7 @@ 'Embeddings', 'Files', 'FilesWithRawResponse', - 'FineTuning', 'Batches', - 'Knowledge', 'Tools', 'Assistant', 'Audio', diff --git a/src/zai/api_resource/fine_tuning/__init__.py b/src/zai/api_resource/fine_tuning/__init__.py deleted file mode 100644 index 7de31ce..0000000 --- a/src/zai/api_resource/fine_tuning/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .fine_tuning import FineTuning -from .jobs import Jobs -from .models import FineTunedModels - -__all__ = ['Jobs', 'FineTunedModels', 'FineTuning'] diff --git a/src/zai/api_resource/fine_tuning/fine_tuning.py b/src/zai/api_resource/fine_tuning/fine_tuning.py deleted file mode 100644 index 4722aa6..0000000 --- a/src/zai/api_resource/fine_tuning/fine_tuning.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import TYPE_CHECKING - -from zai.core import BaseAPI, cached_property - -from .jobs import Jobs -from .models import FineTunedModels - -if TYPE_CHECKING: - pass - - -class FineTuning(BaseAPI): - @cached_property - def jobs(self) -> Jobs: - return Jobs(self._client) - - @cached_property - def models(self) -> FineTunedModels: - return FineTunedModels(self._client) diff --git a/src/zai/api_resource/fine_tuning/jobs/__init__.py b/src/zai/api_resource/fine_tuning/jobs/__init__.py deleted file mode 100644 index 8cda57e..0000000 --- a/src/zai/api_resource/fine_tuning/jobs/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .jobs import Jobs - -__all__ = ['Jobs'] diff --git a/src/zai/api_resource/fine_tuning/jobs/jobs.py b/src/zai/api_resource/fine_tuning/jobs/jobs.py deleted file mode 100644 index 9022b0d..0000000 --- a/src/zai/api_resource/fine_tuning/jobs/jobs.py +++ /dev/null @@ -1,152 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Optional - -import httpx - -from zai.core import ( - NOT_GIVEN, - BaseAPI, - Body, - Headers, - NotGiven, - make_request_options, -) -from zai.types.fine_tuning import ( - FineTuningJob, - FineTuningJobEvent, - ListOfFineTuningJob, - job_create_params, -) - -if TYPE_CHECKING: - from zai._client import ZaiClient - - -class Jobs(BaseAPI): - def __init__(self, client: 'ZaiClient') -> None: - super().__init__(client) - - def create( - self, - *, - model: str, - training_file: str, - hyperparameters: job_create_params.Hyperparameters | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - request_id: Optional[str] | NotGiven = NOT_GIVEN, - validation_file: Optional[str] | NotGiven = NOT_GIVEN, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FineTuningJob: - return self._post( - '/fine_tuning/jobs', - body={ - 'model': model, - 'training_file': training_file, - 'hyperparameters': hyperparameters, - 'suffix': suffix, - 'validation_file': validation_file, - 'request_id': request_id, - }, - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=FineTuningJob, - ) - - def retrieve( - self, - fine_tuning_job_id: str, - *, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FineTuningJob: - return self._get( - f'/fine_tuning/jobs/{fine_tuning_job_id}', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=FineTuningJob, - ) - - def list( - self, - *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ListOfFineTuningJob: - return self._get( - '/fine_tuning/jobs', - cast_type=ListOfFineTuningJob, - options=make_request_options( - extra_headers=extra_headers, - extra_body=extra_body, - timeout=timeout, - query={ - 'after': after, - 'limit': limit, - }, - ), - ) - - def cancel( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API - # that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client - # or passed to this method. - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FineTuningJob: - if not fine_tuning_job_id: - raise ValueError(f'Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}') - return self._post( - f'/fine_tuning/jobs/{fine_tuning_job_id}/cancel', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=FineTuningJob, - ) - - def list_events( - self, - fine_tuning_job_id: str, - *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FineTuningJobEvent: - return self._get( - f'/fine_tuning/jobs/{fine_tuning_job_id}/events', - cast_type=FineTuningJobEvent, - options=make_request_options( - extra_headers=extra_headers, - extra_body=extra_body, - timeout=timeout, - query={ - 'after': after, - 'limit': limit, - }, - ), - ) - - def delete( - self, - fine_tuning_job_id: str, - *, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FineTuningJob: - if not fine_tuning_job_id: - raise ValueError(f'Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}') - return self._delete( - f'/fine_tuning/jobs/{fine_tuning_job_id}', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=FineTuningJob, - ) diff --git a/src/zai/api_resource/fine_tuning/models/__init__.py b/src/zai/api_resource/fine_tuning/models/__init__.py deleted file mode 100644 index 1938013..0000000 --- a/src/zai/api_resource/fine_tuning/models/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .fine_tuned_models import FineTunedModels - -__all__ = ['FineTunedModels'] diff --git a/src/zai/api_resource/fine_tuning/models/fine_tuned_models.py b/src/zai/api_resource/fine_tuning/models/fine_tuned_models.py deleted file mode 100644 index 937ca17..0000000 --- a/src/zai/api_resource/fine_tuning/models/fine_tuned_models.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -import httpx - -from zai.core import ( - NOT_GIVEN, - BaseAPI, - Body, - Headers, - NotGiven, - make_request_options, -) -from zai.types.fine_tuning.models import FineTunedModelsStatus - -if TYPE_CHECKING: - from zai._client import ZaiClient - - -class FineTunedModels(BaseAPI): - def __init__(self, client: 'ZaiClient') -> None: - super().__init__(client) - - def delete( - self, - fine_tuned_model: str, - *, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FineTunedModelsStatus: - if not fine_tuned_model: - raise ValueError(f'Expected a non-empty value for `fine_tuned_model` but received {fine_tuned_model!r}') - return self._delete( - f'fine_tuning/fine_tuned_models/{fine_tuned_model}', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=FineTunedModelsStatus, - ) diff --git a/src/zai/api_resource/knowledge/__init__.py b/src/zai/api_resource/knowledge/__init__.py deleted file mode 100644 index 53c86b5..0000000 --- a/src/zai/api_resource/knowledge/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .knowledge import Knowledge - -__all__ = ['Knowledge'] diff --git a/src/zai/api_resource/knowledge/document/__init__.py b/src/zai/api_resource/knowledge/document/__init__.py deleted file mode 100644 index 67f7fcb..0000000 --- a/src/zai/api_resource/knowledge/document/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .document import Document - -__all__ = ['Document'] diff --git a/src/zai/api_resource/knowledge/document/document.py b/src/zai/api_resource/knowledge/document/document.py deleted file mode 100644 index 5d475e6..0000000 --- a/src/zai/api_resource/knowledge/document/document.py +++ /dev/null @@ -1,254 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Dict, List, Mapping, Optional, cast - -import httpx -from typing_extensions import Literal - -from zai.core import ( - NOT_GIVEN, - BaseAPI, - Body, - FileTypes, - Headers, - NotGiven, - deepcopy_minimal, - extract_files, - make_request_options, - maybe_transform, -) -from zai.types.files import UploadDetail, file_create_params -from zai.types.knowledge.document import ( - DocumentData, - DocumentObject, - document_edit_params, - document_list_params, -) -from zai.types.knowledge.document.document_list_resp import DocumentPage - -if TYPE_CHECKING: - from zai._client import ZaiClient - - -class Document(BaseAPI): - """ - API resource for document operations in knowledge bases - """ - def __init__(self, client: 'ZaiClient') -> None: - super().__init__(client) - - def create( - self, - *, - file: FileTypes = None, - custom_separator: Optional[List[str]] = None, - upload_detail: List[UploadDetail] = None, - purpose: Literal['retrieval'], - knowledge_id: str = None, - sentence_size: int = None, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> DocumentObject: - """ - Create a new document in a knowledge base - - Arguments: - file (FileTypes): File to upload - custom_separator (Optional[List[str]]): Custom separators for text splitting - upload_detail (List[UploadDetail]): Upload details for the document - purpose (Literal['retrieval']): Purpose of the document - knowledge_id (str): ID of the knowledge base - sentence_size (int): Size of sentences for splitting - extra_headers (Headers): Additional headers to send - extra_body (Body): Additional body parameters - timeout (float | httpx.Timeout): Request timeout - """ - if not file and not upload_detail: - raise ValueError('At least one of `file` and `upload_detail` must be provided.') - body = deepcopy_minimal( - { - 'file': file, - 'upload_detail': upload_detail, - 'purpose': purpose, - 'custom_separator': custom_separator, - 'knowledge_id': knowledge_id, - 'sentence_size': sentence_size, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[['file']]) - if files: - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = { - 'Content-Type': 'multipart/form-data', - **(extra_headers or {}), - } - return self._post( - '/files', - body=maybe_transform(body, file_create_params.FileCreateParams), - files=files, - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=DocumentObject, - ) - - def edit( - self, - document_id: str, - knowledge_type: str, - *, - custom_separator: Optional[List[str]] = None, - sentence_size: Optional[int] = None, - callback_url: Optional[str] = None, - callback_header: Optional[Dict[str, str]] = None, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> httpx.Response: - """ - - Args: - document_id: Knowledge ID - knowledge_type: Knowledge type: - 1: Article knowledge: supports pdf, url, docx - 2. Q&A knowledge-document: supports pdf, url, docx - 3. Q&A knowledge-table: supports xlsx - 4. Product library-table: supports xlsx - 5. Custom: supports pdf, url, docx - extra_headers: Send extra headers - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - :param knowledge_type: - :param document_id: - :param timeout: - :param extra_body: - :param callback_header: - :param sentence_size: - :param extra_headers: - :param callback_url: - :param custom_separator: - """ - if not document_id: - raise ValueError(f'Expected a non-empty value for `document_id` but received {document_id!r}') - - body = deepcopy_minimal( - { - 'id': document_id, - 'knowledge_type': knowledge_type, - 'custom_separator': custom_separator, - 'sentence_size': sentence_size, - 'callback_url': callback_url, - 'callback_header': callback_header, - } - ) - - return self._put( - f'/document/{document_id}', - body=maybe_transform(body, document_edit_params.DocumentEditParams), - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=httpx.Response, - ) - - def list( - self, - knowledge_id: str, - *, - purpose: str | NotGiven = NOT_GIVEN, - page: str | NotGiven = NOT_GIVEN, - limit: str | NotGiven = NOT_GIVEN, - order: Literal['desc', 'asc'] | NotGiven = NOT_GIVEN, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> DocumentPage: - """ - List documents in a knowledge base - - Arguments: - knowledge_id (str): ID of the knowledge base - purpose (str): Purpose filter for documents - page (str): Page number for pagination - limit (str): Number of documents per page - order (Literal['desc', 'asc']): Sort order for results - extra_headers (Headers): Additional headers to send - extra_body (Body): Additional body parameters - timeout (float | httpx.Timeout): Request timeout - """ - return self._get( - '/files', - options=make_request_options( - extra_headers=extra_headers, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - 'knowledge_id': knowledge_id, - 'purpose': purpose, - 'page': page, - 'limit': limit, - 'order': order, - }, - document_list_params.DocumentListParams, - ), - ), - cast_type=DocumentPage, - ) - - def delete( - self, - document_id: str, - *, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> httpx.Response: - """ - Delete a file. - - Args: - - document_id: Knowledge ID - extra_headers: Send extra headers - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not document_id: - raise ValueError(f'Expected a non-empty value for `document_id` but received {document_id!r}') - - return self._delete( - f'/document/{document_id}', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=httpx.Response, - ) - - def retrieve( - self, - document_id: str, - *, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> DocumentData: - """ - - Args: - extra_headers: Send extra headers - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - - if not document_id: - raise ValueError(f'Expected a non-empty value for `document_id` but received {document_id!r}') - - return self._get( - f'/document/{document_id}', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=DocumentData, - ) diff --git a/src/zai/api_resource/knowledge/knowledge.py b/src/zai/api_resource/knowledge/knowledge.py deleted file mode 100644 index e6b1d01..0000000 --- a/src/zai/api_resource/knowledge/knowledge.py +++ /dev/null @@ -1,178 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Optional - -import httpx -from typing_extensions import Literal - -from zai.core import ( - NOT_GIVEN, - BaseAPI, - Body, - Headers, - NotGiven, - cached_property, - deepcopy_minimal, - make_request_options, - maybe_transform, -) -from zai.types.knowledge import ( - KnowledgeInfo, - KnowledgeUsed, - knowledge_create_params, - knowledge_list_params, -) -from zai.types.knowledge.knowledge_list_resp import KnowledgePage - -from .document import Document - -if TYPE_CHECKING: - from zai._client import ZaiClient - - -class Knowledge(BaseAPI): - def __init__(self, client: 'ZaiClient') -> None: - super().__init__(client) - - @cached_property - def document(self) -> Document: - return Document(self._client) - - def create( - self, - embedding_id: int, - name: str, - *, - customer_identifier: Optional[str] = None, - description: Optional[str] = None, - background: Optional[Literal['blue', 'red', 'orange', 'purple', 'sky']] = None, - icon: Optional[Literal['question', 'book', 'seal', 'wrench', 'tag', 'horn', 'house']] = None, - bucket_id: Optional[str] = None, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> KnowledgeInfo: - body = deepcopy_minimal( - { - 'embedding_id': embedding_id, - 'name': name, - 'customer_identifier': customer_identifier, - 'description': description, - 'background': background, - 'icon': icon, - 'bucket_id': bucket_id, - } - ) - return self._post( - '/knowledge', - body=maybe_transform(body, knowledge_create_params.KnowledgeBaseParams), - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=KnowledgeInfo, - ) - - def modify( - self, - knowledge_id: str, - embedding_id: int, - *, - name: str, - description: Optional[str] = None, - background: Optional[Literal['blue', 'red', 'orange', 'purple', 'sky']] = None, - icon: Optional[Literal['question', 'book', 'seal', 'wrench', 'tag', 'horn', 'house']] = None, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> httpx.Response: - body = deepcopy_minimal( - { - 'id': knowledge_id, - 'embedding_id': embedding_id, - 'name': name, - 'description': description, - 'background': background, - 'icon': icon, - } - ) - return self._put( - f'/knowledge/{knowledge_id}', - body=maybe_transform(body, knowledge_create_params.KnowledgeBaseParams), - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=httpx.Response, - ) - - def query( - self, - *, - page: int | NotGiven = 1, - size: int | NotGiven = 10, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> KnowledgePage: - return self._get( - '/knowledge', - options=make_request_options( - extra_headers=extra_headers, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - 'page': page, - 'size': size, - }, - knowledge_list_params.KnowledgeListParams, - ), - ), - cast_type=KnowledgePage, - ) - - def delete( - self, - knowledge_id: str, - *, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> httpx.Response: - """ - Delete a knowledge. - - Args: - knowledge_id: Knowledge ID - extra_headers: Send extra headers - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not knowledge_id: - raise ValueError('Expected a non-empty value for `knowledge_id`') - - return self._delete( - f'/knowledge/{knowledge_id}', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=httpx.Response, - ) - - def used( - self, - *, - extra_headers: Headers | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> KnowledgeUsed: - """ - Returns the contents of the specified file. - - Args: - extra_headers: Send extra headers - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get( - '/knowledge/capacity', - options=make_request_options(extra_headers=extra_headers, extra_body=extra_body, timeout=timeout), - cast_type=KnowledgeUsed, - ) diff --git a/src/zai/types/agents/agents_completion.py b/src/zai/types/agents/agents_completion.py index 1f139bd..a575acd 100644 --- a/src/zai/types/agents/agents_completion.py +++ b/src/zai/types/agents/agents_completion.py @@ -46,7 +46,7 @@ class AgentsCompletionChoice(BaseModel): message: AgentsCompletionMessage -class AgentsError: +class AgentsError(BaseModel): """ Represents an error in agents completion. diff --git a/src/zai/types/agents/agents_completion_chunk.py b/src/zai/types/agents/agents_completion_chunk.py index ed75858..5612e75 100644 --- a/src/zai/types/agents/agents_completion_chunk.py +++ b/src/zai/types/agents/agents_completion_chunk.py @@ -43,7 +43,7 @@ class AgentsCompletionUsage(BaseModel): total_tokens: int -class AgentsError: +class AgentsError(BaseModel): """ Represents an error in agents completion chunk. diff --git a/src/zai/types/fine_tuning/__init__.py b/src/zai/types/fine_tuning/__init__.py deleted file mode 100644 index 6f81a2a..0000000 --- a/src/zai/types/fine_tuning/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import annotations - -from .fine_tuning_job import Error, FineTuningJob, Hyperparameters, ListOfFineTuningJob -from .fine_tuning_job_event import FineTuningJobEvent, JobEvent, Metric -from .job_create_params import Hyperparameters as JobHyperparameters - -__all__ = [ - 'FineTuningJob', - 'Error', - 'Hyperparameters', - 'ListOfFineTuningJob', - 'FineTuningJobEvent', - 'Metric', - 'JobEvent', - 'JobHyperparameters', -] diff --git a/src/zai/types/fine_tuning/fine_tuning_job.py b/src/zai/types/fine_tuning/fine_tuning_job.py deleted file mode 100644 index d38c1dc..0000000 --- a/src/zai/types/fine_tuning/fine_tuning_job.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import List, Optional, Union - -from zai.core import BaseModel - - -class Error(BaseModel): - """ - Error information for fine-tuning job - - Attributes: - code: Error code - message: Error message description - param: Optional parameter that caused the error - """ - code: str - message: str - param: Optional[str] = None - - -class Hyperparameters(BaseModel): - """ - Hyperparameters for fine-tuning job - - Attributes: - n_epochs: Number of training epochs - """ - n_epochs: Union[str, int, None] = None - - -class FineTuningJob(BaseModel): - """ - Fine-tuning job information - - Attributes: - id: Unique identifier for the fine-tuning job - request_id: Request identifier - created_at: Timestamp when the job was created - error: Error information if the job failed - fine_tuned_model: Name of the fine-tuned model - finished_at: Timestamp when the job finished - hyperparameters: Hyperparameters used for training - model: Base model used for fine-tuning - object: Object type identifier - result_files: List of result file paths - status: Current status of the fine-tuning job - trained_tokens: Number of tokens used for training - training_file: Path to the training file - validation_file: Path to the validation file - """ - id: Optional[str] = None - request_id: Optional[str] = None - created_at: Optional[int] = None - error: Optional[Error] = None - fine_tuned_model: Optional[str] = None - finished_at: Optional[int] = None - hyperparameters: Optional[Hyperparameters] = None - model: Optional[str] = None - object: Optional[str] = None - result_files: List[str] - status: str - trained_tokens: Optional[int] = None - training_file: str - validation_file: Optional[str] = None - - -class ListOfFineTuningJob(BaseModel): - """ - List of fine-tuning jobs response - - Attributes: - object: Object type identifier - data: List of fine-tuning job objects - """ - object: Optional[str] = None - data: List[FineTuningJob] - has_more: Optional[bool] = None diff --git a/src/zai/types/fine_tuning/fine_tuning_job_event.py b/src/zai/types/fine_tuning/fine_tuning_job_event.py deleted file mode 100644 index e27e1e4..0000000 --- a/src/zai/types/fine_tuning/fine_tuning_job_event.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import List, Optional, Union - -from zai.core import BaseModel - - -class Metric(BaseModel): - epoch: Optional[Union[str, int, float]] = None - current_steps: Optional[int] = None - total_steps: Optional[int] = None - elapsed_time: Optional[str] = None - remaining_time: Optional[str] = None - trained_tokens: Optional[int] = None - loss: Optional[Union[str, int, float]] = None - eval_loss: Optional[Union[str, int, float]] = None - acc: Optional[Union[str, int, float]] = None - eval_acc: Optional[Union[str, int, float]] = None - learning_rate: Optional[Union[str, int, float]] = None - - -class JobEvent(BaseModel): - object: Optional[str] = None - id: Optional[str] = None - type: Optional[str] = None - created_at: Optional[int] = None - level: Optional[str] = None - message: Optional[str] = None - data: Optional[Metric] = None - - -class FineTuningJobEvent(BaseModel): - object: Optional[str] = None - data: List[JobEvent] - has_more: Optional[bool] = None diff --git a/src/zai/types/fine_tuning/job_create_params.py b/src/zai/types/fine_tuning/job_create_params.py deleted file mode 100644 index fea6401..0000000 --- a/src/zai/types/fine_tuning/job_create_params.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import annotations - -from typing import Union - -from typing_extensions import Literal, TypedDict - - -class Hyperparameters(TypedDict, total=False): - """ - Hyperparameters for fine-tuning job configuration - - Attributes: - batch_size: The batch size to use for training (can be 'auto' or an integer) - learning_rate_multiplier: The learning rate multiplier for training (can be 'auto' or a float) - n_epochs: The number of epochs to train for (can be 'auto' or an integer) - """ - batch_size: Union[Literal['auto'], int] - learning_rate_multiplier: Union[Literal['auto'], float] - n_epochs: Union[Literal['auto'], int] diff --git a/src/zai/types/fine_tuning/models/__init__.py b/src/zai/types/fine_tuning/models/__init__.py deleted file mode 100644 index 3650781..0000000 --- a/src/zai/types/fine_tuning/models/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .fine_tuned_models import FineTunedModelsStatus - -__all__ = ['FineTunedModelsStatus'] \ No newline at end of file diff --git a/src/zai/types/fine_tuning/models/fine_tuned_models.py b/src/zai/types/fine_tuning/models/fine_tuned_models.py deleted file mode 100644 index 6c23011..0000000 --- a/src/zai/types/fine_tuning/models/fine_tuned_models.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import ClassVar - -from zai.core import PYDANTIC_V2, BaseModel, ConfigDict - - -class FineTunedModelsStatus(BaseModel): - """ - Fine-tuned model status - - Attributes: - request_id (str): Request id - model_name (str): Model name - delete_status (str): Delete status: deleting (deleting), deleted (deleted) - """ - - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(extra='allow', protected_namespaces=()) - request_id: str - model_name: str - delete_status: str diff --git a/src/zai/types/knowledge/__init__.py b/src/zai/types/knowledge/__init__.py deleted file mode 100644 index 1457cfd..0000000 --- a/src/zai/types/knowledge/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from .knowledge import KnowledgeInfo -from .knowledge_create_params import KnowledgeBaseParams -from .knowledge_list_params import KnowledgeListParams -from .knowledge_list_resp import KnowledgePage -from .knowledge_used import KnowledgeStatistics, KnowledgeUsed - -__all__ = [ - 'KnowledgeInfo', - 'KnowledgeStatistics', - 'KnowledgeUsed', - 'KnowledgeBaseParams', - 'KnowledgeListParams', - 'KnowledgePage', -] diff --git a/src/zai/types/knowledge/document/__init__.py b/src/zai/types/knowledge/document/__init__.py deleted file mode 100644 index 91b4e3a..0000000 --- a/src/zai/types/knowledge/document/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from .document import ( - DocumentData, - DocumentDataFailInfo, - DocumentFailedInfo, - DocumentObject, - DocumentSuccessinfo, -) -from .document_edit_params import DocumentEditParams -from .document_list_params import DocumentListParams -from .document_list_resp import DocumentPage - -__all__ = [ - 'DocumentData', - 'DocumentObject', - 'DocumentSuccessinfo', - 'DocumentFailedInfo', - 'DocumentDataFailInfo', - 'DocumentEditParams', - 'DocumentListParams', - 'DocumentPage', -] diff --git a/src/zai/types/knowledge/document/document.py b/src/zai/types/knowledge/document/document.py deleted file mode 100644 index f404655..0000000 --- a/src/zai/types/knowledge/document/document.py +++ /dev/null @@ -1,87 +0,0 @@ -from typing import List, Optional - -from zai.core import BaseModel - - -class DocumentSuccessinfo(BaseModel): - """ - Represents successful document upload information. - - Attributes: - documentId (Optional[str]): Document ID - filename (Optional[str]): Document filename - """ - - documentId: Optional[str] = None - filename: Optional[str] = None - - -class DocumentFailedInfo(BaseModel): - """ - Represents failed document upload information. - - Attributes: - failReason (Optional[str]): Reason for upload failure, including: unsupported file format, - file size exceeds limit, knowledge base capacity is full, - capacity limit is 500,000 words - filename (Optional[str]): Document filename - documentId (Optional[str]): Knowledge base ID - """ - - failReason: Optional[str] = None - filename: Optional[str] = None - documentId: Optional[str] = None - - -class DocumentObject(BaseModel): - """ - Document information - - Attributes: - successInfos (Optional[List[DocumentSuccessinfo]]): Information about successfully uploaded files - failedInfos (Optional[List[DocumentFailedInfo]]): Information about failed file uploads - """ - - successInfos: Optional[List[DocumentSuccessinfo]] = None - failedInfos: Optional[List[DocumentFailedInfo]] = None - - -class DocumentDataFailInfo(BaseModel): - """ - Document vectorization failure information - - Attributes: - embedding_code (Optional[int]): Error code (10001: Knowledge unavailable, knowledge base space limit reached; - 10002: Knowledge unavailable, word count exceeded) - embedding_msg (Optional[str]): Failure reason description - """ - - embedding_code: Optional[int] = None - embedding_msg: Optional[str] = None - - -class DocumentData(BaseModel): - """ - Document data information - - Attributes: - id (str): Unique knowledge document identifier - custom_separator (List[str]): Custom text slicing rules - sentence_size (str): Text slice size configuration - length (int): File size in bytes - word_num (int): Total word count in the file - name (str): Document file name - url (str): File download URL - embedding_stat (int): Vectorization status (0: vectorizing, 1: completed, 2: failed) - failInfo (Optional[DocumentDataFailInfo]): Failure information when vectorization fails (embedding_stat=2) - """ - - id: str = None - custom_separator: List[str] = None - sentence_size: str = None - length: int = None - word_num: int = None - name: str = None - url: str = None - embedding_stat: int = None - failInfo: Optional[DocumentDataFailInfo] = None diff --git a/src/zai/types/knowledge/document/document_edit_params.py b/src/zai/types/knowledge/document/document_edit_params.py deleted file mode 100644 index af9ab8f..0000000 --- a/src/zai/types/knowledge/document/document_edit_params.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Dict, List, Optional, TypedDict - - -class DocumentEditParams(TypedDict): - """ - Knowledge parameter type definition - - Attributes: - id (str): Knowledge ID - knowledge_type (int): Knowledge type: - 1: Article knowledge: supports pdf,url,docx - 2: Q&A knowledge-document: supports pdf,url,docx - 3: Q&A knowledge-table: supports xlsx - 4: Product library-table: supports xlsx - 5: Custom: supports pdf,url,docx - custom_separator (Optional[List[str]]): Slice rules when current knowledge type is custom - (knowledge_type=5), default \n - sentence_size (Optional[int]): Slice word count when current knowledge type is custom - (knowledge_type=5), value range: 20-2000, default 300 - callback_url (Optional[str]): Callback address - callback_header (Optional[dict]): Header carried during callback - """ - - id: str - knowledge_type: int - custom_separator: Optional[List[str]] - sentence_size: Optional[int] - callback_url: Optional[str] - callback_header: Optional[Dict[str, str]] diff --git a/src/zai/types/knowledge/document/document_list_params.py b/src/zai/types/knowledge/document/document_list_params.py deleted file mode 100644 index 01831df..0000000 --- a/src/zai/types/knowledge/document/document_list_params.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import annotations - -from typing import Optional - -from typing_extensions import TypedDict - - -class DocumentListParams(TypedDict, total=False): - """ - File query parameter type definition - - Attributes: - purpose (Optional[str]): File purpose - knowledge_id (Optional[str]): When file purpose is retrieval, need to provide the knowledge base ID for query - page (Optional[int]): Page number, default 1 - limit (Optional[int]): Number of files to query in the list, default 10 - after (Optional[str]): Query file list after specified fileID (required when file purpose is fine-tune) - order (Optional[str]): Sort rule, optional values ['desc', 'asc'], default desc - (required when file purpose is fine-tune) - """ - - purpose: Optional[str] - knowledge_id: Optional[str] - page: Optional[int] - limit: Optional[int] - after: Optional[str] - order: Optional[str] diff --git a/src/zai/types/knowledge/document/document_list_resp.py b/src/zai/types/knowledge/document/document_list_resp.py deleted file mode 100644 index 11e8930..0000000 --- a/src/zai/types/knowledge/document/document_list_resp.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import annotations - -from typing import List - -from zai.core import BaseModel -from zai.types.knowledge.document.document import DocumentData - - -class DocumentPage(BaseModel): - list: List[DocumentData] - object: str diff --git a/src/zai/types/knowledge/knowledge.py b/src/zai/types/knowledge/knowledge.py deleted file mode 100644 index be22525..0000000 --- a/src/zai/types/knowledge/knowledge.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Optional - -from zai.core import BaseModel - - -class KnowledgeInfo(BaseModel): - # Knowledge base unique ID - id: Optional[str] = None - - # Vectorization model bound to knowledge base - # See model list [Internal Service Open Interface Documentation](https://lslfd0slxc.feishu.cn/docx/YauWdbBiMopV0FxB7KncPWCEn8f#H15NduiQZo3ugmxnWQFcfAHpnQ4) - embedding_id: Optional[str] = None - - # Knowledge base name, 100 character limit - name: Optional[str] = None - - # User identifier, within 32 characters - customer_identifier: Optional[str] = None - - # Knowledge base description, 500 character limit - description: Optional[str] = None - - # Background color (enumeration) 'blue', 'red', 'orange', 'purple', 'sky' - background: Optional[str] = None - - # Knowledge base icon (enumeration) question: question mark, book: book, seal: seal, wrench: wrench, - # tag: tag, horn: horn, house: house - icon: Optional[str] = None - - # Bucket ID, 32 character limit - bucket_id: Optional[str] = None diff --git a/src/zai/types/knowledge/knowledge_create_params.py b/src/zai/types/knowledge/knowledge_create_params.py deleted file mode 100644 index 225d75f..0000000 --- a/src/zai/types/knowledge/knowledge_create_params.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from typing import Optional - -from typing_extensions import Literal, TypedDict - - -class KnowledgeBaseParams(TypedDict): - """ - Knowledge base parameters. - - Attributes: - embedding_id (int): Embedding ID - name (str): Knowledge base name, limited to 100 characters - customer_identifier (Optional[str]): Customer identifier, limited to 32 characters - description (Optional[str]): Knowledge base description, limited to 500 characters - background (Optional[Literal['blue', 'red', 'orange', 'purple', 'sky']]): Background color - icon (Optional[Literal['question', 'book', 'seal', 'wrench', 'tag', 'horn', 'house']]): Knowledge base icon - bucket_id (Optional[str]): Bucket ID, limited to 32 characters - """ - - embedding_id: int - name: str - customer_identifier: Optional[str] - description: Optional[str] - background: Optional[Literal['blue', 'red', 'orange', 'purple', 'sky']] = None - icon: Optional[Literal['question', 'book', 'seal', 'wrench', 'tag', 'horn', 'house']] = None - bucket_id: Optional[str] diff --git a/src/zai/types/knowledge/knowledge_list_params.py b/src/zai/types/knowledge/knowledge_list_params.py deleted file mode 100644 index c647f7c..0000000 --- a/src/zai/types/knowledge/knowledge_list_params.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import annotations - -from typing_extensions import TypedDict - - -class KnowledgeListParams(TypedDict, total=False): - """ - Parameters for listing knowledge resources. - - Attributes: - page (int): Page number, default 1, first page - size (int): Number per page, default 10 - """ - - page: int = 1 - size: int = 10 diff --git a/src/zai/types/knowledge/knowledge_list_resp.py b/src/zai/types/knowledge/knowledge_list_resp.py deleted file mode 100644 index ad5896a..0000000 --- a/src/zai/types/knowledge/knowledge_list_resp.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import annotations - -from typing import List - -from zai.core import BaseModel -from zai.types.knowledge.knowledge import KnowledgeInfo - - -class KnowledgePage(BaseModel): - list: List[KnowledgeInfo] - object: str diff --git a/src/zai/types/knowledge/knowledge_used.py b/src/zai/types/knowledge/knowledge_used.py deleted file mode 100644 index d3d6922..0000000 --- a/src/zai/types/knowledge/knowledge_used.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from zai.core import BaseModel - - -class KnowledgeStatistics(BaseModel): - """ - Usage statistics - """ - - word_num: Optional[int] = None - length: Optional[int] = None - - -class KnowledgeUsed(BaseModel): - used: Optional[KnowledgeStatistics] = None - """Used amount""" - total: Optional[KnowledgeStatistics] = None - """Total knowledge base""" diff --git a/tests/integration_tests/asr1.wav b/tests/integration_tests/asr1.wav index e29ac13..ecff0a3 100644 Binary files a/tests/integration_tests/asr1.wav and b/tests/integration_tests/asr1.wav differ diff --git a/tests/integration_tests/test_agents.py b/tests/integration_tests/test_agents.py index 2ad8503..c5b7a5c 100644 --- a/tests/integration_tests/test_agents.py +++ b/tests/integration_tests/test_agents.py @@ -3,7 +3,7 @@ import time import zai -from zai import ZaiClient +from zai import ZaiClient, ZhipuAiClient def test_completions_sync(logging_conf): diff --git a/tests/integration_tests/test_audio.py b/tests/integration_tests/test_audio.py index 1918767..a0bb2f4 100644 --- a/tests/integration_tests/test_audio.py +++ b/tests/integration_tests/test_audio.py @@ -10,7 +10,7 @@ def test_audio_speech(logging_conf): logging.config.dictConfig(logging_conf) # type: ignore client = ZaiClient() # Fill in your own API Key try: - speech_file_path = Path(__file__).parent / 'speech.wav' + speech_file_path = Path(__file__).parent / 'asr1.wav' response = client.audio.speech( model='cogtts', input='Hello, welcome to Z.ai Open Platform', @@ -30,9 +30,9 @@ def test_audio_speech(logging_conf): def test_audio_customization(logging_conf): logging.config.dictConfig(logging_conf) client = ZaiClient() # Fill in your own API Key - with open(Path(__file__).parent / 'speech.wav', 'rb') as file: + with open(Path(__file__).parent / 'asr1.wav', 'rb') as file: try: - speech_file_path = Path(__file__).parent / 'speech.wav' + speech_file_path = Path(__file__).parent / 'asr1.wav' response = client.audio.customization( model='cogtts', input='Hello, welcome to Z.ai Open Platform', diff --git a/tests/integration_tests/test_finetuning.py b/tests/integration_tests/test_finetuning.py deleted file mode 100644 index 1260f36..0000000 --- a/tests/integration_tests/test_finetuning.py +++ /dev/null @@ -1,134 +0,0 @@ -import logging -import logging.config - -import zai -from zai import ZaiClient - - -def test_finetuning_create(logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - client = ZaiClient() # Please fill in your own API Key - try: - job = client.fine_tuning.jobs.create( - model='chatglm3-6b', - training_file='file-20240428021923715-xjng4', # Please fill in the successfully uploaded file id - validation_file='file-20240428021923715-xjng4', # Please fill in the successfully uploaded file id - suffix='demo_test', - ) - job_id = job.id - print(job_id) - fine_tuning_job = client.fine_tuning.jobs.retrieve(fine_tuning_job_id=job_id) - print(fine_tuning_job) - # ftjob-20240418110039323-j8lh2 - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - -def test_finetuning_retrieve(logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - client = ZaiClient() # Please fill in your own API Key - try: - fine_tuning_job = client.fine_tuning.jobs.retrieve(fine_tuning_job_id='ftjob-20240429112551154-48vq7') - print(fine_tuning_job) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - -def test_finetuning_job_list(logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - client = ZaiClient() # Please fill in your own API Key - try: - job_list = client.fine_tuning.jobs.list() - - print(job_list) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - -def test_finetuning_job_cancel(logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - client = ZaiClient() # Please fill in your own API Key - try: - cancel = client.fine_tuning.jobs.cancel(fine_tuning_job_id='ftjob-20240429112551154-48vq7') - - print(cancel) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - -def test_finetuning_job_delete(logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - client = ZaiClient() # Please fill in your own API Key - try: - delete = client.fine_tuning.jobs.delete(fine_tuning_job_id='ftjob-20240126113041678-cs6s9') - - print(delete) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - -def test_model_check(logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - client = ZaiClient() # Fill in your own API Key - try: - response = client.chat.completions.create( - model='chatglm3-6b-8572905046912426020-demo_test', # Fill in the model name to call - messages=[ - {'role': 'user', 'content': 'You are a helpful, knowledgeable, and versatile AI assistant.'}, - {'role': 'user', 'content': 'Create a more precise and engaging slogan'}, - ], - extra_body={'temperature': 0.5, 'max_tokens': 50}, - ) - print(response.choices[0].message) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - -def test_model_delete(logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - client = ZaiClient() # Fill in your own API Key - try: - delete = client.fine_tuning.models.delete(fine_tuned_model='chatglm3-6b-8572905046912426020-demo_test') - - print(delete) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - -if __name__ == '__main__': - test_finetuning_create() diff --git a/tests/integration_tests/test_knowledge.py b/tests/integration_tests/test_knowledge.py deleted file mode 100644 index e6a4635..0000000 --- a/tests/integration_tests/test_knowledge.py +++ /dev/null @@ -1,168 +0,0 @@ -from __future__ import annotations - -import logging -import logging.config -import os - -import pytest - -import zai -from zai import ZaiClient - - -@pytest.fixture(scope='class') -def test_server(): - class SharedData: - client = ZaiClient() - test_knowledge_document_id = None - test_knowledge_id = None - - return SharedData() - - -class TestZaiClientKnowledgeServer: - def test_logs(self, logging_conf): - logging.config.dictConfig(logging_conf) # type: ignore - - def test_knowledge_create(self, test_server): - try: - result = test_server.client.knowledge.create( - embedding_id=1, - name='test', - description='test', - background='blue', - icon='question', - ) - print(result) - test_server.test_knowledge_id = result.id - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_document_create(self, test_server, test_file_path): - try: - result = test_server.client.knowledge.document.create( - file=open(os.path.join(test_file_path, 'file.xlsx'), 'rb'), - purpose='retrieval', - knowledge_id=test_server.test_knowledge_id, - sentence_size=202, - ) - print(result) - test_server.test_knowledge_document_id = result.successInfos[0].documentId - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_modify(self, test_server): - try: - result = test_server.client.knowledge.modify( - knowledge_id=test_server.test_knowledge_id, - embedding_id=1, - name='test1', - background='red', - icon='book', - ) - print(result) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_query(self, test_server): - try: - result = test_server.client.knowledge.query() - print(result) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_used(self, test_server): - try: - result = test_server.client.knowledge.used() - print(result) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_document_retrieve(self, test_server, test_file_path): - try: - result = test_server.client.knowledge.document.retrieve(test_server.test_knowledge_document_id) - print(result) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_document_edit(self, test_server): - try: - result = test_server.client.knowledge.document.edit( - document_id=test_server.test_knowledge_document_id, - knowledge_type='1', - sentence_size=204, - ) - print(result) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_document_list(self, test_server): - try: - result = test_server.client.knowledge.document.list(test_server.test_knowledge_id, purpose='retrieval') - print(result) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_document_delete(self, test_server): - try: - file1 = test_server.client.knowledge.document.delete(test_server.test_knowledge_document_id) - print(file1) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) - - def test_knowledge_delete(self, test_server): - try: - result = test_server.client.knowledge.delete(knowledge_id=test_server.test_knowledge_id) - print(result) - - except zai.core._errors.APIRequestFailedError as err: - print(err) - except zai.core._errors.APIInternalError as err: - print(err) - except zai.core._errors.APIStatusError as err: - print(err) diff --git a/tests/unit_tests/response_model/test_response.py b/tests/unit_tests/response_model/test_response.py index e26fe70..434b18d 100644 --- a/tests/unit_tests/response_model/test_response.py +++ b/tests/unit_tests/response_model/test_response.py @@ -26,13 +26,6 @@ ) from zai.types.embeddings import Embedding, EmbeddingsResponded from zai.types.files.file_object import FileObject, ListOfFileObject -from zai.types.fine_tuning import FineTuningJobEvent -from zai.types.fine_tuning.fine_tuning_job import Error, FineTuningJob -from zai.types.fine_tuning.fine_tuning_job import ( - Hyperparameters as FineTuningHyperparameters, -) -from zai.types.fine_tuning.fine_tuning_job_event import JobEvent, Metric -from zai.types.fine_tuning.models import FineTunedModelsStatus from zai.types.image import GeneratedImage, ImagesResponded @@ -164,186 +157,6 @@ def test_response_chat_model_cast(R: Type[BaseModel]) -> None: assert False, f'Unexpected model type: {R}' -@pytest.mark.parametrize( - 'R', - [ - FineTunedModelsStatus, - ], -) -def test_response_finetuned_model_model_cast(R: Type[BaseModel]) -> None: - MockClient._process_response_data = HttpClient._process_response_data - response = httpx.Response( - status_code=200, - content="""{ - "request_id": "12345", - "model_name": "my-fine-tuned-model", - "delete_status": "deleted" - }""", - ) - - opts = FinalRequestOptions.construct(method='get', url='path') - http_response = APIResponse( - raw=response, - cast_type=R, - client=MockClient(), - stream=False, - stream_cls=None, - options=opts, - ) - model = http_response.parse() - - assert R == model.__class__ - assert isinstance(model, FineTunedModelsStatus) - assert model.request_id == '12345' - assert model.model_name == 'my-fine-tuned-model' - assert model.delete_status == 'deleted' - - -@pytest.mark.parametrize( - 'R', - [ - FineTuningJob, - ], -) -def test_response_job_model_cast(R: Type[BaseModel]) -> None: - MockClient._process_response_data = HttpClient._process_response_data - response = httpx.Response( - status_code=200, - content=""" { - "id": "job123", - "request_id": "req456", - "created_at": 1617181723, - "error": { - "code": "404", - "message": "Not Found", - "param": "model_id" - }, - "fine_tuned_model": "ft_model_1", - "finished_at": 1617182000, - "hyperparameters": { - "n_epochs": 10 - }, - "model": "base_model", - "object": "fine_tuning_job", - "result_files": [ - "result1.txt", - "result2.json" - ], - "status": "completed", - "trained_tokens": 1000000, - "training_file": "training_data.csv", - "validation_file": "validation_data.csv" - }""", - ) - - opts = FinalRequestOptions.construct(method='get', url='path') - http_response = APIResponse( - raw=response, - cast_type=R, - client=MockClient(), - stream=False, - stream_cls=None, - options=opts, - ) - model = http_response.parse() - - assert R == model.__class__ - assert isinstance(model, FineTuningJob) - assert model.id == 'job123' - assert model.request_id == 'req456' - assert model.created_at == 1617181723 - assert isinstance(model.error, Error) - assert model.error.code == '404' - assert model.error.message == 'Not Found' - assert model.error.param == 'model_id' - assert model.fine_tuned_model == 'ft_model_1' - assert model.finished_at == 1617182000 - assert isinstance(model.hyperparameters, FineTuningHyperparameters) - assert model.hyperparameters.n_epochs == 10 - assert model.model == 'base_model' - assert model.object == 'fine_tuning_job' - assert model.result_files == ['result1.txt', 'result2.json'] - assert model.status == 'completed' - assert model.trained_tokens == 1000000 - assert model.training_file == 'training_data.csv' - assert model.validation_file == 'validation_data.csv' - - -@pytest.mark.parametrize( - 'R', - [ - FineTuningJobEvent, - ], -) -def test_response_joblist_model_cast(R: Type[BaseModel]) -> None: - MockClient._process_response_data = HttpClient._process_response_data - response = httpx.Response( - status_code=200, - content="""{ - "object": "fine_tuning_job", - "data": [ - { - "object": "job_event", - "id": "event123", - "type": "training", - "created_at": 1617181723, - "level": "info", - "message": "Training has started.", - "data": { - "epoch": 1, - "current_steps": 100, - "total_steps": 1000, - "elapsed_time": "00:10:00", - "remaining_time": "05:20:00", - "trained_tokens": 500000, - "loss": 0.05, - "eval_loss": 0.03, - "acc": 0.9, - "eval_acc": 0.95, - "learning_rate": 0.001 - } - } - ], - "has_more": false - }""", - ) - - opts = FinalRequestOptions.construct(method='get', url='path') - http_response = APIResponse( - raw=response, - cast_type=R, - client=MockClient(), - stream=False, - stream_cls=None, - options=opts, - ) - model = http_response.parse() - - assert R == model.__class__ - assert isinstance(model, FineTuningJobEvent) - assert isinstance(model.data, list) - assert isinstance(model.data[0], JobEvent) - assert model.data[0].object == 'job_event' - assert model.data[0].id == 'event123' - assert model.data[0].type == 'training' - assert model.data[0].created_at == 1617181723 - assert model.data[0].level == 'info' - assert model.data[0].message == 'Training has started.' - assert isinstance(model.data[0].data, Metric) - assert model.data[0].data.epoch == 1 - assert model.data[0].data.current_steps == 100 - assert model.data[0].data.total_steps == 1000 - assert model.data[0].data.elapsed_time == '00:10:00' - assert model.data[0].data.remaining_time == '05:20:00' - assert model.data[0].data.trained_tokens == 500000 - assert model.data[0].data.loss == 0.05 - assert model.data[0].data.eval_loss == 0.03 - assert model.data[0].data.acc == 0.9 - assert model.data[0].data.eval_acc == 0.95 - assert model.data[0].data.learning_rate == 0.001 - assert model.has_more == False - - @pytest.mark.parametrize( 'R', [EmbeddingsResponded], diff --git a/tests/unit_tests/test_agent.py b/tests/unit_tests/test_agent.py new file mode 100644 index 0000000..7cb6442 --- /dev/null +++ b/tests/unit_tests/test_agent.py @@ -0,0 +1,35 @@ +from zai.types.agents.agents_completion import AgentsCompletion, AgentsError, AgentsCompletionChoice, AgentsCompletionMessage, AgentsCompletionUsage + +def test_agents_completion_error_field(): + + # 构造一个 AgentsError + error = AgentsError(code="404", message="Not Found") + + # 构造一个完整的 AgentsCompletion + completion = AgentsCompletion( + agent_id="test_agent", + conversation_id="conv_1", + status="failed", + choices=[ + AgentsCompletionChoice( + index=0, + finish_reason="error", + message=AgentsCompletionMessage(content="error", role="system") + ) + ], + request_id="req_1", + id="id_1", + usage=AgentsCompletionUsage(prompt_tokens=1, completion_tokens=1, total_tokens=2), + error=error + ) + + # 检查 error 字段是否为 AgentsError 实例 + assert isinstance(completion.error, AgentsError) + assert completion.error.code == "404" + assert completion.error.message == "Not Found" + + # 检查序列化 + as_dict = completion.model_dump() + assert as_dict["error"]["code"] == "404" + assert as_dict["error"]["message"] == "Not Found" + print("test_agents_completion_error_field passed.") \ No newline at end of file