FastAPI와 Gemini를 사용해 크레딧 기반 AI 웹사이트 빌더 구축기
요약
본 글은 FastAPI와 Gemini를 활용하여 크레딧 기반의 AI 웹사이트 빌더 구축 과정을 설명합니다. 핵심적으로, 모델 출력 형식에 대한 엄격한 검증 과정과 데이터베이스 트랜잭션을 이용한 원자적 크레딧 관리 시스템을 구현하는 방법을 다룹니다.
핵심 포인트
- Gemini 호출 후에는 반드시 HTML 클리닝 및 유효성 검사 단계를 거쳐야 합니다.
- 크레딧 차감은 '확인(check)'과 '감소(decrement)'를 하나의 원자적 DB 작업으로 처리해야 경쟁 조건이 없습니다.
- 결제는 먼저 크레딧을 사용하고, 실패 시에는 반드시 환불하는 로직을 구현해야 사용자 경험을 보호할 수 있습니다.
AI 웹사이트 빌더가 요즘 어디에나 있습니다. 하지만 거의 모든 것이 임대하는 플랫폼입니다. 사용자, 브랜드, 가격 책정은 다른 사람의 것입니다.
저는 정반대를 원했습니다. 프리랜서나 에이전시가 자신들의 이름으로 직접 운영하고 비용을 청구할 수 있는 작은 AI 웹사이트 빌더 말이죠. 그 프로젝트가 Talivo가 되었습니다. 이 포스트에서는 아키텍처와 그 배경이 된 결정들을 설명하겠습니다. 코드 스니펫은 아이디어를 보여주기 위해 단순화되었지만, 중요한 것은 패턴입니다.
라이브 데모 사용하기 (무료 Gemini 키를 가져오세요. 첫 로드는 무료 서버가 깨어나는 동안 약 30초가 걸립니다).
목표는 다음과 같습니다:
사용자가 가입하고,
단계 1: 프롬프트로 전체 웹사이트 생성하기
핵심은 신중하게 작성된 시스템 지침을 사용하여 Gemini에 단 한 번 호출하는 것입니다. 요령은 출력 형식에 대해 매우 명시적으로 지정하는 것입니다. 즉, 마크다운 울타리(markdown fences)가 없고 설명도 없는, 자체 포함적인 HTML 파일 하나여야 합니다.
from google import genai
client = genai.Client(api_key=GEMINI_API_KEY)
...
엄격한 프롬프트를 사용하더라도 모델은 때때로 출력물을 어쨌든 코드 울타리 안에 넣는 경우가 있습니다. 그래서 HTML은 항상 작은 정리 단계를 거칩니다:
import re
def clean_html(text: str) -> str:
...
```
{% endraw %}
html ...
{% raw %}
``` fences if the model added them
text = re.sub(r"^```(?:html)?\s*|\s*```$", "", text)
if "<html" not in text.lower():
raise ValueError("Model did not return an HTML document")
return text
배운 교훈: 모델의 출력 형식을 절대 신뢰하지 마세요. 검증하고, 잘못된 응답은 실패한 생성으로 간주하세요 (이것이 왜 중요한지에 대해서는 아래에서 더 다룰 것입니다).
단계 2: 음수가 될 수 없는 크레딧 시스템
이 부분이 데모를 유료 서비스로 전환시키는 부분입니다. 순진한 버전은 다음과 같습니다:
# ❌ 이렇게 하지 마세요
user = get_user(user_id)
if user.credits > 0:
...
동일 사용자의 두 번의 빠른 요청이 모두 credits = 1을 읽고, 둘 다 검사를 통과하여 무료 생성을 제공하게 됩니다. 해결책은 확인(check)과 감소(decrement)를 하나의 원자적 데이터베이스 작업으로 만드는 것입니다:
def spend_credit(db, user_id: int) -> bool:
cur = db.execute(
"UPDATE users SET credits = credits - 1 "
...
rowcount가 0이면 사용자는 크레딧이 없었다는 뜻이고 아무것도 변경되지 않습니다. 경쟁 조건(race condition)도 없고, 음수 잔액도 없습니다.
두 번째 규칙: 먼저 청구하고, 실패 시 환불하기. Gemini 호출은 시간 초과되거나 쓰레기 같은 것을 반환할 수 있으며, 사용자가 아무것도 얻지 못했는데 비용을 지불하면 (정당하게) 짜증이 납니다.
@app.post("/generate")
def generate(req: GenerateRequest, user=Depends(current_user)):
if not spend_credit(db, user.id):
...
단계 3: 인증 (Auth), 일부러 지루하게 유지하기
인증은 제가 창의성을 제로로 만들고 싶었던 부분입니다. 사용자는 이메일과 비밀번호로 등록하고, 비밀번호는 해시(plain text가 아닌) 형태로 저장되며, 모든 보호된 경로는 위에서 본 current_user와 같은 FastAPI 의존성(dependency)을 거칩니다. Depends()를 사용한다는 것은 크레딧과 관련된 모든 엔드포인트가 사용자 정보를 알아야 한다는 의미입니다. 이 확인 절차를 잊어서는 안 됩니다.
단계 4: 관리자 패널 (The admin panel)
관리자 패널은 의도적으로 단순합니다: 사용자 목록, 그들의 잔액, 그리고 크레딧을 추가하는 방법이 있습니다.
제가 투명하게 밝히고 싶은 디자인 선택 사항이 있습니다. Talivo는 내장된 카드 결제 기능을 포함하지 않습니다. 소유자가 관리자 패널에서 수동으로 크레딧을 충전합니다. 이것은 제한처럼 들릴 수 있고 (어떤 사람들에게는 실제로 그렇습니다), 하지만 v1에서는 의도적이었습니다:
운영자는 원하는 방식으로 요금을 부과할 수 있습니다: 결제 링크, 송장(invoice), 은행 송금, 지역 고객에게 현금 등입니다.
결제 제공업체에 종속되지 않으며 플랫폼 수수료가 없습니다.
에이전시들은 어차피 크레딧을 더 큰 클라이언트 거래에 묶어서 판매하는 경우가 많습니다.
전체 소스 코드가 포함되어 있으므로, 자동으로 크레딧 팩을 추가하려면 Stripe를 연결하는 것이 필요로 하는 모든 사람에게 자연스러운 다음 단계입니다.
단계 5: 비개발자도 설치 가능하게 만들기
대상 구매자는 항상 개발자가 아니기 때문에, 설치는 가능한 한 '더블 클릭'에 가깝게 해야 했습니다. Windows에서는 install.bat 스크립트가 가상 환경을 생성하고, 의존성을 설치하며, 서버를 시작합니다. macOS, Linux 또는 모든 서버의 경우 일반적인 Python 3.10+ 설정입니다. 사용자가 가져와야 할 유일한 것은 Gemini API 키입니다.
AI 래퍼(wrapper) 제품을 구축하는 사람이라면 누구에게든 해주고 싶은 말
AI 호출 자체는 쉬운 부분입니다. 크레딧 관리, 인증(auth), 실패 처리, 그리고 설치 과정에서 가장 많은 작업량(그리고 가장 큰 가치)이 발생합니다.
사용자 입력처럼 모델 출력을 검증하세요. 예상외일 겁니다.
처음부터 결제 시스템을 원자적(atomic)으로 만드세요. 크레딧에 대한 경쟁 조건(race conditions)은 실제 돈과 관련됩니다.
실패 시 환불 기능을 제공하세요. 비용은 거의 들지 않지만 신뢰도를 크게 높여줍니다.
사람들이 실제로 사용할 수 있는 데모를 출시하세요. 스크린샷으로는 개발자들을 설득할 수 없습니다. 작동하는 URL이 설득합니다.
직접 사용해 보세요
라이브 데모: demo-talivo.onrender.com (사용자의 무료 Gemini 키를 사용하세요; 저장되지 않습니다)
📦 전체 소스 코드 받기: Talivo on Gumroad, 출시 가격 €49.99에 일회성 구매
피드백을 받고 싶습니다. 특히 크레딧 또는 사용량 기반 결제 시스템을 구축해 본 분들의 의견이 좋습니다. 다음으로 무엇을 추가할까요: Stripe 크레딧 팩, 여러 AI 제공업체 지원, 아니면 원클릭 클라우드 배포 기능일까요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기