From 9ad5e1f80833f697514a1ee263ed7e4e7daeefcf Mon Sep 17 00:00:00 2001 From: Zamil Majdy Date: Thu, 10 Oct 2024 19:25:29 +0300 Subject: [PATCH] fix(platform): Remove blind try-except for yielding error on block (#8287) --- .../backend/backend/blocks/__init__.py | 13 +- .../blocks/ai_shortform_video_block.py | 116 ++++++++-------- .../backend/backend/blocks/basic.py | 48 +++---- .../backend/backend/blocks/block.py | 8 +- .../backend/backend/blocks/decoder_block.py | 7 +- .../backend/backend/blocks/email_block.py | 37 +++-- .../backend/backend/blocks/github/issues.py | 126 +++++++----------- .../backend/blocks/github/pull_requests.py | 74 ++++------ .../backend/backend/blocks/github/repo.py | 122 +++++++---------- .../backend/backend/blocks/google/gmail.py | 61 +++------ .../backend/backend/blocks/google/sheets.py | 30 ++--- .../backend/backend/blocks/google_maps.py | 19 ++- .../backend/backend/blocks/ideogram.py | 43 +++--- .../backend/backend/blocks/llm.py | 57 ++++---- .../backend/backend/blocks/medium.py | 48 +++---- .../backend/blocks/replicate_flux_advanced.py | 33 +++-- .../backend/backend/blocks/search.py | 85 ++++-------- .../backend/backend/blocks/talking_head.py | 65 +++++---- .../backend/blocks/text_to_speech_block.py | 15 +-- .../backend/backend/blocks/youtube.py | 15 +-- .../backend/backend/data/block.py | 4 +- docs/content/server/new_blocks.md | 12 +- 22 files changed, 428 insertions(+), 610 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/__init__.py b/autogpt_platform/backend/backend/blocks/__init__.py index d090aa41be..1fd85aef46 100644 --- a/autogpt_platform/backend/backend/blocks/__init__.py +++ b/autogpt_platform/backend/backend/blocks/__init__.py @@ -53,15 +53,22 @@ for cls in all_subclasses(Block): if block.id in AVAILABLE_BLOCKS: raise ValueError(f"Block ID {block.name} error: {block.id} is already in use") + input_schema = block.input_schema.model_fields + output_schema = block.output_schema.model_fields + # Prevent duplicate field name in input_schema and output_schema - duplicate_field_names = set(block.input_schema.model_fields.keys()) & set( - block.output_schema.model_fields.keys() - ) + duplicate_field_names = set(input_schema.keys()) & set(output_schema.keys()) if duplicate_field_names: raise ValueError( f"{block.name} has duplicate field names in input_schema and output_schema: {duplicate_field_names}" ) + # Make sure `error` field is a string in the output schema + if "error" in output_schema and output_schema["error"].annotation is not str: + raise ValueError( + f"{block.name} `error` field in output_schema must be a string" + ) + for field in block.input_schema.model_fields.values(): if field.annotation is bool and field.default not in (True, False): raise ValueError(f"{block.name} has a boolean field with no default value") diff --git a/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py b/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py index f4f12c9fe1..127bb3ae8b 100644 --- a/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py +++ b/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py @@ -1,7 +1,6 @@ import logging import time from enum import Enum -from typing import Optional import requests from pydantic import Field @@ -156,7 +155,7 @@ class AIShortformVideoCreatorBlock(Block): class Output(BlockSchema): video_url: str = Field(description="The URL of the created video") - error: Optional[str] = Field(description="Error message if the request failed") + error: str = Field(description="Error message if the request failed") def __init__(self): super().__init__( @@ -239,69 +238,58 @@ class AIShortformVideoCreatorBlock(Block): raise TimeoutError("Video creation timed out") def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - # Create a new Webhook.site URL - webhook_token, webhook_url = self.create_webhook() - logger.debug(f"Webhook URL: {webhook_url}") + # Create a new Webhook.site URL + webhook_token, webhook_url = self.create_webhook() + logger.debug(f"Webhook URL: {webhook_url}") - audio_url = input_data.background_music.audio_url + audio_url = input_data.background_music.audio_url - payload = { - "frameRate": input_data.frame_rate, - "resolution": input_data.resolution, - "frameDurationMultiplier": 18, - "webhook": webhook_url, - "creationParams": { - "mediaType": input_data.video_style, - "captionPresetName": "Wrap 1", - "selectedVoice": input_data.voice.voice_id, - "hasEnhancedGeneration": True, - "generationPreset": input_data.generation_preset.name, - "selectedAudio": input_data.background_music, - "origin": "/create", - "inputText": input_data.script, - "flowType": "text-to-video", - "slug": "create-tiktok-video", - "hasToGenerateVoice": True, - "hasToTranscript": False, - "hasToSearchMedia": True, - "hasAvatar": False, - "hasWebsiteRecorder": False, - "hasTextSmallAtBottom": False, - "ratio": input_data.ratio, - "sourceType": "contentScraping", - "selectedStoryStyle": {"value": "custom", "label": "Custom"}, - "hasToGenerateVideos": input_data.video_style - != VisualMediaType.STOCK_VIDEOS, - "audioUrl": audio_url, - }, - } + payload = { + "frameRate": input_data.frame_rate, + "resolution": input_data.resolution, + "frameDurationMultiplier": 18, + "webhook": webhook_url, + "creationParams": { + "mediaType": input_data.video_style, + "captionPresetName": "Wrap 1", + "selectedVoice": input_data.voice.voice_id, + "hasEnhancedGeneration": True, + "generationPreset": input_data.generation_preset.name, + "selectedAudio": input_data.background_music, + "origin": "/create", + "inputText": input_data.script, + "flowType": "text-to-video", + "slug": "create-tiktok-video", + "hasToGenerateVoice": True, + "hasToTranscript": False, + "hasToSearchMedia": True, + "hasAvatar": False, + "hasWebsiteRecorder": False, + "hasTextSmallAtBottom": False, + "ratio": input_data.ratio, + "sourceType": "contentScraping", + "selectedStoryStyle": {"value": "custom", "label": "Custom"}, + "hasToGenerateVideos": input_data.video_style + != VisualMediaType.STOCK_VIDEOS, + "audioUrl": audio_url, + }, + } - logger.debug("Creating video...") - response = self.create_video(input_data.api_key.get_secret_value(), payload) - pid = response.get("pid") + logger.debug("Creating video...") + response = self.create_video(input_data.api_key.get_secret_value(), payload) + pid = response.get("pid") - if not pid: - logger.error( - f"Failed to create video: No project ID returned. API Response: {response}" - ) - yield "error", "Failed to create video: No project ID returned" - else: - logger.debug( - f"Video created with project ID: {pid}. Waiting for completion..." - ) - video_url = self.wait_for_video( - input_data.api_key.get_secret_value(), pid, webhook_token - ) - logger.debug(f"Video ready: {video_url}") - yield "video_url", video_url - - except requests.RequestException as e: - logger.exception("Error creating video") - yield "error", f"Error creating video: {str(e)}" - except ValueError as e: - logger.exception("Error in video creation process") - yield "error", str(e) - except TimeoutError as e: - logger.exception("Video creation timed out") - yield "error", str(e) + if not pid: + logger.error( + f"Failed to create video: No project ID returned. API Response: {response}" + ) + raise RuntimeError("Failed to create video: No project ID returned") + else: + logger.debug( + f"Video created with project ID: {pid}. Waiting for completion..." + ) + video_url = self.wait_for_video( + input_data.api_key.get_secret_value(), pid, webhook_token + ) + logger.debug(f"Video ready: {video_url}") + yield "video_url", video_url diff --git a/autogpt_platform/backend/backend/blocks/basic.py b/autogpt_platform/backend/backend/blocks/basic.py index 095c3b0e92..60992e0f45 100644 --- a/autogpt_platform/backend/backend/blocks/basic.py +++ b/autogpt_platform/backend/backend/blocks/basic.py @@ -330,20 +330,17 @@ class AddToDictionaryBlock(Block): ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - # If no dictionary is provided, create a new one - if input_data.dictionary is None: - updated_dict = {} - else: - # Create a copy of the input dictionary to avoid modifying the original - updated_dict = input_data.dictionary.copy() + # If no dictionary is provided, create a new one + if input_data.dictionary is None: + updated_dict = {} + else: + # Create a copy of the input dictionary to avoid modifying the original + updated_dict = input_data.dictionary.copy() - # Add the new key-value pair - updated_dict[input_data.key] = input_data.value + # Add the new key-value pair + updated_dict[input_data.key] = input_data.value - yield "updated_dictionary", updated_dict - except Exception as e: - yield "error", f"Failed to add entry to dictionary: {str(e)}" + yield "updated_dictionary", updated_dict class AddToListBlock(Block): @@ -401,23 +398,20 @@ class AddToListBlock(Block): ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - # If no list is provided, create a new one - if input_data.list is None: - updated_list = [] - else: - # Create a copy of the input list to avoid modifying the original - updated_list = input_data.list.copy() + # If no list is provided, create a new one + if input_data.list is None: + updated_list = [] + else: + # Create a copy of the input list to avoid modifying the original + updated_list = input_data.list.copy() - # Add the new entry - if input_data.position is None: - updated_list.append(input_data.entry) - else: - updated_list.insert(input_data.position, input_data.entry) + # Add the new entry + if input_data.position is None: + updated_list.append(input_data.entry) + else: + updated_list.insert(input_data.position, input_data.entry) - yield "updated_list", updated_list - except Exception as e: - yield "error", f"Failed to add entry to list: {str(e)}" + yield "updated_list", updated_list class NoteBlock(Block): diff --git a/autogpt_platform/backend/backend/blocks/block.py b/autogpt_platform/backend/backend/blocks/block.py index a4bea7aee7..a4bf8f6ac5 100644 --- a/autogpt_platform/backend/backend/blocks/block.py +++ b/autogpt_platform/backend/backend/blocks/block.py @@ -37,14 +37,12 @@ class BlockInstallationBlock(Block): if search := re.search(r"class (\w+)\(Block\):", code): class_name = search.group(1) else: - yield "error", "No class found in the code." - return + raise RuntimeError("No class found in the code.") if search := re.search(r"id=\"(\w+-\w+-\w+-\w+-\w+)\"", code): file_name = search.group(1) else: - yield "error", "No UUID found in the code." - return + raise RuntimeError("No UUID found in the code.") block_dir = os.path.dirname(__file__) file_path = f"{block_dir}/{file_name}.py" @@ -63,4 +61,4 @@ class BlockInstallationBlock(Block): yield "success", "Block installed successfully." except Exception as e: os.remove(file_path) - yield "error", f"[Code]\n{code}\n\n[Error]\n{str(e)}" + raise RuntimeError(f"[Code]\n{code}\n\n[Error]\n{str(e)}") diff --git a/autogpt_platform/backend/backend/blocks/decoder_block.py b/autogpt_platform/backend/backend/blocks/decoder_block.py index fb23ef2c56..033cdfb0b3 100644 --- a/autogpt_platform/backend/backend/blocks/decoder_block.py +++ b/autogpt_platform/backend/backend/blocks/decoder_block.py @@ -35,8 +35,5 @@ This is a "quoted" string.""", ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - decoded_text = codecs.decode(input_data.text, "unicode_escape") - yield "decoded_text", decoded_text - except Exception as e: - yield "error", f"Error decoding text: {str(e)}" + decoded_text = codecs.decode(input_data.text, "unicode_escape") + yield "decoded_text", decoded_text diff --git a/autogpt_platform/backend/backend/blocks/email_block.py b/autogpt_platform/backend/backend/blocks/email_block.py index 96e69e1ffc..a7f0f82dce 100644 --- a/autogpt_platform/backend/backend/blocks/email_block.py +++ b/autogpt_platform/backend/backend/blocks/email_block.py @@ -67,35 +67,28 @@ class SendEmailBlock(Block): def send_email( creds: EmailCredentials, to_email: str, subject: str, body: str ) -> str: - try: - smtp_server = creds.smtp_server - smtp_port = creds.smtp_port - smtp_username = creds.smtp_username.get_secret_value() - smtp_password = creds.smtp_password.get_secret_value() + smtp_server = creds.smtp_server + smtp_port = creds.smtp_port + smtp_username = creds.smtp_username.get_secret_value() + smtp_password = creds.smtp_password.get_secret_value() - msg = MIMEMultipart() - msg["From"] = smtp_username - msg["To"] = to_email - msg["Subject"] = subject - msg.attach(MIMEText(body, "plain")) + msg = MIMEMultipart() + msg["From"] = smtp_username + msg["To"] = to_email + msg["Subject"] = subject + msg.attach(MIMEText(body, "plain")) - with smtplib.SMTP(smtp_server, smtp_port) as server: - server.starttls() - server.login(smtp_username, smtp_password) - server.sendmail(smtp_username, to_email, msg.as_string()) + with smtplib.SMTP(smtp_server, smtp_port) as server: + server.starttls() + server.login(smtp_username, smtp_password) + server.sendmail(smtp_username, to_email, msg.as_string()) - return "Email sent successfully" - except Exception as e: - return f"Failed to send email: {str(e)}" + return "Email sent successfully" def run(self, input_data: Input, **kwargs) -> BlockOutput: - status = self.send_email( + yield "status", self.send_email( input_data.creds, input_data.to_email, input_data.subject, input_data.body, ) - if "successfully" in status: - yield "status", status - else: - yield "error", status diff --git a/autogpt_platform/backend/backend/blocks/github/issues.py b/autogpt_platform/backend/backend/blocks/github/issues.py index 0ddeb547ee..ee9391545d 100644 --- a/autogpt_platform/backend/backend/blocks/github/issues.py +++ b/autogpt_platform/backend/backend/blocks/github/issues.py @@ -93,16 +93,13 @@ class GithubCommentBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - id, url = self.post_comment( - credentials, - input_data.issue_url, - input_data.comment, - ) - yield "id", id - yield "url", url - except Exception as e: - yield "error", f"Failed to post comment: {str(e)}" + id, url = self.post_comment( + credentials, + input_data.issue_url, + input_data.comment, + ) + yield "id", id + yield "url", url # --8<-- [end:GithubCommentBlockExample] @@ -179,17 +176,14 @@ class GithubMakeIssueBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - number, url = self.create_issue( - credentials, - input_data.repo_url, - input_data.title, - input_data.body, - ) - yield "number", number - yield "url", url - except Exception as e: - yield "error", f"Failed to create issue: {str(e)}" + number, url = self.create_issue( + credentials, + input_data.repo_url, + input_data.title, + input_data.body, + ) + yield "number", number + yield "url", url class GithubReadIssueBlock(Block): @@ -262,16 +256,13 @@ class GithubReadIssueBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - title, body, user = self.read_issue( - credentials, - input_data.issue_url, - ) - yield "title", title - yield "body", body - yield "user", user - except Exception as e: - yield "error", f"Failed to read issue: {str(e)}" + title, body, user = self.read_issue( + credentials, + input_data.issue_url, + ) + yield "title", title + yield "body", body + yield "user", user class GithubListIssuesBlock(Block): @@ -350,14 +341,11 @@ class GithubListIssuesBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - issues = self.list_issues( - credentials, - input_data.repo_url, - ) - yield from (("issue", issue) for issue in issues) - except Exception as e: - yield "error", f"Failed to list issues: {str(e)}" + issues = self.list_issues( + credentials, + input_data.repo_url, + ) + yield from (("issue", issue) for issue in issues) class GithubAddLabelBlock(Block): @@ -428,15 +416,12 @@ class GithubAddLabelBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - status = self.add_label( - credentials, - input_data.issue_url, - input_data.label, - ) - yield "status", status - except Exception as e: - yield "error", f"Failed to add label: {str(e)}" + status = self.add_label( + credentials, + input_data.issue_url, + input_data.label, + ) + yield "status", status class GithubRemoveLabelBlock(Block): @@ -512,15 +497,12 @@ class GithubRemoveLabelBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - status = self.remove_label( - credentials, - input_data.issue_url, - input_data.label, - ) - yield "status", status - except Exception as e: - yield "error", f"Failed to remove label: {str(e)}" + status = self.remove_label( + credentials, + input_data.issue_url, + input_data.label, + ) + yield "status", status class GithubAssignIssueBlock(Block): @@ -594,15 +576,12 @@ class GithubAssignIssueBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - status = self.assign_issue( - credentials, - input_data.issue_url, - input_data.assignee, - ) - yield "status", status - except Exception as e: - yield "error", f"Failed to assign issue: {str(e)}" + status = self.assign_issue( + credentials, + input_data.issue_url, + input_data.assignee, + ) + yield "status", status class GithubUnassignIssueBlock(Block): @@ -676,12 +655,9 @@ class GithubUnassignIssueBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - status = self.unassign_issue( - credentials, - input_data.issue_url, - input_data.assignee, - ) - yield "status", status - except Exception as e: - yield "error", f"Failed to unassign issue: {str(e)}" + status = self.unassign_issue( + credentials, + input_data.issue_url, + input_data.assignee, + ) + yield "status", status diff --git a/autogpt_platform/backend/backend/blocks/github/pull_requests.py b/autogpt_platform/backend/backend/blocks/github/pull_requests.py index 87540b66df..b04c730dc3 100644 --- a/autogpt_platform/backend/backend/blocks/github/pull_requests.py +++ b/autogpt_platform/backend/backend/blocks/github/pull_requests.py @@ -87,14 +87,11 @@ class GithubListPullRequestsBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - pull_requests = self.list_prs( - credentials, - input_data.repo_url, - ) - yield from (("pull_request", pr) for pr in pull_requests) - except Exception as e: - yield "error", f"Failed to list pull requests: {str(e)}" + pull_requests = self.list_prs( + credentials, + input_data.repo_url, + ) + yield from (("pull_request", pr) for pr in pull_requests) class GithubMakePullRequestBlock(Block): @@ -203,9 +200,7 @@ class GithubMakePullRequestBlock(Block): error_message = error_details.get("message", "Unknown error") else: error_message = str(http_err) - yield "error", f"Failed to create pull request: {error_message}" - except Exception as e: - yield "error", f"Failed to create pull request: {str(e)}" + raise RuntimeError(f"Failed to create pull request: {error_message}") class GithubReadPullRequestBlock(Block): @@ -313,23 +308,20 @@ class GithubReadPullRequestBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - title, body, author = self.read_pr( + title, body, author = self.read_pr( + credentials, + input_data.pr_url, + ) + yield "title", title + yield "body", body + yield "author", author + + if input_data.include_pr_changes: + changes = self.read_pr_changes( credentials, input_data.pr_url, ) - yield "title", title - yield "body", body - yield "author", author - - if input_data.include_pr_changes: - changes = self.read_pr_changes( - credentials, - input_data.pr_url, - ) - yield "changes", changes - except Exception as e: - yield "error", f"Failed to read pull request: {str(e)}" + yield "changes", changes class GithubAssignPRReviewerBlock(Block): @@ -418,9 +410,7 @@ class GithubAssignPRReviewerBlock(Block): ) else: error_msg = f"HTTP error: {http_err} - {http_err.response.text}" - yield "error", error_msg - except Exception as e: - yield "error", f"Failed to assign reviewer: {str(e)}" + raise RuntimeError(error_msg) class GithubUnassignPRReviewerBlock(Block): @@ -490,15 +480,12 @@ class GithubUnassignPRReviewerBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - status = self.unassign_reviewer( - credentials, - input_data.pr_url, - input_data.reviewer, - ) - yield "status", status - except Exception as e: - yield "error", f"Failed to unassign reviewer: {str(e)}" + status = self.unassign_reviewer( + credentials, + input_data.pr_url, + input_data.reviewer, + ) + yield "status", status class GithubListPRReviewersBlock(Block): @@ -586,11 +573,8 @@ class GithubListPRReviewersBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - reviewers = self.list_reviewers( - credentials, - input_data.pr_url, - ) - yield from (("reviewer", reviewer) for reviewer in reviewers) - except Exception as e: - yield "error", f"Failed to list reviewers: {str(e)}" + reviewers = self.list_reviewers( + credentials, + input_data.pr_url, + ) + yield from (("reviewer", reviewer) for reviewer in reviewers) diff --git a/autogpt_platform/backend/backend/blocks/github/repo.py b/autogpt_platform/backend/backend/blocks/github/repo.py index 63dcc7e1a1..29eeb757e2 100644 --- a/autogpt_platform/backend/backend/blocks/github/repo.py +++ b/autogpt_platform/backend/backend/blocks/github/repo.py @@ -96,14 +96,11 @@ class GithubListTagsBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - tags = self.list_tags( - credentials, - input_data.repo_url, - ) - yield from (("tag", tag) for tag in tags) - except Exception as e: - yield "error", f"Failed to list tags: {str(e)}" + tags = self.list_tags( + credentials, + input_data.repo_url, + ) + yield from (("tag", tag) for tag in tags) class GithubListBranchesBlock(Block): @@ -183,14 +180,11 @@ class GithubListBranchesBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - branches = self.list_branches( - credentials, - input_data.repo_url, - ) - yield from (("branch", branch) for branch in branches) - except Exception as e: - yield "error", f"Failed to list branches: {str(e)}" + branches = self.list_branches( + credentials, + input_data.repo_url, + ) + yield from (("branch", branch) for branch in branches) class GithubListDiscussionsBlock(Block): @@ -294,13 +288,10 @@ class GithubListDiscussionsBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - discussions = self.list_discussions( - credentials, input_data.repo_url, input_data.num_discussions - ) - yield from (("discussion", discussion) for discussion in discussions) - except Exception as e: - yield "error", f"Failed to list discussions: {str(e)}" + discussions = self.list_discussions( + credentials, input_data.repo_url, input_data.num_discussions + ) + yield from (("discussion", discussion) for discussion in discussions) class GithubListReleasesBlock(Block): @@ -381,14 +372,11 @@ class GithubListReleasesBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - releases = self.list_releases( - credentials, - input_data.repo_url, - ) - yield from (("release", release) for release in releases) - except Exception as e: - yield "error", f"Failed to list releases: {str(e)}" + releases = self.list_releases( + credentials, + input_data.repo_url, + ) + yield from (("release", release) for release in releases) class GithubReadFileBlock(Block): @@ -474,18 +462,15 @@ class GithubReadFileBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - raw_content, size = self.read_file( - credentials, - input_data.repo_url, - input_data.file_path.lstrip("/"), - input_data.branch, - ) - yield "raw_content", raw_content - yield "text_content", base64.b64decode(raw_content).decode("utf-8") - yield "size", size - except Exception as e: - yield "error", f"Failed to read file: {str(e)}" + raw_content, size = self.read_file( + credentials, + input_data.repo_url, + input_data.file_path.lstrip("/"), + input_data.branch, + ) + yield "raw_content", raw_content + yield "text_content", base64.b64decode(raw_content).decode("utf-8") + yield "size", size class GithubReadFolderBlock(Block): @@ -612,17 +597,14 @@ class GithubReadFolderBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - files, dirs = self.read_folder( - credentials, - input_data.repo_url, - input_data.folder_path.lstrip("/"), - input_data.branch, - ) - yield from (("file", file) for file in files) - yield from (("dir", dir) for dir in dirs) - except Exception as e: - yield "error", f"Failed to read folder: {str(e)}" + files, dirs = self.read_folder( + credentials, + input_data.repo_url, + input_data.folder_path.lstrip("/"), + input_data.branch, + ) + yield from (("file", file) for file in files) + yield from (("dir", dir) for dir in dirs) class GithubMakeBranchBlock(Block): @@ -703,16 +685,13 @@ class GithubMakeBranchBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - status = self.create_branch( - credentials, - input_data.repo_url, - input_data.new_branch, - input_data.source_branch, - ) - yield "status", status - except Exception as e: - yield "error", f"Failed to create branch: {str(e)}" + status = self.create_branch( + credentials, + input_data.repo_url, + input_data.new_branch, + input_data.source_branch, + ) + yield "status", status class GithubDeleteBranchBlock(Block): @@ -775,12 +754,9 @@ class GithubDeleteBranchBlock(Block): credentials: GithubCredentials, **kwargs, ) -> BlockOutput: - try: - status = self.delete_branch( - credentials, - input_data.repo_url, - input_data.branch, - ) - yield "status", status - except Exception as e: - yield "error", f"Failed to delete branch: {str(e)}" + status = self.delete_branch( + credentials, + input_data.repo_url, + input_data.branch, + ) + yield "status", status diff --git a/autogpt_platform/backend/backend/blocks/google/gmail.py b/autogpt_platform/backend/backend/blocks/google/gmail.py index 9cecac81f1..beb96f3439 100644 --- a/autogpt_platform/backend/backend/blocks/google/gmail.py +++ b/autogpt_platform/backend/backend/blocks/google/gmail.py @@ -104,16 +104,11 @@ class GmailReadBlock(Block): def run( self, input_data: Input, *, credentials: GoogleCredentials, **kwargs ) -> BlockOutput: - try: - service = self._build_service(credentials, **kwargs) - messages = self._read_emails( - service, input_data.query, input_data.max_results - ) - for email in messages: - yield "email", email - yield "emails", messages - except Exception as e: - yield "error", str(e) + service = self._build_service(credentials, **kwargs) + messages = self._read_emails(service, input_data.query, input_data.max_results) + for email in messages: + yield "email", email + yield "emails", messages @staticmethod def _build_service(credentials: GoogleCredentials, **kwargs): @@ -267,14 +262,11 @@ class GmailSendBlock(Block): def run( self, input_data: Input, *, credentials: GoogleCredentials, **kwargs ) -> BlockOutput: - try: - service = GmailReadBlock._build_service(credentials, **kwargs) - send_result = self._send_email( - service, input_data.to, input_data.subject, input_data.body - ) - yield "result", send_result - except Exception as e: - yield "error", str(e) + service = GmailReadBlock._build_service(credentials, **kwargs) + send_result = self._send_email( + service, input_data.to, input_data.subject, input_data.body + ) + yield "result", send_result def _send_email(self, service, to: str, subject: str, body: str) -> dict: if not to or not subject or not body: @@ -342,12 +334,9 @@ class GmailListLabelsBlock(Block): def run( self, input_data: Input, *, credentials: GoogleCredentials, **kwargs ) -> BlockOutput: - try: - service = GmailReadBlock._build_service(credentials, **kwargs) - labels = self._list_labels(service) - yield "result", labels - except Exception as e: - yield "error", str(e) + service = GmailReadBlock._build_service(credentials, **kwargs) + labels = self._list_labels(service) + yield "result", labels def _list_labels(self, service) -> list[dict]: results = service.users().labels().list(userId="me").execute() @@ -406,14 +395,9 @@ class GmailAddLabelBlock(Block): def run( self, input_data: Input, *, credentials: GoogleCredentials, **kwargs ) -> BlockOutput: - try: - service = GmailReadBlock._build_service(credentials, **kwargs) - result = self._add_label( - service, input_data.message_id, input_data.label_name - ) - yield "result", result - except Exception as e: - yield "error", str(e) + service = GmailReadBlock._build_service(credentials, **kwargs) + result = self._add_label(service, input_data.message_id, input_data.label_name) + yield "result", result def _add_label(self, service, message_id: str, label_name: str) -> dict: label_id = self._get_or_create_label(service, label_name) @@ -494,14 +478,11 @@ class GmailRemoveLabelBlock(Block): def run( self, input_data: Input, *, credentials: GoogleCredentials, **kwargs ) -> BlockOutput: - try: - service = GmailReadBlock._build_service(credentials, **kwargs) - result = self._remove_label( - service, input_data.message_id, input_data.label_name - ) - yield "result", result - except Exception as e: - yield "error", str(e) + service = GmailReadBlock._build_service(credentials, **kwargs) + result = self._remove_label( + service, input_data.message_id, input_data.label_name + ) + yield "result", result def _remove_label(self, service, message_id: str, label_name: str) -> dict: label_id = self._get_label_id(service, label_name) diff --git a/autogpt_platform/backend/backend/blocks/google/sheets.py b/autogpt_platform/backend/backend/blocks/google/sheets.py index e4318225cc..e7878ff4b6 100644 --- a/autogpt_platform/backend/backend/blocks/google/sheets.py +++ b/autogpt_platform/backend/backend/blocks/google/sheets.py @@ -68,14 +68,9 @@ class GoogleSheetsReadBlock(Block): def run( self, input_data: Input, *, credentials: GoogleCredentials, **kwargs ) -> BlockOutput: - try: - service = self._build_service(credentials, **kwargs) - data = self._read_sheet( - service, input_data.spreadsheet_id, input_data.range - ) - yield "result", data - except Exception as e: - yield "error", str(e) + service = self._build_service(credentials, **kwargs) + data = self._read_sheet(service, input_data.spreadsheet_id, input_data.range) + yield "result", data @staticmethod def _build_service(credentials: GoogleCredentials, **kwargs): @@ -162,17 +157,14 @@ class GoogleSheetsWriteBlock(Block): def run( self, input_data: Input, *, credentials: GoogleCredentials, **kwargs ) -> BlockOutput: - try: - service = GoogleSheetsReadBlock._build_service(credentials, **kwargs) - result = self._write_sheet( - service, - input_data.spreadsheet_id, - input_data.range, - input_data.values, - ) - yield "result", result - except Exception as e: - yield "error", str(e) + service = GoogleSheetsReadBlock._build_service(credentials, **kwargs) + result = self._write_sheet( + service, + input_data.spreadsheet_id, + input_data.range, + input_data.values, + ) + yield "result", result def _write_sheet( self, service, spreadsheet_id: str, range: str, values: list[list[str]] diff --git a/autogpt_platform/backend/backend/blocks/google_maps.py b/autogpt_platform/backend/backend/blocks/google_maps.py index 4edd74113d..3be57b93e8 100644 --- a/autogpt_platform/backend/backend/blocks/google_maps.py +++ b/autogpt_platform/backend/backend/blocks/google_maps.py @@ -82,17 +82,14 @@ class GoogleMapsSearchBlock(Block): ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - places = self.search_places( - input_data.api_key.get_secret_value(), - input_data.query, - input_data.radius, - input_data.max_results, - ) - for place in places: - yield "place", place - except Exception as e: - yield "error", str(e) + places = self.search_places( + input_data.api_key.get_secret_value(), + input_data.query, + input_data.radius, + input_data.max_results, + ) + for place in places: + yield "place", place def search_places(self, api_key, query, radius, max_results): client = googlemaps.Client(key=api_key) diff --git a/autogpt_platform/backend/backend/blocks/ideogram.py b/autogpt_platform/backend/backend/blocks/ideogram.py index 0bf20ee6bd..66dd220614 100644 --- a/autogpt_platform/backend/backend/blocks/ideogram.py +++ b/autogpt_platform/backend/backend/blocks/ideogram.py @@ -128,9 +128,7 @@ class IdeogramModelBlock(Block): class Output(BlockSchema): result: str = SchemaField(description="Generated image URL") - error: Optional[str] = SchemaField( - description="Error message if the model run failed" - ) + error: str = SchemaField(description="Error message if the model run failed") def __init__(self): super().__init__( @@ -166,30 +164,27 @@ class IdeogramModelBlock(Block): def run(self, input_data: Input, **kwargs) -> BlockOutput: seed = input_data.seed - try: - # Step 1: Generate the image - result = self.run_model( + # Step 1: Generate the image + result = self.run_model( + api_key=input_data.api_key.get_secret_value(), + model_name=input_data.ideogram_model_name.value, + prompt=input_data.prompt, + seed=seed, + aspect_ratio=input_data.aspect_ratio.value, + magic_prompt_option=input_data.magic_prompt_option.value, + style_type=input_data.style_type.value, + negative_prompt=input_data.negative_prompt, + color_palette_name=input_data.color_palette_name.value, + ) + + # Step 2: Upscale the image if requested + if input_data.upscale == UpscaleOption.AI_UPSCALE: + result = self.upscale_image( api_key=input_data.api_key.get_secret_value(), - model_name=input_data.ideogram_model_name.value, - prompt=input_data.prompt, - seed=seed, - aspect_ratio=input_data.aspect_ratio.value, - magic_prompt_option=input_data.magic_prompt_option.value, - style_type=input_data.style_type.value, - negative_prompt=input_data.negative_prompt, - color_palette_name=input_data.color_palette_name.value, + image_url=result, ) - # Step 2: Upscale the image if requested - if input_data.upscale == UpscaleOption.AI_UPSCALE: - result = self.upscale_image( - api_key=input_data.api_key.get_secret_value(), - image_url=result, - ) - - yield "result", result - except Exception as e: - yield "error", str(e) + yield "result", result def run_model( self, diff --git a/autogpt_platform/backend/backend/blocks/llm.py b/autogpt_platform/backend/backend/blocks/llm.py index 15f75ecc74..f38b5f5da7 100644 --- a/autogpt_platform/backend/backend/blocks/llm.py +++ b/autogpt_platform/backend/backend/blocks/llm.py @@ -344,7 +344,7 @@ class AIStructuredResponseGeneratorBlock(Block): logger.error(f"Error calling LLM: {e}") retry_prompt = f"Error calling LLM: {e}" - yield "error", retry_prompt + raise RuntimeError(retry_prompt) class AITextGeneratorBlock(Block): @@ -390,14 +390,11 @@ class AITextGeneratorBlock(Block): raise ValueError("Failed to get a response from the LLM.") def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - object_input_data = AIStructuredResponseGeneratorBlock.Input( - **{attr: getattr(input_data, attr) for attr in input_data.model_fields}, - expected_format={}, - ) - yield "response", self.llm_call(object_input_data) - except Exception as e: - yield "error", str(e) + object_input_data = AIStructuredResponseGeneratorBlock.Input( + **{attr: getattr(input_data, attr) for attr in input_data.model_fields}, + expected_format={}, + ) + yield "response", self.llm_call(object_input_data) class SummaryStyle(Enum): @@ -445,11 +442,8 @@ class AITextSummarizerBlock(Block): ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - for output in self._run(input_data): - yield output - except Exception as e: - yield "error", str(e) + for output in self._run(input_data): + yield output def _run(self, input_data: Input) -> BlockOutput: chunks = self._split_text( @@ -642,24 +636,21 @@ class AIConversationBlock(Block): raise ValueError(f"Unsupported LLM provider: {provider}") def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - api_key = ( - input_data.api_key.get_secret_value() - or LlmApiKeys[input_data.model.metadata.provider].get_secret_value() - ) + api_key = ( + input_data.api_key.get_secret_value() + or LlmApiKeys[input_data.model.metadata.provider].get_secret_value() + ) - messages = [message.model_dump() for message in input_data.messages] + messages = [message.model_dump() for message in input_data.messages] - response = self.llm_call( - api_key=api_key, - model=input_data.model, - messages=messages, - max_tokens=input_data.max_tokens, - ) + response = self.llm_call( + api_key=api_key, + model=input_data.model, + messages=messages, + max_tokens=input_data.max_tokens, + ) - yield "response", response - except Exception as e: - yield "error", f"Error calling LLM: {str(e)}" + yield "response", response class AIListGeneratorBlock(Block): @@ -777,9 +768,7 @@ class AIListGeneratorBlock(Block): or LlmApiKeys[input_data.model.metadata.provider].get_secret_value() ) if not api_key_check: - logger.error("No LLM API key provided.") - yield "error", "No LLM API key provided." - return + raise ValueError("No LLM API key provided.") # Prepare the system prompt sys_prompt = """You are a Python list generator. Your task is to generate a Python list based on the user's prompt. @@ -873,7 +862,9 @@ class AIListGeneratorBlock(Block): logger.error( f"Failed to generate a valid Python list after {input_data.max_retries} attempts" ) - yield "error", f"Failed to generate a valid Python list after {input_data.max_retries} attempts. Last error: {str(e)}" + raise RuntimeError( + f"Failed to generate a valid Python list after {input_data.max_retries} attempts. Last error: {str(e)}" + ) else: # Add a retry prompt logger.debug("Preparing retry prompt") diff --git a/autogpt_platform/backend/backend/blocks/medium.py b/autogpt_platform/backend/backend/blocks/medium.py index 9ca9b41bf4..04ebe8fab0 100644 --- a/autogpt_platform/backend/backend/blocks/medium.py +++ b/autogpt_platform/backend/backend/blocks/medium.py @@ -138,31 +138,25 @@ class PublishToMediumBlock(Block): return response.json() def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - response = self.create_post( - input_data.api_key.get_secret_value(), - input_data.author_id.get_secret_value(), - input_data.title, - input_data.content, - input_data.content_format, - input_data.tags, - input_data.canonical_url, - input_data.publish_status, - input_data.license, - input_data.notify_followers, + response = self.create_post( + input_data.api_key.get_secret_value(), + input_data.author_id.get_secret_value(), + input_data.title, + input_data.content, + input_data.content_format, + input_data.tags, + input_data.canonical_url, + input_data.publish_status, + input_data.license, + input_data.notify_followers, + ) + + if "data" in response: + yield "post_id", response["data"]["id"] + yield "post_url", response["data"]["url"] + yield "published_at", response["data"]["publishedAt"] + else: + error_message = response.get("errors", [{}])[0].get( + "message", "Unknown error occurred" ) - - if "data" in response: - yield "post_id", response["data"]["id"] - yield "post_url", response["data"]["url"] - yield "published_at", response["data"]["publishedAt"] - else: - error_message = response.get("errors", [{}])[0].get( - "message", "Unknown error occurred" - ) - yield "error", f"Failed to create Medium post: {error_message}" - - except requests.RequestException as e: - yield "error", f"Network error occurred while creating Medium post: {str(e)}" - except Exception as e: - yield "error", f"Error occurred while creating Medium post: {str(e)}" + raise RuntimeError(f"Failed to create Medium post: {error_message}") diff --git a/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py b/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py index 6795c3c587..38abc8da20 100644 --- a/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py +++ b/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py @@ -139,24 +139,21 @@ class ReplicateFluxAdvancedModelBlock(Block): if seed is None: seed = int.from_bytes(os.urandom(4), "big") - try: - # Run the model using the provided inputs - result = self.run_model( - api_key=input_data.api_key.get_secret_value(), - model_name=input_data.replicate_model_name.api_name, - prompt=input_data.prompt, - seed=seed, - steps=input_data.steps, - guidance=input_data.guidance, - interval=input_data.interval, - aspect_ratio=input_data.aspect_ratio, - output_format=input_data.output_format, - output_quality=input_data.output_quality, - safety_tolerance=input_data.safety_tolerance, - ) - yield "result", result - except Exception as e: - yield "error", str(e) + # Run the model using the provided inputs + result = self.run_model( + api_key=input_data.api_key.get_secret_value(), + model_name=input_data.replicate_model_name.api_name, + prompt=input_data.prompt, + seed=seed, + steps=input_data.steps, + guidance=input_data.guidance, + interval=input_data.interval, + aspect_ratio=input_data.aspect_ratio, + output_format=input_data.output_format, + output_quality=input_data.output_quality, + safety_tolerance=input_data.safety_tolerance, + ) + yield "result", result def run_model( self, diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index f8fc783e56..ecd63e2ee6 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -36,20 +36,12 @@ class GetWikipediaSummaryBlock(Block, GetRequest): ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - topic = input_data.topic - url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{topic}" - response = self.get_request(url, json=True) - yield "summary", response["extract"] - - except requests.exceptions.HTTPError as http_err: - yield "error", f"HTTP error occurred: {http_err}" - - except requests.RequestException as e: - yield "error", f"Request to Wikipedia failed: {e}" - - except KeyError as e: - yield "error", f"Error parsing Wikipedia response: {e}" + topic = input_data.topic + url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{topic}" + response = self.get_request(url, json=True) + if "extract" not in response: + raise RuntimeError(f"Unable to parse Wikipedia response: {response}") + yield "summary", response["extract"] class SearchTheWebBlock(Block, GetRequest): @@ -73,24 +65,17 @@ class SearchTheWebBlock(Block, GetRequest): ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - # Encode the search query - encoded_query = quote(input_data.query) + # Encode the search query + encoded_query = quote(input_data.query) - # Prepend the Jina Search URL to the encoded query - jina_search_url = f"https://s.jina.ai/{encoded_query}" + # Prepend the Jina Search URL to the encoded query + jina_search_url = f"https://s.jina.ai/{encoded_query}" - # Make the request to Jina Search - response = self.get_request(jina_search_url, json=False) + # Make the request to Jina Search + response = self.get_request(jina_search_url, json=False) - # Output the search results - yield "results", response - - except requests.exceptions.HTTPError as http_err: - yield "error", f"HTTP error occurred: {http_err}" - - except requests.RequestException as e: - yield "error", f"Request to Jina Search failed: {e}" + # Output the search results + yield "results", response class ExtractWebsiteContentBlock(Block, GetRequest): @@ -125,13 +110,8 @@ class ExtractWebsiteContentBlock(Block, GetRequest): else: url = f"https://r.jina.ai/{input_data.url}" - try: - content = self.get_request(url, json=False) - yield "content", content - except requests.exceptions.HTTPError as http_err: - yield "error", f"HTTP error occurred: {http_err}" - except requests.RequestException as e: - yield "error", f"Request to URL failed: {e}" + content = self.get_request(url, json=False) + yield "content", content class GetWeatherInformationBlock(Block, GetRequest): @@ -171,26 +151,15 @@ class GetWeatherInformationBlock(Block, GetRequest): ) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - units = "metric" if input_data.use_celsius else "imperial" - api_key = input_data.api_key.get_secret_value() - location = input_data.location - url = f"http://api.openweathermap.org/data/2.5/weather?q={quote(location)}&appid={api_key}&units={units}" - weather_data = self.get_request(url, json=True) + units = "metric" if input_data.use_celsius else "imperial" + api_key = input_data.api_key.get_secret_value() + location = input_data.location + url = f"http://api.openweathermap.org/data/2.5/weather?q={quote(location)}&appid={api_key}&units={units}" + weather_data = self.get_request(url, json=True) - if "main" in weather_data and "weather" in weather_data: - yield "temperature", str(weather_data["main"]["temp"]) - yield "humidity", str(weather_data["main"]["humidity"]) - yield "condition", weather_data["weather"][0]["description"] - else: - yield "error", f"Expected keys not found in response: {weather_data}" - - except requests.exceptions.HTTPError as http_err: - if http_err.response.status_code == 403: - yield "error", "Request to weather API failed: 403 Forbidden. Check your API key and permissions." - else: - yield "error", f"HTTP error occurred: {http_err}" - except requests.RequestException as e: - yield "error", f"Request to weather API failed: {e}" - except KeyError as e: - yield "error", f"Error processing weather data: {e}" + if "main" in weather_data and "weather" in weather_data: + yield "temperature", str(weather_data["main"]["temp"]) + yield "humidity", str(weather_data["main"]["humidity"]) + yield "condition", weather_data["weather"][0]["description"] + else: + raise RuntimeError(f"Expected keys not found in response: {weather_data}") diff --git a/autogpt_platform/backend/backend/blocks/talking_head.py b/autogpt_platform/backend/backend/blocks/talking_head.py index e1851ae030..e93b69ed85 100644 --- a/autogpt_platform/backend/backend/blocks/talking_head.py +++ b/autogpt_platform/backend/backend/blocks/talking_head.py @@ -106,41 +106,40 @@ class CreateTalkingAvatarVideoBlock(Block): return response.json() def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - # Create the clip - payload = { - "script": { - "type": "text", - "subtitles": str(input_data.subtitles).lower(), - "provider": { - "type": input_data.provider, - "voice_id": input_data.voice_id, - }, - "ssml": str(input_data.ssml).lower(), - "input": input_data.script_input, + # Create the clip + payload = { + "script": { + "type": "text", + "subtitles": str(input_data.subtitles).lower(), + "provider": { + "type": input_data.provider, + "voice_id": input_data.voice_id, }, - "config": {"result_format": input_data.result_format}, - "presenter_config": {"crop": {"type": input_data.crop_type}}, - "presenter_id": input_data.presenter_id, - "driver_id": input_data.driver_id, - } + "ssml": str(input_data.ssml).lower(), + "input": input_data.script_input, + }, + "config": {"result_format": input_data.result_format}, + "presenter_config": {"crop": {"type": input_data.crop_type}}, + "presenter_id": input_data.presenter_id, + "driver_id": input_data.driver_id, + } - response = self.create_clip(input_data.api_key.get_secret_value(), payload) - clip_id = response["id"] + response = self.create_clip(input_data.api_key.get_secret_value(), payload) + clip_id = response["id"] - # Poll for clip status - for _ in range(input_data.max_polling_attempts): - status_response = self.get_clip_status( - input_data.api_key.get_secret_value(), clip_id + # Poll for clip status + for _ in range(input_data.max_polling_attempts): + status_response = self.get_clip_status( + input_data.api_key.get_secret_value(), clip_id + ) + if status_response["status"] == "done": + yield "video_url", status_response["result_url"] + return + elif status_response["status"] == "error": + raise RuntimeError( + f"Clip creation failed: {status_response.get('error', 'Unknown error')}" ) - if status_response["status"] == "done": - yield "video_url", status_response["result_url"] - return - elif status_response["status"] == "error": - yield "error", f"Clip creation failed: {status_response.get('error', 'Unknown error')}" - return - time.sleep(input_data.polling_interval) - yield "error", "Clip creation timed out" - except Exception as e: - yield "error", str(e) + time.sleep(input_data.polling_interval) + + raise TimeoutError("Clip creation timed out") diff --git a/autogpt_platform/backend/backend/blocks/text_to_speech_block.py b/autogpt_platform/backend/backend/blocks/text_to_speech_block.py index 5239142ee2..4141276340 100644 --- a/autogpt_platform/backend/backend/blocks/text_to_speech_block.py +++ b/autogpt_platform/backend/backend/blocks/text_to_speech_block.py @@ -68,12 +68,9 @@ class UnrealTextToSpeechBlock(Block): return response.json() def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - api_response = self.call_unreal_speech_api( - input_data.api_key.get_secret_value(), - input_data.text, - input_data.voice_id, - ) - yield "mp3_url", api_response["OutputUri"] - except Exception as e: - yield "error", str(e) + api_response = self.call_unreal_speech_api( + input_data.api_key.get_secret_value(), + input_data.text, + input_data.voice_id, + ) + yield "mp3_url", api_response["OutputUri"] diff --git a/autogpt_platform/backend/backend/blocks/youtube.py b/autogpt_platform/backend/backend/blocks/youtube.py index e299b121aa..cec50109bd 100644 --- a/autogpt_platform/backend/backend/blocks/youtube.py +++ b/autogpt_platform/backend/backend/blocks/youtube.py @@ -64,14 +64,11 @@ class TranscribeYouTubeVideoBlock(Block): return YouTubeTranscriptApi.get_transcript(video_id) def run(self, input_data: Input, **kwargs) -> BlockOutput: - try: - video_id = self.extract_video_id(input_data.youtube_url) - yield "video_id", video_id + video_id = self.extract_video_id(input_data.youtube_url) + yield "video_id", video_id - transcript = self.get_transcript(video_id) - formatter = TextFormatter() - transcript_text = formatter.format_transcript(transcript) + transcript = self.get_transcript(video_id) + formatter = TextFormatter() + transcript_text = formatter.format_transcript(transcript) - yield "transcript", transcript_text - except Exception as e: - yield "error", str(e) + yield "transcript", transcript_text diff --git a/autogpt_platform/backend/backend/data/block.py b/autogpt_platform/backend/backend/data/block.py index 554dfc237c..594fd10e76 100644 --- a/autogpt_platform/backend/backend/data/block.py +++ b/autogpt_platform/backend/backend/data/block.py @@ -272,8 +272,8 @@ class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]): for output_name, output_data in self.run( self.input_schema(**input_data), **kwargs ): - if "error" in output_name: - raise ValueError(output_data) + if output_name == "error": + raise RuntimeError(output_data) if error := self.output_schema.validate_field(output_name, output_data): raise ValueError(f"Block produced an invalid output data: {error}") yield output_name, output_data diff --git a/docs/content/server/new_blocks.md b/docs/content/server/new_blocks.md index a3085f1a7e..a56675810b 100644 --- a/docs/content/server/new_blocks.md +++ b/docs/content/server/new_blocks.md @@ -44,7 +44,7 @@ Follow these steps to create and test a new block: class Output(BlockSchema): summary: str # The summary of the topic from Wikipedia - error: str # Any error message if the request fails + error: str # Any error message if the request fails, error field needs to be named `error`. ``` 4. **Implement the `__init__` method, including test data and mocks:** @@ -95,17 +95,13 @@ Follow these steps to create and test a new block: yield "summary", response['extract'] except requests.exceptions.HTTPError as http_err: - yield "error", f"HTTP error occurred: {http_err}" - except requests.RequestException as e: - yield "error", f"Request to Wikipedia failed: {e}" - except KeyError as e: - yield "error", f"Error parsing Wikipedia response: {e}" + raise RuntimeError(f"HTTP error occurred: {http_err}") ``` - **Try block**: Contains the main logic to fetch and process the Wikipedia summary. - **API request**: Send a GET request to the Wikipedia API. - - **Error handling**: Handle various exceptions that might occur during the API request and data processing. - - **Yield**: Use `yield` to output the results. Prefer to output one result object at a time. If you are calling a function that returns a list, you can yield each item in the list separately. You can also yield the whole list as well, but do both rather than yielding the list. For example: If you were writing a block that outputs emails, you'd yield each email as a separate result object, but you could also yield the whole list as an additional single result object. + - **Error handling**: Handle various exceptions that might occur during the API request and data processing. We don't need to catch all exceptions, only the ones we expect and can handle. The uncaught exceptions will be automatically yielded as `error` in the output. Any block that raises an exception (or yields an `error` output) will be marked as failed. Prefer raising exceptions over yielding `error`, as it will stop the execution immediately. + - **Yield**: Use `yield` to output the results. Prefer to output one result object at a time. If you are calling a function that returns a list, you can yield each item in the list separately. You can also yield the whole list as well, but do both rather than yielding the list. For example: If you were writing a block that outputs emails, you'd yield each email as a separate result object, but you could also yield the whole list as an additional single result object. Yielding output named `error` will break the execution right away and mark the block execution as failed. ### Blocks with authentication