1010from core .tariff_prediction .tools .parse_hs_results import parse_hs6_result , generate_hs10_candidates
1111from core .tariff_prediction .tools .parse_tariff_result import parse_tariff_result
1212from core .tariff_prediction .constants import SUPPORTED_COUNTRIES , SCENARIOS , OFF_TOPIC_KEYWORDS , CORRECTION_KEYWORDS , SESSION_TERMINATION_KEYWORDS
13+ from core .tariff_prediction .agent .step_api import tariff_prediction_step_api
14+ from core .tariff_prediction .dto .tariff_request import TariffPredictionRequest
15+ from core .tariff_prediction .dto .tariff_response import TariffPredictionResponse
1316
1417# 전역 워크플로우 매니저
1518class WorkflowManager :
@@ -101,8 +104,9 @@ def is_off_topic(self, user_input: str) -> bool:
101104 return any (keyword in input_lower for keyword in OFF_TOPIC_KEYWORDS )
102105
103106 def process_user_input (self , user_input : str ) -> str :
104- """사용자 입력을 처리하고 적절한 응답을 반환합니다."""
105-
107+ """
108+ 사용자 입력을 처리하고 적절한 응답을 반환합니다.
109+ """
106110 # 세션 중단 요청 확인
107111 if any (word in user_input for word in SESSION_TERMINATION_KEYWORDS ):
108112 self .reset_session ()
@@ -126,8 +130,8 @@ def process_user_input(self, user_input: str) -> str:
126130 return self .handle_hs6_selection (user_input )
127131 elif self .state ['current_step' ] == 'hs10_selection' :
128132 return self .handle_hs10_selection (user_input )
129- elif self .state ['current_step' ] == 'calculation' :
130- return self .handle_calculation (user_input )
133+ # elif self.state['current_step'] == 'calculation':
134+ # return self.handle_calculation(user_input)
131135
132136 return "죄송합니다. 현재 상태를 인식할 수 없습니다. 처음부터 다시 시작하겠습니다."
133137
@@ -157,9 +161,7 @@ def handle_scenario_selection(self, user_input: str) -> str:
157161번호를 입력하거나 상황을 설명해 주세요."""
158162
159163 def handle_input_collection (self , user_input : str ) -> str :
160- """자연어 입력 수집을 처리합니다."""
161164 parsed = self .parse_user_input (user_input )
162-
163165 # 필수 정보 확인
164166 missing_info = []
165167 if 'product_name' not in parsed :
@@ -168,30 +170,29 @@ def handle_input_collection(self, user_input: str) -> str:
168170 missing_info .append ("구매 국가" )
169171 if 'price' not in parsed :
170172 missing_info .append ("상품 가격" )
171-
172173 if missing_info :
173174 missing_str = ", " .join (missing_info )
174175 return f"다음 정보가 누락되었습니다: { missing_str } \n \n 💡 **상품 묘사의 정확도가 높을수록 정확한 관세 예측이 가능합니다!**\n \n 예시:\n • \" 아랫창은 고무로 되어있고 하얀색 운동화를 80000원에 독일에서 샀어요\" \n • \" 인텔 i7 노트북을 150만원에 미국에서 구매했어요\" \n • \" 블루투스 이어폰 2개를 12만원에 일본에서 샀어요\" "
175-
176- # 국가 지원 여부 확인
177- if not self .is_supported_country (parsed ['country' ]):
178- return f"죄송합니다. '{ parsed ['country' ]} '의 환율 정보는 현재 제공되지 않습니다. 지원되는 국가로 다시 입력해 주세요."
179-
180- # 상품 설명 정제
181- parsed ['product_name' ] = clean_product_description (parsed ['product_name' ])
182-
183176 # 상태 업데이트
184177 self .state .update (parsed )
178+ # step_api.py 활용
179+ req = TariffPredictionRequest (
180+ step = "input" ,
181+ product_description = parsed ['product_name' ],
182+ origin_country = parsed ['country' ],
183+ price = parsed ['price' ],
184+ quantity = parsed .get ('quantity' , 1 ),
185+ shipping_cost = parsed .get ('shipping_cost' , 0 ),
186+ scenario = self .state .get ('scenario' )
187+ )
188+ resp : TariffPredictionResponse = tariff_prediction_step_api (req )
189+ if resp .message and (not resp .hs6_candidates ):
190+ return resp .message
191+ self .state ['hs6_candidates' ] = resp .hs6_candidates
185192 self .state ['current_step' ] = 'hs6_selection'
186-
187- # HS6 예측
188- try :
189- hs6_result = get_hs_classification (parsed ['product_name' ])
190- self .state ['hs6_candidates' ] = self .parse_hs6_result (hs6_result )
191-
192- return f"상품묘사: { parsed ['product_name' ]} \n 국가: { parsed ['country' ]} \n 가격: { parsed ['price' ]:,} 원\n 수량: { parsed .get ('quantity' , 1 )} 개\n \n HS6 코드 후보를 찾았습니다. 번호를 선택해 주세요:\n { self .format_hs6_candidates ()} "
193- except Exception as e :
194- return f"HS 코드 예측 중 오류가 발생했습니다: { str (e )} "
193+ return f"상품묘사: { parsed ['product_name' ]} \n 국가: { parsed ['country' ]} \n 가격: { parsed ['price' ]:,} 원\n 수량: { parsed .get ('quantity' , 1 )} 개\n \n HS6 코드 후보를 찾았습니다. 번호를 선택해 주세요:\n " + '\n ' .join ([
194+ f"{ i + 1 } . { c ['code' ]} - { c ['description' ]} (신뢰도: { c ['confidence' ]} )" for i , c in enumerate (resp .hs6_candidates or [])
195+ ])
195196
196197 def parse_hs6_result (self , hs6_result : str ) -> List [Dict ]:
197198 """HS6 결과를 파싱합니다."""
@@ -205,23 +206,28 @@ def format_hs6_candidates(self) -> str:
205206 return formatted
206207
207208 def handle_hs6_selection (self , user_input : str ) -> str :
208- """HS6 선택을 자연어로 처리합니다."""
209- # 숫자만 추출
210209 number_match = re .search (r'(\d+)' , user_input )
211- if number_match :
210+ if number_match and self . state . get ( 'hs6_candidates' ) :
212211 selection = int (number_match .group (1 ))
213- if 1 <= selection <= len (self .state ['hs6_candidates' ]):
214- selected = self .state ['hs6_candidates' ][selection - 1 ]
212+ candidates = self .state ['hs6_candidates' ]
213+ if 1 <= selection <= len (candidates ):
214+ selected = candidates [selection - 1 ]
215215 self .state ['hs6_code' ] = selected ['code' ]
216+ # step_api.py 활용
217+ req = TariffPredictionRequest (
218+ step = "hs6_select" ,
219+ hs6_code = selected ['code' ]
220+ )
221+ resp : TariffPredictionResponse = tariff_prediction_step_api (req )
222+ if resp .message and (not resp .hs10_candidates ):
223+ return resp .message
224+ self .state ['hs10_candidates' ] = resp .hs10_candidates
216225 self .state ['current_step' ] = 'hs10_selection'
217-
218- # HS10 후보 생성
219- hs10_candidates = self .generate_hs10_candidates (selected ['code' ])
220- self .state ['hs10_candidates' ] = hs10_candidates
221-
222- return f"선택하신 HS6 코드: { selected ['code' ]} \n \n HS10 코드 후보를 선택해 주세요:\n { self .format_hs10_candidates ()} "
226+ return f"선택하신 HS6 코드: { selected ['code' ]} \n \n HS10 코드 후보를 선택해 주세요:\n " + '\n ' .join ([
227+ f"{ i + 1 } . { c ['code' ]} - { c ['description' ]} " for i , c in enumerate (resp .hs10_candidates or [])
228+ ])
223229 else :
224- return f"1부터 { len (self . state [ 'hs6_candidates' ] )} 사이의 번호를 입력해 주세요."
230+ return f"1부터 { len (candidates )} 사이의 번호를 입력해 주세요."
225231 else :
226232 return f"숫자를 입력해 주세요. (예: 1, 2, 3)"
227233
@@ -237,19 +243,31 @@ def format_hs10_candidates(self) -> str:
237243 return formatted
238244
239245 def handle_hs10_selection (self , user_input : str ) -> str :
240- """HS10 선택을 자연어로 처리합니다."""
241- # 숫자만 추출
242246 number_match = re .search (r'(\d+)' , user_input )
243- if number_match :
247+ if number_match and self . state . get ( 'hs10_candidates' ) :
244248 selection = int (number_match .group (1 ))
245- if 1 <= selection <= len (self .state ['hs10_candidates' ]):
246- selected = self .state ['hs10_candidates' ][selection - 1 ]
249+ candidates = self .state ['hs10_candidates' ]
250+ if 1 <= selection <= len (candidates ):
251+ selected = candidates [selection - 1 ]
247252 self .state ['hs10_code' ] = selected ['code' ]
248- self .state ['current_step' ] = 'calculation'
249-
250- return self .perform_calculation ()
253+ # step_api.py 활용
254+ req = TariffPredictionRequest (
255+ step = "hs10_select" ,
256+ hs10_code = selected ['code' ],
257+ origin_country = self .state .get ('country' ),
258+ price = self .state .get ('price' ),
259+ quantity = self .state .get ('quantity' , 1 ),
260+ shipping_cost = self .state .get ('shipping_cost' , 0 ),
261+ scenario = self .state .get ('scenario' )
262+ )
263+ resp : TariffPredictionResponse = tariff_prediction_step_api (req )
264+ self .reset_session ()
265+ if resp .calculation_result :
266+ return f"# 🎯 관세 계산 결과\n { resp .calculation_result } \n \n { resp .message or '' } "
267+ else :
268+ return resp .message or "계산 결과를 가져오지 못했습니다."
251269 else :
252- return f"1부터 { len (self . state [ 'hs10_candidates' ] )} 사이의 번호를 입력해 주세요."
270+ return f"1부터 { len (candidates )} 사이의 번호를 입력해 주세요."
253271 else :
254272 return f"숫자를 입력해 주세요. (예: 1, 2, 3)"
255273
0 commit comments