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"> 언어 선택
<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;
}
};