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

Add fileData case to ModelContent.Part enum #12607

Draft
wants to merge 20 commits into
base: vertex-ai
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
42df2e3
Add prototype for Firebase Vertex AI
andrewheard Feb 5, 2024
720fe2f
Update generative-ai-swift dependency
andrewheard Feb 5, 2024
b0f520c
Use Swift 5.9 `AccessLevelOnImport`
andrewheard Feb 14, 2024
4efb1fa
Set Vertex AI endpoint in `RequestOptions`
andrewheard Feb 20, 2024
aaaa3e5
Revert "Use Swift 5.9 `AccessLevelOnImport`"
andrewheard Feb 20, 2024
c09b0db
Add alternative API surface that returns `GenerativeModel` instances
andrewheard Feb 20, 2024
9ccd47c
Add sample apps using Vertex AI
andrewheard Feb 22, 2024
7f6e272
Update generative-ai-swift dependency
andrewheard Feb 22, 2024
b366b9d
Fix optional VertexAIProvider unwrapping
andrewheard Feb 22, 2024
8308b96
Update `generative-ai-swift` dependency
andrewheard Feb 23, 2024
7598e89
Prototype and sample fixes
andrewheard Mar 4, 2024
c2f0d53
Fork `google-generative-ai` for Firebase (#12564)
andrewheard Mar 18, 2024
3ef7816
Use forked `google-generative-ai` in Vertex AI samples (#12574)
andrewheard Mar 18, 2024
8747624
Add CI workflow for Vertex AI (#12577)
andrewheard Mar 18, 2024
2b53776
Fork `generative-ai-swift` tests for Vertex AI (#12584)
andrewheard Mar 19, 2024
aa474f5
Add local App Check package to sample targets (#12576)
morganchen12 Mar 19, 2024
c68e1e3
Use `generative-ai-swift` tests in Vertex AI (#12585)
andrewheard Mar 19, 2024
2aece5b
Add App Check tests in `GenerativeModelTests` (#12590)
andrewheard Mar 20, 2024
f818a54
Make `generativeModel` an instance method of `VertexAI` (#12599)
andrewheard Mar 21, 2024
8141c83
Add `fileData` case to `ModelContent.Part` enum
andrewheard Mar 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/vertexai.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: vertexai

on:
pull_request:
paths:
- 'FirebaseVertexAI**'
- '.github/workflows/vertexai.yml'
- 'Gemfile*'
schedule:
# Run every day at 11pm (PST) - cron uses UTC times
- cron: '0 7 * * *'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
spm:
strategy:
matrix:
target: [iOS, macOS, catalyst]
os: [macos-13]
include:
- os: macos-13
xcode: Xcode_15.2
runs-on: ${{ matrix.os }}
env:
FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1
steps:
- uses: actions/checkout@v4
- name: Xcode
run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
- name: Initialize xcodebuild
run: scripts/setup_spm_tests.sh
- name: Build and run tests
run: scripts/third_party/travis/retry.sh scripts/build.sh FirebaseVertexAIUnit ${{ matrix.target }} spm
1 change: 1 addition & 0 deletions FirebaseCore/Sources/FIRApp.m
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,7 @@ + (void)registerSwiftComponents {
@"FIRSessions" : @"fire-ses",
@"FIRFunctionsComponent" : @"fire-fun",
@"FIRStorageComponent" : @"fire-str",
@"FIRVertexAIComponent" : @"fire-vtx",
};
for (NSString *className in swiftComponents.allKeys) {
Class klass = NSClassFromString(className);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
36 changes: 36 additions & 0 deletions FirebaseVertexAI/Sample/ChatSample/ChatSampleApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import FirebaseCore
import FirebaseVertexAI
import SwiftUI

@main
struct ChatSampleApp: App {
@StateObject
var viewModel = ConversationViewModel()

init() {
FirebaseApp.configure()
}

var body: some Scene {
WindowGroup {
NavigationStack {
ConversationScreen()
.environmentObject(viewModel)
}
}
}
}
64 changes: 64 additions & 0 deletions FirebaseVertexAI/Sample/ChatSample/Models/ChatMessage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Foundation

enum Participant {
case system
case user
}

struct ChatMessage: Identifiable, Equatable {
let id = UUID().uuidString
var message: String
let participant: Participant
var pending = false

static func pending(participant: Participant) -> ChatMessage {
Self(message: "", participant: participant, pending: true)
}
}

extension ChatMessage {
static var samples: [ChatMessage] = [
.init(message: "Hello. What can I do for you today?", participant: .system),
.init(message: "Show me a simple loop in Swift.", participant: .user),
.init(message: """
Sure, here is a simple loop in Swift:

# Example 1
```
for i in 1...5 {
print("Hello, world!")
}
```

This loop will print the string "Hello, world!" five times. The for loop iterates over a range of numbers,
in this case the numbers from 1 to 5. The variable i is assigned each number in the range, and the code inside the loop is executed.

**Here is another example of a simple loop in Swift:**
```swift
var sum = 0
for i in 1...100 {
sum += i
}
print("The sum of the numbers from 1 to 100 is \\(sum).")
```

This loop calculates the sum of the numbers from 1 to 100. The variable sum is initialized to 0, and then the for loop iterates over the range of numbers from 1 to 100. The variable i is assigned each number in the range, and the value of i is added to the sum variable. After the loop has finished executing, the value of sum is printed to the console.
""", participant: .system),
]

static var sample = samples[0]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
127 changes: 127 additions & 0 deletions FirebaseVertexAI/Sample/ChatSample/Screens/ConversationScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import FirebaseVertexAI
import GenerativeAIUIComponents
import SwiftUI

struct ConversationScreen: View {
@EnvironmentObject
var viewModel: ConversationViewModel

@State
private var userPrompt = ""

enum FocusedField: Hashable {
case message
}

@FocusState
var focusedField: FocusedField?

var body: some View {
VStack {
ScrollViewReader { scrollViewProxy in
List {
ForEach(viewModel.messages) { message in
MessageView(message: message)
}
if let error = viewModel.error {
ErrorView(error: error)
.tag("errorView")
}
}
.listStyle(.plain)
.onChange(of: viewModel.messages, perform: { newValue in
if viewModel.hasError {
// wait for a short moment to make sure we can actually scroll to the bottom
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
withAnimation {
scrollViewProxy.scrollTo("errorView", anchor: .bottom)
}
focusedField = .message
}
} else {
guard let lastMessage = viewModel.messages.last else { return }

// wait for a short moment to make sure we can actually scroll to the bottom
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
withAnimation {
scrollViewProxy.scrollTo(lastMessage.id, anchor: .bottom)
}
focusedField = .message
}
}
})
}
InputField("Message...", text: $userPrompt) {
Image(systemName: viewModel.busy ? "stop.circle.fill" : "arrow.up.circle.fill")
.font(.title)
}
.focused($focusedField, equals: .message)
.onSubmit { sendOrStop() }
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: newChat) {
Image(systemName: "square.and.pencil")
}
}
}
.navigationTitle("Chat sample")
.onAppear {
focusedField = .message
}
}

private func sendMessage() {
Task {
let prompt = userPrompt
userPrompt = ""
await viewModel.sendMessage(prompt, streaming: true)
}
}

private func sendOrStop() {
if viewModel.busy {
viewModel.stop()
} else {
sendMessage()
}
}

private func newChat() {
viewModel.startNewChat()
}
}

struct ConversationScreen_Previews: PreviewProvider {
struct ContainerView: View {
@StateObject var viewModel = ConversationViewModel()

var body: some View {
ConversationScreen()
.environmentObject(viewModel)
.onAppear {
viewModel.messages = ChatMessage.samples
}
}
}

static var previews: some View {
NavigationStack {
ConversationScreen()
}
}
}
Loading
Loading