Skip to content

Commit 47947d8

Browse files
ManuInNZmikeeeyaron2
authored
Adding Ollama as a conversation component for local dev/running of LLMs (#3688)
Signed-off-by: Emmanuel Auffray <[email protected]> Co-authored-by: Mike Nguyen <[email protected]> Co-authored-by: Yaron Schneider <[email protected]>
1 parent b348969 commit 47947d8

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

conversation/ollama/metadata.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# yaml-language-server: $schema=../../../component-metadata-schema.json
2+
schemaVersion: v1
3+
type: conversation
4+
name: ollama
5+
version: v1
6+
status: alpha
7+
title: "Ollama"
8+
urls:
9+
- title: Reference
10+
url: https://docs.dapr.io/reference/components-reference/supported-conversation/ollama/
11+
metadata:
12+
- name: model
13+
required: false
14+
description: |
15+
The Ollama LLM to use. Defaults to llama3.2:latest
16+
type: string
17+
example: 'llama3.2:latest'
18+
- name: cacheTTL
19+
required: false
20+
description: |
21+
A time-to-live value for a prompt cache to expire. Uses Golang durations
22+
type: string
23+
example: '10m'

conversation/ollama/ollama.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
Copyright 2024 The Dapr Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
package ollama
16+
17+
import (
18+
"context"
19+
"reflect"
20+
21+
"github.com/dapr/components-contrib/conversation"
22+
"github.com/dapr/components-contrib/metadata"
23+
"github.com/dapr/kit/logger"
24+
kmeta "github.com/dapr/kit/metadata"
25+
26+
"github.com/tmc/langchaingo/llms"
27+
"github.com/tmc/langchaingo/llms/ollama"
28+
)
29+
30+
type Ollama struct {
31+
llm llms.Model
32+
33+
logger logger.Logger
34+
}
35+
36+
func NewOllama(logger logger.Logger) conversation.Conversation {
37+
o := &Ollama{
38+
logger: logger,
39+
}
40+
41+
return o
42+
}
43+
44+
const defaultModel = "llama3.2:latest"
45+
46+
func (o *Ollama) Init(ctx context.Context, meta conversation.Metadata) error {
47+
md := conversation.LangchainMetadata{}
48+
err := kmeta.DecodeMetadata(meta.Properties, &md)
49+
if err != nil {
50+
return err
51+
}
52+
53+
model := defaultModel
54+
if md.Model != "" {
55+
model = md.Model
56+
}
57+
58+
llm, err := ollama.New(
59+
ollama.WithModel(model),
60+
)
61+
if err != nil {
62+
return err
63+
}
64+
65+
o.llm = llm
66+
67+
if md.CacheTTL != "" {
68+
cachedModel, cacheErr := conversation.CacheModel(ctx, md.CacheTTL, o.llm)
69+
if cacheErr != nil {
70+
return cacheErr
71+
}
72+
73+
o.llm = cachedModel
74+
}
75+
return nil
76+
}
77+
78+
func (o *Ollama) GetComponentMetadata() (metadataInfo metadata.MetadataMap) {
79+
metadataStruct := conversation.LangchainMetadata{}
80+
metadata.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo, metadata.ConversationType)
81+
return
82+
}
83+
84+
func (o *Ollama) Converse(ctx context.Context, r *conversation.ConversationRequest) (res *conversation.ConversationResponse, err error) {
85+
messages := make([]llms.MessageContent, 0, len(r.Inputs))
86+
87+
for _, input := range r.Inputs {
88+
role := conversation.ConvertLangchainRole(input.Role)
89+
90+
messages = append(messages, llms.MessageContent{
91+
Role: role,
92+
Parts: []llms.ContentPart{
93+
llms.TextPart(input.Message),
94+
},
95+
})
96+
}
97+
98+
opts := []llms.CallOption{}
99+
100+
if r.Temperature > 0 {
101+
opts = append(opts, conversation.LangchainTemperature(r.Temperature))
102+
}
103+
104+
resp, err := o.llm.GenerateContent(ctx, messages, opts...)
105+
if err != nil {
106+
return nil, err
107+
}
108+
109+
outputs := make([]conversation.ConversationResult, 0, len(resp.Choices))
110+
111+
for i := range resp.Choices {
112+
outputs = append(outputs, conversation.ConversationResult{
113+
Result: resp.Choices[i].Content,
114+
Parameters: r.Parameters,
115+
})
116+
}
117+
118+
res = &conversation.ConversationResponse{
119+
Outputs: outputs,
120+
}
121+
122+
return res, nil
123+
}
124+
125+
func (o *Ollama) Close() error {
126+
return nil
127+
}

0 commit comments

Comments
 (0)