구글 스프레드 시트에서 공짜로 LLM 사용하기(심화-결과)
결국 이 코드만 살아 남았다.
전제 조건
A열에는 프롬프트를 적용할 글이, B1에는 프롬프트가, B2에는 서식(예: =gpt2(a2,$b$1)이 있어야 합니다.
주석은 1분 후로 되어 있지만 30초로 조정함
// 배치 작업: A열의 다음 10개 행에 수식을 입력하고, 1분 후 결과 처리를 위한 트리거를 등록
function processBatch() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var scriptProperties = PropertiesService.getScriptProperties();
// 마지막 처리한 행 번호 (없으면 1, 즉 B2부터 시작)
var lastProcessedRow = Number(scriptProperties.getProperty("lastProcessedRow")) || 1;
var startRow = lastProcessedRow + 1;
var batchSize = 10;
// 이번 배치 대상: A열의 startRow ~ (startRow+batchSize-1)
var dataRange = sheet.getRange("A" + startRow + ":A" + (startRow + batchSize - 1));
var dataValues = dataRange.getValues();
var rowsToProcess = 0;
for (var i = 0; i < dataValues.length; i++) {
if (dataValues[i][0] === "" || dataValues[i][0] === null) break;
rowsToProcess++;
}
if (rowsToProcess === 0) {
Logger.log("더 이상 처리할 데이터가 없습니다.");
deleteTimeBasedTriggers();
return;
}
// 이번 배치의 시작 행을 저장 (processResults에서 사용)
scriptProperties.setProperty("currentBatchStartRow", startRow.toString());
// B열 해당 범위에 대해 수식 입력 (B2는 처음 입력된 수식 그대로 유지)
for (var i = 0; i < rowsToProcess; i++) {
var rowNumber = startRow + i;
var cell = sheet.getRange("B" + rowNumber);
if (cell.getFormula() === "") {
cell.setFormula("=gpt2(A" + rowNumber + ",$B$1)");
}
}
// 이번 배치의 마지막 행 업데이트
scriptProperties.setProperty("lastProcessedRow", (startRow + rowsToProcess - 1).toString());
// 1분 후에 결과값으로 붙여넣기(수식을 값으로 전환)하는 작업을 위한 트리거 등록
ScriptApp.newTrigger("processResults")
.timeBased()
.after(30000)
.create();
Logger.log("processBatch 실행: " + startRow + "행부터 " + (startRow+rowsToProcess-1) + "행까지 처리.");
}
// 1분 후 실행: 이번 배치의 수식을 결과값으로 고정한 후 다음 배치 실행을 예약
function processResults() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var scriptProperties = PropertiesService.getScriptProperties();
var startRow = Number(scriptProperties.getProperty("currentBatchStartRow"));
var lastProcessedRow = Number(scriptProperties.getProperty("lastProcessedRow"));
var rowsToProcess = lastProcessedRow - startRow + 1;
// 첫 배치일 경우(B2는 수식을 유지) B3부터 값 붙여넣기, 그 외 배치는 전체 범위 변환
if (startRow === 2 && rowsToProcess > 1) {
var convertRange = sheet.getRange("B" + (startRow + 1) + ":B" + lastProcessedRow);
convertRange.setValues(convertRange.getValues());
} else {
var batchRange = sheet.getRange("B" + startRow + ":B" + lastProcessedRow);
batchRange.setValues(batchRange.getValues());
}
// processResults 트리거 삭제 (방금 실행된 트리거)
deleteTriggerByFunction("processResults");
// 다음 배치 진행 여부 확인
var nextRow = lastProcessedRow + 1;
var nextValue = sheet.getRange("A" + nextRow).getValue();
if (nextValue !== "" && nextValue !== null) {
// 1초 후 다음 배치를 위한 processBatch 실행 트리거 등록
ScriptApp.newTrigger("processBatch")
.timeBased()
.after(1000)
.create();
Logger.log("다음 배치 예약: " + nextRow + "행부터 실행 예정.");
} else {
Logger.log("모든 데이터를 처리했습니다.");
deleteTimeBasedTriggers();
}
}
// 지정된 함수 이름의 트리거(시간 기반 트리거)만 삭제
function deleteTriggerByFunction(functionName) {
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() === functionName &&
triggers[i].getTriggerSource() === ScriptApp.TriggerSource.CLOCK) {
ScriptApp.deleteTrigger(triggers[i]);
}
}
}
// 모든 시간 기반(Clock) 트리거 삭제
function deleteTimeBasedTriggers() {
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
if (triggers[i].getTriggerSource() === ScriptApp.TriggerSource.CLOCK) {
ScriptApp.deleteTrigger(triggers[i]);
}
}
}
공유하기



조회수 : 121