카카오톡 챗봇(메신저봇) + 구글 시트 + Gemini 로 자동 CS봇 만들기 테스트입니다. (2부)

배경 및 목적

안녕하세요~ 전승현입니다 🤗

며칠 전에 카카오톡 챗봇(메신저봇)에 구글 시트를 연동해서 그룹채팅방, 오픈채팅방에 자동CS를 해주는 챗봇을 만드는 테스트 글을 작성했습니다. (카카오톡 비지니스 채널은 제외)

이어서 Gemini 도 붙여서 얼마나 답변을 잘해주는지 테스트를 진행한 내용입니다.

참고 자료

솔론봇, 윤자동봇

*테스트 환경 : 와이파이 환경에서 갤럭시탭에 메신저봇(안드로이드앱)을 설치 후 테스트했습니다.

활용 툴

ChatGPT로 가상의 온라인 마케팅 대행회사(서울마케팅)를 만들고, 회사 서비스 내용을 만들어 달라고 요청했습니다.

한국어 스크립트의 스크린샷
한국어 텍스트 편집기의 스크린샷

ChatGPT가 만든 내용을 구글 시트에 넣고 테스트를 진행했습니다.

한국어 단어가 포함된 스프레드시트의 스크린샷

실행 과정

‎​

Cursor에서 대화를 통해 다음과 같은 코드를 만들었습니다.

// CS봇 2024-10-27  1.1.7
// gemini-1.5-flash_api_key 사용
// 구글시트(SHEET_ID, SHEET_API_KEY)-카카오톡(메신저봇) 연동
// 답변에 Markdown 중 ## 와 ** 제거

// 구글 시트 주소 : https://docs.google.com/spreadsheets...
// 구글 시트 공유 : 뷰어로 변경하기 (링크가 있는 인터넷상의 모든 사용자가 볼 수 있음 )
// 호출 : "CS봇", "cs봇", "!질문",  "!"

var SHEET_ID = "SHEET_ID";
var SHEET_API_KEY = "SHEET_API_KEY";
var GEMINI_API_KEY = 'GEMINI_API_KEY';
var GEMINI_ENDPOINT = 'https://generativelanguage.googleapis.com/v1/models/gemini-1.5-flash:generateContent?key=';

function customLog(message) {
    var logMessage = new Date().toLocaleString() + ": " + message;
    Log.i(logMessage);
}

function extractJSON(text) {
    var match = text.match(/\{[\s\S]*\}/);
    return match ? match[0] : null;
}

function getSheetNames() {
    var url = "https://sheets.googleapis.com/v4/spreadsheets/" + SHEET_ID + "?key=" + SHEET_API_KEY;
    try {
        var response = Utils.getWebText(url);
        var jsonStr = extractJSON(response);
        if (!jsonStr) {
            customLog("JSON 데이터를 추출할 수 없습니다.");
            return null;
        }
        var data = JSON.parse(jsonStr);
        return data.sheets.map(function(sheet) {
            return sheet.properties.title;
        });
    } catch (e) {
        customLog("시트 이름 가져오기 에러: " + e.message);
        return null;
    }
}

function getSheetData(sheetName) {
    var url = "https://sheets.googleapis.com/v4/spreadsheets/" + SHEET_ID + "/values/" + 
              encodeURIComponent(sheetName) + "!A1:B1000?key=" + SHEET_API_KEY;
    try {
        var response = Utils.getWebText(url);
        var jsonStr = extractJSON(response);
        if (!jsonStr) {
            customLog("JSON 데이터를 추출할 수 없습니다.");
            return null;
        }
        var data = JSON.parse(jsonStr);
        return data.values;
    } catch (e) {
        customLog(sheetName + " 시트 데이터 가져오기 에러: " + e.message);
        return null;
    }
}

function getAllSheetsData() {
    var sheetNames = getSheetNames();
    if (!sheetNames) {
        return null;
    }
    
    var allData = [];
    sheetNames.forEach(function(sheetName) {
        var sheetData = getSheetData(sheetName);
        if (sheetData) {
            allData = allData.concat(sheetData);
        }
    });
    
    return allData;
}

// Markdown 중 ## 와 ** 제거
function removeSpecificMarkdown(text) {
    return text
        .replace(/^##\s+/gm, '')  // 줄 시작 부분의 ## 제거
        .replace(/\*\*(.*?)\*\*/g, '$1')  // ** 제거
        .replace(/^\s*\*\s/gm, '• ');  // 줄 시작 부분의 * 을 • 로 변경
}

function callGeminiAPI(prompt) {
    var url = GEMINI_ENDPOINT + GEMINI_API_KEY;
    var headers = {
        'Content-Type': 'application/json'
    };
    var data = {
        "contents": [{
            "parts":[{
                "text": prompt
            }]
        }]
    };
    
    try {
        var response = org.jsoup.Jsoup.connect(url)
            .ignoreContentType(true)
            .headers(headers)
            .requestBody(JSON.stringify(data))
            .post();
        
        var jsonResponse = JSON.parse(response.body().text());
        var rawText = jsonResponse.candidates[0].content.parts[0].text;
        
        // 링크 활성화 로직 추가
        rawText = rawText.replace(/(https?:\/\/\S+)/g, '<$1>');
        // ##와 ** 제거
        return removeSpecificMarkdown(rawText);  
    } catch (e) {
        customLog("Gemini API 호출 에러: " + e.message);
        return null;
    }
}

function response(room, msg, sender, isGroupChat, replier, imageDB, packageName) {
    var triggers = ["CS봇", "cs봇", "!질문", "!"];
    var isQuestion = triggers.some(function(trigger) {
        return msg.toLowerCase().startsWith(trigger.toLowerCase());
    });

    if (isQuestion) {
        var question = msg.replace(/^(CS봇\s*|cs봇\s*|!질문\s*|!\s*)/i, "").trim();
        
        if (question === "") {
            replier.reply("질문을 입력해주세요. 예: CS봇 전자책 또는 !질문 강의 다시보기");
            return;
        }
        
        replier.reply("CS봇이 질문을 분석 중입니다. 잠시만 기다려주세요...");
        
        var allSheetsData = getAllSheetsData();
        if (!allSheetsData) {
            replier.reply("죄송합니다. 데이터를 가져오는 데 문제가 발생했습니다.");
            return;
        }
        
        var context = "다음은 FAQ 데이터입니다:\n\n";
        allSheetsData.forEach(function(row) {
            if (row[0] && row[1]) {
                context += "Q: " + row[0] + "\nA: " + row[1] + "\n\n";
            }
        });
        
        var prompt = context + "\n사용자 질문: " + question + 
                     "\n\n위의 FAQ 데이터를 참고하여 사용자의 질문에 친절하고 상세하게 답변해주세요. " +
                     "FAQ에 관련 내용이 없다면 '죄송합니다. 현재 DB에 관련 내용이 없습니다. 더 자세한 정보를 원하시면 스탭에게 문의해 주세요.'라고 답변해주세요. " +
                     "답변은 한국어로 작성해주세요.";
        
        var answer = callGeminiAPI(prompt);
        if (answer) {
            replier.reply("[CS봇의 답변]\n\n" + removeSpecificMarkdown(answer));
        } else {
            replier.reply("죄송합니다. 답변을 생성하는 데 문제가 발생했습니다.");
        }
    }
}

메신저봇에 코드를 설정했습니다.

CSS CSS CSS CSS CSS CSS CSS CSS C

코드는 아래와 같은 흐름으로 동작 합니다.

숫자 목록을 보여주는 컴퓨터 화면의 스크린샷

결과 및 인사이트

서울마케팅(가상의 회사) 카톡방에 고객이 FAQ를 하는 모습입니다.

휴대폰 화면에 한국어 문자 메시지 두 개

고객이 질문을 할때 마다

구글 시트에 있는 내용을 서치해서

최종적으로 Gemini가 답변을 해주는 모습니다.

한국어로 된 문자 메시지의 스크린샷

한국어로 된 문자 메시지의 스크린샷

한국어 메시지 스크린샷

구글 시트에 내용이 없으면 현재 DB에 관련 내용이 없으니

스탭에게 문의하라고 안내를 해줍니다.

(할루시네이션을 하지 않고 있습니다.)

한국어 문자 메시지 스크린샷

[결론]

갤럭시탭(갤럭시폰)에 메신저봇을 설치하고, 구글 시트, 제미나이(Gemini)를 연동하여 CS봇(Customer Service Bot)을 만들어서 테스트해봤습니다. 일반인에게 최대한 진입장벽을 낮춘 환경으로 메신저봇에 코드를 넣고, 구글 시트에 서비스DB를 입력하는 등의 절차를 진행하면 소규모 비지니스, 지식사업자, 오픈채팅, 그룹채팅을 많이 이용하시는 분들에게 빠르고 유연한 고객 응대 솔루션을 제공할 수 있는 방법 같습니다.

[구글 시트 특징]

1. 순차적 데이터 읽기: 상위에 있는 데이터가 우선 처리되어 더 빠르게 응답할 가능성이 큽니다.

2. 데이터 반영 지연: 구글 시트에서 새로운 데이터를 입력한 후 실제로 챗봇에 반영되는 데 약간의 시간이 걸릴 수 있습니다.

3. 기존 데이터의 빠른 응답: 이전부터 존재하던 데이터는 비교적 빠르게 응답할 가능성이 있습니다.

[장점]

1. 구축과 관리의 용이성

  • 구글 시트는 접근성과 사용이 쉬운 데이터베이스 역할을 할 수 있어, 비전문가도 데이터를 쉽게 관리하고 업데이트할 수 있습니다. 실시간으로 데이터를 수정할 수 있어 빠르게 CS 응답을 할 수 있고, 협업 할때도 좋습니다.

2. 빠른 응답과 자동화된 상담 지원

  • 제미나이와 같은 AI 모델을 활용하면 고객의 질문에 대해 자연스럽고 빠른 응답이 가능합니다. 카카오톡 메신저봇과 연결함으로써 24/7 응대가 가능해 고객 만족도를 높일 수 있습니다.

3. 간편한 비용 관리

  • 구글 시트는 기본적으로 무료 서비스이며, AI 모델과의 연동 역시 서버나 데이터베이스 구축 비용을 절감할 수 있습니다. 초기 비용이 낮고 유지 관리가 용이합니다.

[단점]

1. 복잡한 데이터 처리의 한계

  • 구글 시트는 간단한 데이터베이스로는 유용하지만, 정보가 많아지거나 복잡한 데이터 처리가 필요한 경우 성능이 떨어질 수 있습니다. 대규모 데이터를 관리하기에는 구글 시트의 한계가 있습니다.

3. 응답 품질의 제한

  • 제미나이가 일반적인 질문에는 잘 응답할 수 있지만, 복잡한 문의나 특정한 비즈니스 정책에 대한 답변이 필요할 경우 정확도가 떨어질 수 있습니다. 또한, AI 모델 특성상 예측하지 못한 응답이 나올 가능성도 있습니다.

4. 제미나이(Gemini) 모델의 비용

  • AI 모델을 상시 운영할 경우 사용량에 따라 비용이 발생할 수 있습니다. 특히 AI 모델이 많은 고객 요청을 처리해야 하는 환경에서는 비용이 급격히 증가할 수 있습니다.

    (다행히 제미나이는 무료 플랜이 있습니다.)

12
4개의 답글

👉 이 게시글도 읽어보세요