소개
(지난 번 글을 작성한 이후 진행된 내용을 더하여 글을 작성함)
하루 동안 발생한 중요한 기사와 그 내용을 요약
요약한 기사를 대시보드 형태로 웹형식으로 html파일을 만들고
지메일에 발송함.
진행 방법
1. 사용한 툴 소개
n8n: 워크프로우 자동화 플랫폼
ChatGPT: n8n에서 ChatGPT node를 사용하여 뉴스기사 요약 진행
Lovable: 대시보드 웹시각화 디자인
tavily: 뉴스기사 수집 api
2. 워크플로우
(1) 워크플로우1
스케쥴링: 매일 밤 12시 업데이트
뉴스기사 수집
수집된 html구조 변경
return $json["results"].map(item => { return { json: { title: item.title, original_text: item.content, // 이름 변경 url: item.url, published_date: item.published_date, score: item.score ?? null // 필요 시 score 유지 } }; });원하는 컬럼만 남기기
뉴스기사 요약, 주제와 세부주제 선정, 키워드 선정
구글시트에 넣을 형식으로 데이터 정리(제목에서 출처분리, 수집일 컬럼 만들기)
const items = $input.all(); const now = new Date().toISOString().split("T")[0]; // "2025-06-04" 형식 for (let i = 0; i < items.length; i++) { const item = items[i]; const raw = item.json?.message?.content || ""; let parsed = {}; try { parsed = JSON.parse(raw); } catch (e) { item.json = { error: "JSON parse failed", raw_content: raw }; continue; } const fullTitle = parsed.title || ""; const splitTitle = fullTitle.split(" - "); const cleanTitle = splitTitle[0]?.trim() || ""; const source = splitTitle[1]?.trim() || ""; const idNumber = String(i + 1).padStart(3, "0"); // 001, 002, ... const id = `news-${idNumber}`; item.json = { id: id, title: cleanTitle, source: source, original_text: parsed.original_text || "", url: parsed.url || "", published_date: parsed.published_date || "", collected_date: now, // ✅ 오늘 날짜를 수집일로 저장 theme: parsed.theme || "", sub_theme: parsed.sub_theme || "", summary: parsed.summary || "", keywords: parsed.keywords || "" }; } return items;구글시트에 저장
(2) 워크플로우2
구글시트에서 데이터 읽기
html 구조로 변환
const today = new Date().toLocaleDateString('ko-KR', { year: 'numeric', month: 'long', day: 'numeric' }); function escapeHTML(str) { return str?.replace(/[&<>"']/g, (m) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[m]) ?? ''; } const articles = $input.all().map(item => item.json); const html = ` <!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>오늘의 뉴스 대시보드</title> <script src="https://cdn.tailwindcss.com"></script> </head> <body class="bg-gradient-to-br from-slate-50 to-blue-50 min-h-screen"> <div class="p-6 space-y-6 max-w-7xl mx-auto"> <div class="text-center space-y-2"> <h1 class="text-4xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"> 오늘의 주요 뉴스 </h1> <p class="text-sm text-gray-600">📅 ${today} 기준</p> <p class="text-lg text-muted-foreground">최신 뉴스를 한눈에 확인하세요</p> </div> <div class="flex justify-center"> <input id="searchInput" placeholder="키워드로 검색..." class="max-w-md w-full shadow-sm border border-blue-200 focus:border-blue-400 transition-colors h-10 rounded-md px-3 py-2 text-base" /> </div> <div id="newsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> ${ articles.map(a => ` <div class="news-card rounded-2xl shadow-md bg-white p-6 space-y-3 hover:shadow-lg transition"> <h2 class="text-lg font-semibold text-gray-800"> <a href="${escapeHTML(a.url)}" target="_blank" class="hover:underline text-blue-600"> ${escapeHTML(a.title)} </a> </h2> <p class="text-sm text-gray-600">출처: ${escapeHTML(a.source)} | 작성일: ${escapeHTML(a.published_date)}</p> <p class="text-base">${escapeHTML(a.summary)}</p> <div class="text-sm italic text-gray-600">키워드: ${escapeHTML(a.keywords)}</div> <div class="text-sm italic text-gray-600"> 주제: ${escapeHTML(a.theme)}<br> 세부주제: ${escapeHTML(a.sub_theme)} </div> </div> `).join('\n') } </div> <div class="text-center pt-8"> <p class="text-sm text-gray-500"> 더 많은 뉴스는 각 기사의 원문 링크를 확인해주세요. </p> </div> </div> <script> document.getElementById('searchInput').addEventListener('input', function () { const query = this.value.toLowerCase(); const cards = document.querySelectorAll('.news-card'); cards.forEach(card => { const text = card.innerText.toLowerCase(); card.style.display = text.includes(query) ? 'block' : 'none'; }); }); </script> </body> </html> `; return [{ json: { html } }];html 다운로드 파일 생성
const html = items[0].json.html; // 또는 직접 HTML 문자열 return [ { binary: { data: { data: Buffer.from(html, 'utf-8').toString('base64'), mimeType: 'text/html', fileName: 'news_dashboard.html' } } } ];Gmail로 보내기
결과와 배운점
평소에 내가 생각하는 것들을 간단히 구현해보고 싶은 욕구가 있었으나
개발을 배우는 것에 대한 부담이 커서 시도를 못했는데
개발을 모르는 사람도 완벽하지는 않지만 생각을 초안 정도는 구현해 볼 수 있는 시대가 열린 것 같다.
이렇게 하기까지 n8n의 역할도 컸지만 무엇보다 chatGPT의 역할이 컸다.
chatGPT가 내가 전혀 모르는 언어들을 만들어주었기 때문에 해낼 수 있었다.
다만, 자바스크립트 코드를 잘못 작성해줘서 여러차레 물어봐야 했다.
이부분은 클로드가 훨씬 잘 한다고 하기에 다음에 사용해보고 싶다.
또 lovable은 chatGPT보다 훨씬 디자인 을 잘해주는 것 같다.
처음에 n8n을 익히는데 약간 버거웠지만 익숙해지니 뚝딱 데이터 수집부터 메일링까지 완성하였다.
n8n을 활용하기 위해서는 다음과 같은 것들에 익숙해지면 좋을 것 같다.
- n8n에서 제공하는 노드들의 활용법
- LLM이 제공한 자바스크립트를 이해하고 수정할 수 있는 능력
- LLM 프롬프트 활용능력 (SYSTEM PROMPT, USER PROMPT, LANG CHAIN)
앞으로도 내가 그동안 해보고 싶었던 것들
그리고 내 생활에서 자동화가 가능한 부분들을 찾아서 자동화를 진행해봐야겠다.