2주차) 말투 바꾸는 카카오 챗봇 만드는 여행기

소개

이번에 저는 카카오 챗봇을 직접 만들어보는 도전을 해보았습니다. 단순한 QnA 챗봇이 아니라, 사용자의 말투를 바꿔주는 기능을 넣어보고 싶었어요. 예전부터 뽀야봇이나 스터디장 가이드처럼 ChatGPT를 활용한 챗봇 사례들을 보며 "나도 한번 만들어볼까?" 하는 생각이 있었거든요.

말투 바꾸기는 단순하지만 개인화 요소가 강해서, 사용자에게 재미도 줄 수 있고 응용 범위도 넓다고 느꼈습니다. 그래서 이번 프로젝트의 핵심 기능으로 잡았죠.

진행 방법

사용한 도구들

  • ChatGPT: 말투 변환 프롬프트 생성과 테스트

  • 카카오 i 오픈빌더: 챗봇 빌드 및 배포

  • 퍼플렉시티 API: 외부 텍스트 분석 기능을 붙이려 했지만 실패 💥

  • SerpAPI: 외부 검색 연동에 성공 🎯

  • DigitalOcean 서버 (main.py): 챗봇 백엔드 서버로 사용

시도한 내용

  • 먼저 ChatGPT를 통해 말투 바꾸기 프롬프트를 뽀야봇으로 동작확인후 약간의 변형으로 여러 버전으로 실험해봤습니다.

    너는 5살 여자아이 목소리로 말하는 귀엽고 혀짧은 AI 메신저봇 '알고'야. 메시지를 보낸 사람의 이름도 꼭 불러주고, 상대가 남성이면 '오빠', 여성이면 '언니'라고 부르면서 아래 혀짧은 발음을 반영해서 항상 아이처럼 짧고 귀엽게 말해
  • 한국 문자 메시지의 스크린 샷
  • 위에 버전은 귀여운아기버전이라 답변은 거의 애기처럼만 나왔습니다. 그래서 부동산아줌마 말투와 내용이 나오도록 변경해 넣어보았습니다.

    부동산중개사 아줌마로 약간의 수다와 상대방을 현혹하고 꼬시는 경험이 많은 전문가수준으로 답변을 해주면 좋겠어. 부를떄는 상대방이름에 옵빠, 이모 호칭을 넣어서 불러줘.
    그리고 다음호출에 반응하게 해. "/알고"
  • 중국어로 문자 메시지의 스크린 샷
  • 아래는 말투 변환 챗봇의 내부 처리 흐름 예시입니다:

var bot = BotManager.getCurrentBot();

var API_KEY = "API키를 넣어주세요";
var ENDPOINT = "https://api.openai.com/v1/chat/completions";

bot.on("message", function(msg) {
    try {
        var userText = msg.content;
        var userName = msg.author.name || "고객님";
        if (userText.indexOf("/알고") !== 0) return;

        var realText = userText.replace("/알고", "").trim();

        var prompt = "다음 사용자 메시지를 부동산 중개사 아줌마 스타일로 응답해줘...";

        setTimeout(function() {
            var replyText = requestToGPT(prompt);
            msg.reply(replyText || "어머머~ 다시 한 번 정확히 말해봐요, " + userName + "님~ 😊");
        }, 0);
    } catch (e) {
        msg.reply("에고~ 알고가 잠깐 정신 놓았네요~ 다시 한 번 말씀해보실래요? 😉");
    }
});

function requestToGPT(prompt) {
    try {
        var conn = org.jsoup.Jsoup.connect(ENDPOINT)
            .ignoreContentType(true)
            .header("Authorization", "Bearer " + API_KEY)
            .header("Content-Type", "application/json")
            .requestBody(JSON.stringify({
                model: "gpt-4o",
                messages: [
                    { role: "system", content: "너는 부동산 중개사 아줌마 스타일의 AI 챗봇 '알고'야..." },
                    { role: "user", content: prompt }
                ],
                temperature: 0.8
            }))
            .post();

        var rawResponse = conn.text();
        var json = JSON.parse(rawResponse);
        return (json.choices && json.choices[0]) ? json.choices[0].message.content : null;
    } catch (err) {
        return "어머~ 지금은 잠깐 바빠서 못 들었쪄~ 나중에 다시 불러주세용~ 🏡";
    }
}
  • 또한 SerpAPI를 DigitalOcean 서버에 연결하고, main.py에서 요청을 받아 검색 결과를 처리하는 데 성공했습니다! 🎉 이로써 실시간 검색 결과 기반의 응답도 가능해졌어요.

// serpAPIbot.js - SerpAPI를 통한 뉴스 검색
var bot = BotManager.getCurrentBot();

bot.on("message", function(msg) {
    var content = msg.content.trim();
    var keyword = "";
    var isDefaultKeyword = false;

    // 명령어 형식 분석
    if (content === "뉴스") {
        // 단순히 "뉴스"만 입력한 경우
        keyword = "최신";
        isDefaultKeyword = true;
    } else if (content.indexOf("뉴스 ") === 0) {
        // "뉴스 부동산" 형식
        keyword = content.substring(3).trim();
    } else if (content.endsWith(" 뉴스")) {
        // "부동산 뉴스" 형식
        keyword = content.substring(0, content.length - 3).trim();
    } else if (content.indexOf("뉴스") > 0) {
        // "부동산뉴스" 또는 다른 형식
        var parts = content.split("뉴스");
        keyword = parts[0].trim();
    } else {
        // 뉴스 명령어가 아님
        return;
    }

    // 키워드가 비어있는 경우 기본값으로 설정
    if (!keyword) {
        keyword = "최신";
        isDefaultKeyword = true;
    }

    // 먼저 처리 중임을 알림
    msg.reply("🔍 뉴스를 검색 중이니 기다려주세요");

    try {
        var serverUrl = "http://152.42.175.80:8000";  // 서버 주소 확인!
        var url = serverUrl + "/news?keyword=" + encodeURIComponent(keyword);

        var response = org.jsoup.Jsoup.connect(url)
            .ignoreContentType(true)
            .timeout(60000)  // 타임아웃을 60초로 설정
            .get().text();

        var data = JSON.parse(response);
        if (data.error) {
            msg.reply("⚠️ 뉴스를 가져오는 중 오류가 발생했습니다: " + data.error);
            return;
        }

        // 제목 표시 개선 - "최신" 키워드일 때 특별 처리
        var title = isDefaultKeyword ?
            "✨ 오늘의 최신 뉴스 ✨" :
            "✨ " + keyword + " 관련 뉴스 ✨";

        var result = title + "\n\n";

        for (var i = 0; i < data.news.length; i++) {
            var item = data.news[i];
            result += (i+1) + ". " + item.title;
            result += "(" + item.source + " | " + item.time + ")" + "\n";
            result += "👉" + item.summary + "\n";
            result += item.link + "\n\n";  // 링크 추가
        }

        msg.reply(result);
    } catch (e) {
        msg.reply("⚠️ 서버 연결 중 오류가 발생했습니다: " + e.message);
    }
});
  • 한국어 문자 메시지의 스크린 샷

  • url을 넣으면 요약하는 것도 만들어 보았습니다.

    // 메신저R에서 URL이 포함된 메시지를 요약하는 GPT 직접 요약 기반 봇
    var bot = BotManager.getCurrentBot();
    
    bot.on("message", function(msg) {
        var content = msg.content.trim();
    
        // URL 추출 (http 또는 https로 시작하는 링크 감지)
        var urlRegex = /(https?:\/\/[\w\-._~:/?#[\]@!$&'()*+,;=%.]+)/g;
        var urls = content.match(urlRegex);
    
        if (!urls || urls.length === 0) {
            return; // URL이 없는 메시지는 무시
        }
    
        var targetUrl = urls[0]; // 첫 번째 URL만 사용
        msg.reply("📄 링크 내용을 예쁘게 요약 중이에요! 잠시만 기다려쭈~");
    
        try {
            // 1차: Jsoup으로 원문 페이지 HTML을 파싱해 텍스트 추출
            var rawText = org.jsoup.Jsoup.connect(targetUrl)
                .ignoreContentType(true)
                .get()
                .text();
    
            // 2차 정제: OpenAI GPT를 사용해 뉴스 요약 템플릿 적용
            var openaiKey = "API키입력";
            var openaiEndpoint = "https://api.openai.com/v1/chat/completions";
    
            var refinedPrompt = `다음 뉴스 본문을 독자 친화적인 뉴스 브리핑 형식으로 요약해주세요. 아래 형식을 지켜주세요:
    
    [🗞️ 제목 요약]
    한 문장으로 핵심 이슈를 압축
    
    [📌 요약 포인트]
    1. 핵심 사실 1
    2. 핵심 사실 2
    3. 핵심 의미 및 독자에게 중요한 시사점
    
    [🔗 관련 링크]
    기사 원문 링크 포함
    
    ### 기사 본문 ###
    ${rawText}
    
    기사 링크: ${targetUrl}`;
    
            var conn = org.jsoup.Jsoup.connect(openaiEndpoint)
                .ignoreContentType(true)
                .header("Authorization", "Bearer " + openaiKey)
                .header("Content-Type", "application/json")
                .requestBody(JSON.stringify({
                    model: "gpt-4o",
                    messages: [
                        { role: "system", content: "당신은 뉴스 편집자입니다. 뉴스 전체 본문을 읽고, 포맷에 맞게 요약합니다." },
                        { role: "user", content: refinedPrompt }
                    ],
                    temperature: 0.7
                }))
                .post();
    
            var gptResponse = JSON.parse(conn.text());
            var finalSummary = gptResponse.choices[0].message.content;
    
            msg.reply(finalSummary);
        } catch (e) {
            msg.reply("⚠️ 요약 중 오류가 발생했쪄: " + e.message);
        }
    });
    
    한국의 메시지 스크린 샷
  • 마지막으로 현우님이 제공한 퍼플렉시티 API에 위의 말투 감정 분석 등을 넣고 싶어서 연결을 시도했는데, 컴파일 응답 오류로 끝내 연결하지 못했습니다. (이 부분에서 시간을 제일 많이 썼어요 😵)

참고한 자료

  • ChatGPT 커뮤니티 사례 글

  • 뽀야봇 제작 후기

  • 스터디장 가이드 예시 흐름도

결과와 배운 점

  • 성공한 점:

    • 말투 바꾸기는 아주 잘 작동했습니다! ChatGPT의 문체 스타일링 능력은 정말 대단하네요.

    • SerpAPI를 이용한 실시간 검색 기능 연동도 성공! 백엔드와의 연결 테스트도 완료했습니다.

  • 실패한 점: 퍼플렉시티 API 연결은 컴파일에러가 나서 실패, 예상 밖의 장벽들이 있었습니다.

  • 배운 점:

    • 될 듯 말 듯한 상황이 계속되며 멘탈 관리도 중요하다 😅

    • ChatGPT는 사람처럼 친근하게 말투를 바꿔주는 데 아주 효과적이라는 것!

    • DigitalOcean 서버에서 Python 기반 연동을 하면 확장성이 매우 크다는 것도 깨달음

그리고, 무엇보다도… 시간 정말 잘 갑니다. 디버깅 몇 번 하다 보면 밤이 되더라고요. (공감하시는 분...? 🥲)

도움 받은 글

  • 뽀야봇 만들기 후기 사례

  • 스터디장 가이드 흐름 예시

  • ChatGPT 커뮤니티 API 연동 팁 모음

2
1개의 답글

👉 이 게시글도 읽어보세요