Skip to content

Commit

Permalink
feat: support latest model gpt-4-turbo + important fixes to ensure it…
Browse files Browse the repository at this point in the history
… works
  • Loading branch information
mondaychen committed Apr 9, 2024
1 parent 316f92c commit 3d8f21d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 33 deletions.
4 changes: 2 additions & 2 deletions src/common/RecommendedTasks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, VStack, Text } from "@chakra-ui/react";
import { useAppState } from "../state/store";

const tasks = [
'Post on twitter.com with content "an automated post from WebWand by @NormalComputing" If I\'m not logged in, fail the task and wait for me to log in.',
'Post on twitter.com with content "an automated post from WebWand by @NormalComputing! :)" If I\'m not logged in, fail the task and wait for me to log in.',
"Find a book about AI and add a physical copy to cart on Amazon.com. Pick the cheaper one from papaerback and hardcover.",
];

Expand Down Expand Up @@ -39,7 +39,7 @@ const RecommendedTasks = ({
</Text>
<Text fontWeight={400} noOfLines={1} color="gray">
with content &quot;an automated post from WebWand by
@NormalComputing&quot;
@NormalComputing!&quot;
</Text>
</Button>
<Button
Expand Down
48 changes: 40 additions & 8 deletions src/helpers/aiSdkUtils.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
import Anthropic from "@anthropic-ai/sdk";
import OpenAI from "openai";
import { useAppState } from "../state/store";
import { enumValues } from "./utils";

export enum SupportedModels {
Gpt35Turbo16k = "gpt-3.5-turbo-16k",
Gpt4 = "gpt-4",
Gpt4TurboPreview = "gpt-4-turbo-preview",
Gpt4VisionPreview = "gpt-4-vision-preview",
Gpt4Turbo = "gpt-4-turbo",
Claude3Sonnet = "claude-3-sonnet-20240229",
}

function isSupportedModel(value: string): value is SupportedModels {
return enumValues(SupportedModels).includes(value as SupportedModels);
}

export const DEFAULT_MODEL = SupportedModels.Gpt4Turbo;

export const DisplayName = {
[SupportedModels.Gpt35Turbo16k]: "GPT-3.5 Turbo (16k)",
[SupportedModels.Gpt4]: "GPT-4",
[SupportedModels.Gpt4TurboPreview]: "GPT-4 Turbo (Preview)",
[SupportedModels.Gpt4VisionPreview]: "GPT-4 Vision (Preview)",
[SupportedModels.Gpt4Turbo]: "GPT-4 Turbo",
[SupportedModels.Claude3Sonnet]: "Claude 3 Sonnet",
};

export function hasVisionSupport(model: SupportedModels) {
return (
model === SupportedModels.Gpt4VisionPreview ||
model === SupportedModels.Gpt4Turbo ||
model === SupportedModels.Claude3Sonnet
);
}
Expand All @@ -41,6 +51,26 @@ export function isAnthropicModel(model: SupportedModels) {
return chooseSDK(model) === "Anthropic";
}

export function findBestMatchingModel(
selectedModel: string,
openAIKey: string | undefined,
anthropicKey: string | undefined,
): SupportedModels {
let result: SupportedModels = DEFAULT_MODEL;
// verify the string value is a supported model
// this is to handle the case when we drop support for a model
if (isSupportedModel(selectedModel)) {
result = selectedModel;
}
// ensure the provider's API key is available
if (!openAIKey && anthropicKey && !isAnthropicModel(result)) {
result = SupportedModels.Claude3Sonnet;
} else if (openAIKey && !anthropicKey && !isOpenAIModel(result)) {
result = SupportedModels.Gpt4Turbo;
}
return result;
}

export type CommonMessageCreateParams = {
prompt: string;
imageData?: string;
Expand Down Expand Up @@ -92,20 +122,22 @@ export async function fetchResponseFromModelOpenAI(
role: "user",
content,
});
// this trick does not work for GPT-4
// if (params.jsonMode) {
// messages.push({
// role: "assistant",
// content: "{",
// });
// }
if (params.jsonMode) {
messages.push({
role: "assistant",
content: "{",
});
}
const completion = await openai.chat.completions.create({
model: model,
messages,
max_tokens: 1000,
temperature: 0,
});
const rawResponse = completion.choices[0].message?.content?.trim() ?? "";
let rawResponse = completion.choices[0].message?.content?.trim() ?? "";
if (params.jsonMode && !rawResponse.startsWith("{")) {
rawResponse = "{" + rawResponse;
}
return {
usage: completion.usage,
rawResponse,
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/errorChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default function errorChecker(
// other API errors are not recoverable
return false;
}
log("Error:", err);
log("Error: " + err.message, err);
// retry everything else (e.g. network errors, syntax error, timeout)
return true;
}
27 changes: 7 additions & 20 deletions src/state/settings.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { type Data } from "../helpers/knowledge/index";
import { MyStateCreator } from "./store";
import {
SupportedModels,
isAnthropicModel,
isOpenAIModel,
} from "../helpers/aiSdkUtils";
import { SupportedModels, findBestMatchingModel } from "../helpers/aiSdkUtils";

export type SettingsSlice = {
openAIKey: string | undefined;
Expand All @@ -23,27 +19,18 @@ export const createSettingsSlice: MyStateCreator<SettingsSlice> = (set) => ({
anthropicKey: undefined,
openAIBaseUrl: undefined,
anthropicBaseUrl: undefined,
selectedModel: SupportedModels.Gpt4VisionPreview,
selectedModel: SupportedModels.Gpt4Turbo,
voiceMode: false,
customKnowledgeBase: {},
actions: {
update: (values) => {
set((state) => {
const newSettings: SettingsSlice = { ...state.settings, ...values };
// set default model based on the API key
if (
!newSettings.openAIKey &&
newSettings.anthropicKey &&
!isAnthropicModel(newSettings.selectedModel)
) {
newSettings.selectedModel = SupportedModels.Claude3Sonnet;
} else if (
newSettings.openAIKey &&
!newSettings.anthropicKey &&
!isOpenAIModel(newSettings.selectedModel)
) {
newSettings.selectedModel = SupportedModels.Gpt4VisionPreview;
}
newSettings.selectedModel = findBestMatchingModel(
newSettings.selectedModel,
newSettings.openAIKey,
newSettings.anthropicKey,
);
// voice model current relies on OpenAI API key
if (!newSettings.openAIKey) {
newSettings.voiceMode = false;
Expand Down
12 changes: 10 additions & 2 deletions src/state/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createJSONStorage, devtools, persist } from "zustand/middleware";
import { createCurrentTaskSlice, CurrentTaskSlice } from "./currentTask";
import { createUiSlice, UiSlice } from "./ui";
import { createSettingsSlice, SettingsSlice } from "./settings";
import { findBestMatchingModel } from "../helpers/aiSdkUtils";

export type StoreType = {
currentTask: CurrentTaskSlice;
Expand Down Expand Up @@ -46,8 +47,15 @@ export const useAppState = create<StoreType>()(
customKnowledgeBase: state.settings.customKnowledgeBase,
},
}),
merge: (persistedState, currentState) =>
merge(currentState, persistedState),
merge: (persistedState, currentState) => {
const result = merge(currentState, persistedState);
result.settings.selectedModel = findBestMatchingModel(
result.settings.selectedModel,
result.settings.openAIKey,
result.settings.anthropicKey,
);
return result;
},
},
),
);
Expand Down

0 comments on commit 3d8f21d

Please sign in to comment.