From eae76bd1ab4d567b071779dd33b9e0467bc6af94 Mon Sep 17 00:00:00 2001 From: Andrew Michael McNutt Date: Thu, 30 May 2024 10:52:50 -0700 Subject: [PATCH] Add anthropic support --- netlify/utils.ts | 17 +++++++++++++- package.json | 1 + src/controls/Config.svelte | 2 +- src/lib/api-calls.ts | 48 ++++++++++++++++++++++++++------------ src/stores/config-store.ts | 3 ++- yarn.lock | 14 +++++++++++ 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/netlify/utils.ts b/netlify/utils.ts index 1639249d..6bf41584 100644 --- a/netlify/utils.ts +++ b/netlify/utils.ts @@ -3,11 +3,16 @@ import OpenAI from "openai"; import { GoogleGenerativeAI } from "@google/generative-ai"; const genAI = new GoogleGenerativeAI(process.env.GEMINI_KEY as string); const model = genAI.getGenerativeModel({ model: "gemini-pro" }); +import Anthropic from "@anthropic-ai/sdk"; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); +const anthropic = new Anthropic({ + apiKey: process.env.ANTHROPIC_KEY, // defaults to process.env["ANTHROPIC_API_KEY"] +}); + export function errorResponse(callback, err) { console.error(err); @@ -24,11 +29,20 @@ const engines = { messages: [{ role: "user", content: prompt }], // model: "gpt-3.5-turbo", n: 1, - temperature: 0.7, + temperature: 0, model: "gpt-4o", // model: "gpt-4", // model: "gpt-4-turbo-preview", }), + anthropic: (prompt: string) => + anthropic.messages.create({ + // model: "claude-3-opus-20240229", + model: "claude-3-haiku-20240307", + // model: "claude-3-sonnet-20240229", + max_tokens: 256, + temperature: 0, + messages: [{ role: "user", content: prompt }], + }), }; export const genericHandler = @@ -54,5 +68,6 @@ export const genericHandler = const content = prompt(promptInput); console.log(engine, content); const result = await engines[engine](content); + console.log(result); callback(null, { statusCode: 200, body: JSON.stringify(result) }); }; diff --git a/package.json b/package.json index bae5e9b2..276a769c 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "vitest": "^1.1.3" }, "dependencies": { + "@anthropic-ai/sdk": "^0.22.0", "@google/generative-ai": "^0.1.1", "chroma-js": "^2.4.2", "color-namer": "^1.4.0", diff --git a/src/controls/Config.svelte b/src/controls/Config.svelte index 622d8d3c..fe970de2 100644 --- a/src/controls/Config.svelte +++ b/src/controls/Config.svelte @@ -5,7 +5,7 @@ import Tooltip from "../components/Tooltip.svelte"; import colorStore from "../stores/color-store"; import { buttonStyle } from "../lib/styles"; - const aiModes = ["google", "openai"] as const; + const aiModes = ["google", "openai", "anthropic"] as const; $: showBg = $configStore.showColorBackground; $: showOutOfGamut = $configStore.showGamutMarkers; diff --git a/src/lib/api-calls.ts b/src/lib/api-calls.ts index 5db279f3..778b47e3 100644 --- a/src/lib/api-calls.ts +++ b/src/lib/api-calls.ts @@ -4,26 +4,30 @@ import LintWorker from "./linter-tools/lint-worker.worker?worker"; import { summarizePal } from "./utils"; import type { WorkerCommand } from "./linter-tools/worker-types"; -type Engine = "openai" | "google"; +export type Engine = "openai" | "google" | "anthropic"; type SimplePal = { background: string; colors: string[] }; const palToString = (pal: Palette) => ({ background: pal.background.toHex(), colors: pal.colors.map((x) => x.color.toHex()), }); +const postCreds = { + method: "POST", + mode: "cors", + cache: "no-cache", + credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + redirect: "follow", + referrerPolicy: "no-referrer", +} as any; + function openAIScaffold( api: string, body: string, parseAsJSON: boolean ): Promise { return fetch(`/.netlify/functions/${api}?engine=openai`, { - method: "POST", - mode: "cors", - cache: "no-cache", - credentials: "same-origin", - headers: { "Content-Type": "application/json" }, - redirect: "follow", - referrerPolicy: "no-referrer", + ...postCreds, body, }) .then((response) => response.json()) @@ -36,19 +40,32 @@ function openAIScaffold( }); } +function anthropicScaffold( + api: string, + body: string, + parseAsJSON: boolean +): Promise { + return fetch(`/.netlify/functions/${api}?engine=anthropic`, { + ...postCreds, + body, + }) + .then((response) => response.json()) + .then((x: any) => { + console.log(x); + return x.content + .map((x: any) => x?.text) + .filter((x: any) => x) + .flatMap((x: any) => (parseAsJSON ? Json.parse(x) : x)); + }); +} + function googleScaffold( api: string, body: string, parseAsJSON: boolean ): Promise { return fetch(`/.netlify/functions/${api}?engine=google`, { - method: "POST", - mode: "cors", - cache: "no-cache", - credentials: "same-origin", - headers: { "Content-Type": "application/json" }, - redirect: "follow", - referrerPolicy: "no-referrer", + ...postCreds, body, }) .then((response) => response.json()) @@ -67,6 +84,7 @@ function googleScaffold( const engineToScaffold = { openai: openAIScaffold, google: googleScaffold, + anthropic: anthropicScaffold, }; // supports the add color search function diff --git a/src/stores/config-store.ts b/src/stores/config-store.ts index 2effb614..ad42c113 100644 --- a/src/stores/config-store.ts +++ b/src/stores/config-store.ts @@ -1,4 +1,5 @@ import { writable } from "svelte/store"; +import type { Engine } from "../lib/api-calls"; interface StoreData { channelPickerSpace: "lab" | "lch" | "hsl" | "hsv" | "rgb"; @@ -8,7 +9,7 @@ interface StoreData { compareBackgroundSpace: "lab" | "lch" | "hsl" | "hsv" | "rgb"; comparePal: number | undefined; compareSelectedExample: number; - engine: "openai" | "google"; + engine: Engine; evalDeltaDisplay: "none" | "76" | "CMC" | "2000" | "ITP" | "Jz" | "OK"; evalDisplayMode: "regular" | "compact" | "lint-customization"; exampleRoute: "svg" | "vega" | "swatches"; diff --git a/yarn.lock b/yarn.lock index 425e7a4e..2576d6d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,6 +15,20 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" +"@anthropic-ai/sdk@^0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.22.0.tgz#548e4218d9810fd494e595d4e57cb2d46d301a1a" + integrity sha512-dv4BCC6FZJw3w66WNLsHlUFjhu19fS1L/5jMPApwhZLa/Oy1j0A2i3RypmDtHEPp4Wwg3aZkSHksp7VzYWjzmw== + dependencies: + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + web-streams-polyfill "^3.2.1" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0": version "7.23.5" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz"