μ¬μ©μ μκΈμ¨λ₯Ό κΈ°λ°μΌλ‘ ν°νΈλ₯Ό μλ μμ±νλ νμ΄νλΌμΈ μλ²μ λλ€.
- FastAPI κΈ°λ° API ν μ€νΈ μλ²
- AWS SQS κΈ°λ° μλν νμ΄νλΌμΈ
- νκ΅μ΄ μκΈμ¨ ν°νΈ μλ μμ±
- μμΈ λ‘κΉ λ° μ€λ₯ μ²λ¦¬
- AWS S3 νμΌ μλ μ²λ¦¬ (μ λ‘λ/λ€μ΄λ‘λ)
μ΄ νλ‘μ νΈλ λ κ°μ§ λ°©μμΌλ‘ λμν©λλ€:
-
FastAPI μλ² (ν μ€νΈ μ©λ):
- ν°νΈ μμ± κΈ°λ₯λ§ μ 곡
- λ‘컬 ν μ€νΈ λ° κ°λ° νκ²½μμ μ¬μ©
-
AWS SQS κΈ°λ° νμ΄νλΌμΈ:
- SQS νλ₯Ό μ§μμ μΌλ‘ ν΄λ§νλ©° λ©μμ§ μμ λκΈ°
- λ©μμ§ μμ μ μλμΌλ‘ ν°νΈ μμ± νμ΄νλΌμΈ μμ
- S3μμ ν νλ¦Ώ λ€μ΄λ‘λ
- ν°νΈ μμ±
- μμ±λ ν°νΈ λ° λ‘κ·Έ νμΌ S3 μ λ‘λ
- μ²λ¦¬ μλ£ ν SQS λ©μμ§ μλ μμ
-
S3 ν νλ¦Ώ λ€μ΄λ‘λ - AWS S3μ μ μ₯λ ν νλ¦Ώμ λ€μ΄λ‘λ (SQS λͺ¨λμμλ§ μ€ν) ν νλ¦Ώ μμ
-
κΈλ¦¬ν ν¬λ‘ - μμ±λ λ¬Έμ μ΄λ―Έμ§λ₯Ό κ°λ³ κΈλ¦¬νλ‘ μΆμΆ (Docker 컨ν μ΄λλ‘ μ€ν)
μ λ‘λλ μ΄λ―Έμ§ μ€μ μΆμΆν λΆλΆ 

-
μΆλ‘ μ€ν - λ₯λ¬λ λͺ¨λΈμ μ¬μ©ν κΈλ¦¬ν μμ± (Docker 컨ν μ΄λλ‘ μ€ν)
-
JPG β SVG λ³ν - λΉνΈλ§΅ μ΄λ―Έμ§λ₯Ό λ²‘ν° νμμΌλ‘ λ³ν (Docker 컨ν μ΄λλ‘ μ€ν)
-
SVG β TTF/WOFF λ³ν - λ²‘ν° κΈλ¦¬νλ₯Ό ν°νΈ νμΌλ‘ λ³ν (Docker 컨ν μ΄λλ‘ μ€ν)
-
S3 μ λ‘λ - μμ±λ ν°νΈ λ° κ²°κ³Όλ¬Όμ AWS S3μ μ λ‘λ (SQS λͺ¨λμμλ§ μ€ν)
Screen.Recording.2025-11-13.at.14.13.33.mp4
μ°Έκ³ : S3 μ°κ³(ν νλ¦Ώ λ€μ΄λ‘λ λ° κ²°κ³Όλ¬Ό μ λ‘λ)λ₯Ό μ μΈν λͺ¨λ νμ΄νλΌμΈ λ¨κ³λ Docker 컨ν μ΄λλ‘ μ€νλ©λλ€. κ° λ¨κ³λ λ 립μ μΈ Docker 컨ν μ΄λμμ μ€νλλ©°, μ€κ° κ²°κ³Όλ¬Όμ νΈμ€νΈ μμ€ν μ 곡μ λ³Όλ₯¨μ ν΅ν΄ μ λ¬λ©λλ€.
μ΄ νλ‘μ νΈλ νκ΅μ΄ κΈκΌ΄ μμ±μ μν΄ DM-FONT λͺ¨λΈμ μ¬μ©ν©λλ€. λͺ¨λΈ νμΌ(체ν¬ν¬μΈνΈ)μ λ€μ μμΉμ λ°°μΉν΄μΌ ν©λλ€:
inference/resources/checkpoints/
βββ last.pth # λͺ¨λΈ 체ν¬ν¬μΈνΈ νμΌ
λͺ¨λΈ νμΌμ λ°°μΉν νμ νμ΄νλΌμΈμ΄ μ¬λ°λ₯΄κ² λμν©λλ€.
- Python 3.8 μ΄μ
- Docker
- pip
- Ubuntu 20.04 LTS μ΄μ (κΆμ₯)
- NVIDIA GPU: μ΅μ 8GB VRAM (κΆμ₯ 12GB μ΄μ, μΆλ‘ λͺ¨λΈ μ€νμ©)
pipeline/ # νλ‘μ νΈ λ£¨νΈ λλ ν 리
β
βββ crop/ # μ΄λ―Έμ§ ν¬λ‘ κ΄λ ¨ μ½λ
βββ jpg2svg/ # JPG to SVG λ³ν κ΄λ ¨ μ½λ
βββ make_template/ # ν
νλ¦Ώ μμ± κ΄λ ¨ μ½λ
βββ svg2ttf/ # SVG to TTF λ³ν κ΄λ ¨ μ½λ
βββ inference/ # λͺ¨λΈ μΆλ‘ κ΄λ ¨ μ½λ
β βββ resources/checkpoints/
β βββ last.pth # λͺ¨λΈ 체ν¬ν¬μΈνΈ νμΌ
β
βββ scripts/ # νμ΄νλΌμΈ λ¨κ³λ³ μ€ν μ€ν¬λ¦½νΈ
β
βββ fastAPI/ # FastAPI μ ν리μΌμ΄μ
μ½λ
β βββ config.py # μ€μ κ΄λ¦¬
β βββ main.py # μλ² μ§μ
μ
β βββ models.py # λ°μ΄ν° λͺ¨λΈ μ μ
β βββ s3_utils.py # S3 κ΄λ ¨ μ νΈλ¦¬ν°
β βββ sqs_utils.py # SQS κ΄λ ¨ μ νΈλ¦¬ν°
β βββ prometheus_loki/ # Prometheus λ° Loki λͺ¨λν°λ§ μ€μ
β β βββ compose.yml # λͺ¨λν°λ§ μλΉμ€ Docker Compose νμΌ
β β βββ prometheus.config # Prometheus μ€μ νμΌ
β β βββ prometheus_api.py # Prometheus API ν΅ν© μ½λ
β β βββ prometheus_config.py # Prometheus μ€μ κ΄λ¦¬
β βββ .env # νκ²½ λ³μ μ€μ νμΌ
β
βββ resource/ # νλ‘μ νΈ λ¦¬μμ€ νμΌ
βββ written/ # μ¬μ©μ μμ± μ΄λ―Έμ§ μ
λ ₯
βββ log/ # μ€ν λ‘κ·Έ νμΌ
β
βββ result/ # νμ΄νλΌμΈ κ²°κ³Ό λλ ν 리
β βββ 1_cropped/ # ν¬λ‘λ κΈλ¦¬ν
β βββ 2_inference/ # μΆλ‘ κ²°κ³Ό
β βββ 3_svg/ # SVG λ³ν κ²°κ³Ό
β βββ 4_fonts/ # μ΅μ’
ν°νΈ νμΌ
β
βββ reference_chars.txt # ν°νΈ μμ±μ© μ°Έμ‘° λ¬Έμ νμΌ
βββ run_server.sh # μλ² μ€ν μ€ν¬λ¦½νΈ
βββ stop_server.sh # μλ² μ€μ§ μ€ν¬λ¦½νΈ
βββ test_request.py # μλ² ν
μ€νΈ μ€ν¬λ¦½νΈ
μ΄ νλ‘μ νΈλ AWS μλΉμ€μμ μ°λμ μν΄ νκ²½ λ³μλ₯Ό μ¬μ©ν©λλ€. νλ‘μ νΈ λ£¨νΈμ fastAPI λλ ν 리 λ΄μ .env νμΌμ μμ±νκ³ λ€μ λ³μλ€μ μ€μ ν΄μΌ ν©λλ€:
AWS_REGION=your_aws_region
AWS_ACCESS_KEY=your_aws_access_key
AWS_SECRET_KEY=your_aws_secret_key
QUEUE_URL=your_sqs_queue_url
FONT_BUCKET_NAME=your_font_bucket_name
FONT_CREATE_LOG_BUCKET_NAME=your_log_bucket_name
FONT_ENG_NAME=μλ¬Έ ν°νΈλͺ
(μ: "MyHandwriting")
CDN_URL=μ΄λ―Έμ§ CDN λ² μ΄μ€ URL (μ: "https://cdn.example.com/")AWS_REGION: μ¬μ©νλ AWS 리μ (μ:ap-northeast-2)AWS_ACCESS_KEY: AWS IAM μ¬μ©μμ μ‘μΈμ€ ν€ IDAWS_SECRET_KEY: AWS IAM μ¬μ©μμ λΉλ° μ‘μΈμ€ ν€QUEUE_URL: ν°νΈ μμ± μμ²μ μ²λ¦¬ν SQS νμ URLFONT_BUCKET_NAME: μμ±λ ν°νΈ νμΌμ μ λ‘λν S3 λ²ν· μ΄λ¦FONT_CREATE_LOG_BUCKET_NAME: λ‘κ·Έ νμΌμ μ λ‘λν S3 λ²ν· μ΄λ¦FONT_ENG_NAME: μλ¬Έ ν°νΈλͺ (μ: "MyHandwriting")CDN_URL: μ΄λ―Έμ§ CDN λ² μ΄μ€ URL (μ: "https://cdn.example.com/")
AWS IAM μ¬μ©μλ λ€μ κΆνμ΄ νμν©λλ€:
-
SQS κ΄λ ¨ κΆν:
sqs:ReceiveMessage- νμμ λ©μμ§λ₯Ό λ°μμ€λ κΆνsqs:DeleteMessage- μ²λ¦¬ μλ£λ λ©μμ§λ₯Ό μμ νλ κΆν
-
S3 κ΄λ ¨ κΆν:
s3:PutObject- μμ±λ ν°νΈ νμΌ(.ttf, .woff)κ³Ό λ‘κ·Έ νμΌμ μ λ‘λνλ κΆν- λ²ν· μ μ±
μ λ°λΌ λ€μ κ²½λ‘μ λν μ
λ‘λ κΆν νμ:
[FONT_BUCKET_NAME]/fonts/*- ν°νΈ νμΌ μ μ₯ κ²½λ‘[FONT_CREATE_LOG_BUCKET_NAME]/logs/*- λ‘κ·Έ νμΌ μ μ₯ κ²½λ‘
-
ν νλ¦Ώ μ΄λ―Έμ§ μ κ·Όμ±:
- ν νλ¦Ώ μ΄λ―Έμ§κ° μ μ₯λ S3 λ²ν·/κ°μ²΄λ 곡κ°μ μΌλ‘ μ κ·Ό κ°λ₯ν΄μΌ ν©λλ€.
- λλ SQS λ©μμ§μ
templateURLνλμ μ ν¨ν 미리 μλͺ λ URL(pre-signed URL)μ μ 곡ν΄μΌ ν©λλ€. - μ½λλ
urllib.request.urlretrieveλ₯Ό μ¬μ©νμ¬ HTTP URLμ ν΅ν΄ μ§μ λ€μ΄λ‘λνλ―λ‘ S3 μΈμ¦μ΄ νμνμ§ μμ΅λλ€.
μ΄λ¬ν κΆνμ΄ μλ IAM μ¬μ©μμ ACCESS_KEYμ SECRET_KEYλ₯Ό μ λ ₯ν΄μΌ ν©λλ€.
chmod +x ./scripts/*
chmod +X ./*.sh
./scripts/0_generate_template.shμ°Έκ³ : μ΄ λ¨κ³λ ν μ€νΈμ© APIλ₯Ό μ¬μ©ν λλ§ νμν©λλ€. SQS λ°©μμμλ S3μμ ν νλ¦Ώμ μλμΌλ‘ λ€μ΄λ‘λνλ―λ‘ μ΄ λ¨κ³λ₯Ό 건λλΈ μ μμ΅λλ€.
μμμ μμ±λ ν
νλ¦Ώμ λ€μ΄λ°κ³ μκΈμ¨λ‘ μμ±λ μ΄λ―Έμ§ νμΌ(.jpg) μ ./written λλ ν 리μ μ μ₯ν©λλ€.
./run_server.shμλ² μ€ν μ λ€μ μμ μ΄ μνλ©λλ€:
- νμν λλ ν 리 ꡬ쑰 μμ±
- Python κ°μ νκ²½ μ€μ
- μμ‘΄μ± ν¨ν€μ§ μ€μΉ
- Prometheus λ° Loki λͺ¨λν°λ§ μλΉμ€ μμ (Docker Compose μ¬μ©)
- FastAPI μλ² μ€ν
λ‘컬 API μλ²λ₯Ό ν΅ν΄ ν°νΈ μμ±μ ν μ€νΈν μ μμ΅λλ€. μ΄ λ°©μμ ν°νΈ μμ±λ§ μννλ©° S3 μ λ‘λλ ν¬ν¨νμ§ μμ΅λλ€.
# ν
μ€νΈ μ€ν¬λ¦½νΈ μ¬μ©
python test_request.py MyCustomFont
# λλ curl μ¬μ©
curl -X POST "http://localhost:8000/font" \
-H "Content-Type: application/json" \
-d '{
"fontId": "231",
"memberId": "213123",
"fontName": "ν°νΈνκΈμ΄λ¦",
"fontEngName": "testFontNameEng",
"templateURL": "https://....",
"author": "author",
"requestUUID": "550e8400-e29b-41d4-a716-446655440000"
}'AWS SQS νμμ λ©μμ§λ₯Ό λ°μμ νμ΄νλΌμΈμ μ€νν©λλ€. μ΄ λ°©μμ ν νλ¦Ώ λ€μ΄λ‘λ + ν°νΈ μμ± + ν°νΈ λ° λ‘κ·Έ S3 μ λ‘λλ₯Ό λͺ¨λ μνν©λλ€.
AWS CLI νΉμ AWS μ½μμ ν΅ν΄ μ§μ SQSμ λ©μμ§λ₯Ό λ³΄λΌ μ μμ΅λλ€. .env νμΌμ μ€μ λ QUEUE_URLμ μ¬μ©ν΄μΌ ν©λλ€.
(μ°Έκ³ : AWS CLIλ₯Ό μ¬μ©νλ €λ©΄ AWS μ격 μ¦λͺ
μ€μ μ΄ νμν©λλ€. aws configure λͺ
λ Ήμ΄λ νκ²½ λ³μ λ±μ ν΅ν΄ μ€μ ν μ μμ΅λλ€.)
aws sqs send-message --queue-url YOUR_SQS_QUEUE_URL \
--message-body '{
"memberId": "213123",
"author": "author",
"fontId": "231",
"fontName": "ν°νΈνκΈμ΄λ¦",
"fontEngName": "testFontNameEng"
"templateURL": "https://....",
"requestUUID": "550e8400-e29b-41d4-a716-446655440000"
}' \
--message-group-id MyFontGroupYOUR_SQS_QUEUE_URL:.envνμΌμ μ€μ ν SQS ν URLλ‘ λ³κ²½ν΄μΌ ν©λλ€.--message-body: ν°νΈ κ΄λ ¨ μ 보λ₯Ό ν¬ν¨νλ JSON νμμ λ©μμ§ λ³Έλ¬Έμ λλ€.--message-group-id: FIFO νμ κ²½μ° λ©μμ§ κ·Έλ£Ή IDκ° νμν©λλ€. λμΌν κ·Έλ£Ή ID λ΄μμλ λ©μμ§ μμκ° λ³΄μ₯λ©λλ€. ν°νΈ μ΄λ¦μ΄λ μ¬μ©μ ID λ± μ μ ν κ°μ μ¬μ©ν©λλ€.
λ€μ μλ²λ₯Ό λͺ λ ΉμΌλ‘ μ€μ§ν μ μμ΅λλ€:
./stop_server.shμ΄ λͺ λ Ήμ΄λ λ€μ μμ μ μνν©λλ€:
- Prometheus λ° Loki λͺ¨λν°λ§ μλΉμ€ μ€μ§ (Docker Compose μ¬μ©)
- ν¬νΈ 8000μμ μ€ν μ€μΈ FastAPI μλ² νλ‘μΈμ€ μ’ λ£
μ΄ νλ‘μ νΈλ μ ν리μΌμ΄μ λͺ¨λν°λ§μ μν΄ Prometheusμ Lokiλ₯Ό ν΅ν©νμ΅λλ€:
- λ©νΈλ¦ μμ§ λ° λͺ¨λν°λ§μ μν μ€νμμ€ μμ€ν
- ν¬νΈ 9090μμ μ κ·Ό κ°λ₯ (http://localhost:9090/prometheus)
- API μμ² μ, μλ΅ μκ°, μ€λ₯μ¨ λ±μ λ©νΈλ¦ μμ§
- λ‘κ·Έ μ§κ³ μμ€ν
- ν¬νΈ 3100μμ μ κ·Ό κ°λ₯
- μ ν리μΌμ΄μ λ‘κ·Έλ₯Ό μ€μ μ§μ€μμΌλ‘ μ μ₯ λ° μ‘°ν κ°λ₯
λͺ¨λν°λ§ μλΉμ€λ Docker Composeλ₯Ό ν΅ν΄ κ΄λ¦¬λλ©°, run_server.sh λ° stop_server.sh μ€ν¬λ¦½νΈμ ν΅ν©λμ΄ μμ΅λλ€.
μ°Έκ³ : Prometheusμ Lokiλ Grafanaμ λ°μ΄ν° μμ€λ‘ μΆκ°νμ¬ μ¬μ©ν μ μμ΅λλ€. Grafanaμμ Prometheus(9090 ν¬νΈ)μ Loki(3100 ν¬νΈ)λ₯Ό λ°μ΄ν° μμ€λ‘ λ±λ‘νλ©΄ λ©νΈλ¦κ³Ό λ‘κ·Έ λ°μ΄ν°λ₯Ό μκ°ννκ³ λͺ¨λν°λ§ λμ보λλ₯Ό ꡬμ±ν μ μμ΅λλ€.
ν μ€νΈμ© λ‘컬 API μλν¬μΈνΈλ‘, ν°νΈ μμ±λ§ μνν©λλ€. S3 μ λ‘λλ ν¬ν¨νμ§ μμ΅λλ€.
μμ² λ³Έλ¬Έ:
{
"fontId": "231",
"memberId": "213123",
"fontName": "ν°νΈνκΈμ΄λ¦",
"templateURL": "https://....",
"author": "author",
"fontEngName": "testFontNameEng",
"requestUUID": "550e8400-e29b-41d4-a716-446655440000"
}μλ΅:
{
"message": "ν°νΈ 'testFontName' μμ± μλ£",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"log_file": "./log/550e84_213123_231_testFontName.log",
"output_ttf": "./result/4_fonts/testFontName.ttf",
"output_woff": "./result/4_fonts/testFontName.woff"
}SQS νμ λ©μμ§λ₯Ό μ μ‘νλ©΄ μμ ν νμ΄νλΌμΈ(ν νλ¦Ώ λ€μ΄λ‘λ, ν°νΈ μμ±, S3 μ λ‘λ)μ΄ μ€νλ©λλ€.
λ©μμ§ νμ:
{
"memberId": "213123",
"author": "author",
"fontId": "231",
"fontName": "ν°νΈνκΈμ΄λ¦",
"templateURL": "https://....",
"fontEngName": "testFontNameEng",
"requestUUID": "550e8400-e29b-41d4-a716-446655440000"
}μ²λ¦¬ κ²°κ³Ό:
- ν νλ¦Ώ λ€μ΄λ‘λ (templateURLμμ)
- ν°νΈ νμΌ μμ± (.ttf, .woff)
- μμ±λ ν°νΈ λ° λ‘κ·Έ νμΌ S3 μ λ‘λ
- μλ£ μ S3μ λ€μ νμΌλ€μ΄ μ
λ‘λλ©λλ€:
[FONT_BUCKET_NAME]/fonts/[fontId].ttf[FONT_BUCKET_NAME]/fonts/[fontId].woff[FONT_CREATE_LOG_BUCKET_NAME]/logs/[fontId].log
μ°Έκ³ : μ²λ¦¬ κ³Όμ μμ μ€λ₯κ° λ°μνλλΌλ λ‘κ·Έ νμΌμ S3μ μ λ‘λλ©λλ€.
Swagger UI λ¬Έμ μ κ·Ό URL (λ‘컬 API μλ² μ€ν μ):
http://localhost:8000/docs
κ° μμ²μ κ³ μ IDμ μ¬μ©μ μ λ³΄κ° ν¬ν¨λ λ‘κ·Έ νμΌμ κΈ°λ‘λ©λλ€:
./log/[short-requestUUID]_[memberId]_[fontId]_[fontName].log
μμ: ./log/550e84_213123_231_testFontName.log
SQS λͺ¨λμμλ λ‘κ·Έ νμΌμ΄ λ‘컬μ μ μ₯λ ν S3μλ μ λ‘λλ©λλ€. S3μ μ λ‘λλ λλ λ€μ νμμ μ¬μ©ν©λλ€:
[FONT_CREATE_LOG_BUCKET_NAME]/[fontId].log
μμ: font_log_bucket/231.log
SQS μ²λ¦¬κ° μλ£λλ©΄ λ‘컬 λ‘κ·Έ νμΌκ³Ό S3μ μ λ‘λλ λ‘κ·Έ νμΌ λͺ¨λ μ¬μ© κ°λ₯ν©λλ€.
