고객 문의 자동 응답 시스템 구축: Google과 ChatGPT 활용

회사 홈페이지 고객 질문 처리 프로세스 구축 목표: 고객이 홈페이지에 질문을 남기면, 다음 두 가지 자동화된 결과를 이메일로 발송하도록 설정한다. 1. 회사 소개 PDF 파일 자동 발송 - 고객이 질문을 제출하면 회사 소개를 담고 있는 PDF 파일이 고객의 이메일로 자동으로 전송된다. 2. 질문에 대한 답변 자동 생성 및 전송 - 고객의 질문에 대한 답변은 챗GPT를 활용하여 작성하며, 작성된 답변은 고객의 이메일로 자동으로 발송된다. 기술 스택: - Google Forms: 고객 질문 수집 폼 작성 및 배포 - Google Sheets: 고객의 질문 및 정보를 저장할 스프레드 시트 생성 - Google Drive: 회사 소개 PDF 파일 저장 및 링크 공유 - Google Apps Script: 자동화 프로세스를 처리할 수 있는 스크립트 작성 작업 단계: 1. Google Form을 통해 고객의 질문을 수집하고, 질문 제출 시 Google Sheets에 자동으로 저장되도록 설정. 2. Google Sheets에서 질문을 감지하여 Google Apps Script를 활용해 챗GPT API 호출, 고객 질문에 대한 답변 생성. 3. 생성된 답변과 회사 소개 PDF 파일 링크를 고객의 이메일로 전송하는 이메일 발송 스크립트 작성. 4. 전체 프로세스의 오류 및 예외 처리를 설정하여 안정적인 자동화 보장. 이 과정을 위한 프레임워크를 설계해 줄 수 있는지 확인 부탁드립니다.

개요

디지털 시대에서 고객 문의에 대한 신속하고 효율적인 대응은 기업 경쟁력의 핵심 요소입니다.

본 프로젝트에서는 Google Forms, Google Sheets, Gmail, Google Drive, 그리고 OpenAI ChatGPT API를 활용하여 고객 문의에 자동으로 응답하는 시스템을 구축하였습니다.

이 시스템은 웹사이트뿐만 아니라 블로그, SNS(인스타그램, 페이스북, 트위터 등) 등 다양한 플랫폼에서도 적용할 수 있어 확장성이 뛰어납니다.

또한, 문의 고객의 이메일 및 휴대전화번호를 합법적으로 수집할 수 있어 향후 마케팅 활동 및 고객 관리에 효과적으로 활용할 수 있습니다. 이를 통해 고객과의 접점을 확대하고, 맞춤형 프로모션 및 소식 전달이 가능해집니다.

한국어 단어가있는 녹색 화면

시스템 구성 및 작동 원리

1️⃣ 시스템 흐름

  1. Google Forms를 통해 고객이 이름, 이메일, 문의 내용을 입력

  2. Google Sheets에 응답이 자동 저장

  3. Apps Script가 새로운 응답을 감지하고 OpenAI ChatGPT API를 호출하여 답변 생성

  4. Gmail을 통해 자동으로 답변 이메일 전송 (회사 소개 PDF 첨부)

  5. 향후 확장: 문자(SMS) 및 카카오톡 메시지 전송 기능 추가 예정

  6. SNS 및 블로그 활용: 다양한 플랫폼에서 문의 링크 버튼을 제공하여 고객 접근성 확대

새 이메일 생성 과정을 보여주는 다이어그램

2️⃣ 기대 효과

즉각적인 응답 - 24시간 자동 응답으로 고객 만족도 향상

업무 자동화 - 반복적인 문의 응대를 자동화하여 인력 운영 최적화

브랜드 신뢰도 강화 - 일관된 응답 제공으로 기업 이미지 향상

멀티 채널 지원 - 웹사이트뿐만 아니라 블로그, SNS에서도 문의 접수 가능

마케팅 기회 확대 - 문의 고객의 정보를 수집하여 향후 맞춤형 프로모션 진행 가능

구현 코드

📌 Google Apps Script를 활용한 자동 응답 시스템

function processNewFormResponses() {
  const SPREADSHEET_ID = '1b2CoGKbqvi9tj0cmRR3PPiohMM4yQtNipq_-B7g_0sM';
  const SHEET_NAME = 'sheet4';
  const STATUS_COLUMN_INDEX = 7;
  const STATUS_COMPLETE = "완료";
  
  const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = ss.getSheetByName(SHEET_NAME);
  if (!sheet) return;
  
  const lastRow = sheet.getLastRow();
  if (lastRow <= 1) return;
  
  const dataRange = sheet.getRange(2, 1, lastRow - 1, STATUS_COLUMN_INDEX);
  const responses = dataRange.getValues();
  
  for (let i = 0; i < responses.length; i++) {
    const currentRow = i + 2;
    const email = responses[i][2];
    const phoneNumber = responses[i][3];
    const inquiry = responses[i][5];
    
    if (responses[i][STATUS_COLUMN_INDEX - 1] === STATUS_COMPLETE) continue;
    
    const chatGPTResponse = generateChatGPTResponse(inquiry);
    if (!chatGPTResponse) continue;
    
    const pdfAttachment = getCompanyPdfAttachment();
    sendCustomerEmail(email, "문의 답변 및 회사 소개", chatGPTResponse, pdfAttachment);
    
    sendSMSNotification(phoneNumber, chatGPTResponse);
    sendKakaoNotification(phoneNumber, chatGPTResponse);
    
    sheet.getRange(currentRow, STATUS_COLUMN_INDEX).setValue(STATUS_COMPLETE);
  }
}

  • 메인함수

/**
 * Google Forms의 새로운 응답을 처리하는 메인 함수
 * - 트리거 설정: Forms 제출 시 또는 시간 기반 트리거로 실행
 */
function processNewFormResponses() {
  // 스프레드시트 ID를 상수로 지정 (실제 스프레드시트 ID로 변경)
  const SPREADSHEET_ID = '1nAdWTuJvIJV4eSa_WfDSnLEo_7eYw2rUHxaccurDjTw';
  
  // 시트 및 열 관련 상수 정의
  const SHEET_NAME = 'sheet4';
  const STATUS_HEADER = "처리상태";
  const STATUS_COLUMN_INDEX = 7; // G열
  
  // 처리 상태 상수
  const STATUS_COMPLETE = "완료";
  const STATUS_EMAIL_ERROR = "이메일 오류";
  const STATUS_ERROR = "오류";
  
  // 응답 데이터 열 인덱스 (0부터 시작하는 배열 인덱스)
  const COL_TIMESTAMP = 0; // A열
  const COL_NAME      = 1; // B열
  const COL_EMAIL     = 2; // C열
  const COL_PHONE     = 3; // D열
  const COL_NEEDS_PDF = 4; // E열
  const COL_INQUIRY   = 5; // F열

  try {
    // 트리거 실행 시 활성 스프레드시트가 없으므로, 스프레드시트 ID를 통해 직접 엽니다.
    const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
    const sheet = ss.getSheetByName(SHEET_NAME);
    if (!sheet) {
      Logger.log(`시트 '${SHEET_NAME}'를 찾을 수 없습니다.`);
      return;
    }
    
    // 데이터가 있는 마지막 행 가져오기
    const lastRow = sheet.getLastRow();
    if (lastRow <= 1) {
      Logger.log("처리할 응답이 없습니다.");
      return; // 헤더만 있는 경우 종료
    }
    
    // 상태 열 헤더 확인 및 설정
    const headerRange = sheet.getRange(1, STATUS_COLUMN_INDEX, 1, 1);
    if (headerRange.getValue() !== STATUS_HEADER) {
      headerRange.setValue(STATUS_HEADER);
    }
    
    // 모든 응답 데이터 가져오기 (A열부터 상태 열까지)
    const dataRange = sheet.getRange(2, 1, lastRow - 1, STATUS_COLUMN_INDEX);
    const responses = dataRange.getValues();
    
    // 각 응답 처리
    for (let i = 0; i < responses.length; i++) {
      const currentRow = i + 2; // 실제 시트의 행 번호 (헤더 다음부터)
      const response = responses[i];
      
      // 이미 처리된 응답은 건너뛰기
      if (response[STATUS_COLUMN_INDEX - 1] === STATUS_COMPLETE) {
        continue;
      }
      
      // 응답 데이터 추출
      const responseData = {
        timestamp: response[COL_TIMESTAMP],
        name: response[COL_NAME],
        email: response[COL_EMAIL],
        phone: response[COL_PHONE],
        needsPDF: String(response[COL_NEEDS_PDF]).toLowerCase().includes('네'),
        inquiry: response[COL_INQUIRY]
      };
      
      // 이메일 유효성 검사
      if (!responseData.email || !validateEmail(responseData.email)) {
        sheet.getRange(currentRow, STATUS_COLUMN_INDEX).setValue(STATUS_EMAIL_ERROR);
        Logger.log(`행 ${currentRow} - 이메일 오류: ${responseData.email}`);
        continue;
      }
      
      try {
        // PDF 첨부 파일 준비 (필요한 경우에만)
        let pdfAttachment = null;
        if (responseData.needsPDF) {
          pdfAttachment = preparePDFAttachment(); // 별도 구현 필요
        }
        
        // ChatGPT 응답 생성
        const chatGPTResponse = generateChatGPTResponse(responseData.inquiry); // 별도 구현 필요
        
        // 이메일 내용 생성
        const emailContent = createEmailContent(responseData.name, chatGPTResponse); // 별도 구현 필요
        
        // 이메일 전송
        sendCustomerEmail(
          responseData.email,
          "회사 소개 PDF 및 문의 답변",
          emailContent,
          pdfAttachment
        ); // 별도 구현 필요
        
        // 처리 상태 업데이트
        sheet.getRange(currentRow, STATUS_COLUMN_INDEX).setValue(STATUS_COMPLETE);
        
        // 처리 로그 기록
        logProcessResult(currentRow, "성공", "이메일 전송 완료");
      } catch (processError) {
        // 개별 응답 처리 중 발생한 오류 처리
        sheet.getRange(currentRow, STATUS_COLUMN_INDEX).setValue(STATUS_ERROR);
        logProcessResult(currentRow, "실패", processError.message);
        Logger.log(`행 ${currentRow} 처리 중 오류 발생: ${processError.message}`);
      }
    }
    
  } catch (error) {
    // 전체 프로세스 실행 중 발생한 오류 처리
    Logger.log("프로세스 실행 중 오류 발생: " + error.message);
    throw error;
  }
}

/**
 * 이메일 주소 유효성 검사 헬퍼 함수
 */
function validateEmail(email) {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

  • 트리거

  • 답변 내용

한국의 메시지 스크린 샷

기대 성과 및 향후 개선점

✅ 구축 후 기대 성과

🚀 업무 자동화 - 반복적인 고객 문의 응대 부담 해소

🚀 신속한 고객 대응 - 실시간 자동 응답을 통한 고객 만족도 향상

🚀 기업 홍보 강화 - 브랜드 신뢰도 및 인지도 상승

🚀 멀티 채널 대응 - 이메일뿐만 아니라 문자, 카카오톡 등 다양한 채널 활용 가능

🚀 데이터 기반 마케팅 - 수집된 고객 정보를 활용한 맞춤형 마케팅 가능

🔍 향후 개선 및 확장 계획

📍 다국어 지원 - 글로벌 고객을 위한 다국어 자동 응답 시스템 구축

📍 AI 학습 기능 강화 - 기존 문의 데이터를 학습하여 더 정교한 응답 제공

📍 고객 응답 통계 대시보드 구축 - 주요 문의 유형 및 트렌드 분석

📍 SNS 연동 최적화 - 블로그 및 SNS에서도 원활한 고객 문의 접수 가능

📍 맞춤형 마케팅 캠페인 실행 - 고객 데이터를 활용한 효과적인 마케팅 전략 수립

마무리

생소한 Google Apps Script를 처음 접하면서 많은 시행착오를 겪고 있으며, 지금도 여전히 익숙해지는 과정 중에 있습니다.

하지만, 이 다재다능한 도구를 AI와 함께 제대로 활용한다면 업무 자동화 및 효율화를 크게 개선할 수 있을 것으로 기대됩니다.

늦었지만 이제라도 Google Apps Script를 접하게 되어 다행이라는 생각이 듭니다.

4

👉 이 게시글도 읽어보세요