Skip to content

Commit

Permalink
feat: 모델 3개 선택 가능하게 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonghakseo committed Jul 18, 2024
1 parent 716776d commit 20df20f
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 73 deletions.
4 changes: 2 additions & 2 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ declare module "*.json" {

declare global {
type ChatGPTSlot = {
type: "gpt4-turbo" | "gpt4o";
type: "gpt-4-turbo" | "gpt-4o" | "gpt-3.5-turbo";
system?: string;
/** config */
maxTokens?: number; // max 4000
Expand Down Expand Up @@ -108,7 +108,7 @@ declare global {
type: "RequestQuickChatGPTStream";
input?: {
messages: Chat[];
isGpt4Turbo: boolean;
model: "gpt-4-turbo" | "gpt-4o" | "gpt-3.5-turbo";
};
data?: { result: string; chunk?: string; isDone?: boolean };
};
Expand Down
13 changes: 8 additions & 5 deletions src/pages/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ chrome.runtime.onConnect.addListener((port) => {
await chatGPT({
input: "hello",
apiKey: message.input,
slot: { type: "gpt4o" },
slot: { type: "gpt-3.5-turbo" },
}).catch((error) => {
ApiKeyStorage.setApiKey(null);
throw error;
Expand Down Expand Up @@ -136,14 +136,17 @@ chrome.runtime.onConnect.addListener((port) => {
break;
}
case "RequestQuickChatGPTStream": {
if (!message.input) {
throw Error("RequestQuickChatGPTStream input is undefined");
}
await QuickChatHistoryStorage.pushChatHistories({
role: "user",
content: message.input?.messages.at(-1)?.content ?? "",
content: message.input.messages.at(-1)?.content ?? "",
});
const apiKey = await ApiKeyStorage.getApiKey();
const response = await chatGPT({
chats: message.input?.messages,
slot: { type: message.input?.isGpt4Turbo ? "gpt4-turbo" : "gpt4o" },
chats: message.input.messages,
slot: { type: message.input.model },
apiKey,
onDelta: (chunk) => {
sendResponse({
Expand Down Expand Up @@ -204,7 +207,7 @@ chrome.runtime.onConnect.addListener((port) => {
const response = await chatGPT({
input: message.input,
slot: {
type: "gpt4o",
type: "gpt-4o",
system: PROMPT_GENERATE_PROMPT,
},
apiKey,
Expand Down
3 changes: 2 additions & 1 deletion src/pages/background/lib/infra/chatGPT.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { OpenAI } from "openai";
import { ChatCompletionMessageParam } from "openai/resources";
import { ChatModel } from "openai/src/resources/chat/chat";

export async function chatGPT({
input,
Expand Down Expand Up @@ -34,7 +35,7 @@ export async function chatGPT({
const stream = client.beta.chat.completions
.stream({
messages,
model: slot.type === "gpt4-turbo" ? "gpt-4-turbo" : "gpt-4o",
model: slot.type,
max_tokens: slot.maxTokens,
temperature: slot.temperature,
top_p: slot.topP,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const defaultSlot: Slot = {
id: "1",
name: "name",
isSelected: false,
type: "gpt4o",
type: "gpt-4o",
};

describe("SlotsManipulator test", () => {
Expand Down
14 changes: 7 additions & 7 deletions src/pages/background/lib/storage/slotStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe("SlotStorage test", () => {
test("선택된 슬롯이 없으면 에러가 발생한다", async () => {
// given
const savedSlots: Slot[] = [
{ type: "gpt4o", id: "id", name: "name", isSelected: false },
{ type: "gpt-4o", id: "id", name: "name", isSelected: false },
];
jest
.spyOn(SlotStorage, "getAllSlots")
Expand All @@ -76,7 +76,7 @@ describe("SlotStorage test", () => {
test("선택된 슬롯이 있으면 가져온다", async () => {
// given
const savedSelectedSlot: Slot = {
type: "gpt4o",
type: "gpt-4o",
id: "id",
name: "name",
isSelected: true,
Expand All @@ -99,7 +99,7 @@ describe("SlotStorage test", () => {
// given
const savedSlots: Slot[] = [];
const slot: Slot = {
type: "gpt4o",
type: "gpt-4o",
id: "id",
name: "name",
isSelected: false,
Expand All @@ -121,14 +121,14 @@ describe("SlotStorage test", () => {
// given
const savedSlots: Slot[] = [
{
type: "gpt4o",
type: "gpt-4o",
id: "id1",
name: "name",
isSelected: false,
},
];
const slot: Slot = {
type: "gpt4o",
type: "gpt-4o",
id: "id2",
name: "name",
isSelected: false,
Expand All @@ -150,7 +150,7 @@ describe("SlotStorage test", () => {
test("updateSlot", async () => {
// given
const slot: Slot = {
type: "gpt4o",
type: "gpt-4o",
id: "id",
name: "name",
isSelected: false,
Expand All @@ -175,7 +175,7 @@ describe("SlotStorage test", () => {
// given
const slotId = "slotId";
const slot: Slot = {
type: "gpt4o",
type: "gpt-4o",
id: slotId,
name: "name",
isSelected: false,
Expand Down
49 changes: 31 additions & 18 deletions src/pages/popup/components/SlotDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import {
Box,
Button,
ButtonProps,
HStack,
Input,
Menu,
MenuButton,
MenuItem,
MenuList,
Slider,
SliderFilledTrack,
SliderThumb,
SliderTrack,
Switch,
Text,
Textarea,
Tooltip,
VStack,
} from "@chakra-ui/react";
import { useState } from "react";
import { forwardRef, ForwardRefRenderFunction, useState } from "react";
import styled from "@emotion/styled";
import StyledButton from "@pages/popup/components/StyledButton";
import { COLORS } from "@src/constant/style";
Expand All @@ -34,7 +39,6 @@ export default function SlotDetail({
exitDetail,
}: SlotDetailProps) {
const [slot, setSlot] = useState(initialSlot);
const isGpt4Turbo = slot.type === "gpt4-turbo";

const onSaveButtonClick = () => {
onUpdate(slot);
Expand All @@ -48,11 +52,6 @@ export default function SlotDetail({
}));
};

const toggleGpt4TurboSwitch = () => {
updateSlot("type", isGpt4Turbo ? "gpt4-turbo" : "gpt4o");
console.log(isGpt4Turbo, slot);
};

return (
<VStack spacing={3} alignItems="flex-start">
<Text color={COLORS.WHITE} fontSize={12}>
Expand Down Expand Up @@ -100,16 +99,23 @@ export default function SlotDetail({
updateSlot("temperature", temperature);
}}
/>
<HStack justifyContent="space-between">
<Text
color={COLORS.WHITE}
textAlign="start"
whiteSpace="pre-wrap"
fontSize={12}
>
{t("slotDetail_isGpt4Turbo")}
</Text>
<Switch isChecked={isGpt4Turbo} onChange={toggleGpt4TurboSwitch} />
<HStack>
<Menu>
<MenuButton as={forwardRef(ModelSelectButton)}>
{slot.type}
</MenuButton>
<MenuList>
<MenuItem onClick={() => updateSlot("type", "gpt-3.5-turbo")}>
gpt-3.5-turbo
</MenuItem>
<MenuItem onClick={() => updateSlot("type", "gpt-4o")}>
gpt-4o
</MenuItem>
<MenuItem onClick={() => updateSlot("type", "gpt-4-turbo")}>
gpt-4-turbo
</MenuItem>
</MenuList>
</Menu>
</HStack>
<HStack paddingTop={4} width="100%" justifyContent="space-between">
<StyledButton onClick={onSaveButtonClick} colorScheme="blue">
Expand All @@ -123,6 +129,13 @@ export default function SlotDetail({
);
}

const ModelSelectButton: ForwardRefRenderFunction<
HTMLButtonElement,
ButtonProps
> = (props, ref) => {
return <Button ref={ref} {...props} size="xs" />;
};

type TemperatureSliderProps = {
temperature: number;
onChangeTemperature: (temperature: number) => void;
Expand Down
64 changes: 46 additions & 18 deletions src/pages/popup/pages/QuickChattingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import {
Button,
FormLabel,
ButtonProps,
HStack,
Switch,
Menu,
MenuButton,
MenuItem,
MenuList,
Textarea,
VStack,
} from "@chakra-ui/react";
Expand All @@ -12,13 +15,17 @@ import {
sendMessageToBackground,
sendMessageToBackgroundAsync,
} from "@src/chrome/message";
import { FormEventHandler, KeyboardEventHandler } from "react";
import {
FormEventHandler,
forwardRef,
ForwardRefRenderFunction,
KeyboardEventHandler,
} from "react";
import { useScrollDownEffect } from "@src/shared/hook/useScrollDownEffect";
import { t } from "@src/chrome/i18n";
import { useCopyClipboard } from "@src/shared/hook/useCopyClipboard";
import streamChatStateMachine from "@src/shared/xState/streamChatStateMachine";
import { getQuickGPTResponseAsStream } from "@src/shared/services/getGPTResponseAsStream";
import { COLORS } from "@src/constant/style";
import useGeneratedId from "@src/shared/hook/useGeneratedId";
import { ChatBox } from "@pages/content/src/ContentScriptApp/components/messageBox/ResponseMessageBox";

Expand All @@ -40,6 +47,12 @@ export default function QuickChattingPage({
const { id: sessionId, regenerate: regenerateSessionId } =
useGeneratedId("quick_");
const [state, send] = useMachine(streamChatStateMachine, {
context: {
inputText: "",
chats: [],
tempResponse: "",
model: (localStorage.getItem("model") as any) ?? "gpt-3.5-turbo",
},
services: {
getChatHistoryFromBackground: () => {
return sendMessageToBackgroundAsync({
Expand All @@ -48,7 +61,7 @@ export default function QuickChattingPage({
},
getGPTResponse: (context) => {
return getQuickGPTResponseAsStream({
isGpt4Turbo: context.isGpt4Turbo,
model: context.model,
messages: context.chats,
onDelta: (chunk) => {
send("RECEIVE_ING", { data: chunk });
Expand Down Expand Up @@ -101,6 +114,11 @@ export default function QuickChattingPage({
send("RECEIVE_CANCEL");
};

const onSelectModel = (model: "gpt-4-turbo" | "gpt-4o" | "gpt-3.5-turbo") => {
send("SELECT_GPT_MODEL", { data: model });
localStorage.setItem("model", model);
};

const onChatInputKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = (
event
) => {
Expand Down Expand Up @@ -155,19 +173,22 @@ export default function QuickChattingPage({
? t("quickChattingPage_copyButtonText_copied")
: t("quickChattingPage_copyButtonText_copy")}
</StyledButton>
<FormLabel
htmlFor="is-gpt4-switch"
mb="0"
color={COLORS.WHITE}
fontSize={12}
>
{t("quickChattingPage_isGpt4")}
</FormLabel>
<Switch
id="is-gpt4-switch"
isChecked={state.context.isGpt4Turbo}
onChange={() => send("TOGGLE_IS_GPT4_TURBO")}
/>
<Menu>
<MenuButton as={forwardRef(ModelSelectButton)}>
{state.context.model}
</MenuButton>
<MenuList>
<MenuItem onClick={() => onSelectModel("gpt-3.5-turbo")}>
gpt-3.5-turbo
</MenuItem>
<MenuItem onClick={() => onSelectModel("gpt-4o")}>
gpt-4o
</MenuItem>
<MenuItem onClick={() => onSelectModel("gpt-4-turbo")}>
gpt-4-turbo
</MenuItem>
</MenuList>
</Menu>
</HStack>
<HStack justifyContent="end">
{isReceiving && (
Expand All @@ -194,6 +215,13 @@ export default function QuickChattingPage({
);
}

const ModelSelectButton: ForwardRefRenderFunction<
HTMLButtonElement,
ButtonProps
> = (props, ref) => {
return <Button ref={ref} {...props} size="xs" />;
};

function findLastResponseChat(chats: Chat[]) {
return chats.filter((chat) => chat.role === "assistant").at(-1);
}
6 changes: 3 additions & 3 deletions src/shared/services/getGPTResponseAsStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { sendMessageToBackground } from "@src/chrome/message";

export async function getQuickGPTResponseAsStream({
messages,
isGpt4Turbo,
model,
onDelta,
onFinish,
}: {
messages: Chat[];
isGpt4Turbo: boolean;
model: "gpt-4-turbo" | "gpt-4o" | "gpt-3.5-turbo";
onDelta: (chunk: string) => unknown;
onFinish: (result: string) => unknown;
}) {
Expand All @@ -16,7 +16,7 @@ export async function getQuickGPTResponseAsStream({
const { disconnect } = sendMessageToBackground({
message: {
type: "RequestQuickChatGPTStream",
input: { messages, isGpt4Turbo },
input: { messages, model },
},
handleSuccess: (response) => {
if (response.isDone || !response.chunk) {
Expand Down
2 changes: 1 addition & 1 deletion src/shared/slot/createNewChatGPTSlot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function createNewChatGPTSlot(config?: Partial<Slot>): Slot {
return {
type: "gpt4o",
type: "gpt-4o",
isSelected: false,
id: generateId(),
name: "",
Expand Down
Loading

0 comments on commit 20df20f

Please sign in to comment.