|
6 | 6 | import tempfile |
7 | 7 | import traceback |
8 | 8 | from typing import Optional, List |
| 9 | +from datetime import datetime |
9 | 10 |
|
10 | 11 | # UTF-8 인코딩 설정 |
11 | 12 | import sys |
|
26 | 27 |
|
27 | 28 | # AI 모델 필수 import |
28 | 29 | from generators.risk_report import RiskReportGenerator |
29 | | -from generators.contract_report import ContractValidationGenerator |
30 | 30 | from generators.clause_report import ClauseReportGenerator |
31 | 31 | from generators.improve_report import ClauseImprovementController |
32 | 32 |
|
|
76 | 76 |
|
77 | 77 | # 위험도 분석기 인스턴스 생성 (필수) |
78 | 78 | risk_report_generator = None |
79 | | -contract_validation_generator = None |
80 | 79 | clause_report_generator = None |
81 | 80 | clause_improvement_controller = None |
82 | 81 | try: |
|
89 | 88 | risk_report_generator = RiskReportGenerator() |
90 | 89 | logger.info("Risk analysis model loaded successfully") |
91 | 90 |
|
92 | | - contract_validation_generator = ContractValidationGenerator() |
93 | | - logger.info("Contract validation model loaded successfully") |
94 | | - |
95 | 91 | clause_report_generator = ClauseReportGenerator() |
96 | 92 | logger.info("Clause report generator loaded successfully") |
97 | 93 |
|
@@ -171,31 +167,6 @@ class RiskAnalysisRequest(BaseModel): |
171 | 167 | model_config = ConfigDict(populate_by_name=True) |
172 | 168 |
|
173 | 169 |
|
174 | | -class ContractValidationRequest(BaseModel): |
175 | | - """계약서 검증 요청 모델 |
176 | | - |
177 | | - Spring backend에서 전달하는 계약서 정보를 담는 데이터 전송 객체입니다. |
178 | | - """ |
179 | | - contract_id: int = Field(..., alias="contractId", description="계약서 ID", example=1) |
180 | | - home_id: int = Field(..., alias="homeId", description="매물 ID", example=100) |
181 | | - owner_id: int = Field(..., alias="ownerId", description="임대인 ID", example=10) |
182 | | - buyer_id: int = Field(..., alias="buyerId", description="임차인 ID", example=20) |
183 | | - contract_date: str = Field(..., alias="contractDate", description="계약 날짜 (YYYY-MM-DD)", example="2024-01-01") |
184 | | - contract_expire_date: str = Field(..., alias="contractExpireDate", description="계약 만료 날짜 (YYYY-MM-DD)", example="2025-12-31") |
185 | | - deposit_price: Optional[int] = Field(None, alias="depositPrice", description="보증금 (원)", example=200000000) |
186 | | - monthly_rent: Optional[int] = Field(None, alias="monthlyRent", description="월세 (원)", example=1000000) |
187 | | - maintenance_fee: Optional[int] = Field(None, alias="maintenanceFee", description="관리비 (원)", example=150000) |
188 | | - special_clauses: List[str] = Field(..., alias="specialClauses", description="특약사항 목록", |
189 | | - example=[ |
190 | | - "임차인은 계약 해지 시 원상복구 비용을 전액 부담한다.", |
191 | | - "애완동물 사육을 허가하되, 추가 보증금 50만원을 납부한다.", |
192 | | - "임대인은 언제든지 3일 전 통보로 계약을 해지할 수 있다.", |
193 | | - "임차인은 전대 및 양도를 할 수 없다.", |
194 | | - "월세를 3일 이상 연체 시 연체료는 일 1%로 한다." |
195 | | - ]) |
196 | | - |
197 | | - model_config = ConfigDict(populate_by_name=True) |
198 | | - |
199 | 170 |
|
200 | 171 | class RestoreCategoryInfo(BaseModel): |
201 | 172 | """원상복구 카테고리 정보""" |
@@ -581,7 +552,6 @@ async def root(): |
581 | 552 | "parse_contract": "/api/parse/contract", |
582 | 553 | "analyze_risk": "/api/analyze/risk", |
583 | 554 | "validate_contract": "/api/contract/validate", |
584 | | - "generate_contract": "/api/contract/generate", |
585 | 555 | "recommend_clauses": "/api/clause/recommend", |
586 | 556 | "improve_clause": "/api/clause/improve" |
587 | 557 | } |
@@ -933,16 +903,66 @@ async def analyze_risk(request: RiskAnalysisRequest): |
933 | 903 | } |
934 | 904 | } |
935 | 905 | }) |
936 | | -async def validate_contract(request: ContractValidationRequest): |
| 906 | +async def validate_contract(request: ContractReportRequest): |
937 | 907 | """계약서 법령 검증 API""" |
938 | 908 | try: |
939 | | - logger.info(f"계약서 검증 시작: contract_id={request.contract_id}") |
| 909 | + logger.info(f"계약서 검증 시작: contract_chat_id={request.contract_chat_id}") |
| 910 | + |
| 911 | + # ContractValidationGenerator 사용 |
| 912 | + from generators.contract_report import ContractValidationGenerator |
940 | 913 |
|
941 | | - # Request DTO를 generator가 기대하는 형식으로 변환 |
| 914 | + # 요청 데이터를 Dict로 변환 |
942 | 915 | contract_data = request.model_dump(by_alias=True) |
943 | 916 |
|
944 | | - # 계약서 검증 수행 |
945 | | - result = contract_validation_generator.validate_contract_for_spring(contract_data) |
| 917 | + # 특약사항을 clauses_data 형식으로 변환 |
| 918 | + clauses_data = { |
| 919 | + "timestamp": "", # ContractValidationGenerator에서 필요하지만 사용하지 않음 |
| 920 | + "total_clauses": len(contract_data.get('specialContracts', [])), |
| 921 | + "clauses": [ |
| 922 | + { |
| 923 | + "order": clause.get('order'), |
| 924 | + "title": clause.get('title'), |
| 925 | + "content": clause.get('content'), |
| 926 | + "assessment": { |
| 927 | + "owner": { |
| 928 | + "level": "안심", |
| 929 | + "reason": "검토 대기 중" |
| 930 | + }, |
| 931 | + "tenant": { |
| 932 | + "level": "안심", |
| 933 | + "reason": "검토 대기 중" |
| 934 | + } |
| 935 | + } |
| 936 | + } for clause in contract_data.get('specialContracts', []) |
| 937 | + ] |
| 938 | + } |
| 939 | + |
| 940 | + # 기본 계약 정보 추출 |
| 941 | + basic_info = { |
| 942 | + "contractChatId": contract_data.get('contractChatId'), |
| 943 | + "ownerName": contract_data.get('ownerName'), |
| 944 | + "ownerAddr": contract_data.get('ownerAddr'), |
| 945 | + "ownerPhoneNum": contract_data.get('ownerPhoneNum'), |
| 946 | + "buyerName": contract_data.get('buyerName'), |
| 947 | + "buyerAddr": contract_data.get('buyerAddr'), |
| 948 | + "buyerPhoneNum": contract_data.get('buyerPhoneNum'), |
| 949 | + "homeAddr1": contract_data.get('homeAddr1'), |
| 950 | + "homeAddr2": contract_data.get('homeAddr2'), |
| 951 | + "residenceType": contract_data.get('residenceType'), |
| 952 | + "exclusiveArea": contract_data.get('exclusiveArea'), |
| 953 | + "homeFloor": contract_data.get('homeFloor'), |
| 954 | + "contractStartDate": contract_data.get('contractStartDate'), |
| 955 | + "contractEndDate": contract_data.get('contractEndDate'), |
| 956 | + "depositPrice": contract_data.get('depositPrice'), |
| 957 | + "monthlyRent": contract_data.get('monthlyRent'), |
| 958 | + "maintenanceFee": contract_data.get('maintenanceFee') |
| 959 | + } |
| 960 | + |
| 961 | + # 적법성 검사 수행 |
| 962 | + result = ContractValidationGenerator.validate_contract_with_clauses( |
| 963 | + clauses_data_json=clauses_data, |
| 964 | + contract_basic_info_json=basic_info |
| 965 | + ) |
946 | 966 |
|
947 | 967 | logger.info(f"계약서 검증 완료: status={result.get('validation_status')}, violations={result.get('total_violations')}") |
948 | 968 |
|
@@ -1164,110 +1184,6 @@ async def recommend_clauses(request: ClauseRecommendationRequest): |
1164 | 1184 | ) |
1165 | 1185 |
|
1166 | 1186 |
|
1167 | | -@app.post("/api/contract/generate", |
1168 | | - summary="계약서 적법성 검사", |
1169 | | - description="""임대차 계약서 정보의 적법성을 검사합니다. |
1170 | | -
|
1171 | | -주요 기능: |
1172 | | -- 계약 조건 적법성 검사 |
1173 | | -- 특약사항 법적 문제 분석 |
1174 | | -- 주의사항 및 위반사항 도출 |
1175 | | -- 개선 권고사항 제공 |
1176 | | -
|
1177 | | -검사 항목: |
1178 | | -- 계약 기간 및 금액의 적정성 |
1179 | | -- 특약사항의 법적 유효성 |
1180 | | -- 임대차보호법 준수 여부 |
1181 | | -- 계약 당사자 정보 완전성 |
1182 | | -
|
1183 | | -응답 형식: |
1184 | | -- 검사 상태 (SAFE/WARN/DANGER) |
1185 | | -- 문제점 목록 (violations/warnings) |
1186 | | -- 계약 정보 요약 |
1187 | | -- 개선 권고사항 |
1188 | | -""", |
1189 | | - tags=["위험도 분석"], |
1190 | | - response_model=ApiResponse) |
1191 | | -async def generate_contract(request: ContractReportRequest): |
1192 | | - """계약서 적법성 검사 API |
1193 | | - |
1194 | | - 임대차 계약서 정보를 분석하여 법적 문제점을 검사합니다. |
1195 | | - """ |
1196 | | - try: |
1197 | | - logger.info(f"계약서 검사 API 호출 - 채팅방 ID: {request.contract_chat_id}") |
1198 | | - |
1199 | | - # 기존 ContractValidationGenerator 사용 |
1200 | | - from generators.contract_report import ContractValidationGenerator |
1201 | | - |
1202 | | - # 요청 데이터를 Dict로 변환 |
1203 | | - contract_data = request.model_dump(by_alias=True) |
1204 | | - |
1205 | | - # 특약사항을 clauses_data 형식으로 변환 |
1206 | | - # timestamp는 ApiResponse에서 자동 생성되므로 여기서는 빈 문자열로 설정 |
1207 | | - clauses_data = { |
1208 | | - "timestamp": "", # ContractValidationGenerator에서 필요하지만 사용하지 않음 |
1209 | | - "total_clauses": len(contract_data.get('specialContracts', [])), |
1210 | | - "clauses": [ |
1211 | | - { |
1212 | | - "order": clause.get('order'), |
1213 | | - "title": clause.get('title'), |
1214 | | - "content": clause.get('content'), |
1215 | | - "assessment": { |
1216 | | - "owner": { |
1217 | | - "level": "안심", |
1218 | | - "reason": "검토 대기 중" |
1219 | | - }, |
1220 | | - "tenant": { |
1221 | | - "level": "안심", |
1222 | | - "reason": "검토 대기 중" |
1223 | | - } |
1224 | | - } |
1225 | | - } for clause in contract_data.get('specialContracts', []) |
1226 | | - ] |
1227 | | - } |
1228 | | - |
1229 | | - # 기본 계약 정보 추출 |
1230 | | - basic_info = { |
1231 | | - "contractChatId": contract_data.get('contractChatId'), |
1232 | | - "ownerName": contract_data.get('ownerName'), |
1233 | | - "ownerAddr": contract_data.get('ownerAddr'), |
1234 | | - "ownerPhoneNum": contract_data.get('ownerPhoneNum'), |
1235 | | - "buyerName": contract_data.get('buyerName'), |
1236 | | - "buyerAddr": contract_data.get('buyerAddr'), |
1237 | | - "buyerPhoneNum": contract_data.get('buyerPhoneNum'), |
1238 | | - "homeAddr1": contract_data.get('homeAddr1'), |
1239 | | - "homeAddr2": contract_data.get('homeAddr2'), |
1240 | | - "residenceType": contract_data.get('residenceType'), |
1241 | | - "exclusiveArea": contract_data.get('exclusiveArea'), |
1242 | | - "homeFloor": contract_data.get('homeFloor'), |
1243 | | - "contractStartDate": contract_data.get('contractStartDate'), |
1244 | | - "contractEndDate": contract_data.get('contractEndDate'), |
1245 | | - "depositPrice": contract_data.get('depositPrice'), |
1246 | | - "monthlyRent": contract_data.get('monthlyRent'), |
1247 | | - "maintenanceFee": contract_data.get('maintenanceFee') |
1248 | | - } |
1249 | | - |
1250 | | - # 적법성 검사 수행 |
1251 | | - result = ContractValidationGenerator.validate_contract_with_clauses( |
1252 | | - clauses_data_json=clauses_data, |
1253 | | - contract_basic_info_json=basic_info |
1254 | | - ) |
1255 | | - |
1256 | | - logger.info(f"계약서 검사 완료 - 상태: {result.get('validation_status')}, 문제: {result.get('total_violations', 0)}개") |
1257 | | - |
1258 | | - return ApiResponse.success( |
1259 | | - data=result, |
1260 | | - message="계약서 적법성 검사가 완료되었습니다." |
1261 | | - ) |
1262 | | - |
1263 | | - except Exception as e: |
1264 | | - logger.error(f"계약서 검사 API 오류: {str(e)}") |
1265 | | - logger.error(traceback.format_exc()) |
1266 | | - return ApiResponse.error( |
1267 | | - message="계약서 검사 중 예상치 못한 오류가 발생했습니다.", |
1268 | | - code="INTERNAL_ERROR" |
1269 | | - ) |
1270 | | - |
1271 | 1187 |
|
1272 | 1188 | @app.post("/api/clause/improve", |
1273 | 1189 | summary="특약 개선", |
|
0 commit comments