prompt.go 1.67 KB
Newer Older
1
2
3
package server

import (
Michael Yang's avatar
Michael Yang committed
4
5
	"bytes"
	"context"
6
	"log/slog"
Michael Yang's avatar
Michael Yang committed
7
	"slices"
8

9
	"github.com/ollama/ollama/api"
Michael Yang's avatar
Michael Yang committed
10
	"github.com/ollama/ollama/llm"
Michael Yang's avatar
Michael Yang committed
11
	"github.com/ollama/ollama/template"
12
13
)

Michael Yang's avatar
Michael Yang committed
14
15
16
17
18
19
20
func chatPrompt(ctx context.Context, r *runnerRef, msgs []api.Message) (prompt string, images []llm.ImageData, _ error) {
	// extract system messages which should always be included
	var system []api.Message
	msgs = slices.DeleteFunc(msgs, func(m api.Message) bool {
		if m.Role == "system" {
			system = append(system, m)
			return true
21
22
		}

Michael Yang's avatar
Michael Yang committed
23
24
		return false
	})
25

Michael Yang's avatar
Michael Yang committed
26
27
28
	if len(system) == 0 && r.model.System != "" {
		// add model system prompt since it wasn't provided
		system = append(system, api.Message{Role: "system", Content: r.model.System})
29
30
	}

Michael Yang's avatar
Michael Yang committed
31
32
33
34
35
	n := len(msgs) - 1
	for i := n - 1; i >= 0; i-- {
		var b bytes.Buffer
		if err := r.model.Template.Execute(&b, template.Values{Messages: append(system, msgs[i:]...)}); err != nil {
			return "", nil, err
36
37
		}

Michael Yang's avatar
Michael Yang committed
38
		s, err := r.llama.Tokenize(ctx, b.String())
39
		if err != nil {
Michael Yang's avatar
Michael Yang committed
40
			return "", nil, err
41
42
		}

Michael Yang's avatar
Michael Yang committed
43
44
45
46
47
48
		c := len(s)
		if r.model.ProjectorPaths != nil {
			for _, m := range msgs[i:] {
				// TODO: get image embedding length from project metadata
				c += 768 * len(m.Images)
			}
49
50
		}

Michael Yang's avatar
Michael Yang committed
51
52
		if c > r.NumCtx {
			slog.Debug("truncating input messages which exceed context length", "truncated", len(msgs[i:]))
53
			break
Michael Yang's avatar
Michael Yang committed
54
55
		} else {
			n = i
56
		}
Michael Yang's avatar
Michael Yang committed
57
	}
58

Michael Yang's avatar
Michael Yang committed
59
60
61
	var b bytes.Buffer
	if err := r.model.Template.Execute(&b, template.Values{Messages: append(system, msgs[n:]...)}); err != nil {
		return "", nil, err
62
63
	}

Michael Yang's avatar
Michael Yang committed
64
65
66
67
68
69
	for _, m := range msgs[n:] {
		for _, i := range m.Images {
			images = append(images, llm.ImageData{
				ID:   len(images),
				Data: i,
			})
70
71
72
		}
	}

Michael Yang's avatar
Michael Yang committed
73
	return b.String(), images, nil
74
}