반응형

저번편에는 API 연동 및 STT, TTS 를 사용해 gpt3.5 와 대화하는 것까지 구현을 진행했다.

하지만, 곰곰히 생각해보니 이 기능만으로는 부족하다는 생각이 들었고 추가 기능을 생각해보기로 했다.

추가 기능 구현

노인을 위한 이미지 편집 기능

보통 어르신들이 친구들과 카카오톡 대화를 할 때 카카오톡 이모티콘 만큼 자주 사용하는 사진들이 있다.

 

 

바로 요런 사진들!

나는 이미지를 Stable-diffusion 을 이용해 생성을 한 후 사용자가 원하는 글귀를 이미지에 삽입하는 기능을 구상했다.

위의 기능을 구현하기 위해 생각한 흐름을 한 번 보자면

 

알고리즘

  1. 이미지로 만들고 싶은 카테고리를 선택한다.
  2. 원하는 글귀를 선택한다.
  3. 이미지를 생성한다.
  4. 원하는 글귀를 이미지에 넣는다.

이미지생성

이미지 생성은 원래 로컬서버에 저장 후 사용하는 방식을 썼는데 그렇게하면 나중에 서버에 여러 이미지가 쌓여 넘칠게 뻔하기 때문에 API 를 이용해 보기로 했다.

async function query() {
        console.log("Send Query")
        setImageURL('');
        var data = { "inputs": props.inputValue,"use_cache":false }
        const response = await fetch(
            "<https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-2-1>",
            {
                headers: { Authorization: "Bearer API_KEY" },
                method: "POST",
                body: JSON.stringify(data),
            }
        );
        var formData = new FormData();
        await response.blob().then((res)=>{
            formData.append('image',res);
            formData.append('textPrompt', props.textPrompt)
            
            axios.post("/api/imgEdit",formData).then((res) => {
                console.log("api img edit response", res.data);
                setImageURL(res.data.slice(2,-1))
                props.setLoading(false)  
              });
        })
    }

frontend 에서 이미지를 받아올 것이기 때문에 js 코드로 함수를 구현했다.

huggingface API 를 사용하면 이미지 데이터는 blob 형식으로 받게 된다. 해당 데이터를 서버로 보내 처리하기 위해서는 formdata 에 저장 후 보내야한다.

formData.append(’image’,res) 를 사용해 blob 데이터를 저장한다. 이제 여기서 blob 데이터를 이미지로 출력하면 생성된 이미지가 화면에 나오게 된다.

나는 여기에 텍스트를 편집할것 이기 때문에 서버로 blob 과 텍스트 데이터를 전송하겠다.

이제 서버에 전달받은 데이터를 파이썬 코드를 실행하기 위해 다음과 같은 코드를 작성했다.

async function imgEdit (imgBlob, text) {
    return new Promise((resolve, reject) =>{
        let dataToSend;
        const msg = text;
        console.log("img edit : ",text, "img URL : ", imgBlob.path);
        const python = spawn(desiredPath, [ msg, imgBlob.path]);

        python.stdout.on('data', async function(data){
            dataToSend = data.toString();
            console.log("imgEdit start", dataToSend);
            resolve(dataToSend)
        });

        python.stderr.on("data", async function(data) {
            console.error("Python Error: ", data.toString())
            reject(data.toString())
        });

        python.on('error', (error) => {
            console.error("Spawn Error: ", error);
            reject(error);
        });
    })
}

Promise 객체를 생성 후 spawn 을 이용해 데이터를 파이썬 코드로 보낸다. 파이썬에서 처리를 한 데이터를 resolve 를 통해 받아 frontend 로 전달한다.

파이썬 코드는 다음과 같다.

import numpy as np
from PIL import ImageFont, ImageDraw, Image
import cv2
import sys
import base64
from io import BytesIO

def calculate_average_color(image):
    # 이미지의 RGB값을 계산
    r, g, b = 0, 0, 0
    pixels = image.load()
    width, height = image.size
    for y in range(height):
        for x in range(width):
            _r, _g, _b = pixels[x, y]
            r += _r
            g += _g
            b += _b
    # 평균값을 계산
    num_pixels = width * height
    r //= num_pixels
    g //= num_pixels
    b //= num_pixels
    return b,g,r

def get_complementary_color(b,g,r):
    # 보색을 계산
    r, g, b = b,g,r
    return 255 - r, 255 - g, 255 - b

try:    
    image = cv2.imread(sys.argv[2], cv2.IMREAD_ANYCOLOR)
    overlay = image.copy()
except Exception as e:
    print("error", e)

imgForColor = Image.open(sys.argv[2])

avgB, avgG,avgR = calculate_average_color(imgForColor)
comB,comG,comR = get_complementary_color(avgB,avgG,avgR)
b,g,r= 0,0,0

if((avgB+avgG+avgR)/3 >=128):
    b,g,r = 0,0,0
else:
    b,g,r = 255,255,255

font_size = 80
h,w,c = image.shape

line_w = w/font_size

height = str(h)

test_str = sys.argv[1]
max_line = (int)(len(test_str)/line_w)+1

str_slice = test_str.split(" ")
exp_str = []
str_token = ""

font = ImageFont.truetype("arial.ttf", font_size)

i = 0
while i != len(str_slice):
    if len(str_token) + len(str_slice[i]) + 1 <= line_w:
        str_token += " " + str_slice[i]
        i += 1
    else:
        exp_str.append(str_token.strip())  # str_token의 앞뒤 공백 제거 후 추가
        str_token = ""  # str_token 초기화
    if i == len(str_slice) and str_token:  # 마지막 요소이고, str_token이 빈 문자열이 아닌 경우
        exp_str.append(str_token.strip()) 

background_h = []

center_w = []
for i in range(len(exp_str)):
    left,top,right,bottom = font.getbbox(exp_str[i])
    center_w.append(right)

for i in range (len(exp_str)):
    background_h.append((int)((h/2) + (i - len(exp_str)/2) * font_size))

cv2.rectangle(overlay, (0, background_h[0]), (w, background_h[len(exp_str)-1]+font_size), (comB, comG, comR), -1)
alpha = 0.7  # 투명도 설정 (0은 완전 투명, 1은 완전 불투명)
image = cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0)

img = np.zeros((200,400,3),np.uint8)
#b,g,r,a = 0,0,0,0
fontpath = "fonts/batang.ttc"
font = ImageFont.truetype(fontpath, font_size)
img_pil = Image.fromarray(image)
draw = ImageDraw.Draw(img_pil)

for i in range (len(exp_str)):
    ex = (int)((w-center_w[i])/2)-50   
    draw.text((ex,(int)((h/2) + (i - len(exp_str)/2) * font_size)), exp_str[i],font=font,fill=(b,g,r))
    
img = np.array(img_pil)

# 임의의 행렬을 생성
matrix = np.array([...])  # 여기에 실제 행렬을 입력

# 행렬을 이미지로 변환
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
resultImg = Image.fromarray(img)

# 이미지를 base64 문자열로 변환
buffered = BytesIO()
resultImg.save(buffered, format="JPEG")
img_str = base64.b64encode(buffered.getvalue())

print(str(img_str))

cv2.waitKey()
cv2.destroyAllWindows()

텍스트와 이미지를 받아 중앙정렬 후 텍스트를 돋보이기 위한 상자를 배치한다.

정말 가독성이 1도 없는 코드라 바꾸고 싶지만 그럴 시간이 있을까?

위의 프로세스를 수행하면 다음과 같은 그림이 생성된다.

 

 

짜란 정말 아무도 안쓸것같은 이미지 완성!

 

반응형

'ChatGPT > 챗봇프로젝트' 카테고리의 다른 글

[프로젝트] 노인을 위한 스마트챗봇 -1-  (2) 2023.03.21
반응형

프로젝트: 노인을 위한 스마트챗봇

본 문서는 [프로젝트] 노인을 위한 스마트챗봇에 대한 설명서입니다.

프로젝트 개요

노인분들이 스마트폰 등 디지털 기기를 사용하는 데 어려움을 겪는 경우가 많습니다. 이에 따라 노인분들이 쉽게 사용할 수 있는 인터페이스를 제공하고, 일상생활에서 유용한 정보와 서비스를 제공하는 스마트챗봇을 개발하고자 합니다.

프로젝트 목표

  • 노인분들이 쉽게 사용할 수 있는 인터페이스 제공
  • 일상생활에서 유용한 정보와 서비스 제공
  • 사용자 맞춤형 서비스 제공

프로젝트 일정

  • 기획 및 설계: 2022년 1월 ~ 2월
  • 개발: 2022년 3월 ~ 6월
  • 테스트 및 보완: 2022년 7월 ~ 8월
  • 출시 및 유지보수: 2022년 9월 이후

프로젝트 구성원

  • 기획팀: 1명
  • 개발팀: 3명
  • 디자인팀: 1명
  • 마케팅팀: 1명

프로젝트 결과물

  • 노인분들이 쉽게 사용할 수 있는 스마트챗봇
  • 일상생활에서 유용한 정보와 서비스를 제공하는 스마트챗봇

프로젝트 예산

  • 총 예산: 100,000,000원
  • 인건비: 60,000,000원
  • 개발비: 20,000,000원
  • 디자인비: 5,000,000원
  • 마케팅비: 5,000,000원
  • 기타 경비: 10,000,000원

노션 ai 를 써서 알아서 써보라고 하니 이렇게 작성해준다. ㅋㅋㅋㅋ은근 잘써주네.

 

여튼

👉프로젝트: 노인을 위한 스마트챗봇

본 문서는 [프로젝트] 노인을 위한 스마트챗봇에 대한 설명서입니다.

GPT API 를 이용한 챗봇을 개발합니다.

👉프로젝트 개요

노인분들이 스마트폰 등 디지털 기기를 사용하는 데 어려움을 겪는 경우가 많습니다. 이에 따라 노인분들이 쉽게 사용할 수 있는 인터페이스를 제공하고, 일상생활에서 유용한 정보와 서비스를 제공하는 스마트챗봇을 개발하고자 합니다.

👉프로젝트 목표

  • 노인분들이 쉽게 사용할 수 있는 인터페이스 제공
  • 일상생활에서 유용한 정보와 서비스 제공
    • 찾기 쉬운 노인복지
    • 요즘 젊은이들은? 젊은이들과 대화하기
    • 지하철 길찾기 (더이상 주변사람에게 묻지마)
  • 사용자 맞춤형 서비스 제공

👉프로젝트 일정

  • 기획, 설계, 개발, QA : 2022년 3월 ~ 6월
  • 빨리 끝내고싶다.

👉프로젝트 개발환경

  1. React + Express
    • 일단은 웹 프로젝트로 진행할 예정.
    • 시간이 된다면 flutter로 전환예정.
  2. STT : React-speech-recognition
    • google cloud STT 도 있지만 일단 연결이 쉬운 패키지로 선정했다.
    • openai Whisper 도 보았으나 실시간 처리를 지원하지 않아 패스하기로 했다.
  3. Openai GPT3.5
  4. TTS : Google Cloud

진행사항

현재 React 로 테스트 페이지를 제작했으며, 음성인식을 통해 텍스트를 화면에 출력하고, 텍스트를 api 통신 후 response 를 받는데 성공했다. 이 response 를 출력하는데 까지 진행했다.

 

 

나말고도 STT, TTS 를 이용하는 분이 한 분 계시는데 그분은 Google Cloud STT 를 사용하는 것 같다. 시연 테스트를 보니 정확도는 나나 그분이나 비슷한 것 같아서 다행이긴한데 실시간 처리가 정확히 되는 모델을 무료로 찾는건 어려울 것 같다.

 

이제 TTS 도 연결하고 시나리오를 구체화해서 개발을 진행하면 될 것 같다.

 

기존 GPT 3.5 를 이용해 챗봇을 만들기엔 한계가 있기 때문에 open ai 에서 제공하는 fine tuning 을 이용할 예정이다.

위 기능을 이용하려면 데이터가 필요한데 데이터를 어떻게 학습시킬지 모델 구상하기가 조금 귀찮다. ㅋ

반응형

'ChatGPT > 챗봇프로젝트' 카테고리의 다른 글

[프로젝트] 노인을 위한 스마트챗봇 -2-  (0) 2023.06.17

+ Recent posts