Spaces:
Running
Running
| """ | |
| Asset Text Parser | |
| ================== | |
| ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ํ ์คํธ์์ ํฌ์ธํธ/๋ง์ผ๋ฆฌ์ง ์ ๋ณด๋ฅผ ์๋ ์ถ์ถํฉ๋๋ค. | |
| ์์ ์ ๋ ฅ: | |
| - "๋ํํญ๊ณต 45,000 ๋ง์ผ" | |
| - "AMEX MR 50000์ " | |
| - "์ฒด์ด์ค UR 30,000" | |
| """ | |
| import re | |
| from typing import Dict, Any, List, Optional | |
| from datetime import datetime | |
| from .config import POINT_VALUATIONS | |
| # ============================================================================= | |
| # ํ๋ก๊ทธ๋จ ๋ณ์นญ ๋งคํ | |
| # ============================================================================= | |
| PROGRAM_ALIASES = { | |
| # ํ๊ตญ ํญ๊ณต | |
| "๋ํํญ๊ณต": "KOREAN_AIR", | |
| "๋ํ": "KOREAN_AIR", | |
| "kal": "KOREAN_AIR", | |
| "korean air": "KOREAN_AIR", | |
| "์ค์นด์ดํจ์ค": "KOREAN_AIR", | |
| "์์์๋": "ASIANA", | |
| "oz": "ASIANA", | |
| "asiana": "ASIANA", | |
| # ๋ฏธ๊ตญ ํญ๊ณต | |
| "delta": "DELTA_SKYMILES", | |
| "๋ธํ": "DELTA_SKYMILES", | |
| "skymiles": "DELTA_SKYMILES", | |
| "united": "UNITED_MILEAGEPLUS", | |
| "์ ๋์ดํฐ๋": "UNITED_MILEAGEPLUS", | |
| "mileageplus": "UNITED_MILEAGEPLUS", | |
| "american": "AA_AADVANTAGE", | |
| "aa": "AA_AADVANTAGE", | |
| "์๋ฉ๋ฆฌ์นธ": "AA_AADVANTAGE", | |
| "aadvantage": "AA_AADVANTAGE", | |
| # ์ ์ฉ์นด๋ ํฌ์ธํธ | |
| "amex": "AMEX_MR", | |
| "์๋ฉ์ค": "AMEX_MR", | |
| "mr": "AMEX_MR", | |
| "membership rewards": "AMEX_MR", | |
| "chase": "CHASE_UR", | |
| "์ฒด์ด์ค": "CHASE_UR", | |
| "ur": "CHASE_UR", | |
| "ultimate rewards": "CHASE_UR", | |
| "citi": "CITI_TYP", | |
| "์ํฐ": "CITI_TYP", | |
| "typ": "CITI_TYP", | |
| "thankyou": "CITI_TYP", | |
| "capital one": "CAPITAL_ONE", | |
| "์บํผํ์": "CAPITAL_ONE", | |
| # ํธํ ํฌ์ธํธ | |
| "marriott": "MARRIOTT_BONVOY", | |
| "๋ฉ๋ฆฌ์ดํธ": "MARRIOTT_BONVOY", | |
| "๋ณธ๋ณด์ด": "MARRIOTT_BONVOY", | |
| "bonvoy": "MARRIOTT_BONVOY", | |
| "hilton": "HILTON_HONORS", | |
| "ํํผ": "HILTON_HONORS", | |
| "honors": "HILTON_HONORS", | |
| "ihg": "IHG_REWARDS", | |
| "hyatt": "HYATT_WOH", | |
| "ํ์ํธ": "HYATT_WOH", | |
| "woh": "HYATT_WOH", | |
| "world of hyatt": "HYATT_WOH", | |
| } | |
| # ============================================================================= | |
| # ํ์ฑ ํจ์ | |
| # ============================================================================= | |
| def parse_asset_text(text: str) -> List[Dict[str, Any]]: | |
| """ | |
| ํ ์คํธ์์ ํฌ์ธํธ/๋ง์ผ๋ฆฌ์ง ์ ๋ณด๋ฅผ ์ถ์ถํฉ๋๋ค. | |
| Args: | |
| text: ์ฌ์ฉ์ ์ ๋ ฅ ํ ์คํธ | |
| Returns: | |
| ์ถ์ถ๋ ์์ฐ ๋ชฉ๋ก [{"program": "...", "amount": ...}, ...] | |
| """ | |
| assets = [] | |
| # ์ค ๋จ์ + ์ผํ ๋จ์๋ก ๋ถ๋ฆฌ | |
| lines = re.split(r'[\n,]', text) | |
| for line in lines: | |
| line = line.strip() | |
| if not line: | |
| continue | |
| result = _parse_single_line(line) | |
| if result: | |
| # ์ค๋ณต ์ ๊ฑฐ (๊ฐ์ ํ๋ก๊ทธ๋จ์ด๋ฉด ํฉ์ฐ) | |
| existing = next( | |
| (a for a in assets if a["program"] == result["program"]), | |
| None | |
| ) | |
| if existing: | |
| existing["amount"] += result["amount"] | |
| else: | |
| assets.append(result) | |
| return assets | |
| def _parse_single_line(line: str) -> Optional[Dict[str, Any]]: | |
| """๋จ์ผ ๋ผ์ธ์์ ํ๋ก๊ทธ๋จ๊ณผ ์๋ ์ถ์ถ.""" | |
| line_lower = line.lower() | |
| # ์ซ์ ์ถ์ถ (์ผํ ์ ๊ฑฐ) | |
| numbers = re.findall(r'[\d,]+', line) | |
| if not numbers: | |
| return None | |
| # ๊ฐ์ฅ ํฐ ์ซ์๋ฅผ amount๋ก ์ฌ์ฉ | |
| amount = max(int(n.replace(',', '')) for n in numbers if n.replace(',', '').isdigit()) | |
| if amount == 0: | |
| return None | |
| # ํ๋ก๊ทธ๋จ ์๋ณ | |
| program = None | |
| for alias, prog_id in PROGRAM_ALIASES.items(): | |
| if alias in line_lower: | |
| program = prog_id | |
| break | |
| if not program: | |
| # ์ซ์๋ง ์๋ ๊ฒฝ์ฐ - ๋ฌธ๋งฅ์ผ๋ก ์ถ๋ก ๋ถ๊ฐ | |
| return None | |
| return {"program": program, "amount": amount} | |
| def normalize_program_name(name: str) -> Optional[str]: | |
| """ํ๋ก๊ทธ๋จ ๋ณ์นญ์ ์ ๊ทํํฉ๋๋ค.""" | |
| name_lower = name.lower().strip() | |
| return PROGRAM_ALIASES.get(name_lower) | |
| # ============================================================================= | |
| # MCP Tool ํธ๋ค๋ฌ | |
| # ============================================================================= | |
| async def handle_parse_asset_text( | |
| arguments: Dict[str, Any], | |
| user_id: str | |
| ) -> Dict[str, Any]: | |
| """ | |
| user_parse_asset_text Tool ํธ๋ค๋ฌ. | |
| ์ฌ์ฉ์ ์ ๋ ฅ ํ ์คํธ์์ ํฌ์ธํธ/๋ง์ผ๋ฆฌ์ง๋ฅผ ์๋ ์ถ์ถํฉ๋๋ค. | |
| """ | |
| text = arguments.get("text", "") | |
| save_to_profile = arguments.get("save_to_profile", False) | |
| if not text: | |
| return { | |
| "success": False, | |
| "error": "ํ์ฑํ ํ ์คํธ๊ฐ ์์ต๋๋ค.", | |
| "usage": "์: '๋ํํญ๊ณต 45000 ๋ง์ผ, AMEX MR 50000์ '" | |
| } | |
| # ํ์ฑ | |
| assets = parse_asset_text(text) | |
| if not assets: | |
| return { | |
| "success": False, | |
| "error": "์ธ์ ๊ฐ๋ฅํ ํฌ์ธํธ/๋ง์ผ๋ฆฌ์ง ์ ๋ณด๊ฐ ์์ต๋๋ค.", | |
| "tip": "ํ๋ก๊ทธ๋จ๋ช ๊ณผ ์ซ์๋ฅผ ํจ๊ป ์ ๋ ฅํด์ฃผ์ธ์. ์: '๋ํํญ๊ณต 45000'", | |
| "supported_programs": list(POINT_VALUATIONS.keys()) | |
| } | |
| # ํ๋ก๊ทธ๋จ ์ด๋ฆ ๋ณด๊ฐ | |
| for asset in assets: | |
| prog_info = POINT_VALUATIONS.get(asset["program"], {}) | |
| asset["program_name"] = prog_info.get("name", asset["program"]) | |
| asset["currency"] = prog_info.get("currency", "USD") | |
| result = { | |
| "success": True, | |
| "parsed_assets": assets, | |
| "count": len(assets), | |
| "parsed_at": datetime.now().isoformat(), | |
| "tip": "user_get_asset_valuation์ ํธ์ถํ์ฌ ์ด ๊ฐ์น๋ฅผ ๊ณ์ฐํ ์ ์์ต๋๋ค." | |
| } | |
| # ํฅํ: save_to_profile์ด True๋ฉด DB์ ์ ์ฅ | |
| if save_to_profile: | |
| result["save_status"] = "not_implemented" | |
| result["save_note"] = "์์ฐ ์ ์ฅ ๊ธฐ๋ฅ์ ํฅํ ๊ตฌํ ์์ " | |
| return result | |