구글 스프레드시트에서 GPT 호출 함수 만들기

8기에서 캔로봇님의 특강을 통해서 구글 스프레드시트에서 ChatGPT를 호출하는 것을 처음 접하였고, 그 때 OpenAI api 요금을 5달러 결제하고 지금까지 잘 사용하고 있습니다.

그 때 사용했던 함수는 GPT for Sheets and Docs라는 익스텐션의 GPT()라는 함수입니다.

그런데, 얼마 전 이 익스텐션이 유료로 바뀌어서..

구글 스프레드시트에서 GPT() 함수를 사용하게 되면 과금이 되게 됩니다.

유료로 바뀌면서 0.1달러(유효 기간 90일)를 기본으로 제공해 주는데, 몇 번 테스트로 호출했더니 벌써 0.07달러가 소진되었다고 나옵니다.


이제 구글 스프레드시트에서 GPT() 함수를 사용하게 되면

  • OpenAI API 비용

  • GPT fot Sheets and Docs 비용


이렇게 2중으로 비용이 발생하게 되는데요.

이왕 결제를 한 OpenAI API 비용만 가지고 구글 스프레드시트에서 ChatGPT를 이용하기 위해서 Apps Script로 함수를 직접 만들어 보았습니다.

늘 그렇지만, 이 과정 또한 우리의 ChatGPT(Grimoire GPTs)의 도움으로 진행하였습니다.



※ 참… ChatGPT 유료 구독과는 별개로 OpenAI API Key 가 있어야 합니다.

OpenAI API


자, 이제 시작하겠습니다.


  • 먼저, Grimoire 한테 Apps Script를 만들고 싶다고 얘기를 합니다.

이러면.. Grimoire가 자기 소개와 함께 이 작업을 진행하는 단계, 그리고 예시 코드를 만들어 줍니다.

(거의 80% 이상 ??? 작업이 끝납니다..ㅎㅎ)

참고로 Grimoire GPTs는 답변을 할 때, 이렇게 문제 해결의 단계를 먼저 안내를 해 줍니다.(Recipe Prompt Pattern이 적용 된 듯)




예시로 준 코드에서 몇 가지 수정이 필요해 보이는데요.

( 9기 문과생도AI 실습 과제가 도움이 되었습니다~^^)

1) 사용하는 모델 : davinci가 아니라 gpt-3.5-turbo 모델로 변경

2) 모델 변경에 따른 endpoint url 수정.

3) 보안을 위해 API_Key를 apps script 속성으로 지정.



여기서 잠시 Grimoire와의 대화를 이어가기 전에 구글 스프레드시트에서 준비 작업을 진행합니다.

“제목 없는 프로젝트”를 적당한 다른 이름으로 변경합니다. (예 : GPT함수 만들기)



  • 이제 위의 내용을 반영하여 Grimoire에게 수정해 달라고 요청합니다.

function callChatGPT() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var questionCell = sheet.getRange("A1"); // 질문이 입력될 셀
  var responseCell = sheet.getRange("B1"); // 응답이 표시될 셀

  var question = questionCell.getValue();
  if (question) {
    var response = getChatGPTResponse(question);
    responseCell.setValue(response);
  } else {
    responseCell.setValue("질문을 입력하세요.");
  }
}

function getChatGPTResponse(question) {
  var url = "https://api.openai.com/v1/completions";
  var payload = {
    model: "gpt-3.5-turbo",
    prompt: question,
    max_tokens: 150
  };

  var scriptProperties = PropertiesService.getScriptProperties();
  var apiKey = scriptProperties.getProperty("API_KEY");

  var options = {
    method: "post",
    contentType: "application/json",
    headers: {
      Authorization: "Bearer " + apiKey
    },
    payload: JSON.stringify(payload)
  };

  var response = UrlFetchApp.fetch(url, options);
  var result = JSON.parse(response.getContentText());

  return result.choices[0].text.trim();
}


수정된 Apps Script 코드를 복사한 다음, 위에서 열어 놓은 Apps Script 편집기의 “function myFunction()~~~” 라는 곳에 붙여 넣습니다.(기존 myFunction ~~~ 은 삭제)

그리고, 저장(1번) → 실행(2번) !!


이 때, 권한 승인이 필요하다는 창이 뜨는데요. 이것은 계속 오케이 하는 방향으로 진행하시면 됩니다.


  • 이제 OpenAI API Key를 스크립트 속성에 추가해 줍니다.


  • 여기까지 한 다음 스크립트 편집기 위에 있는 “실행” 버튼을 누르면 다음과 같은 error가 나오는데요.

말 그대로 endpoint 주소가 v1/completions 이 아닌, v1/chat/completions 이라는 뜻인데요.

이 에러문을 그대로 Grimoire에게 넣고 물어 보면, 다음과 같은 답변과 함께 수정 코드를 생성해 줍니다.


function callChatGPT() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var questionCell = sheet.getRange("A1"); // 질문이 입력될 셀
  var responseCell = sheet.getRange("B1"); // 응답이 표시될 셀

  var question = questionCell.getValue();
  if (question) {
    var response = getChatGPTResponse(question);
    responseCell.setValue(response);
  } else {
    responseCell.setValue("질문을 입력하세요.");
  }
}

function getChatGPTResponse(question) {
  var url = "https://api.openai.com/v1/chat/completions"; // URL 수정
  var payload = {
    model: "gpt-3.5-turbo",
    messages: [{
      role: "system",
      content: "This is a test message for the ChatGPT model."
    }, {
      role: "user",
      content: question
    }]
  };

  var scriptProperties = PropertiesService.getScriptProperties();
  var apiKey = scriptProperties.getProperty("API_KEY");

  var options = {
    method: "post",
    contentType: "application/json",
    headers: {
      Authorization: "Bearer " + apiKey
    },
    payload: JSON.stringify(payload)
  };

  var response = UrlFetchApp.fetch(url, options);
  var result = JSON.parse(response.getContentText());

  return result.choices[0].message.content.trim();
}


이렇게 수정된 코드를 다시 Script 편집기에 복사 / 붙여 넣기 한 후 실행을 시키면.. 이상 없이 실행이 되었습니다.

  • 아.. 그런데.. 이제 다 되었다고 생각하는 찰나.. 이상한 걸 발견했습니다.

function callChatGPT() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var questionCell = sheet.getRange("A1"); // 질문이 입력될 셀
  var responseCell = sheet.getRange("B1"); // 응답이 표시될 셀

  var question = questionCell.getValue();
  if (question) {


이 부분인데요. 질문이 입력된 셀이 A1, 응답이 표시될 셀이 B1으로 고정되어 있는 겁니다…

원래 GPT() 함수 처럼.. 프롬프트가 있는 셀의 값을 함수의 파라미터로 넣고.. 함수가 사용된 셀에 결과값이 나오도록 되어야 하는데 말이죠..


  • 그래서 , 마지막으로 이 부분에 대한 수정을 요청하였습니다. 그리고, 함수명도 너무 긴 것 같아서 myGPT()로 수정하였습니다.

이렇게 해서 나온 최종 결과는 다음과 같습니다.

/**
 * 스프레드시트의 셀에서 직접 호출할 수 있는 myGPT 함수
 *
 * @param {string} prompt ChatGPT에게 전달할 프롬프트
 * @return {string} ChatGPT의 응답
 * @customfunction
 */
function myGPT(prompt) {
  if (!prompt) {
    return "프롬프트를 입력하세요.";
  }

  var url = "https://api.openai.com/v1/chat/completions";
  var payload = {
    model: "gpt-3.5-turbo",
    messages: [{
      role: "system",
      content: "This is a test message for the ChatGPT model."
    }, {
      role: "user",
      content: prompt
    }]
  };

  var scriptProperties = PropertiesService.getScriptProperties();
  var apiKey = scriptProperties.getProperty("API_KEY");

  var options = {
    method: "post",
    contentType: "application/json",
    headers: {
      Authorization: "Bearer " + apiKey
    },
    payload: JSON.stringify(payload)
  };

  try {
    var response = UrlFetchApp.fetch(url, options);
    var result = JSON.parse(response.getContentText());
    return result.choices[0].message.content.trim();
  } catch (e) {
    return "오류: " + e.message;
  }
}


  • 최종 스크립트를 복사해 넣고, 실행을 눌려 보면 이상이 없다고 나오고.. 이제 스프레드 시트 창으로 돌아 와서 함수를 사용하면 다음과 같은 결과를 얻을 수 있습니다.


  • 마지막으로 이 상태로 두게 되면 이 파일을 열 때 마다 자동으로 OpenAI API가 호출이 되어 비용이 발생하게 됩니다. 이를 방지하기 위해 8기 때 캔로봇님이 알려 주신 팁을 적용해 보았습니다.



이상으로 구글 스프레드시트에서 OpenAI API를 호출하는 함수를 Apps Script로 만드는 과정을 정리해 보았는데요.

과정 자체가 실제로는 그리 복잡하지 않지만, Apps Script나 OpenAI API를 잘 모르는 상태에서 조금씩 배우면서 하려다 보니.. 중간 중간 고민의 포인트가 있었는데요..

그런 경험을 최대한 살려서 가급적 세세하게 작성해 보았습니다.

이 점 참고해 주세요~

그럼, 이만!!

(선 등록 후 수정하도록 하겠습니다.)


#9기문과생도AI

14
15개의 답글