diff --git a/src/browser.ts b/src/browser.ts index 7fa23cd..6d8dcc6 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,5 +1,5 @@ import * as utils from './utils.js' -import { AbortableAsyncIterator, parseJSON, post } from './utils.js' +import { AbortableAsyncIterator, parseJSON } from './utils.js' import 'whatwg-fetch' import type { @@ -34,15 +34,14 @@ export class Ollama { constructor(config?: Partial) { this.config = { host: '', + headers: config?.headers } + if (!config?.proxy) { this.config.host = utils.formatHost(config?.host ?? 'http://127.0.0.1:11434') } - this.fetch = fetch - if (config?.fetch != null) { - this.fetch = config.fetch - } + this.fetch = config?.fetch ?? fetch } // Abort any ongoing streamed requests to Ollama @@ -72,7 +71,7 @@ export class Ollama { const host = `${this.config.host}/api/${endpoint}` if (request.stream) { const abortController = new AbortController() - const response = await post(this.fetch, host, request, { + const response = await utils.post(this.fetch, host, request, { signal: abortController.signal, headers: this.config.headers }) @@ -236,9 +235,12 @@ async encodeImage(image: Uint8Array | string): Promise { * @returns {Promise} - The response object. */ async delete(request: DeleteRequest): Promise { - await utils.del(this.fetch, `${this.config.host}/api/delete`, { - name: request.model, - }) + await utils.del( + this.fetch, + `${this.config.host}/api/delete`, + { name: request.model }, + { headers: this.config.headers } + ) return { status: 'success' } } @@ -249,7 +251,9 @@ async encodeImage(image: Uint8Array | string): Promise { * @returns {Promise} - The response object. */ async copy(request: CopyRequest): Promise { - await utils.post(this.fetch, `${this.config.host}/api/copy`, { ...request }) + await utils.post(this.fetch, `${this.config.host}/api/copy`, { ...request }, { + headers: this.config.headers + }) return { status: 'success' } } @@ -259,7 +263,9 @@ async encodeImage(image: Uint8Array | string): Promise { * @throws {Error} - If the response body is missing. */ async list(): Promise { - const response = await utils.get(this.fetch, `${this.config.host}/api/tags`) + const response = await utils.get(this.fetch, `${this.config.host}/api/tags`, { + headers: this.config.headers + }) return (await response.json()) as ListResponse } @@ -271,6 +277,8 @@ async encodeImage(image: Uint8Array | string): Promise { async show(request: ShowRequest): Promise { const response = await utils.post(this.fetch, `${this.config.host}/api/show`, { ...request, + }, { + headers: this.config.headers }) return (await response.json()) as ShowResponse } @@ -283,6 +291,8 @@ async encodeImage(image: Uint8Array | string): Promise { async embed(request: EmbedRequest): Promise { const response = await utils.post(this.fetch, `${this.config.host}/api/embed`, { ...request, + }, { + headers: this.config.headers }) return (await response.json()) as EmbedResponse } @@ -295,6 +305,8 @@ async encodeImage(image: Uint8Array | string): Promise { async embeddings(request: EmbeddingsRequest): Promise { const response = await utils.post(this.fetch, `${this.config.host}/api/embeddings`, { ...request, + }, { + headers: this.config.headers }) return (await response.json()) as EmbeddingsResponse } @@ -305,7 +317,9 @@ async encodeImage(image: Uint8Array | string): Promise { * @throws {Error} - If the response body is missing. */ async ps(): Promise { - const response = await utils.get(this.fetch, `${this.config.host}/api/ps`) + const response = await utils.get(this.fetch, `${this.config.host}/api/ps`, { + headers: this.config.headers + }) return (await response.json()) as ListResponse } } diff --git a/src/interfaces.ts b/src/interfaces.ts index 5b7b115..a5058f5 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -4,7 +4,7 @@ export interface Config { host: string fetch?: Fetch proxy?: boolean - headers?: Headers + headers?: HeadersInit } // request types diff --git a/src/utils.ts b/src/utils.ts index 7ab32d4..76976bf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -115,15 +115,20 @@ const fetchWithHeaders = async ( 'Content-Type': 'application/json', Accept: 'application/json', 'User-Agent': `ollama-js/${version} (${getPlatform()})`, - } + } as HeadersInit if (!options.headers) { options.headers = {} } + // Filter out default headers from custom headers + const customHeaders = Object.fromEntries( + Object.entries(options.headers).filter(([key]) => !Object.keys(defaultHeaders).some(defaultKey => defaultKey.toLowerCase() === key.toLowerCase())) + ) + options.headers = { ...defaultHeaders, - ...options.headers, + ...customHeaders } return fetch(url, options) @@ -135,8 +140,10 @@ const fetchWithHeaders = async ( * @param host {string} - The host to fetch * @returns {Promise} - The fetch response */ -export const get = async (fetch: Fetch, host: string): Promise => { - const response = await fetchWithHeaders(fetch, host) +export const get = async (fetch: Fetch, host: string, options?: { headers?: HeadersInit }): Promise => { + const response = await fetchWithHeaders(fetch, host, { + headers: options?.headers + }) await checkOk(response) @@ -169,7 +176,7 @@ export const post = async ( fetch: Fetch, host: string, data?: Record | BodyInit, - options?: { signal?: AbortSignal, headers?: Headers }, + options?: { signal?: AbortSignal, headers?: HeadersInit }, ): Promise => { const isRecord = (input: any): input is Record => { return input !== null && typeof input === 'object' && !Array.isArray(input) @@ -199,10 +206,12 @@ export const del = async ( fetch: Fetch, host: string, data?: Record, + options?: { headers?: HeadersInit }, ): Promise => { const response = await fetchWithHeaders(fetch, host, { method: 'DELETE', body: JSON.stringify(data), + headers: options?.headers }) await checkOk(response)