본문 바로가기
Programming/FrontEnd

[OpenAI] 음악 추천 서비스 만들어보기 (React) 2부

by devpine 2023. 2. 22.
반응형

오늘은 저번에 이어서 OpenAI 를 사용한 서비스를 만들어보겠습니다. 1부 포스팅은 여기에서 볼 수 있습니다. 

1부: https://bolob.tistory.com/entry/OpenAI-%EC%9D%8C%EC%95%85-%EC%B6%94%EC%B2%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EA%B8%B0-React-1%EB%B6%80

 

[OpenAI] 음악 추천 서비스 만들어보기 (React) 1부

오늘은 ChatGPT에 사용된 OpenAI를 사용해서 음악 추천 서비스를 만들어보려고 합니다! 어떻게 만들면 되는지 과정을 기록해보고 공유해보겠습니다. OpenAI 가이드를 따라서 하면 어렵지 않게 서비스

bolob.tistory.com

 

문제 발생

우선 1부를 마무리하면서 예상하지 못한 문제가 생겼는데, maniaDB의 음악 검색 Open Api가 당연히 제목, 가수가 동시에 필터링되도록 검색이 가능할 것이라고 생각했던 것이 발목을 잡았습니다.

제 프로젝트에서 maniaDB의 검색 Api 사용 관련해서 발생한 이슈는 2가지였습니다.

 

이슈 1 (Critical)

1. 첫 번째 이슈는 한번에 한 검색어만 파라미터(쿼리 스트링)로 넘길 수 있어서, 노래제목 + 가수를 동시에 검색하지 못했습니다. 따라서 원하는 가수의 노래를 검색하기 위해서는, 가수(또는 노래)를 먼저 검색해서 해당 페이지에 찾는 노래(또는 가수)가 없다면 찾는 노래(또는 가수)가 조회될 때까지 Api를 계속 호출해주어야 하고, 언제까지 호출을 해야 할지도 모르는 상태에서 기약 없는 호출을 반복하게 됩니다. 이 이슈는 크리티컬 이슈로 판단하였는데, 제가 원했던 기능을 아예 구현하기 어렵게 되었기 때문에 프로젝트가 스탑 되었기 때문입니다.

const sr = 'song'; // or 'artist'
fetch(`/api/search/${keyword}/?sr=${sr}&display=1&v=0.5`);

 

해결방안 1

1-1. 첫 번째 해결 방안은 Open Api를 더 조사해서 제목, 가수 키워드를 동시에 검색할 수 있는 Api로 변경하자! 였습니다. 알아본 API 중 가장 괜찮은 건 Spotify에서 제공하는 OpenApi 였는데, 사용한다면 Spotify 로그인 기능까지 구현해야 한다는 문제점이 있었습니다. 추후에 프로젝트를 고도화하는 과정에서 로그인 기능 추가도 하면 좋겠다고 생각했지만, 다만 이번 프로젝트의 주목적은 OpenAI API 적용이었으며, 단기간에 적용해보고자 했기 때문에 Spotify Api는 사용하지 않기로 결정하였습니다. 다음으로는 Last.fm API를 찾았는데, 제가 원한 앨범커버, 가수, 제목을 받아올 수 있는 것 같아서 괜찮은 대안이 될 것 같다는 생각이 들었지만, docs 파악에 시간이 걸리던 중 다른 해결 방법을 찾아 Open Api 조사를 중단하였습니다.

Spotify API: https://developer.spotify.com/documentation/web-api/

 

Web API | Spotify for Developers

Simply put, your app receives Spotify content through the Spotify Web API.

developer.spotify.com

Last.fm API: https://www.last.fm/api

 

API Docs | Last.fm

The world's largest online music service. Listen online, find out more about your favourite artists, and get music recommendations, only at Last.fm

www.last.fm

 

해결방안 2

1-2. 바로 이 해결 방법을 찾아서 프로젝트를 다시 진행할 수 있게 되었는데요. sr 파라미터를 song이나 artist 대신 album으로 넘겨주었을 때, 원하는 검색 결과에 가까운 데이터를 얻을 수 있었습니다. 모두 정확한 응답 데이터를 반환하는지는 테스트해보고 확인해보아야 할 것 같지만, 우선 원하는 동작을 성공하였으므로 이 방법으로 진행하되, 만약 작업 중 이슈가 발견된다면 대안인 Last.fm API으로 변경도 고려하고 있습니다.

const sr = 'album';
fetch(`/api/search/${keyword}/?sr=${sr}&display=1&v=0.5`);

 

이슈 2 (Minor)

2. 두 번째 이슈는 응답 데이터가 XML 형식으로 rss 컨테이너 안에 있어서 내부의 item을 찾아서 파싱을 해주어야 한다는 불편함이 있었습니다. JSON 형식을 주로 다루어서 파싱하고 내부의 데이터를 파악하는 데에 좀 번거롭다는 생각이 들었지만, 라이브러리를 사용한다면 불가능하지는 않아서 마이너 이슈라고 판단했습니다.

 

음악 검색 기능 추가

그럼 제가 음악 검색 기능을 연동한 코드를 첨부하겠습니다. 아래는 현재까지의 App.js 코드입니다.

import { useCallback, useEffect, useState } from 'react';
import './App.css';
import XMLParser from 'react-xml-parser';
import { Configuration, OpenAIApi } from 'openai';

function App() {
  const [music, setMusic] = useState({ title: '', artist: '', img: '' });
  const regExp = /[\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]/g; // eslint-disable-line

  // Mania search API 호출
  const fetchMusicSearchApi = useCallback(
    (keyword) => {
      const sr = 'album';

      fetch(`/api/search/${keyword}/?sr=${sr}&display=1&v=0.5`)
        .then((response) => response.text())
        .then((str) => new XMLParser().parseFromString(str))
        .then((data) => {
          const { children } = data.children[0];
          const item = children.filter((child) => child.name === 'item')[0]
            .children;

          const text = item.filter((el) => el.name === 'title')[0].value;
          const img = item
            .filter((el) => el.name === 'image')[0]
            .value.replace('>', '');
          const [artist, title] = text.split(regExp);

          setMusic({ title, artist, img });
        })
        .catch((error) => {
          console.log(`error: ${error}`);
        });
    },
    [regExp]
  );

  // OpenAI API 호출
  const fetchOpenAIApi = useCallback(() => {
    const configuration = new Configuration({
      apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const testPrompt = 'recommend me one male indie song';

    new OpenAIApi(configuration)
      .createCompletion({
        model: 'text-davinci-003',
        prompt: testPrompt,
        temperature: 0,
        max_tokens: 150,
      })
      .then((res) => {
        const { choices } = res.data;
        const [title] = choices[0].text.split('by');

        fetchMusicSearchApi(title);
      });
  }, [fetchMusicSearchApi]);

  useEffect(() => {
    fetchOpenAIApi(); // Mount 시 호출한다.
  }, [fetchOpenAIApi]);

  const { title, artist, img } = music;

  return (
    <div className="App">
      <img className="Thumbnail" src={img} alt="Thumbnail" />
      {title} {artist}
    </div>
  );
}

export default App;

 

현재까지 하드코딩으로 넣어준 질문에 대해 OpenAI로 노래를 추천받고, 해당 노래를 maniaDB Search Api로 검색하여 노래 제목, 가수, 앨범 커버 이미지를 화면에 노출하는 작업까지 해보았습니다. 

다음 3부에서는 질문을 기분, 날씨, 장르 등 원하는 키워드를 선택하여 사용자마다 다른 노래를 추천받을 수 있도록 해보려고 합니다. 그럼 읽어주셔서 감사하고 다음 포스팅으로 돌아오겠습니다!

반응형

댓글