Ver3.5 파이썬 + OpenAI API로자동 요약 시스템 구축하기

파이썬 + OpenAI API로
자동 요약 시스템 구축하기
솔직히 말해서... 요즘 정보가 너무 많잖아ㅋㅋㅋ
뉴스 기사 하나 읽으려면 스크롤이 끝도 없고, 논문은 영어에 전문용어 범벅이고,
유튜브 영상은 1시간짜리인데 핵심은 5분이고... 😩
그래서 오늘은 파이썬(Python)이랑 OpenAI API를 조합해서
자동 요약 시스템을 직접 만드는 방법을 완전 실전 위주로 파헤쳐볼 거야!
코드 복붙만 해도 돌아가는 수준으로 설명할 테니까 걱정 ㄴㄴ 😎
AI/머신러닝 개발 입문자부터 실무자까지 다 유용할 내용이니까 끝까지 봐줘~
자동 요약(Automatic Summarization)은 크게 두 가지 방식으로 나뉘어:
① 추출적 요약 (Extractive Summarization)
원문에서 중요한 문장을 그대로 뽑아내는 방식.
예전 NLP 방식에서 많이 썼고, 원문 문장을 그대로 가져오니까 왜곡이 없다는 장점이 있어.
② 생성적 요약 (Abstractive Summarization)
원문을 이해하고 새로운 문장으로 재생성하는 방식.
GPT 같은 LLM이 바로 이 방식이야. 훨씬 자연스럽고 핵심을 잘 잡아줌!
우리가 오늘 만들 건 당연히 생성적 요약 방식이고,
OpenAI의 GPT 모델을 API로 호출해서 구현할 거야. 🔥
HTTP 요청으로 호출할 수 있어. 파이썬 SDK도 공식 지원해서 코드 몇 줄이면 연동 완료!
준비물 체크리스트야. 다 있으면 바로 시작 가능!
터미널(cmd/PowerShell/bash)에서 아래 명령어 실행해줘:
# 기본 openai 패키지 설치
pip install openai
# 추가로 유용한 패키지들도 같이 설치하자
pip install python-dotenv # 환경변수 관리용
pip install tiktoken # 토큰 수 계산용
pip install requests # HTTP 요청용 (웹 크롤링 등)
pip install beautifulsoup4 # HTML 파싱용
API 키를 코드에 직접 박아넣으면 절대 안 돼!! 😱
깃허브에 올리는 순간 키 탈취당하고 요금 폭탄 맞을 수 있거든.
.env 파일을 사용해서 환경변수로 관리하자:
# .env 파일 생성 (프로젝트 루트에)
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# .gitignore 파일에 반드시 추가!
.env
__pycache__/
*.pyc
# Python 코드에서 불러오기
import os
from dotenv import load_dotenv
load_dotenv() # .env 파일 로드
api_key = os.getenv("OPENAI_API_KEY")
print(f"API 키 로드 완료: {api_key[:10]}...") # 앞 10자리만 확인
.gitignore에 추가하는 거 잊으면 진짜 큰일 나요ㅋㅋ 실제로 매년 수천 명이 이 실수로 요금 폭탄 맞음...
환경 세팅 끝났으면 바로 코드 써보자.
가장 기본적인 텍스트 요약 코드야. 복붙하면 바로 돌아감!
import os
from openai import OpenAI
from dotenv import load_dotenv
# 환경변수 로드
load_dotenv()
# OpenAI 클라이언트 초기화
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def summarize_text(text: str, max_length: int = 300) -> str:
"""
텍스트를 요약하는 기본 함수
Args:
text: 요약할 원문 텍스트
max_length: 요약문 최대 글자 수 (기본 300자)
Returns:
요약된 텍스트 문자열
"""
# 시스템 프롬프트 설정
system_prompt = """당신은 전문 텍스트 요약 AI입니다.
주어진 텍스트를 핵심 내용만 추출하여 명확하고 간결하게 요약해주세요.
요약 시 다음 원칙을 따르세요:
1. 핵심 정보를 빠짐없이 포함
2. 불필요한 반복 제거
3. 자연스러운 한국어 문장 사용
4. 원문의 사실 관계를 정확하게 유지"""
# 사용자 프롬프트 구성
user_prompt = f"""다음 텍스트를 {max_length}자 이내로 요약해주세요:
---
{text}
---
요약:"""
# API 호출
response = client.chat.completions.create(
model="gpt-4o-mini", # 비용 효율적인 모델
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
max_tokens=500,
temperature=0.3 # 낮을수록 일관된 출력
)
# 결과 추출
summary = response.choices[0].message.content.strip()
return summary
# 테스트 실행
if __name__ == "__main__":
sample_text = """
인공지능(AI) 기술이 빠르게 발전하면서 다양한 산업 분야에서 혁신이 일어나고 있다.
특히 자연어 처리(NLP) 분야에서는 GPT, BERT 등 대형 언어 모델이 등장하면서
텍스트 이해와 생성 능력이 인간 수준에 근접하고 있다. 이러한 기술은 의료, 법률,
금융, 교육 등 전문 분야에서도 활발히 적용되고 있으며, 특히 문서 요약, 번역,
질의응답 시스템 등에서 두드러진 성과를 보이고 있다. 전문가들은 향후 5년 내에
AI가 대부분의 반복적인 지식 작업을 자동화할 것으로 전망하고 있으며, 이에 따른
직업 시장의 변화와 새로운 역할의 등장에 대한 논의도 활발해지고 있다.
"""
result = summarize_text(sample_text, max_length=150)
print("=== 요약 결과 ===")
print(result)
요약 작업에는 충분히 강력하고, 비용도 GPT-4 대비 약 15배 저렴함!
(2024년 기준 입력 $0.15/1M 토큰, 출력 $0.60/1M 토큰)
솔직히 API 호출 자체는 쉬워.
근데 좋은 요약을 뽑아내려면 프롬프트를 잘 짜야 해!
프롬프트 엔지니어링이 전체 퀄리티의 70%를 결정한다고 봐도 과언이 아님ㅋㅋ
class SummaryPrompts:
"""다양한 요약 목적에 맞는 프롬프트 모음"""
@staticmethod
def news_summary(text: str) -> dict:
"""뉴스 기사 요약용"""
return {
"system": "당신은 뉴스 편집 전문가입니다. 기사의 핵심 사실을 5W1H(누가, 언제, 어디서, 무엇을, 왜, 어떻게) 기준으로 요약합니다.",
"user": f"다음 뉴스 기사를 3문장으로 요약해주세요. 가장 중요한 사실부터 서술하세요:\n\n{text}"
}
@staticmethod
def academic_summary(text: str) -> dict:
"""학술 논문/보고서 요약용"""
return {
"system": "당신은 학술 문서 분석 전문가입니다. 연구의 목적, 방법론, 주요 결과, 결론을 체계적으로 요약합니다.",
"user": f"""다음 학술 텍스트를 아래 형식으로 요약해주세요:
【연구 목적】
【연구 방법】
【주요 결과】
【결론 및 시사점】
텍스트:
{text}"""
}
@staticmethod
def meeting_summary(text: str) -> dict:
"""회의록 요약용"""
return {
"system": "당신은 비즈니스 회의 전문 서기입니다. 회의의 핵심 결정사항, 액션 아이템, 담당자를 명확히 정리합니다.",
"user": f"""다음 회의 내용을 요약해주세요:
📌 주요 논의 사항:
✅ 결정된 사항:
📋 액션 아이템 (담당자 - 기한):
❓ 미결 사항:
회의 내용:
{text}"""
}
@staticmethod
def bullet_summary(text: str, num_points: int = 5) -> dict:
"""불릿 포인트 요약용"""
return {
"system": "당신은 정보를 명확하고 간결한 핵심 포인트로 정리하는 전문가입니다.",
"user": f"다음 텍스트의 핵심 내용을 {num_points}개의 불릿 포인트로 정리해주세요. 각 포인트는 한 문장으로 작성하세요:\n\n{text}"
}
@staticmethod
def keyword_extract(text: str) -> dict:
"""키워드 추출용"""
return {
"system": "당신은 텍스트 분석 전문가입니다. 텍스트에서 가장 중요한 키워드와 핵심 개념을 추출합니다.",
"user": f"다음 텍스트에서 핵심 키워드 10개를 추출하고, 각 키워드의 중요도를 1-5점으로 평가해주세요. JSON 형식으로 출력하세요:\n\n{text}"
}
def smart_summarize(text: str, mode: str = "general") -> str:
"""
목적에 맞는 스마트 요약 함수
mode 옵션:
- "general": 일반 요약
- "news": 뉴스 기사
- "academic": 학술 문서
- "meeting": 회의록
- "bullet": 불릿 포인트
- "keyword": 키워드 추출
"""
prompts = SummaryPrompts()
mode_map = {
"news": prompts.news_summary,
"academic": prompts.academic_summary,
"meeting": prompts.meeting_summary,
"bullet": prompts.bullet_summary,
"keyword": prompts.keyword_extract,
}
if mode in mode_map:
prompt_data = mode_map[mode](text)
else:
# 기본 일반 요약
prompt_data = {
"system": "당신은 전문 텍스트 요약 AI입니다.",
"user": f"다음 텍스트를 핵심 내용 중심으로 간결하게 요약해주세요:\n\n{text}"
}
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": prompt_data["system"]},
{"role": "user", "content": prompt_data["user"]}
],
temperature=0.3,
max_tokens=800
)
return response.choices[0].message.content.strip()
# 사용 예시
result = smart_summarize(my_text, mode="news")
print(result)
GPT 모델에는 컨텍스트 윈도우(Context Window)라는 한계가 있어.
쉽게 말해서 한 번에 처리할 수 있는 텍스트 양에 제한이 있다는 거야.
GPT-4o-mini 기준으로 128K 토큰이 한계인데,
한국어 기준으로 대략 1토큰 ≈ 0.5~1글자 정도야.
그래도 엄청 긴 문서는 분할 처리가 필요해!
| 모델 | 컨텍스트 윈도우 | 한국어 기준 처리량 |
|---|---|---|
| gpt-3.5-turbo | 16K 토큰 | 약 8,000~16,000자 |
| gpt-4o-mini | 128K 토큰 | 약 64,000~128,000자 |
| gpt-4o | 128K 토큰 | 약 64,000~128,000자 |
| gpt-4-turbo | 128K 토큰 | 약 64,000~128,000자 |
정말 긴 문서(책, 긴 보고서 등)는 Map-Reduce 방식으로 처리해!
① 문서를 청크로 분할 → ② 각 청크 요약 → ③ 요약들을 다시 요약
import tiktoken
def count_tokens(text: str, model: str = "gpt-4o-mini") -> int:
"""텍스트의 토큰 수를 계산하는 함수"""
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
encoding = tiktoken.get_encoding("cl100k_base")
return len(encoding.encode(text))
def split_text_into_chunks(text: str, max_tokens: int = 3000) -> list[str]:
"""
텍스트를 토큰 기준으로 청크 분할
문단 단위로 분할하여 문맥 유지
"""
paragraphs = text.split('\n\n') # 문단 단위로 분할
chunks = []
current_chunk = []
current_tokens = 0
for para in paragraphs:
para_tokens = count_tokens(para)
if current_tokens + para_tokens > max_tokens and current_chunk:
# 현재 청크 저장하고 새 청크 시작
chunks.append('\n\n'.join(current_chunk))
current_chunk = [para]
current_tokens = para_tokens
else:
current_chunk.append(para)
current_tokens += para_tokens
# 마지막 청크 추가
if current_chunk:
chunks.append('\n\n'.join(current_chunk))
return chunks
def hierarchical_summarize(text: str, final_max_tokens: int = 500) -> str:
"""
계층적 요약 (Map-Reduce 방식)
긴 텍스트를 청크로 나눠 요약 후 최종 요약 생성
"""
total_tokens = count_tokens(text)
print(f"📊 원문 토큰 수: {total_tokens:,}")
# 토큰이 적으면 바로 요약
if total_tokens < 3000:
print("✅ 직접 요약 처리")
return summarize_text(text)
# 청크 분할
chunks = split_text_into_chunks(text, max_tokens=3000)
print(f"✂️ {len(chunks)}개 청크로 분할 완료")
# 각 청크 요약 (Map 단계)
chunk_summaries = []
for i, chunk in enumerate(chunks):
print(f"🔄 청크 {i+1}/{len(chunks)} 요약 중...")
summary = summarize_text(chunk, max_length=200)
chunk_summaries.append(summary)
# 청크 요약들을 합쳐서 최종 요약 (Reduce 단계)
combined_summaries = '\n\n'.join(chunk_summaries)
print("🎯 최종 요약 생성 중...")
final_prompt = f"""다음은 긴 문서를 여러 부분으로 나눠 요약한 내용들입니다.
이 요약들을 종합하여 전체 문서의 핵심 내용을 하나의 완결된 요약문으로 작성해주세요.
중복 내용은 제거하고, 가장 중요한 정보를 중심으로 정리해주세요.
부분 요약들:
{combined_summaries}
최종 종합 요약:"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "당신은 여러 요약문을 하나의 완결된 요약으로 통합하는 전문가입니다."},
{"role": "user", "content": final_prompt}
],
max_tokens=final_max_tokens,
temperature=0.3
)
return response.choices[0].message.content.strip()
# 사용 예시
with open("long_document.txt", "r", encoding="utf-8") as f:
long_text = f.read()
final_summary = hierarchical_summarize(long_text)
print("\n=== 최종 요약 ===")
print(final_summary)
URL 하나만 넣으면 웹 페이지 내용을 자동으로 가져와서 요약해주는 기능이야.
뉴스 기사, 블로그 포스트 등에 바로 적용 가능! 😎
import requests
from bs4 import BeautifulSoup
import re
def fetch_webpage_text(url: str) -> str:
"""
웹 페이지에서 텍스트 추출
Args:
url: 크롤링할 웹 페이지 URL
Returns:
추출된 텍스트
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
response.encoding = response.apparent_encoding # 인코딩 자동 감지
soup = BeautifulSoup(response.text, 'html.parser')
# 불필요한 태그 제거
for tag in soup(['script', 'style', 'nav', 'footer', 'header',
'aside', 'advertisement', 'iframe']):
tag.decompose()
# 본문 텍스트 추출 (article, main, p 태그 우선)
article = soup.find('article') or soup.find('main') or soup.find('body')
if article:
text = article.get_text(separator='\n', strip=True)
else:
text = soup.get_text(separator='\n', strip=True)
# 텍스트 정제
lines = [line.strip() for line in text.split('\n') if line.strip()]
text = '\n'.join(lines)
# 연속 공백 제거
text = re.sub(r'\n{3,}', '\n\n', text)
return text
except requests.RequestException as e:
raise Exception(f"웹 페이지 로드 실패: {e}")
def summarize_url(url: str, mode: str = "news") -> dict:
"""
URL을 입력받아 웹 페이지 내용을 요약
Returns:
{
"url": 원본 URL,
"text_length": 원문 글자 수,
"summary": 요약 결과
}
"""
print(f"🌐 URL 로딩 중: {url}")
text = fetch_webpage_text(url)
print(f"📝 텍스트 추출 완료: {len(text):,}자")
# 너무 짧으면 요약 불필요
if len(text) < 100:
return {"url": url, "text_length": len(text), "summary": "텍스트가 너무 짧아 요약이 불필요합니다."}
# 요약 실행
summary = smart_summarize(text, mode=mode)
return {
"url": url,
"text_length": len(text),
"summary": summary
}
# 사용 예시
result = summarize_url("https://example-news.com/article/12345", mode="news")
print(f"원문 길이: {result['text_length']:,}자")
print(f"\n요약:\n{result['summary']}")
상업적 목적의 크롤링은 사이트 이용약관도 꼭 확인하자!
여러 문서를 동시에 요약해야 할 때는 비동기(async) 처리가 필수야!
동기 방식으로 10개 문서 처리하면 10초 걸릴 거 비동기로 하면 2~3초면 됨ㅋㅋ
import asyncio
from openai import AsyncOpenAI
# 비동기 클라이언트 초기화
async_client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
async def async_summarize(text: str, session_id: str = "") -> dict:
"""비동기 요약 함수"""
response = await async_client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "당신은 전문 텍스트 요약 AI입니다."},
{"role": "user", "content": f"다음 텍스트를 200자 이내로 요약해주세요:\n\n{text}"}
],
max_tokens=400,
temperature=0.3
)
return {
"id": session_id,
"summary": response.choices[0].message.content.strip()
}
async def batch_summarize(texts: list[dict]) -> list[dict]:
"""
여러 텍스트를 동시에 요약 (배치 처리)
Args:
texts: [{"id": "1", "text": "..."}, ...] 형태의 리스트
Returns:
요약 결과 리스트
"""
# 동시 요청 수 제한 (Rate Limit 방지)
semaphore = asyncio.Semaphore(5) # 최대 5개 동시 요청
async def limited_summarize(item):
async with semaphore:
return await async_summarize(item["text"], item["id"])
# 모든 요약 작업을 동시 실행
tasks = [limited_summarize(item) for item in texts]
results = await asyncio.gather(*tasks, return_exceptions=True)
# 에러 처리
processed_results = []
for i, result in enumerate(results):
if isinstance(result, Exception):
processed_results.append({
"id": texts[i]["id"],
"summary": f"오류 발생: {str(result)}"
})
else:
processed_results.append(result)
return processed_results
# 실행 예시
async def main():
documents = [
{"id": "doc1", "text": "첫 번째 문서 내용..."},
{"id": "doc2", "text": "두 번째 문서 내용..."},
{"id": "doc3", "text": "세 번째 문서 내용..."},
# ... 더 많은 문서들
]
print(f"📦 {len(documents)}개 문서 동시 요약 시작...")
import time
start = time.time()
results = await batch_summarize(documents)
elapsed = time.time() - start
print(f"⏱️ 처리 완료: {elapsed:.2f}초")
for result in results:
print(f"\n[{result['id']}] {result['summary']}")
# 실행
asyncio.run(main())
API 호출은 네트워크 상황, Rate Limit, 서버 오류 등으로 실패할 수 있어.
실전 서비스라면 재시도(Retry) 로직은 필수야!
import time
import random
from openai import RateLimitError, APIError, APIConnectionError
def robust_summarize(text: str, max_retries: int = 3) -> str:
"""
에러 처리와 재시도 로직이 포함된 견고한 요약 함수
Exponential Backoff 전략 사용
"""
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "당신은 전문 텍스트 요약 AI입니다."},
{"role": "user", "content": f"다음 텍스트를 요약해주세요:\n\n{text}"}
],
max_tokens=500,
temperature=0.3,
timeout=30 # 30초 타임아웃
)
return response.choices[0].message.content.strip()
except RateLimitError as e:
# Rate Limit 초과 시 대기 후 재시도
wait_time = (2 ** attempt) + random.uniform(0, 1)
print(f"⚠️ Rate Limit 초과. {wait_time:.1f}초 후 재시도... (시도 {attempt+1}/{max_retries})")
time.sleep(wait_time)
except APIConnectionError as e:
# 연결 오류 시 재시도
wait_time = 2 ** attempt
print(f"🔌 연결 오류. {wait_time}초 후 재시도... (시도 {attempt+1}/{max_retries})")
time.sleep(wait_time)
except APIError as e:
# 서버 오류 (5xx) 시 재시도
if e.status_code >= 500:
wait_time = 2 ** attempt
print(f"🚨 서버 오류 ({e.status_code}). {wait_time}초 후 재시도...")
time.sleep(wait_time)
else:
# 4xx 오류는 재시도 불필요
raise Exception(f"API 오류: {e.status_code} - {e.message}")
except Exception as e:
print(f"❌ 예상치 못한 오류: {e}")
if attempt == max_retries - 1:
raise
raise Exception(f"최대 재시도 횟수({max_retries}) 초과")
# 비용 추적 기능 추가
class CostTracker:
"""API 사용 비용 추적 클래스"""
# 2024년 기준 가격 (USD per 1M tokens)
PRICES = {
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
"gpt-4o": {"input": 5.00, "output": 15.00},
"gpt-3.5-turbo": {"input": 0.50, "output": 1.50},
}
def __init__(self):
self.total_input_tokens = 0
self.total_output_tokens = 0
self.total_cost_usd = 0.0
self.request_count = 0
def track(self, response, model: str = "gpt-4o-mini"):
"""API 응답에서 토큰 사용량 추적"""
usage = response.usage
input_tokens = usage.prompt_tokens
output_tokens = usage.completion_tokens
self.total_input_tokens += input_tokens
self.total_output_tokens += output_tokens
self.request_count += 1
if model in self.PRICES:
cost = (input_tokens * self.PRICES[model]["input"] / 1_000_000 +
output_tokens * self.PRICES[model]["output"] / 1_000_000)
self.total_cost_usd += cost
def report(self):
"""비용 리포트 출력"""
print(f"\n💰 API 사용 현황")
print(f" 총 요청 수: {self.request_count:,}회")
print(f" 입력 토큰: {self.total_input_tokens:,}")
print(f" 출력 토큰: {self.total_output_tokens:,}")
print(f" 예상 비용: ${self.total_cost_usd:.4f} USD")
print(f" (약 {self.total_cost_usd * 1350:.0f}원)") # 환율 1350원 기준
# 전역 비용 추적기
tracker = CostTracker()
지금까지 배운 걸 다 합쳐서 실제로 쓸 수 있는 CLI 도구를 만들어보자!
터미널에서 명령어 하나로 요약 가능한 도구야 😎
#!/usr/bin/env python3
"""
auto_summarizer.py
파이썬 + OpenAI API 자동 요약 시스템
사용법: python auto_summarizer.py [옵션]
"""
import os
import sys
import argparse
import json
from pathlib import Path
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def read_input(source: str) -> str:
"""다양한 소스에서 텍스트 읽기"""
# URL인 경우
if source.startswith(('http://', 'https://')):
return fetch_webpage_text(source) # 위에서 정의한 함수
# 파일인 경우
path = Path(source)
if path.exists():
suffix = path.suffix.lower()
if suffix == '.txt':
return path.read_text(encoding='utf-8')
elif suffix == '.pdf':
try:
import pypdf
reader = pypdf.PdfReader(str(path))
text = ""
for page in reader.pages:
text += page.extract_text() + "\n"
return text
except ImportError:
print("PDF 처리를 위해 pypdf 설치 필요: pip install pypdf")
sys.exit(1)
elif suffix in ['.md', '.rst']:
return path.read_text(encoding='utf-8')
else:
print(f"지원하지 않는 파일 형식: {suffix}")
sys.exit(1)
# 직접 텍스트인 경우
return source
def format_output(summary: str, output_format: str, original_length: int) -> str:
"""출력 형식 포맷팅"""
if output_format == "json":
result = {
"summary": summary,
"original_length": original_length,
"summary_length": len(summary),
"compression_ratio": f"{(1 - len(summary)/original_length)*100:.1f}%"
}
return json.dumps(result, ensure_ascii=False, indent=2)
elif output_format == "markdown":
return f"""# 📋 요약 결과
**원문 길이:** {original_length:,}자
**요약 길이:** {len(summary):,}자
**압축률:** {(1 - len(summary)/original_length)*100:.1f}%
---
## 요약
{summary}
"""
else: # plain text
return f"""
{'='*50}
📋 요약 결과
{'='*50}
원문: {original_length:,}자 → 요약: {len(summary):,}자 ({(1 - len(summary)/original_length)*100:.1f}% 압축)
{'='*50}
{summary}
{'='*50}
"""
def main():
parser = argparse.ArgumentParser(
description='🤖 AI 자동 요약 시스템',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
사용 예시:
python auto_summarizer.py "https://news.example.com/article"
python auto_summarizer.py document.txt --mode academic
python auto_summarizer.py document.pdf --format json --output result.json
python auto_summarizer.py "긴 텍스트 내용..." --mode bullet --points 5
"""
)
parser.add_argument('source', help='요약할 소스 (URL, 파일 경로, 또는 텍스트)')
parser.add_argument('--mode', choices=['general', 'news', 'academic', 'meeting', 'bullet', 'keyword'],
default='general', help='요약 모드 (기본: general)')
parser.add_argument('--format', choices=['text', 'json', 'markdown'],
default='text', help='출력 형식 (기본: text)')
parser.add_argument('--output', '-o', help='결과 저장 파일 경로')
parser.add_argument('--model', default='gpt-4o-mini', help='사용할 GPT 모델')
parser.add_argument('--points', type=int, default=5, help='불릿 포인트 수 (bullet 모드)')
parser.add_argument('--max-length', type=int, default=300, help='요약 최대 글자 수')
args = parser.parse_args()
print(f"🚀 요약 시작...")
print(f" 모드: {args.mode} | 모델: {args.model}")
# 텍스트 읽기
text = read_input(args.source)
original_length = len(text)
print(f" 원문 길이: {original_length:,}자")
# 요약 실행
if original_length > 10000:
print(" 📦 긴 문서 감지 - 계층적 요약 적용")
summary = hierarchical_summarize(text)
else:
summary = smart_summarize(text, mode=args.mode)
# 출력 포맷팅
output = format_output(summary, args.format, original_length)
# 결과 출력/저장
if args.output:
Path(args.output).write_text(output, encoding='utf-8')
print(f"✅ 결과 저장 완료: {args.output}")
else:
print(output)
if __name__ == "__main__":
main()
# 실제 사용 예시들
# 뉴스 기사 URL 요약
python auto_summarizer.py "https://www.bbc.com/news/article" --mode news
# PDF 파일 학술 요약 (JSON 출력)
python auto_summarizer.py research.pdf --mode academic --format json -o result.json
# 텍스트 파일 불릿 포인트 요약
python auto_summarizer.py report.txt --mode bullet --points 7
# 마크다운 형식으로 저장
python auto_summarizer.py document.txt --format markdown -o summary.md
영어 문서를 한국어로 요약하거나, 한국어 문서를 영어로 요약하는 것도 GPT로 쉽게 가능해!
이게 진짜 강력한 기능 중 하나야 ㅋㅋㅋ
def multilingual_summarize(text: str,
source_lang: str = "auto",
target_lang: str = "ko") -> dict:
"""
다국어 요약 함수
Args:
text: 원문 텍스트
source_lang: 원문 언어 ("auto", "en", "ko", "ja", "zh" 등)
target_lang: 요약 출력 언어 ("ko", "en", "ja" 등)
Returns:
{"original_lang": ..., "summary": ..., "keywords": [...]}
"""
lang_names = {
"ko": "한국어", "en": "영어", "ja": "일본어",
"zh": "중국어", "fr": "프랑스어", "de": "독일어"
}
target_lang_name = lang_names.get(target_lang, target_lang)
system_prompt = f"""당신은 다국어 텍스트 분석 및 요약 전문가입니다.
주어진 텍스트를 분석하고 {target_lang_name}로 요약해주세요.
원문이 어떤 언어이든 상관없이 {target_lang_name}로 핵심 내용을 요약합니다."""
user_prompt = f"""다음 텍스트를 {target_lang_name}로 요약해주세요.
아래 JSON 형식으로 출력해주세요:
{{
"detected_language": "감지된 원문 언어",
"summary": "{target_lang_name} 요약 (200자 이내)",
"key_points": ["핵심 포인트 1", "핵심 포인트 2", "핵심 포인트 3"],
"keywords": ["키워드1", "키워드2", "키워드3", "키워드4", "키워드5"]
}}
텍스트:
{text}"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
response_format={"type": "json_object"}, # JSON 모드 활성화!
temperature=0.3,
max_tokens=600
)
result = json.loads(response.choices[0].message.content)
return result
# 사용 예시: 영어 뉴스를 한국어로 요약
english_article = """
Artificial intelligence is transforming the way we work and live.
Recent advances in large language models have enabled machines to
understand and generate human-like text with unprecedented accuracy...
"""
result = multilingual_summarize(english_article, target_lang="ko")
print(f"감지된 언어: {result['detected_language']}")
print(f"\n한국어 요약:\n{result['summary']}")
print(f"\n핵심 포인트:")
for point in result['key_points']:
print(f" • {point}")
print(f"\n키워드: {', '.join(result['keywords'])}")
구조화된 데이터가 필요할 때 진짜 유용함! 단, 시스템 프롬프트나 유저 프롬프트에 "JSON" 언급이 있어야 작동해.
특정 키워드 관련 뉴스를 자동 수집하고 요약해서 매일 아침 이메일로 받기.
기업 PR팀, 투자자, 리서처들이 많이 씀!
arXiv, PubMed 등에서 논문 PDF를 받아서 연구 목적/방법/결과를 자동 요약.
연구자들의 문헌 검토 시간을 80% 이상 단축 가능!
YouTube API로 자막 추출 후 GPT로 요약.
1시간짜리 강의도 5분 만에 핵심 파악 가능!
음성 인식(Whisper API)으로 회의 녹음을 텍스트로 변환 후 GPT로 요약.
Whisper + GPT 조합이면 완전 자동화 가능!
수천 개의 상품 리뷰를 요약하고 긍/부정 핵심 포인트 추출.
이커머스, 앱 서비스 등에서 UX 개선에 활용!
계약서, 약관, 판례 등 복잡한 법률 문서를 쉬운 말로 요약.
단, 법적 효력이 있는 판단은 반드시 전문가 검토 필요!
이런 서비스들을 직접 만들어서 재능넷 같은 플랫폼에서 프리랜서로 제공하면
꽤 괜찮은 수익을 올릴 수 있어! AI 개발 재능을 거래하는 시장이 점점 커지고 있거든 😎
API 비용이 걱정된다면? 걱정 ㄴㄴ! 최적화 방법이 있어.
| 전략 | 방법 | 절감 효과 |
|---|---|---|
| 🎯 모델 선택 | gpt-4o-mini 우선 사용, 복잡한 경우만 gpt-4o | 최대 97% 절감 |
| ✂️ 텍스트 전처리 | 불필요한 공백, HTML 태그 제거 후 API 호출 | 10~30% 절감 |
| 💾 캐싱 | 동일 텍스트 재요약 방지 (Redis, SQLite 활용) | 중복 요청 100% 절감 |
| 📏 프롬프트 최적화 | 시스템 프롬프트 간결하게 유지 | 5~15% 절감 |
| 🔢 배치 처리 | Batch API 사용 (비동기, 50% 할인) | 50% 절감 |
import hashlib
import sqlite3
import json
class SummaryCache:
"""SQLite 기반 요약 결과 캐싱"""
def __init__(self, db_path: str = "summary_cache.db"):
self.conn = sqlite3.connect(db_path, check_same_thread=False)
self._init_db()
def _init_db(self):
self.conn.execute("""
CREATE TABLE IF NOT EXISTS cache (
text_hash TEXT PRIMARY KEY,
mode TEXT,
summary TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
self.conn.commit()
def _hash(self, text: str, mode: str) -> str:
"""텍스트 + 모드의 해시값 생성"""
content = f"{mode}:{text}"
return hashlib.sha256(content.encode()).hexdigest()
def get(self, text: str, mode: str) -> str | None:
"""캐시에서 요약 결과 조회"""
key = self._hash(text, mode)
cursor = self.conn.execute(
"SELECT summary FROM cache WHERE text_hash = ?", (key,)
)
row = cursor.fetchone()
return row[0] if row else None
def set(self, text: str, mode: str, summary: str):
"""요약 결과를 캐시에 저장"""
key = self._hash(text, mode)
self.conn.execute(
"INSERT OR REPLACE INTO cache (text_hash, mode, summary) VALUES (?, ?, ?)",
(key, mode, summary)
)
self.conn.commit()
# 캐시 적용된 요약 함수
cache = SummaryCache()
def cached_summarize(text: str, mode: str = "general") -> tuple[str, bool]:
"""
캐시를 활용한 요약 함수
Returns:
(summary, from_cache) - 요약 결과와 캐시 여부
"""
# 캐시 확인
cached = cache.get(text, mode)
if cached:
print("⚡ 캐시에서 결과 로드 (API 호출 없음!)")
return cached, True
# API 호출
summary = smart_summarize(text, mode=mode)
# 캐시 저장
cache.set(text, mode, summary)
return summary, False
긴 요약을 생성할 때 결과가 다 나올 때까지 기다리면 UX가 별로잖아.
스트리밍(Streaming)을 쓰면 ChatGPT처럼 글자가 실시간으로 출력돼! 😎
def stream_summarize(text: str) -> str:
"""
스트리밍 방식으로 요약 결과를 실시간 출력
ChatGPT처럼 글자가 하나씩 나타나는 효과!
"""
print("📝 요약 생성 중...\n")
print("-" * 40)
full_response = ""
# stream=True로 스트리밍 활성화
with client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "당신은 전문 텍스트 요약 AI입니다."},
{"role": "user", "content": f"다음 텍스트를 요약해주세요:\n\n{text}"}
],
max_tokens=500,
temperature=0.3,
stream=True # 스트리밍 활성화!
) as stream:
for chunk in stream:
if chunk.choices[0].delta.content is not None:
content = chunk.choices[0].delta.content
print(content, end="", flush=True) # 실시간 출력
full_response += content
print("\n" + "-" * 40)
return full_response
# Flask/FastAPI 웹 서버에서 스트리밍 응답 예시
from flask import Flask, Response, request, stream_with_context
app = Flask(__name__)
@app.route('/summarize/stream', methods=['POST'])
def summarize_stream():
"""스트리밍 요약 API 엔드포인트"""
data = request.json
text = data.get('text', '')
def generate():
with client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "당신은 전문 텍스트 요약 AI입니다."},
{"role": "user", "content": f"다음 텍스트를 요약해주세요:\n\n{text}"}
],
stream=True
) as stream:
for chunk in stream:
if chunk.choices[0].delta.content:
yield f"data: {chunk.choices[0].delta.content}\n\n"
yield "data: [DONE]\n\n"
return Response(
stream_with_context(generate()),
mimetype='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no'
}
)
if __name__ == '__main__':
app.run(debug=True, port=5000)
① 환경 세팅: pip install openai + .env로 API 키 관리 (절대 코드에 직접 넣지 말 것!)
② 프롬프트가 핵심: 목적에 맞는 시스템 프롬프트 + 유저 프롬프트 조합이 퀄리티를 결정함
③ 긴 텍스트: tiktoken으로 토큰 계산 → 청크 분할 → Map-Reduce 계층적 요약
④ 비용 최적화: gpt-4o-mini 우선 사용 + 캐싱 + 텍스트 전처리로 비용 최소화
⑤ 실전 기능: 비동기 처리, 에러 재시도, 스트리밍, 다국어 지원으로 프로급 시스템 완성
⑥ 활용: 뉴스 모니터링, 논문 리뷰, 회의록 정리, 고객 리뷰 분석 등 무궁무진!
이 정도면 진짜 실전에서 쓸 수 있는 자동 요약 시스템을 만들 수 있어!
처음엔 기본 코드부터 시작해서 조금씩 기능을 추가해나가는 게 베스트야.
AI 개발 관련 재능을 키워서 재능넷에서 프리랜서로 활동하거나,
자신만의 SaaS 서비스로 발전시켜보는 것도 완전 현실적인 목표야! 💪
OpenAI API는 계속 업데이트되고 있으니까 공식 문서(platform.openai.com/docs)도
주기적으로 체크하는 습관을 들이면 더 좋아. 새 모델이나 기능이 자주 추가되거든!
자, 이제 직접 만들어봐~ 코드 짜다가 막히면 GPT한테 물어보면 되잖아ㅋㅋㅋ 🎉
댓글 작성
이 글에 대한 여러분의 생각을 들려주세요
로그인이 필요합니다
댓글을 작성하려면 먼저 로그인해주세요.
댓글 0
지식인의 숲 - 지적 재산권 보호 고지
지적 재산권 보호 고지
- 저작권 및 소유권: 본 컨텐츠는 재능넷의 독점 AI 기술로 생성되었으며, 대한민국 저작권법 및 국제 저작권 협약에 의해 보호됩니다.
- AI 생성 컨텐츠의 법적 지위: 본 AI 생성 컨텐츠는 재능넷의 지적 창작물로 인정되며, 관련 법규에 따라 저작권 보호를 받습니다.
- 사용 제한: 재능넷의 명시적 서면 동의 없이 본 컨텐츠를 복제, 수정, 배포, 또는 상업적으로 활용하는 행위는 엄격히 금지됩니다.
- 데이터 수집 금지: 본 컨텐츠에 대한 무단 스크래핑, 크롤링, 및 자동화된 데이터 수집은 법적 제재의 대상이 됩니다.
- AI 학습 제한: 재능넷의 AI 생성 컨텐츠를 타 AI 모델 학습에 무단 사용하는 행위는 금지되며, 이는 지적 재산권 침해로 간주됩니다.
아직 댓글이 없습니다.