Skip to content

Commit 0d868e9

Browse files
authored
Merge pull request #11 from hanjuhn/main
chore: 관세 예측 프로세스 step으로 분기
2 parents c1af722 + a03f725 commit 0d868e9

File tree

4 files changed

+85
-16
lines changed

4 files changed

+85
-16
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from core.tariff_prediction.dto.tariff_request import TariffPredictionRequest
2+
from core.tariff_prediction.dto.tariff_response import TariffPredictionResponse
3+
from core.tariff_prediction.tools.get_hs_classification import get_hs_classification
4+
from core.tariff_prediction.tools.parse_hs_results import parse_hs6_result, generate_hs10_candidates
5+
from core.tariff_prediction.tools.calculate_tariff_amount import calculate_tariff_amount
6+
from core.shared.utils.llm import get_llm
7+
8+
def tariff_prediction_step_api(req: TariffPredictionRequest) -> TariffPredictionResponse:
9+
step = req.stepㄴ
10+
# Step 자동 분류: step이 'auto'이거나 비어 있으면 LLM으로 분류
11+
if not step or step == 'auto':
12+
llm = get_llm()
13+
step_prompt = f"""
14+
다음 사용자 입력이 관세 예측 플로우의 어떤 단계에 해당하는지 분류하세요.
15+
- 상품 설명 입력: input
16+
- HS6 코드 선택: hs6_select
17+
- HS10 코드 선택 및 관세 계산: hs10_select
18+
반드시 input, hs6_select, hs10_select 중 하나로만 답하세요.
19+
사용자 입력: {req.product_description or req.hs6_code or req.hs10_code or ''}
20+
"""
21+
step_result = llm.invoke([{"role": "system", "content": step_prompt}])
22+
step = str(getattr(step_result, 'content', step_result)).strip()
23+
# Step별 분기
24+
if step == "input":
25+
# 상품 설명 → HS6 후보 예측
26+
hs6_result = get_hs_classification(req.product_description)
27+
hs6_candidates = parse_hs6_result(hs6_result)
28+
return TariffPredictionResponse(
29+
step="hs6_select",
30+
hs6_candidates=hs6_candidates,
31+
message="상품에 해당하는 HS6 코드를 선택해 주세요."
32+
)
33+
elif step == "hs6_select":
34+
# HS6 코드 → HS10 후보 추출
35+
hs10_candidates = generate_hs10_candidates(req.hs6_code)
36+
return TariffPredictionResponse(
37+
step="hs10_select",
38+
hs10_candidates=hs10_candidates,
39+
message="해당하는 HS10 코드를 선택해 주세요."
40+
)
41+
elif step == "hs10_select":
42+
# HS10 코드, 국가, 가격 등 입력받아 관세 계산
43+
result = calculate_tariff_amount.invoke({
44+
"product_code": req.hs10_code,
45+
"value": req.price,
46+
"origin_country": req.origin_country,
47+
"item_count": req.quantity,
48+
"shipping_cost": req.shipping_cost,
49+
"situation": req.scenario
50+
})
51+
if isinstance(result, str):
52+
# 에러 메시지
53+
return TariffPredictionResponse(
54+
step="result",
55+
calculation_result=None,
56+
message=result
57+
)
58+
else:
59+
return TariffPredictionResponse(
60+
step="result",
61+
calculation_result=result,
62+
message="관세 계산 결과입니다."
63+
)
64+
else:
65+
return TariffPredictionResponse(
66+
step="input",
67+
message="잘못된 요청입니다. 상품 설명을 입력해 주세요."
68+
)
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from pydantic import BaseModel
2-
from typing import Optional
2+
from typing import Optional, Literal
33

44
class TariffPredictionRequest(BaseModel):
5-
"""관세 예측 요청 DTO"""
6-
product_description: str
7-
price: Optional[float] = None
8-
quantity: Optional[int] = 1
9-
origin_country: Optional[str] = None
10-
shipping_cost: Optional[float] = 0
11-
scenario: Optional[str] = "해외직구" # 해외직구, 해외체류 중 구매, 해외배송
5+
step: Literal["input", "hs6_select", "hs10_select"] # 현재 단계
6+
product_description: Optional[str] = None # 상품 설명 (input 단계)
7+
hs6_code: Optional[str] = None # 선택한 HS6 코드 (hs6_select 단계)
8+
hs10_code: Optional[str] = None # 선택한 HS10 코드 (hs10_select 단계)
9+
origin_country: Optional[str] = None # 원산지 국가 (hs10_select 단계)
10+
price: Optional[float] = None # 상품 가격 (hs10_select 단계)
11+
quantity: Optional[int] = 1 # 수량 (hs10_select 단계)
12+
shipping_cost: Optional[float] = 0 # 배송비 (hs10_select 단계)
13+
scenario: Optional[str] = "해외직구" # 시나리오 (hs10_select 단계)

core/tariff_prediction/dto/tariff_response.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pydantic import BaseModel
2-
from typing import List, Optional
2+
from typing import List, Optional, Dict, Any, Literal
33

44
class HSClassificationResult(BaseModel):
55
"""HS 코드 분류 결과"""
@@ -25,9 +25,8 @@ class ExchangeRateResult(BaseModel):
2525
date: str
2626

2727
class TariffPredictionResponse(BaseModel):
28-
"""관세 예측 응답 DTO"""
29-
product_description: str
30-
hs_classifications: List[HSClassificationResult]
31-
tariff_calculation: Optional[TariffCalculationResult] = None
32-
exchange_rate: Optional[ExchangeRateResult] = None
33-
total_response: str
28+
step: Literal["hs6_select", "hs10_select", "result"] # 다음 단계
29+
hs6_candidates: Optional[List[Dict[str, Any]]] = None # HS6 후보 리스트 (input 단계 응답)
30+
hs10_candidates: Optional[List[Dict[str, Any]]] = None # HS10 후보 리스트 (hs6_select 단계 응답)
31+
calculation_result: Optional[Dict[str, Any]] = None # 관세 계산 결과 (hs10_select 단계 응답)
32+
message: Optional[str] = None # 안내/에러 메시지

core/tariff_prediction/tools/parse_hs_results.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def generate_hs10_candidates(hs6_code: str) -> List[Dict]:
5858
candidates = []
5959
for _, row in matching_rows.iterrows():
6060
candidates.append({
61-
'code': row['HS10'],
61+
'code': str(row['HS10']), # 항상 문자열로 변환
6262
'description': row['한글품목명']
6363
})
6464

0 commit comments

Comments
 (0)