OpenSource-Hub

screenshot-to-code

애플리케이션

abi/screenshot-to-code

스크린샷과 디자인 시안을 깔끔한 코드로 변환하는 AI 도구.

개요

Screenshot-to-Code는 AI 모델을 활용해 스크린샷, 디자인 시안, 화면 녹화를 실행 가능한 코드로 변환하며, HTML, React, Vue 등의 프론트엔드 프레임워크를 지원합니다. 스크린샷에서 실제 에셋을 추출할 수 있고, 다양한 모델 제공업체를 지원합니다. 이 프로젝트는 React 프론트엔드와 FastAPI 백엔드로 구성되어 있으며, 로컬에 배포하거나 공식 호스팅 서비스를 이용할 수 있습니다.

README 미리보기

# screenshot-to-code\n\nConvert screenshots, mockups, Figma designs, and screen recordings into clean, functional code using AI. The easiest way to try this is using the official, hosted product at screenshottocode.com →\n\n\nhttps://github.com/user-attachments/assets/ec08a5e6-9606-41c5-b03a-1bf47dfeba75\n\n\nSupported stacks:\n\n- HTML + Tailwind\n- HTML + CSS\n- React + Tailwind\n- Vue + Tailwind\n- Bootstrap\n- Ionic + Tailwind\n\nDefault AI models:\n\n- Gemini 3 Flash Preview and Gemini 3.1 Pro Preview - the best models\n- GPT-5.5 and GPT-5.4 Mini\n- Claude Opus 4.6, Claude Opus 4.8\n- z-image-turbo (using Replicate) for image generation\n\nSee the [Examples](#-examples) section below for more demos.\n\nScreenshot to Code also supports taking a screen recording of a website in action and turning that into a functional prototype.\n\n\n\n## 🛠 Getting Started\n\nChoose the path that fits what you want to do:\n\n- **Run locally:** best if you want to customize, self-host, or contribute.\n- **Use the hosted app:** the fastest way to try Screenshot to Code with no local setup. Open the hosted app →\n\nRunning locally requires API keys and a backend/frontend setup. The app has a React/Vite frontend and a FastAPI backend.\n\n### API keys\n\nYou need **at least one** model provider key (OpenAI, Anthropic, or Gemini).\n**Gemini and Replicate are strongly recommended for the best quality of\nscreenshot-to-code accuracy** — Gemini powers asset extraction (reusing the\nreal logos/images from your screenshot) and Replicate powers image\ngeneration, background removal, and image editing. Adding all four keys gives\nthe best results and lets you compare multiple models per generation.\n\n| Key | Required? | What it unlocks |\n|-----|-----------|-----------------|\n| `OPENAI_API_KEY` | One of these three | GPT code-gen variants (GPT-5.5, GPT-5.4 Mini) |\n| `ANTHROPIC_API_KEY` | One of these three | Claude code-gen variants (Opus 5, Opus 4.8, Fable 5, Sonnet 4.6) |\n| `GEMINI_AP

FAQ (5)

문제 해결
Starlette WebSocket 크래시 해결 방법: 비정상 종료 코드 1006 이후 발생하는 RuntimeError "Unexpected ASGI message 'websocket.close'"?

이슈 #599에 대한 수정이 포함된 최신 릴리스로 업그레이드하세요. 임시 해결 방법으로 이전 메이저 버전으로 다운그레이드하세요. 코드를 패치하려면 Starlette에서 WebSocketDisconnect를 임포트하고 WebSocketCommunicator.close()와 throw_error()가 이미 닫힌 상태를 처리하도록 하세요. 예를 들면 다음과 같습니다:

from starlette.websockets import WebSocketDisconnect

try:
    await ws_comm.close()
except (
    ConnectionClosedOK,
    ConnectionClosedError,
    WebSocketDisconnect,
    RuntimeError,
):
    pass

throw_error()에도 동일한 예외 처리를 적용하세요. 이렇게 하면 uvicorn이 이미 연결을 닫은 후에 finally 블록이 또 다른 websocket.close ASGI 메시지를 전송하는 것을 방지할 수 있습니다. 이 크래시는 Python 3.11, uvicorn 0.25.0, Starlette 0.41.3 및 websockets 14.1에서 관찰되었습니다.

원본 Issue #599
문제 해결
스트리밍 중 예외가 발생할 때 AsyncAnthropic 커넥션 풀 고갈 또는 커넥션 누수 문제를 해결하려면 어떻게 해야 하나요?

클라이언트 수명 주기를 try/finally로 감싸서 스트리밍 또는 세션 초기화가 실패하더라도 close()가 실행되도록 하세요:

client = AsyncAnthropic(api_key=api_key)
try:
    # streaming / session logic
    ...
finally:
    await client.close()

또는 클라이언트를 비동기 컨텍스트 매니저로 사용하세요:

async with AsyncAnthropic(api_key=api_key) as client:
    # streaming logic
    ...

동일한 패턴을 AsyncOpenAI와 stream_claude_response 및 stream_claude_response_native 모두에 적용하세요. 정리를 하지 않으면 예외 발생 시 HTTP 연결이 열린 상태로 남아, 장기 실행 서비스에서 연결 풀을 고갈시킬 수 있습니다.

원본 Issue #534
문제 해결
OpenAI 모델을 찾을 수 없음, 유효하지 않은 API 키 또는 rate limit 오류로 인해 screenshot-to-code 코드 생성이 실패하는 문제를 어떻게 해결하나요?

정확한 OpenAI 오류를 파악하려면 먼저 백엔드 로그를 확인하세요:

docker compose logs backend --tail=100
# 또는
docker logs <container_id>

일반적인 해결 방법:

1. **API 키가 유효하지 않거나 누락됨:** 환경 변수 또는 .env 파일에 OPENAI_API_KEY가 올바르게 설정되어 있는지 확인한 후 컨테이너를 재시작하세요.
2. **모델을 찾을 수 없거나 사용할 수 없음:** generate_code.py가 gpt-4o-2024-11-20과 같이 날짜가 지정된 모델로 고정되어 있다면, OpenAI 계정에서 사용 가능한 모델(예: gpt-4o 또는 gpt-4)로 변경하세요.
3. **속도 제한 또는 계정 제한:** OpenAI 결제/사용량 대시보드를 확인하고 요청 빈도를 줄이거나 속도 제한이 초기화될 때까지 기다리세요.
4. **구성 변경 후 재시작:** docker compose down && docker compose up --build를 실행하세요.

영구적인 해결을 위해서는 generate_code.py에 명시적인 OpenAI API 오류 처리를 추가하여 인증, 속도 제한, 모델을 찾을 수 없음 오류가 조용히 실패하는 대신 표시되도록 하세요.

원본 Issue #506
문제 해결
Poetry가 typing-extensions 4.12.2를 설치할 때 "All attempts to connect to pypi.org failed" 오류로 실패하는 이유는 무엇인가요?

이 문제는 typing-extensions 패키지의 문제가 아니라 네트워크/DNS/프록시 문제입니다. PowerShell에서 먼저 연결을 테스트하세요:

Resolve-DnsName pypi.org
Invoke-WebRequest https://pypi.org/simple/ -UseBasicParsing
poetry install -v

로컬 프록시 뒤에 있는 경우, Poetry를 실행하기 전에 프록시를 설정하세요(포트는 사용 중인 프록시 포트로 바꾸세요):

$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
poetry install

네트워크에서 PyPI가 차단된 경우, 임시로 미러를 사용하세요:

$env:POETRY_PYPI_MIRROR_URL = "https://pypi.tuna.tsinghua.edu.cn/simple/"
poetry install

또한 VPN/방화벽 소프트웨어를 비활성화하거나 재구성한 후 poetry install을 다시 실행해 보세요.

원본 Issue #520
문제 해결
OpenAI SDK를 사용할 때 발생하는 DeepSeek API 오류 "Failed to deserialize the JSON body into target type: messages[1] ... ChatCompletionRequestContent"를 해결하는 방법은?

이 422 오류는 messages[1].content가 DeepSeek에서 허용하지 않는 형식을 사용한다는 의미입니다. DeepSeek는 OpenAI와 호환되지만, OpenAI의 멀티모달 콘텐츠 파트 배열을 허용하지 않을 수 있습니다. 대신 메시지 content를 일반 텍스트 문자열로 보내세요.

실패한 메시지를 확인하세요:

import json
print(json.dumps(params["messages"][1], ensure_ascii=False, indent=2))

API를 호출하기 전에 콘텐츠 배열을 텍스트로 변환하세요:

def normalize_deepseek_messages(messages):
    for message in messages:
        content = message.get("content")

        if isinstance(content, list):
            message["content"] = "".join(
                part.get("text", "")
                for part in content
                if isinstance(part, dict) and part.get("type") == "text"
            )
        elif content is None:
            message["content"] = ""

    return messages

params["messages"] = normalize_deepseek_messages(params["messages"])
stream = await client.chat.completions.create(**params)

또한 image_url 또는 input_audio와 같은 지원되지 않는 파트는 제거하고 DeepSeek의 텍스트/채팅 형식만 사용하세요. 에이전트 프레임워크를 사용하는 경우 비전/멀티모달 메시지 형식을 비활성화하거나 일반 텍스트 OpenAI 호환 메시지를 강제로 사용하세요.

원본 Issue #488