UNPKG

@fine-dev/fine-js

Version:

Javascript client for Fine BaaS

228 lines 9.23 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); function fileToAttachment(file) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.addEventListener("load", () => resolve({ data: reader.result, name: file.name })); reader.addEventListener("error", () => reject(reader.error)); reader.readAsDataURL(file); }); }); } class FineAIClient { constructor({ baseUrl, headers, fetch: customFetch }) { this.config = { baseUrl: baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl, fetch(input, init) { if (!customFetch) customFetch = fetch.bind(window); return customFetch(input, Object.assign(Object.assign({}, init), { headers, credentials: "include" })); } }; } get threads() { return this.config.fetch(`${this.config.baseUrl}/threads`).then((response) => __awaiter(this, void 0, void 0, function* () { if (!response.ok) throw new Error(`Failed to fetch threads: ${yield response.text()}`); return response .json() .then(({ data }) => data.map((t) => new FineAIThread(t.id, this.config, t))); })); } thread(threadId) { return new FineAIThread(threadId, this.config); } message(assistantId, content) { return new FineAIMessage(this.config, assistantId, content); } } exports.default = FineAIClient; class FineAIThread { constructor(id, config, threadData) { this.id = id; this.config = config; this.threadData = threadData; } get data() { var _a; return ((_a = this.threadData) !== null && _a !== void 0 ? _a : this.makeThreadRequest({ errorText: `Failed to fetch thread ${this.id}` }).then((result) => (this.threadData = result))); } get messages() { return this.makeThreadRequest({ errorText: `Failed to fetch messages for thread ${this.id}`, endpoint: "/messages" }).then(({ data }) => data); } update(metadata) { return __awaiter(this, void 0, void 0, function* () { return this.makeThreadRequest({ errorText: `Failed to update thread ${this.id}`, method: "POST", body: JSON.stringify({ metadata }) }).then((result) => (this.threadData = result)); }); } delete() { return __awaiter(this, void 0, void 0, function* () { return this.makeThreadRequest({ errorText: `Failed to delete thread ${this.id}`, method: "DELETE" }).then(() => (this.threadData = undefined)); }); } message(assistantId, content) { return new FineAIMessage(this.config, assistantId, content, this.id); } makeThreadRequest(_a) { var { errorText, endpoint } = _a, options = __rest(_a, ["errorText", "endpoint"]); return this.config .fetch(`${this.config.baseUrl}/threads/${this.id}${endpoint !== null && endpoint !== void 0 ? endpoint : ""}`, options) .then((response) => __awaiter(this, void 0, void 0, function* () { if (!response.ok) throw new Error(`${errorText}: ${yield response.text()}`); else return response.json(); })) .catch((error) => { console.error(error); throw new Error(`${errorText}: ${error}`); }); } } class FineAIMessage { constructor(config, assistantId, content, threadId) { this.config = config; this.assistantId = assistantId; this.threadId = threadId; if (typeof content === "string") { this.content = [{ type: "text", text: content }]; } else if (!Array.isArray(content)) { this.content = [content]; } else { this.content = content.map((c) => (typeof c === "string" ? { type: "text", text: c } : c)); } } setMetadata(metadata) { this.metadata = metadata; return this; } attach(files) { if (!Array.isArray(files)) files = [files]; for (const file of files) if (file.size / 1048576 > 10) throw new Error(`Attachment ${file.name} is too large. Maximum size is 10MB.`); this.attachments || (this.attachments = []); this.attachments.push(...files.map(fileToAttachment)); return this; } send() { return this.prepareBody(false) .then((body) => this.config.fetch(`${this.config.baseUrl}/run`, { method: "POST", body })) .then((response) => __awaiter(this, void 0, void 0, function* () { if (!response.ok) throw new Error(`Failed to send message: ${yield response.text()}`); else return response.json(); })); } stream(callback) { return __awaiter(this, void 0, void 0, function* () { let runId = ""; try { const response = yield this.config.fetch(`${this.config.baseUrl}/run`, { method: "POST", body: yield this.prepareBody(true) }); const reader = response.body.getReader(); this.readStream(reader, (event) => { if ("runId" in event) runId = event.runId; callback(event); }); return reader; } catch (error) { callback({ type: "runError", runId, error: error instanceof Error ? error.message : typeof error === "string" ? error : JSON.stringify(error) }); throw new Error(`Failed to send message stream: ${error}`); } }); } prepareBody(stream) { return __awaiter(this, void 0, void 0, function* () { return JSON.stringify({ assistantId: this.assistantId, messages: [ { role: "user", content: this.content, attachments: this.attachments ? yield Promise.all(this.attachments) : undefined } ], threadId: this.threadId, metadata: this.metadata, stream }); }); } readStream(reader, callback) { return __awaiter(this, void 0, void 0, function* () { const decoder = new TextDecoder("utf-8"); let bufferedChunks = ""; while (true) { const { value, done } = yield reader.read(); if (done) break; const str = decoder.decode(value); bufferedChunks += str; if (!bufferedChunks) continue; const events = bufferedChunks.split("\n\n"); for (let i = 0; i < events.length; i++) { const event = events[i]; if (!event.trim()) continue; const data = event.slice("data: ".length); try { const result = JSON.parse(data); bufferedChunks = ""; callback(result); } catch (error) { // Failed to parse JSON. This is probably an incomplete chunk, so we buffer it and wait for the next chunk bufferedChunks = events.slice(i).join("\n\n"); continue; } } } }); } } //# sourceMappingURL=ai.js.map