File size: 6,433 Bytes
cc7330c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import uvicorn
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import FileResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from typing import List, Optional, Dict, Any
import os
import uuid
from matplotlib import font_manager
from . import core, ppt

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# --- Pydantic 모델 ---

class OptionsRequest(BaseModel):
    job: Optional[str] = None
    bm: Optional[str] = None
    sales: Optional[str] = None

class SearchParamsModel(BaseModel):
    job: str
    bm: str
    sales: str
    emp: str
    userBase: str
    userValue: int

class DiagnosisRequest(BaseModel):
    params: SearchParamsModel
    answers: List[int]

# Get BASE_DIR for the project root (one level up from this 'core' folder)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# --- 폰트 설치 확인 (디버깅용) ---
font_path = os.path.join(BASE_DIR, "core", "data", "Paperlogy-4Regular.ttf")
if os.path.exists(font_path):
    font_name = font_manager.FontProperties(fname=font_path).get_name()
    print(f"Loaded font: {font_name}")
else:
    print(f"Warning: Font file not found at {font_path}")

# --- 엔드포인트 ---

@app.post("/api/options")
def get_options_endpoint(req: OptionsRequest):
    return core.get_step_options(core.conds_df, job=req.job, bm=req.bm, sales=req.sales)

@app.post("/api/survey")
def get_survey_items_endpoint(req: SearchParamsModel):
    levels = core.get_levels_by_wage(core.avg_df, req.job, req.bm, req.sales, req.emp, req.userBase, req.userValue)
    if not levels: levels = ["L3", "L4"]
    bars_indicator, _ = core.make_bars_table(core.bars_df, req.job, levels)
    return bars_indicator.to_dict(orient='records')

@app.post("/api/diagnosis")
def post_diagnosis_endpoint(req: DiagnosisRequest):
    p = req.params
    levels = core.get_levels_by_wage(core.avg_df, p.job, p.bm, p.sales, p.emp, p.userBase, p.userValue)
    if not levels: levels = ["L3", "L4"]
    _, ppt_tables = core.make_bars_table(core.bars_df, p.job, levels)
    levels_def = core.get_levels_definition(p.job, levels, core.job_def)
    final_lv, level_out = core.judge_level(req.answers, core.factors, levels, levels_def)
    head_msg, text1, text2, pct, c3, table3 = core.judge_wage(core.raw_df, p.job, p.bm, p.sales, p.emp, final_lv, p.userBase, p.userValue)
    
    table1, chart1 = core.format_table(ppt_tables[0], core.factors, req.answers, cut=2)
    table2, chart2 = core.format_table(ppt_tables[1], core.factors, req.answers, cut=4)

    level_out.columns = ['left', 'right']

    level_info = {
        "left": level_out['left'].to_dict(),
        "right": level_out['right'].to_dict(),
    }

    for chart in [chart1, chart2]:
        chart.columns = ['subject', 'target', 'user']
        subjects = [
            '기술 전문성', '도메인 이해', '데이터 리터러시', '고객중심 사고',
            '문제해결능력', '애자일 실행', '협업', '책임감', '영향범위', '리더십'
        ]
        chart['subject'] = subjects

    wage_records = table3.to_dict(orient='records')
    for rec in wage_records:
        rec['description'] = text1

    level_chart = {
        "left": chart1.to_dict(orient='records'),
        "right": chart2.to_dict(orient='records')
    }

    info_pool = [p.job, final_lv, p.userBase, p.bm, p.sales, p.emp]
    
    result_data = {
        "headMessage": head_msg.split('\n'),
        "levelInfo": level_info,
        "levelChart": level_chart,
        "percentile": pct,
        "wageOutput": wage_records,
        "info": [x for x in info_pool if x != '전체']
    }
        
    return result_data


@app.post("/api/report")
def download_report(req: DiagnosisRequest):
    p = req.params
    levels = core.get_levels_by_wage(core.avg_df, p.job, p.bm, p.sales, p.emp, p.userBase, p.userValue)
    if not levels: levels = ["L3", "L4"]
    _, ppt_tables = core.make_bars_table(core.bars_df, p.job, levels)
    levels_def = core.get_levels_definition(p.job, levels, core.job_def)
    final_lv, lv_out = core.judge_level(req.answers, core.factors, levels, levels_def)
    head_msg, blk1, blk2, pct, c3, t3 = core.judge_wage(core.raw_df, p.job, p.bm, p.sales, p.emp, final_lv, p.userBase, p.userValue)
    
    table1, chart1 = core.format_table(ppt_tables[0], core.factors, req.answers, cut=2)
    table2, chart2 = core.format_table(ppt_tables[1], core.factors, req.answers, cut=4)

    ppt_dataset = {
        0 : {"head_message": head_msg, "texts": [blk1, blk2, f"{pct:.1f}%"], "tables": [lv_out.iloc[:2], lv_out.iloc[2:], t3]},
        1 : {"title": lv_out.columns[0], "table": [table1]},
        2 : {"title": lv_out.columns[1], "table": [table2]}
    }
    
    out_path = os.path.join(core.BASE_DIR, "tmp", f"report_{uuid.uuid4().hex[:8]}.pptx")
    os.makedirs(os.path.dirname(out_path), exist_ok=True)
    ppt.update_ppt_with_data(ppt_dataset, out_path)
    
    return FileResponse(out_path, filename="진단리포트.pptx", media_type="application/vnd.openxmlformats-officedocument.presentationml.presentation")


# --- 정적 파일 서빙 ---
# api.py가 core/ 폴더 안에 있으므로 BASE_DIR는 상위 디렉토리(루트)입니다.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUT_DIR = os.path.join(BASE_DIR, "out")

if os.path.exists(OUT_DIR):
    app.mount("/_next", StaticFiles(directory=os.path.join(OUT_DIR, "_next")), name="next_static")
    @app.api_route("/{full_path:path}", methods=["GET", "HEAD"])
    async def serve_spa(full_path: str):
        if full_path.startswith("api"): raise HTTPException(status_code=404)
        
        file_path = os.path.join(OUT_DIR, full_path)
        if os.path.isfile(file_path): return FileResponse(file_path)
        
        html_file = os.path.join(OUT_DIR, f"{full_path}.html")
        if os.path.isfile(html_file): return FileResponse(html_file)
        
        index_file = os.path.join(file_path, "index.html")
        if os.path.isdir(file_path) and os.path.isfile(index_file): return FileResponse(index_file)
            
        return FileResponse(os.path.join(OUT_DIR, "index.html"))

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=7860)