λΉμ ν λ¬Έμ(.hwp, .hwpx, .pdf, .docx, .ppt, .pptx)λ₯Ό μ
λ‘λνλ©΄ ν
μ€νΈ μΆμΆ, OCR 보μ, μμ½ λ° μΉ΄ν
κ³ λ¦¬ λΆλ₯, PostgreSQL μ μ₯κΉμ§ μλμΌλ‘ μ²λ¦¬νλ μΉ μ ν리μΌμ΄μ
μ
λλ€.
μ΄ νλ‘μ νΈλ FastAPI λ°±μλμ React νλ‘ νΈμλλ‘ κ΅¬μ±λμ΄ μμΌλ©°, λ¬Έμ μ²λ¦¬ κ²°κ³Όλ₯Ό λΉλκΈ° μμ λ¨μλ‘ μΆμ ν μ μμ΅λλ€.
- λ¬Έμ μ λ‘λ λ° λΉλκΈ° μ²λ¦¬
- ν¬λ§·λ³ ν μ€νΈ μΆμΆ
- OCR κΈ°λ° ν μ€νΈ 보μ
- Ollama κΈ°λ° μμ½ λ° μΉ΄ν κ³ λ¦¬ λΆλ₯
- PostgreSQL μ΄λ ₯ μ μ₯ λ° κ²μ
- React UIλ₯Ό ν΅ν μ§ν μν λ° κ²°κ³Ό νμΈ
.hwp.hwpx.pdf.docx.ppt.pptx
νμΌ μ
λ‘λ
-> νμΌ μ μ₯
-> νμ₯μλ³ μΆμΆκΈ° μ€ν
-> ν
μ€νΈ/JSON μ 리
-> Ollama μμ½ λ° μΉ΄ν
κ³ λ¦¬ λΆλ₯
-> PostgreSQL μ μ₯
-> νλ‘ νΈμλμμ μν μ‘°ν λ° κ²°κ³Ό νμΈ
ν¬λ§·λ³ μ²λ¦¬ λ°©μμ λλ΅ λ€μκ³Ό κ°μ΅λλ€.
PDF: λ΄μ₯ ν μ€νΈ μΆμΆ ν λΆμ‘±ν νμ΄μ§λ OCRλ‘ λ³΄μDOCX: λ¬Έλ¨/ν μ§μ μΆμΆ ν ν¬ν¨ μ΄λ―Έμ§ OCR μνHWPX: XML κΈ°λ° μ§μ νμ±HWP: μ§μ ν μ€νΈ μΆμΆ μλ ν νμ μ COM λ³ν λ° OCR fallbackPPT/PPTX: μ¬λΌμ΄λ ν μ€νΈ μΆμΆ, μΌλΆ μ΄λ―Έμ§ OCR 보쑰
| μμ | μ¬μ© κΈ°μ |
|---|---|
| Backend | FastAPI, Uvicorn |
| DB | PostgreSQL, SQLAlchemy |
| LLM | Ollama, httpx |
| OCR | PaddleOCR, PaddlePaddle |
| λ¬Έμ μ²λ¦¬ | pdfplumber, pdf2image, PyMuPDF, python-docx, python-pptx, olefile |
| Frontend | React, Vite, Axios |
AI_Document_Analyzer/
ββ main.py # FastAPI μ§μ
μ λ° API λΌμ°νΈ
ββ database.py # SQLAlchemy μμ§/μΈμ
μμ±
ββ models.py # Category, Document, Job ν
μ΄λΈ μ μ
ββ document_pipeline.py # νμ₯μλ³ extractor λΌμ°ν
ββ llm_chain.py # Ollama νΈμΆ λ° μμ½/λΆλ₯ κ²°κ³Ό νμ±
ββ config.py # μΆμΆκΈ° κ³΅ν΅ μ€μ
ββ app/
β ββ config.py # μ ν리μΌμ΄μ
νκ²½μ€μ
β ββ schemas.py # API μλ΅ μ€ν€λ§
ββ extractors/
β ββ pdf_ext/ # PDF μΆμΆκΈ°
β ββ docx_ext/ # DOCX μΆμΆκΈ°
β ββ hwp_ext/ # HWP/HWPX μΆμΆκΈ°
β ββ ppt_ext/ # PPT/PPTX μΆμΆκΈ°
ββ frontend/
β ββ src/App.jsx # μ
λ‘λ/μν/κ²°κ³Ό UI
β ββ src/api.js # λ°±μλ API νΈμΆ
β ββ package.json
ββ data/
β ββ uploads/ # μ
λ‘λ μλ³Έ μ μ₯ κ²½λ‘
β ββ work/ # μμ
μ© μμ κ²½λ‘
β ββ ocr_output/ # μΆμΆ JSON μ μ₯ κ²½λ‘
ββ output/ # μΌλΆ μΆμΆκΈ°μ μ€κ° μ°μΆλ¬Ό κ²½λ‘
λ€μ κ΅¬μ± μμκ° νμν©λλ€.
- Python 3.10 μ΄μ
- PostgreSQL
- Ollama
- Node.js λ° npm
λ¬Έμ νμμ λ°λΌ μΆκ° μμ‘΄μ±μ΄ νμν μ μμ΅λλ€.
PDF OCR: Poppler νμHWP μ²λ¦¬: Windows νκ²½μμ Hancom Office/COM κΈ°λ° λμμ΄ νμν μ μμ
.env.exampleλ₯Ό 볡μ¬ν΄ .envλ₯Ό λ§λ λ€ κ°μ μ€μ ν©λλ€.
# Windows PowerShell
copy .env.example .env# macOS/Linux
cp .env.example .envμ£Όμ νκ²½λ³μλ μλμ κ°μ΅λλ€.
| λ³μλͺ | μ€λͺ | μμ |
|---|---|---|
DATABASE_URL |
PostgreSQL μ°κ²° λ¬Έμμ΄ | postgresql+psycopg2://postgres:YOUR_PASSWORD@localhost:5432/document_db |
APP_NAME |
FastAPI μ± μ΄λ¦ | Document Analyzer |
UPLOAD_DIR |
μ λ‘λ νμΌ μ μ₯ κ²½λ‘ | ./data/uploads |
WORK_DIR |
μμ μ© μμ κ²½λ‘ | ./data/work |
OCR_OUTPUT_DIR |
μΆμΆ JSON μ μ₯ κ²½λ‘ | ./data/ocr_output |
OLLAMA_URL |
Ollama μλ² μ£Όμ | http://localhost:11434 |
OLLAMA_MODEL |
μ¬μ©ν Ollama λͺ¨λΈλͺ | llama3.1:8b |
OLLAMA_TIMEOUT_SEC |
Ollama μμ² νμμμ | 300 |
μ£Όμ:
- νμ¬ κ΅¬μ‘°μ
DATABASE_URLμ΄ μμΌλ©΄ μλ² μμ μμ μ μ€ν¨ν©λλ€. .env.exampleλ μμ νμΌμ΄κ³ , μ€μ μ€νμλ.envκ° νμν©λλ€.
python -m venv .venv# Windows PowerShell
.venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt# macOS/Linux
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txtollama pull llama3.1:8bOLLAMA_MODELμ λ€λ₯Έ κ°μΌλ‘ λ°κΏ¨λ€λ©΄ ν΄λΉ λͺ¨λΈμ 미리 λ°μλ¬μΌ ν©λλ€.
μ΄ νλ‘μ νΈμ PDF OCR κ²½λ‘λ pdf2imageλ₯Ό μ¬μ©νλ―λ‘, Windowsμμλ Popplerκ° μ€μΉλμ΄ μμ΄μΌ ν©λλ€.
μ€μΉ μμ:
- Windowsμ© Poppler μμΆ νμΌμ λ€μ΄λ‘λ
- μνλ μμΉμ μμΆ ν΄μ
- μμΆ ν΄μ ν ν΄λμ
Library/binκ²½λ‘λ₯Ό μμ€ν PATHμ μΆκ° - μ ν°λ―Έλμ μ΄κ³ μλ λͺ λ ΉμΌλ‘ μ€μΉ μ¬λΆ νμΈ
μμ κ²½λ‘:
C:\Users\<μ¬μ©μλͺ
>\Downloads\poppler-xx\Library\bin
νμΈ λͺ λ Ή:
where.exe pdfinfo
where.exe pdftoppm
python -c "import shutil; print(shutil.which('pdfinfo'))"μ λͺ λ Ήμμ κ²½λ‘κ° μ μμ μΌλ‘ μΆλ ₯λλ©΄ μ€λΉκ° λ μνμ λλ€.
uvicorn main:app --reload --port 8000ν¬μ€μ²΄ν¬:
GET http://localhost:8000/health
cd frontend
npm install
npm run devκΈ°λ³Έ κ°λ° μλ² μ£Όμ:
λ°±μλ κΈ°λ³Έ μ£Όμ:
POST /api/process/startmultipart/form-data- νλλͺ
:
file
μλ΅ μμ:
{
"job_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}GET /api/process/{job_id}
μλ΅ μμ:
{
"job_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "completed",
"progress": 100,
"stage": "completed",
"message": "μ²λ¦¬ μλ£",
"result": {
"filename": "sample.pdf",
"raw_text": "...",
"ocr_text": "",
"merged_text": "...",
"summary": "...",
"category": "κΈ°μ ",
"main_category": "κΈ°μ ",
"sub_category": "AI",
"confidence": 0.0,
"category_reason": ""
}
}GET /api/history
쿼리 νλΌλ―Έν°:
limit: κΈ°λ³Έ50, μ΅λ200
GET /api/history/search
쿼리 νλΌλ―Έν°:
q: κ²μμ΄limit: κΈ°λ³Έ50, μ΅λ200
μμΈ:
.envνμΌμ΄ μκ±°λDATABASE_URLμ΄ λΉμ΄ μμ
ν΄κ²°:
.env.exampleλ₯Ό.envλ‘ λ³΅μ¬DATABASE_URLκ°μ μ€μ PostgreSQL νκ²½μ λ§κ² μμ - PostgreSQL μ€ν μ¬λΆ νμΈ
μ:
- λͺ¨λΈμ μ°Ύμ μ μμ
- Ollama μλν¬μΈνΈ μ°κ²° μ€ν¨
ν΄κ²°:
- Ollama μλ² μ€ν μ¬λΆ νμΈ
.envμOLLAMA_URLνμΈ.envμOLLAMA_MODELνμΈollama pull <λͺ¨λΈλͺ >μ€ν
μ:
Unable to get page countpdfinfo not installed
μμΈ:
- Popplerκ° μ€μΉλμ§ μμκ±°λ PATHμ μμ
ν΄κ²°:
- Poppler μ€μΉ
Library/binκ²½λ‘λ₯Ό PATHμ μΆκ°- μ ν°λ―Έλμμ
where.exe pdfinfoλ‘ νμΈ
μμΈ:
- Hancom Office COM μλν νκ²½ λ¬Έμ
- λ³ν νμμμ
- νμΌ νμ/μΈμ½λ© μ΄μ
ν΄κ²°:
- Windows νκ²½μμ νκΈ νλ‘κ·Έλ¨ μ€μΉ μν νμΈ
- HWP νμΌμ΄ μ μμ μΌλ‘ μ΄λ¦¬λμ§ μλ νμΈ
- νμ μ OCR fallback κ²½λ‘ μ¬μ© μ¬λΆ λ‘κ·Έ νμΈ
- μμ
μν μΆμ μ λ©λͺ¨λ¦¬ κΈ°λ°μ΄λ―λ‘ μλ² μ¬μμ μ μ§ν μ€μΈ
job_idμνλ μ μ§λμ§ μμ΅λλ€. - μ΄λ ₯ μ‘°νλ PostgreSQL μ μ₯ κ²°κ³Όλ₯Ό κΈ°μ€μΌλ‘ ν©λλ€.
- μΌλΆ μΆμΆκΈ°λ μ€κ° μ°μΆλ¬Όμ
output/μ μ μ₯νκ³ , API νμ΄νλΌμΈμ© JSONμdata/ocr_output/μ μ μ₯ν©λλ€. - CORSλ νμ¬ μ 체 νμ©μΌλ‘ μ€μ λμ΄ μμ΄ μ΄μ νκ²½μμλ λ³λ μ νμ΄ νμν©λλ€.
- λΉλκΈ° μμ ν λμ
- μμ μνλ₯Ό DBμλ μ μ₯νλλ‘ νμ₯
- νλ‘ νΈμλ μ΄λ ₯ UI κ°μ
- μΆμΆκΈ°λ³ μΆλ ₯ κ²½λ‘ μΌκ΄μ± μ 리
- μμΈ λ©μμ§ λ° μ΄μ λ‘κ·Έ κ°μ
- ν μ€νΈ μ½λ μΆκ°
μΈλΆ OCR, PDF, HWP μ²λ¦¬ λꡬ λ° λͺ¨λΈ μμ‘΄μ±μ΄ μμΌλ―λ‘ μ€μ λ°°ν¬ μ μλ λ€μ νλͺ©μ λ³λλ‘ μ κ²νλ κ²μ κΆμ₯ν©λλ€.
- μλ² OSλ³ μμ‘΄μ± μ€μΉ μ¬λΆ
- PostgreSQL μ°κ²° μ 보 보μ κ΄λ¦¬
.envλ° μ λ‘λ νμΌμ Git μ μΈ μ²λ¦¬- μ΄μ νκ²½μ© CORS λ° λ‘κ·Έ μ μ±