네, Google Apps Script와 Gemini API를 결합하여 과제 피드백을 자동화하는 상세 단계를 안내해 드리겠습니다. 이 가이드는 과제가 주로 Google Docs 형식이라고 가정하고 작성되었지만, 다른 형식에도 응용 가능합니다.
사전 준비:
- Gemini API 키 발급:
- Google AI Studio 로 이동하여 구글 계정으로 로그인합니다.
- 새 프로젝트를 생성하거나 기존 프로젝트를 선택합니다.
- 왼쪽 메뉴에서 "Get API key"를 클릭하여 API 키를 생성하고 안전한 곳에 복사해 둡니다. 이 키는 절대로 외부에 노출되어서는 안 됩니다.
- 피드백 받을 과제 폴더 확인:
- Google Drive에서 Classroom > 클래스룸명 > 과제명 폴더로 이동합니다.
- 이 폴더의 URL을 보면 folders/ 뒤에 긴 문자열이 있습니다. 이것이 폴더 ID입니다. 이 ID를 복사해 둡니다. (폴더 이름보다 ID를 사용하는 것이 더 정확합니다.)
구현 단계:
1단계: Apps Script 프로젝트 생성 및 기본 설정
- 스크립트 편집기 열기:
- 피드백 결과를 정리할 새 Google 스프레드시트를 하나 만듭니다. (선택 사항이지만 결과 로깅 및 관리에 편리합니다.)
- 스프레드시트 메뉴에서 도구 > 스크립트 편집기를 엽니다.
- 또는 Google Drive에서 새로 만들기 > 더보기 > Google Apps Script를 선택하여 독립형 스크립트 프로젝트를 만듭니다.
- 프로젝트 이름 지정: 스크립트 편집기 상단의 "제목 없는 프로젝트"를 클릭하여 "과제 자동 피드백" 등 알아보기 쉬운 이름으로 변경합니다.
- API 키 안전하게 저장 (Script Properties):
- 스크립트 편집기 왼쪽 메뉴에서 프로젝트 설정 (톱니바퀴 아이콘)을 클릭합니다.
- 아래로 스크롤하여 스크립트 속성(Script Properties) 섹션을 찾고 스크립트 속성 추가를 클릭합니다.
- 속성 이름으로 GEMINI_API_KEY (또는 원하는 이름)를 입력하고, 값에 사전 준비에서 복사한 Gemini API 키를 붙여넣습니다. 스크립트 속성 저장을 클릭합니다. 이렇게 하면 코드에 API 키가 직접 노출되지 않아 안전합니다.
- 필요한 서비스 활성화:
- 스크립트 편집기 왼쪽 메뉴에서 서비스 + 버튼을 클릭합니다.
- Drive API 와 Google Docs API 를 찾아 선택하고 추가 버튼을 누릅니다. (다른 형식의 파일이라면 해당 API, 예: Slides API, Sheets API 추가)
2단계: Apps Script 코드 작성
스크립트 편집기에 다음 코드를 붙여넣고 필요한 부분을 수정합니다.
// --- 설정 값 ---
// 1. 과제 파일들이 모여있는 구글 드라이브 폴더 ID를 입력하세요.
const ASSIGNMENT_FOLDER_ID = '여기에_과제_폴더_ID_붙여넣기';
// 2. Gemini API 키를 스크립트 속성에서 가져옵니다.
const API_KEY = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
// Gemini API 엔드포인트 (텍스트 전용 모델 예시)
const API_ENDPOINT = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${API_KEY}`;
// 3. (선택사항) 피드백 결과를 기록할 스프레드시트 설정
const SPREADSHEET_ID = SpreadsheetApp.getActiveSpreadsheet().getId(); // 현재 스프레드시트 사용 시
const LOG_SHEET_NAME = '피드백 로그'; // 결과 기록 시트 이름
// 4. AI에게 전달할 프롬프트 (가장 중요! 구체적으로 작성하세요)
const PROMPT_TEMPLATE = `
당신은 [과목명] 과제를 채점하고 피드백을 제공하는 교사입니다.
다음은 학생이 제출한 과제 내용입니다.
[학생 과제 내용 시작]
{{STUDENT_TEXT}}
[학생 과제 내용 끝]
아래 평가 기준(루브릭)을 바탕으로 학생의 과제에 대해 구체적인 피드백을 작성해 주세요.
[평가 기준 시작]
- 항목 1: [구체적인 기준 설명]
- 항목 2: [구체적인 기준 설명]
- 항목 3: [구체적인 기준 설명]
[평가 기준 끝]
피드백 형식:
1. **잘한 점:** (2-3가지 구체적인 예시 포함)
2. **개선할 점:** (2-3가지 구체적인 예시 및 개선 방안 제시)
3. **총평:** (간결하게 요약)
한국어로 작성해 주세요.
`;
// --- 메인 함수 ---
function generateFeedbackForAllAssignments() {
const folder = DriveApp.getFolderById(ASSIGNMENT_FOLDER_ID);
// Google Docs 파일만 가져오기 (필요시 MimeType 변경)
const files = folder.getFilesByType(MimeType.GOOGLE_DOCS);
// (선택사항) 로그 시트 준비
const ss = SpreadsheetApp.getActiveSpreadsheet(); // 독립형 스크립트 사용 시 SpreadsheetApp.openById(SPREADSHEET_ID) 사용
let sheet = ss.getSheetByName(LOG_SHEET_NAME);
if (!sheet) {
sheet = ss.insertSheet(LOG_SHEET_NAME);
sheet.appendRow(['파일명', '학생 이름 (추정)', '과제 내용 (요약)', 'AI 피드백', '오류']); // 헤더 추가
}
while (files.hasNext()) {
const file = files.next();
const fileName = file.getName();
const fileId = file.getId();
let studentName = extractStudentName(fileName); // 파일명에서 학생 이름 추출 시도
let feedback = '';
let errorMsg = '';
let docContent = '';
try {
// 1. 문서 내용 추출
docContent = DocumentApp.openById(fileId).getBody().getText();
if (!docContent.trim()) {
errorMsg = '문서 내용이 비어있습니다.';
Logger.log(`${fileName}: 문서 내용 비어있음`);
} else {
// 2. 프롬프트 생성
const prompt = PROMPT_TEMPLATE.replace('{{STUDENT_TEXT}}', docContent);
// 3. Gemini API 호출
const requestBody = {
"contents": [{
"parts": [{
"text": prompt
}]
}],
// 필요시 추가 파라미터 설정 (temperature, topK, topP 등)
// "generationConfig": {
// "temperature": 0.7,
// "topK": 40
// }
};
const options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(requestBody),
'muteHttpExceptions': true // API 오류 시 스크립트 중단 방지
};
const response = UrlFetchApp.fetch(API_ENDPOINT, options);
const responseCode = response.getResponseCode();
const responseBody = response.getContentText();
if (responseCode === 200) {
const jsonResponse = JSON.parse(responseBody);
// 응답 구조 확인 필요 (API 변경 가능성 있음)
if (jsonResponse.candidates && jsonResponse.candidates.length > 0 &&
jsonResponse.candidates[0].content && jsonResponse.candidates[0].content.parts &&
jsonResponse.candidates[0].content.parts.length > 0) {
feedback = jsonResponse.candidates[0].content.parts[0].text.trim();
Logger.log(`${fileName}: 피드백 생성 완료`);
// 4. 피드백 전달 (옵션 선택)
// 옵션 A: 문서에 댓글로 추가
addCommentToDoc(fileId, feedback);
// 옵션 B: (주석 처리됨) 이메일로 보내기 등 다른 작업 추가 가능
} else {
errorMsg = 'API 응답에서 피드백 내용을 찾을 수 없습니다. 응답: ' + responseBody;
Logger.log(`${fileName}: 피드백 추출 오류 - ${errorMsg}`);
}
} else {
errorMsg = `API 오류 발생 (코드: ${responseCode}): ${responseBody}`;
Logger.log(`${fileName}: API 오류 - ${errorMsg}`);
}
}
} catch (e) {
errorMsg = `스크립트 실행 중 오류: ${e.message} \n Stack: ${e.stack}`;
Logger.log(`${fileName}: 스크립트 오류 - ${errorMsg}`);
}
// (선택사항) 로그 시트에 결과 기록
sheet.appendRow([
fileName,
studentName,
docContent.substring(0, 100) + (docContent.length > 100 ? '...' : ''), // 내용 앞부분만 로깅
feedback,
errorMsg
]);
// API 과부하 방지를 위한 잠시 대기 (필요시 조절)
Utilities.sleep(1500); // 1.5초 대기
}
Logger.log('모든 과제 피드백 생성 작업 완료');
SpreadsheetApp.getUi().alert('자동 피드백 생성 및 로그 기록이 완료되었습니다.');
}
// --- 보조 함수 ---
/**
* Google 문서에 댓글을 추가하는 함수
* @param {string} docId 댓글을 추가할 문서 ID
* @param {string} commentText 추가할 댓글 내용
*/
function addCommentToDoc(docId, commentText) {
try {
const doc = DocumentApp.openById(docId);
// 문서 최상단에 댓글 추가 (선택 범위를 지정하여 특정 부분에 달 수도 있음)
doc.getBody().editAsText().insertText(0, ''); // 댓글 앵커를 위한 빈 텍스트 삽입 (필요 없을 수도 있음)
doc.addComment(commentText); // 문서 자체에 댓글 추가
Logger.log(`문서(${docId})에 댓글 추가 완료`);
} catch (e) {
Logger.log(`문서(${docId}) 댓글 추가 오류: ${e.message}`);
// 로그 시트에도 기록되므로 여기서는 로깅만 수행
}
}
/**
* 파일 이름에서 학생 이름을 추출하는 함수 (샘플 로직)
* 클래스룸 파일명 규칙에 맞게 수정 필요 (예: '과제명 - 학생이름.docx')
* @param {string} fileName 파일 이름
* @returns {string} 추출된 학생 이름 또는 빈 문자열
*/
function extractStudentName(fileName) {
// 예시: "과제 제목 - 홍길동.docx" 같은 형식일 경우
const parts = fileName.split(' - ');
if (parts.length > 1) {
// 마지막 부분에서 확장자 제거
const namePart = parts[parts.length - 1];
const dotIndex = namePart.lastIndexOf('.');
if (dotIndex > 0) {
return namePart.substring(0, dotIndex).trim();
} else {
return namePart.trim();
}
}
// 다른 형식의 파일 이름 규칙이 있다면 여기에 로직 추가
return ''; // 추출 실패 시
}
Use code with caution.JavaScript
3단계: 코드 수정 및 설정 값 입력
- ASSIGNMENT_FOLDER_ID: 코드 상단의 여기에_과제_폴더_ID_붙여넣기 부분을 사전 준비에서 복사한 실제 폴더 ID로 교체합니다.
- PROMPT_TEMPLATE: 이 부분이 가장 중요합니다!
- [과목명]을 실제 과목명으로 바꾸세요.
- [평가 기준 시작]과 [평가 기준 끝] 사이에 실제 사용하는 평가 기준(루브릭)이나 핵심 질문들을 명확하고 구체적으로 넣어주세요. AI는 이 기준을 바탕으로 피드백을 생성합니다.
- 피드백 형식을 원하는 대로 수정할 수 있습니다. (예: 점수 포함, 특정 부분 강조 등)
- 테스트를 통해 프롬프트를 계속 개선해야 좋은 품질의 피드백을 얻을 수 있습니다.
- (선택사항) 로그 시트 설정:
- 독립형 스크립트를 사용한다면 SPREADSHEET_ID에 대상 스프레드시트 ID를 직접 입력해야 합니다.
- LOG_SHEET_NAME을 원하는 시트 이름으로 변경할 수 있습니다.
- (선택사항) 피드백 전달 방식 결정:
- 기본 코드는 addCommentToDoc 함수를 호출하여 각 학생의 Google 문서에 직접 댓글을 답니다. 이것이 가장 일반적입니다.
- 만약 로그 시트에만 기록하고 싶다면 addCommentToDoc(fileId, feedback); 라인을 주석 처리(// 추가)하거나 삭제하세요.
- extractStudentName 함수: 클래스룸에서 생성되는 파일 이름 규칙에 맞게 학생 이름을 추출하는 로직을 수정해야 할 수 있습니다. (현재는 ' - ' 뒤의 텍스트를 이름으로 간주하는 예시)
4단계: 스크립트 실행 및 권한 부여
- 스크립트 편집기 상단 메뉴에서 generateFeedbackForAllAssignments 함수를 선택합니다.
- 실행 (▶︎ 아이콘) 버튼을 클릭합니다.
- 최초 실행 시 권한 요청:
- 스크립트가 Google Drive, Google Docs, 외부 서비스(Gemini API), Google Sheets 등에 접근할 수 있도록 권한을 부여해야 합니다.
- 권한 검토 버튼을 클릭하고, 스크립트를 실행할 구글 계정을 선택합니다.
- "Google에서 이 앱을 확인하지 않았습니다."라는 경고가 나올 수 있습니다. 고급을 클릭하고 (프로젝트 이름)(으)로 이동 (안전하지 않음)을 선택하여 진행합니다. (본인이 작성한 스크립트이므로 안전합니다.)
- 요청하는 모든 권한에 대해 허용 버튼을 클릭합니다.
5단계: 실행 결과 확인 및 피드백 검토
- 스크립트 실행이 완료될 때까지 기다립니다. (학생 수에 따라 시간이 걸릴 수 있습니다. Apps Script 실행 시간 제한에 유의하세요.)
- 로그 시트 확인: 스프레드시트의 피드백 로그 시트에 각 파일별 처리 결과(파일명, 학생 이름, 피드백 내용, 오류 여부)가 기록됩니다. 오류가 발생했다면 오류 열의 내용을 확인하여 원인을 파악합니다.
- 학생 문서 확인: addCommentToDoc 함수를 사용했다면, 각 학생의 Google 문서 파일에 AI가 생성한 피드백 댓글이 추가되었는지 확인합니다.
- AI 피드백 검토 및 수정: 매우 중요! AI가 생성한 피드백은 초안일 뿐입니다. 반드시 로그 시트나 학생 문서의 댓글을 교사가 직접 검토하고 필요한 부분을 수정해야 합니다. AI는 문맥을 잘못 이해하거나 부적절한 피드백을 생성할 수 있습니다.
추가 팁 및 고려사항:
- 테스트: 처음에는 1~2개의 파일만 있는 테스트 폴더를 만들어 스크립트가 정상 작동하는지, 프롬프트가 원하는 대로 피드백을 생성하는지 충분히 테스트하세요.
- 실행 시간 제한: 학생 수가 매우 많으면 Apps Script의 실행 시간 제한(일반 계정 6분, Workspace 계정 30분)을 초과할 수 있습니다. 이 경우, 스크립트를 여러 번 실행하거나, 특정 개수만 처리하고 다음 실행을 예약하는 등의 로직이 필요할 수 있습니다. Utilities.sleep()을 사용하여 API 호출 사이에 적절한 지연 시간을 주는 것이 좋습니다.
- 오류 처리: 제공된 코드는 기본적인 오류 처리를 포함하지만, 실제 운영 시에는 더 견고한 오류 처리 로직(예: 특정 횟수 재시도)을 추가하는 것이 좋습니다.
- 비용: Gemini API는 사용량에 따라 비용이 발생할 수 있습니다. Google AI Studio에서 가격 정책과 무료 사용량을 확인하세요.
- 프롬프트 개선: 피드백 품질은 프롬프트에 크게 좌우됩니다. 다양한 프롬프트를 시도하고, 좋은 예시와 나쁜 예시를 프롬프트에 포함하는 등 '프롬프트 엔지니어링'에 노력을 기울이세요.
이 가이드가 구글 클래스룸 과제 피드백 자동화 시스템 구축에 도움이 되기를 바랍니다! 막히는 부분이 있다면 언제든지 다시 질문해주세요.
'1일 1 AI 공부' 카테고리의 다른 글
1min.AI 평생구독권 구입!! (블랙프라이데이 행사중!) (1) | 2024.11.24 |
---|---|
미드저니 sref 사용해보기 (1) | 2024.09.04 |
Claude AI System Prompts 공개 (2) | 2024.08.31 |
Ideogram 2.0 출시 (0) | 2024.08.23 |
Flux Lora the Explorer (0) | 2024.08.19 |