프로젝트

ResourceExhausted

content0474 2025. 1. 21. 20:10

상황

챗봇코드와 cnn 크롤링 코드를 통합하여 크롤링 후 챗봇에 바로 기사를 넘기도록 함

 

오류 메시지

google.api_core.exceptions.ResourceExhausted: 429 Resource has been exhausted (e.g. check quota).

 

기존챗봇코드

class learnChat():
    model = genai.GenerativeModel("gemini-1.5-flash")
    chat = model.start_chat(history=[{'role':'user', 'parts':article.content}])
    # fetch Gemini API Key
    os.environ["GOOGLE_API_KEY"] = getpass("Gemini API Key:")

# create summary
    def Summary():
        summary=[]
        summary[0] = chat.send_message("입력된 내용을 영어로 요약해서 출력해줘. 요약문은 100자 이내여야 해.").text
        while len(summary)>400:
            summary[0] = chat.send_message("너무 길어, 더 줄여줘.").text
        summary[1] = chat.send_message("요약본을 한국어로 번역해줘").text
        return summary

# create vocab
    def vocab():
        prompt="""
        영문 요약본에서 적당한 난이도의 단어 3개만 찾아줘, 단어 옆에  한국어 뜻을 붙여줘. 단어와 뜻만 출력해. 
        예시: 
        collates 모으다
        Crucial 중요한
        Attributed 귀속된
        """
        response = chat.send_message(prompt)
        response=response.text.split('\n')
        response.pop()
        vocab={}
        for i in range(len(response)):
            v,m=response[i].split(maxsplit=1)
            vocab[v]=m
        return vocab

 

 

추정되는 원인

  1. CNN과 NYT 데이터를 처리하는 Celery 작업에서 챗봇 API를 호출할 때, 요청이 잦아 ResourceExhausted 오류발생
  2. 특히 요약과 번역 작업을 합쳐 실행하는 경우, 반복적인 요청으로 인해 Google Generative AI의 쿼터가 소진되는 것으로 추정

해결

  1. 요약과 번역을 별도의 함수로 분리
  2. 기존의 while len(summary[0]) > 400 루프를 제거하여 반복요청을 줄임
  3. time.sleep(5) 추가하여 요청간 간격 조정

수정한 챗봇코드

import google.generativeai as genai
import time
from django.conf import settings

genai.configure(api_key=settings.GEMINI_API_KEY)

class LearnChat:
    def __init__(self, article_content):
        self.model = genai.GenerativeModel("gemini-1.5-flash")
        self.chat = self.model.start_chat(history=[{'role': 'user', 'parts': article_content}])

    def summarize(self):
        """
        기사 내용을 영어로 요약하는 함수.
        """
        time.sleep(5)  # 요청 간 대기 시간
        return self.chat.send_message("입력된 내용을 핵심만 80자 이내로 영어로 요약해줘.").text

    def translate_to_korean(self, english_text):
        """
        영어 텍스트를 한국어로 번역하는 함수.
        """
        time.sleep(5)  # 요청 간 대기 시간
        return self.chat.send_message(f"'{english_text}'를 한국어로 번역해줘.").text

    def vocab(self, text):
        """
        영어 텍스트에서 어려운 단어 3개를 추출하고, 한국어 뜻과 함께 반환하는 함수.
        """
        prompt = f"""
        '{text}'에서 적당한 난이도의 단어 3개를 찾아줘. 단어와 한국어 뜻만 출력해.
        """
        response = self.chat.send_message(prompt)
        vocab = {}
        for line in response.text.split('\n'):
            if line.strip():
                word, meaning = line.split(maxsplit=1)
                vocab[word] = meaning
        return vocab

 

CNN 크롤링: 요약과 번역 모두

@shared_task
def fetch_and_store_cnn_news():
    categories = Category.objects.all()
    if not categories.exists():
        print("No categories found in the database.")
        return

    for category in categories:
        category_url = f"https://edition.cnn.com/{category.get_source_category(category.name, 'CNN')}"
        articles = scrape_cnn_news_with_selenium(category_url)

        if articles:
            for article in articles:
                chat = LearnChat(article['content'])
                summary_english = chat.summarize()
                summary_korean = chat.translate_to_korean(summary_english)
                vocab = chat.vocab(summary_english)

                redis_key = f"news:{category.name.lower()}:{article['url']}"
                redis_value = json.dumps({
                    'title': article['title'],
                    'abstract': article['content'],
                    'summary_english': summary_english,
                    'summary_korean': summary_korean,
                    'vocab': vocab,
                    'url': article['url'],
                    'category': category.name
                })
                redis_client.set(redis_key, redis_value, ex=86400)
                News.objects.update_or_create(
                    url=article['url'],
                    defaults={
                        'title': article['title'],
                        'abstract': article['content'],
                        'summary_english': summary_english,
                        'summary_korean': summary_korean,
                        'vocab': vocab,
                        'category': category
                    }
                )

 

 

NYT: 요약본이 주어지므로 번역만 시행

@shared_task
def fetch_and_store_nyt_news():
    categories = Category.objects.all()
    if not categories.exists():
        print("No categories found in the database.")
        return

    for category in categories:
        category_url = f"https://api.nytimes.com/svc/topstories/v2/{category.get_source_category(category.name, 'NYTimes')}.json"
        articles = get_nyt_articles(category_url)  # NYT 기사 수집 함수

        if articles:
            for article in articles:
                chat = LearnChat(article['abstract'])  # NYT의 abstract를 사용
                summary_korean = chat.translate_to_korean(article['abstract'])
                vocab = chat.vocab(article['abstract'])

                redis_key = f"news:{category.name.lower()}:{article['url']}"
                redis_value = json.dumps({
                    'title': article['title'],
                    'abstract': article['abstract'],
                    'summary_english': article['abstract'],  # NYT abstract 자체가 요약
                    'summary_korean': summary_korean,
                    'vocab': vocab,
                    'url': article['url'],
                    'category': category.name
                })
                redis_client.set(redis_key, redis_value, ex=86400)
                News.objects.update_or_create(
                    url=article['url'],
                    defaults={
                        'title': article['title'],
                        'abstract': article['abstract'],
                        'summary_english': article['abstract'],
                        'summary_korean': summary_korean,
                        'vocab': vocab,
                        'category': category
                    }
                )