카테고리 없음

[AI 글쓰기] Huggingface Inference

bay07 2024. 8. 13. 11:39
import { HfInference } from '@huggingface/inference';
더보기
import React, { useState } from 'react';
import { HfInference } from '@huggingface/inference';
import './Huggingwrite.css';
import { translateText } from '../../services/translateService';
import { useSpeechSynthesis } from 'react-speech-kit';


const hf = new HfInference('토큰');

const languageMap = {
  'en': 'English',
  'ko': 'Korean',
  'ja': 'Japanese',
  'es': 'Spanish'
};


interface SpeechSynthesisVoice {
  voiceURI: string;
  name: string;
  lang: string;
  default: boolean;
  localService: boolean;
}

const Huggingwrite: React.FC = () => {
  const [inputText, setInputText] = useState<string>('');
  // const [story, setStory] = useState<string | null>(null); 
  const [loading, setLoading] = useState<boolean>(false);
  const [translatedStory, setTranslatedStory] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [selectedLanguage, setSelectedLanguage] = useState<string>('ko'); 
  const [isSpeaking, setIsSpeaking] = useState<boolean>(false); 

  const { speak, cancel, voices } = useSpeechSynthesis();

  const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
    setInputText(event.target.value);
  };

  const handleLanguageChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
    setSelectedLanguage(event.target.value);
  };

  const generateStory = async () => {
    setLoading(true);
    setError(null);
    try {
      let textToGenerate = inputText;

      console.log('Initial Input Text:', inputText);

      if (selectedLanguage !== 'en') {
        console.log('Translating input text to English...');
        textToGenerate = await translateText(inputText, selectedLanguage, 'en');
        console.log('Translated Text to English:', textToGenerate);
      }

      console.log('Generating story with text:', textToGenerate);
      const result = await hf.textGeneration({
        model: 'HuggingFaceH4/zephyr-7b-beta',
        inputs: textToGenerate,
      });

      const cleanedStory = result.generated_text.replace(/(\r\n|\n|\r)/g, ' ');
      console.log('Generated Story in English:', cleanedStory);
      // setStory(cleanedStory);

      if (selectedLanguage !== 'en') {
        console.log('Translating generated story to selected language...');
        const translatedResult = await translateText(cleanedStory, 'en', selectedLanguage);
        console.log('Translated Story:', translatedResult);
        setTranslatedStory(translatedResult);
      } else {
        setTranslatedStory(cleanedStory);
      }
    } catch (error) {
      setError('Please try again.');
      console.error('Error generating story:', error);
    } finally {
      setLoading(false);
    }
  };

  const handleSpeak = () => {
    if (isSpeaking) {
      cancel();
      setIsSpeaking(false);
    } else if (translatedStory) {
      const voice = voices.find((v: SpeechSynthesisVoice) => v.lang.startsWith(selectedLanguage));
      
      if (voice) {
        speak({ text: translatedStory, voice });
        setIsSpeaking(true);
      } else {
        console.error(`No voice found for the selected language: ${selectedLanguage}`);
        alert(`No voice available for the selected language. Please check your browser's language settings.`);
      }
    }
  };

  return (
    <div>
      <div className='language-selection'>
        <label htmlFor="languageSelect">&nbsp;&nbsp;&nbsp;언어 선택 &nbsp;&nbsp;
          <select
            id="languageSelect"
            value={selectedLanguage}
            onChange={handleLanguageChange}
          >
            {Object.entries(languageMap).map(([code, name]) => (
              <option key={code} value={code}>{name}</option>
            ))}
          </select>
        </label>
      </div>

      <div className='total huggingwrite-container'>
        <div className='mid1'>
          <h1 className="huggingwrite-title" style={{ textAlign: 'center' }}>줄거리를 입력해주세요😊</h1>
          
          <div className='midbox1'>
            <textarea
              id="storyInput"
              name="storyInput"
              value={inputText}
              onChange={handleInputChange}
              rows={4}
              cols={50}
              style={{ fontSize: '20px' }}
              placeholder="Enter your text here..."
              className="huggingwrite-textarea"
            />
          </div>

          <button
            onClick={generateStory}
            disabled={loading}
            className={`huggingwrite-button ${loading ? 'loading' : ''}`}
          >
            {loading ? '잠시 기다려주세요...⚡⚡⚡' : '만들기'}
          </button>
        </div>

        <div className='mid2'>
          <h1 className="huggingwrite-title" style={{ textAlign: 'center' }}>만들어진 이야기 🧙</h1>
          <div className='midbox2'>
            <div className="huggingwrite-story-container">
              {error && <div className="error-message">{error}</div>}
              {/* <div>{story || ""}</div> */}
              <div>{translatedStory || ""}</div>
            </div>
          </div>
          {translatedStory && (
            <button onClick={handleSpeak} className="huggingwrite-button">
              {isSpeaking ? '멈추기' : '이야기 읽기'}
            </button>
          )}
        </div>
      </div>
    </div>
  );
};


export default Huggingwrite;

 

AI 글쓰기 기능을 어떻게 구현할 수 있을까 ? 
고민을 하다가, Hugging Face에서 제공하는 Inference를 사용할 수 있다는 것을 알게 되었습니다.

서버가 없어도 사용할 수 있고, 간편하게 모델을 불러올 수 있다는 장점이 있습니다. 

여기서는 H4zephyr-7b-beta라는 모델을 사용했습니다. 

 

https://huggingface.co/HuggingFaceH4/zephyr-7b-beta

 

HuggingFaceH4/zephyr-7b-beta · Hugging Face

Model Card for Zephyr 7B β Zephyr is a series of language models that are trained to act as helpful assistants. Zephyr-7B-β is the second model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1 that was trained on on a mix of public

huggingface.co

 

그런데, 이 모델은 영어 input과 output만 가능하기 때문에

중간에 MyMemory API 를 사용해서 번역하는 기능을 추가했습니다.  

MyMemory API 를 사용한 이유는, 오픈 소스이기도 하고 간단하게 불러와서 사용할 수 있기 때문

 

더보기
// translateService.ts

import axios from 'axios';

// MyMemory API URL
const MYMEMORY_API_URL = 'https://api.mymemory.translated.net/get';

// 번역 함수
export const translateText = async (text: string, sourceLang: string, targetLang: string): Promise<string> => {
  try {
    // GET 요청을 통해 번역 수행
    const response = await axios.get(MYMEMORY_API_URL, {
      params: {
        q: text,
        langpair: `${sourceLang}|${targetLang}`,
      },
    });

    // 번역된 텍스트 반환
    return response.data.responseData.translatedText;
  } catch (error) {
    console.error('Error translating text:', error);
    throw error;
  }
};

 

 

 

 

 

mainai3.mp4
0.43MB