ronantakizawa/codereview-bench huggingface dataset:
Repository: ollama/ollama
File: app/src/index.ts (TypeScript)

Code before:
  tray.setContextMenu(contextMenu)
  tray.setToolTip('Ollama')
}

if (require('electron-squirrel-startup')) {
  app.quit()
}

function server() {
  const binary = app.isPackaged
  ? path.join(process.resourcesPath, 'ollama')
  : path.resolve(process.cwd(), '..', 'ollama')

  const proc = spawn(binary, ['serve'])

  proc.stdout.on('data', data => {
    logger.info(data.toString().trim())
  })

  proc.stderr.on('data', data => {
    logger.error(data.toString().trim())
  })
    

  proc.on('exit', (code, signal) => {
    if (code === 0 || code === null) {
      logger.info('Server has stopped.')
      setTimeout(server, 5000)
    } else {
      logger.error(`Server exited with code: ${code}, signal: ${signal}`)
      setTimeout(server, 3000)
    }
  })

  app.on('before-quit', () => {
    proc.off('exit', server)
    proc.kill()
  })
}

if (process.platform === 'darwin') {
  app.dock.hide()
}

app.on('ready', () => {
  if (process.platform === 'darwin') {
    if (app.isPackaged) {
      if (!app.isInApplicationsFolder()) {
        const chosen = dialog.showMessageBoxSync({
          type: 'question',
          buttons: ['Move to Applications', 'Do Not Move'],

Review comment (suggestion):
Would it be better to do:

```
if (!code) {
```

Code after:
  tray.setContextMenu(contextMenu)
  tray.setToolTip('Ollama')
}

if (require('electron-squirrel-startup')) {
  app.quit()
}

function server() {
  const binary = app.isPackaged
    ? path.join(process.resourcesPath, 'ollama')
    : path.resolve(process.cwd(), '..', 'ollama')

  const proc = spawn(binary, ['serve'])

  proc.stdout.on('data', data => {
    logger.info(data.toString().trim())
  })

  proc.stderr.on('data', data => {
    logger.error(data.toString().trim())
  })

  function restart() {
    setTimeout(server, 3000)
  }

  proc.on('exit', restart)

  app.on('before-quit', () => {
    proc.off('exit', restart)
    proc.kill()
  })
}

if (process.platform === 'darwin') {
  app.dock.hide()
}

app.on('ready', () => {
  if (process.platform === 'darwin') {
    if (app.isPackaged) {
      if (!app.isInApplicationsFolder()) {
        const chosen = dialog.showMessageBoxSync({
          type: 'question',
          buttons: ['Move to Applications', 'Do Not Move'],
          message: 'Ollama works best when run from the Applications directory.',
          defaultId: 0,
          cancelId: 1,
        })
Repository: ollama/ollama
File: app/src/index.ts (TypeScript)

Code before:
}

function server() {
  const binary = app.isPackaged
  ? path.join(process.resourcesPath, 'ollama')
  : path.resolve(process.cwd(), '..', 'ollama')

  const proc = spawn(binary, ['serve'])

  proc.stdout.on('data', data => {
    logger.info(data.toString().trim())
  })

  proc.stderr.on('data', data => {
    logger.error(data.toString().trim())
  })
    

  proc.on('exit', (code, signal) => {
    if (!code) {
      logger.info('Server has stopped.')
      setTimeout(server, 5000)
    } else {
      logger.error(`Server exited with code: ${code}, signal: ${signal}`)
      setTimeout(server, 3000)
    }
  })

  app.on('before-quit', () => {
    proc.off('exit', server)
    proc.kill()
  })
}

if (process.platform === 'darwin') {
  app.dock.hide()
}

app.on('ready', () => {
  if (process.platform === 'darwin') {
    if (app.isPackaged) {
      if (!app.isInApplicationsFolder()) {
        const chosen = dialog.showMessageBoxSync({
          type: 'question',
          buttons: ['Move to Applications', 'Do Not Move'],
          message: 'Ollama works best when run from the Applications directory.',
          defaultId: 0,
          cancelId: 1,
        })

        if (chosen === 0) {

Review comment (suggestion):
```suggestion
    logger.error(`Server exited with code: ${code}`)
    setTimeout(server, 3000)
```

Code after:
}

function server() {
  const binary = app.isPackaged
    ? path.join(process.resourcesPath, 'ollama')
    : path.resolve(process.cwd(), '..', 'ollama')

  const proc = spawn(binary, ['serve'])

  proc.stdout.on('data', data => {
    logger.info(data.toString().trim())
  })

  proc.stderr.on('data', data => {
    logger.error(data.toString().trim())
  })

  function restart() {
    setTimeout(server, 3000)
  }

  proc.on('exit', restart)

  app.on('before-quit', () => {
    proc.off('exit', restart)
    proc.kill()
  })
}

if (process.platform === 'darwin') {
  app.dock.hide()
}

app.on('ready', () => {
  if (process.platform === 'darwin') {
    if (app.isPackaged) {
      if (!app.isInApplicationsFolder()) {
        const chosen = dialog.showMessageBoxSync({
          type: 'question',
          buttons: ['Move to Applications', 'Do Not Move'],
          message: 'Ollama works best when run from the Applications directory.',
          defaultId: 0,
          cancelId: 1,
        })

        if (chosen === 0) {
          try {
            app.moveToApplicationsFolder({
              conflictHandler: conflictType => {
                if (conflictType === 'existsAndRunning') {
                  dialog.showMessageBoxSync({
Repository: ollama/ollama
File: parser/parser.go (Go)

Code before:

type Command struct {
	Name string
	Args string
}

func (c *Command) Reset() {
	c.Name = ""
	c.Args = ""
}

func Parse(reader io.Reader) ([]Command, error) {
	var commands []Command
	var command, modelCommand Command

	scanner := bufio.NewScanner(reader)
	scanner.Split(scanModelfile)
	for scanner.Scan() {
		line := scanner.Bytes()

		fields := bytes.SplitN(line, []byte(" "), 2)
		if len(fields) == 0 {
			continue
		}

		switch strings.ToUpper(string(fields[0])) {
		case "FROM":
			command.Name = "model"
			command.Args = string(fields[1])
			// copy command for validation
			modelCommand = command
		case "LICENSE", "TEMPLATE", "SYSTEM", "PROMPT":
			command.Name = strings.ToLower(string(fields[0]))
			command.Args = string(fields[1])
		case "PARAMETER":
			fields = bytes.SplitN(fields[1], []byte(" "), 2)
			command.Name = string(fields[0])
			command.Args = string(fields[1])
		default:
			return nil, fmt.Errorf("unknown command: %s", fields[0])
		}

		commands = append(commands, command)
		command.Reset()
	}

	if modelCommand.Args == "" {
		return nil, errors.New("no FROM line for the model was specified")
	}

	return commands, scanner.Err()

Review comment (suggestion):
These are functionally identical. The previous version was picked because it would not be necessary to import `strings`.

Code after:
	Name string
	Args string
}

func (c *Command) Reset() {
	c.Name = ""
	c.Args = ""
}

func Parse(reader io.Reader) ([]Command, error) {
	var commands []Command
	var command, modelCommand Command

	scanner := bufio.NewScanner(reader)
	scanner.Split(scanModelfile)
	for scanner.Scan() {
		line := scanner.Bytes()

		fields := bytes.SplitN(line, []byte(" "), 2)
		if len(fields) == 0 {
			continue
		}

		switch string(bytes.ToUpper(fields[0])) {
		case "FROM":
			command.Name = "model"
			command.Args = string(fields[1])
			// copy command for validation
			modelCommand = command
		case "LICENSE", "TEMPLATE", "SYSTEM", "PROMPT":
			command.Name = string(bytes.ToLower(fields[0]))
			command.Args = string(fields[1])
		case "PARAMETER":
			fields = bytes.SplitN(fields[1], []byte(" "), 2)
			command.Name = string(fields[0])
			command.Args = string(fields[1])
		default:
			// log a warning for unknown commands
			fmt.Printf("WARNING: Unknown command: %s\n", fields[0])
			continue
		}

		commands = append(commands, command)
		command.Reset()
	}

	if modelCommand.Args == "" {
		return nil, errors.New("no FROM line for the model was specified")
	}

	return commands, scanner.Err()
Repository: ollama/ollama
File: parser/parser.go (Go)

Code before:
	"errors"
	"fmt"
	"io"
)

type Command struct {
	Name string
	Args string
}

func (c *Command) Reset() {
	c.Name = ""
	c.Args = ""
}

func Parse(reader io.Reader) ([]Command, error) {
	var commands []Command
	var command, modelCommand Command

	scanner := bufio.NewScanner(reader)
	scanner.Split(scanModelfile)
	for scanner.Scan() {
		line := scanner.Bytes()

		fields := bytes.SplitN(line, []byte(" "), 2)
		if len(fields) == 0 {
			continue
		}

		switch string(bytes.ToUpper(fields[0])) {
		case "FROM":
			command.Name = "model"
			command.Args = string(fields[1])
			// copy command for validation
			modelCommand = command
		case "LICENSE", "TEMPLATE", "SYSTEM", "PROMPT":
			command.Name = string(bytes.ToLower(fields[0]))
			command.Args = string(fields[1])
		case "PARAMETER":
			fields = bytes.SplitN(fields[1], []byte(" "), 2)
			command.Name = string(fields[0])
			command.Args = string(fields[1])
		default:
			// log a warning for unknown commands
			fmt.Printf("WARNING: Unknown command: %s\n", fields[0])
			continue
		}

		commands = append(commands, command)
		command.Reset()
	}

Review comment (bug):
This was a bug from earlier where an empty line will be parsed into a [][]byte of length 1 where fields[0] is the empty line

Code after:
	"errors"
	"io"
	"log"
)

type Command struct {
	Name string
	Args string
}

func (c *Command) Reset() {
	c.Name = ""
	c.Args = ""
}

func Parse(reader io.Reader) ([]Command, error) {
	var commands []Command
	var command, modelCommand Command

	scanner := bufio.NewScanner(reader)
	scanner.Split(scanModelfile)
	for scanner.Scan() {
		line := scanner.Bytes()

		fields := bytes.SplitN(line, []byte(" "), 2)
		if len(fields) == 0 || len(fields[0]) == 0 {
			continue
		}

		switch string(bytes.ToUpper(fields[0])) {
		case "FROM":
			command.Name = "model"
			command.Args = string(fields[1])
			// copy command for validation
			modelCommand = command
		case "LICENSE", "TEMPLATE", "SYSTEM", "PROMPT":
			command.Name = string(bytes.ToLower(fields[0]))
			command.Args = string(fields[1])
		case "PARAMETER":
			fields = bytes.SplitN(fields[1], []byte(" "), 2)
			command.Name = string(fields[0])
			command.Args = string(fields[1])
		default:
			// log a warning for unknown commands
			log.Printf("WARNING: Unknown command: %s", fields[0])
			continue
		}

		commands = append(commands, command)
		command.Reset()
	}
Repository: ollama/ollama
File: server/images.go (Go)

Code before:
			Total:     int(fi.Size()),
			Completed: int(fi.Size()),
		})

		return nil
	}

	_, downloading := inProgress.LoadOrStore(digest, &DownloadProgress{Total: 1, Completed: 0}) // store a dummy value to indicate that we're downloading
	if downloading {
		for {
			val, downloading := inProgress.Load(digest)
			if !downloading {
				break
			}
			dl, ok := val.(*DownloadProgress)
			if !ok || dl.Completed >= dl.Total {
				break
			}
			fn(api.ProgressResponse{
				Status:    fmt.Sprintf("downloading %s", digest),
				Digest:    digest,
				Total:     int(dl.Total),
				Completed: int(dl.Completed),
			})
			sleep := time.NewTimer(1 * time.Second)
			<-sleep.C
		}
		return nil
	}

	var size int64
	chunkSize := 1024 * 1024 // 1 MiB in bytes

	fi, err := os.Stat(fp + "-partial")
	switch {
	case errors.Is(err, os.ErrNotExist):
		// noop, file doesn't exist so create it
	case err != nil:
		return fmt.Errorf("stat: %w", err)
	default:
		size = fi.Size()
		// Ensure the size is divisible by the chunk size by removing excess bytes
		size -= size % int64(chunkSize)

		err := os.Truncate(fp+"-partial", size)
		if err != nil {
			return fmt.Errorf("truncate: %w", err)
		}
	}

	url := fmt.Sprintf("%s/v2/%s/blobs/%s", mp.Registry, mp.GetNamespaceRepository(), digest)

Review comment (suggestion):
This can be replaced with a ticker:

```
tick := time.NewTicker(time.Second)
for range tick.C {
  ...
}
```

Code after:
	if resp.StatusCode != http.StatusOK {
		if resp.StatusCode == http.StatusNotFound {
			return nil, fmt.Errorf("model not found")
		}
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("on pull registry responded with code %d: %s", resp.StatusCode, body)
	}

	var m *ManifestV2
	if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
		return nil, err
	}

	return m, err
}

func createConfigLayer(layers []string) (*LayerReader, error) {
	// TODO change architecture and OS
	config := ConfigV2{
		Architecture: "arm64",
		OS:           "linux",
		RootFS: RootFS{
			Type:    "layers",
			DiffIDs: layers,
		},
	}

	configJSON, err := json.Marshal(config)
	if err != nil {
		return nil, err
	}

	digest, size := GetSHA256Digest(bytes.NewBuffer(configJSON))

	layer := &LayerReader{
		Layer: Layer{
			MediaType: "application/vnd.docker.container.image.v1+json",
			Digest:    digest,
			Size:      size,
		},
		Reader: bytes.NewBuffer(configJSON),
	}
	return layer, nil
}

// GetSHA256Digest returns the SHA256 hash of a given buffer and returns it, and the size of buffer
func GetSHA256Digest(r io.Reader) (string, int) {
	h := sha256.New()
	n, err := io.Copy(h, r)
	if err != nil {
		log.Fatal(err)
Repository: ollama/ollama
File: llama/llama.go (Go)

Code before:

	llm.marshalPrompt(tokens, prompt)

	C.llama_set_rng_seed(llm.ctx, C.uint(llm.Seed))

	var b bytes.Buffer
	for {
		token, err := llm.next()
		if llm.gc {
			return nil
		} else if errors.Is(err, io.EOF) {
			break
		} else if err != nil {
			return err
		}

		b.WriteString(llm.detokenize(token))

		if err := llm.checkStopConditions(b); err != nil {
			if errors.Is(err, io.EOF) {
				break
			} else if errors.Is(err, errNeedMoreData) {
				continue
			}

			return nil
		}

		if utf8.Valid(b.Bytes()) || b.Len() >= utf8.UTFMax {
			fn(api.GenerateResponse{Response: b.String()})
			b.Reset()
		}
	}

	last := make([]int, 0, len(llm.last))
	for _, i := range llm.last {
		if i != 0 {
			last = append(last, int(i))
		}
	}

	timings := C.llama_get_timings(llm.ctx)
	fn(api.GenerateResponse{
		Done:               true,
		Context:            last,
		SampleCount:        int(timings.n_sample),
		SampleDuration:     parseDurationMs(float64(timings.t_sample_ms)),
		PromptEvalCount:    int(timings.n_p_eval),
		PromptEvalDuration: parseDurationMs(float64(timings.t_p_eval_ms)),
		EvalCount:          int(timings.n_eval),
		EvalDuration:       parseDurationMs(float64(timings.t_eval_ms)),

Review comment (bug):
should we return the error here rather than swallowing it? I see that no other type of error can be returned atm in any case

Code after:
	}

	llm.marshalPrompt(tokens, prompt)

	C.llama_set_rng_seed(llm.ctx, C.uint(llm.Seed))

	var b bytes.Buffer
	for {
		token, err := llm.next()
		if llm.gc {
			return nil
		} else if errors.Is(err, io.EOF) {
			break
		} else if err != nil {
			return err
		}

		b.WriteString(llm.detokenize(token))

		if err := llm.checkStopConditions(b); err != nil {
			if errors.Is(err, io.EOF) {
				break
			} else if errors.Is(err, errNeedMoreData) {
				continue
			}

			return err
		}

		if utf8.Valid(b.Bytes()) || b.Len() >= utf8.UTFMax {
			fn(api.GenerateResponse{Response: b.String()})
			b.Reset()
		}
	}

	last := make([]int, 0, len(llm.last))
	for _, i := range llm.last {
		if i != 0 {
			last = append(last, int(i))
		}
	}

	timings := C.llama_get_timings(llm.ctx)
	fn(api.GenerateResponse{
		Done:               true,
		Context:            last,
		SampleCount:        int(timings.n_sample),
		SampleDuration:     parseDurationMs(float64(timings.t_sample_ms)),
		PromptEvalCount:    int(timings.n_p_eval),
		PromptEvalDuration: parseDurationMs(float64(timings.t_p_eval_ms)),
		EvalCount:          int(timings.n_eval),
Repository: ollama/ollama
File: cmd/cmd.go (Go)

Code before:
	}

	return nil
}

func RunServer(_ *cobra.Command, _ []string) error {
	host := os.Getenv("OLLAMA_HOST")
	if host == "" {
		host = "127.0.0.1"
	}

	port := os.Getenv("OLLAMA_PORT")
	if port == "" {
		port = "11434"
	}

	ln, err := net.Listen("tcp", fmt.Sprintf("%s:%s", host, port))
	if err != nil {
		return err
	}

	return server.Serve(ln)
}

func startMacApp(client *api.Client) error {
	link, err := os.Readlink("/usr/local/bin/ollama")
	if err != nil {
		return err
	}
	if !strings.Contains(link, "Ollama.app") {
		return fmt.Errorf("could not find ollama app")
	}
	path := strings.Split(link, "Ollama.app")
	if err := exec.Command("/usr/bin/open", "-a", path[0]+"Ollama.app").Run(); err != nil {
		return err
	}
	// wait for the server to start
	timeout := time.After(5 * time.Second)
	tick := time.Tick(500 * time.Millisecond)
	for {
		select {
		case <-timeout:
			return errors.New("timed out waiting for server to start")
		case <-tick:
			if err := client.Heartbeat(context.Background()); err == nil {
				return nil // server has started
			}
		}
	}
}


Review comment (suggestion):
This isn't a good check if the user runs ollama on Mac without the Mac app. It should probably call instead `os.Readlink(os.Executable())` 

Code after:
	}

	return nil
}

func RunServer(_ *cobra.Command, _ []string) error {
	host := os.Getenv("OLLAMA_HOST")
	if host == "" {
		host = "127.0.0.1"
	}

	port := os.Getenv("OLLAMA_PORT")
	if port == "" {
		port = "11434"
	}

	ln, err := net.Listen("tcp", fmt.Sprintf("%s:%s", host, port))
	if err != nil {
		return err
	}

	return server.Serve(ln)
}

func startMacApp(client *api.Client) error {
	exe, err := os.Executable()
	if err != nil {
		return err
	}
	link, err := os.Readlink(exe)
	if err != nil {
		return err
	}
	if !strings.Contains(link, "Ollama.app") {
		return fmt.Errorf("could not find ollama app")
	}
	path := strings.Split(link, "Ollama.app")
	if err := exec.Command("/usr/bin/open", "-a", path[0]+"Ollama.app").Run(); err != nil {
		return err
	}
	// wait for the server to start
	timeout := time.After(5 * time.Second)
	tick := time.Tick(500 * time.Millisecond)
	for {
		select {
		case <-timeout:
			return errors.New("timed out waiting for server to start")
		case <-tick:
			if err := client.Heartbeat(context.Background()); err == nil {
				return nil // server has started
			}
Repository: ollama/ollama
File: api/client.go (Go)

Code before:
type Client struct {
	Base    url.URL
	HTTP    http.Client
	Headers http.Header
}

func checkError(resp *http.Response, body []byte) error {
	if resp.StatusCode >= 200 && resp.StatusCode < 400 {
		return nil
	}

	apiError := StatusError{StatusCode: resp.StatusCode}

	err := json.Unmarshal(body, &apiError)
	if err != nil {
		// Use the full body as the message if we fail to decode a response.
		apiError.ErrorMessage = string(body)
	}

	return apiError
}

// Host returns the default host to use for the client. It is determined in the following order:
// 1. The OLLAMA_CLIENT_HOST environment variable
// 2. The default host (localhost:11434)
func Host() string {
	if envHost != "" {
		return envHost
	}
	return DefaultHost
}

// FromEnv creates a new client using Host() as the host. An error is returns
// if the host is invalid.
func FromEnv() (*Client, error) {
	u, err := url.Parse(Host())
	if err != nil {
		return nil, err
	}
	return &Client{Base: *u}, nil
}

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

	return &Client{
		Base: url.URL{Scheme: "http", Host: host},
		HTTP: http.Client{},

Review comment (suggestion):
I think `Host()` is a bit too generic. What if other host-related functions are added later? I think `GetHost()` would be more specific and descriptive.

Code after:
type Client struct {
	Base    url.URL
	HTTP    http.Client
	Headers http.Header
}

func checkError(resp *http.Response, body []byte) error {
	if resp.StatusCode >= 200 && resp.StatusCode < 400 {
		return nil
	}

	apiError := StatusError{StatusCode: resp.StatusCode}

	err := json.Unmarshal(body, &apiError)
	if err != nil {
		// Use the full body as the message if we fail to decode a response.
		apiError.ErrorMessage = string(body)
	}

	return apiError
}

// Host returns the default host to use for the client. It is determined in the following order:
// 1. The OLLAMA_HOST environment variable
// 2. The default host (localhost:11434)
func Host() string {
	if envHost != "" {
		return envHost
	}
	return DefaultHost
}

// FromEnv creates a new client using Host() as the host. An error is returns
// if the host is invalid.
func FromEnv() (*Client, error) {
	u, err := url.Parse(Host())
	if err != nil {
		return nil, err
	}
	return &Client{Base: *u}, nil
}

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

	return &Client{
		Base: url.URL{Scheme: "http", Host: host},
		HTTP: http.Client{},
Repository: ollama/ollama
File: api/client.go (Go)

Code before:
package api

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
)

const DefaultHost = "localhost:11434"

var (
	envHost = os.Getenv("OLLAMA_CLIENT_HOST")
)

type Client struct {
	Base    url.URL
	HTTP    http.Client
	Headers http.Header
}

func checkError(resp *http.Response, body []byte) error {
	if resp.StatusCode >= 200 && resp.StatusCode < 400 {
		return nil
	}

	apiError := StatusError{StatusCode: resp.StatusCode}

	err := json.Unmarshal(body, &apiError)
	if err != nil {
		// Use the full body as the message if we fail to decode a response.
		apiError.ErrorMessage = string(body)
	}

	return apiError
}

// Host returns the default host to use for the client. It is determined in the following order:

Review comment (suggestion):
```suggestion
	envHost = os.Getenv("OLLAMA_HOST")
```

Code after:
package api

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
)

const DefaultHost = "localhost:11434"

var (
	envHost = os.Getenv("OLLAMA_HOST")
)

type Client struct {
	Base    url.URL
	HTTP    http.Client
	Headers http.Header
}

func checkError(resp *http.Response, body []byte) error {
	if resp.StatusCode >= 200 && resp.StatusCode < 400 {
		return nil
	}

	apiError := StatusError{StatusCode: resp.StatusCode}

	err := json.Unmarshal(body, &apiError)
	if err != nil {
		// Use the full body as the message if we fail to decode a response.
		apiError.ErrorMessage = string(body)
	}

	return apiError
}

// Host returns the default host to use for the client. It is determined in the following order:
Repository: ollama/ollama
File: api/client.go (Go)

Code before:
)

type Client struct {
	Base    url.URL
	HTTP    http.Client
	Headers http.Header
}

func checkError(resp *http.Response, body []byte) error {
	if resp.StatusCode >= 200 && resp.StatusCode < 400 {
		return nil
	}

	apiError := StatusError{StatusCode: resp.StatusCode}

	err := json.Unmarshal(body, &apiError)
	if err != nil {
		// Use the full body as the message if we fail to decode a response.
		apiError.ErrorMessage = string(body)
	}

	return apiError
}

// Host returns the default host to use for the client. It is determined in the following order:
// 1. The OLLAMA_CLIENT_HOST environment variable
// 2. The default host (localhost:11434)
func Host() string {
	if envHost != "" {
		return envHost
	}
	return DefaultHost
}

// FromEnv creates a new client using Host() as the host. An error is returns
// if the host is invalid.
func FromEnv() (*Client, error) {
	u, err := url.Parse(Host())
	if err != nil {
		return nil, err
	}
	return &Client{Base: *u}, nil
}

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

	return &Client{

Review comment (suggestion):
```suggestion
// 1. The OLLAMA_HOST environment variable
```

Code after:
)

type Client struct {
	Base    url.URL
	HTTP    http.Client
	Headers http.Header
}

func checkError(resp *http.Response, body []byte) error {
	if resp.StatusCode >= 200 && resp.StatusCode < 400 {
		return nil
	}

	apiError := StatusError{StatusCode: resp.StatusCode}

	err := json.Unmarshal(body, &apiError)
	if err != nil {
		// Use the full body as the message if we fail to decode a response.
		apiError.ErrorMessage = string(body)
	}

	return apiError
}

// Host returns the default host to use for the client. It is determined in the following order:
// 1. The OLLAMA_HOST environment variable
// 2. The default host (localhost:11434)
func Host() string {
	if envHost != "" {
		return envHost
	}
	return DefaultHost
}

// FromEnv creates a new client using Host() as the host. An error is returns
// if the host is invalid.
func FromEnv() (*Client, error) {
	u, err := url.Parse(Host())
	if err != nil {
		return nil, err
	}
	return &Client{Base: *u}, nil
}

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

	return &Client{