--- title: SmartEyeSsen Backend emoji: "๐Ÿ”" colorFrom: blue colorTo: green sdk: docker app_port: 7860 pinned: false --- # SmartEyeSsen Backend > FastAPI ยท MySQL ยท DocLayout-YOLO ๊ธฐ๋ฐ˜ AI ๋ฌธ์„œ ๋ถ„์„ ๋ฐฑ์—”๋“œ ## ๐Ÿ“š ๋ชฉ์ฐจ - [ํ”„๋กœ์ ํŠธ ๊ฐœ์š”](#-ํ”„๋กœ์ ํŠธ-๊ฐœ์š”) - [๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ](#-๋””๋ ‰ํ„ฐ๋ฆฌ-๊ตฌ์กฐ) - [์‹คํ–‰ ๋ชจ๋“œ](#-์‹คํ–‰-๋ชจ๋“œ) - [ํ™˜๊ฒฝ ๋ณ€์ˆ˜](#-ํ™˜๊ฒฝ-๋ณ€์ˆ˜) - [๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค & Docker ๊ตฌ์„ฑ](#-๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค--docker-๊ตฌ์„ฑ) - [FastAPI ๋ชจ๋“ˆ ๊ตฌ์„ฑ](#-fastapi-๋ชจ๋“ˆ-๊ตฌ์„ฑ) - [ํ…Œ์ŠคํŠธ & ์Šคํฌ๋ฆฝํŠธ](#-ํ…Œ์ŠคํŠธ--์Šคํฌ๋ฆฝํŠธ) - [์ž์ฃผ ๋ฌป๋Š” ๋ฌธ์ œ](#-์ž์ฃผ-๋ฌป๋Š”-๋ฌธ์ œ) - [์ฐธ๊ณ  ์ž๋ฃŒ](#-์ฐธ๊ณ -์ž๋ฃŒ) --- ## ๐ŸŽฏ ํ”„๋กœ์ ํŠธ ๊ฐœ์š” - PDF/์ด๋ฏธ์ง€ ์—…๋กœ๋“œ โ†’ **DocLayout-YOLO + Tesseract**๋กœ ๋ ˆ์ด์•„์›ƒ๊ณผ ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœํ•˜๊ณ , **OpenAI Vision**์œผ๋กœ ๋„ํ‘œยทํ‘œ ์„ค๋ช…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. - ๊ฒฐ๊ณผ๋ฌผ์€ **SmartEye ์ •๋ ฌ ๊ทœ์น™**์„ ๊ฑฐ์ณ ํ”„๋กœ์ ํŠธ/ํŽ˜์ด์ง€/์š”์†Œ ๋‹จ์œ„๋กœ ์ €์žฅ๋˜๋ฉฐ, **DOCX** ๋‹ค์šด๋กœ๋“œ๊นŒ์ง€ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. - ์šด์˜ ํ™˜๊ฒฝ์€ DigitalOcean Droplet์—์„œ `docker-compose.prod.yml`์„ ํ†ตํ•ด **MySQL + Backend + Frontend + Certbot** ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. --- ## ๐Ÿ—‚ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ ``` Backend/ โ”œโ”€โ”€ app/ โ”‚ โ”œโ”€โ”€ main.py # FastAPI ์—”ํŠธ๋ฆฌํฌ์ธํŠธ โ”‚ โ”œโ”€โ”€ database.py # ์„ธ์…˜/์—”์ง„, MySQL ์—ฐ๊ฒฐ โ”‚ โ”œโ”€โ”€ models.py # SQLAlchemy ORM โ”‚ โ”œโ”€โ”€ schemas.py # Pydantic v2 ์Šคํ‚ค๋งˆ โ”‚ โ”œโ”€โ”€ crud.py # DB ์ ‘๊ทผ ํ—ฌํผ โ”‚ โ”œโ”€โ”€ routers/ # ํ”„๋กœ์ ํŠธ/ํŽ˜์ด์ง€/๋ถ„์„/๋‹ค์šด๋กœ๋“œ ๋ผ์šฐํ„ฐ โ”‚ โ””โ”€โ”€ services/ # OCRยท๋ ˆ์ด์•„์›ƒยท์ •๋ ฌยทAI ์„ค๋ช… ๋ชจ๋“ˆ โ”œโ”€โ”€ scripts/ โ”‚ โ”œโ”€โ”€ init_db_complete.sql # 12๊ฐœ ํ…Œ์ด๋ธ” + ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ โ”‚ โ””โ”€โ”€ reset_db.sh (์˜ต์…˜) # ๊ฐœ๋ฐœ์šฉ ์ดˆ๊ธฐํ™” ์Šคํฌ๋ฆฝํŠธ โ”œโ”€โ”€ uploads/, static/ # ์—…๋กœ๋“œ/์ •์  ๊ฒฐ๊ณผ (์ปจํ…Œ์ด๋„ˆ ๋ณผ๋ฅจ ์—ฐ๊ฒฐ) โ”œโ”€โ”€ Dockerfile # ๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ ํ”„๋กœ๋•์…˜ ์ด๋ฏธ์ง€ โ”œโ”€โ”€ docker-compose.yml # ๋ฐฑ์—”๋“œ ๋‹จ๋… MySQL ์ปจํ…Œ์ด๋„ˆ โ”œโ”€โ”€ requirements.txt # Python ์˜์กด์„ฑ โ””โ”€โ”€ README.md # ๋ณธ ๋ฌธ์„œ ``` --- ## โš™ ์‹คํ–‰ ๋ชจ๋“œ ### 1. ๋กœ์ปฌ ๊ฐœ๋ฐœ (venv + Uvicorn) ```bash cd Backend python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt cp .env.example .env uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` ํ•„์š” ์‹œ `OPENAI_API_KEY`๋ฅผ `.env`์— ์„ค์ •ํ•˜๋ฉด AI ์„ค๋ช… ๊ธฐ๋Šฅ์ด ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ### 2. ๋ฐฑ์—”๋“œ ์ „์šฉ Docker Compose (MySQL ํฌํ•จ) `Backend/docker-compose.yml`์€ MySQL 8.0 ์ปจํ…Œ์ด๋„ˆ๋งŒ ๋„์›Œ FastAPI๋ฅผ ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ```bash cd Backend docker compose up -d # smart_mysql ์ปจํ…Œ์ด๋„ˆ ์‹œ์ž‘ (๊ธฐ๋ณธ ํฌํŠธ 3308โ†’3306) uvicorn app.main:app --reload ``` ์ข…๋ฃŒ ๋˜๋Š” ์ดˆ๊ธฐํ™”: ```bash docker compose down # ์ปจํ…Œ์ด๋„ˆ๋งŒ ์ข…๋ฃŒ docker compose down -v # smart_mysql_data ๋ณผ๋ฅจ๊นŒ์ง€ ์‚ญ์ œ (โš  ์ „์ฒด ๋ฐ์ดํ„ฐ ์‚ญ์ œ) ``` ### 3. ํ”„๋กœ๋•์…˜ Docker Compose (์ „์ฒด ์Šคํƒ) ๋ฃจํŠธ `docker-compose.prod.yml`์˜ `backend` ์„œ๋น„์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ```yaml backend: build: context: ./Backend dockerfile: Dockerfile env_file: - Backend/.env environment: DB_HOST: mysql DB_PORT: 3306 ENVIRONMENT: production volumes: - ./Backend/uploads:/app/uploads - ./Backend/static:/app/static depends_on: mysql: condition: service_healthy ``` ๋ฐฐํฌ ์‹œ ์„œ๋ฒ„์—์„œ: ```bash git checkout main && git pull --ff-only origin main docker compose -f docker-compose.prod.yml build backend docker compose -f docker-compose.prod.yml up -d --force-recreate backend ``` --- ## ๐Ÿ” ํ™˜๊ฒฝ ๋ณ€์ˆ˜ `.env.example`์„ ๊ธฐ๋ฐ˜์œผ๋กœ `.env`๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. | ๋ณ€์ˆ˜ | ์„ค๋ช… | ๋น„๊ณ  | |------|------|------| | `DB_HOST`, `DB_PORT` | MySQL ์ ‘์† ์ •๋ณด | Docker ์‚ฌ์šฉ ์‹œ `mysql`/`3306`์œผ๋กœ ์ž๋™ override | | `DB_USER`, `DB_PASSWORD`, `DB_NAME` | DB ๊ณ„์ • | ์ดˆ๊ธฐ ์Šคํฌ๋ฆฝํŠธ ๊ธฐ๋ณธ๊ฐ’: root / change_this_password / smarteyessen_db | | `DATABASE_URL` | SQLAlchemy ์ ‘์† URL | ๋ณ€๊ฒฝ ๋ถˆํ•„์š” (ํ…œํ”Œ๋ฆฟ ์ž๋™ ์กฐํ•ฉ) | | `API_HOST`, `API_PORT` | FastAPI ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธ/ํฌํŠธ | ๊ธฐ๋ณธ `0.0.0.0:8000` | | `ENVIRONMENT` | `development` / `production` | Compose์—์„œ `production`์œผ๋กœ ๊ฐ•์ œ | | `OPENAI_API_KEY` | ์„ ํƒ ํ•ญ๋ชฉ | ์—†์œผ๋ฉด AI ์„ค๋ช… ๋น„ํ™œ์„ฑํ™” | | `UPLOAD_DIR`, `MAX_FILE_SIZE`, `ALLOWED_EXTENSIONS` | ์—…๋กœ๋“œ ์„ค์ • | ๊ธฐ๋ณธ 100 MB, jpg/jpeg/png/pdf | | `SECRET_KEY`, `ALGORITHM` | JWT/๋ณด์•ˆ ์˜ต์…˜ | ํ•„์š” ์‹œ ์—…๋ฐ์ดํŠธ | | `USE_ADAPTIVE_SORTER`, `PDF_PROCESSOR_DPI` ๋“ฑ | ํŒŒ์ดํ”„๋ผ์ธ ๋™์ž‘ ์ œ์–ด | `.env.example` ์ฐธ๊ณ  | --- ## ๐Ÿณ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค & Docker ๊ตฌ์„ฑ ### Backend/docker-compose.yml (๋กœ์ปฌ MySQL) | ํ•ญ๋ชฉ | ๊ฐ’ | |------|----| | ์ด๋ฏธ์ง€ | `mysql:8.0` | | ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„ | `smart_mysql` | | ํฌํŠธ | ํ˜ธ์ŠคํŠธ `${MYSQL_PORT:-3308} โ†’ 3306` | | ๋ณผ๋ฅจ | `smart_mysql_data:/var/lib/mysql` (Named Volume) | | ์ดˆ๊ธฐํ™” | `./scripts/init_db_complete.sql` โ†’ `/docker-entrypoint-initdb.d/01_init.sql` | | ๋ฌธ์ž์…‹ | `utf8mb4 / utf8mb4_unicode_ci` | | ํ—ฌ์Šค์ฒดํฌ | `mysqladmin ping` (10์ดˆ ๊ฐ„๊ฒฉ, 5ํšŒ ์žฌ์‹œ๋„) | ### Backend/Dockerfile (ํ”„๋กœ๋•์…˜ ์ด๋ฏธ์ง€) 1. **Builder ๋‹จ๊ณ„ (python:3.9-slim)** - Tesseract(ko/en), OpenCV ์˜์กด ํŒจํ‚ค์ง€ ์„ค์น˜ - `pip install -r requirements.txt` + `doclayout-yolo` 2. **Runtime ๋‹จ๊ณ„ (python:3.9-slim)** - ๋Ÿฐํƒ€์ž„ ํŒจํ‚ค์ง€ ์„ค์น˜ ํ›„ Builder์—์„œ site-packages ๋ณต์‚ฌ - `ko_KR.UTF-8` ๋กœ์ผ€์ผ ์ƒ์„ฑ - `/app/uploads`, `/app/static`, `/app/test_pipeline_outputs` ์ƒ์„ฑ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ - Healthcheck: `requests.get('http://localhost:8000/health')` - CMD: Gunicorn + UvicornWorker (1 worker, timeout 300์ดˆ) ### DB ์ดˆ๊ธฐ ์Šคํ‚ค๋งˆ - `scripts/init_db_complete.sql`์ด 12๊ฐœ ํ…Œ์ด๋ธ”(users, projects, pages, โ€ฆ combined_results)๊ณผ ์‹œ๋“œ ๋ฐ์ดํ„ฐ(document_types 2๊ฑด, formatting_rules 25๊ฑด)๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. - `combined_results.combined_text` ํƒ€์ž…์€ `LONGTEXT`๋กœ 4GB๊นŒ์ง€ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. --- ## ๐Ÿง  FastAPI ๋ชจ๋“ˆ ๊ตฌ์„ฑ | ์˜์—ญ | ์„ค๋ช… | |------|------| | `routers/projects.py` | ํ”„๋กœ์ ํŠธ CRUD, ๋ถ„์„ ํŠธ๋ฆฌ๊ฑฐ | | `routers/pages.py` | ํŽ˜์ด์ง€ ์—…๋กœ๋“œ, ํ…์ŠคํŠธ ๋ฒ„์ „ API | | `routers/analyze.py` | DocLayout-YOLO ์‹คํ–‰, Tesseract OCR, AI ์„ค๋ช… | | `routers/download.py` | ํ†ตํ•ฉ ํ…์ŠคํŠธ/WORD ์ƒ์„ฑ | | `services/layout_service.py` | ๋ชจ๋ธ ๋กœ๋”ฉ, ๋ ˆ์ด์•„์›ƒ ํ›„์ฒ˜๋ฆฌ | | `services/ocr_service.py` | PDF ๋ถ„๋ฆฌ, ์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ, Tesseract ํ˜ธ์ถœ | | `services/sorter_service.py` | ๋ฌธ์ œ์ง€/์ผ๋ฐ˜ ๋ฌธ์„œ๋ณ„ ์ •๋ ฌ ๋กœ์ง | | `services/ai_description_service.py` | OpenAI Vision ํ˜ธ์ถœ ๋ฐ ์บ์‹ฑ | ๋ชจ๋“  ๋ผ์šฐํ„ฐ๋Š” `app/main.py`์—์„œ FastAPI ์ธ์Šคํ„ด์Šค์— ๋“ฑ๋ก๋˜๋ฉฐ, `database.SessionLocal` ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•ด ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. --- ## ๐Ÿงช ํ…Œ์ŠคํŠธ & ์Šคํฌ๋ฆฝํŠธ - **Pytest**: ๋ฃจํŠธ์—์„œ `pytest -c Project/pytest.ini` ์‹คํ–‰ (ํšŒ๊ท€/ํ†ตํ•ฉ ์‹œ `-m regression` ์‚ฌ์šฉ) - **start_backend.sh**: ์˜์กด์„ฑ ์ฒดํฌ ํ›„ Uvicorn ์‹คํ–‰ (๋ฃจํŠธ ์Šคํฌ๋ฆฝํŠธ) - **scripts/reset_db.sh**: ๊ฐœ๋ฐœ DB ์ดˆ๊ธฐํ™” (๋ฐ์ดํ„ฐ ์ „์ฒด ์‚ญ์ œ) - **api_server.py**: ๋ ˆ๊ฑฐ์‹œ ๋‹จ์ผ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰(ํ•„์š” ์‹œ๋งŒ ์‚ฌ์šฉ) --- ## ๐Ÿšจ ์ž์ฃผ ๋ฌป๋Š” ๋ฌธ์ œ | ์ฆ์ƒ | ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• | |------|-----------| | MySQL ์ปจํ…Œ์ด๋„ˆ ํ—ฌ์Šค์ฒดํฌ ์‹คํŒจ | `docker compose logs mysql` ํ™•์ธ, ํฌํŠธ ์ถฉ๋Œ ์‹œ `MYSQL_PORT` ๋ณ€๊ฒฝ, `docker compose down -v`๋กœ ์žฌ์ƒ์„ฑ | | `DataError: ... combined_text` | `scripts/init_db_complete.sql` ์ตœ์‹  ๋ฒ„์ „ ์ ์šฉ ํ›„ `reset_db.sh` ์‹คํ–‰ | | Tesseract ์–ธ์–ด ๋ฏธํƒ‘์žฌ | Dockerfile ์ด๋ฏธ์ง€๋Š” `tesseract-ocr-kor/eng`๋ฅผ ํฌํ•จํ•จ. ๋กœ์ปฌ ์ˆ˜๋™ ์„ค์น˜ ์‹œ `sudo apt install tesseract-ocr-kor` | | OpenAI ์˜ค๋ฅ˜ | `.env`์˜ `OPENAI_API_KEY` ํ™•์ธ, ์š”์ฒญ ์ˆ˜ ์ œํ•œ ์‹œ `OPENAI_MAX_CONCURRENCY` ๊ฐ’ ์กฐ์ • | | ์—…๋กœ๋“œ ํŒŒ์ผ ๋ฏธ์ €์žฅ | ์ปจํ…Œ์ด๋„ˆ ๋ณผ๋ฅจ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งˆ์šดํŠธ๋˜์—ˆ๋Š”์ง€ (`./Backend/uploads:/app/uploads`) ํ™•์ธ | --- ## ๐Ÿ“Ž ์ฐธ๊ณ  ์ž๋ฃŒ - `../README.md` โ€“ ์ „์ฒด ์‹œ์Šคํ…œ ๊ฐœ์š” ๋ฐ ๋ฐฐํฌ ์ „๋žต - `Backend/docs/Backend API ๋ฌธ์„œ/` โ€“ ์„ธ๋ถ€ API ์ŠคํŽ™