Skip to content

Repository files navigation

freebuff2cloudflare-api

License: MIT

freebuff 무료 모델을 OpenAI 호환 API로 쓸 수 있게 해주는 Cloudflare Worker입니다. TypeScript 소스를 Wrangler가 하나의 Worker로 번들링하며, 별도 런타임 의존성 없이 배포됩니다.

주요 기능

  • 계정·모델별 한도 관측 — 인증된 GET /v1/accounts?refresh=1으로 Worker egress 기준 계정 tier와 DeepSeek Flash·Muse Spark의 upstream 한도 스냅샷을 확인합니다.
  • 나머지 모델도 정상 호출meta/muse-spark-1.2-contributorminimal ~ xhigh까지 공식 reasoning_effort를 지원합니다. 현재 배포 환경(미국 리전 고정)에서는 high, xhigh 등으로 실제 호출이 성공했습니다.
  • 미국 리전 고정 배포wrangler.toml[placement] region = "aws:us-west-1"로 Worker 실행 위치를 미국 서부 근처로 고정했습니다. freebuff 무료 모델이 미국 출구 IP를 요구하기 때문입니다.
  • 세션별 계정 고정 — 하나의 클라이언트 대화는 한 upstream 계정만 계속 사용합니다. 해당 계정이 실제 429를 반환할 때만 다음 계정으로 같은 요청을 재시도하고 바인딩을 이동합니다.
  • 소진 계정 회피 — upstream의 모델 사용량이 한도에 도달했거나 429 한도 초과를 반환한 계정·모델 조합은 45분 동안 제외합니다. 모든 후보가 소진되면 Worker는 HTTP 429Retry-After를 반환합니다.
  • 중복 토큰 자동 정리 — 같은 토큰을 두 번 넣어도 하나의 계정으로만 처리됩니다.
  • 살아 있는 세션 재사용 우선 — 세션은 보통 1시간 정도 유지되며 만들 때만 한도가 차감됩니다. 아직 유효한 세션이 있으면 같은 계정을 계속 쓰고, 없을 때만 다른 계정으로 옮겨 한도를 아납니다.
  • 광고 요청 흐름 모방 — 세션 확보 후 논리적 프롬프트당 공식 형식의 광고 요청을 한 번 보냅니다. 실패해도 채팅에는 영향이 없습니다.
  • 대화 ID 정합 — 같은 대화의 계정 바인딩, chat client_id, ads sessionId가 하나의 안정적인 UUID를 공유합니다.
  • Freebuff 스트림 복구 — tool call이 없는 응답이 reasoning 도중 끊기거나 reasoning만 남기고 끝나면 공식 CLI처럼 같은 계정·세션에서 최대 3회 이어서 요청합니다.
  • 전역 계정 세션 조정 — Durable Object가 모든 Worker isolate에서 같은 계정의 Freebuff session/run/chat을 직렬화하고, 유휴 10분 뒤 공식 CLI 종료처럼 upstream session을 DELETE합니다.
  • OpenAI 호환GET /v1/models, POST /v1/chat/completions을 스트리밍과 일반 응답 모두 지원합니다.
  • 헬스 체크GET /healthz는 인증 없이 호출할 수 있습니다.
  • TypeScript 모듈 — session/run, SSE 복구, message 정규화, Durable Object를 책임별 모듈로 나누고 strict typecheck를 적용합니다.
  • 전체 한국어 — 코드 주석, CLI 출력, 텔레그램 알림까지 모두 한국어입니다.

모델과 한도

한도는 모델·계정별로 다르며, 서버가 수시로 갱신합니다. 아래는 실측 기준 rateLimitsByModel에서 확인한 값입니다.

모델 한도
deepseek/deepseek-v4-flash 계정별 상이. limited 계정에서는 실측 6회/태평양일
mimo/mimo-v2.5 계정별 상이. upstream rateLimitsByModel로 확인
meta/muse-spark-1.2-contributor 계정마다 다름 — 어떤 계정은 6회/일, 어떤 계정은 제한 없음
z-ai/glm-5.2 레퍼럴 없이는 한도 0 (세션 생성 429)

한도는 태평양 시간 기준 하루 단위이며, 한국 시간으로는 보통 오후 4시쯤 리셋됩니다. 세션을 새로 만들 때만 차감됩니다.

전체 모델 목록

API 모델 이름 세션 모델 upstream agentId
deepseek/deepseek-v4-flash 동일 base2-free-deepseek-flash
deepseek/deepseek-v4-pro 동일 base2-free-deepseek
minimax/minimax-m3 동일 base2-free-minimax-m3
mimo/mimo-v2.5 동일 base2-free-mimo
openai/gpt-5.6-luna 동일 base2-free-luna
z-ai/glm-5.2 동일 base2-free-glm
poolside/laguna-s-2.1 동일 base2-free-laguna-s-2-1
openrouter/poolside/laguna-s-2.1 동일 base2-free-laguna-s-2-1-openrouter
inclusionai/ling-3.0-flash:free 동일 base2-free-ling-3-flash
crof/greg-2-ultra 동일 base2-free-greg-2-ultra
crof/greg-2-super 동일 base2-free-greg-2-super
anthropic/claude-fable-5 동일 base2-free-fable
meta/muse-spark-1.2-contributor 동일 base2-free-muse-spark

reasoning_effort (Muse Spark)

  • none은 지원하지 않습니다 (400 오류)
  • minimal, low, medium, high, xhigh만 공식에서 지원합니다
  • max, extreme, ultra는 공식에 없고 무시될 수 있습니다

참고: https://dev.meta.ai/docs/reasoning

빠르게 시작하기

  1. freebuff 토큰을 발급합니다 (아래 `FREEBUFF_TOKEN 발급` 참고)
  2. Worker를 배포합니다 (아래 `배포` 참고. 콘솔에 붙여넣거나 wrangler로 배포)
  3. Cloudflare 대시보드에서 변수를 설정합니다
    • FREEBUFF_TOKEN (필수)
    • FREEBUFF_API_KEY (선택, 비워두면 freebuff-default-key)
  4. OpenAI 호환 클라이언트에서 아래처럼 연결합니다
    • Base URL: https://<워커 주소>/v1
    • API Key: FREEBUFF_API_KEY에 넣은 값

헬스 체크

curl https://<워커 주소>/healthz
# {"status":"ok","version":"1.6.0","time":"..."}

인증 없이 호출할 수 있어 모니터링용으로 쓰기 좋습니다.

계정 권한·모델 한도 조회

인증된 계정 관측 endpoint입니다. 토큰은 끝 4자리만 표시됩니다.

# 현재 Worker isolate에 캐시된 상태만 반환. upstream 호출 없음.
curl -H "Authorization: Bearer <API_KEY>" \
  https://<워커 주소>/v1/accounts

# Worker egress에서 각 계정의 upstream GET /session을 실행해 상태를 새로 조회.
curl -H "Authorization: Bearer <API_KEY>" \
  'https://<워커 주소>/v1/accounts?refresh=1'

refresh=1 응답은 계정별 다음 데이터를 포함합니다.

  • upstream.access_tier: upstream 계정 권한 (full, limited 등)
  • upstream.status: free session 상태 (none, active 등)
  • upstream.country_code, upstream.country_block_reason: Worker egress 기준 upstream 지역/리스크 판정
  • models.deepseek/deepseek-v4-flash.rateLimitsEntry, models.meta/muse-spark-1.2-contributor.rateLimitsEntry: upstream 원본 한도 데이터 (limit, recentCount, resetAt 등)

rateLimitsEntry: null은 upstream이 해당 모델 한도를 이 응답에 싣지 않았다는 뜻입니다. 무제한을 보장하는 표시는 아닙니다. refresh=1은 세션을 만들거나 모델을 호출하지 않지만, 활성 free session의 상태를 조회하므로 운영 중인 대화와 겹치지 않을 때만 실행하세요.

FREEBUFF_TOKEN 발급

freebuff_tools/extract_freebuff.py를 씁니다. 파이썬 표준 라이브러리만 있으면 됩니다.

cd freebuff_tools
python3 extract_freebuff.py login   # 인증 주소가 나오면 브라우저에서 열고 구글 로그인, 이후 자동으로 토큰 저장
python3 extract_freebuff.py show    # 저장된 토큰 확인 (마스킹되어 표시)
python3 extract_freebuff.py tgsend  # 텔레그램 연결 테스트 (선택)

토큰은 freebuff_tools/freebuff_credentials.json에 저장됩니다. 이 파일은 깃에 올리지 마세요. login은 기본적으로 이메일의 @ 앞부분을 프로필 레이블로 사용하며, session --label <레이블>, chat --label <레이블>, quota --label <레이블>로 특정 계정을 선택할 수 있습니다.

GitHub Actions로 원격 발급 (권장 — 미국 IP로 받으면 tier가 달라질 수 있음)

이 저장소에는 이미 워크플로가 포함되어 있습니다 (.github/workflows/extract-token.yml).

필요한 준비물

  1. 텔레그램에서 @BotFather에게 /newbot을 보내 봇을 만든 뒤 HTTP API 토큰을 받습니다
  2. @freebuff_token_bot(방금 만든 봇)을 열고 /start를 보낸 뒤, 터미널에서 curl "https://api.telegram.org/bot<토큰>/getUpdates"chat.id를 확인합니다
  3. 저장소의 Settings → Secrets and variables → Actions에서 두 secret을 넣습니다
    • TG_BOT_TOKEN: 봇 토큰
    • TG_CHAT_ID: 숫자 chat id

실행

Actions → Freebuff authToken 발급 → Run workflow → Run을 누르면 GitHub의 미국 러너에서 인증 절차가 시작됩니다. 텔레그램 봇 채팅으로 인증 링크가 오면, 꼭 새 구글 계정으로 로그인하세요. 같은 구글 계정으로 다시 로그인하면 같은 토큰이 다시 발급될 수 있습니다. 인증이 끝나면 새 토큰이 텔레그램으로 옵니다.

  • 텔레그램 봇 토큰을 채팅에 그대로 올리면 즉시 유출로 간주됩니다. 확인 뒤 @BotFather에서 /revoke로 재발급하세요.
  • 실제 토큰을 채팅에 붙여넣지 마세요.

배포

방법 A: Cloudflare 콘솔에 붙여넣기 (권장)

  1. https://dash.cloudflare.com 에서 Workers & Pages로 이동한 뒤 이 GitHub 저장소를 연결합니다.
  2. Build command는 비워 두고 deploy command를 npx wrangler deploy로 설정합니다. Wrangler가 src/worker.ts와 import된 TypeScript 모듈을 하나의 Worker 번들로 만듭니다.
  3. Settings, Variables and Secrets에서 Add를 눌러 아래 값을 넣습니다
    • FREEBUFF_TOKEN
    • FREEBUFF_API_KEY (선택)
  4. 배포가 잘 됐는지 확인합니다
curl https://<워커 주소>/healthz
curl https://<워커 주소>/v1/models -H "Authorization: Bearer <API_KEY>"

방법 B: wrangler CLI

npm i -g wrangler
npx wrangler login
npm install
npm run typecheck
cp .env.example .dev.vars  # FREEBUFF_TOKEN 입력
npm run dev                # 로컬에서 테스트
npm run deploy             # 배포
npx wrangler secret put FREEBUFF_TOKEN
npx wrangler secret put FREEBUFF_API_KEY

Placement (미국 고정 — 지연 실측으로 고정)

wrangler.toml에 아래 설정이 추가되어 있습니다.

[placement]
region = "aws:us-west-1"

freebuff 무료 모델은 미국 출구 IP를 요구합니다. Cloudflare Workers는 기본적으로 미국 쪽으로 나가지만, 이 설정을 넣으면 실행 위치 자체를 미국 서부(N. California) 근처로 고정해 지연을 줄일 수 있습니다.

북미 6개 리전을 실제로 배포해가며 실측한 결과 (서울에서)

리전 median healthz
aws:us-west-2 (Oregon) 0.308초
aws:us-west-1 (N. California) 0.326초 — 편차 최소
gcp:us-west1 0.319초
gcp:us-central1 0.335초
gcp:us-east4 0.315초
aws:us-east-1 (Virginia 동부, 이전 기본값) 0.382초
  • 서부 리전이 동부 대비 50~75ms 빠릅니다
  • aws:us-west-1이 편차가 가장 작아 최종 고정했습니다
  • mode = "smart"는 북미가 아닌 곳으로 튈 수 있어 쓰지 않았습니다
  • chat 스모크(deepseek-v4-flash)는 6/6 리전 모두 성공했습니다

관련 문서: https://developers.cloudflare.com/workers/configuration/placement/

커스텀 도메인

*.workers.dev 접속이 막힌 환경이라면 Worker에 본인 도메인을 연결한 뒤 Base URL을 https://api.내도메인/v1 형태로 바꾸면 됩니다.

호출 예시

curl https://<워커 주소>/v1/chat/completions \
  -H "Authorization: Bearer <API_KEY>" -H "Content-Type: application/json" \
  -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"안녕"}],"reasoning_effort":"high"}'

curl -N https://<워커 주소>/v1/chat/completions \
  -H "Authorization: Bearer <API_KEY>" -H "Content-Type: application/json" \
  -d '{"model":"meta/muse-spark-1.2-contributor","messages":[{"role":"user","content":"증명해줘"}],"reasoning_effort":"xhigh","stream":true}'

여러 계정으로 쓰기

FREEBUFF_TOKENtoken1,token2처럼 쉼표로 구분해 넣으면 됩니다. 각 대화는 첫 요청에서 선택된 한 계정에 24시간 동안 고정됩니다. 그 계정이 upstream 429를 반환할 때만 다음 계정으로 같은 요청을 재시도하고, 성공한 계정을 이후 요청에도 계속 사용합니다. 428/409는 같은 계정에서 세션만 재생성하며 timeout·5xx·기타 오류 때문에 계정을 바꾸지는 않습니다.

클라이언트가 x-freebuff-session-id, x-session-id, x-client-session-id 중 하나를 보내면 그 값을 대화 키로 사용합니다. 별도 ID가 없는 OpenAI 호환 클라이언트는 첫 user 메시지에서 안정적인 대화 키를 계산합니다.

성공 응답에는 운영 진단용 X-Freebuff-Session-Key, X-Freebuff-Account-Tail 헤더가 포함됩니다. 429 때문에 계정이 이동한 요청에는 X-Freebuff-Failover: 이전끝4자->새끝4자도 포함됩니다.

중복으로 넣어도 무해합니다. 같은 토큰을 두 번 넣어도 내부에서 하나의 계정으로만 처리됩니다.

계정을 추가하거나 교체한 뒤에는 GET /v1/accounts?refresh=1로 각각의 token_tail, access_tier, refresh_errors를 확인하세요. 401 unauthorized가 반환되는 토큰은 매 요청의 실패 비용만 늘리므로 FREEBUFF_TOKENFREEBUFF_USER_IDS 양쪽에서 제거해야 합니다.

무제한/한도 계정이 섞였을 때 (muse-spark)

muse-spark는 계정마다 한도가 다릅니다 — 어떤 계정은 6회/일, 어떤 계정은 한도 항목 자체가 없습니다. 현재 풀은 3계정 모두 6회로 동일하지만, 이전에는 중복 토큰으로 한 계정이 두 번 보이며 실제로는 한도만 공유되는 상태가 생겼고, 또 6회 계정이 먼저 선택되어 바로 한도에 걸리면 무제한 계정은 나중에야 선택되는 문제가 있었습니다. 지금은 같은 토큰은 Set으로 중복을 제거하고, 한 계정이 429 한도 초과로 거부되면 그 모델에 대해 소진으로 기억해 두고 다음 요청부터는 소진되지 않은 계정을 먼저 선택합니다 (45분 유지).

계정이 full/limited로 보이는 차이

처음 로컬에서 발급받은 토큰은 세션 조회에서 accessTier: limited였고, GitHub Actions 미국 러너에서 새로 발급받은 토큰은 full로 표시되었습니다. freebuff가 가입/로그인 시점의 출구 IP(리전)에 따라 등급을 매기는 것으로 보입니다. 한국 IP와 미국 IP에서 같은 절차로 받아도 tier가 달랐습니다.

추가로, 처음에는 muse-sparklimited 계정에서 session_model_mismatch로 거부되었고, 같은 토큰을 미국 출구 Worker에 그대로 두면 정상 동작했습니다. 한국 로컬과 미국 Worker의 차이가 실제 호출에도 반영됩니다.

레퍼럴과 GLM 5.2

레퍼럴 코드 (FREEBUFF_TOKEN과 함께 오는 referral/streak 정보)는 현재 z-ai/glm-5.2의 한도를 여는 데 주로 관여합니다. 레퍼럴 없이는 limit 0으로 세션 생성 429가 납니다. muse-spark, deepseek, mimo의 한도는 레퍼럴로 크게 늘어나지 않습니다.

내부 동작

세션 생성 -> agent-runs (root START + context-pruner의 로컬 untracked id) -> chat/completions

이 전체 과정을 Worker가 처리합니다. upstream에서 바이트 단위로 검증하는 You are Buffy, the strategic coding assistant. 접두사도 자동으로 붙입니다. /v1/models는 upstream을 조회하지 않고 목록을 그대로 돌려줍니다. 한 계정에서 동시에 세션을 하나만 쓸 수 있어, 조회가 진행 중인 대화를 방해할 수 있기 때문입니다.

끊겼을 때 재시도

중간에 끊기는 원인은 대부분 upstream codebuff.com의 free 채널 불안정(동시 1 초과 시 queued 타임아웃 — 최대 8회×1.5초 폴링, 428 waiting_room_required, 세션 만료 409 등)입니다. 세션 만료 428/409는 바인딩된 같은 계정의 sessCache를 비우고 강제 재생성해 1회 재시도합니다. 계정별 뮤텍스와 300ms 간격으로 같은 계정의 upstream 요청을 직렬화하며, 스트리밍 응답 본문이 끝날 때까지 해당 계정 락을 유지합니다. 계정 전환은 upstream 429에서만 일어납니다. 다른 계정에서도 429가 반환되면 마지막 upstream 429 body와 Retry-After를 클라이언트로 전달합니다. timeout·5xx·기타 오류는 현재 대화의 계정 바인딩을 유지한 채 그대로 반환합니다.

스트림이 finish_reason 없이 끝나거나 reasoning만 출력하고 length/stop으로 종료되면 Worker가 이미 받은 assistant reasoning을 history에 넣고 공식 recovery prompt를 추가해 같은 계정에서 최대 3회 재개합니다. tool-call delta는 arguments JSON이 완성될 때까지 Worker가 버퍼링합니다. 미완성 상태에서 끊기면 client에 노출되지 않았으므로 안전하게 재개하고, 완성된 call은 한 번에 정확히 한 번만 전달합니다. 완성 call을 전달한 뒤에는 도구 이중 실행을 막기 위해 자동 재개하지 않습니다.

agent-runs는 사용자 turn마다 새 START/FINISH 한 쌍을 사용합니다. 내부 recovery 요청은 원래 turn의 run_id를 유지하며, 정상 완료는 completed, 429·upstream 오류·복구 실패는 failed, client 취소는 cancelled 상태와 error message로 FINISH합니다.

Durable Object 조정

ConversationRouter는 대화별 clientId와 계정 token을 원자적으로 저장합니다. 동시에 들어온 첫 요청도 같은 대화라면 하나의 계정만 선택되며, 429 failover는 기존 token이 예상 계정일 때만 compare-and-set으로 이동합니다.

AccountCoordinator는 Freebuff token을 그대로 계정 식별자로 사용해 계정 하나당 하나씩 존재하며 최대 30초 동안 FIFO에 가까운 lease 대기를 제공합니다. lease가 있는 동안 다른 대화는 기존 upstream session을 빼앗지 않습니다. stream 본문과 FINISH가 끝난 뒤 lease를 반환하고, 마지막 사용 후 10분 동안 새 요청이 없으면 alarm에서 DELETE /api/v1/freebuff/session을 전송합니다. 모델이 바뀌면 새 lease를 잡은 뒤 기존 session을 먼저 DELETE하고 새 모델 session을 생성합니다.

Durable Object binding이 없는 로컬 개발 환경에서는 기존 isolate-local mutex와 메모리 route로 자동 fallback합니다.

라이선스

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages