kcsc-mcp / src /utils /common.py
nicefree19's picture
Upload 105 files
0ee3c92 verified
Raw
History Blame Contribute Delete
4.28 kB
"""
์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜
"""
import os
import json
import uuid
import logging
from datetime import datetime
from typing import Dict, List, Any, Optional, Union
from src import config
logger = config.setup_logger("common")
def generate_unique_id(prefix: str = "") -> str:
"""
๊ณ ์œ  ID ์ƒ์„ฑ
Args:
prefix: ID ์ ‘๋‘์‚ฌ
Returns:
๊ณ ์œ  ID ๋ฌธ์ž์—ด
"""
unique_id = str(uuid.uuid4())
if prefix:
return f"{prefix}-{unique_id}"
return unique_id
def save_json_data(data: Any, filename: str, directory: str = None) -> str:
"""
๋ฐ์ดํ„ฐ๋ฅผ JSON ํŒŒ์ผ๋กœ ์ €์žฅ
Args:
data: ์ €์žฅํ•  ๋ฐ์ดํ„ฐ (JSON ์ง๋ ฌํ™” ๊ฐ€๋Šฅ)
filename: ํŒŒ์ผ๋ช…
directory: ์ €์žฅ ๋””๋ ‰ํ† ๋ฆฌ (๊ธฐ๋ณธ๊ฐ’: config.DATA_DIR)
Returns:
์ €์žฅ๋œ ํŒŒ์ผ์˜ ์ „์ฒด ๊ฒฝ๋กœ
"""
directory = directory or config.DATA_DIR
os.makedirs(directory, exist_ok=True)
# ํƒ€์ž„์Šคํƒฌํ”„ ์ถ”๊ฐ€ (ํŒŒ์ผ๋ช…์— ์ด๋ฏธ ์žˆ์œผ๋ฉด ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Œ)
if not any(part.isdigit() and len(part) == 8 for part in filename.split('_')):
timestamp = datetime.now().strftime("%Y%m%d")
base_name, ext = os.path.splitext(filename)
filename = f"{base_name}_{timestamp}{ext}"
filepath = os.path.join(directory, filename)
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
logger.info(f"๋ฐ์ดํ„ฐ ์ €์žฅ ์™„๋ฃŒ: {filepath}")
return filepath
def format_error_response(error: Exception) -> Dict[str, Any]:
"""
์˜ˆ์™ธ๋ฅผ API ์‘๋‹ต ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
Args:
error: ์˜ˆ์™ธ ๊ฐ์ฒด
Returns:
์˜ค๋ฅ˜ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ๋”•์…”๋„ˆ๋ฆฌ
"""
error_code = getattr(error, 'error_code', 'UNKNOWN')
error_detail = {
"status": "error",
"error": {
"type": error.__class__.__name__,
"code": error_code,
"message": str(error),
"timestamp": datetime.now().isoformat()
}
}
# ์ถ”๊ฐ€ ์ƒ์„ธ ์ •๋ณด๊ฐ€ ์žˆ์œผ๋ฉด ํฌํ•จ
if hasattr(error, 'status_code'):
error_detail["error"]["status_code"] = error.status_code
if hasattr(error, 'response') and error.response:
error_detail["error"]["response"] = error.response
return error_detail
def sanitize_string(text: str) -> str:
"""
๋ฌธ์ž์—ด์—์„œ ์œ„ํ—˜ํ•œ ๋ฌธ์ž ๋˜๋Š” ์ฝ”๋“œ ์‚ฝ์ž… ์‹œ๋„ ์ œ๊ฑฐ
Args:
text: ์ •์ œํ•  ๋ฌธ์ž์—ด
Returns:
์ •์ œ๋œ ๋ฌธ์ž์—ด
"""
if not text:
return ""
# ๊ธฐ๋ณธ์ ์ธ ์ •์ œ (์ค„๋ฐ”๊ฟˆ, ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ ๋“ฑ ์ฒ˜๋ฆฌ)
sanitized = text.replace('<script>', '&lt;script&gt;') \
.replace('</script>', '&lt;/script&gt;')
# ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ถ”๊ฐ€ ์ •์ œ ๋กœ์ง ๊ตฌํ˜„
return sanitized
def merge_metadata(base: Dict[str, Any], updates: Dict[str, Any]) -> Dict[str, Any]:
"""
๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ณ‘ํ•ฉ
Args:
base: ๊ธฐ๋ณธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
updates: ์—…๋ฐ์ดํŠธํ•  ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
Returns:
๋ณ‘ํ•ฉ๋œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
"""
result = base.copy()
if updates:
for key, value in updates.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
# ์ค‘์ฒฉ๋œ ๋”•์…”๋„ˆ๋ฆฌ๋Š” ์žฌ๊ท€์ ์œผ๋กœ ๋ณ‘ํ•ฉ
result[key] = merge_metadata(result[key], value)
else:
# ๊ทธ ์™ธ์—๋Š” ๋ฎ์–ด์“ฐ๊ธฐ
result[key] = value
return result
def normalize_doc_type(doc_type: str) -> str:
"""
๋ฌธ์„œ ์œ ํ˜• ์ •๊ทœํ™”
Args:
doc_type: ์ •๊ทœํ™”ํ•  ๋ฌธ์„œ ์œ ํ˜•
Returns:
์ •๊ทœํ™”๋œ ๋ฌธ์„œ ์œ ํ˜•
"""
if not doc_type:
return ""
# ๋Œ€๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๊ณต๋ฐฑ ์ œ๊ฑฐ
normalized = doc_type.upper().strip()
# ์•Œ๋ ค์ง„ ๋ฌธ์„œ ์œ ํ˜• ๋งคํ•‘
mapping = {
"KDS": "KDS",
"KOREAN DESIGN STANDARD": "KDS",
"KCS": "KCS",
"KOREAN CONSTRUCTION SPECIFICATION": "KCS"
}
return mapping.get(normalized, normalized)