ChatGPT API로 velog 요약 크롬 앱 만들기 (React, Vite)

LEEJAEJUN·2024년 2월 9일
0

2024

목록 보기
3/5
post-thumbnail

개요

다운로드 링크

개발 공부를 하다보면 탭이 30~40개씩 띄워져 있는 경우가 있습니다. 크롬이 메모리도 엄청 잡아먹고 배터리가 빨리 닳는 것 같기도 해서 탭 관리를 해주는 앱이 있으면 좋겠다 싶었습니다. 제가 생각한 앱의 용도는 아래와 같습니다.

  • 전체 탭 띄워주기
    • 탭이 열린 시간과 얼마나 경과되었는지 보여줄 원
    • 탭 제목 클릭 시 해당 탭 열기
    • 특정 시간이 지나면 탭 끄기
    • 요약하기

하루 이상 지나면 정리를 해야 한다는 빨간 원을 보여줌으로써 사용자가 인지하고 한 번더 공부하고 정리할 수 있게 해줍니다. 그 과정에서 시간이 부족한 경우 요약하기 버튼을 통해 약식으로 정리하고 탭을 닫을 수 있습니다.

프로세스

  • vite.config.ts 빌드 설정
    먼저 크롬 웹스토어에 맞는 아웃풋을 만들기 위해 vite.config.ts의 rollupOptions를 수정합니다. popup.js, background.js, contentScript.jsdist 폴더 안에 번들링할 수 있도록 아래와 같이 세팅했습니다.
export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      input: {
        popup: "/popup.html",
        background: "/src/background.ts",
        contentScript: "/src/contentScript.ts",
      },
      output: {
        entryFileNames: `[name].js`,
        chunkFileNames: `[name].js`,
        assetFileNames: `[name].[ext]`,
      },
    },
  },
});

Popup.tsx

  • 크롬 로컬 스토리지에 저장되어 있는 탭을 fetch합니다.
  • 지금 켜져있는 탭을 스토리지에 저장하는데 만약 이미 스토리지에 들어있다면 따로 저장하지 않습니다.
  • 존재하는 탭을 state로 관리하고 map 을 사용해 리스트를 보여줍니다.
  • 유틸 함수를 만들어 해당 탭에 대한 시간 정보를 몇 분 전 의 형태로 보여줍니다.
  • Puppeteer를 활용해 해당 사이트에 중요한 정보를 크롤링하고 텍스트 형태로 반환합니다. 이 텍스트는 GPT 요약에 사용됩니다. (사이트마다 트리구조가 달라서 velog에만 적용했습니다.)
  • GPT를 활용해 요약하기 버튼 클릭 시 text를 전송해 요약해달라고 부탁합니다. (gpt-4-turbo-preview 사용)
const summarizeWithGPT = async (tabId: number, text: string) => {
  try {
    const completion = await openai.chat.completions.create({
      messages: [
        {
          role: "system",
          content: `You are a summary expert. Summarize the text into 3 sentences in English. '''${text}'''`,
        },
      ],
      model: "gpt-4-turbo-preview",
      max_tokens: 100,
    });
    setSummaries((prev) => ({
      ...prev,
      [tabId]: completion.choices[0].message.content!,
    }));
  } catch (err) {
    console.error(err);
  }
};
  • 어떤 프로세스가 진행중인지 보여주기 위해 로딩 상태를 string으로 관리합니다.
const handleSummarize = async (tabId: number, url: string) => {
    setLoadingStates((prev) => ({
      ...prev,
      [tabId]: { type: "read", state: true },
    }));
    try {
      const textContet = await handleCrawl(url);
      setLoadingStates((prev) => ({
        ...prev,
        [tabId]: { type: "summarize", state: true },
      }));
      if (textContet) {
        await summarizeWithGPT(tabId, textContet);
      } else {
        console.error("No text content");
      }
    } catch (error) {
      console.error("Summarize failed:", error);
    } finally {
      setLoadingStates((prev) => ({
        ...prev,
        [tabId]: { type: "finish", state: false },
      }));
    }
  };

background.ts

  • 탭이 켜지거나 업데이트 될 때 스토리지 정보를 수정합니다. (tabId 활용)
  • 탭이 꺼질 때 스토리지에서 삭제합니다.
id: tab.id,
title: tab.title,
url: tab.url,
favicon: tab.favIconUrl,
createdAt: Date.now(),

크롬 웹 스토어 등록

번들링 결과인 dist 폴더를 압축해 크롬 개발자 대시보드에서 검토 요청을 합니다. 2-3일 후 거부, 혹은 게시 결과를 보내줍니다.

느낀점

  • 요약하기 버튼을 눌렀을 때 어떤 프로세스가 진행중인지 보이지 않아 로딩 상태를 각각 관리했습니다. 덕분에 사용 시 제대로 작동하는지 고민하는 시간이 줄어들었습니다.
  • 요약하기를 진행할 때 전체 글을 긁어오다보니 token이 한 번에 1500-2000개가 사용되었습니다. 텍스트 가중치를 이용해 특정 중요 문장만 input에 넣을 수 있도록 만들어 볼 예정입니다.
  • https에서 EC2 http로 요청을 보내니 block이 되는 것 같습니다. AWS certificate manager를 활용해 https로 전환해볼 예정입니다.
  • 역시 만들고 나면 부족한 부분이 많이 보이는 것 같습니다. UX 개선 사항이 많이 보입니다.
profile
always be fresh

0개의 댓글

관련 채용 정보