client.go 1.79 KB
Newer Older
Jeffrey Morgan's avatar
Jeffrey Morgan committed
1
2
3
package api

import (
Jeffrey Morgan's avatar
Jeffrey Morgan committed
4
	"bufio"
Jeffrey Morgan's avatar
Jeffrey Morgan committed
5
6
7
8
9
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
Michael Yang's avatar
Michael Yang committed
10
	"net/url"
Jeffrey Morgan's avatar
Jeffrey Morgan committed
11
12
13
)

type Client struct {
Michael Yang's avatar
Michael Yang committed
14
15
16
17
18
19
20
21
22
23
24
25
	base url.URL
}

func NewClient(hosts ...string) *Client {
	host := "127.0.0.1:11434"
	if len(hosts) > 0 {
		host = hosts[0]
	}

	return &Client{
		base: url.URL{Scheme: "http", Host: host},
	}
Jeffrey Morgan's avatar
Jeffrey Morgan committed
26
27
}

Michael Yang's avatar
Michael Yang committed
28
func (c *Client) stream(ctx context.Context, method string, path string, reqData any, fn func(bts []byte) error) error {
Jeffrey Morgan's avatar
Jeffrey Morgan committed
29
30
31
32
33
34
35
36
37
38
39
	var reqBody io.Reader
	var data []byte
	var err error
	if reqData != nil {
		data, err = json.Marshal(reqData)
		if err != nil {
			return err
		}
		reqBody = bytes.NewReader(data)
	}

Michael Yang's avatar
Michael Yang committed
40
	request, err := http.NewRequestWithContext(ctx, method, c.base.JoinPath(path).String(), reqBody)
Jeffrey Morgan's avatar
Jeffrey Morgan committed
41
42
43
44
	if err != nil {
		return err
	}

Michael Yang's avatar
Michael Yang committed
45
46
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("Accept", "application/json")
Jeffrey Morgan's avatar
Jeffrey Morgan committed
47

Michael Yang's avatar
Michael Yang committed
48
	response, err := http.DefaultClient.Do(request)
Jeffrey Morgan's avatar
Jeffrey Morgan committed
49
50
51
	if err != nil {
		return err
	}
Michael Yang's avatar
Michael Yang committed
52
	defer response.Body.Close()
Jeffrey Morgan's avatar
Jeffrey Morgan committed
53

Michael Yang's avatar
Michael Yang committed
54
	scanner := bufio.NewScanner(response.Body)
Michael Yang's avatar
Michael Yang committed
55
56
	for scanner.Scan() {
		if err := fn(scanner.Bytes()); err != nil {
Jeffrey Morgan's avatar
Jeffrey Morgan committed
57
58
59
60
			return err
		}
	}

Michael Yang's avatar
Michael Yang committed
61
62
	return nil
}
Jeffrey Morgan's avatar
Jeffrey Morgan committed
63

Michael Yang's avatar
Michael Yang committed
64
type GenerateResponseFunc func(GenerateResponse) error
Jeffrey Morgan's avatar
Jeffrey Morgan committed
65

Michael Yang's avatar
Michael Yang committed
66
67
68
69
func (c *Client) Generate(ctx context.Context, req *GenerateRequest, fn GenerateResponseFunc) error {
	return c.stream(ctx, http.MethodPost, "/api/generate", req, func(bts []byte) error {
		var resp GenerateResponse
		if err := json.Unmarshal(bts, &resp); err != nil {
Jeffrey Morgan's avatar
Jeffrey Morgan committed
70
71
			return err
		}
Jeffrey Morgan's avatar
Jeffrey Morgan committed
72

Michael Yang's avatar
Michael Yang committed
73
74
		return fn(resp)
	})
Jeffrey Morgan's avatar
Jeffrey Morgan committed
75
}
Bruce MacDonald's avatar
Bruce MacDonald committed
76

Michael Yang's avatar
Michael Yang committed
77
78
79
80
81
82
83
type PullProgressFunc func(PullProgress) error

func (c *Client) Pull(ctx context.Context, req *PullRequest, fn PullProgressFunc) error {
	return c.stream(ctx, http.MethodPost, "/api/pull", req, func(bts []byte) error {
		var resp PullProgress
		if err := json.Unmarshal(bts, &resp); err != nil {
			return err
Bruce MacDonald's avatar
Bruce MacDonald committed
84
		}
Bruce MacDonald's avatar
Bruce MacDonald committed
85

Michael Yang's avatar
Michael Yang committed
86
87
		return fn(resp)
	})
Bruce MacDonald's avatar
Bruce MacDonald committed
88
}