API 호출 및 활용
실제 API 및 모델의 사용방법
¶ FastAPI & GPT-4o Chat 서비스
¶ YOLO Webcam 이용 객체 탐지
¶ Eleven Labs & NLLB-200 번역 서비스
FastAPI & GPT-4o Chat 서비스
main.py
: Back-end 웹이나 앱에서 사용자의 행동을 처리하고, 정보를 저장, 관리, 전달하며, 서버와 데이터베이스를 관리template
-index.html
: Front-end 웹사이트나 앱 등의 사용자 인터페이스(UI)
main.py
- 서비스를 실제로 작동시키는 역할
패키지 설치 및 모듈 불러오기
패키지
- FastAPI
Form
데이터 처리를 위해python-multipart
설치
pip install openai
pip install fastapi
pip install python-multipart # Form 데이터 처리
모듈
OpenAI
: 핵심 프로그램 제공FastAPI
: API 요청과 html 응답처리Jinja2Templates
: html 파일과 상호작용StaticFiles
: 정적 파일과 상호작용
from openai import OpenAI
from fastapi import FastAPI, Request, Form
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
기본 설정
- API 설정
- 템플릿 설정
- 정적 파일 설정
- 프로그램 초기 설정
app = FastAPI() # fastapi 인스턴스르 통해 api요청-html 응답 처리
# OpenAI API 클라이언트 설정
client = OpenAI()
# Jinja2 템플릿 설정
templates = Jinja2Templates(directory="/templates")
# 정적 파일 서빙
app.mount("/static", StaticFiles(directory="/static"), name="static")
# 초기 시스템 메시지 설정
system_message = {
"role": "system",
"content": "너는 시인이야, 주제를 주면 5줄의 시를 지어줘"
}
# 대화 내역을 저장할 리스트 초기화
messages = [system_message]
기본 페이지 설정
async def
비동기 함수"/"
경로(기본 페이지)에 대한 GET요청을 처리response_class=HTMLResponse
는 응답을 HTML 형식으로 설정(기본값 json)
"request": request
는 FastAPI와 Jinja2 템플릿 엔진을 사용할 때 필요한 매개변수- 템플릿에서 요청 관련 정보에 접근할 수 있게 됨
@app.get("/", response_class=HTMLResponse)
async def get_chat_page(request: Request):
conversation_history = [msg for msg in messages if msg["role"] != "system"]
# 시스템 메시지 제외
return templates.TemplateResponse("index.html", {"request": request, "conversation_history": conversation_history})
서비스 페이지 설정
async def
비동기 함수 설정
user_input
: 사용자 입력을 받아옴str
: 변수 타입Form
: HTML 폼 데이터를 서버로 전달할 때 사용 (기본값 json)...
: 필수 필드임을 나타내는 FastAPI의 방식
@app.post("/chat", response_class=HTMLResponse)
async def chat(request: Request, user_input: str = Form(...)):
프로그램 설정
global
: 전역 변수로 설정- 전체 영역에서 영향을 주는 변수
global messages # 이전 대화 내용을 저장하여 대화
# 사용자의 메시지를 대화 내역에 추가
messages.append({"role": "user", "content": user_input})
# OpenAI API 호출
completion = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
# AI의 응답 가져오기
assistant_reply = completion.choices[0].message.content
# AI의 응답을 대화 내역에 추가
messages.append({"role": "assistant", "content": assistant_reply})
# 화면에 표시할 대화 내역에서 system 메시지를 제외하고 전달
conversation_history = [msg for msg in messages if msg["role"] != "system"]
# 결과를 HTML로 반환 (대화 내역과 함께)
return templates.TemplateResponse("index.html", {
"request": request,
"conversation_history": conversation_history
})
index.html
¶
- Github Pages : Jekyll 사용
- post 내부에 html 코드가 포함되면 markdown을 html로 변환하는 과정에 오류 발생
- 별도의 링크로 연결하여 내용 대체
결과
User : 가을에 관한 시를 지어줘
Assistant : 낙엽은 금빛 춤을 추며 내려앉고, 바람은 가을의 이야기를 속삭이네. 짧아진 해는 노을 속에 스며들고, 서늘한 공기에 달콤한 기운 담겨, 가을은 또 한 번 마음 깊이 물들여.
YOLO Webcam 이용 객체 탐지
PyQt5
: 유저 인터페이스를 구성하는 라이브러리
모듈 불러오기
- 사용 모듈이 많은 경우 번거롭더라도 한번에 불러오기
- 분리해서 불러올 경우 관리가 어려움
from ultralytics import YOLO
import cv2 # openCV 핵심 모듈
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget, QPushButton # 인터페이스
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QImage, QPixmap # 이미지 처리
인터페이스 구성
- 인터페이스의 각 부분을 설정하고 기능 함수와 연결
class VideoCaptureWidget(QWidget):
# Qwidget 상속
def __init__(self):
super().__init__()
# YOLOv8x 모델 로드
self.model = YOLO('yolov8x.pt')
# UI 설정
# 타이틀 설정
self.setWindowTitle('실시간 객체 탐지')
self.image_label = QLabel(self)
self.layout = QVBoxLayout()
self.layout.addWidget(self.image_label)
# 시작 버튼 설정
self.start_button = QPushButton('Start Webcam', self)
self.start_button.clicked.connect(self.start_webcam) ##
self.layout.addWidget(self.start_button)
# 종료 버튼 설정
self.stop_button = QPushButton('Stop Webcam', self)
self.stop_button.clicked.connect(self.stop_webcam) ##
self.layout.addWidget(self.stop_button)
self.setLayout(self.layout)
# 웹캠 초기화
self.capture = None
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_frame)
# 주기적으로 새로운 프레임 업데이트
함수 설정
- 객체 탐지 및 이미지 변환 함수
- 인터페이스 작동 함수
def stop_webcam(self):
# 웹캠, 타이머 중지
self.timer.stop()
if self.capture is not None:
self.capture.release()
def start_webcam(self):
# 웹캠, 타이머 시작, 주기적으로 프레임 업데이트
self.capture = cv2.VideoCapture(0)
self.timer.start(20) # 20ms마다 프레임 업데이트 - 50fps(초당 50 프레임)
def update_frame(self):
# 웹캠에서 프레임을 읽은 후 YOLO 객체 탐지 후 UI에 표시
ret, frame = self.capture.read()
if ret:
# YOLO 객체 탐지
results = self.model(frame)
result = results[0]
# 바운딩 박스가 포함된 이미지 호출
img_with_boxes = result.plot()
# OpenCV 이미지를 QImage로 변환
rgb_image = cv2.cvtColor(img_with_boxes, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * 2
convert_to_Qt_format = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
# QImage를 QLabel에 표시하기 위해 QPixmap으로 변환
self.image_label.setPixmap(QPixmap.fromImage(convert_to_Qt_format))
def closeEvent(self, event):
# 종료 시 웹캠 해제
if self.capture is not None:
self.capture.release()
실행
if __name__ == "__main__"
: 실행 파일이 main(가장 처음 시작되는 중심 파일)인 경우 실행
if __name__ == "__main__":
app = QApplication([])
# QApplication 실행: PyQt5 GUI 앱을 실행하고, VideoCaptureWidget 객체 호출
window = VideoCaptureWidget()
window.show()
app.exec_()
결과
0: 384x640 1 person, 1 chair, 1 bed, 1 refrigerator, 531.4ms
Speed: 7.4ms preprocess, 531.4ms inference, 8.5ms postprocess per image at shape (1, 3, 384, 640)
Eleven Labs & NLLB-200 번역 서비스
- NLLLB-200 모델로 번역 수행
- Eleven Labs API로 번역 내용 음성 생성
- PyQt5로 UI 구성
주의점
transformers
의 최신 버전(4.38 이후)에서는lang_code_to_id
를 제공하지 않음pip install transformers==4.37.0
모듈 불러오기
import os
import requests
from PyQt5 import QtWidgets
from PyQt5.QtCore import QUrl
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
from pydub import AudioSegment
from pydub.playback import play
import io
API 설정
- 환경 변수에서 불러오기
api_key = os.environ.get('Eleven_Labs_API_KEY')
# model url = "https://api.elevenlabs.io/v1/text-to-speech/{VOICE_ID}/stream"
url = "https://api.elevenlabs.io/v1/text-to-speech/ZJCNdZEjYwkOElxugmW2/stream"
class TranslatorApp(QtWidgets.QWidget):
초기화 함수 설정
- 초기화 함수 상속
- 모델 및 API 설정
def __init__(self):
super().__init__()
self.init_ui()
# 번역 모델 로드
model_name = "facebook/nllb-200-distilled-600M"
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
# API 설정
self.api_key = api_key
self.url = url
# 음성 재생기
self.player = QMediaPlayer()
UI 설정
def init_ui(self):
# UI 구성
self.text_input = QtWidgets.QLineEdit(self)
self.text_input.setPlaceholderText("번역할 텍스트 입력")
self.translate_button = QtWidgets.QPushButton("번역 및 음성 생성", self)
self.output_label = QtWidgets.QLabel(self)
self.play_button = QtWidgets.QPushButton("음성 재생", self)
self.play_button.setEnabled(False)
# 레이아웃 설정
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.text_input)
layout.addWidget(self.translate_button)
layout.addWidget(self.output_label)
layout.addWidget(self.play_button)
self.setLayout(layout)
# 버튼 클릭 시 이벤트 핸들러 연결
self.translate_button.clicked.connect(self.translate_and_generate_audio)
self.play_button.clicked.connect(self.play_audio)
# 윈도우 창 설정
self.setWindowTitle("번역 및 음성 생성기")
self.show()
음성 생성 기능 설정
- 사용자 입력을 변수로 번역수행 함수 설정
- 번역 결과를 변수로 음성 생성 함수 설정
- 결과 저장 경로를 확인
def translate_and_generate_audio(self):
text = self.text_input.text()
# 번역 수행
inputs = self.tokenizer(text, return_tensors="pt")
generated_tokens = self.model.generate(inputs.input_ids, forced_bos_token_id=self.tokenizer.lang_code_to_id["kor_Hang"])
translated_text = self.tokenizer.decode(generated_tokens[0], skip_special_tokens=True)
# 음성 생성 요청
data = {
"text": translated_text,
"model_id": "eleven_multilingual_v2",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 1,
"style": 0.5,
"use_speaker_boost": True
}
}
headers = {
"xi-api-key": self.api_key,
"Content-Type": "application/json"
}
response = requests.post(self.url, json=data, headers=headers)
if response.status_code == 200:
output_audio_path = "/translator/output_audio.mp3"
with open(output_audio_path, "wb") as f:
f.write(response.content)
self.output_label.setText(f"번역 결과: {translated_text}")
self.play_button.setEnabled(True)
else:
self.output_label.setText("음성 생성 실패")
음성 재생 설정
- 재생할 음성 경로 확인
def play_audio(self):
# 음성 파일 재생
audio_path = "/translator/output_audio.mp3"
if os.path.exists(audio_path):
# Pydub을 통해 mp3 파일을 불러와서 재생
audio = AudioSegment.from_mp3(audio_path)
play(audio) # Pydub의 play() 함수 사용
else:
self.output_label.setText("오디오 파일을 찾을 수 없습니다.")
실행
if __name__ == '__main__':
app = QtWidgets.QApplication([])
translator = TranslatorApp()
app.exec_()
결과
안녕하세요 마리오 입니다.
- HYUK : 한국어 음성 모델 최상단