client.go

  1package ollama
  2
  3import (
  4	"bytes"
  5	"context"
  6	"encoding/json"
  7	"fmt"
  8	"net/http"
  9)
 10
 11// httpClient creates a configured HTTP client
 12func httpClient() *http.Client {
 13	return &http.Client{
 14		Timeout: DefaultTimeout,
 15	}
 16}
 17
 18// IsRunning checks if Ollama service is running
 19func IsRunning(ctx context.Context) bool {
 20	return isRunning(ctx, DefaultBaseURL)
 21}
 22
 23// isRunning checks if Ollama is running at the specified URL
 24func isRunning(ctx context.Context, baseURL string) bool {
 25	client := httpClient()
 26
 27	req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/tags", nil)
 28	if err != nil {
 29		return false
 30	}
 31
 32	resp, err := client.Do(req)
 33	if err != nil {
 34		return false
 35	}
 36	defer resp.Body.Close()
 37
 38	return resp.StatusCode == http.StatusOK
 39}
 40
 41// GetModels retrieves all available models
 42func GetModels(ctx context.Context) ([]Model, error) {
 43	return getModels(ctx, DefaultBaseURL)
 44}
 45
 46// getModels retrieves models from the specified URL
 47func getModels(ctx context.Context, baseURL string) ([]Model, error) {
 48	client := httpClient()
 49
 50	req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/tags", nil)
 51	if err != nil {
 52		return nil, fmt.Errorf("failed to create request: %w", err)
 53	}
 54
 55	resp, err := client.Do(req)
 56	if err != nil {
 57		return nil, fmt.Errorf("failed to connect to Ollama: %w", err)
 58	}
 59	defer resp.Body.Close()
 60
 61	if resp.StatusCode != http.StatusOK {
 62		return nil, fmt.Errorf("Ollama returned status %d", resp.StatusCode)
 63	}
 64
 65	var response TagsResponse
 66	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
 67		return nil, fmt.Errorf("failed to decode response: %w", err)
 68	}
 69
 70	return response.Models, nil
 71}
 72
 73// GetRunningModels retrieves currently running models
 74func GetRunningModels(ctx context.Context) ([]RunningModel, error) {
 75	return getRunningModels(ctx, DefaultBaseURL)
 76}
 77
 78// getRunningModels retrieves running models from the specified URL
 79func getRunningModels(ctx context.Context, baseURL string) ([]RunningModel, error) {
 80	client := httpClient()
 81
 82	req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/ps", nil)
 83	if err != nil {
 84		return nil, fmt.Errorf("failed to create request: %w", err)
 85	}
 86
 87	resp, err := client.Do(req)
 88	if err != nil {
 89		return nil, fmt.Errorf("failed to connect to Ollama: %w", err)
 90	}
 91	defer resp.Body.Close()
 92
 93	if resp.StatusCode != http.StatusOK {
 94		return nil, fmt.Errorf("Ollama returned status %d", resp.StatusCode)
 95	}
 96
 97	var response ProcessStatusResponse
 98	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
 99		return nil, fmt.Errorf("failed to decode response: %w", err)
100	}
101
102	return response.Models, nil
103}
104
105// IsModelRunning checks if a specific model is currently running
106func IsModelRunning(ctx context.Context, modelName string) (bool, error) {
107	runningModels, err := GetRunningModels(ctx)
108	if err != nil {
109		return false, err
110	}
111
112	for _, model := range runningModels {
113		if model.Name == modelName {
114			return true, nil
115		}
116	}
117
118	return false, nil
119}
120
121// LoadModel loads a model into memory by sending a simple request
122func LoadModel(ctx context.Context, modelName string) error {
123	return loadModel(ctx, DefaultBaseURL, modelName)
124}
125
126// loadModel loads a model at the specified URL
127func loadModel(ctx context.Context, baseURL, modelName string) error {
128	client := httpClient()
129
130	reqBody := GenerateRequest{
131		Model:  modelName,
132		Prompt: "hi",
133		Stream: false,
134	}
135
136	reqData, err := json.Marshal(reqBody)
137	if err != nil {
138		return fmt.Errorf("failed to marshal request: %w", err)
139	}
140
141	req, err := http.NewRequestWithContext(ctx, "POST", baseURL+"/api/generate", bytes.NewBuffer(reqData))
142	if err != nil {
143		return fmt.Errorf("failed to create request: %w", err)
144	}
145
146	req.Header.Set("Content-Type", "application/json")
147
148	resp, err := client.Do(req)
149	if err != nil {
150		return fmt.Errorf("failed to load model: %w", err)
151	}
152	defer resp.Body.Close()
153
154	if resp.StatusCode != http.StatusOK {
155		return fmt.Errorf("failed to load model, status: %d", resp.StatusCode)
156	}
157
158	return nil
159}