SAP-ERP-AI-Agent / src /api /schemas.py
daisysooyeon's picture
deploy: SAP ERP AI Agent (HF Spaces docker)
50efdc6
Raw
History Blame Contribute Delete
2.45 kB
"""
src/api/schemas.py
FastAPI / LangGraphμ—μ„œ μ‚¬μš©ν•˜λŠ” Pydantic μš”μ²­/응닡 μŠ€ν‚€λ§ˆ
"""
from pydantic import BaseModel, Field, field_validator
from typing import Optional, Literal
class ERPActionRequest(BaseModel):
"""Worker Aκ°€ LLM을 톡해 μΆ”μΆœν•˜λŠ” ERP μˆ˜μ • μš”μ²­ μŠ€ν‚€λ§ˆ"""
# νŒ¨λ”©μ€ LLM이 μ•„λ‹ˆλΌ worker_a ν›„μ²˜λ¦¬ μ½”λ“œκ°€ λ‹΄λ‹Ήν•œλ‹€. LLM은 원본 숫자λ₯Ό
# κ·ΈλŒ€λ‘œ μΆ”μΆœν•˜λ©΄ λ˜λ―€λ‘œ(예: "6105"), 1~N자리λ₯Ό ν—ˆμš©ν•œλ‹€.
order_id: str = Field(..., description="SAP μ˜μ—… μ˜€λ” 번호 (VBELN), 원본 숫자 κ·ΈλŒ€λ‘œ", pattern=r"^\d{1,10}$")
item_no: str = Field(..., description="μ˜€λ” μ•„μ΄ν…œ 번호 (POSNR), 원본 숫자 κ·ΈλŒ€λ‘œ", pattern=r"^\d{1,6}$")
action_type: Literal["CHANGE_QTY", "CHANGE_DATE", "CANCEL_ITEM", "CHANGE_ADDR", "OTHER"]
# μ ˆλŒ€ μˆ˜λŸ‰: "set quantity to 264" β†’ 264
new_quantity: Optional[int] = Field(None, ge=1, description="λ³€κ²½ ν›„ μ ˆλŒ€ μˆ˜λŸ‰ (μ–‘μˆ˜). μ ˆλŒ€ 지정일 λ•Œλ§Œ μ‚¬μš©")
# μƒλŒ€ μˆ˜λŸ‰ λ³€ν™”: "reduce by 50" β†’ -50, "increase by 30" β†’ +30.
# worker_aκ°€ ν˜„μž¬ μˆ˜λŸ‰(KWMENG)을 μ‘°νšŒν•΄ new_quantity둜 ν™˜μ‚°ν•œλ‹€.
quantity_change: Optional[int] = Field(None, description="μƒλŒ€ μˆ˜λŸ‰ λ³€ν™” (κ°μ†Œ=음수, 증가=μ–‘μˆ˜)")
new_date: Optional[str] = Field(None, description="λ³€κ²½ 납기일 (YYYY-MM-DD)")
new_address: Optional[str] = Field(None, description="λ³€κ²½ 배솑지 μ£Όμ†Œ (자유 ν…μŠ€νŠΈ)")
@field_validator("new_quantity")
@classmethod
def qty_must_be_positive(cls, v: Optional[int]) -> Optional[int]:
if v is not None and v <= 0:
raise ValueError("μˆ˜λŸ‰μ€ λ°˜λ“œμ‹œ μ–‘μˆ˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.")
return v
class RunRequest(BaseModel):
"""POST /api/run μš”μ²­ μŠ€ν‚€λ§ˆ"""
email_text: str = Field(..., description="μ²˜λ¦¬ν•  이메일 원문 ν…μŠ€νŠΈ")
thread_id: Optional[str] = Field(None, description="μŠ€λ ˆλ“œ ID (λ―Έμ§€μ • μ‹œ μžλ™ 생성)")
class RunResponse(BaseModel):
"""POST /api/run 응닡 μŠ€ν‚€λ§ˆ"""
thread_id: str
intent: Optional[str] = None
erp_status: Optional[str] = None
final_response: Optional[str] = None
requires_approval: bool = False
class ApproveResponse(BaseModel):
"""GET /api/approve 응닡 μŠ€ν‚€λ§ˆ"""
thread_id: str
approved: bool
final_status: str # SUCCESS | REJECTED | FAILED
message: str
errors: list[str] = []