실습 6에서는 Google Sheets에서 특정 칼럼이 체크되면 ChatGPT API를 통해 내용을 요약하고, 이를 네이버 카페 API를 활용하여 자동으로 게시글을 업로드하는 시스템을 구축합니다. 또한, 추가 실습으로 게시글에 이미지 첨부 기능도 구현해보겠습니다.
-
스프레드시트 생성:
- Google Sheets에 접속하여 새로운 스프레드시트를 만듭니다.
- 예시:
게시글 관리 시트
-
시트 구성:
- 첫 번째 행에 헤더를 추가합니다:
제목
,내용
,요약
,게시 여부
게시 여부
열은 체크박스 형식으로 설정합니다:- 해당 열을 선택한 후, 상단 메뉴에서 삽입 > 체크박스를 클릭합니다.
- 첫 번째 행에 헤더를 추가합니다:
-
OpenAI 계정 생성 및 로그인:
- OpenAI에서 계정을 생성하고 로그인합니다.
-
API 키 생성:
- 로그인 후, API 키 생성 페이지에서 새로운 비밀 키를 생성하고 복사하여 안전한 곳에 저장합니다.
-
네이버 개발자 센터 접속 및 로그인:
- 네이버 개발자 센터에 접속하여 네이버 계정으로 로그인합니다.
-
애플리케이션 등록:
- 상단 메뉴에서 애플리케이션 > 애플리케이션 등록을 클릭합니다.
- 애플리케이션 이름과 사용 API를 선택합니다. 여기서는 네이버 로그인과 카페 API를 선택합니다.
-
Redirect URI 설정:
- 애플리케이션 등록 시 Redirect URI를 설정해야 합니다. 이는 OAuth 2.0 인증 과정에서 필요합니다.
- 예시:
https://your-redirect-uri.com/callback
-
네이버 로그인 API를 통한 사용자 인증:
- 네이버 로그인 API를 사용하여 사용자의 인증을 받아 **접근 토큰(access token)**을 발급받습니다.
- 자세한 내용은 네이버 로그인 개발 가이드를 참고하세요.
-
카페 API 권한 요청:
- 발급받은 접근 토큰을 사용하여 카페 API를 호출할 수 있습니다.
- 카페에 게시글을 작성하려면 사용자가 해당 카페의 회원이어야 하며, API 사용 권한이 부여되어야 합니다.
- 편집기 열기:
- Google Sheets에서 상단 메뉴의 확장 프로그램 > Apps Script를 클릭합니다.
-
ChatGPT를 통한 내용 요약 함수 작성:
- OpenAI의 ChatGPT API를 호출하여 입력된 내용을 요약하는 함수를 작성합니다.
/** * ChatGPT API를 호출하여 내용을 요약하는 함수 * @param {string} content - 요약할 원본 내용 * @returns {string} - 요약된 내용 */ function generateSummary(content) { const apiUrl = 'https://api.openai.com/v1/completions'; const prompt = `다음 내용을 요약해 주세요:\n\n${content}`; const options = { method: 'post', headers: { 'Authorization': `Bearer ${OPENAI_API_KEY}`, 'Content-Type': 'application/json' }, payload: JSON.stringify({ model: 'text-davinci-003', prompt: prompt, max_tokens: 150 }) }; try { const response = UrlFetchApp.fetch(apiUrl, options); const json = JSON.parse(response.getContentText()); return json.choices[0].text.trim(); } catch (error) { Logger.log('요약 생성 오류:', error); return ''; } }
-
네이버 카페에 게시글을 업로드하는 함수 작성:
- 네이버 카페 API를 사용하여 게시글을 업로드하는 함수를 작성합니다.
/** * 네이버 카페에 게시글을 업로드하는 함수 * @param {string} title - 게시글 제목 * @param {string} content - 게시글 내용 * @returns {object} - API 응답 객체 */ function postToNaverCafe(title, content) { const apiUrl = `https://openapi.naver.com/v1/cafe/${NAVER_CAFE_ID}/menu/${NAVER_CAFE_MENU_ID}/articles`; const options = { method: 'post', headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}`, 'Content-Type': 'application/json', 'X-Naver-Client-Id': NAVER_CLIENT_ID, 'X-Naver-Client-Secret': NAVER_CLIENT_SECRET }, payload: JSON.stringify({ subject: title, content: content }) }; try { const response = UrlFetchApp.fetch(apiUrl, options); return JSON.parse(response.getContentText()); } catch (error) { Logger.log('게시글 업로드 오류:', error); return null; } }
-
스프레드시트에서 체크박스 변경을 감지하여 자동으로 처리하는 함수 작성:
- 스프레드시트의 '게시 여부' 열에서 체크박스가 체크되면 자동으로 요약 및 게시를 수행하는 함수를 작성합니다.
/** * 스프레드시트에서 '게시 여부' 체크박스 변경 시 호출되는 함수 * @param {Event} e - onEdit 이벤트 객체 */ function onEdit(e) { const sheet = e.source.getActiveSheet(); const range = e.range; const column = range.getColumn(); const row = range.getRow(); const postColumn = 4; // '게시 여부' 열 번호 // '게시 여부' 열에서 체크박스가 체크된 경우 if (column === postColumn && range.getValue() === true) { const title = sheet.getRange(row, 1).getValue(); const content = sheet.getRange(row, 2).getValue(); const summary = generateSummary(content); // 요약된 내용을 '요약' 열에 입력 sheet.getRange(row, 3).setValue(summary); // 네이버 카페에 게시글 업로드 const postContent = `요약: ${summary}\n\n원문: ${content}`; const response = postToNaverCafe(title, postContent); if (response) { Logger.log('게시 성공:', response); } else { Logger.log('게시 실패'); } } }
-
트리거 추가:
- Apps Script 편집기에서 상단의 시계 아이콘(트리거)을 클릭합니다.
- 트리거 추가 버튼을 눌러 새로운 트리거를 생성합니다.
- 다음과 같이 설정합니다:
- 함수:
onEdit
- 이벤트 소스: 스프레드시트
- 이벤트 유형: 수정 시
- 함수:
-
권한 부여:
- 트리거를 설정하면 해당 스크립트가 외부 서비스(API)에 접근할 수 있도록 권한을 부여해야 합니다.
- 권한 요청 창이 나타나면 지시에 따라 권한을 승인합니다.
-
테스트 데이터 입력:
- 스프레드시트에 테스트용 데이터를 입력합니다.
- 예시:
- 제목:
새로운 제품 출시
- 내용:
저희 회사에서 새로운 제품을 출시했습니다. 많은 관심 부탁드립니다.
- 요약: (비워둠)
- 게시 여부: (체크박스 미체크)
- 제목:
- 예시:
- 스프레드시트에 테스트용 데이터를 입력합니다.
-
게시 여부 체크:
- 해당 행의 '게시 여부' 열에 체크박스를 체크합니다.
- 잠시 후 '요약' 열에 요약된 내용이 입력되고, 네이버 카페에 게시글이 업로드되었는지 확인합니다.
네이버 카페 API를 통해 게시글에 이미지를 첨부하려면 multipart/form-data 형식으로 요청을 보내야 합니다. 그러나 Google Apps Script의 UrlFetchApp
은 기본적으로 multipart/form-data
형식의 요청을 직접 지원하지 않습니다. 따라서, 이를 구현하기 위해서는 수동으로 HTTP 요청의 본문을 작성해야 합니다.
우선, 첨부할 이미지를 Google Drive에 저장하고, 해당 이미지 파일을 스크립트에서 접근할 수 있도록 합니다.
-
이미지 업로드:
- Google Drive에 접속하여 첨부할 이미지를 업로드합니다.
-
파일 ID 확인:
- 업로드한 이미지 파일을 마우스 오른쪽 버튼으로 클릭하고, 공유를 선택합니다.
- 공유 설정에서 링크가 있는 모든 사용자에게 공개로 설정하여 링크 복사를 클릭합니다.
- 복사한 링크에서 파일 ID를 추출합니다. 파일 ID는 URL 중간의 고유한 문자열입니다. 예:
https://drive.google.com/file/d/FILE_ID/view
에서FILE_ID
부분이 파일 ID입니다.
이제, 스크립트에서 해당 이미지를 읽어와 네이버 카페에 게시글과 함께 업로드하도록 코드를 수정합니다.
-
이미지 파일 읽기 함수 추가:
Google Drive에 저장된 이미지를 읽어오는 함수를 작성합니다.
/** * Google Drive에서 이미지 파일을 읽어오는 함수 * @param {string} fileId - 이미지 파일의 ID * @returns {Blob} - 이미지 파일의 Blob 객체 */ function getImageBlob(fileId) { try { const file = DriveApp.getFileById(fileId); const blob = file.getBlob(); return blob; } catch (error) { Logger.log('이미지 파일 읽기 오류:', error); return null; } }
-
네이버 카페에 게시글과 이미지 업로드 함수 수정:
이전에 작성한
postToNaverCafe
함수를 수정하여 이미지도 함께 업로드하도록 합니다./** * 네이버 카페에 게시글과 이미지를 업로드하는 함수 * @param {string} title - 게시글 제목 * @param {string} content - 게시글 내용 * @param {string} imageFileId - 첨부할 이미지 파일의 ID * @returns {object} - API 응답 객체 */ function postToNaverCafeWithImage(title, content, imageFileId) { const apiUrl = `https://openapi.naver.com/v1/cafe/${NAVER_CAFE_ID}/menu/${NAVER_CAFE_MENU_ID}/articles`; const boundary = '----WebKitFormBoundary' + Math.random().toString(36).substring(2); const imageBlob = getImageBlob(imageFileId); if (!imageBlob) { Logger.log('이미지 Blob을 가져오지 못했습니다.'); return null; } const payload = Utilities.newBlob('', 'multipart/form-data; boundary=' + boundary) .setDataFromString( '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="subject"\r\n\r\n' + title + '\r\n' + '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="content"\r\n\r\n' + content + '\r\n' + '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="image"; filename="' + imageBlob.getName() + '"\r\n' + 'Content-Type: ' + imageBlob.getContentType() + '\r\n\r\n' ) .getBytes() .concat(imageBlob.getBytes()) .concat(Utilities.newBlob('\r\n--' + boundary + '--').getBytes()); const options = { method: 'post', contentType: 'multipart/form-data; boundary=' + boundary, headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}`, 'X-Naver-Client-Id': NAVER_CLIENT_ID, 'X-Naver-Client-Secret': NAVER_CLIENT_SECRET }, payload: payload }; try { const response = UrlFetchApp.fetch(apiUrl, options); return JSON.parse(response.getContentText()); } catch (error) { Logger.log('게시글 업로드 오류:', error); return null; } }
-
onEdit 함수 수정:
스프레드시트에서 '게시 여부' 체크박스가 체크될 때, 이미지도 함께 업로드하도록
onEdit
함수를 수정합니다.function onEdit(e) { const sheet = e.source.getActiveSheet(); const range = e.range; const column = range.getColumn(); const row = range.getRow(); const postColumn = 4; // '게시 여부' 열 번호 const imageFileIdColumn = 5; // '이미지 파일 ID' 열 번호 if (column === postColumn && range.getValue() === true) { const title = sheet.getRange(row, 1).getValue(); const content = sheet.getRange(row, 2).getValue(); const imageFileId = sheet.getRange(row, imageFileIdColumn).getValue(); const summary = generateSummary(content); sheet.getRange(row, 3).setValue(summary); // 요약 열에 결과 저장 const postContent = `요약: ${summary}\n\n원문: ${content}`; const response = postToNaverCafeWithImage(title, postContent, imageFileId); if (response) { Logger.log('게시 성공:', response); } else { Logger.log('게시 실패'); } } }
이제 Google Sheets에서 특정 칼럼을 체크하면 ChatGPT를 통해 내용을 요약하고, 네이버 카페 API를 활용하여 이미지와 함께 자동으로 게시글을 업로드하는 시스템을 구축할 수 있습니다.
중요 참고 사항:
-
네이버 카페 API 사용 시 주의점: 네이버 카페 API를 통해 이미지를 업로드할 때, 이미지가 본문 상단에 고정되거나 원하는 위치에 삽입되지 않는 이슈가 있을 수 있습니다. 이러한 문제는 네이버 개발자 포럼에서 다루어지고 있으므로, 최신 정보를 확인하시기 바랍니다. citeturn0search5
-
API 사용 정책 준수: 네이버 카페 API를 사용하여 자동으로 게시글을 업로드할 때는 네이버의 API 사용 정책과 카페 운영 원칙을 준수해야 합니다. 자동화된 게시글 업로드는 카페의 스팸 방지 정책에 위배될 수 있으므로, 사용 전에 해당 카페의 운영 방침을 확인하시기 바랍니다.
이러한 시스템을 구축함으로써 업무 효율성을 높일 수 있지만, 항상 플랫폼의 정책과 규정을 준수하는 것이 중요합니다.