agent 가격협상 무한 루프 수정 + 선행 chat_server 의 가격협상 연출(카드 스크립트 + 협상지표 게이지) 복원, 버짓 확인 입력가 표시 버그, 요약카드 공급사 담당자/날짜 표시 정비. - agent: 가격협상 루프를 라운드 상한(MAX_ROUNDS)으로 종료(카드선택 실패해도 종료 보장 — 기존엔 카드소진에만 의존해 무한 입력). chat_server iteration>=3 동작 복원. - agent: 가격협상 턴에 선택 카드 스크립트(scripts_cards.json)를 script 로 렌더 + 협상지표(indicator.py, 1~99/PZ) 산출해 indicator_value/bot_chat_type 전달. Res_Chat 에 indicator/bot_chat_type, Req_Chat 에 item_price 추가. - agent: 가격협상_확인 멘트에 할인율(discount_rate) 표시, 가격협상_확인_버짓이 target 이 아니라 입력가(input_price)를 표시하도록 수정. - backend: item_price(기존 공급가) 를 agent 로 전달. 요약카드 공급사 담당자 정보를 supplier_users(빈 이메일) 대신 partner.suppliers.manager_* 에서 조회, ChatSummary.supplier_manager_phone 추가. - frontend: 요약카드 협상 개시/종료 시각을 "YYYY년 MM월 dd일 HH시 MM분 SS초"(KST) 로, 공급 계약 만료일(+1년) ISO 파싱, 우선협상 대상자에 공급사 연락처/이메일 표시. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
43 lines
1.8 KiB
Python
43 lines
1.8 KiB
Python
"""협상지표(협상 성공률) 산출 — 3구간 모델.
|
|
|
|
선행 chat_server 의 ThreeSegIndicator 를 우리 구현으로 재작성(브랜드/특정사 비포함, CLEANROOM.md).
|
|
가격협상(카드선택) 턴에 화면 게이지로 표시할 값을 만든다. anchor < target 전제
|
|
(anchor=우선협상 기준가, target=목표 매입가). 구매자 관점이라 제시가가 낮을수록 지표가 높다.
|
|
|
|
- PZ1: 제시가 ≤ anchor → 99 (우선협상 가능 구간)
|
|
- PZ2: anchor < 제시가 < target → 99→80 선형 보간(19 스텝)
|
|
- PZ3: 제시가 ≥ target → 79 에서 지수감쇠, 최소 1
|
|
|
|
반환: (indicator_value 1~99, indicator_range "PZ1"|"PZ2"|"PZ3") 또는 입력이 부적합하면 None.
|
|
backend 컬럼이 NUMERIC(8,6)(절대값 <100)이라 값은 항상 1~99 범위로 보장한다.
|
|
"""
|
|
|
|
import math
|
|
from typing import Optional, Tuple
|
|
|
|
|
|
def compute_indicator(anchor_price, current_price, target_price) -> Optional[Tuple[int, str]]:
|
|
try:
|
|
anchor = float(anchor_price)
|
|
current = float(current_price)
|
|
target = float(target_price)
|
|
except (TypeError, ValueError):
|
|
return None
|
|
if target <= 0 or current <= 0:
|
|
return None
|
|
|
|
# PZ1 — 우선협상 구간(제시가가 앵커가 이하)
|
|
if current <= anchor:
|
|
return 99, "PZ1"
|
|
|
|
# PZ2 — 협상 가능 구간(앵커가 초과 ~ 목표가 미만): 99→80 선형 보간
|
|
if anchor < current < target:
|
|
value = int(math.floor(99 - ((current - anchor) / (target - anchor) * 19)))
|
|
return max(80, min(99, value)), "PZ2"
|
|
|
|
# PZ3 — 목표가 이상: 79 에서 목표가 정규화 지수감쇠, 최소 1
|
|
scale_exponent = int(math.floor(math.log10(target)))
|
|
k = math.pow(10, -scale_exponent)
|
|
raw_score = 79 * math.exp(-k * (current - target))
|
|
return max(1, int(math.floor(raw_score))), "PZ3"
|