Repository navigation
mime_type and resolution parameters aded to the dspy.File type
#10500
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
base: main
Are you sure you want to change the base?
Changes from all commits
939f387
edb02b5
37ce589
c235e72
0b717c1
0d8faa4
dd6fbfa
dddb22a
25d70d9
d1f0258
a6f20fd
1d77e39
3017d20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -36,6 +36,8 @@ class QA(dspy.Signature): | |||||||||
| file_data: str | None = None | ||||||||||
| file_id: str | None = None | ||||||||||
| filename: str | None = None | ||||||||||
| mime_type: str | None = None | ||||||||||
| resolution: str | None = None | ||||||||||
|
|
||||||||||
| model_config = pydantic.ConfigDict( | ||||||||||
| frozen=True, | ||||||||||
|
|
@@ -66,6 +68,8 @@ def validate_input(cls, values: Any) -> Any: | |||||||||
| "file_data": values.file_data, | ||||||||||
| "file_id": values.file_id, | ||||||||||
| "filename": values.filename, | ||||||||||
| "mime_type": values.mime_type, | ||||||||||
| "resolution": values.resolution | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if isinstance(values, dict): | ||||||||||
|
|
@@ -84,6 +88,10 @@ def format(self) -> list[dict[str, Any]]: | |||||||||
| file_dict["file_id"] = self.file_id | ||||||||||
| if self.filename: | ||||||||||
| file_dict["filename"] = self.filename | ||||||||||
| if self.mime_type: | ||||||||||
| file_dict["format"] = self.mime_type | ||||||||||
| if self.resolution: | ||||||||||
| file_dict["resolution"] = self.resolution | ||||||||||
|
|
||||||||||
| return [{"type": "file", "file": file_dict}] | ||||||||||
| except Exception as e: | ||||||||||
|
|
@@ -98,9 +106,7 @@ def __repr__(self): | |||||||||
| if self.file_data.startswith("data:"): | ||||||||||
| # file data has "data:text/plain;base64,..." format | ||||||||||
| mime_type = self.file_data.split(";")[0].split(":")[1] | ||||||||||
| len_data = ( | ||||||||||
| len(self.file_data.split("base64,")[1]) if "base64," in self.file_data else len(self.file_data) | ||||||||||
| ) | ||||||||||
| len_data = len(self.file_data.split("base64,")[1]) if "base64," in self.file_data else len(self.file_data) | ||||||||||
| parts.append(f"file_data=<DATA_URI({mime_type}, {len_data} chars)>") | ||||||||||
| else: | ||||||||||
| len_data = len(self.file_data) | ||||||||||
|
|
@@ -109,16 +115,21 @@ def __repr__(self): | |||||||||
| parts.append(f"file_id='{self.file_id}'") | ||||||||||
| if self.filename is not None: | ||||||||||
| parts.append(f"filename='{self.filename}'") | ||||||||||
| if self.mime_type is not None: | ||||||||||
| parts.append(f"mime_type='{self.mime_type}'") | ||||||||||
| if self.resolution is not None: | ||||||||||
| parts.append(f"resolution='{self.resolution}'") | ||||||||||
| return f"File({', '.join(parts)})" | ||||||||||
|
|
||||||||||
| @classmethod | ||||||||||
| def from_path(cls, file_path: str, filename: str | None = None, mime_type: str | None = None) -> "File": | ||||||||||
| def from_path(cls, file_path: str, filename: str | None = None, mime_type: str | None = None, resolution: str | None = None) -> "File": | ||||||||||
| """Create a File from a local file path. | ||||||||||
|
|
||||||||||
| Args: | ||||||||||
| file_path: Path to the file to read | ||||||||||
| filename: Optional filename to use (defaults to basename of path) | ||||||||||
| mime_type: Optional MIME type (defaults to auto-detection from file extension) | ||||||||||
| resolution: Optional resolution used to rescale the file by some providers | ||||||||||
| """ | ||||||||||
| if not os.path.isfile(file_path): | ||||||||||
| raise ValueError(f"File not found: {file_path}") | ||||||||||
|
|
@@ -137,11 +148,13 @@ def from_path(cls, file_path: str, filename: str | None = None, mime_type: str | | |||||||||
| encoded_data = base64.b64encode(file_bytes).decode("utf-8") | ||||||||||
| file_data = f"data:{mime_type};base64,{encoded_data}" | ||||||||||
|
|
||||||||||
| return cls(file_data=file_data, filename=filename) | ||||||||||
| return cls(file_data=file_data, filename=filename, resolution=resolution) | ||||||||||
|
|
||||||||||
| @classmethod | ||||||||||
| def from_bytes( | ||||||||||
| cls, file_bytes: bytes, filename: str | None = None, mime_type: str = "application/octet-stream" | ||||||||||
| cls, file_bytes: bytes, filename: str | None = None, | ||||||||||
| mime_type: str = "application/octet-stream", | ||||||||||
| resolution:str = "medium" | ||||||||||
| ) -> "File": | ||||||||||
| """Create a File from raw bytes. | ||||||||||
|
|
||||||||||
|
|
@@ -152,12 +165,22 @@ def from_bytes( | |||||||||
| """ | ||||||||||
| encoded_data = base64.b64encode(file_bytes).decode("utf-8") | ||||||||||
| file_data = f"data:{mime_type};base64,{encoded_data}" | ||||||||||
| return cls(file_data=file_data, filename=filename) | ||||||||||
| return cls(file_data=file_data, filename=filename, resolution=resolution) | ||||||||||
|
|
||||||||||
| @classmethod | ||||||||||
| def from_file_id(cls, file_id: str, filename: str | None = None) -> "File": | ||||||||||
| """Create a File from an uploaded file ID.""" | ||||||||||
| return cls(file_id=file_id, filename=filename) | ||||||||||
| def from_file_id(cls, file_id: str, filename: str | None = None, | ||||||||||
| mime_type: str | None = None, | ||||||||||
| resolution: str | None = None | ||||||||||
| ) -> "File": | ||||||||||
| """Create a File from an uploaded file ID. | ||||||||||
|
|
||||||||||
| Args: | ||||||||||
| file_id: The uploaded file ID | ||||||||||
| filename: Optional filename | ||||||||||
| mime_type: Optional MIME type (passed as 'format' to the API) | ||||||||||
| resolution: Optional file resolution (e.g., low, medium, high) | ||||||||||
| """ | ||||||||||
| return cls(file_id=file_id, filename=filename, mime_type=mime_type, resolution=resolution) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def encode_file_to_dict(file_input: Any) -> dict: | ||||||||||
|
|
@@ -178,6 +201,10 @@ def encode_file_to_dict(file_input: Any) -> dict: | |||||||||
| result["file_id"] = file_input.file_id | ||||||||||
| if file_input.filename is not None: | ||||||||||
| result["filename"] = file_input.filename | ||||||||||
| if file_input.mime_type is not None: | ||||||||||
| result["format"] = file_input.mime_type | ||||||||||
|
Comment on lines
+204
to
+205
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! ArtifactsExecuted File constructor reproduction script
Constructor output without a MIME type
Constructor output with a MIME type
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The File model has aalready been updated in this fix to inlcude
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing that out. In the revision under review, Therefore, Tip: You can customize Greptile's behavior for this repo with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right that
Suggested change
The |
||||||||||
| if file_input.resolution is not None: | ||||||||||
| result["resolution"] = file_input.resolution | ||||||||||
| return result | ||||||||||
|
|
||||||||||
| elif isinstance(file_input, dict): | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
from_file_idsets a MIME type or resolution,format()emitsformatorresolutionin the file block. Native conversion rejects either field, so a native Gemini request using the new metadata fails before reaching the provider. This must be fixed before merging.Knowledge Base Used: Language model integration
Artifacts
Executable Gemini file-ID reproduction script
Gemini file-ID run before the change
Gemini file-ID run after the change