From 7562c00daed3fd08143eb055ac813fa83af688ea Mon Sep 17 00:00:00 2001 From: wellenzheng <40078093+wellenzheng@users.noreply.github.com> Date: Tue, 22 Jul 2025 17:23:32 +0800 Subject: [PATCH 1/6] fix: update video generation params and examples (#10) Co-authored-by: zhengweijun --- .vscode/settings.json | 3 + examples/agent_examples.py | 17 +- examples/basic_usage.py | 4 +- examples/check_apikey_env.py | 14 ++ examples/glm4_example.py | 18 +- examples/video_generator.py | 19 +- examples/video_models_examples.py | 191 ++++++++++++--------- examples/web_search_example.py | 15 +- src/zai/api_resource/videos/videos.py | 27 ++- src/zai/types/video/video_create_params.py | 20 ++- 10 files changed, 176 insertions(+), 152 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 examples/check_apikey_env.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ff5300e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.languageServer": "None" +} \ No newline at end of file diff --git a/examples/agent_examples.py b/examples/agent_examples.py index 22f0c28..3db6bfa 100644 --- a/examples/agent_examples.py +++ b/examples/agent_examples.py @@ -1,26 +1,12 @@ -import os from zai import ZaiClient import asyncio import time -# Try to load .env file -try: - from dotenv import load_dotenv - load_dotenv() -except ImportError: - # If python-dotenv is not installed, continue using system environment variables - pass - -api_key = os.getenv('ZAI_API_KEY') -if not api_key: - print("Please set the ZAI_API_KEY environment variable or configure it in the .env file") - exit() -client = ZaiClient(api_key=api_key) - # ==================== General Translation Scenario ==================== def translate_text(): """General translation example""" + client = ZaiClient() response = client.agents.invoke( agent_id="general_translation", stream=True, @@ -57,6 +43,7 @@ async def async_special_effects_video_example(): # Submit async task print("Submitting async special effects video generation task...") + client = ZaiClient() response = client.agents.invoke( agent_id="vidu_template_agent", custom_variables={ diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 988b7d3..00d6635 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -1,6 +1,5 @@ from zai import ZaiClient - def completion(): # Initialize client client = ZaiClient() @@ -161,8 +160,9 @@ def audio_transcription(): if __name__ == '__main__': + completion() # completion_with_websearch() # multi_modal_chat() # role_play() # assistant_conversation() - video_generation() + # video_generation() diff --git a/examples/check_apikey_env.py b/examples/check_apikey_env.py new file mode 100644 index 0000000..23b8f69 --- /dev/null +++ b/examples/check_apikey_env.py @@ -0,0 +1,14 @@ +import os + + +def check_apikey(): + api_key = os.getenv('ZAI_API_KEY') + if api_key and api_key.strip(): + print('ZAI_API_KEY is set.') + print(api_key) + else: + print('ZAI_API_KEY is NOT set. Please set the ZAI_API_KEY environment variable or configure it in the .env file.') + + +if __name__ == '__main__': + check_apikey() \ No newline at end of file diff --git a/examples/glm4_example.py b/examples/glm4_example.py index 6d46544..66db70a 100644 --- a/examples/glm4_example.py +++ b/examples/glm4_example.py @@ -2,20 +2,6 @@ import os import time from zai import ZaiClient -# Try to load .env file -try: - from dotenv import load_dotenv - load_dotenv() -except ImportError: - pass - -api_key = os.getenv('ZAI_API_KEY') -if not api_key: - print("Please set the ZAI_API_KEY environment variable or configure it in the .env file.") - exit() - -client = ZaiClient(api_key=api_key) - def stream_web_search_example(): print("=== GLM-4 Streaming Web Search Example ===") tools = [{ @@ -35,6 +21,7 @@ def stream_web_search_example(): "role": "user", "content": "Major financial events, policy changes, and market data in April 2025." }] + client = ZaiClient() response = client.chat.completions.create( model="glm-4-air", messages=messages, @@ -46,6 +33,7 @@ def stream_web_search_example(): def sync_example(): print("=== GLM-4 Synchronous Example ===") + client = ZaiClient() response = client.chat.completions.create( model="glm-4-plus", messages=[ @@ -57,6 +45,7 @@ def sync_example(): def async_example(): print("=== GLM-4 Async Example ===") + client = ZaiClient() response = client.chat.asyncCompletions.create( model="glm-4-plus", messages=[ @@ -73,6 +62,7 @@ def async_result_example(task_id): print("=== GLM-4 Async Result Polling Example ===") task_status = '' get_cnt = 0 + client = ZaiClient() while task_status != 'SUCCESS' and task_status != 'FAILED' and get_cnt <= 40: result_response = client.chat.asyncCompletions.retrieve_completion_result(id=task_id) print(result_response) diff --git a/examples/video_generator.py b/examples/video_generator.py index aee9933..c773397 100644 --- a/examples/video_generator.py +++ b/examples/video_generator.py @@ -4,22 +4,9 @@ import time from zai import ZaiClient -# Try to load .env file -try: - from dotenv import load_dotenv - load_dotenv() -except ImportError: - # If python-dotenv is not installed, continue using system environment variables - pass - -api_key = os.getenv('ZAI_API_KEY') -if not api_key: - print("Please set the ZAI_API_KEY environment variable or configure it in the .env file") - exit() - class VideoGenerator: - def __init__(self, api_key: str): - self.client = ZaiClient(api_key=api_key) + def __init__(self): + self.client = ZaiClient() async def video_generate( self, @@ -95,7 +82,7 @@ class VideoGenerator: # Usage example async def main(): - generator = VideoGenerator(api_key) + generator = VideoGenerator() try: result = await generator.video_generate( prompt='A beautiful sunset beach scene with a beautiful girl', diff --git a/examples/video_models_examples.py b/examples/video_models_examples.py index dd7a176..38e99a3 100644 --- a/examples/video_models_examples.py +++ b/examples/video_models_examples.py @@ -5,22 +5,9 @@ from typing import List, Optional from zai import ZaiClient -# Try to load .env file -try: - from dotenv import load_dotenv - load_dotenv() -except ImportError: - # If python-dotenv is not installed, continue using system environment variables - pass - -api_key = os.getenv('ZAI_API_KEY') -if not api_key: - print("Please set the ZAI_API_KEY environment variable or configure it in the .env file") - exit() - class VideoModelsExamples: - def __init__(self, api_key: str): - self.client = ZaiClient(api_key=api_key) + def __init__(self): + self.client = ZaiClient() async def cogvideox3_text_to_video( self, @@ -165,21 +152,26 @@ class VideoModelsExamples: async def viduq1_text_to_video( self, prompt: str, - quality: str = "quality", - with_audio: bool = True, + style: str = "general", + duration: int = 5, + aspect_ratio: str = "16:9", size: str = "1920x1080", - fps: int = 30, + movement_amplitude: str = "auto", + quality: str = None, + with_audio: bool = None, max_wait_time: int = 300, ): """ viduq1-text text-to-video generation - Args: prompt: Video generation prompt - quality: Output mode, "quality" for quality priority, "speed" for speed priority - with_audio: Whether to include audio + style: Video style (e.g., "general", "anime") + duration: Video duration in seconds + aspect_ratio: Aspect ratio (e.g., "16:9") size: Video resolution - fps: Frame rate + movement_amplitude: Movement amplitude (e.g., "auto") + quality: Output mode + with_audio: Whether to include audio max_wait_time: Maximum wait time (seconds) """ print("=== viduq1-text Text-to-Video ===") @@ -187,10 +179,13 @@ class VideoModelsExamples: response = self.client.videos.generations( model="viduq1-text", prompt=prompt, + style=style, + duration=duration, + aspect_ratio=aspect_ratio, + size=size, + movement_amplitude=movement_amplitude, quality=quality, with_audio=with_audio, - size=size, - fps=fps, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -201,22 +196,23 @@ class VideoModelsExamples: self, image_url: str, prompt: str, - quality: str = "quality", - with_audio: bool = True, + duration: int = 5, size: str = "1920x1080", - fps: int = 30, + movement_amplitude: str = "auto", + quality: str = None, + with_audio: bool = None, max_wait_time: int = 300, ): """ viduq1-image image-to-video generation - Args: image_url: Image URL or Base64 encoding prompt: Video generation prompt - quality: Output mode, "quality" for quality priority, "speed" for speed priority - with_audio: Whether to include audio + duration: Video duration in seconds size: Video resolution - fps: Frame rate + movement_amplitude: Movement amplitude (e.g., "auto") + quality: Output mode + with_audio: Whether to include audio max_wait_time: Maximum wait time (seconds) """ print("=== viduq1-image Image-to-Video ===") @@ -225,10 +221,11 @@ class VideoModelsExamples: model="viduq1-image", image_url=image_url, prompt=prompt, + duration=duration, + size=size, + movement_amplitude=movement_amplitude, quality=quality, with_audio=with_audio, - size=size, - fps=fps, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -239,34 +236,36 @@ class VideoModelsExamples: self, image_urls: List[str], prompt: str, - quality: str = "quality", - with_audio: bool = True, + duration: int = 5, size: str = "1920x1080", - fps: int = 30, + movement_amplitude: str = "auto", + quality: str = None, + with_audio: bool = None, max_wait_time: int = 300, ): """ viduq1-start-end start-end frame video generation - Args: image_urls: List of start and end frame image URLs prompt: Video generation prompt - quality: Output mode, "quality" for quality priority, "speed" for speed priority - with_audio: Whether to include audio + duration: Video duration in seconds size: Video resolution - fps: Frame rate + movement_amplitude: Movement amplitude (e.g., "auto") + quality: Output mode + with_audio: Whether to include audio max_wait_time: Maximum wait time (seconds) """ print("=== viduq1-start-end Start-End Frame Video ===") try: response = self.client.videos.generations( model="viduq1-start-end", - image_urls=image_urls, + image_url=image_urls, prompt=prompt, + duration=duration, + size=size, + movement_amplitude=movement_amplitude, quality=quality, with_audio=with_audio, - size=size, - fps=fps, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -277,22 +276,23 @@ class VideoModelsExamples: self, image_url: str, prompt: str, - quality: str = "quality", + duration: int = 4, + size: str = "1280x720", + movement_amplitude: str = "auto", with_audio: bool = True, - size: str = "1920x1080", - fps: int = 30, + quality: str = None, max_wait_time: int = 300, ): """ vidu2-image image-to-video generation - Args: image_url: Image URL or Base64 encoding prompt: Video generation prompt - quality: Output mode, "quality" for quality priority, "speed" for speed priority - with_audio: Whether to include audio + duration: Video duration in seconds size: Video resolution - fps: Frame rate + movement_amplitude: Movement amplitude (e.g., "auto") + with_audio: Whether to include audio + quality: Output mode max_wait_time: Maximum wait time (seconds) """ print("=== vidu2-image Image-to-Video ===") @@ -301,10 +301,11 @@ class VideoModelsExamples: model="vidu2-image", image_url=image_url, prompt=prompt, - quality=quality, - with_audio=with_audio, + duration=duration, size=size, - fps=fps, + movement_amplitude=movement_amplitude, + with_audio=with_audio, + quality=quality, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -315,34 +316,36 @@ class VideoModelsExamples: self, image_urls: List[str], prompt: str, - quality: str = "quality", + duration: int = 4, + size: str = "1280x720", + movement_amplitude: str = "auto", with_audio: bool = True, - size: str = "1920x1080", - fps: int = 30, + quality: str = None, max_wait_time: int = 300, ): """ vidu2-start-end start-end frame video generation - Args: image_urls: List of start and end frame image URLs prompt: Video generation prompt - quality: Output mode, "quality" for quality priority, "speed" for speed priority - with_audio: Whether to include audio + duration: Video duration in seconds size: Video resolution - fps: Frame rate + movement_amplitude: Movement amplitude (e.g., "auto") + with_audio: Whether to include audio + quality: Output mode max_wait_time: Maximum wait time (seconds) """ print("=== vidu2-start-end Start-End Frame Video ===") try: response = self.client.videos.generations( model="vidu2-start-end", - image_urls=image_urls, + image_url=image_urls, prompt=prompt, - quality=quality, - with_audio=with_audio, + duration=duration, size=size, - fps=fps, + movement_amplitude=movement_amplitude, + with_audio=with_audio, + quality=quality, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -351,24 +354,27 @@ class VideoModelsExamples: async def vidu2_reference_video( self, - image_url: str, + image_url: List[str], prompt: str, - quality: str = "quality", + duration: int = 4, + aspect_ratio: str = "16:9", + size: str = "1280x720", + movement_amplitude: str = "auto", with_audio: bool = True, - size: str = "1920x1080", - fps: int = 30, + quality: str = None, max_wait_time: int = 300, ): """ vidu2-reference reference video generation - Args: - image_url: Reference video URL + image_url: Reference image URLs prompt: Video generation prompt - quality: Output mode, "quality" for quality priority, "speed" for speed priority - with_audio: Whether to include audio + duration: Video duration in seconds + aspect_ratio: Aspect ratio (e.g., "16:9") size: Video resolution - fps: Frame rate + movement_amplitude: Movement amplitude (e.g., "auto") + with_audio: Whether to include audio + quality: Output mode max_wait_time: Maximum wait time (seconds) """ print("=== vidu2-reference Reference Video Generation ===") @@ -377,10 +383,12 @@ class VideoModelsExamples: model="vidu2-reference", image_url=image_url, prompt=prompt, - quality=quality, - with_audio=with_audio, + duration=duration, + aspect_ratio=aspect_ratio, size=size, - fps=fps, + movement_amplitude=movement_amplitude, + with_audio=with_audio, + quality=quality, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -426,7 +434,7 @@ class VideoModelsExamples: # Usage examples async def main(): # Please fill in your API Key - examples = VideoModelsExamples(api_key) + examples = VideoModelsExamples() # Sample image and video URLs (please replace with actual URLs) sample_image_url = "https://i0.sinaimg.cn/edu/2011/1125/U4999P42DT20111125164101.jpg" @@ -461,7 +469,7 @@ async def main(): # 3. cogvideox-3 start-end frame video print("\n" + "="*50) result3 = await examples.cogvideox3_start_end_video( - image_urls=[sample_first_frame, sample_last_frame], + image_url=[sample_first_frame, sample_last_frame], prompt="Make the scene come alive", quality="speed", with_audio=True, @@ -483,6 +491,11 @@ async def main(): print("\n" + "="*50) result5 = await examples.viduq1_text_to_video( prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", + style="general", + duration=5, + aspect_ratio="16:9", + size="1920x1080", + movement_amplitude="auto", quality="speed", with_audio=True, ) @@ -493,6 +506,9 @@ async def main(): result6 = await examples.viduq1_image_to_video( image_url=sample_image_url, prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", + duration=5, + size="1920x1080", + movement_amplitude="auto", quality="speed", with_audio=True, ) @@ -503,6 +519,9 @@ async def main(): result7 = await examples.viduq1_start_end_video( image_url=[sample_first_frame, sample_last_frame], prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", + duration=5, + size="1920x1080", + movement_amplitude="auto", quality="speed", with_audio=True, ) @@ -513,8 +532,11 @@ async def main(): result8 = await examples.vidu2_image_to_video( image_url=sample_image_url, prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", - quality="speed", + duration=4, + size="1280x720", + movement_amplitude="auto", with_audio=True, + quality="speed", ) print("vidu2-image image-to-video result:", result8) @@ -523,8 +545,11 @@ async def main(): result9 = await examples.vidu2_start_end_video( image_url=[sample_first_frame, sample_last_frame], prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", - quality="speed", + duration=4, + size="1280x720", + movement_amplitude="auto", with_audio=True, + quality="speed", ) print("vidu2-start-end start-end frame video result:", result9) @@ -533,8 +558,12 @@ async def main(): result10 = await examples.vidu2_reference_video( image_url=ref_image_url, prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", - quality="speed", + duration=4, + aspect_ratio="16:9", + size="1280x720", + movement_amplitude="auto", with_audio=True, + quality="speed", ) print("vidu2-reference reference video generation result:", result10) except Exception as e: diff --git a/examples/web_search_example.py b/examples/web_search_example.py index 5488416..e06901c 100644 --- a/examples/web_search_example.py +++ b/examples/web_search_example.py @@ -1,21 +1,10 @@ import os +from pydoc import cli from zai import ZaiClient -# Try to load .env file -try: - from dotenv import load_dotenv - load_dotenv() -except ImportError: - pass - -api_key = os.getenv('ZAI_API_KEY') -if not api_key: - print("Please set the ZAI_API_KEY environment variable or configure it in the .env file") - exit() - -client = ZaiClient(api_key=api_key) def web_search_example(): + client = ZaiClient() response = client.web_search.web_search( search_engine="search_pro", search_query="Search for financial news in April 2025", diff --git a/src/zai/api_resource/videos/videos.py b/src/zai/api_resource/videos/videos.py index 4328cd5..fc0298d 100644 --- a/src/zai/api_resource/videos/videos.py +++ b/src/zai/api_resource/videos/videos.py @@ -31,15 +31,18 @@ class Videos(BaseAPI): def generations( self, - model: str, *, + model: str, prompt: str = None, - image_url: str | List[str] | None = None, + image_url: str | List[str] | dict | None = None, quality: str = None, with_audio: bool = None, size: str = None, duration: int = None, fps: int = None, + style: str = None, + aspect_ratio: str = None, + movement_amplitude: str = None, sensitive_word_check: Optional[SensitiveWordCheckRequest] | NotGiven = NOT_GIVEN, request_id: str = None, user_id: str = None, @@ -53,12 +56,15 @@ class Videos(BaseAPI): Arguments: model (str): The model to use for video generation prompt (str): Text description for video generation - image_url (str): URL of image to use as video input - quality (str): Quality level of the generated video + image_url (str | List[str] | dict): Image(s) for video generation (URL, Base64, or object) + quality (str): Output mode, "quality" or "speed" with_audio (bool): Whether to include audio in the video size (str): Size/resolution of the generated video duration (int): Duration of the video in seconds fps (int): Frames per second for the video + style (str): Style, e.g., "general", "anime" + aspect_ratio (str): Aspect ratio, e.g., "16:9", "9:16", "1:1" + movement_amplitude (str): Movement amplitude, e.g., "auto", "small", "medium", "large" sensitive_word_check (Optional[SensitiveWordCheckRequest]): Sensitive word check configuration request_id (str): Unique identifier for the request user_id (str): User identifier @@ -66,21 +72,24 @@ class Videos(BaseAPI): extra_body (Body): Additional body parameters timeout (float | httpx.Timeout): Request timeout """ - if not model and not model: - raise ValueError('At least one of `model` and `prompt` must be provided.') + if not model: + raise ValueError('`model` must be provided.') body = deepcopy_minimal( { 'model': model, 'prompt': prompt, 'image_url': image_url, - 'sensitive_word_check': sensitive_word_check, - 'request_id': request_id, - 'user_id': user_id, 'quality': quality, 'with_audio': with_audio, 'size': size, 'duration': duration, 'fps': fps, + 'style': style, + 'aspect_ratio': aspect_ratio, + 'movement_amplitude': movement_amplitude, + 'sensitive_word_check': sensitive_word_check, + 'request_id': request_id, + 'user_id': user_id, } ) return self._post( diff --git a/src/zai/types/video/video_create_params.py b/src/zai/types/video/video_create_params.py index 45307cb..0b66c44 100644 --- a/src/zai/types/video/video_create_params.py +++ b/src/zai/types/video/video_create_params.py @@ -14,7 +14,15 @@ class VideoCreateParams(TypedDict, total=False): Attributes: model (str): Model encoding prompt (str): Text description of the desired video - image_url (str): Image URL for image-to-video generation (supports URL or Base64 format) + image_url (str | list | dict): Image URL(s) or object for image-to-video generation (supports URL, Base64, or object) + quality (str): Output mode, "quality" or "speed" + with_audio (bool): Whether to include audio in the video + size (str): Size/resolution of the generated video + duration (int): Duration of the video in seconds + fps (int): Frames per second for the video + style (str): Style, e.g., "general", "anime" + aspect_ratio (str): Aspect ratio, e.g., "16:9", "9:16", "1:1" + movement_amplitude (str): Movement amplitude, e.g., "auto", "small", "medium", "large" sensitive_word_check (Optional[SensitiveWordCheckRequest]): Sensitive word check configuration request_id (str): Request ID passed by client, must be unique; used to distinguish each request, platform will generate default if not provided by client @@ -22,7 +30,15 @@ class VideoCreateParams(TypedDict, total=False): """ model: str prompt: str - image_url: str + image_url: str | list | dict + quality: str + with_audio: bool + size: str + duration: int + fps: int + style: str + aspect_ratio: str + movement_amplitude: str sensitive_word_check: Optional[SensitiveWordCheckRequest] request_id: str user_id: str From 42a921e770f5dc56d52ab4c2e9517cd965b13b15 Mon Sep 17 00:00:00 2001 From: wellenzheng <40078093+wellenzheng@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:36:48 +0800 Subject: [PATCH 2/6] fix: video params (#11) Co-authored-by: zhengweijun --- examples/video_models_examples.py | 41 +++---------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/examples/video_models_examples.py b/examples/video_models_examples.py index 38e99a3..f73f2d4 100644 --- a/examples/video_models_examples.py +++ b/examples/video_models_examples.py @@ -157,8 +157,6 @@ class VideoModelsExamples: aspect_ratio: str = "16:9", size: str = "1920x1080", movement_amplitude: str = "auto", - quality: str = None, - with_audio: bool = None, max_wait_time: int = 300, ): """ @@ -184,8 +182,6 @@ class VideoModelsExamples: aspect_ratio=aspect_ratio, size=size, movement_amplitude=movement_amplitude, - quality=quality, - with_audio=with_audio, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -199,8 +195,6 @@ class VideoModelsExamples: duration: int = 5, size: str = "1920x1080", movement_amplitude: str = "auto", - quality: str = None, - with_audio: bool = None, max_wait_time: int = 300, ): """ @@ -224,8 +218,6 @@ class VideoModelsExamples: duration=duration, size=size, movement_amplitude=movement_amplitude, - quality=quality, - with_audio=with_audio, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -239,8 +231,6 @@ class VideoModelsExamples: duration: int = 5, size: str = "1920x1080", movement_amplitude: str = "auto", - quality: str = None, - with_audio: bool = None, max_wait_time: int = 300, ): """ @@ -264,8 +254,6 @@ class VideoModelsExamples: duration=duration, size=size, movement_amplitude=movement_amplitude, - quality=quality, - with_audio=with_audio, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -279,8 +267,6 @@ class VideoModelsExamples: duration: int = 4, size: str = "1280x720", movement_amplitude: str = "auto", - with_audio: bool = True, - quality: str = None, max_wait_time: int = 300, ): """ @@ -304,8 +290,6 @@ class VideoModelsExamples: duration=duration, size=size, movement_amplitude=movement_amplitude, - with_audio=with_audio, - quality=quality, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -319,8 +303,6 @@ class VideoModelsExamples: duration: int = 4, size: str = "1280x720", movement_amplitude: str = "auto", - with_audio: bool = True, - quality: str = None, max_wait_time: int = 300, ): """ @@ -344,8 +326,6 @@ class VideoModelsExamples: duration=duration, size=size, movement_amplitude=movement_amplitude, - with_audio=with_audio, - quality=quality, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -360,9 +340,8 @@ class VideoModelsExamples: aspect_ratio: str = "16:9", size: str = "1280x720", movement_amplitude: str = "auto", - with_audio: bool = True, - quality: str = None, max_wait_time: int = 300, + with_audio: bool = True, ): """ vidu2-reference reference video generation @@ -388,7 +367,6 @@ class VideoModelsExamples: size=size, movement_amplitude=movement_amplitude, with_audio=with_audio, - quality=quality, ) return await self._wait_for_completion(response.id, max_wait_time) except Exception as e: @@ -469,7 +447,7 @@ async def main(): # 3. cogvideox-3 start-end frame video print("\n" + "="*50) result3 = await examples.cogvideox3_start_end_video( - image_url=[sample_first_frame, sample_last_frame], + image_urls=[sample_first_frame, sample_last_frame], prompt="Make the scene come alive", quality="speed", with_audio=True, @@ -496,8 +474,6 @@ async def main(): aspect_ratio="16:9", size="1920x1080", movement_amplitude="auto", - quality="speed", - with_audio=True, ) print("viduq1-text text-to-video result:", result5) @@ -509,21 +485,17 @@ async def main(): duration=5, size="1920x1080", movement_amplitude="auto", - quality="speed", - with_audio=True, ) print("viduq1-image image-to-video result:", result6) # 7. viduq1-start-end start-end frame video print("\n" + "="*50) result7 = await examples.viduq1_start_end_video( - image_url=[sample_first_frame, sample_last_frame], + image_urls=[sample_first_frame, sample_last_frame], prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", duration=5, size="1920x1080", movement_amplitude="auto", - quality="speed", - with_audio=True, ) print("viduq1-start-end start-end frame video result:", result7) @@ -535,21 +507,17 @@ async def main(): duration=4, size="1280x720", movement_amplitude="auto", - with_audio=True, - quality="speed", ) print("vidu2-image image-to-video result:", result8) # 9. vidu2-start-end start-end frame video print("\n" + "="*50) result9 = await examples.vidu2_start_end_video( - image_url=[sample_first_frame, sample_last_frame], + image_urls=[sample_first_frame, sample_last_frame], prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", duration=4, size="1280x720", movement_amplitude="auto", - with_audio=True, - quality="speed", ) print("vidu2-start-end start-end frame video result:", result9) @@ -563,7 +531,6 @@ async def main(): size="1280x720", movement_amplitude="auto", with_audio=True, - quality="speed", ) print("vidu2-reference reference video generation result:", result10) except Exception as e: From ee0a2b3e4cf3a3acf2af90d141fb9d534d29b384 Mon Sep 17 00:00:00 2001 From: wellenzheng <40078093+wellenzheng@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:53:32 +0800 Subject: [PATCH 3/6] feat: switchtozhipu (#12) Co-authored-by: zhengweijun --- examples/basic_usage.py | 12 +++++++++++- src/zai/_client.py | 9 +++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 00d6635..ca0072a 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -158,11 +158,21 @@ def audio_transcription(): ) print(response.text) +def ofZhipu(): + client = ZaiClient() + response = client.zhipu.chat.completions.create( + model='glm-4', + messages=[{'role': 'user', 'content': 'Hello, Z.ai!'}], + temperature=0.7, + ) + print(response.choices[0].message.content) if __name__ == '__main__': - completion() + # completion() # completion_with_websearch() # multi_modal_chat() # role_play() # assistant_conversation() # video_generation() + ofZhipu() + diff --git a/src/zai/_client.py b/src/zai/_client.py index 53835bd..ce2a591 100644 --- a/src/zai/_client.py +++ b/src/zai/_client.py @@ -62,7 +62,6 @@ class ZaiClient(HttpClient): disable_token_cache: bool = True, _strict_response_validation: bool = False, source_channel: str | None = None, - switch_to_zhipu: bool = False, ) -> None: """ Initialize the ZAI client @@ -79,7 +78,6 @@ class ZaiClient(HttpClient): disable_token_cache (bool): Whether to disable JWT token caching _strict_response_validation (bool): Whether to enable strict response validation source_channel (str | None): Source channel identifier - switch_to_zhipu (bool): Whether to switch to Zhipu base_url """ if api_key is None: api_key = os.environ.get('ZAI_API_KEY') @@ -93,8 +91,6 @@ class ZaiClient(HttpClient): base_url = os.environ.get('ZAI_BASE_URL') if base_url is None: base_url = 'https://api.z.ai/api/paas/v4' - if switch_to_zhipu: - base_url = 'https://open.bigmodel.cn/api/paas/v4' from ._version import __version__ super().__init__( @@ -107,6 +103,11 @@ class ZaiClient(HttpClient): _strict_response_validation=_strict_response_validation, ) + @cached_property + def zhipu(self): + self.base_url = 'https://open.bigmodel.cn/api/paas/v4' + return self + @cached_property def chat(self) -> Chat: from zai.api_resource.chat import Chat From b4ff07c1582cda4313f613a7d2bf33e2c91f69a1 Mon Sep 17 00:00:00 2001 From: wellenzheng <40078093+wellenzheng@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:22:48 +0800 Subject: [PATCH 4/6] feat: add zhipuclient (#13) Co-authored-by: zhengweijun --- .gitignore | 4 ++-- .vscode/settings.json | 3 --- README.md | 8 +++++++- README_CN.md | 12 ++++++++++-- examples/basic_usage.py | 20 ++++++++++++++++---- src/zai/__init__.py | 4 ++-- src/zai/_client.py | 32 +++++++++++++++++++++----------- 7 files changed, 58 insertions(+), 25 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 2b39825..818207a 100644 --- a/.gitignore +++ b/.gitignore @@ -173,7 +173,7 @@ cython_debug/ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +.idea/ # Abstra # Abstra is an AI-powered process automation framework. @@ -186,7 +186,7 @@ cython_debug/ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore # and can be added to the global gitignore or merged into this file. However, if you prefer, # you could uncomment the following to ignore the entire vscode folder -# .vscode/ +.vscode/ # Ruff stuff: .ruff_cache/ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ff5300e..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.languageServer": "None" -} \ No newline at end of file diff --git a/README.md b/README.md index 13b803e..df64fcd 100644 --- a/README.md +++ b/README.md @@ -116,12 +116,18 @@ export ZAI_BASE_URL="https://api.z.ai/api/paas/v4/" # Optional #### Code Configuration ```python -from zai import ZaiClient +from zai import ZaiClient, ZhipuAiClient client = ZaiClient( api_key="your-api-key", base_url="https://api.z.ai/api/paas/v4/" # Optional ) + +# if you want to use ZhipuAiClient +zhipu_client = ZhipuAiClient( + api_key="your-api-key", + base_url="https://open.bigmodel.cn/api/paas/v4/" # Optional +) ``` ### Advanced Configuration diff --git a/README_CN.md b/README_CN.md index 7ff2647..e0f3e5f 100644 --- a/README_CN.md +++ b/README_CN.md @@ -97,12 +97,20 @@ export ZAI_BASE_URL="https://api.z.ai/api/paas/v4/" # 可选 **代码配置:** ```python -from zai import ZaiClient +from zai import ZaiClient, ZhipuAiClient client = ZaiClient( api_key="your_api_key_here", # 填写您的 APIKey -) + base_url="https://api.z.ai/api/paas/v4/" # 可选 +) + +# if you want to use ZhipuAiClient +zhipu_client = ZhipuAiClient( + api_key="your_api_key_here", # 填写您的 APIKey + base_url="https://open.bigmodel.cn/api/paas/v4/" # 可选 +) ``` + **高级配置:** SDK提供了灵活的客户端配置选项: diff --git a/examples/basic_usage.py b/examples/basic_usage.py index ca0072a..2e3b4bd 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -1,4 +1,4 @@ -from zai import ZaiClient +from zai import ZaiClient, ZhipuAiClient def completion(): # Initialize client @@ -158,9 +158,20 @@ def audio_transcription(): ) print(response.text) +def ofZai(): + client = ZaiClient() + print(client.base_url) + response = client.chat.completions.create( + model='glm-4', + messages=[{'role': 'user', 'content': 'Hello, Z.ai!'}], + temperature=0.7, + ) + print(response.choices[0].message.content) + def ofZhipu(): - client = ZaiClient() - response = client.zhipu.chat.completions.create( + client = ZhipuAiClient() + print(client.base_url) + response = client.chat.completions.create( model='glm-4', messages=[{'role': 'user', 'content': 'Hello, Z.ai!'}], temperature=0.7, @@ -174,5 +185,6 @@ if __name__ == '__main__': # role_play() # assistant_conversation() # video_generation() + ofZai() ofZhipu() - + diff --git a/src/zai/__init__.py b/src/zai/__init__.py index e09fefe..f362804 100644 --- a/src/zai/__init__.py +++ b/src/zai/__init__.py @@ -1,4 +1,4 @@ -from ._client import ZaiClient +from ._client import ZaiClient, ZhipuAiClient from ._version import __version__ -__all__ = ['ZaiClient', '__version__'] +__all__ = ['ZaiClient', 'ZhipuAiClient', '__version__'] diff --git a/src/zai/_client.py b/src/zai/_client.py index ce2a591..5f911bb 100644 --- a/src/zai/_client.py +++ b/src/zai/_client.py @@ -33,8 +33,7 @@ from .core import ( _jwt_token, ) - -class ZaiClient(HttpClient): +class BaseClient(HttpClient): """ Main client for interacting with the ZAI API @@ -47,7 +46,8 @@ class ZaiClient(HttpClient): chat: Chat api_key: str - _disable_token_cache: bool = True + base_url: str + disable_token_cache: bool = True source_channel: str def __init__( @@ -85,14 +85,15 @@ class ZaiClient(HttpClient): raise ZaiError('api_key not provided, please provide it through parameters or environment variables') self.api_key = api_key self.source_channel = source_channel - self._disable_token_cache = disable_token_cache + self.disable_token_cache = disable_token_cache if base_url is None: base_url = os.environ.get('ZAI_BASE_URL') if base_url is None: - base_url = 'https://api.z.ai/api/paas/v4' - from ._version import __version__ + base_url = self.default_base_url + self.base_url = base_url + from ._version import __version__ super().__init__( version=__version__, base_url=base_url, @@ -103,10 +104,9 @@ class ZaiClient(HttpClient): _strict_response_validation=_strict_response_validation, ) - @cached_property - def zhipu(self): - self.base_url = 'https://open.bigmodel.cn/api/paas/v4' - return self + @property + def default_base_url(self): + raise NotImplementedError("Subclasses must define default_base_url") @cached_property def chat(self) -> Chat: @@ -197,7 +197,7 @@ class ZaiClient(HttpClient): def auth_headers(self) -> dict[str, str]: api_key = self.api_key source_channel = self.source_channel or 'python-sdk' - if self._disable_token_cache: + if self.disable_token_cache: return { 'Authorization': f'Bearer {api_key}', 'x-source-channel': source_channel, @@ -217,3 +217,13 @@ class ZaiClient(HttpClient): return self.close() + +class ZaiClient(BaseClient): + @property + def default_base_url(self): + return 'https://api.z.ai/api/paas/v4' + +class ZhipuAiClient(BaseClient): + @property + def default_base_url(self): + return 'https://open.bigmodel.cn/api/paas/v4' \ No newline at end of file From eb49b8c06ce65a0ec4e50b9764763335f0c6b52b Mon Sep 17 00:00:00 2001 From: wellenzheng <40078093+wellenzheng@users.noreply.github.com> Date: Wed, 23 Jul 2025 17:04:00 +0800 Subject: [PATCH 5/6] fix: improve type hint for image_url in video_create_params.py (#14) Co-authored-by: zhengweijun --- examples/check_apikey_env.py | 3 +-- examples/video_models_examples.py | 7 ++++++- src/zai/types/video/video_create_params.py | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/check_apikey_env.py b/examples/check_apikey_env.py index 23b8f69..5d06d01 100644 --- a/examples/check_apikey_env.py +++ b/examples/check_apikey_env.py @@ -1,6 +1,5 @@ import os - def check_apikey(): api_key = os.getenv('ZAI_API_KEY') if api_key and api_key.strip(): @@ -11,4 +10,4 @@ def check_apikey(): if __name__ == '__main__': - check_apikey() \ No newline at end of file + check_apikey() \ No newline at end of file diff --git a/examples/video_models_examples.py b/examples/video_models_examples.py index f73f2d4..981e709 100644 --- a/examples/video_models_examples.py +++ b/examples/video_models_examples.py @@ -418,7 +418,11 @@ async def main(): sample_image_url = "https://i0.sinaimg.cn/edu/2011/1125/U4999P42DT20111125164101.jpg" sample_first_frame = "https://gd-hbimg.huaban.com/ccee58d77afe8f5e17a572246b1994f7e027657fe9e6-qD66In_fw1200webp" sample_last_frame = "https://gd-hbimg.huaban.com/cc2601d568a72d18d90b2cc7f1065b16b2d693f7fa3f7-hDAwNq_fw1200webp" - ref_image_url = ["ref1", "ref2", "ref3"] + ref_image_url = [ + "https://gd-hbimg.huaban.com/ccee58d77afe8f5e17a572246b1994f7e027657fe9e6-qD66In_fw1200webp", + "https://gd-hbimg.huaban.com/cc2601d568a72d18d90b2cc7f1065b16b2d693f7fa3f7-hDAwNq_fw1200webp", + "https://gd-hbimg.huaban.com/cc2601d568a72d18d90b2cc7f1065b16b2d693f7fa3f7-hDAwNq_fw1200webp" + ] try: # 1. cogvideox-3 text-to-video @@ -467,6 +471,7 @@ async def main(): # 5. viduq1-text text-to-video print("\n" + "="*50) + print(os.environ.get("ZAI_API_KEY")) result5 = await examples.viduq1_text_to_video( prompt="Peter Rabbit driving a car, wandering on the road, with a happy and joyful expression on his face.", style="general", diff --git a/src/zai/types/video/video_create_params.py b/src/zai/types/video/video_create_params.py index 0b66c44..197fe89 100644 --- a/src/zai/types/video/video_create_params.py +++ b/src/zai/types/video/video_create_params.py @@ -30,7 +30,7 @@ class VideoCreateParams(TypedDict, total=False): """ model: str prompt: str - image_url: str | list | dict + image_url: str | list[str] | dict quality: str with_audio: bool size: str From 010acdd2d4dae9f22da10d6ed8c80b0181cd3cd7 Mon Sep 17 00:00:00 2001 From: wellenzheng <40078093+wellenzheng@users.noreply.github.com> Date: Wed, 23 Jul 2025 17:47:00 +0800 Subject: [PATCH 6/6] feat: update version to 0.0.1b2 in pyproject.toml (#15) Co-authored-by: zhengweijun --- Release-Note.md | 4 ++-- pyproject.toml | 2 +- src/zai/_version.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Release-Note.md b/Release-Note.md index 4c17c7d..cefed25 100644 --- a/Release-Note.md +++ b/Release-Note.md @@ -1,6 +1,6 @@ # Release Notes -## v0.0.1b1 - Major Enhancements & Restructuring (2025-07-22) +## v0.0.1b2 - Major Enhancements & Restructuring (2025-07-22) 🚀 **A comprehensive update focusing on developer experience, code organization, and expanded examples!** @@ -311,7 +311,7 @@ This initial release establishes the foundation for Z.ai's Python SDK. Future re ## Migration Guide -### From v0.0.1a1 to v0.0.1b1 +### From v0.0.1a1 to v0.0.1b2 *No breaking changes - all existing code continues to work!* **Optional Enhancements:** diff --git a/pyproject.toml b/pyproject.toml index 6d0c50f..e85f1bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "zai-sdk" -version = "0.0.1b1" +version = "0.0.1b2" description = "A SDK library for accessing big model apis from Z.ai" authors = ["Z.ai"] readme = "README.md" diff --git a/src/zai/_version.py b/src/zai/_version.py index 63a75a6..0fecd85 100644 --- a/src/zai/_version.py +++ b/src/zai/_version.py @@ -1,2 +1,2 @@ __title__ = 'Z.ai' -__version__ = '0.0.1b1' +__version__ = '0.0.1b2'