Skip to content

[WIP] Remove retry logic from chat API for 429 errors#4

Merged
redsunjin merged 1 commit intomainfrom
copilot/remove-retry-logic-in-chat-api
Mar 6, 2026
Merged

[WIP] Remove retry logic from chat API for 429 errors#4
redsunjin merged 1 commit intomainfrom
copilot/remove-retry-logic-in-chat-api

Conversation

Copy link
Contributor

Copilot AI commented Mar 6, 2026

  • Understand the current code in api/chat.js and index.html
  • Replace callGeminiWithRetry in api/chat.js with a simple single-request handler that returns 429 immediately
  • Replace the retry while-loop in index.html's handleInquiryStep with a simple try/catch that handles 429 with a friendly Korean message
Original prompt

문제

현재 api/chat.jsindex.html 양쪽 모두에서 재시도 로직이 있어서, Gemini API 429(Too Many Requests) 에러 발생 시 최대 9번까지 연속 요청이 발생하는 문제가 있습니다.

수정 사항

1. api/chat.js 수정

  • 기존 callGeminiWithRetry 함수(3번 재시도)를 제거
  • 429 에러를 즉시 클라이언트에 429 상태코드로 반환 (재시도 없음)
  • 단순하고 명확한 단일 요청 구조로 변경
// api/chat.js - Vercel Serverless Function
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';

const SYSTEM_INSTRUCTION = `당신은 Gov-Tech AI 에이전시 '라이트닝(Lightning)'의 전문 AI 컨설턴트입니다. 사용자(공공기관/대기업 담당자)가 프로젝트 아이디어나 요구사항을 말하면, 이를 '라이트닝'의 핵심 역량(전자정부프레임워크 준수, 72시간 내 프로토타이핑, 보안 규정 준수, 2주 내 런칭)을 바탕으로 분석하여 답변하세요. 답변은 전문적이고 신뢰감 있게 하되, 핵심 기술(AI, 모바일, 웹 익스텐션)을 어떻게 활용할지 구체적으로 제안하세요. 답변은 한국어로 작성하며, 중요한 키워드는 **굵게** 표시하세요. 너무 길지 않게 핵심 위주로 답변하세요. 사용자의 요구사항이 충분히 파악되었다고 판단되면(또는 3~4번의 대화 이후), 반드시 응답 마지막에 정확히 "[INQUIRY_COMPLETE]" 라는 태그를 포함하세요.`;

module.exports = async function handler(req, res) {
  res.setHeader('Access-Control-Allow-Origin', 'https://flashgta-github-io.vercel.app');
  res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

  if (req.method === 'OPTIONS') return res.status(200).end();
  if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' });

  const apiKey = process.env.GEMINI_API_KEY;
  if (!apiKey) return res.status(500).json({ error: 'GEMINI_API_KEY not configured' });

  const { contents } = req.body;
  if (!contents || !Array.isArray(contents)) return res.status(400).json({ error: 'Invalid request body' });

  try {
    const response = await fetch(`${GEMINI_API_URL}?key=${apiKey}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        contents,
        systemInstruction: { parts: [{ text: SYSTEM_INSTRUCTION }] }
      })
    });

    if (response.status === 429) {
      return res.status(429).json({ error: 'Too many requests. Please wait a moment.' });
    }

    if (!response.ok) {
      const errBody = await response.text();
      throw new Error(`HTTP ${response.status}: ${errBody}`);
    }

    const data = await response.json();
    return res.status(200).json({ text: data.candidates[0].content.parts[0].text });

  } catch (error) {
    console.error('Gemini API error:', error);
    return res.status(500).json({ error: 'Failed to get AI response' });
  }
};

2. index.html 수정 (handleInquiryStep 함수)

index.htmlhandleInquiryStep 함수에서 재시도 while 루프를 제거하고, 429 에러에 대한 친절한 한국어 메시지를 표시하도록 변경합니다.

기존 코드 (260~292번 줄):

let aiText = null;
let retryCount = 0;
const maxRetries = 3;

while (retryCount < maxRetries) {
    try {
        const response = await fetch('/api/chat', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ contents: conversationHistory })
        });

        if (!response.ok) throw new Error(`HTTP ${response.status}`);

        const data = await response.json();
        aiText = data.text;
        break;

    } catch (err) {
        retryCount++;
        if (retryCount < maxRetries) {
            hideTyping();
            appendMessage(`잠시 후 재시도 중... (${retryCount}/${maxRetries})`, 'ai');
            await new Promise(r => setTimeout(r, Math.pow(2, retryCount - 1) * 1000));
            showTyping();
        } else {
            hideTyping();
            appendMessage('현재 AI 응답이 지연되고 있습니다. 잠시 후 다시 시도해주세요.', 'ai');
            conversationHistory.pop();
            return;
        }
    }
}

변경 후:

let aiText = null;

try {
    const response = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ contents: conversationHistory })
    });

    if (response.status === 429) {
        hideTyping();
        appendMessage('요청이 너무 많습니다. 잠시 후 다시 시도해주세요. 🙏', 'ai');
        conversationHistory.pop();
        return;
    }

    if (!response.ok) throw new Error(`HTTP ${response.status}`);

    const data = await response.json();
    aiText = data.text;

} catch (err) {
    hideTyping();
    appendMessage('현재 AI 응답이 지연되고 있습니다. 잠시 후 다시 시도해주세요.', 'ai');
    conversationHistory.pop();
    return;
}

기대 효과

  • 429 에러 발생 시 재시도 없이 즉시 사용자에게 안내 메시지 표시
  • Gemini API 요청 횟수 대폭 감소
  • 사용자에게 429 전용 친절한 한국어 안내 메시지 제공

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@vercel
Copy link

vercel bot commented Mar 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flashgta-github-io Ready Ready Preview, Comment Mar 6, 2026 4:39pm

@redsunjin redsunjin marked this pull request as ready for review March 6, 2026 16:40
@redsunjin redsunjin merged commit 089de61 into main Mar 6, 2026
2 of 3 checks passed
Copilot stopped work on behalf of redsunjin due to an error March 6, 2026 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants