Skip to content

Commit

Permalink
Add support for referring to uploaded files (#115)
Browse files Browse the repository at this point in the history
Adding only the support to refer to files which for now need to be
uploaded separately.

- Add a `FilePart` subclass of `Part` with a Uri argument for a file
  uploaded to the google AI file service.
- Change an exhaustive switch on a `Part` to an if/else to avoid needing
  to update for further new subtypes of `Part`.
- Add the new classes to an exhaustive switch in a testing utility.
  • Loading branch information
natebosch authored Apr 10, 2024
1 parent 20e96b9 commit 1c34637
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 13 deletions.
4 changes: 3 additions & 1 deletion pkgs/google_generative_ai/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
## 0.2.4-wip
## 0.3.0-wip

- Allow specifying an API version in a `requestOptions` argument when
constructing a model.
- Add support for referring to uploaded files in request contents.
- **Breaking** Added a new subclass `FilePart` of the sealed class `Part`.

## 0.2.3

Expand Down
2 changes: 1 addition & 1 deletion pkgs/google_generative_ai/lib/google_generative_ai.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export 'src/api.dart'
SafetySetting,
TaskType;
export 'src/chat.dart' show ChatSession, StartChatExtension;
export 'src/content.dart' show Content, DataPart, Part, TextPart;
export 'src/content.dart' show Content, DataPart, FilePart, Part, TextPart;
export 'src/error.dart'
show
GenerativeAIException,
Expand Down
17 changes: 8 additions & 9 deletions pkgs/google_generative_ai/lib/src/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,14 @@ final class ChatSession {

for (final content in contents) {
for (final part in content.parts) {
switch (part) {
case TextPart(:final text):
if (text.isNotEmpty) {
previousText = textBuffer.isEmpty ? part : null;
textBuffer.write(text);
}
case DataPart():
addBufferedText();
parts.add(part);
if (part case TextPart(:final text)) {
if (text.isNotEmpty) {
previousText = textBuffer.isEmpty ? part : null;
textBuffer.write(text);
}
} else {
addBufferedText();
parts.add(part);
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions pkgs/google_generative_ai/lib/src/content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ final class TextPart implements Part {
Object toJson() => {'text': text};
}

/// A [Part] with the byte content of a file.
final class DataPart implements Part {
final String mimeType;
final Uint8List bytes;
Expand All @@ -84,3 +85,15 @@ final class DataPart implements Part {
'inlineData': {'data': base64Encode(bytes), 'mimeType': mimeType}
};
}

/// A [Part] referring to an uploaded file.
///
/// The [uri] should refer to a file uploaded to the Google AI File Service API.
final class FilePart implements Part {
final Uri uri;
FilePart(this.uri);
@override
Object toJson() => {
'file_data': {'file_uri': '$uri'}
};
}
2 changes: 1 addition & 1 deletion pkgs/google_generative_ai/lib/src/version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
// See the License for the specific language governing permissions and
// limitations under the License.

const packageVersion = '0.2.4-wip';
const packageVersion = '0.3.0-wip';
2 changes: 1 addition & 1 deletion pkgs/google_generative_ai/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: google_generative_ai
version: 0.2.4-wip
version: 0.3.0-wip
description: >-
The Google AI Dart SDK enables developers to use Google's state-of-the-art
generative AI models (like Gemini).
Expand Down
4 changes: 4 additions & 0 deletions pkgs/google_generative_ai/test/utils/matchers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Matcher matchesPart(Part part) => switch (part) {
// TODO: When updating min SDK remove ignore.
// ignore: unused_result, implementation bug
.having((p) => p.bytes, 'bytes', bytes),
FilePart(uri: final uri) => isA<FilePart>()
// TODO: When updating min SDK remove ignore.
// ignore: unused_result, implementation bug
.having((p) => p.uri, 'uri', uri),
};

Matcher matchesContent(Content content) => isA<Content>()
Expand Down

0 comments on commit 1c34637

Please sign in to comment.