camel-ai 0.2.67__py3-none-any.whl → 0.2.80a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/_types.py +6 -2
  3. camel/agents/_utils.py +38 -0
  4. camel/agents/chat_agent.py +4014 -410
  5. camel/agents/mcp_agent.py +30 -27
  6. camel/agents/repo_agent.py +2 -1
  7. camel/benchmarks/browsecomp.py +6 -6
  8. camel/configs/__init__.py +15 -0
  9. camel/configs/aihubmix_config.py +88 -0
  10. camel/configs/amd_config.py +70 -0
  11. camel/configs/cometapi_config.py +104 -0
  12. camel/configs/minimax_config.py +93 -0
  13. camel/configs/nebius_config.py +103 -0
  14. camel/configs/vllm_config.py +2 -0
  15. camel/data_collectors/alpaca_collector.py +15 -6
  16. camel/datagen/self_improving_cot.py +1 -1
  17. camel/datasets/base_generator.py +39 -10
  18. camel/environments/__init__.py +12 -0
  19. camel/environments/rlcards_env.py +860 -0
  20. camel/environments/single_step.py +28 -3
  21. camel/environments/tic_tac_toe.py +1 -1
  22. camel/interpreters/__init__.py +2 -0
  23. camel/interpreters/docker/Dockerfile +4 -16
  24. camel/interpreters/docker_interpreter.py +3 -2
  25. camel/interpreters/e2b_interpreter.py +34 -1
  26. camel/interpreters/internal_python_interpreter.py +51 -2
  27. camel/interpreters/microsandbox_interpreter.py +395 -0
  28. camel/loaders/__init__.py +11 -2
  29. camel/loaders/base_loader.py +85 -0
  30. camel/loaders/chunkr_reader.py +9 -0
  31. camel/loaders/firecrawl_reader.py +4 -4
  32. camel/logger.py +1 -1
  33. camel/memories/agent_memories.py +84 -1
  34. camel/memories/base.py +34 -0
  35. camel/memories/blocks/chat_history_block.py +122 -4
  36. camel/memories/blocks/vectordb_block.py +8 -1
  37. camel/memories/context_creators/score_based.py +29 -237
  38. camel/memories/records.py +88 -8
  39. camel/messages/base.py +166 -40
  40. camel/messages/func_message.py +32 -5
  41. camel/models/__init__.py +10 -0
  42. camel/models/aihubmix_model.py +83 -0
  43. camel/models/aiml_model.py +1 -16
  44. camel/models/amd_model.py +101 -0
  45. camel/models/anthropic_model.py +117 -18
  46. camel/models/aws_bedrock_model.py +2 -33
  47. camel/models/azure_openai_model.py +205 -91
  48. camel/models/base_audio_model.py +3 -1
  49. camel/models/base_model.py +189 -24
  50. camel/models/cohere_model.py +5 -17
  51. camel/models/cometapi_model.py +83 -0
  52. camel/models/crynux_model.py +1 -16
  53. camel/models/deepseek_model.py +6 -16
  54. camel/models/fish_audio_model.py +6 -0
  55. camel/models/gemini_model.py +71 -20
  56. camel/models/groq_model.py +1 -17
  57. camel/models/internlm_model.py +1 -16
  58. camel/models/litellm_model.py +49 -32
  59. camel/models/lmstudio_model.py +1 -17
  60. camel/models/minimax_model.py +83 -0
  61. camel/models/mistral_model.py +1 -16
  62. camel/models/model_factory.py +27 -1
  63. camel/models/model_manager.py +24 -6
  64. camel/models/modelscope_model.py +1 -16
  65. camel/models/moonshot_model.py +185 -19
  66. camel/models/nebius_model.py +83 -0
  67. camel/models/nemotron_model.py +0 -5
  68. camel/models/netmind_model.py +1 -16
  69. camel/models/novita_model.py +1 -16
  70. camel/models/nvidia_model.py +1 -16
  71. camel/models/ollama_model.py +4 -19
  72. camel/models/openai_compatible_model.py +171 -46
  73. camel/models/openai_model.py +205 -77
  74. camel/models/openrouter_model.py +1 -17
  75. camel/models/ppio_model.py +1 -16
  76. camel/models/qianfan_model.py +1 -16
  77. camel/models/qwen_model.py +1 -16
  78. camel/models/reka_model.py +1 -16
  79. camel/models/samba_model.py +34 -47
  80. camel/models/sglang_model.py +64 -31
  81. camel/models/siliconflow_model.py +1 -16
  82. camel/models/stub_model.py +0 -4
  83. camel/models/togetherai_model.py +1 -16
  84. camel/models/vllm_model.py +1 -16
  85. camel/models/volcano_model.py +0 -17
  86. camel/models/watsonx_model.py +1 -16
  87. camel/models/yi_model.py +1 -16
  88. camel/models/zhipuai_model.py +60 -16
  89. camel/parsers/__init__.py +18 -0
  90. camel/parsers/mcp_tool_call_parser.py +176 -0
  91. camel/retrievers/auto_retriever.py +1 -0
  92. camel/runtimes/configs.py +11 -11
  93. camel/runtimes/daytona_runtime.py +15 -16
  94. camel/runtimes/docker_runtime.py +6 -6
  95. camel/runtimes/remote_http_runtime.py +5 -5
  96. camel/services/agent_openapi_server.py +380 -0
  97. camel/societies/__init__.py +2 -0
  98. camel/societies/role_playing.py +26 -28
  99. camel/societies/workforce/__init__.py +2 -0
  100. camel/societies/workforce/events.py +122 -0
  101. camel/societies/workforce/prompts.py +249 -38
  102. camel/societies/workforce/role_playing_worker.py +82 -20
  103. camel/societies/workforce/single_agent_worker.py +634 -34
  104. camel/societies/workforce/structured_output_handler.py +512 -0
  105. camel/societies/workforce/task_channel.py +169 -23
  106. camel/societies/workforce/utils.py +176 -9
  107. camel/societies/workforce/worker.py +77 -23
  108. camel/societies/workforce/workflow_memory_manager.py +772 -0
  109. camel/societies/workforce/workforce.py +3168 -478
  110. camel/societies/workforce/workforce_callback.py +74 -0
  111. camel/societies/workforce/workforce_logger.py +203 -175
  112. camel/societies/workforce/workforce_metrics.py +33 -0
  113. camel/storages/__init__.py +4 -0
  114. camel/storages/key_value_storages/json.py +15 -2
  115. camel/storages/key_value_storages/mem0_cloud.py +48 -47
  116. camel/storages/object_storages/google_cloud.py +1 -1
  117. camel/storages/vectordb_storages/__init__.py +6 -0
  118. camel/storages/vectordb_storages/chroma.py +731 -0
  119. camel/storages/vectordb_storages/oceanbase.py +13 -13
  120. camel/storages/vectordb_storages/pgvector.py +349 -0
  121. camel/storages/vectordb_storages/qdrant.py +3 -3
  122. camel/storages/vectordb_storages/surreal.py +365 -0
  123. camel/storages/vectordb_storages/tidb.py +8 -6
  124. camel/tasks/task.py +244 -27
  125. camel/toolkits/__init__.py +46 -8
  126. camel/toolkits/aci_toolkit.py +64 -19
  127. camel/toolkits/arxiv_toolkit.py +6 -6
  128. camel/toolkits/base.py +63 -5
  129. camel/toolkits/code_execution.py +28 -1
  130. camel/toolkits/context_summarizer_toolkit.py +684 -0
  131. camel/toolkits/craw4ai_toolkit.py +93 -0
  132. camel/toolkits/dappier_toolkit.py +10 -6
  133. camel/toolkits/dingtalk.py +1135 -0
  134. camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
  135. camel/toolkits/excel_toolkit.py +901 -67
  136. camel/toolkits/file_toolkit.py +1402 -0
  137. camel/toolkits/function_tool.py +30 -6
  138. camel/toolkits/github_toolkit.py +107 -20
  139. camel/toolkits/gmail_toolkit.py +1839 -0
  140. camel/toolkits/google_calendar_toolkit.py +38 -4
  141. camel/toolkits/google_drive_mcp_toolkit.py +54 -0
  142. camel/toolkits/human_toolkit.py +34 -10
  143. camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
  144. camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
  145. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
  146. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1973 -0
  147. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  148. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +3749 -0
  149. camel/toolkits/hybrid_browser_toolkit/ts/package.json +32 -0
  150. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
  151. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1815 -0
  152. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
  153. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +590 -0
  154. camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
  155. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  156. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  157. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  158. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +130 -0
  159. camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +26 -0
  160. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
  161. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1032 -0
  162. camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
  163. camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
  164. camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
  165. camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
  166. camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
  167. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
  168. camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
  169. camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
  170. camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
  171. camel/toolkits/image_generation_toolkit.py +390 -0
  172. camel/toolkits/jina_reranker_toolkit.py +3 -4
  173. camel/toolkits/klavis_toolkit.py +5 -1
  174. camel/toolkits/markitdown_toolkit.py +104 -0
  175. camel/toolkits/math_toolkit.py +64 -10
  176. camel/toolkits/mcp_toolkit.py +370 -45
  177. camel/toolkits/memory_toolkit.py +5 -1
  178. camel/toolkits/message_agent_toolkit.py +608 -0
  179. camel/toolkits/message_integration.py +724 -0
  180. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  181. camel/toolkits/note_taking_toolkit.py +277 -0
  182. camel/toolkits/notion_mcp_toolkit.py +224 -0
  183. camel/toolkits/openbb_toolkit.py +5 -1
  184. camel/toolkits/origene_mcp_toolkit.py +56 -0
  185. camel/toolkits/playwright_mcp_toolkit.py +12 -31
  186. camel/toolkits/pptx_toolkit.py +25 -12
  187. camel/toolkits/resend_toolkit.py +168 -0
  188. camel/toolkits/screenshot_toolkit.py +213 -0
  189. camel/toolkits/search_toolkit.py +437 -142
  190. camel/toolkits/slack_toolkit.py +104 -50
  191. camel/toolkits/sympy_toolkit.py +1 -1
  192. camel/toolkits/task_planning_toolkit.py +3 -3
  193. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  194. camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
  195. camel/toolkits/terminal_toolkit/utils.py +532 -0
  196. camel/toolkits/thinking_toolkit.py +1 -1
  197. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  198. camel/toolkits/video_analysis_toolkit.py +106 -26
  199. camel/toolkits/video_download_toolkit.py +17 -14
  200. camel/toolkits/web_deploy_toolkit.py +1219 -0
  201. camel/toolkits/wechat_official_toolkit.py +483 -0
  202. camel/toolkits/zapier_toolkit.py +5 -1
  203. camel/types/__init__.py +2 -2
  204. camel/types/agents/tool_calling_record.py +4 -1
  205. camel/types/enums.py +316 -40
  206. camel/types/openai_types.py +2 -2
  207. camel/types/unified_model_type.py +31 -4
  208. camel/utils/commons.py +36 -5
  209. camel/utils/constants.py +3 -0
  210. camel/utils/context_utils.py +1003 -0
  211. camel/utils/mcp.py +138 -4
  212. camel/utils/mcp_client.py +45 -1
  213. camel/utils/message_summarizer.py +148 -0
  214. camel/utils/token_counting.py +43 -20
  215. camel/utils/tool_result.py +44 -0
  216. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +296 -85
  217. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +219 -146
  218. camel/loaders/pandas_reader.py +0 -368
  219. camel/toolkits/dalle_toolkit.py +0 -175
  220. camel/toolkits/file_write_toolkit.py +0 -444
  221. camel/toolkits/openai_agent_toolkit.py +0 -135
  222. camel/toolkits/terminal_toolkit.py +0 -1037
  223. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
  224. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,590 @@
1
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+
15
+ import asyncio
16
+ import base64
17
+ import os
18
+ from typing import Any, Dict, List, Optional, Tuple
19
+
20
+ from camel.logger import get_logger
21
+ from camel.toolkits import FunctionTool
22
+ from camel.toolkits.base import BaseToolkit
23
+ from camel.utils import api_keys_required, dependencies_required
24
+
25
+ logger = get_logger(__name__)
26
+
27
+
28
+ @api_keys_required(
29
+ [("GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_APPLICATION_CREDENTIALS")]
30
+ )
31
+ class VertexAIVeoToolkit(BaseToolkit):
32
+ r"""A toolkit for interacting with Google Vertex AI Veo video generation.
33
+
34
+ This toolkit provides methods for generating videos using Google's Veo,
35
+ supporting both text-to-video and image-to-video generation with various
36
+ customization options.
37
+ """
38
+
39
+ @dependencies_required('google.cloud.aiplatform')
40
+ def __init__(
41
+ self,
42
+ project_id: Optional[str] = None,
43
+ location: str = "us-central1",
44
+ model_id: str = "veo-2.0-generate-001",
45
+ output_storage_uri: Optional[str] = None,
46
+ timeout: Optional[float] = None,
47
+ ) -> None:
48
+ r"""Initialize the Vertex AI Veo toolkit.
49
+
50
+ Args:
51
+ project_id (Optional[str]): Google Cloud project ID. If not
52
+ provided,
53
+ will use the default project from environment.
54
+ (default: :obj:`None`)
55
+ location (str): Google Cloud location for the API calls.
56
+ (default: :obj:`"us-central1"`)
57
+ model_id (str): The Veo model ID to use. Options include
58
+ "veo-2.0-generate-001" or "veo-3.0-generate-preview".
59
+ (default: :obj:`"veo-2.0-generate-001"`)
60
+ output_storage_uri (Optional[str]): Cloud Storage URI to save
61
+ output videos. If not provided, returns video bytes.
62
+ (default: :obj:`None`)
63
+ timeout (Optional[float]): Request timeout in seconds.
64
+ (default: :obj:`None`)
65
+ """
66
+ super().__init__(timeout)
67
+
68
+ from google.cloud import aiplatform
69
+
70
+ self.project_id = project_id or os.getenv("GOOGLE_CLOUD_PROJECT")
71
+ self.location = location
72
+ self.model_id = model_id
73
+ self.output_storage_uri = output_storage_uri
74
+
75
+ if not self.project_id:
76
+ raise ValueError(
77
+ "Project ID must be provided either as parameter or "
78
+ "GOOGLE_CLOUD_PROJECT environment variable"
79
+ )
80
+
81
+ aiplatform.init(project=self.project_id, location=self.location)
82
+ self.client = aiplatform.gapic.PredictionServiceClient()
83
+
84
+ def generate_video_from_text(
85
+ self,
86
+ text_prompt: str,
87
+ response_count: int = 1,
88
+ duration: int = 5,
89
+ aspect_ratio: str = "16:9",
90
+ negative_prompt: Optional[str] = None,
91
+ person_generation: str = "allow_adult",
92
+ ) -> Dict[str, Any]:
93
+ r"""Generate video from text prompt using Vertex AI Veo.
94
+
95
+ Args:
96
+ text_prompt (str): The text prompt to guide video generation.
97
+ response_count (int): Number of videos to generate (1-4).
98
+ (default: :obj:`1`)
99
+ duration (int): Video duration in seconds (5-8).
100
+ (default: :obj:`5`)
101
+ aspect_ratio (str): Video aspect ratio. Options: "16:9", "9:16".
102
+ (default: :obj:`"16:9"`)
103
+ negative_prompt (Optional[str]): What to avoid in the video.
104
+ (default: :obj:`None`)
105
+ person_generation (str): Person safety setting. Options:
106
+ "allow_adult", "dont_allow". (default: :obj:`"allow_adult"`)
107
+
108
+ Returns:
109
+ Dict[str, Any]:
110
+ A dictionary containing:
111
+ - 'success' (bool): Whether the operation was successful
112
+ - 'videos' (List[Dict]): List of generated video data
113
+ - 'metadata' (Dict): Additional metadata from the response
114
+ - 'error' (str): Error message if operation failed
115
+ """
116
+ try:
117
+ from google.protobuf import json_format
118
+ from google.protobuf.struct_pb2 import Value
119
+
120
+ # Construct the request
121
+ endpoint = (
122
+ f"projects/{self.project_id}/locations/{self.location}/"
123
+ f"publishers/google/models/{self.model_id}"
124
+ )
125
+
126
+ # Build parameters
127
+ parameters = {
128
+ "aspectRatio": aspect_ratio,
129
+ "personGeneration": person_generation,
130
+ }
131
+
132
+ if negative_prompt:
133
+ parameters["negativePrompt"] = negative_prompt
134
+
135
+ # Build request body
136
+ request_body = {
137
+ "contents": [
138
+ {"role": "user", "parts": [{"text": text_prompt}]}
139
+ ],
140
+ "generationConfig": {
141
+ "responseCount": response_count,
142
+ "duration": duration,
143
+ },
144
+ "parameters": parameters,
145
+ }
146
+
147
+ if self.output_storage_uri:
148
+ generation_config = request_body.setdefault(
149
+ "generationConfig", {}
150
+ )
151
+ if isinstance(generation_config, dict):
152
+ generation_config["outputStorageUri"] = (
153
+ self.output_storage_uri
154
+ )
155
+
156
+ # Convert to protobuf format
157
+ request_value = json_format.ParseDict(request_body, Value())
158
+
159
+ # Make the API call
160
+ response = self.client.predict(
161
+ endpoint=endpoint,
162
+ instances=[request_value],
163
+ timeout=self.timeout,
164
+ )
165
+
166
+ return self._parse_video_response(response)
167
+
168
+ except Exception as e:
169
+ logger.error(f"Error generating video from text: {e}")
170
+ return {"error": str(e)}
171
+
172
+ def generate_video_from_image(
173
+ self,
174
+ image_path: str,
175
+ text_prompt: str,
176
+ response_count: int = 1,
177
+ duration: int = 5,
178
+ aspect_ratio: str = "16:9",
179
+ negative_prompt: Optional[str] = None,
180
+ person_generation: str = "allow_adult",
181
+ ) -> Dict[str, Any]:
182
+ r"""Generate video from image and text prompt using Vertex AI Veo.
183
+
184
+ Args:
185
+ image_path (str): Path to the input image file (local or GCS URI).
186
+ text_prompt (str): The text prompt to guide video generation.
187
+ response_count (int): Number of videos to generate (1-4).
188
+ (default: :obj:`1`)
189
+ duration (int): Video duration in seconds (5-8).
190
+ (default: :obj:`5`)
191
+ aspect_ratio (str): Video aspect ratio. Options: "16:9", "9:16".
192
+ (default: :obj:`"16:9"`)
193
+ negative_prompt (Optional[str]): What to avoid in the video.
194
+ (default: :obj:`None`)
195
+ person_generation (str): Person safety setting.
196
+ (default: :obj:`"allow_adult"`)
197
+
198
+ Returns:
199
+ Dict[str, Any]:
200
+ A dictionary containing:
201
+ - 'success' (bool): Whether the operation was successful
202
+ - 'videos' (List[Dict]): List of generated video data
203
+ - 'metadata' (Dict): Additional metadata from the response
204
+ - 'error' (str): Error message if operation failed
205
+ """
206
+ try:
207
+ from google.protobuf import json_format
208
+ from google.protobuf.struct_pb2 import Value
209
+
210
+ # Read and encode image
211
+ image_data, mime_type = self._process_image(image_path)
212
+
213
+ # Construct the request
214
+ endpoint = (
215
+ f"projects/{self.project_id}/locations/{self.location}/"
216
+ f"publishers/google/models/{self.model_id}"
217
+ )
218
+
219
+ # Build parameters
220
+ parameters = {
221
+ "aspectRatio": aspect_ratio,
222
+ "personGeneration": person_generation,
223
+ }
224
+
225
+ if negative_prompt:
226
+ parameters["negativePrompt"] = negative_prompt
227
+
228
+ # Build request body with image
229
+ request_body = {
230
+ "contents": [
231
+ {
232
+ "role": "user",
233
+ "parts": [
234
+ {
235
+ "inlineData": {
236
+ "mimeType": mime_type,
237
+ "data": image_data,
238
+ }
239
+ },
240
+ {"text": text_prompt},
241
+ ],
242
+ }
243
+ ],
244
+ "generationConfig": {
245
+ "responseCount": response_count,
246
+ "duration": duration,
247
+ },
248
+ "parameters": parameters,
249
+ }
250
+
251
+ if self.output_storage_uri:
252
+ generation_config = request_body.setdefault(
253
+ "generationConfig", {}
254
+ )
255
+ if isinstance(generation_config, dict):
256
+ generation_config["outputStorageUri"] = (
257
+ self.output_storage_uri
258
+ )
259
+
260
+ # Convert to protobuf format
261
+ request_value = json_format.ParseDict(request_body, Value())
262
+
263
+ # Make the API call
264
+ response = self.client.predict(
265
+ endpoint=endpoint,
266
+ instances=[request_value],
267
+ timeout=self.timeout,
268
+ )
269
+
270
+ return self._parse_video_response(response)
271
+
272
+ except Exception as e:
273
+ logger.error(f"Error generating video from image: {e}")
274
+ return {"error": str(e)}
275
+
276
+ def extend_video(
277
+ self,
278
+ video_uri: str,
279
+ text_prompt: str,
280
+ duration: int = 5,
281
+ aspect_ratio: str = "16:9",
282
+ negative_prompt: Optional[str] = None,
283
+ ) -> Dict[str, Any]:
284
+ r"""Extend an existing video using Vertex AI Veo.
285
+
286
+ Args:
287
+ video_uri (str): Cloud Storage URI of the video to extend.
288
+ text_prompt (str): The text prompt to guide video extension.
289
+ duration (int): Duration to extend in seconds (5-8).
290
+ (default: :obj:`5`)
291
+ aspect_ratio (str): Video aspect ratio.
292
+ (default: :obj:`"16:9"`)
293
+ negative_prompt (Optional[str]): What to avoid in the extension.
294
+ (default: :obj:`None`)
295
+
296
+ Returns:
297
+ Dict[str, Any]:
298
+ A dictionary containing:
299
+ - 'success' (bool): Whether the operation was successful
300
+ - 'videos' (List[Dict]): List of extended video data
301
+ - 'metadata' (Dict): Additional metadata from the response
302
+ - 'error' (str): Error message if operation failed
303
+ """
304
+ try:
305
+ from google.protobuf import json_format
306
+ from google.protobuf.struct_pb2 import Value
307
+
308
+ # Construct the request
309
+ endpoint = (
310
+ f"projects/{self.project_id}/locations/{self.location}/"
311
+ f"publishers/google/models/{self.model_id}"
312
+ )
313
+
314
+ # Build parameters
315
+ parameters = {
316
+ "aspectRatio": aspect_ratio,
317
+ "videoToExtend": video_uri,
318
+ }
319
+
320
+ if negative_prompt:
321
+ parameters["negativePrompt"] = negative_prompt
322
+
323
+ # Build request body
324
+ request_body = {
325
+ "contents": [
326
+ {"role": "user", "parts": [{"text": text_prompt}]}
327
+ ],
328
+ "generationConfig": {
329
+ "duration": duration,
330
+ },
331
+ "parameters": parameters,
332
+ }
333
+
334
+ if self.output_storage_uri:
335
+ generation_config = request_body.setdefault(
336
+ "generationConfig", {}
337
+ )
338
+ if isinstance(generation_config, dict):
339
+ generation_config["outputStorageUri"] = (
340
+ self.output_storage_uri
341
+ )
342
+
343
+ # Convert to protobuf format
344
+ request_value = json_format.ParseDict(request_body, Value())
345
+
346
+ # Make the API call
347
+ response = self.client.predict(
348
+ endpoint=endpoint,
349
+ instances=[request_value],
350
+ timeout=self.timeout,
351
+ )
352
+
353
+ return self._parse_video_response(response)
354
+
355
+ except Exception as e:
356
+ logger.error(f"Error extending video: {e}")
357
+ return {"error": str(e)}
358
+
359
+ async def agenerate_video_from_text(
360
+ self,
361
+ text_prompt: str,
362
+ response_count: int = 1,
363
+ duration: int = 5,
364
+ aspect_ratio: str = "16:9",
365
+ negative_prompt: Optional[str] = None,
366
+ person_generation: str = "allow_adult",
367
+ ) -> Dict[str, Any]:
368
+ r"""Generate video from text prompt using Vertex AI Veo.
369
+
370
+ Args:
371
+ text_prompt (str): The text prompt to guide video generation.
372
+ response_count (int): Number of videos to generate (1-4).
373
+ (default: :obj:`1`)
374
+ duration (int): Video duration in seconds (5-8).
375
+ (default: :obj:`5`)
376
+ aspect_ratio (str): Video aspect ratio. Options: "16:9", "9:16".
377
+ (default: :obj:`"16:9"`)
378
+ negative_prompt (Optional[str]): What to avoid in the video.
379
+ (default: :obj:`None`)
380
+ person_generation (str): Person safety setting. Options:
381
+ "allow_adult", "dont_allow". (default: :obj:`"allow_adult"`)
382
+
383
+ Returns:
384
+ Dict[str, Any]:
385
+ A dictionary containing:
386
+ - 'success' (bool): Whether the operation was successful
387
+ - 'videos' (List[Dict]): List of generated video data
388
+ - 'metadata' (Dict): Additional metadata from the response
389
+ - 'error' (str): Error message if operation failed
390
+ """
391
+ loop = asyncio.get_event_loop()
392
+ return await loop.run_in_executor(
393
+ None,
394
+ self.generate_video_from_text,
395
+ text_prompt,
396
+ response_count,
397
+ duration,
398
+ aspect_ratio,
399
+ negative_prompt,
400
+ person_generation,
401
+ )
402
+
403
+ async def agenerate_video_from_image(
404
+ self,
405
+ image_path: str,
406
+ text_prompt: str,
407
+ response_count: int = 1,
408
+ duration: int = 5,
409
+ aspect_ratio: str = "16:9",
410
+ negative_prompt: Optional[str] = None,
411
+ person_generation: str = "allow_adult",
412
+ ) -> Dict[str, Any]:
413
+ r"""Generate video from image and text prompt using Vertex AI Veo.
414
+
415
+ Args:
416
+ image_path (str): Path to the input image file (local or GCS URI).
417
+ text_prompt (str): The text prompt to guide video generation.
418
+ response_count (int): Number of videos to generate (1-4).
419
+ (default: :obj:`1`)
420
+ duration (int): Video duration in seconds (5-8).
421
+ (default: :obj:`5`)
422
+ aspect_ratio (str): Video aspect ratio. Options: "16:9", "9:16".
423
+ (default: :obj:`"16:9"`)
424
+ negative_prompt (Optional[str]): What to avoid in the video.
425
+ (default: :obj:`None`)
426
+ person_generation (str): Person safety setting.
427
+ (default: :obj:`"allow_adult"`)
428
+
429
+ Returns:
430
+ Dict[str, Any]:
431
+ A dictionary containing:
432
+ - 'success' (bool): Whether the operation was successful
433
+ - 'videos' (List[Dict]): List of generated video data
434
+ - 'metadata' (Dict): Additional metadata from the response
435
+ - 'error' (str): Error message if operation failed
436
+ """
437
+ loop = asyncio.get_event_loop()
438
+ return await loop.run_in_executor(
439
+ None,
440
+ self.generate_video_from_image,
441
+ image_path,
442
+ text_prompt,
443
+ response_count,
444
+ duration,
445
+ aspect_ratio,
446
+ negative_prompt,
447
+ person_generation,
448
+ )
449
+
450
+ async def aextend_video(
451
+ self,
452
+ video_uri: str,
453
+ text_prompt: str,
454
+ duration: int = 5,
455
+ aspect_ratio: str = "16:9",
456
+ negative_prompt: Optional[str] = None,
457
+ ) -> Dict[str, Any]:
458
+ r"""Extend an existing video using Vertex AI Veo.
459
+
460
+ Args:
461
+ video_uri (str): Cloud Storage URI of the video to extend.
462
+ text_prompt (str): The text prompt to guide video extension.
463
+ duration (int): Duration to extend in seconds (5-8).
464
+ (default: :obj:`5`)
465
+ aspect_ratio (str): Video aspect ratio.
466
+ (default: :obj:`"16:9"`)
467
+ negative_prompt (Optional[str]): What to avoid in the extension.
468
+ (default: :obj:`None`)
469
+
470
+ Returns:
471
+ Dict[str, Any]:
472
+ A dictionary containing:
473
+ - 'success' (bool): Whether the operation was successful
474
+ - 'videos' (List[Dict]): List of extended video data
475
+ - 'metadata' (Dict): Additional metadata from the response
476
+ - 'error' (str): Error message if operation failed
477
+ """
478
+ loop = asyncio.get_event_loop()
479
+ return await loop.run_in_executor(
480
+ None,
481
+ self.extend_video,
482
+ video_uri,
483
+ text_prompt,
484
+ duration,
485
+ aspect_ratio,
486
+ negative_prompt,
487
+ )
488
+
489
+ def _process_image(self, image_path: str) -> Tuple[str, str]:
490
+ r"""Process image file and return base64 encoded data and MIME type."""
491
+ if image_path.startswith('gs://'):
492
+ # Handle Google Cloud Storage URIs
493
+ from google.cloud import storage # type: ignore[attr-defined]
494
+
495
+ # Parse GCS URI
496
+ parts = image_path[5:].split('/', 1)
497
+ bucket_name = parts[0]
498
+ blob_name = parts[1]
499
+
500
+ # Download image from GCS
501
+ client = storage.Client()
502
+ bucket = client.bucket(bucket_name)
503
+ blob = bucket.blob(blob_name)
504
+ image_bytes = blob.download_as_bytes()
505
+
506
+ # Determine MIME type from file extension
507
+ if blob_name.lower().endswith('.png'):
508
+ mime_type = "image/png"
509
+ elif blob_name.lower().endswith(('.jpg', '.jpeg')):
510
+ mime_type = "image/jpeg"
511
+ else:
512
+ raise ValueError("Unsupported image format. Use PNG or JPEG.")
513
+
514
+ else:
515
+ # Handle local file paths
516
+ with open(image_path, 'rb') as f:
517
+ image_bytes = f.read()
518
+
519
+ # Determine MIME type from file extension
520
+ if image_path.lower().endswith('.png'):
521
+ mime_type = "image/png"
522
+ elif image_path.lower().endswith(('.jpg', '.jpeg')):
523
+ mime_type = "image/jpeg"
524
+ else:
525
+ raise ValueError("Unsupported image format. Use PNG or JPEG.")
526
+
527
+ # Encode to base64
528
+ image_data = base64.b64encode(image_bytes).decode('utf-8')
529
+
530
+ return image_data, mime_type
531
+
532
+ def _parse_video_response(self, response: Any) -> Dict[str, Any]:
533
+ r"""Parse the video generation response."""
534
+ try:
535
+ result: Dict[str, Any] = {
536
+ "success": True,
537
+ "videos": [],
538
+ "metadata": {},
539
+ }
540
+
541
+ # Extract prediction results
542
+ if hasattr(response, 'predictions'):
543
+ for prediction in response.predictions:
544
+ # Convert prediction to dict if needed
545
+ if hasattr(prediction, 'struct_value'):
546
+ pred_dict = dict(prediction.struct_value)
547
+ else:
548
+ pred_dict = prediction
549
+
550
+ videos_list = result["videos"]
551
+ if isinstance(videos_list, list):
552
+ videos_list.append(pred_dict)
553
+
554
+ # Extract metadata if available
555
+ if hasattr(response, 'metadata'):
556
+ result["metadata"] = dict(response.metadata)
557
+
558
+ return result
559
+
560
+ except Exception as e:
561
+ logger.error(f"Error parsing video response: {e}")
562
+ return {
563
+ "success": False,
564
+ "error": str(e),
565
+ "raw_response": str(response),
566
+ }
567
+
568
+ def get_tools(self) -> List[FunctionTool]:
569
+ r"""Get a list of tools for video generation with Vertex AI Veo.
570
+
571
+ Returns:
572
+ List[FunctionTool]: List of available function tools.
573
+ """
574
+ return [
575
+ FunctionTool(self.generate_video_from_text),
576
+ FunctionTool(self.generate_video_from_image),
577
+ FunctionTool(self.extend_video),
578
+ ]
579
+
580
+ def get_async_tools(self) -> List[FunctionTool]:
581
+ r"""Get a list of async tools for video generation with Vertex AI Veo.
582
+
583
+ Returns:
584
+ List[FunctionTool]: List of available async function tools.
585
+ """
586
+ return [
587
+ FunctionTool(self.agenerate_video_from_text),
588
+ FunctionTool(self.agenerate_video_from_image),
589
+ FunctionTool(self.aextend_video),
590
+ ]