From 70c99725fd12c93136af84a4557742ceea7cce48 Mon Sep 17 00:00:00 2001 From: Emmanuel Auffray Date: Thu, 10 Apr 2025 10:06:37 +1200 Subject: [PATCH] Adding GoogleAI models too (#3689) Signed-off-by: Emmanuel Auffray Co-authored-by: Josh van Leeuwen Co-authored-by: Yaron Schneider Co-authored-by: Cassie Coyle --- conversation/googleai/googleai.go | 132 ++++++++++++++++++++++++++++ conversation/googleai/metadata.yaml | 35 ++++++++ go.mod | 5 ++ go.sum | 10 +++ 4 files changed, 182 insertions(+) create mode 100644 conversation/googleai/googleai.go create mode 100644 conversation/googleai/metadata.yaml diff --git a/conversation/googleai/googleai.go b/conversation/googleai/googleai.go new file mode 100644 index 000000000..700d62a20 --- /dev/null +++ b/conversation/googleai/googleai.go @@ -0,0 +1,132 @@ +/* +Copyright 2024 The Dapr Authors +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. +*/ +package googleai + +import ( + "context" + "reflect" + + "github.com/dapr/components-contrib/conversation" + "github.com/dapr/components-contrib/metadata" + "github.com/dapr/kit/logger" + kmeta "github.com/dapr/kit/metadata" + + "github.com/tmc/langchaingo/llms" + "github.com/tmc/langchaingo/llms/googleai" +) + +type GoogleAI struct { + llm llms.Model + + logger logger.Logger +} + +func NewGoogleAI(logger logger.Logger) conversation.Conversation { + g := &GoogleAI{ + logger: logger, + } + + return g +} + +const defaultModel = "gemini-1.5-flash" + +func (g *GoogleAI) Init(ctx context.Context, meta conversation.Metadata) error { + md := conversation.LangchainMetadata{} + err := kmeta.DecodeMetadata(meta.Properties, &md) + if err != nil { + return err + } + + model := defaultModel + if md.Model != "" { + model = md.Model + } + + opts := []googleai.Option{ + googleai.WithAPIKey(md.Key), + googleai.WithDefaultModel(model), + } + llm, err := googleai.New( + ctx, + opts..., + ) + if err != nil { + return err + } + + g.llm = llm + + if md.CacheTTL != "" { + cachedModel, cacheErr := conversation.CacheModel(ctx, md.CacheTTL, g.llm) + if cacheErr != nil { + return cacheErr + } + + g.llm = cachedModel + } + return nil +} + +func (g *GoogleAI) GetComponentMetadata() (metadataInfo metadata.MetadataMap) { + metadataStruct := conversation.LangchainMetadata{} + metadata.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo, metadata.ConversationType) + return +} + +func (g *GoogleAI) Converse(ctx context.Context, r *conversation.ConversationRequest) (res *conversation.ConversationResponse, err error) { + messages := make([]llms.MessageContent, 0, len(r.Inputs)) + + for _, input := range r.Inputs { + role := conversation.ConvertLangchainRole(input.Role) + + messages = append(messages, llms.MessageContent{ + Role: role, + Parts: []llms.ContentPart{ + llms.TextPart(input.Message), + }, + }) + } + + opts := []llms.CallOption{} + + if r.Temperature > 0 { + opts = append(opts, conversation.LangchainTemperature(r.Temperature)) + } + + resp, err := g.llm.GenerateContent(ctx, messages, opts...) + if err != nil { + return nil, err + } + + outputs := make([]conversation.ConversationResult, 0, len(resp.Choices)) + + for i := range resp.Choices { + outputs = append(outputs, conversation.ConversationResult{ + Result: resp.Choices[i].Content, + Parameters: r.Parameters, + }) + } + + res = &conversation.ConversationResponse{ + Outputs: outputs, + } + + return res, nil +} + +func (g *GoogleAI) Close() error { + return nil +} diff --git a/conversation/googleai/metadata.yaml b/conversation/googleai/metadata.yaml new file mode 100644 index 000000000..4a741723e --- /dev/null +++ b/conversation/googleai/metadata.yaml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: conversation +name: googleai +version: v1 +status: alpha +title: "GoogleAI" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-conversation/googleai/ +authenticationProfiles: + - title: "API Key" + description: "Authenticate using an API key" + metadata: + - name: key + type: string + required: true + sensitive: true + description: | + API key for GoogleAI. + example: "**********" + default: "" +metadata: + - name: model + required: false + description: | + The GoogleAI LLM to use. Defaults to gemini-1.5-flash + type: string + example: 'gemini-2.0-flash' + - name: cacheTTL + required: false + description: | + A time-to-live value for a prompt cache to expire. Uses Golang durations + type: string + example: '10m' diff --git a/go.mod b/go.mod index 7191d5fa6..fe08f72ae 100644 --- a/go.mod +++ b/go.mod @@ -146,10 +146,14 @@ require ( require ( cloud.google.com/go v0.113.0 // indirect + cloud.google.com/go/ai v0.6.0 // indirect + cloud.google.com/go/aiplatform v1.67.0 // indirect cloud.google.com/go/auth v0.4.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.7 // indirect + cloud.google.com/go/longrunning v0.5.7 // indirect + cloud.google.com/go/vertexai v0.10.0 // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect @@ -261,6 +265,7 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v23.5.26+incompatible // indirect + github.com/google/generative-ai-go v0.14.0 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect diff --git a/go.sum b/go.sum index 57cc6afdb..135bef03e 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,10 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.113.0 h1:g3C70mn3lWfckKBiCVsAshabrDg01pQ0pnX1MNtnMkA= cloud.google.com/go v0.113.0/go.mod h1:glEqlogERKYeePz6ZdkcLJ28Q2I6aERgDDErBg9GzO8= +cloud.google.com/go/ai v0.6.0 h1:QWjb2UoaM15e51IMeLuIUFyWxooKOKDb66Mk47zZ2/g= +cloud.google.com/go/ai v0.6.0/go.mod h1:6/mrRq6aJdK7MZH76ZvcMpESiAiha5aRvurmroiOrgI= +cloud.google.com/go/aiplatform v1.67.0 h1:YWeqD4BjYwrmY4fa+isGcw0P81lJ3dKVxbWxdBchoiU= +cloud.google.com/go/aiplatform v1.67.0/go.mod h1:s/sJ6btBEr6bKnrNWdK9ZgHCvwbZNdP90b3DDtxxw+Y= cloud.google.com/go/auth v0.4.1 h1:Z7YNIhlWRtrnKlZke7z3GMqzvuYzdc2z98F9D1NV5Hg= cloud.google.com/go/auth v0.4.1/go.mod h1:QVBuVEKpCn4Zp58hzRGvL0tjRGU0YqdRTdCHM1IHnro= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= @@ -36,6 +40,8 @@ cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= +cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= +cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -51,6 +57,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= +cloud.google.com/go/vertexai v0.10.0 h1:k157bLrtyajGtAAZnqdEn8lwFlUTG3BgHc7kvWbP/3s= +cloud.google.com/go/vertexai v0.10.0/go.mod h1:w/Zb22QvOVvxx5CGM4fPzH3WA6gwUkId9juA7pigzFI= contrib.go.opencensus.io/exporter/prometheus v0.4.1/go.mod h1:t9wvfitlUjGXG2IXAZsuFq26mDGid/JwCEXp+gTG/9U= contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= @@ -797,6 +805,8 @@ github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl76 github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/generative-ai-go v0.14.0 h1:2GwFKXui9LmG+PukQwYk9KpJUIemmQ9NJ46BV9VIw38= +github.com/google/generative-ai-go v0.14.0/go.mod h1:hOzbW3cB5hRV2x05McOwJS4GsqSluYwejjk5tSfb6YY= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=