AI ๊ธฐ๋ฐ ํ์ ๋ฐฐ์ถ ๊ด๋ฆฌ ๋ฐ ์ ๋ต์ ์์ฌ๊ฒฐ์ ์ง์ ํ๋ซํผ
ESG Carbon Dashboard๋ ๊ธฐ์ ์ ํ๊ฒฝ์ ์ฑ ์(Environmental)์ ๋ฐ์ดํฐ ์ค์ฌ์ ์ ๋ต์ ์์ฐ์ผ๋ก ์ ํํ๊ธฐ ์ํด ๊ฐ๋ฐ๋ Carbon Strategic OS์ ๋๋ค.
๋จ์ํ ๊ณผ๊ฑฐ์ ๋ฐฐ์ถ๋์ ๊ธฐ๋กํ๋ ๋ฐ ๊ทธ์น์ง ์๊ณ , ๋ค์๊ณผ ๊ฐ์ ํต์ฌ ๊ฐ์น๋ฅผ ์ ๊ณตํฉ๋๋ค:
์ด ํ๋ก์ ํธ๋ ๊ฐ๋ฐ์๋ฟ๋ง ์๋๋ผ ESG ์ค๋ฌด์, CFO, ๊ทธ๋ฆฌ๊ณ ์ง์ ๊ฐ๋ฅ์ฑ ์ ๋ต๊ฐ๊ฐ ์ค๋ฌด์์ ์ฆ์ ํ์ฉํ ์ ์๋ ์์ค์ ์ ๋ฌธ ๊ธฐ์ ๋๊ตฌ๋ฅผ ๋ชฉํ๋ก ํฉ๋๋ค.
graph TB
subgraph "Client Layer"
Browser[์น ๋ธ๋ผ์ฐ์ ]
end
subgraph "Frontend (React 18 + TypeScript + Vite)"
UI[UI Components<br/>Recharts / TailwindCSS 4]
State[State Management<br/>React Hooks + localStorage]
Router[View State Router<br/>URL Query Params + History API]
end
subgraph "Backend (FastAPI + Uvicorn, Port 8000)"
Auth[Auth Router<br/>/auth]
Profile[Profile Router<br/>/profile]
Dashboard[Dashboard Router<br/>/api/v1/dashboard]
Sim[Simulator Router<br/>/api/v1/sim]
AI[AI Router<br/>/api/v1/ai]
end
subgraph "Data & AI Layer"
MySQL[(MySQL DB<br/>users / dashboard_emissions)]
ChromaDB[(ChromaDB<br/>Vector Store / RAG)]
OpenAI[OpenAI API<br/>gpt-4o / gpt-4o-mini]
BGE[BGE Embedding / Reranker<br/>bge-m3, bge-reranker-v2-m3]
end
subgraph "External Data Sources"
yfinance[yfinance / yahoo_fin<br/>EU-ETS ๊ฐ๊ฒฉ]
FDR[FinanceDataReader<br/>K-ETS KAU ๊ฐ๊ฒฉ]
end
Browser --> UI
UI --> State --> Router
Router -->|Axios HTTP/REST| Auth & Profile & Dashboard & Sim & AI
Auth --> MySQL
Profile --> MySQL
Dashboard --> MySQL
Sim --> yfinance & FDR
AI --> ChromaDB & OpenAI
ChromaDB --> BGE
revenue(ํ์ ์ง์ฝ๋), energy(์๋์ง ์ง์ฝ๋)์ธ๋ถ ์คํ ๊ณํ ๋ฒํผ์ผ๋ก Simulator ํญ ์ด๋CompareTab.tsx: Recharts BarChart, ReferenceLine, ๋์ ์์ ์
๋ ๋๋งPOST /api/v1/dashboard/compare/insight๋ก AI ์ธ์ฌ์ดํธ ์์ฑnavigateTo('dashboard', 'simulator')์์๋ฐฐ์ถ๋, ๋ฌด์ํ ๋น, ์๋
ธ์ถ๋(Net Exposure), ์ปดํ๋ผ์ด์ธ์ค ๋น์ฉ ๊ณ์ฐ์ฐ์ ์งํ/์์ฌ ์ดํ ๋น์จ ์๋ฎฌ๋ ์ด์
์ค์๊ฐ/์ง์ ์
๋ ฅ)์๋
ธ์ถ๋ = ์กฐ์ ๋ฐฐ์ถ๋ - ์กฐ์ ๋ฌด์ํ ๋น๋์ปดํ๋ผ์ด์ธ์ค ๋น์ฉ = ์๋
ธ์ถ๋ ร ์คํจ ํ์๊ฐ๊ฒฉ(๊ฒฝ๋งค ํ ์ธ ๋ฐ์)ํด์ธ ์์๋น์ฉ = ํด์ธ S1+S2 ร EUA ร EUR/KRWํตํฉ ์ด๊ณ = ๊ตญ๋ด ์ด ํ์๋น์ฉ + ํด์ธ ์์๋น์ฉs1Domestic, s2Domestic) ์ฐ์ ์ฌ์ฉs1, s2, s3) ์ฌ์ฉSimulatorTab.tsx (์ํ ๊ธฐ๋ฐ ์ฆ์ ์ฌ๊ณ์ฐ)GET /api/v1/sim/dashboard/market-trendsyfinance(EU-ETS), FinanceDataReader(K-ETS)open.er-api.com EUR ๊ธฐ์ค ์ค์๊ฐ ์กฐํ + fallback(1450)์ญํ (Role): SBTi ๊ธฐ์ค์ฐ๋(2021) ๋๋น ๊ฐ์ถ ๊ฒฝ๋ก์ ํ์ฌ ์ค์ ๊ฐ ๊ฒฉ์ฐจ๋ฅผ ์๊ฐํํ๊ณ 2030/2050 ๋ชฉํ ๋ฌ์ฑ ๊ฐ๋ฅ์ฑ์ ์ ๋ํ.
์๋(Purpose):
latestDataYear, ์ต์ ๋ฐ๊ฐ๋ ESG๋ณด๊ณ ์์์์ ์ฐ๋ ๊ธฐ์ค์ด๋ฉฐ ํ์ฌ๋ 2024๋
)๋ก ์ค์ ํ์ฌ ๋์ผ ์ฐ๋ ๊ธฐ์ค์ผ๋ก ์ ํํ ํ์ .KPI ์นด๋ ๊ตฌ์ฑ:
์์ธก ๋ฐฉ๋ฒ๋ก :
๋ชจ๋ธ: log(E_t) = ฮฑ + ฮฒ*t (๋ก๊ทธ-์ ํ OLS ํ๊ท)
๊ฐ์ถ ๋ชฉํ: ์ฐ๊ฐ 4.2% (SBTi ์ ๋ ๊ฐ์ถ ๊ธฐ์ค)
Monte Carlo: 10,000ํ ์ํ๋ง โ 2030 ๋ฌ์ฑ ํ๋ฅ ๊ณ์ฐ
๊ธฐ์ ์์: OLS ํ๊ท, Monte Carlo ์๋ฎฌ๋ ์ด์ (10,000ํ), Recharts(๊ถค์ ์ฐจํธ).
์ญํ (Role): ESG ๋ฌธ์ ๊ธฐ๋ฐ ์ง์์๋ต + ์์ฅ/์ ๋ต ๋งฅ๋ฝํ ๋ต๋ณ ์ ๊ณต
ํต์ฌ ๋์:
strategy ์๋ํฌ์ธํธ๋ก ์๋ฎฌ๋ ์ดํฐ ์ ๋ต ๋ฌธ์ ์์ฑ๊ธฐ์ ์์:
POST /api/v1/ai/chat (StreamingResponse), POST /api/v1/ai/strategy, POST /api/v1/ai/text-to-sqlgpt-4o, gpt-4o-mini) ์๋ต ์์ฑRAG ํ์ดํ๋ผ์ธ:
์ฌ์ฉ์ ์ง๋ฌธ
โ ์๋ ํ๋ณ(RAG ํ์ ์ฌ๋ถ)
โ [RAG ON] ChromaDB ๊ฒ์(semantic/BM25 + rerank) + ๋ฉํ๋ฐ์ดํฐ ํํฐ
โ ์ปจํ
์คํธ + ๋ํ ํ์คํ ๋ฆฌ + ์์คํ
ํ๋กฌํํธ
โ OpenAI ์คํธ๋ฆฌ๋ฐ ์๋ต
๊ธฐ์ ์์: ChromaDB, Sentence-Transformers(BAAI/bge-m3), CrossEncoder reranker, FastAPI StreamingResponse, ํ๋ก ํธ ReadableStream ์ฒ๋ฆฌ.
์ญํ (Role): ์ฌ์ฉ์ ํ์๊ฐ์ , ๋ก๊ทธ์ธ, JWT ์ธ์ ๊ด๋ฆฌ.
์๋(Purpose):
์ธ์ฆ ํ๋ฆ:
Signup โ pbkdf2_sha256 ํด์ ์ ์ฅ โ User ์ ์ฅ(MySQL)
Login โ ๋น๋ฐ๋ฒํธ ๊ฒ์ฆ โ JWT ๋ฐ๊ธ (HS256, ๊ธฐ๋ณธ 60๋ถ)
โ localStorage ์ ์ฅ โ WelcomePage ์ด๋ (3์ด ์๋)
Refresh โ token ์กด์ฌ ์ dashboard ์๋ ๋ณต์
๊ธฐ์ ์์: passlib(pbkdf2_sha256), JWT(python-jose), SQLAlchemy (User ๋ชจ๋ธ).
| ๊ธฐ์ | ๋ฒ์ | ์ฉ๋ |
|---|---|---|
| React | 18 | ์ ์ธ์ UI ๋ฐ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ |
| TypeScript | 5.2 | ๊ฐํ ํ์ ์ฒดํฌ๋ก ๋๊ท๋ชจ ์๋ฎฌ๋ ์ด์ ์์๋ ๋ ๋๋ง ์์ ์ฑ ํ๋ณด |
| Vite | 5.1 | ๋น ๋ฅธ HMR ๋ฐ ์ต์ ํ๋ ํ๋ก๋์ ๋น๋ |
| TailwindCSS | 4.0 | ์ ํธ๋ฆฌํฐ ๊ธฐ๋ฐ ์คํ์ผ๋ง ๋ฐ ์ปดํฌ๋ํธ UI ์ผ๊ด์ฑ ๊ด๋ฆฌ |
| Recharts | 2.12 | ์๊ณ์ด ์์ฅ ๋ฐ์ดํฐ ๋ฐ ๋น๊ต ์ฐจํธ (Line, Bar, Pie, Area) |
| Axios + Fetch | - | ์ผ๋ฐ REST ํต์ + ์ฑ๋ด ์คํธ๋ฆฌ๋ฐ ์๋ต ์ฒ๋ฆฌ |
| Framer Motion | - | ํ์ด์ง ์ ํ ๋ฐ ์ปดํฌ๋ํธ ์ ๋๋ฉ์ด์ |
| Lucide React | - | ์์ด์ฝ ๋ผ์ด๋ธ๋ฌ๋ฆฌ |
| CVA (class-variance-authority) | - | ์กฐ๊ฑด๋ถ Tailwind ํด๋์ค ๊ด๋ฆฌ |
| ๊ธฐ์ | ์ฉ๋ |
|---|---|
| FastAPI & Uvicorn | API ์๋ฒ ๋ฐ ๋น๋๊ธฐ ์์ฒญ ์ฒ๋ฆฌ |
| SQLAlchemy & MySQL (PyMySQL) | ์ฌ์ฉ์/๋ฐฐ์ถ๋ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ORM ํธ๋์ญ์ ์ฒ๋ฆฌ |
| yfinance / yahoo_fin | EU-ETS ๊ฐ๊ฒฉ ๋ฐ์ดํฐ ์กฐํ ๋ฐ fallback |
| FinanceDataReader | K-ETS(KAU) ์๊ณ์ด ๋ฐ์ดํฐ ์กฐํ |
| passlib + python-jose | ๋น๋ฐ๋ฒํธ ํด์ฑ(pbkdf2_sha256) ๋ฐ JWT ์ธ์ฆ |
| python-jose | JWT ํ ํฐ ์์ฑ ๋ฐ ๊ฒ์ฆ (HS256) |
| ๊ธฐ์ | ์ฉ๋ |
|---|---|
| OpenAI API | ์ฑ๋ด/์ ๋ต ์์ฑ LLM ์๋ต ์์ง (gpt-4o, gpt-4o-mini) |
| ChromaDB | RAG ๋ฒกํฐ ์ ์ฅ์ (๋ก์ปฌ Persistent ๋๋ ์๊ฒฉ HTTP ์๋ฒ) |
| Sentence-Transformers | ์๋ฒ ๋ฉ ๋ชจ๋ธ (BAAI/bge-m3) |
| CrossEncoder | ๋ฆฌ๋ญํน ๋ชจ๋ธ (BAAI/bge-reranker-v2-m3) |
| Docling & PyMuPDF | PDF ๊ตฌ์กฐ ์ถ์ถ ๋ฐ ๋ฒกํฐํ ์ ์ฒ๋ฆฌ |
ESG_Dashboard/
โโโ requirements.txt # ๊ณตํต Python ์์กด์ฑ (backend/PDF ๊ณต์ฉ)
โโโ README.md
โโโ ํ์ด์ง_๋ผ์ฐํ
_๊ตฌ์กฐ.md
โโโ start_all.sh # ๋ก์ปฌ ๋์ ์คํ ์คํฌ๋ฆฝํธ
โโโ backend/
โ โโโ requirements.txt # ๋ฐฑ์๋ ์ ์ฉ ์์กด์ฑ
โ โโโ main.py # ํตํฉ ์ํธ๋ฆฌํฌ์ธํธ (RAG ๋ณด์กฐ ์๋ํฌ์ธํธ ํฌํจ)
โ โโโ app/
โ โโโ main.py # ์ฝ์ด API ์๋ฒ ์ํธ๋ฆฌํฌ์ธํธ
โ โโโ config.py # .env ๊ธฐ๋ฐ ์ค์ ๋ก๋
โ โโโ database.py
โ โโโ models.py # User, DashboardEmission
โ โโโ schemas.py
โ โโโ init_db.py
โ โโโ routers/ # auth/profile/dashboard/simulator/ai
โ โโโ services/ # ai_service, market_data ๋ฑ
โ โโโ static/profile/ # ์
๋ก๋๋ ํ๋กํ ์ด๋ฏธ์ง
โโโ frontend/
โ โโโ package.json
โ โโโ package-lock.json
โ โโโ vite.config.ts
โ โโโ src/
โ โโโ App.tsx # react-router-dom ๊ฒฝ๋ก ๋ผ์ฐํ
+ ํญ ์ํ ๊ด๋ฆฌ
โ โโโ config.ts # API base URL ๊ตฌ์ฑ
โ โโโ services/ # auth/profile/market/ai API ํธ์ถ
โ โโโ features/ # ํญ/ํ์ด์ง๋ณ UI
โ โโโ types/
โโโ PDF_Extraction/
โ โโโ requirements.txt # PDF/RAG ํ์ดํ๋ผ์ธ ์์กด์ฑ
โ โโโ src/ # ์ถ์ถ/์ ์ฌ/๋ฒกํฐDB ๊ตฌ์ถ ์คํฌ๋ฆฝํธ
โ โโโ docs/
โ โโโ vector_db/ # (์ ํ) ๋ก์ปฌ Chroma Persistent ์ ์ฅ ๊ฒฝ๋ก
โโโ evaluation/
โโโ evaluate_models.py
[!NOTE]
PDF_Extraction/vector_db/๋ ๋ก์ปฌ Persistent Chroma๋ฅผ ์ธ ๋์ ๊ธฐ๋ณธ ๊ฒฝ๋ก์ ๋๋ค. ์๊ฒฉ Chroma ์๋ฒ(CHROMA_HOST,CHROMA_PORT)๋ฅผ ์ฐ๋ฉด ์ด ํด๋๊ฐ ์์ด๋ ์ฑ๋ด์ด ๋์ํฉ๋๋ค.
react-router-dom๊ธฐ๋ฐ ๊ฒฝ๋ก ๋ผ์ฐํ +activeTab์ํ ๋๊ธฐํ ์์ธ ์ค๊ณ์:ํ์ด์ง_๋ผ์ฐํ _๊ตฌ์กฐ.md
| ๊ฒฝ๋ก | ํ๋ฉด | ์ค๋ช |
|---|---|---|
/login | <Login> | ๋ก๊ทธ์ธ |
/signup | <Signup> | ํ์๊ฐ์ |
/welcome | <WelcomePage> | ๋ก๊ทธ์ธ ์งํ ํ์ ํ๋ฉด |
/dashboard | <DashboardTab> | ๋ฉ์ธ ๋์๋ณด๋ ํญ |
/dashboard/compare | <CompareTab> | Compare ํญ |
/dashboard/simulator | <SimulatorTab> | Simulator ํญ |
/dashboard/target | <TargetTab> | Target ํญ |
/profile | <Profile> | ํ๋กํ ์ค์ |
/data-input | <DataInput> | ๋ฐ์ดํฐ ์ ๋ ฅ |
/reports | <Reports> | ๋ฆฌํฌํธ |
/analytics | <Analytics> | ๋ถ์ ํ๋ฉด |
/login์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ/, /login, /signup ์ ๊ทผ ์ /dashboard๋ก ๋ฆฌ๋ค์ด๋ ํธ/dashboard ๋๋ /login์ผ๋ก ์ ๋ฆฌ/dashboard/*)์์ activeTab์ ์ญ๋งคํํด ํค๋ ํญ UI์ ๋๊ธฐํnavigate('/dashboard/...') ํธ์ถ๋ก ๋ธ๋ผ์ฐ์ ํ์คํ ๋ฆฌ์ ์๋ ์ฐ๋| ์ํํธ์จ์ด | ๊ถ์ฅ ๋ฒ์ | ์ฉ๋ |
|---|---|---|
| Python | 3.11.x | ๋ฐฑ์๋ ์๋ฒ ๋ฐ PDF/RAG ํ์ดํ๋ผ์ธ |
| Node.js | 18+ | ํ๋ก ํธ์๋ ๋น๋ |
| MySQL | 5.7+ | ์ฌ์ฉ์ ๋ฐ ๋ฐฐ์ถ๋ ๋ฐ์ดํฐ ์ ์ฅ |
| OpenAI API Key | ์ ํจ ํค | ์ฑ๋ด/์ ๋ต ์์ฑ LLM ํธ์ถ |
# ํ๋ก์ ํธ ๋ฃจํธ ๊ธฐ์ค
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -r backend/requirements.txt
# DB ์ด๊ธฐํ (์ต์ด 1ํ)
cd backend/app
python init_db.py
cd ../..
# ์๋ฒ ์คํ (๊ถ์ฅ: app ์ํธ๋ฆฌํฌ์ธํธ)
cd backend
uvicorn app.main:app --reload --port 8000
backend/main.py๋ PDF ๊ฒ์/ํต๊ณ ๋ณด์กฐ ์๋ํฌ์ธํธ๊น์ง ํจ๊ป ์ฐ๋ ํตํฉ ๋ชจ๋์ ๋๋ค.
cd frontend
npm install
npm run dev
๋ธ๋ผ์ฐ์ ์์ http://localhost:5173 ์ ์
CHROMA_HOST=your-chroma-host
CHROMA_PORT=8000
RAG_EMBEDDING_MODEL=BAAI/bge-m3
PDF_Extraction/vector_db ํด๋๊ฐ ์์ด๋ ๋ฉ๋๋ค.esg_chunks, esg_pages ๋๋ esg_documents)์ ์กฐํํฉ๋๋ค.pip install -r PDF_Extraction/requirements.txt
cd PDF_Extraction
python src/build_vector_db.py
PDF_Extraction/vector_db์
๋๋ค.BAAI/bge-m3 ์๋ณธ์ pytorch_model.bin ๊ธฐ๋ฐ์ด๋ฏ๋ก, ํ ๊ณต์ฉ ํ๊ฒฝ์์๋ safetensors ๋ณํ๋ณธ์ ์ฌ๋ด ๊ฒฝ๋ก/์ํฐํฉํธ๋ก ๋ฐฐํฌํด ์ฐ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
cd PDF_Extraction
python src/convert_embedding_to_safetensors.py \
--source-model BAAI/bge-m3 \
--output-dir models/bge-m3-safetensors
๋ฐฐํฌ ํ .env์ ๋์ผ ๊ฒฝ๋ก๋ฅผ ์ค์ ํฉ๋๋ค.
RAG_EMBEDDING_MODEL=/absolute/path/to/models/bge-m3-safetensors
ํ๋ก์ ํธ ๋ฃจํธ .env ์์:
# --- Database (MySQL) ---
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=esg
# --- Frontend API URL ---
VITE_API_BASE_URL=http://127.0.0.1:8000
# --- JWT ---
JWT_SECRET_KEY=your_jwt_secret_key_here
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60
# --- RAG/LLM ---
VECTOR_DB_PATH=/absolute/path/to/vector_db # ์ ํ
CHROMA_HOST= # ์๊ฒฉ ์ฌ์ฉ ์ ์ค์
CHROMA_PORT=8000
RAG_EMBEDDING_MODEL=BAAI/bge-m3
# --- Market Data ---
Alpha_Vantage_API=your_alpha_vantage_key
USE_MOCK_DATA=true
# --- Optional ---
OPENAI_API_KEY=sk-...
HF_TOKEN=hf_...
FastAPI Swagger UI:
http://127.0.0.1:8000/docs
/auth)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/auth/signup | POST | ํ์๊ฐ์ |
/auth/login | POST | ๋ก๊ทธ์ธ(JWT access token ๋ฐ๊ธ) |
/auth/me | GET | ํ์ฌ ์ฌ์ฉ์ ์กฐํ (Authorization: Bearer <token>) |
/profile)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/profile/me | GET | ํ๋กํ ์กฐํ |
/profile/me | PUT | ํ๋กํ ์์ (nickname, company_name, classification, bio) |
/profile/me/password | POST | ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ |
/profile/me/email | POST | ์ด๋ฉ์ผ ๋ณ๊ฒฝ |
/profile/me/delete | POST | ๊ณ์ ์ญ์ |
/profile/me/avatar | POST | ์๋ฐํ ์ด๋ฏธ์ง ์
๋ก๋(multipart/form-data) |
/api/v1/dashboard)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/api/v1/dashboard/companies | GET | ๊ธฐ์ ๋ณ ์ต์ /์ฐ๋๋ณ ๋ฐฐ์ถ ๋ฐ์ดํฐ ๋ชฉ๋ก(์ ์ฒด ๋ฐฐ์ถ + ๊ตญ๋ด/ํด์ธ ๋ถ๋ฆฌ ํ๋ ํฌํจ) |
/api/v1/dashboard/compare/insight | POST | Compare ํญ AI ์ธ์ฌ์ดํธ ์์ฑ |
/api/v1/sim)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ฃผ์ ํ๋ผ๋ฏธํฐ | ์ค๋ช |
|---|---|---|---|
/api/v1/sim/dashboard/market-trends | GET | `period=1m | 3m |
/api/v1/sim/dashboard/trend-combined | GET | company, period, start_year, end_year | ๋ฆฌ์คํฌ ๋น์ฉ ์ถ์ด ๊ณ์ฐ |
/api/v1/ai)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/api/v1/ai/chat | POST | RAG ๊ธฐ๋ฐ ์คํธ๋ฆฌ๋ฐ ์ฑ๋ด |
/api/v1/ai/strategy | POST | ์์ฅ ๋ฐ์ดํฐ ๊ธฐ๋ฐ ์ ๋ต ์์ฑ |
/api/v1/ai/text-to-sql | POST | ์์ฐ์ด ์ง์ SQL ๋ณํ |
backend/main.py)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/ | GET | ์๋ฒ ์ํ |
/api/health | GET | ํฌ์ค์ฒดํฌ |
/api/search | GET | ๋ฒกํฐ ๊ฒ์ |
/api/companies | GET | ๋ฒกํฐ DB ๊ธฐ์ค ๊ธฐ์ ๋ชฉ๋ก |
/api/stats | GET | ๋ฒกํฐ DB ํต๊ณ |
ํ๋ซํผ์ ์ ๋ขฐ์ฑ์ ์ํด ํ์ฌ๋ ๋ชจ๋ธ๋ค์ ์ ๊ธฐ์ ์ผ๋ก ์๋ ํ๊ฐํฉ๋๋ค.
python evaluation/evaluate_models.pyusers| ์ปฌ๋ผ๋ช | ํ์ | ์ค๋ช |
|---|---|---|
id | INT (PK) | ์ฌ์ฉ์ ID |
email | VARCHAR(255) UNIQUE | ๋ก๊ทธ์ธ ์๋ณ์ |
company_name | VARCHAR(255) | ์์ ๊ธฐ์ ๋ช |
hashed_password | VARCHAR(255) | ํด์๋ ๋น๋ฐ๋ฒํธ |
nickname | VARCHAR(100) | ํ์ ์ด๋ฆ |
classification | VARCHAR(50) | ๋ถ๋ฅ ํ ๋ง |
bio | VARCHAR(500) | ์๊ธฐ์๊ฐ |
profile_image_url | VARCHAR(500) NULL | ํ๋กํ ์ด๋ฏธ์ง ๊ฒฝ๋ก |
role | VARCHAR(20) | ์ฌ์ฉ์ ๊ถํ ๋ฌธ์์ด |
is_admin | BOOLEAN | ๊ด๋ฆฌ์ ์ฌ๋ถ |
created_at | DATETIME | ์์ฑ ์๊ฐ |
updated_at | DATETIME | ์์ ์๊ฐ |
dashboard_emissions| ์ปฌ๋ผ๋ช | ํ์ | ์ค๋ช |
|---|---|---|
id | INT (PK) | ๋ ์ฝ๋ ID |
company_id | INT INDEX | ๊ธฐ์ ์๋ณ์ |
company_name | VARCHAR(100) INDEX | ๊ธฐ์ ๋ช |
year | INT INDEX | ์ฐ๋ |
scope1 scope2 scope3 | FLOAT | Scope๋ณ ๋ฐฐ์ถ๋(์๋ณธ ์ด๋) |
s1_domestic s2_domestic s3_domestic | FLOAT | ๊ตญ๋ด Scope ๋ฐฐ์ถ๋(์ ํ ์ปฌ๋ผ) |
s1_abroad s2_abroad s3_abroad | FLOAT | ํด์ธ Scope ๋ฐฐ์ถ๋(์ ํ ์ปฌ๋ผ) |
allowance | FLOAT NULL | ๋ฌด์ ํ ๋น๋ |
revenue | BIGINT | ๋งค์ถ |
energy_intensity | FLOAT | ์๋์ง ์ง์ฝ๋ |
carbon_intensity | FLOAT | (S1+S2) ํ์ ์ง์ฝ๋ |
carbon_intensity_scope1 | FLOAT | Scope1 ์ง์ฝ๋ |
carbon_intensity_scope2 | FLOAT | Scope2 ์ง์ฝ๋ |
carbon_intensity_scope3 | FLOAT | Scope3 ์ง์ฝ๋ |
base_year | INT | ๊ธฐ์ค ์ฐ๋ |
base_emissions | FLOAT | ๊ธฐ์ค ๋ฐฐ์ถ๋ |
source_doc_id | INT | ์๋ณธ ๋ฌธ์ ID |
data_source | VARCHAR(500) | ๋ฐ์ดํฐ ์ถ์ฒ |
extraction_method | VARCHAR(50) | ์ถ์ถ ๋ฐฉ์ |
is_verified | BOOLEAN | ๊ฒ์ฆ ์ฌ๋ถ |
created_at | DATETIME | ์์ฑ ์๊ฐ |
updated_at | DATETIME | ์์ ์๊ฐ |
๐ Last Updated: 2026-02-24 ๐ License: Educational & Research Purpose Only
AI ๊ธฐ๋ฐ ํ์ ๋ฐฐ์ถ ๊ด๋ฆฌ ๋ฐ ์ ๋ต์ ์์ฌ๊ฒฐ์ ์ง์ ํ๋ซํผ
ESG Carbon Dashboard๋ ๊ธฐ์ ์ ํ๊ฒฝ์ ์ฑ ์(Environmental)์ ๋ฐ์ดํฐ ์ค์ฌ์ ์ ๋ต์ ์์ฐ์ผ๋ก ์ ํํ๊ธฐ ์ํด ๊ฐ๋ฐ๋ Carbon Strategic OS์ ๋๋ค.
๋จ์ํ ๊ณผ๊ฑฐ์ ๋ฐฐ์ถ๋์ ๊ธฐ๋กํ๋ ๋ฐ ๊ทธ์น์ง ์๊ณ , ๋ค์๊ณผ ๊ฐ์ ํต์ฌ ๊ฐ์น๋ฅผ ์ ๊ณตํฉ๋๋ค:
์ด ํ๋ก์ ํธ๋ ๊ฐ๋ฐ์๋ฟ๋ง ์๋๋ผ ESG ์ค๋ฌด์, CFO, ๊ทธ๋ฆฌ๊ณ ์ง์ ๊ฐ๋ฅ์ฑ ์ ๋ต๊ฐ๊ฐ ์ค๋ฌด์์ ์ฆ์ ํ์ฉํ ์ ์๋ ์์ค์ ์ ๋ฌธ ๊ธฐ์ ๋๊ตฌ๋ฅผ ๋ชฉํ๋ก ํฉ๋๋ค.
graph TB
subgraph "Client Layer"
Browser[์น ๋ธ๋ผ์ฐ์ ]
end
subgraph "Frontend (React 18 + TypeScript + Vite)"
UI[UI Components<br/>Recharts / TailwindCSS 4]
State[State Management<br/>React Hooks + localStorage]
Router[View State Router<br/>URL Query Params + History API]
end
subgraph "Backend (FastAPI + Uvicorn, Port 8000)"
Auth[Auth Router<br/>/auth]
Profile[Profile Router<br/>/profile]
Dashboard[Dashboard Router<br/>/api/v1/dashboard]
Sim[Simulator Router<br/>/api/v1/sim]
AI[AI Router<br/>/api/v1/ai]
end
subgraph "Data & AI Layer"
MySQL[(MySQL DB<br/>users / dashboard_emissions)]
ChromaDB[(ChromaDB<br/>Vector Store / RAG)]
OpenAI[OpenAI API<br/>gpt-4o / gpt-4o-mini]
BGE[BGE Embedding / Reranker<br/>bge-m3, bge-reranker-v2-m3]
end
subgraph "External Data Sources"
yfinance[yfinance / yahoo_fin<br/>EU-ETS ๊ฐ๊ฒฉ]
FDR[FinanceDataReader<br/>K-ETS KAU ๊ฐ๊ฒฉ]
end
Browser --> UI
UI --> State --> Router
Router -->|Axios HTTP/REST| Auth & Profile & Dashboard & Sim & AI
Auth --> MySQL
Profile --> MySQL
Dashboard --> MySQL
Sim --> yfinance & FDR
AI --> ChromaDB & OpenAI
ChromaDB --> BGE
revenue(ํ์ ์ง์ฝ๋), energy(์๋์ง ์ง์ฝ๋)์ธ๋ถ ์คํ ๊ณํ ๋ฒํผ์ผ๋ก Simulator ํญ ์ด๋CompareTab.tsx: Recharts BarChart, ReferenceLine, ๋์ ์์ ์
๋ ๋๋งPOST /api/v1/dashboard/compare/insight๋ก AI ์ธ์ฌ์ดํธ ์์ฑnavigateTo('dashboard', 'simulator')์์๋ฐฐ์ถ๋, ๋ฌด์ํ ๋น, ์๋
ธ์ถ๋(Net Exposure), ์ปดํ๋ผ์ด์ธ์ค ๋น์ฉ ๊ณ์ฐ์ฐ์ ์งํ/์์ฌ ์ดํ ๋น์จ ์๋ฎฌ๋ ์ด์
์ค์๊ฐ/์ง์ ์
๋ ฅ)์๋
ธ์ถ๋ = ์กฐ์ ๋ฐฐ์ถ๋ - ์กฐ์ ๋ฌด์ํ ๋น๋์ปดํ๋ผ์ด์ธ์ค ๋น์ฉ = ์๋
ธ์ถ๋ ร ์คํจ ํ์๊ฐ๊ฒฉ(๊ฒฝ๋งค ํ ์ธ ๋ฐ์)ํด์ธ ์์๋น์ฉ = ํด์ธ S1+S2 ร EUA ร EUR/KRWํตํฉ ์ด๊ณ = ๊ตญ๋ด ์ด ํ์๋น์ฉ + ํด์ธ ์์๋น์ฉs1Domestic, s2Domestic) ์ฐ์ ์ฌ์ฉs1, s2, s3) ์ฌ์ฉSimulatorTab.tsx (์ํ ๊ธฐ๋ฐ ์ฆ์ ์ฌ๊ณ์ฐ)GET /api/v1/sim/dashboard/market-trendsyfinance(EU-ETS), FinanceDataReader(K-ETS)open.er-api.com EUR ๊ธฐ์ค ์ค์๊ฐ ์กฐํ + fallback(1450)์ญํ (Role): SBTi ๊ธฐ์ค์ฐ๋(2021) ๋๋น ๊ฐ์ถ ๊ฒฝ๋ก์ ํ์ฌ ์ค์ ๊ฐ ๊ฒฉ์ฐจ๋ฅผ ์๊ฐํํ๊ณ 2030/2050 ๋ชฉํ ๋ฌ์ฑ ๊ฐ๋ฅ์ฑ์ ์ ๋ํ.
์๋(Purpose):
latestDataYear, ์ต์ ๋ฐ๊ฐ๋ ESG๋ณด๊ณ ์์์์ ์ฐ๋ ๊ธฐ์ค์ด๋ฉฐ ํ์ฌ๋ 2024๋
)๋ก ์ค์ ํ์ฌ ๋์ผ ์ฐ๋ ๊ธฐ์ค์ผ๋ก ์ ํํ ํ์ .KPI ์นด๋ ๊ตฌ์ฑ:
์์ธก ๋ฐฉ๋ฒ๋ก :
๋ชจ๋ธ: log(E_t) = ฮฑ + ฮฒ*t (๋ก๊ทธ-์ ํ OLS ํ๊ท)
๊ฐ์ถ ๋ชฉํ: ์ฐ๊ฐ 4.2% (SBTi ์ ๋ ๊ฐ์ถ ๊ธฐ์ค)
Monte Carlo: 10,000ํ ์ํ๋ง โ 2030 ๋ฌ์ฑ ํ๋ฅ ๊ณ์ฐ
๊ธฐ์ ์์: OLS ํ๊ท, Monte Carlo ์๋ฎฌ๋ ์ด์ (10,000ํ), Recharts(๊ถค์ ์ฐจํธ).
์ญํ (Role): ESG ๋ฌธ์ ๊ธฐ๋ฐ ์ง์์๋ต + ์์ฅ/์ ๋ต ๋งฅ๋ฝํ ๋ต๋ณ ์ ๊ณต
ํต์ฌ ๋์:
strategy ์๋ํฌ์ธํธ๋ก ์๋ฎฌ๋ ์ดํฐ ์ ๋ต ๋ฌธ์ ์์ฑ๊ธฐ์ ์์:
POST /api/v1/ai/chat (StreamingResponse), POST /api/v1/ai/strategy, POST /api/v1/ai/text-to-sqlgpt-4o, gpt-4o-mini) ์๋ต ์์ฑRAG ํ์ดํ๋ผ์ธ:
์ฌ์ฉ์ ์ง๋ฌธ
โ ์๋ ํ๋ณ(RAG ํ์ ์ฌ๋ถ)
โ [RAG ON] ChromaDB ๊ฒ์(semantic/BM25 + rerank) + ๋ฉํ๋ฐ์ดํฐ ํํฐ
โ ์ปจํ
์คํธ + ๋ํ ํ์คํ ๋ฆฌ + ์์คํ
ํ๋กฌํํธ
โ OpenAI ์คํธ๋ฆฌ๋ฐ ์๋ต
๊ธฐ์ ์์: ChromaDB, Sentence-Transformers(BAAI/bge-m3), CrossEncoder reranker, FastAPI StreamingResponse, ํ๋ก ํธ ReadableStream ์ฒ๋ฆฌ.
์ญํ (Role): ์ฌ์ฉ์ ํ์๊ฐ์ , ๋ก๊ทธ์ธ, JWT ์ธ์ ๊ด๋ฆฌ.
์๋(Purpose):
์ธ์ฆ ํ๋ฆ:
Signup โ pbkdf2_sha256 ํด์ ์ ์ฅ โ User ์ ์ฅ(MySQL)
Login โ ๋น๋ฐ๋ฒํธ ๊ฒ์ฆ โ JWT ๋ฐ๊ธ (HS256, ๊ธฐ๋ณธ 60๋ถ)
โ localStorage ์ ์ฅ โ WelcomePage ์ด๋ (3์ด ์๋)
Refresh โ token ์กด์ฌ ์ dashboard ์๋ ๋ณต์
๊ธฐ์ ์์: passlib(pbkdf2_sha256), JWT(python-jose), SQLAlchemy (User ๋ชจ๋ธ).
| ๊ธฐ์ | ๋ฒ์ | ์ฉ๋ |
|---|---|---|
| React | 18 | ์ ์ธ์ UI ๋ฐ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ |
| TypeScript | 5.2 | ๊ฐํ ํ์ ์ฒดํฌ๋ก ๋๊ท๋ชจ ์๋ฎฌ๋ ์ด์ ์์๋ ๋ ๋๋ง ์์ ์ฑ ํ๋ณด |
| Vite | 5.1 | ๋น ๋ฅธ HMR ๋ฐ ์ต์ ํ๋ ํ๋ก๋์ ๋น๋ |
| TailwindCSS | 4.0 | ์ ํธ๋ฆฌํฐ ๊ธฐ๋ฐ ์คํ์ผ๋ง ๋ฐ ์ปดํฌ๋ํธ UI ์ผ๊ด์ฑ ๊ด๋ฆฌ |
| Recharts | 2.12 | ์๊ณ์ด ์์ฅ ๋ฐ์ดํฐ ๋ฐ ๋น๊ต ์ฐจํธ (Line, Bar, Pie, Area) |
| Axios + Fetch | - | ์ผ๋ฐ REST ํต์ + ์ฑ๋ด ์คํธ๋ฆฌ๋ฐ ์๋ต ์ฒ๋ฆฌ |
| Framer Motion | - | ํ์ด์ง ์ ํ ๋ฐ ์ปดํฌ๋ํธ ์ ๋๋ฉ์ด์ |
| Lucide React | - | ์์ด์ฝ ๋ผ์ด๋ธ๋ฌ๋ฆฌ |
| CVA (class-variance-authority) | - | ์กฐ๊ฑด๋ถ Tailwind ํด๋์ค ๊ด๋ฆฌ |
| ๊ธฐ์ | ์ฉ๋ |
|---|---|
| FastAPI & Uvicorn | API ์๋ฒ ๋ฐ ๋น๋๊ธฐ ์์ฒญ ์ฒ๋ฆฌ |
| SQLAlchemy & MySQL (PyMySQL) | ์ฌ์ฉ์/๋ฐฐ์ถ๋ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ORM ํธ๋์ญ์ ์ฒ๋ฆฌ |
| yfinance / yahoo_fin | EU-ETS ๊ฐ๊ฒฉ ๋ฐ์ดํฐ ์กฐํ ๋ฐ fallback |
| FinanceDataReader | K-ETS(KAU) ์๊ณ์ด ๋ฐ์ดํฐ ์กฐํ |
| passlib + python-jose | ๋น๋ฐ๋ฒํธ ํด์ฑ(pbkdf2_sha256) ๋ฐ JWT ์ธ์ฆ |
| python-jose | JWT ํ ํฐ ์์ฑ ๋ฐ ๊ฒ์ฆ (HS256) |
| ๊ธฐ์ | ์ฉ๋ |
|---|---|
| OpenAI API | ์ฑ๋ด/์ ๋ต ์์ฑ LLM ์๋ต ์์ง (gpt-4o, gpt-4o-mini) |
| ChromaDB | RAG ๋ฒกํฐ ์ ์ฅ์ (๋ก์ปฌ Persistent ๋๋ ์๊ฒฉ HTTP ์๋ฒ) |
| Sentence-Transformers | ์๋ฒ ๋ฉ ๋ชจ๋ธ (BAAI/bge-m3) |
| CrossEncoder | ๋ฆฌ๋ญํน ๋ชจ๋ธ (BAAI/bge-reranker-v2-m3) |
| Docling & PyMuPDF | PDF ๊ตฌ์กฐ ์ถ์ถ ๋ฐ ๋ฒกํฐํ ์ ์ฒ๋ฆฌ |
ESG_Dashboard/
โโโ requirements.txt # ๊ณตํต Python ์์กด์ฑ (backend/PDF ๊ณต์ฉ)
โโโ README.md
โโโ ํ์ด์ง_๋ผ์ฐํ
_๊ตฌ์กฐ.md
โโโ start_all.sh # ๋ก์ปฌ ๋์ ์คํ ์คํฌ๋ฆฝํธ
โโโ backend/
โ โโโ requirements.txt # ๋ฐฑ์๋ ์ ์ฉ ์์กด์ฑ
โ โโโ main.py # ํตํฉ ์ํธ๋ฆฌํฌ์ธํธ (RAG ๋ณด์กฐ ์๋ํฌ์ธํธ ํฌํจ)
โ โโโ app/
โ โโโ main.py # ์ฝ์ด API ์๋ฒ ์ํธ๋ฆฌํฌ์ธํธ
โ โโโ config.py # .env ๊ธฐ๋ฐ ์ค์ ๋ก๋
โ โโโ database.py
โ โโโ models.py # User, DashboardEmission
โ โโโ schemas.py
โ โโโ init_db.py
โ โโโ routers/ # auth/profile/dashboard/simulator/ai
โ โโโ services/ # ai_service, market_data ๋ฑ
โ โโโ static/profile/ # ์
๋ก๋๋ ํ๋กํ ์ด๋ฏธ์ง
โโโ frontend/
โ โโโ package.json
โ โโโ package-lock.json
โ โโโ vite.config.ts
โ โโโ src/
โ โโโ App.tsx # react-router-dom ๊ฒฝ๋ก ๋ผ์ฐํ
+ ํญ ์ํ ๊ด๋ฆฌ
โ โโโ config.ts # API base URL ๊ตฌ์ฑ
โ โโโ services/ # auth/profile/market/ai API ํธ์ถ
โ โโโ features/ # ํญ/ํ์ด์ง๋ณ UI
โ โโโ types/
โโโ PDF_Extraction/
โ โโโ requirements.txt # PDF/RAG ํ์ดํ๋ผ์ธ ์์กด์ฑ
โ โโโ src/ # ์ถ์ถ/์ ์ฌ/๋ฒกํฐDB ๊ตฌ์ถ ์คํฌ๋ฆฝํธ
โ โโโ docs/
โ โโโ vector_db/ # (์ ํ) ๋ก์ปฌ Chroma Persistent ์ ์ฅ ๊ฒฝ๋ก
โโโ evaluation/
โโโ evaluate_models.py
[!NOTE]
PDF_Extraction/vector_db/๋ ๋ก์ปฌ Persistent Chroma๋ฅผ ์ธ ๋์ ๊ธฐ๋ณธ ๊ฒฝ๋ก์ ๋๋ค. ์๊ฒฉ Chroma ์๋ฒ(CHROMA_HOST,CHROMA_PORT)๋ฅผ ์ฐ๋ฉด ์ด ํด๋๊ฐ ์์ด๋ ์ฑ๋ด์ด ๋์ํฉ๋๋ค.
react-router-dom๊ธฐ๋ฐ ๊ฒฝ๋ก ๋ผ์ฐํ +activeTab์ํ ๋๊ธฐํ ์์ธ ์ค๊ณ์:ํ์ด์ง_๋ผ์ฐํ _๊ตฌ์กฐ.md
| ๊ฒฝ๋ก | ํ๋ฉด | ์ค๋ช |
|---|---|---|
/login | <Login> | ๋ก๊ทธ์ธ |
/signup | <Signup> | ํ์๊ฐ์ |
/welcome | <WelcomePage> | ๋ก๊ทธ์ธ ์งํ ํ์ ํ๋ฉด |
/dashboard | <DashboardTab> | ๋ฉ์ธ ๋์๋ณด๋ ํญ |
/dashboard/compare | <CompareTab> | Compare ํญ |
/dashboard/simulator | <SimulatorTab> | Simulator ํญ |
/dashboard/target | <TargetTab> | Target ํญ |
/profile | <Profile> | ํ๋กํ ์ค์ |
/data-input | <DataInput> | ๋ฐ์ดํฐ ์ ๋ ฅ |
/reports | <Reports> | ๋ฆฌํฌํธ |
/analytics | <Analytics> | ๋ถ์ ํ๋ฉด |
/login์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ/, /login, /signup ์ ๊ทผ ์ /dashboard๋ก ๋ฆฌ๋ค์ด๋ ํธ/dashboard ๋๋ /login์ผ๋ก ์ ๋ฆฌ/dashboard/*)์์ activeTab์ ์ญ๋งคํํด ํค๋ ํญ UI์ ๋๊ธฐํnavigate('/dashboard/...') ํธ์ถ๋ก ๋ธ๋ผ์ฐ์ ํ์คํ ๋ฆฌ์ ์๋ ์ฐ๋| ์ํํธ์จ์ด | ๊ถ์ฅ ๋ฒ์ | ์ฉ๋ |
|---|---|---|
| Python | 3.11.x | ๋ฐฑ์๋ ์๋ฒ ๋ฐ PDF/RAG ํ์ดํ๋ผ์ธ |
| Node.js | 18+ | ํ๋ก ํธ์๋ ๋น๋ |
| MySQL | 5.7+ | ์ฌ์ฉ์ ๋ฐ ๋ฐฐ์ถ๋ ๋ฐ์ดํฐ ์ ์ฅ |
| OpenAI API Key | ์ ํจ ํค | ์ฑ๋ด/์ ๋ต ์์ฑ LLM ํธ์ถ |
# ํ๋ก์ ํธ ๋ฃจํธ ๊ธฐ์ค
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -r backend/requirements.txt
# DB ์ด๊ธฐํ (์ต์ด 1ํ)
cd backend/app
python init_db.py
cd ../..
# ์๋ฒ ์คํ (๊ถ์ฅ: app ์ํธ๋ฆฌํฌ์ธํธ)
cd backend
uvicorn app.main:app --reload --port 8000
backend/main.py๋ PDF ๊ฒ์/ํต๊ณ ๋ณด์กฐ ์๋ํฌ์ธํธ๊น์ง ํจ๊ป ์ฐ๋ ํตํฉ ๋ชจ๋์ ๋๋ค.
cd frontend
npm install
npm run dev
๋ธ๋ผ์ฐ์ ์์ http://localhost:5173 ์ ์
CHROMA_HOST=your-chroma-host
CHROMA_PORT=8000
RAG_EMBEDDING_MODEL=BAAI/bge-m3
PDF_Extraction/vector_db ํด๋๊ฐ ์์ด๋ ๋ฉ๋๋ค.esg_chunks, esg_pages ๋๋ esg_documents)์ ์กฐํํฉ๋๋ค.pip install -r PDF_Extraction/requirements.txt
cd PDF_Extraction
python src/build_vector_db.py
PDF_Extraction/vector_db์
๋๋ค.BAAI/bge-m3 ์๋ณธ์ pytorch_model.bin ๊ธฐ๋ฐ์ด๋ฏ๋ก, ํ ๊ณต์ฉ ํ๊ฒฝ์์๋ safetensors ๋ณํ๋ณธ์ ์ฌ๋ด ๊ฒฝ๋ก/์ํฐํฉํธ๋ก ๋ฐฐํฌํด ์ฐ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
cd PDF_Extraction
python src/convert_embedding_to_safetensors.py \
--source-model BAAI/bge-m3 \
--output-dir models/bge-m3-safetensors
๋ฐฐํฌ ํ .env์ ๋์ผ ๊ฒฝ๋ก๋ฅผ ์ค์ ํฉ๋๋ค.
RAG_EMBEDDING_MODEL=/absolute/path/to/models/bge-m3-safetensors
ํ๋ก์ ํธ ๋ฃจํธ .env ์์:
# --- Database (MySQL) ---
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=esg
# --- Frontend API URL ---
VITE_API_BASE_URL=http://127.0.0.1:8000
# --- JWT ---
JWT_SECRET_KEY=your_jwt_secret_key_here
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60
# --- RAG/LLM ---
VECTOR_DB_PATH=/absolute/path/to/vector_db # ์ ํ
CHROMA_HOST= # ์๊ฒฉ ์ฌ์ฉ ์ ์ค์
CHROMA_PORT=8000
RAG_EMBEDDING_MODEL=BAAI/bge-m3
# --- Market Data ---
Alpha_Vantage_API=your_alpha_vantage_key
USE_MOCK_DATA=true
# --- Optional ---
OPENAI_API_KEY=sk-...
HF_TOKEN=hf_...
FastAPI Swagger UI:
http://127.0.0.1:8000/docs
/auth)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/auth/signup | POST | ํ์๊ฐ์ |
/auth/login | POST | ๋ก๊ทธ์ธ(JWT access token ๋ฐ๊ธ) |
/auth/me | GET | ํ์ฌ ์ฌ์ฉ์ ์กฐํ (Authorization: Bearer <token>) |
/profile)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/profile/me | GET | ํ๋กํ ์กฐํ |
/profile/me | PUT | ํ๋กํ ์์ (nickname, company_name, classification, bio) |
/profile/me/password | POST | ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ |
/profile/me/email | POST | ์ด๋ฉ์ผ ๋ณ๊ฒฝ |
/profile/me/delete | POST | ๊ณ์ ์ญ์ |
/profile/me/avatar | POST | ์๋ฐํ ์ด๋ฏธ์ง ์
๋ก๋(multipart/form-data) |
/api/v1/dashboard)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/api/v1/dashboard/companies | GET | ๊ธฐ์ ๋ณ ์ต์ /์ฐ๋๋ณ ๋ฐฐ์ถ ๋ฐ์ดํฐ ๋ชฉ๋ก(์ ์ฒด ๋ฐฐ์ถ + ๊ตญ๋ด/ํด์ธ ๋ถ๋ฆฌ ํ๋ ํฌํจ) |
/api/v1/dashboard/compare/insight | POST | Compare ํญ AI ์ธ์ฌ์ดํธ ์์ฑ |
/api/v1/sim)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ฃผ์ ํ๋ผ๋ฏธํฐ | ์ค๋ช |
|---|---|---|---|
/api/v1/sim/dashboard/market-trends | GET | `period=1m | 3m |
/api/v1/sim/dashboard/trend-combined | GET | company, period, start_year, end_year | ๋ฆฌ์คํฌ ๋น์ฉ ์ถ์ด ๊ณ์ฐ |
/api/v1/ai)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/api/v1/ai/chat | POST | RAG ๊ธฐ๋ฐ ์คํธ๋ฆฌ๋ฐ ์ฑ๋ด |
/api/v1/ai/strategy | POST | ์์ฅ ๋ฐ์ดํฐ ๊ธฐ๋ฐ ์ ๋ต ์์ฑ |
/api/v1/ai/text-to-sql | POST | ์์ฐ์ด ์ง์ SQL ๋ณํ |
backend/main.py)| ์๋ํฌ์ธํธ | ๋ฉ์๋ | ์ค๋ช |
|---|---|---|
/ | GET | ์๋ฒ ์ํ |
/api/health | GET | ํฌ์ค์ฒดํฌ |
/api/search | GET | ๋ฒกํฐ ๊ฒ์ |
/api/companies | GET | ๋ฒกํฐ DB ๊ธฐ์ค ๊ธฐ์ ๋ชฉ๋ก |
/api/stats | GET | ๋ฒกํฐ DB ํต๊ณ |
ํ๋ซํผ์ ์ ๋ขฐ์ฑ์ ์ํด ํ์ฌ๋ ๋ชจ๋ธ๋ค์ ์ ๊ธฐ์ ์ผ๋ก ์๋ ํ๊ฐํฉ๋๋ค.
python evaluation/evaluate_models.pyusers| ์ปฌ๋ผ๋ช | ํ์ | ์ค๋ช |
|---|---|---|
id | INT (PK) | ์ฌ์ฉ์ ID |
email | VARCHAR(255) UNIQUE | ๋ก๊ทธ์ธ ์๋ณ์ |
company_name | VARCHAR(255) | ์์ ๊ธฐ์ ๋ช |
hashed_password | VARCHAR(255) | ํด์๋ ๋น๋ฐ๋ฒํธ |
nickname | VARCHAR(100) | ํ์ ์ด๋ฆ |
classification | VARCHAR(50) | ๋ถ๋ฅ ํ ๋ง |
bio | VARCHAR(500) | ์๊ธฐ์๊ฐ |
profile_image_url | VARCHAR(500) NULL | ํ๋กํ ์ด๋ฏธ์ง ๊ฒฝ๋ก |
role | VARCHAR(20) | ์ฌ์ฉ์ ๊ถํ ๋ฌธ์์ด |
is_admin | BOOLEAN | ๊ด๋ฆฌ์ ์ฌ๋ถ |
created_at | DATETIME | ์์ฑ ์๊ฐ |
updated_at | DATETIME | ์์ ์๊ฐ |
dashboard_emissions| ์ปฌ๋ผ๋ช | ํ์ | ์ค๋ช |
|---|---|---|
id | INT (PK) | ๋ ์ฝ๋ ID |
company_id | INT INDEX | ๊ธฐ์ ์๋ณ์ |
company_name | VARCHAR(100) INDEX | ๊ธฐ์ ๋ช |
year | INT INDEX | ์ฐ๋ |
scope1 scope2 scope3 | FLOAT | Scope๋ณ ๋ฐฐ์ถ๋(์๋ณธ ์ด๋) |
s1_domestic s2_domestic s3_domestic | FLOAT | ๊ตญ๋ด Scope ๋ฐฐ์ถ๋(์ ํ ์ปฌ๋ผ) |
s1_abroad s2_abroad s3_abroad | FLOAT | ํด์ธ Scope ๋ฐฐ์ถ๋(์ ํ ์ปฌ๋ผ) |
allowance | FLOAT NULL | ๋ฌด์ ํ ๋น๋ |
revenue | BIGINT | ๋งค์ถ |
energy_intensity | FLOAT | ์๋์ง ์ง์ฝ๋ |
carbon_intensity | FLOAT | (S1+S2) ํ์ ์ง์ฝ๋ |
carbon_intensity_scope1 | FLOAT | Scope1 ์ง์ฝ๋ |
carbon_intensity_scope2 | FLOAT | Scope2 ์ง์ฝ๋ |
carbon_intensity_scope3 | FLOAT | Scope3 ์ง์ฝ๋ |
base_year | INT | ๊ธฐ์ค ์ฐ๋ |
base_emissions | FLOAT | ๊ธฐ์ค ๋ฐฐ์ถ๋ |
source_doc_id | INT | ์๋ณธ ๋ฌธ์ ID |
data_source | VARCHAR(500) | ๋ฐ์ดํฐ ์ถ์ฒ |
extraction_method | VARCHAR(50) | ์ถ์ถ ๋ฐฉ์ |
is_verified | BOOLEAN | ๊ฒ์ฆ ์ฌ๋ถ |
created_at | DATETIME | ์์ฑ ์๊ฐ |
updated_at | DATETIME | ์์ ์๊ฐ |
๐ Last Updated: 2026-02-24 ๐ License: Educational & Research Purpose Only