Skip to content

Commit 49bfed1

Browse files
authored
Merge pull request #16 from hanjuhn/main
chore: 관세 예측 기능 입출력 양식 보완
2 parents 388de7a + ab6812f commit 49bfed1

3 files changed

Lines changed: 58 additions & 26 deletions

File tree

app/__init__.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,9 @@
1-
from flask import Flask, jsonify
1+
from flask import Flask
22
from flasgger import Swagger
33
from .routes import api_blueprint
44

55
def create_app():
66
app = Flask(__name__)
77
Swagger(app)
88
app.register_blueprint(api_blueprint)
9-
10-
@app.route('/')
11-
def index():
12-
return jsonify({
13-
"message": "관세청 챗봇 API 서버",
14-
"endpoints": {
15-
"/predict": "POST - 관세 예측 및 통관 관련 질문 처리",
16-
"/apidocs": "GET - API 문서 (Swagger)"
17-
},
18-
"example": {
19-
"question": "미국에서 150만원에 노트북을 샀는데 관세가 얼마나 나올까요?"
20-
}
21-
})
22-
239
return app

core/tariff_prediction/agent/tariff_prediction_agent.py

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,15 @@ def handle_scenario_selection(self, user_input: str) -> str:
162162
self.state['scenario'] = detected_scenario
163163
self.state['current_step'] = 'input_collection'
164164
self.state['session_active'] = True
165-
response = f"'{detected_scenario}'로 인식했습니다! 이제 구매하신 상품에 대해 자유롭게 말씀해 주세요.\n\n💡 **상품 묘사의 정확도가 높을수록 정확한 관세 예측이 가능합니다!**\n\n예시:\n\"아랫창은 고무로 되어있고 하얀색 운동화를 80000원에 독일에서 샀어요\"\n\"인텔 i7 노트북을 150만원에 미국에서 구매했어요\"\n\"블루투스 이어폰 2개를 12만원에 일본에서 샀어요\"\n\n위 예시를 참고하여 상품 정보를 입력해 주세요."
165+
response = (
166+
"구매하신 상품 정보를 입력해 주세요!\n\n"
167+
"💡 **상품 묘사의 정확도가 높을수록 정확한 관세 예측이 가능합니다!**\n\n"
168+
"예시:\n"
169+
"• \"아랫창은 고무로 되어있고 하얀색 운동화를 80000원에 독일에서 샀어요\"\n"
170+
"• \"인텔 i7 노트북을 150만원에 미국에서 구매했어요\"\n"
171+
"• \"블루투스 이어폰 2개를 12만원에 일본에서 샀어요\"\n\n"
172+
"위 예시를 참고하여 상품 정보를 입력해 주세요."
173+
)
166174
self.state['responses'].append(response)
167175
return response
168176

@@ -171,7 +179,15 @@ def handle_scenario_selection(self, user_input: str) -> str:
171179
self.state['scenario'] = self.scenarios[user_input]
172180
self.state['current_step'] = 'input_collection'
173181
self.state['session_active'] = True
174-
response = f"'{self.state['scenario']}'로 선택하셨습니다! 이제 구매하신 상품에 대해 자유롭게 말씀해 주세요.\n\n💡 **상품 묘사의 정확도가 높을수록 정확한 관세 예측이 가능합니다!**\n\n예시:\n\"아랫창은 고무로 되어있고 하얀색 운동화를 80000원에 독일에서 샀어요\"\n\"인텔 i7 노트북을 150만원에 미국에서 구매했어요\"\n\"블루투스 이어폰 2개를 12만원에 일본에서 샀어요\"\n\n위 예시를 참고하여 상품 정보를 입력해 주세요."
182+
response = (
183+
"구매하신 상품 정보를 입력해 주세요!\n\n"
184+
"💡 **상품 묘사의 정확도가 높을수록 정확한 관세 예측이 가능합니다!**\n\n"
185+
"예시:\n"
186+
"• \"아랫창은 고무로 되어있고 하얀색 운동화를 80000원에 독일에서 샀어요\"\n"
187+
"• \"인텔 i7 노트북을 150만원에 미국에서 구매했어요\"\n"
188+
"• \"블루투스 이어폰 2개를 12만원에 일본에서 샀어요\"\n\n"
189+
"위 예시를 참고하여 상품 정보를 입력해 주세요."
190+
)
175191
self.state['responses'].append(response)
176192
return response
177193

@@ -203,15 +219,35 @@ def handle_input_collection(self, user_input: str) -> str:
203219
parsed = self.parse_user_input(enhanced_input)
204220
# 필수 정보 확인
205221
missing_info = []
206-
if 'product_name' not in parsed:
207-
missing_info.append("상품에 대한 묘사")
208-
if 'country' not in parsed:
222+
if 'product_name' not in parsed or not parsed['product_name']:
223+
missing_info.append("상품명")
224+
if 'country' not in parsed or not parsed['country']:
209225
missing_info.append("구매 국가")
210-
if 'price' not in parsed:
226+
if 'price' not in parsed or not parsed['price']:
211227
missing_info.append("상품 가격")
212228
if missing_info:
229+
# 이미 입력된 정보는 보여주고, 누락된 정보만 안내
230+
info_lines = []
231+
if 'product_name' in parsed and parsed['product_name']:
232+
info_lines.append(f"상품명: {parsed['product_name']}")
233+
if 'country' in parsed and parsed['country']:
234+
info_lines.append(f"구매 국가: {parsed['country']}")
235+
if 'price' in parsed and parsed['price']:
236+
info_lines.append(f"상품 가격: {parsed['price']:,}원")
237+
if 'quantity' in parsed and parsed['quantity']:
238+
info_lines.append(f"수량: {parsed['quantity']}개")
239+
info_str = "\n".join(info_lines)
213240
missing_str = ", ".join(missing_info)
214-
response = f"다음 정보가 누락되었습니다: {missing_str}\n\n💡 **상품 묘사의 정확도가 높을수록 정확한 관세 예측이 가능합니다!**\n\n예시:\n\"아랫창은 고무로 되어있고 하얀색 운동화를 80000원에 독일에서 샀어요\"\n\"인텔 i7 노트북을 150만원에 미국에서 구매했어요\"\n\"블루투스 이어폰 2개를 12만원에 일본에서 샀어요\""
241+
response = (
242+
(info_str + "\n\n" if info_str else "") +
243+
f"다음 정보가 누락되었습니다: {missing_str}\n"
244+
"💡 **상품명, 구매 국가, 상품 가격을 모두 입력해 주세요!**\n\n"
245+
"예시:\n"
246+
"• \"미국에서 150만원에 노트북을 샀어요\"\n"
247+
"• \"일본에서 10만원짜리 이어폰을 구매했어요\"\n"
248+
"• \"독일에서 80만원에 운동화 2켤레를 샀어요\"\n\n"
249+
"위 예시를 참고하여 상품 정보를 입력해 주세요."
250+
)
215251
self.state['responses'].append(response)
216252
return response
217253
# 상태 업데이트
@@ -232,7 +268,9 @@ def handle_input_collection(self, user_input: str) -> str:
232268
return resp.message
233269
self.state['hs6_candidates'] = resp.hs6_candidates
234270
self.state['current_step'] = 'hs6_selection'
235-
response = f"상품묘사: {parsed['product_name']}\n국가: {parsed['country']}\n가격: {parsed['price']:,}\n수량: {parsed.get('quantity', 1)}\n\nHS6 코드 후보를 찾았습니다. 번호를 선택해 주세요:\n" + '\n'.join([
271+
scenario_str = self.state.get('scenario', '')
272+
scenario_guide = f"{scenario_str}로 예상하고 안내를 도와드릴게요.\n\n" if scenario_str else ""
273+
response = scenario_guide + f"상품묘사: {parsed['product_name']}\n국가: {parsed['country']}\n가격: {parsed['price']:,}\n수량: {parsed.get('quantity', 1)}\n\nHS6 코드 후보를 찾았습니다. 번호를 선택해 주세요:\n" + '\n'.join([
236274
f"{i+1}. {c['code']} - {c['description']} (신뢰도: {c['confidence']})" for i, c in enumerate(resp.hs6_candidates or [])
237275
]) + f"\n\n💡 **위 후보 중 하나를 선택해 주세요.**\n예시: \"1번\", \"2번\", \"3번\" 등"
238276
self.state['responses'].append(response)
@@ -268,7 +306,7 @@ def handle_hs6_selection(self, user_input: str) -> str:
268306
return resp.message
269307
self.state['hs10_candidates'] = resp.hs10_candidates
270308
self.state['current_step'] = 'hs10_selection'
271-
response = f"선택하신 HS6 코드: {selected['code']}\n\nHS10 코드 후보를 선택해 주세요:\n" + '\n'.join([
309+
response = f"선택하신 HS 6자리 코드: {selected['code']}\n\nHS 10자리 코드 후보를 선택해 주세요:\n" + '\n'.join([
272310
f"{i+1}. {c['code']} - {c['description']}" for i, c in enumerate(resp.hs10_candidates or [])
273311
]) + f"\n\n💡 **위 후보 중 하나를 선택해 주세요.**\n예시: \"1번\", \"2번\", \"3번\" 등"
274312
self.state['responses'].append(response)

core/tariff_prediction/tools/parse_hs_results.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66

77
@tool
88
def parse_hs6_result(hs6_result: str) -> List[Dict]:
9-
"""HS6 결과를 파싱합니다."""
9+
"""HS6 결과를 파싱합니다. (HS6.csv에서 검색텍스트도 함께 반환)"""
1010
candidates = []
11+
# HS6.csv 파일 로드
12+
data_dir = os.path.join(os.path.dirname(__file__), '..', 'data')
13+
hs6_df = pd.read_csv(os.path.join(data_dir, 'HS6.csv'), dtype={'HS코드': str})
1114

1215
# 결과에서 HS 코드와 확률 추출
1316
lines = hs6_result.strip().split('\n')
@@ -20,9 +23,14 @@ def parse_hs6_result(hs6_result: str) -> List[Dict]:
2023
code = match.group(2)
2124
confidence = float(match.group(3)) / 100.0
2225
hs6_code = code[:4] + '.' + code[4:]
26+
# HS6.csv에서 정보 찾기
27+
hs6_row = hs6_df[hs6_df['HS코드'] == code]
28+
search_text = ""
29+
if not hs6_row.empty:
30+
search_text = str(hs6_row.iloc[0]['검색텍스트'])
2331
candidates.append({
2432
'code': hs6_code,
25-
'description': f'HS6 코드 {hs6_code}',
33+
'description': f'HS코드: {code}, 설명: {search_text}',
2634
'confidence': confidence,
2735
'full_code': code
2836
})

0 commit comments

Comments
 (0)