Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: image block for claude #9309

Open
wants to merge 30 commits into
base: dev
Choose a base branch
from
Open

feat: image block for claude #9309

wants to merge 30 commits into from

Conversation

ntindle
Copy link
Member

@ntindle ntindle commented Jan 21, 2025

I wanted claude to take image inputs

Changes πŸ—οΈ

Adds image inputs to claude (only latest message)

Checklist πŸ“‹

For code changes:

  • I have clearly listed my changes in the PR description
  • I have made a test plan
  • I have tested my changes according to the test plan:
    • Built agent with it

@ntindle ntindle requested a review from a team as a code owner January 21, 2025 16:03
@ntindle ntindle requested review from Swiftyos and Pwuts and removed request for a team January 21, 2025 16:03
@github-actions github-actions bot added size/l platform/backend AutoGPT Platform - Back end platform/blocks and removed size/l labels Jan 21, 2025
Copy link

PR Reviewer Guide πŸ”

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 πŸ”΅πŸ”΅πŸ”΅πŸ”΅βšͺ
πŸ§ͺΒ PR contains tests
πŸ”’Β Security concerns

Input validation:
The code processes base64 encoded image data from user input without proper validation of the content or size limits. This could potentially lead to memory issues or processing of malicious content. Consider adding validation for maximum image size and proper base64/MIME type validation.

⚑ Recommended focus areas for review

Error Handling

The error handling in the parse_response function returns partial results even when validation fails. Consider returning empty dict consistently on all error cases.

try:
    parsed = json.loads(resp)
    if not isinstance(parsed, dict):
        return {}, f"Expected a dictionary, but got {type(parsed)}"
    if input_data.expected_format:
        miss_keys = set(input_data.expected_format.keys()) - set(
            parsed.keys()
        )
        if miss_keys:
            return parsed, f"Missing keys: {miss_keys}"
    return parsed, None
except JSONDecodeError as e:
    return {}, f"JSON decode error: {e}"
Resource Management

The Anthropic client is created for each call but not properly closed/cleaned up. Consider implementing proper resource management.

client = anthropic.Anthropic(api_key=credentials.api_key.get_secret_value())
Input Validation

The prompt_values handling assumes valid image data without thorough validation of the base64 content and MIME type.

for key, value in values.items():
    if isinstance(value, dict) and "content_type" in value and "data" in value:
        # This is an image
        content.append(
            {
                "type": "image",
                "source": {
                    "type": "base64",
                    "media_type": value["content_type"],
                    "data": value["data"],
                },
            }
        )

@Bentlybro
Copy link
Member

i tried this and this is the full error

2025-01-24 14:21:34 Traceback (most recent call last):
2025-01-24 14:21:34   File "<frozen runpy>", line 198, in _run_module_as_main
2025-01-24 14:21:34   File "<frozen runpy>", line 88, in _run_code
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/rest.py", line 2, in <module>
2025-01-24 14:21:34     from backend.executor import DatabaseManager, ExecutionScheduler
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/executor/__init__.py", line 1, in <module>
2025-01-24 14:21:34     from .database import DatabaseManager
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/executor/database.py", line 4, in <module>
2025-01-24 14:21:34     from backend.data.credit import get_user_credit_model
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/data/credit.py", line 13, in <module>
2025-01-24 14:21:34     from backend.data.block_cost_config import BLOCK_COSTS
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/data/block_cost_config.py", line 3, in <module>
2025-01-24 14:21:34     from backend.blocks.ai_music_generator import AIMusicGeneratorBlock
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/blocks/__init__.py", line 24, in <module>
2025-01-24 14:21:34     importlib.import_module(f".{module}", package=__name__)
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
2025-01-24 14:21:34     return _bootstrap._gcd_import(name[level:], package, level)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/blocks/llm.py", line 1136, in <module>
2025-01-24 14:21:34     class ClaudeWithImageBlock(Block):
2025-01-24 14:21:34   File "/app/autogpt_platform/backend/backend/blocks/llm.py", line 1139, in ClaudeWithImageBlock
2025-01-24 14:21:34     class Input(BlockSchema):
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 226, in __new__
2025-01-24 14:21:34     complete_model_class(
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 658, in complete_model_class
2025-01-24 14:21:34     schema = cls.__get_pydantic_core_schema__(cls, handler)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/main.py", line 702, in __get_pydantic_core_schema__
2025-01-24 14:21:34     return handler(source)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_schema_generation_shared.py", line 84, in __call__
2025-01-24 14:21:34     schema = self._handler(source_type)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 612, in generate_schema
2025-01-24 14:21:34     schema = self._generate_schema_inner(obj)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 881, in _generate_schema_inner
2025-01-24 14:21:34     return self._model_schema(obj)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 693, in _model_schema
2025-01-24 14:21:34     {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
2025-01-24 14:21:34     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 693, in <dictcomp>
2025-01-24 14:21:34     {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
2025-01-24 14:21:34         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 1073, in _generate_md_field_schema
2025-01-24 14:21:34     common_field = self._common_field_schema(name, field_info, decorators)
2025-01-24 14:21:34                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 1265, in _common_field_schema
2025-01-24 14:21:34     schema = self._apply_annotations(
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 2062, in _apply_annotations
2025-01-24 14:21:34     schema = get_inner_schema(source_type)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_schema_generation_shared.py", line 84, in __call__
2025-01-24 14:21:34     schema = self._handler(source_type)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 2043, in inner_handler
2025-01-24 14:21:34     schema = self._generate_schema_inner(obj)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 886, in _generate_schema_inner
2025-01-24 14:21:34     return self.match_type(obj)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 988, in match_type
2025-01-24 14:21:34     return self._match_generic_type(obj, origin)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 1026, in _match_generic_type
2025-01-24 14:21:34     return self._dict_schema(*self._get_first_two_args_or_any(obj))
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 372, in _dict_schema
2025-01-24 14:21:34     return core_schema.dict_schema(self.generate_schema(keys_type), self.generate_schema(values_type))
2025-01-24 14:21:34                                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 612, in generate_schema
2025-01-24 14:21:34     schema = self._generate_schema_inner(obj)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 886, in _generate_schema_inner
2025-01-24 14:21:34     return self.match_type(obj)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 988, in match_type
2025-01-24 14:21:34     return self._match_generic_type(obj, origin)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 1016, in _match_generic_type
2025-01-24 14:21:34     return self._union_schema(obj)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 1327, in _union_schema
2025-01-24 14:21:34     choices.append(self.generate_schema(arg))
2025-01-24 14:21:34                    ^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 612, in generate_schema
2025-01-24 14:21:34     schema = self._generate_schema_inner(obj)
2025-01-24 14:21:34              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 886, in _generate_schema_inner
2025-01-24 14:21:34     return self.match_type(obj)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 958, in match_type
2025-01-24 14:21:34     return self._typed_dict_schema(obj, None)
2025-01-24 14:21:34            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-01-24 14:21:34   File "/usr/local/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py", line 1408, in _typed_dict_schema
2025-01-24 14:21:34     raise PydanticUserError(
2025-01-24 14:21:34 pydantic.errors.PydanticUserError: Please use `typing_extensions.TypedDict` instead of `typing.TypedDict` on Python < 3.12.
2025-01-24 14:21:34 
2025-01-24 14:21:34 For further information visit https://errors.pydantic.dev/2.10/u/typed-dict-version

@ntindle ntindle force-pushed the claude-image-blcok branch from 8ea1e5e to b8749f7 Compare January 26, 2025 13:09
@github-actions github-actions bot added platform/frontend AutoGPT Platform - Front end size/xl and removed size/l labels Jan 26, 2025
@ntindle ntindle changed the base branch from screenshotone to zamilmajdy/multimediafilesupport January 26, 2025 13:09
@github-actions github-actions bot removed the platform/frontend AutoGPT Platform - Front end label Jan 26, 2025
@github-actions github-actions bot added size/l and removed size/xl labels Jan 26, 2025


class Image(BaseModel):
content_type: str # MIME type of the image
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base64 URI is already within this format:

data:mime/type;base64=.......
https://developer.mozilla.org/en-US/docs/Web/URI/Schemes/data#syntax

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#9320 already uses this format, and this can be shown to the frontend directly as embedded image/video/audio

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would that type just be string?

Base automatically changed from zamilmajdy/multimediafilesupport to dev January 26, 2025 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

3 participants