Ssul's Blog
[ChatGPT, DALLE2] 인공지능 카카오챗봇 만들기 본문
0. 챗봇을 쉽게 만들수 있는 세상
- 그동안은 NLP연구와 알고리즘을 통해서, 챗봇이 동작하였다.
- 하지만, GPT가 나오면서, 그동안 챗봇기술은 모두 비슷한 출발 선상에 서게 되었음
- 정말로 비슷한 출발 선상에 서게 되었을까? 그렇다면 나만의 상담챗봇, 그림그려주는 챗봇을 제작해보자!
- 카카오챗봇 + openai + lambda(aws서버)를 통해서 24시간 동작하는 챗봇 만들기
1. 카카오채널 셋팅
- business.kakao.com 방문
- 오른쪽 상단 내 비즈니스 클릭
- 왼쪽 상단 채널 클릭
- 새 채널 만들기 클릭
- 작성해서 확인 클릭(채널 생성 완료)
- 생성한 채널로 들어가서
- 오른쪽 하단에 채널공개, 검색허용 on으로 셋팅
- 왼쪽상단 채널 클릭 -> 서랍형태로 챗봇나오면 클릭
- 봇만들기 클릭
- 카카오톡 챗봇 클릭
- 챗봇 생성
- 카카오 챗봇 생성완료 화면
2. 기능 구현
import json
import openai
import threading
import time
import queue as q
import os
# OpenAI API KEY
openai.api_key = os.environ['OPENAI_API']
- 필요한 라이브러리 가져오고,
- OPENAI 키 가져오기
def getTextFromGPT(prompt):
messages_prompt = [{"role": "system", "content": 'You are a thoughtful assistant. Respond to all input in 25 words and answer in korea'}]
messages_prompt += [{"role": "user", "content": prompt}]
response = openai.ChatCompletion.create(model="gpt-3.5-turbo", messages=messages_prompt)
message = response["choices"][0]["message"]["content"]
return message
# DALLE.2에게 질문/그림 URL 받기
def getImageURLFromDALLE(prompt):
response = openai.Image.create(prompt=prompt,n=1,size="512x512")
image_url = response['data'][0]['url']
return image_url
- 프롬프트를 받아서, Chatgpt가 응답해주는 함수
- 프롬프트를 받아서 Dalle2가 그림그려주는 함수
# 카카오채널에 gpt의 메세지 전송
def textResponseFormat(bot_response):
response = {'version': '2.0', 'template': {
'outputs': [{'simpleText': {'text': bot_response}}], 'quickReplies': []}}
return response
# 카카오채널에 dalle 이미지 전송
def imageResponseFormat(bot_response, prompt):
output_text = prompt + "내용에 관한 이미지 입니다"
response = {'version': '2.0', 'template': {
'outputs': [{'simpleImage': {'imageUrl': bot_response, 'altText': output_text}}], 'quickReplies': []}}
return response
- 챗봇에 gpt가 응답한 답을 카카오챗봇 형식에 맞게 변화해서 응답
- 챗봇이 그린 그림을 카카오챗봇 형식에 맞게 변화해서 응답
# 응답시간 초과시 먼저 답변
def timeover():
response = {'version': '2.0', 'template': {
'outputs': [
{
'simpleText': {
'text': "아직 제가 생각이 끝나지 않았어요\n잠시 후 아래 말풍선을 눌러주세요"
}
}
], 'quickReplies': [
# 생각이 다 끝남? 버튼생성
{
'action': 'message',
'label': '생각이 다 끝남?',
'messageText': '생각이 다 끝남?'
}
]
}}
return response
- 카카오 챗봇의 경우 5초간 응답이 없으면 에러가 발생
- 하지만, 달리나 gpt의 응답같은경우 5초가 넘는 경우가 많음
- 이를 해결하는 방법이 필요.
- 5초 이내에 대답을 못할때, 채널 챗봇에 버튼을 생성하는 함수
# 메인 함수
def lambda_handler(event, context):
run_flag = False
start_time = time.time()
# 카카오 정보 저장
kakaorequest = json.loads(event['body'])
# 응답 결과를 저장하기 위한 텍스트 파일 생성
filename ="/tmp/botlog.txt"
if not os.path.exists(filename):
with open(filename, "w") as f:
f.write("")
else:
print("File Exists")
# 답변 생성 함수 실행
# 큐 생성(퍼스트 인, 퍼스트 아웃)
response_queue = q.Queue()
request_respond = threading.Thread(target=responseOpenAI, args=(kakaorequest, response_queue, filename))
# responseOpenAI 함수를 비동기적으로 만들어서, 실행. 결과 기다리지 않고 다음줄 실행
request_respond.start()
# 응답이 3.5초 이내에 오면
while(time.time() - start_time < 3.5):
# 답변이 있으면,
if not response_queue.empty():
response = response_queue.get()
run_flag = True
break
# 안정적인 구동을 위한 딜레이 타임 설정
time.sleep(0.01)
# 응답이 3.5초 이내에 오지 않으면
if run_flag == False:
# 생각 끝남버튼 출력함수 호출
response = timeover()
return{
'statusCode':200,
'body': json.dumps(response),
'headers': {
'Access-Control-Allow-Origin': '*',
}
}
# 답변/사진 요청 및 응답 확인 함수
def responseOpenAI(request,response_queue,filename):
# 사용자다 버튼을 클릭하여 답변 완성 여부를 다시 봤을 시
if '생각 다 끝났나요?' in request["userRequest"]["utterance"]:
# 텍스트 파일 열기
with open(filename) as f:
last_update = f.read()
# 텍스트 파일 내 저장된 정보가 있을 경우
if len(last_update.split())>1:
kind = last_update.split()[0]
if kind == "img":
bot_res, prompt = last_update.split()[1],last_update.split()[2]
response_queue.put(imageResponseFormat(bot_res,prompt))
else:
bot_res = last_update[4:]
response_queue.put(textResponseFormat(bot_res))
dbReset(filename)
# 이미지 생성을 요청한 경우
elif '/img' in request["userRequest"]["utterance"]:
dbReset(filename)
prompt = request["userRequest"]["utterance"].replace("/img", "")
bot_res = getImageURLFromDALLE(prompt)
response_queue.put(imageResponseFormat(bot_res,prompt))
save_log = "img"+ " " + str(bot_res) + " " + str(prompt)
with open(filename, 'w') as f:
f.write(save_log)
# ChatGPT 답변을 요청한 경우
elif '/ask' in request["userRequest"]["utterance"]:
dbReset(filename)
prompt = request["userRequest"]["utterance"].replace("/ask", "")
bot_res = getTextFromGPT(prompt)
response_queue.put(textResponseFormat(bot_res))
save_log = "ask"+ " " + str(bot_res)
with open(filename, 'w') as f:
f.write(save_log)
#아무 답변 요청이 없는 채팅일 경우
else:
# 기본 response 값
base_response = {'version': '2.0', 'template': {'outputs': [], 'quickReplies': []}}
response_queue.put(base_response)
- 사람의 채팅이 발생하면, lambda_handler호출
- 질문과 응답(또는 이미지)을 담아둘 파일 생성
- Python의 큐(Queue)와 스레딩(threading) 모듈을 사용하여 비동기적으로 작업을 처리
response_queue = q.Queue()
request_respond = threading.Thread(target=responseOpenAI, args=(kakaorequest, response_queue,filename))
request_respond.start()
- q를 생성, responseOpenAI함수를 비동기로 호출. 호출을 마치지 않았어도 아래 코드로 이동
- 답변이 3.5초 이내에 돌아 왔으면, q에 저장된 응답을 꺼내어서 응답한다
- 답변이 3.5초 이내에 안오면, timeover()를 통해서 "생각이 다 끝남?"버튼 출력
- responseOpenAI는 파일과 q를 받아서
- "생각이 다 끝남?"버튼 클릭이면, 파일에 저장된 응답 결과를 응답해준다
이미지의 경우: img + 이미지주소 + 사용자요청채팅 구조
ChatGPT응답의 경우: ask + 응답 구조
- 문서에 저장된 결과를 카카오챗봇 채팅 구조로 응답해준다
- 이미지 요청('/img')이면,
- getImageURLFromDALLE함수를 호출하여, 그림을 받고, 받은 그림 결과는 q에 넣어준다
- 파일에 저장한다
- gpt물음 ('/ask')이면,
- getTextFromGPT함수를 호출하여, Chatgpt에게 응답을 받고, 받은 응답을 q에 넣어준다
- 파일에 저장한다
- "생각이 다 끝남?" 버튼이 클릭되면, 위에서 저장된 파일의 결과를 채팅으로 돌려주고,
- 해당 내용이 사용되었으니, dbReset(filename)으로 파일을 비운다
def dbReset(filename):
with open(filename, 'w') as f:
f.write("")
3. AWS lambda + api gateway 셋팅(24시간 응답 서버 구성)
- lambda 셋팅 전, 카카오 챗봇이 작동되는 구조
(1) 사용자가 카카오톡 방에 질문 '/ask 상담가능?' 입력
(2) 카카오api서버가 json형태의 메세지 발송(위에서 챗봇 설정에서 </>스킬 메뉴에서 어디로 보낼지 설정해줌)
여기를 나의 aws api gateway-lambda로 설정해주면 됨
(3) api gateway - lambda로 들어온 메세지를 코드의 "lambda_handler"가 호출
(4) 코드에 있는 내용을 기반으로 gpt 또는 dalle2를 호출
(5) gpt, dalle2가 보내온 응답을, 카카오챗봇 json구조로 바꿔서, response
(6) 해당 response내용을 채팅방에 챗봇이 출력(이미지 출력 또는 gpt응답 출력)
- aws lambda로 들어가서, 함수 생성 클릭
- 함수이름, 런타임, 아키텍처 설정 후 함수 생성
- 함수 코드 작성
- 배포 Deploy 클릭
- 구성>환경변수>편집 들어가서
- OPENAI키 셋팅
- lambda에 파이썬 패키지 설치가 필요
- pip install openai를 할수 없으니...
- 내 로컬 venv폴더로 이동: cd venv/lib/python3.10/site-packages/
- 해당 위치에 있는 모든 파일/폴더 zip으로 압축(m1등 실리콘은 추가 조치가 필요함)
- lambda>계층>계층생성 들어가서 zip파일 업로드(나의 venv내용으로 lambda구성하는 개념)
- 생성된 lambda 밑에 layers 클릭
- add a layer 클릭
- 방금 생성한 계층을 선택해서 추가해주기
- lambda기본 제한시간 3초에서 1분으로 변경하기
- 구성>일반구성>편집 눌러서 제한시간 1분으로 변경
- lambda가 완성이 되었으니,
- 카카오톡에서 보내온 채팅메세지를 받아서 lambda에게 전달할 api gateway설정하자
- aws api gateway 클릭>HTTP API 구축 클릭
- 통합추가 클릭>Lambda선택>내가 만든 Lambda선택> 다음 클릭
- POST로 바꾸고, 다음
- 그다음 그대로 다음 클릭
- 생성도 그대로 다음
- API Gateway생성 완료
- 다시 Lambda로 돌아오면
- Gateway가 잘 연결된 것을 확인할 수 있다
- API Gateway 클릭
- 카카오톡 채팅방이 사용자의 입력을 보낼 api gateway 주소를 확인할 수 있다.
- 해당 주소를 복사한다
4. 카카오 챗봇에 24시간 응답해주는 lambda서비스 연결해주기
- 사용자입력>카카오api>aws api gateway>lambda>openai(gpt,dalle)로 사용자의 입력이 전달
- gpt/dalle응답>lambda가 카카오 챗봇데이터 구조로 리턴> api gateway가 카카오api에게 전달 > 채팅방에 이미지 또는 응답 보이기
- api gateway를 카카오챗봇 api와 연결한다.
- URL에 위에서 생성하고, 복사해 놓은 AWS API Gateway 주소를 넣어준다
그러면 AI 챗봇이 완성된다
(lambda 코드: 도서 "진짜 챗GPT API 활용법" ch04 코드 참고)
'dev > 기능구현' 카테고리의 다른 글
IOS 앱개발 String Catalog로 한국어, 영어 (다국어)동시설정(swiftui) (0) | 2025.04.02 |
---|---|
ios push알림 기능 설정 (0) | 2025.02.25 |
[Django, tailwind] AI가 상담글에 자동으로 댓글 달아주기 #2 (react, tailwind) (1) | 2024.01.24 |
[Django, tailwind] AI가 상담글에 자동으로 댓글 달아주기 #1(signal, threading사용) (0) | 2024.01.18 |
Youtube 영상 정보/자막 정보 추출방법 (2) | 2024.01.12 |