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

배경 및 목적

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

평소에 카카오톡 챗봇에 대해 관심이 많아서

AI와 대화를 통해 카카오톡 봇을 만들고

테스트를 진행하고 있습니다.

온라인 지식사업자, 쇼핑몰 대표님 등

카카오톡 오픈채팅을 많이 사용하시는 대표님들에게

자주 질문하고 답하는 내용들을 안내해주는

챗봇이 있으면 좋겠다는 생각으로

구글시트와 연동해서 간단한 CS를

할 수 있는 봇을 테스트 하고 있습니다.

(카카오톡 비지니스 채널은 제외)

참고 자료

윤자동봇 참고했습니다.

활용 툴

클로드, ChatGPT와 대화하면서 만들고 있습니다.

실행 과정

  1. 카카오톡 (커스텀) 챗봇 만들기

갤럭시탭+메신저봇으로 셋팅.

  1. 구글 시트 생성

  2. 카카오톡 + 구글 시트 연동


// CS봇
// 구글시트(SHEET_ID, SHEET_API_KEY)-카카오톡(메신저봇) 연동 

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

var SHEET_ID = "SHEET_ID";
var SHEET_API_KEY = "SHEET_API_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 searchGoogleSheet(keywords) {
    customLog("구글 시트 검색 시작: 키워드 = " + keywords.join(", "));
    var sheetNames = getSheetNames();
    if (!sheetNames) {
        return null;
    }
    
    var allResults = [];
    
    sheetNames.forEach(function(sheetName) {
        var url = "https://sheets.googleapis.com/v4/spreadsheets/" + SHEET_ID + "/values/" + encodeURIComponent(sheetName) + "!A1:B1002?key=" + SHEET_API_KEY;
        customLog("요청 URL: " + url);
        try {
            var response = Utils.getWebText(url);
            var jsonStr = extractJSON(response);
            if (!jsonStr) {
                customLog(sheetName + " 시트에서 JSON 데이터를 추출할 수 없습니다.");
                return;
            }
            
            var data = JSON.parse(jsonStr);
            
            if (data.error) {
                customLog(sheetName + " 시트 API 에러: " + JSON.stringify(data.error));
                return;
            }
            
            if (data.values && data.values.length > 1) {
                customLog(sheetName + " 시트 데이터 행 수: " + data.values.length);
                for (var i = 1; i < data.values.length; i++) {
                    if (data.values[i][0]) {
                        var sheetQuestion = data.values[i][0].toLowerCase().replace(/\s+/g, '');
                        var found = keywords.some(function(keyword) {
                            return sheetQuestion.includes(keyword.toLowerCase().replace(/\s+/g, ''));
                        });
                        if (found) {
                            customLog(sheetName + " 시트에서 일치하는 항목 찾음: " + data.values[i][0]);
                            allResults.push({
                                sheet: sheetName,
                                question: data.values[i][0],
                                answer: data.values[i][1] || "답변이 없습니다."
                            });
                        }
                    }
                }
            } else {
                customLog(sheetName + " 시트 데이터가 비어있거나 없음");
            }
        } catch (e) {
            customLog(sheetName + " 시트 검색 에러: " + e.message);
        }
    });
    
    // 결과를 문자열로 변환
    var resultText = "";
    if (allResults.length > 0) {
        allResults.forEach(function(item, index) {
            resultText += (index + 1) + ". " + item.question + "\n";
            resultText += "   " + item.answer + "\n\n";
        });
    }
    
    return resultText || null;
}

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());
        return jsonResponse.candidates[0].content.parts[0].text;
    } catch (e) {
        customLog("Gemini API 호출 에러: " + e.message);
        return null;
    }
}

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

    if (isQuestion) {
        var question = msg.replace(/^(!질문|CS봇|cs봇|!)/i, "").trim();
        if (question) {
            // 즉시 준비 중 메시지 전송
            replier.reply("[CS봇이 답변을 준비중입니다~ 🤖]");
            
            var questionParts = question.split(",").map(part => part.trim());
            customLog("사용자 질문: " + questionParts.join(", "));
            var sheetData = searchGoogleSheet(questionParts);
            
            if (sheetData) {
                var reply = "[CS봇 답변! 🤖]\n" + sheetData.trim();
                replier.reply(reply);
            } else {
                replier.reply("[CS봇 답변! 🤖]\n죄송합니다. DB에서 관련 정보를 찾지 못했습니다. 스탭에게 문의하세요");
            }
        } else {
            replier.reply("[CS봇 답변! 🤖]\n질문을 입력해주세요. 예: !질문 카페, CS봇 카페, !카페");
        }
    } else if (msg === "!디버그") {
        var sheetNames = getSheetNames();
        if (sheetNames) {
            var debugInfo = "시트 목록:\n" + sheetNames.join(", ");
            replier.reply(debugInfo);
        } else {
            replier.reply("시트 정보를 가져오는 데 실패했습니다.");
        }
    }
}

결과 및 인사이트

[구글 시트]

한국어 구글 문서

"서울마켓(가상의 회사)"이라는 회사가 있다는 가정하고

구글 시트에 판매하는 제품리스트와 구매링크를 기입했습니다.

고객이 궁금한 것들을 문의 했을 때

대답해주는 형식으로 테스트를 하고 있습니다.

[챗봇과 대화 예시]

"서울마켓(가상의 회사) 오픈채팅방"에 고객이 들어와서

궁금한 것들을 묻고 답한다는 시나리오입니다.

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

챗봇이 고객의 질문에 대한 답변을 하고

구매링크를 제공해 줍니다.

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

고양이 사진이 담긴 한국어 문자 메시지

  1. 구글 시트 사용

장점: 익숙함, 사용 편의성, 무료, 실시간 협업 가능

단점: AI 기능 제한적, 복잡한 데이터 처리에 한계

  1. AI 도입

장점: 데이터 분석 향상, 자동화 가능, 예측 분석

단점: 초기 비용, 학습 곡선, 데이터 보안 우려

  1. 다른 툴 사용

장점: 특정 니즈에 맞는 기능 제공 가능

단점: 새로운 시스템 적응 필요, 추가 비용 발생 가능

이렇게 테스트 중입니다~

3
3개의 답글

👉 이 게시글도 읽어보세요