본문 바로가기

AI 활용

[AI 음성변환] firebase storage, firestore 파일 저장 - (2)

반응형

1. 프론트에서 firebase storage 음성 업로드 기능

초기 기획에서 프론트에서 음성을 업로드하는 형태는 박스를 클릭 혹은 박스에 드래그앤 드롭으로 동작해야하며 

다음과 같은 반응이 추가시켰다.

- 업로드가 진행중인 표시가 나타나게

- 파일이 정상적으로 업로드가 완료되면 완료 표시, 실패시 실패 표시

- 파일 확장자가 wav, mp3 인지

- 파일 크기가 15 mb 미만인지

 

이를 위해 <input> 과 <div> 태그를 이용해 간략하게 드래그앤드롭 및 css 등을 구성하였다.

해당 코드는 간략하게 다음과 같다.

<div
  onMouseEnter={handleMouseEnter}
  onMouseLeave={handleMouseLeave}
  onDragOver={handleDragOver}
  onDrop={handleDrop}
  onClick={handleDivClick}
>
  <input
    type={"file"}
    ref={inputRef}
    onChange={handleFileChange}
    style={{ display: "none" }}
  />
  {state.origin_file.url ? (
    <div>
      <p>{state.origin_file.filename}</p>
      <p>업로드 성공</p>
    </div>
  ) : uploadLoading ? (
    <p>
    	uploading 진행중
    </p>
  ) : (
      <p>
        클릭 혹은 드래그하여 파일을 업로드해주세요.
      </p>
  )}
</div>

input 태그의 handleFileChange 가 작동되면 

 

validation 함수를 통해 유저가 로그인되어있는지, 파일크기나 확정자 확인 후 전부 만족하면

firebase storage 에 저장 후 저장이 성공적으로 이뤄지면 firestore 에 유저와 storage url 이 저장된다.

 

이를 위해 addStorageData 함수와, addData 함수를 firebaes/storage, firebase/firestore에 각 각 작성해주고

export default async function addStorageData(file, point) {
  let storageRef = ref(storage, point);

  let url = null;
  let error = null;
  let fileName = null;

  try {
    await uploadBytes(storageRef, file);
    url = await getDownloadURL(storageRef);
    fileName = storageRef.name;
  } catch (e) {
    error = e;
  }

  return { url, fileName, error };
}

 

 

[addData 생략]

 

다음과 같이 handleUpload 를 통해 위의 과정을 수행하였다.

const handleUpload = async (file) => {
  try {
    const sanitizeName = sanitizeFileName(file.fileName);

    // 1. storage에 저장
    const uploadPath = "audio/" + id + "/" + sanitizeName

    const saveStorageResult = await addStorageData(
      file,
      uploadPath
    );

    if(saveStorageResult.error){
      alert('데이터베이스 삽입 시 에러가 발생했습니다.')
      return;
    }

    // 2. context api 에 저장
    dispatch({
      type: 'SET_ORIGIN_FILE_INFO',
	  ...
      upload_path : uploadPath,
    })

    // 3. database 에 저장
    const audioData = {
      ...
      uploadPath: uploadPath,
    };

    const addDataResult = await addData("audio",audioData);
    if (addDataResult.error) {
      alert("에러가 발생했습니다.");
      return;
    }
  } catch (e) {
    ...
  }
};

이런식으로 빠르고 간단하게 storage 를 이용하여 audio 파일을 저장하고, 

해당 url 을 firestore 에 저장, 필요한 상황에 쿼리를 통해 audio 파일을 다운로드 하거나, 재생할 수 있게 구현을 완료하였다.

 

audio 파일을 재생 할 때에는 wavesurfer.js 라이브러리를 통해 간략하게 디자인해서 다음과 같이

재생, 볼륨조절, 삭제 + 저장버튼 이 존재하는 컴포넌트를 구현하였고,

저장 버튼을 누르면 firebase/storage 의 getDownloadURL 메소드를 통해 다운로드 될수 있게 - 코드는 다음과 같다

 


// wavesurfer player component 중 download 

const onClickDownload = () => {
  downloadData(state.remix_upload_path)
}

// downloadData
export default function downloadData(uploadPath){
  getDownloadURL(ref(storage, uploadPath))
    .then((url) => {
      const fileName = uploadPath.fileName

      // This can be downloaded directly:
      const xhr = new XMLHttpRequest();
      xhr.responseType = 'blob';
      xhr.onload = (event) => {
        const blob = xhr.response;

        const reader = new FileReader();
        reader.onloadend = () => {
          // `reader.result` contains the file content as a data URL
          const dataURL = reader.result;

          // Create a new anchor element
          const link = document.createElement('a');
          link.href = dataURL;
          link.download = fileName

          // Simulate a click event to trigger the download
          link.dispatchEvent(new MouseEvent('click'));
        };
        reader.readAsDataURL(blob);
      };
      xhr.open('GET', url);
      xhr.send();

    })
    .catch((error) => {
      alert('다운로드 실패')
      ...
    });

 

 

그냥 아주 간략하게 구상한 부분과 코드 일부분을 기억하기 위해 작성하였으니

궁금하신 분은 댓글을 통해 물어봐주세요

 

 

반응형