API 없이 구글스프레드 시트 자동화하기 (feat.Apps script)


#9기AI알바생

#9기 #AI알바생

▶구글 스프레드 시트 링크

https://docs.google.com/spreadsheets/d/1L5epnrZUkLmsapmMQOkGP0edhWzJC_zE9txGmBsi2XA/edit?usp=sharing

▶ ChatGPT4 대화내용

(1) 첫번째 함수: https://chat.openai.com/share/7cf63f6a-6c17-409d-8630-1b73053e7b08
(2) 두번째 함수: https://chat.openai.com/share/0bace466-c4ff-42f3-8ac5-abb8ad2345ae


안녕하세요, 업무 자동화에 관심이 많은 2년차 주니어 마케터 하수경입니다.

이번 9기 AI알바생 캠프를 통해서 업무 시간을 단축시킬 수 있는 방법에 대해서 알아보려고 합니다.



분석 대상: 구글스프레드 시트


회사에서는 팀 내 업무 공유를 위해 구글 스프레드 시트를 활용합니다. 업무를 진행하다보니 의미없이 반복되는 과정이 많은데, API를 활용하면 자동화할 수 있는 구석이 많을 것 같더라고요. 그래서 ChatGPT와 Gemini를 활용해서 업무를 자동화할 수 있는 방법을 알아보기로 했습니다.


단, 구글 스프레드 시트에서 데이터를 다운 받는 번거로운 과정을 생략하고 시트 내에서 바로 데이터를 분석하고 싶었습니다. 이를 위해서 아래 두 가지 방법을 고려해보았습니다.


  1. API를 활용하여 프롬프트에서 데이터 분석을 명령/작성

  2. 스프레드 시트 내 함수를 활용하여 데이터를 분석


API 사용이 더 편하기는 하겠지만, 이번 프로젝트에서는 최대한 ChatGPT를 많이 활용해보기 위해서 1번 방법은 제외하기로 했습니다.



분석 방법: 함수? Google Apps script?


우선 데이터를 분석하기 이전에, 저는 구글 스프레드 시트와 코딩 모두에 배경지식이 없는 상태였다는 점을 말씀드리려고 합니다. 때문에 함수를 사용할 수 있는 방법이 있는지를 ChatGPT 4.0에 물어보았습니다.

제가 하고 싶은 데이터 분석은 다음과 같았습니다.

  1. 팀원들과 동시 작업을 하고 있다보니 작업한 내용이 겹치는 경우가 많았습니다.

  2. 따라서 C열에 입력한 내용이 겹치지 않도록 모두 읽어서 확인을 해야 했는데, 300개가 넘어가다보니 그것도 어렵더라고요.

  3. 때문에 너무 내용이 겹치는 경우에는 확인을 해주는 함수를 만들고 싶었습니다.


질문을 할 때에는 #역할 #의도 #상세내용 을 나누어서 질문했고,
순서대로 진행(Step by step)해달라는 이야기도 함께 덧붙였습니다.


친절한 ChatGPT는 함수로는 해당 업무를 해결하기는 어렵고, 대안으로 Google Apps Script를 제안해주었습니다. Apps scripts가 무엇인지 아예 모르는 저를 위해서 접속 방법까지 친절하게 설명해주는 모습입니다.

저는 코딩은 물론이고 Apps scripts의 존재조차 몰랐지만,
우선은 ChatGPT를 믿고 따라가보기로 했습니다.



분석 과정: 스크립트 작성과 오류 수정


작성해준 스크립트는 다음과 같았습니다. 스크립트를 잘 모르기는 하지만,
ChatGPT가 영어로 코드 내에 설명까지 덧붙여주는 것을 확인할 수 있었습니다.


작성해준 스크립트를 복사 붙여넣기를 하고 실행하려고 했더니,
아래와 같은 메시지가 뜨면서 에러가 발생했습니다.

TypeError: Cannot read properties of undefined (reading 'length')
getLevenshteinDistance	@ Code.gs:2

ChatGPT에게 오류메시지를 전달하고, Step by step으로 오류를 분석하고 수정한 스크립트를 전달해달라고 해보았습니다. 오류가 될 수 있는 원인을 분석하고 덧붙여야 할 코드까지 잘 전달해주는 모습입니다.


이후에 2,3단계 해결책도 전달해주고, 코드도 전달해주었지만 계속해서 오류가 발생했습니다.
알고보니 제가 실행하는 함수를 잘못 지정하는 기본적인 실수를 했더라고요.

이런 부분은 GPT가 짚어주지 못하는 것 같아서 아쉬웠습니다.
(제가 전달한 오류에만 집중하고 제가 함수 자체를 잘못 실행했을 거라고는 예상을 못하더라고요.)



아무튼 제대로 실행을 했지만, 제가 원하는 내용과 다른 결과물이 나와서 수정이 필요했습니다.
(색깔을 지정하는 내용도 너무 오래 걸려서 삭제해달라고 부탁하고,
해당 내용은 Google 스프레드 시트 내에 조건부서식으로 대체했습니다.)


코드가 짜준 내용

C열에 있는 모든 데이터&선택한 셀의 데이터 유사도를 검사해줌.

원하는 분석 내용

C열에 있는 각각의 데이터&선택한 셀의 데이터 유사도를 검사해줌.


수정이 필요한 내용을 전달해서 ChatGPT에게 코드를 다시 짜달라고 부탁했습니다.
(색깔을 지정하는 내용도 너무 오래 걸려서 삭제해달라고 추가로 부탁했습니다.)


아래는 수정해준 결과물입니다.

function updateMaxSimilarityForColumnC() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('질문 내용');
 var lastRow = sheet.getLastRow();
 var cRange = sheet.getRange('C1:C' + lastRow);
 var cValues = cRange.getValues();
 var dValues = [];

 for (var i = 0; i < cValues.length; i++) {
  var maxSimilarity = 0; // 초기 최대 유사도 값은 0
  for (var j = 0; j < cValues.length; j++) {
   if (i !== j) { // 자기 자신과의 비교는 제외
    var similarity = calculateSimilarity(cValues[i][0], cValues[j][0]);
    maxSimilarity = Math.max(maxSimilarity, similarity); // 최대 유사도 갱신
   }
  }
  dValues.push([maxSimilarity]); // 계산된 최대 유사도를 D열 값 배열에 추가
 }

 // D열에 계산된 최대 유사도 값을 한 번에 업데이트
 sheet.getRange(1, 4, dValues.length, 1).setValues(dValues);
}

function calculateSimilarity(text1, text2) {
 var distance = getLevenshteinDistance(text1, text2);
 var maxLength = Math.max(text1.length, text2.length);
 if (maxLength === 0) return 0; // 두 문자열이 모두 비어있으면 유사도는 0
 return (maxLength - distance) / maxLength; // 유사도 계산
}

function getLevenshteinDistance(s, t) {
 var d = []; // 거리를 계산할 2차원 배열
 var n = s.length;
 var m = t.length;

 if (n == 0) return m;
 if (m == 0) return n;

 // 2차원 배열 초기화
 for (var i = 0; i <= n; d[i] = [i++]);
 for (var j = 0; j <= m; d[0][j] = j++);

 for (var i = 1; i <= n; i++) {
  for (var j = 1; j <= m; j++) {
   var cost = s.charAt(i - 1) == t.charAt(j - 1) ? 0 : 1;
   d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
  }
 }
 return d[n][m];
}



분석 수정: 스크립트 작업 효율 향상


분석 실행 시간을 줄이기 위해서, 코드의 일부를 수정하기로 했습니다.
(이 부분은 AI알바생 9기 파트너 몽주님이 아이디어를 주셨습니다.)


<이전에 생성한 코드>

C열에 있는 모든 데이터하루에 한 번 자동으로 검사해서 D열에 기록

※ Google Apps script 트리거 기능을 활용

<새로 생성할 코드>

C열에 새로 데이터가 입력되는 경우, 해당 행에 있는 데이터만 검사해서 D열에 기록

Ex) C120에 데이터가 입력되면, D120에만 데이터 입력


우선 ChatGPT에 기존 코드를 입력하고,
제가 분석하고 있는 방식이 맞는지 검토를 진행했습니다.


아래 사진을 보면 알겠지만, 유사도 개념을 활용해서 분석이 잘 되고 있다고 설명해주었습니다.

지피터스 오프라인 모임에서 해당 내용을 발표했을 당시에 개발자분들도 많이 계셨는데,
레벤슈타인 거리 알고리즘 개념(getLevenshteinDistance 함수)이 생소하다고 신기해하셨습니다.


이제 새로 생성할 코드에 대해서 GPT에게 설명했습니다.
제가 원하는대로 코드가 만들어질 수 있도록 예시를 자세하게 입력해주었습니다.


저는 트리거 기능을 활용할 생각이었지만,
onEdit이라는 함수를 통해서 문제를 해결할 수 있다고 이야기해주네요.


제가 Apps script에 들어가서 실행 버튼을 누르지 않아도 되고,
트리거가 없어도 셀이 편집되면 바로 함수가 실행되는 방식이라 훨씬 효율적이었습니다.


아래는 GPT에게 받은 스크립트입니다.

function onEdit(e) {
  var range = e.range; // 편집된 셀의 범위
  var sheet = range.getSheet();
  if (sheet.getName() === '질문 내용' && range.getColumn() === 3) { // C열(3번째 열)과 '질문 내용' 시트에 대한 변경사항만 처리
    var row = range.getRow(); // 편집된 셀의 행 번호
    updateMaxSimilarityForRow(row); // 해당 행에 대한 최대 유사도 계산 및 업데이트
  }
}

function updateMaxSimilarityForRow(row) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('질문 내용');
  var cValue = sheet.getRange(row, 3).getValue(); // 변경된 C열의 값
  var lastRow = sheet.getLastRow();
  var cRange = sheet.getRange('C1:C' + lastRow);
  var cValues = cRange.getValues();
  var maxSimilarity = 0; // 초기 최대 유사도 값은 0

  for (var i = 0; i < cValues.length; i++) {
    if (row !== i + 1) { // 자기 자신과의 비교는 제외
      var similarity = calculateSimilarity(cValue, cValues[i][0]);
      maxSimilarity = Math.max(maxSimilarity, similarity); // 최대 유사도 갱신
    }
  }
  // D열에 계산된 최대 유사도 값을 업데이트
  sheet.getRange(row, 4).setValue(maxSimilarity);
}

// calculateSimilarity 함수와 getLevenshteinDistance 함수는 이전에 제공된 코드를 그대로 사용합니다.



분석 검토: Gemini 활용하기


ChatGPT로 작성한 코드를 넣고 Bard에게 궁금한 점을 물어보았습니다.

  • 숨김 처리한 행이 있어도 바가 스크립트가 실행되는지

  • D열에 이미 데이터가 있어도, 덮어쓰기 되는지


Gemini는 제 질문에 친절하게 모두 가능하다고 답변해주었습니다.



번외로, 코드 실행 시간을 단축시키기 위해서 명령을 하는 경우
제가 방향성을 제시해주지 않는다면 오류가 나는 코드를 전달해주더라고요.

사용 방향성을 생각해서 어떤식으로 하고 싶은지
구체적인 방향성을 가지고 질문을 해야 최적의 결과를 도출해주는 것 같습니다.

참고하세요!


동일한 글을 포스팅한 블로그 주소도 함께 첨부합니다.
다른 주제의 글이 많지만, 궁금하신 분들은 놀러오세요!

https://blog.naver.com/everyday_in_seoul/223350605989

6
5개의 답글

(채용) 콘텐츠 마케터, AI 엔지니어, 백엔드 개발자

지피터스의 수 천개 AI 활용 사례 데이터를 AI로 재가공 할 인재를 찾습니다

👉 이 게시글도 읽어보세요