로그인 유지
브라우저를 닫더라도 로그인이 계속 유지될 수 있습니다. 로그인 유지 기능을 사용할 경우 다음 접속부터는 로그인할 필요가 없습니다. 단, PC방, 학교, 도서관 등 공공장소에서 이용 시 개인정보가 유출될 수 있으니 꼭 로그아웃을 해주세요.
2026.01.31 13:51
맥가이버 조회 수:15
const OPENAI_API_KEY = "본인APIKEY";
// ⚠️ 반드시 여기에 본인의 OpenAI API 키를 넣으세요! (sk-로 시작)
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('✨ AI 기능')
.addItem('기존 데이터 피드백 생성 (전체)', 'processExistingRows')
.addItem('🔍 단일 행 테스트 (현재 선택)', 'testSingleRow')
.addToUi();
}
// ✨ 테스트용 함수
function testSingleRow() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const currentRow = sheet.getActiveRange().getRow();
if (currentRow < 2) {
SpreadsheetApp.getUi().alert("3행 이상을 선택해주세요.");
return;
const row = sheet.getRange(currentRow, 1, 1, 10).getValues()[0];
const data5to11 = row.slice(4, 10);
const combinedAnswers = data5to11.join("\n- ");
const prompt = createPrompt(combinedAnswers);
Logger.log("=== 프롬프트 ===");
Logger.log(prompt);
const result = callOpenAI(prompt);
Logger.log("=== 결과 ===");
Logger.log(result);
sheet.getRange(currentRow, 11).setValue(result);
SpreadsheetApp.getUi().alert(`결과:\n${result}`);
function processExistingRows() {
const lastRow = sheet.getLastRow();
if (lastRow < 2) {
SpreadsheetApp.getUi().alert("처리할 데이터가 없습니다.");
const dataRange = sheet.getRange(2, 1, lastRow - 1, 10);
const data = dataRange.getValues();
let successCount = 0;
let failCount = 0;
data.forEach((row, index) => {
const currentRow = index + 2;
const existingFeedback = sheet.getRange(currentRow, 11).getValue();
if (!existingFeedback || existingFeedback.toString().includes("오류")) {
if (result && !result.includes("오류")) {
successCount++;
} else {
failCount++;
Utilities.sleep(1000);
});
SpreadsheetApp.getUi().alert(`작업 완료!\n성공: ${successCount}개\n실패: ${failCount}개`);
// ✨ 프롬프트 생성 함수
function createPrompt(combinedAnswers) {
return `다음은 중학교 학생의 수학 학습 설문 답변입니다.
학생의 답변을 읽고, 따뜻하고 격려하는 피드백을 정확히 2문장으로 작성해주세요.
[작성 규칙]
- 1문장: 학생 답변의 긍정적인 부분을 구체적으로 칭찬
- 2문장: 성장을 위한 실천 가능한 조언이나 격려
- 반말 사용 (예: ~야, ~거야, ~네, ~어)
- 반드시 2문장으로 완성
- 문장 끝을 명확하게 (마침표, 느낌표 사용)
[예시]
답변: 수학은 어렵지만 문제를 풀면 뿌듯해요.
피드백: 어려움 속에서도 문제를 해결하려는 노력이 정말 멋져. 그 성취감을 계속 느끼면서 한 걸음씩 나아가면 수학 실력이 쑥쑥 자랄 거야.
[학생 답변]
${combinedAnswers}
위 답변에 대한 피드백 (정확히 3문장):`;
// ✨ OpenAI API 호출 함수
function callOpenAI(prompt) {
if (!OPENAI_API_KEY || OPENAI_API_KEY.trim() === "" || !OPENAI_API_KEY.startsWith("sk-")) {
return "⚠️ 오류: OpenAI API 키를 입력해주세요. (sk-로 시작해야 합니다)";
try {
const url = "https://api.openai.com/v1/chat/completions";
const payload = {
"model": "gpt-4o-mini", // 비용 효율적인 모델 (gpt-4o, gpt-4-turbo, gpt-3.5-turbo도 가능)
"messages": [
{
"role": "system",
"content": "당신은 학생 개개인의 생각을 존중하고 성장을 응원하는 중학교 수학 선생님입니다. 항상 2문장으로 피드백을 작성합니다."
},
"role": "user",
"content": prompt
],
"temperature": 0.8,
"max_tokens": 700
};
const options = {
"method": "post",
"contentType": "application/json",
"headers": {
"Authorization": `Bearer ${OPENAI_API_KEY}`
"payload": JSON.stringify(payload),
"muteHttpExceptions": true
const response = UrlFetchApp.fetch(url, options);
const responseCode = response.getResponseCode();
const responseText = response.getContentText();
Logger.log(`응답 코드: ${responseCode}`);
if (responseCode !== 200) {
Logger.log(`응답 내용: ${responseText}`);
const errorJson = JSON.parse(responseText);
if (errorJson.error) {
return `⚠️ OpenAI API 오류: ${errorJson.error.message}`;
return `⚠️ HTTP 오류 ${responseCode}`;
const json = JSON.parse(responseText);
if (json.error) {
Logger.log(`API 에러: ${JSON.stringify(json.error)}`);
return `⚠️ API 에러: ${json.error.message}`;
if (!json.choices || json.choices.length === 0) {
Logger.log("choices 없음");
return "⚠️ 응답 생성 실패";
const choice = json.choices[0];
// finish_reason 체크
Logger.log(`finish_reason: ${choice.finish_reason}`);
if (choice.finish_reason === "content_filter") {
return "⚠️ 콘텐츠 필터에 의해 차단됨";
if (choice.finish_reason === "length") {
return "⚠️ 토큰 제한 초과";
if (!choice.message || !choice.message.content) {
Logger.log("message.content 없음");
return "⚠️ 응답 내용 없음";
const text = choice.message.content.trim();
if (text === "") {
return "⚠️ 빈 응답";
Logger.log(`생성된 텍스트: ${text}`);
return text;
} catch (e) {
Logger.log(`예외 발생: ${e.toString()}`);
return `⚠️ 시스템 오류: ${e.message}`;