feat: 항생제/항구토제 마스터 JSON 추가 + 템플릿 레이아웃

This commit is contained in:
청춘약국
2026-03-18 22:12:52 +09:00
parent 2681da0d01
commit a6725dace4
4 changed files with 274 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
{
"product_id": "MASTER-003",
"apc_code": "0519-ENROFLOXACIN",
"name": "아시엔로 50",
"english_name": "Enrofloxacin 50mg",
"manufacturer": "아시아제약",
"category": "antibiotic",
"category_display": "항생제 (퀴놀론계)",
"target_animal": ["개", "고양이"],
"administration": "경구 (정제)",
"image_url": "/images/enrofloxacin.png",
"indication": "피부감염, 요로감염, 호흡기감염, 상처감염 등 세균성 감염증 치료",
"mechanism": {
"drug_class": "Fluoroquinolone (3세대 퀴놀론)",
"action": "DNA gyrase 및 topoisomerase IV 억제 → 세균 DNA 복제 차단",
"spectrum": "그람양성균, 그람음성균 광범위"
},
"dosage": {
"standard": "5mg/kg 1일 1회",
"duration": "7~14일",
"note": "음식과 함께 또는 공복 투여 가능"
},
"dosage_table": [
{"weight": "5kg", "daily_dose": "25mg", "tablets": "0.5정"},
{"weight": "10kg", "daily_dose": "50mg", "tablets": "1정"},
{"weight": "15kg", "daily_dose": "75mg", "tablets": "1.5정"},
{"weight": "20kg", "daily_dose": "100mg", "tablets": "2정"},
{"weight": "25kg", "daily_dose": "125mg", "tablets": "2.5정"}
],
"warnings": [
"⚠️ 고양이: 5mg/kg 초과 금지 (망막 독성 위험!)",
"⚠️ 성장기 동물: 연골 손상 가능성 (1세 미만 주의)",
"⚠️ 간질/경련 병력 동물 주의",
"⚠️ 제산제(알루미늄, 마그네슘)와 2시간 간격 투여"
],
"contraindications": [
"1세 미만 강아지 (대형견은 18개월 미만)",
"임신/수유 중",
"간질/경련 병력",
"퀴놀론 과민반응 이력"
],
"side_effects": {
"common": ["구토", "설사", "식욕부진"],
"serious": ["고양이 망막 독성 (고용량)", "연골 손상 (성장기)", "경련 (드묾)"]
},
"cat_warning": {
"max_dose": "5mg/kg/day",
"max_duration": "21일",
"risk": "망막 변성 → 실명 가능",
"source": "다수 문헌 보고"
},
"storage": "실온 보관, 습기 피할 것",
"source": {
"guidelines": ["ISCAID Antimicrobial Guidelines"],
"notes": "고양이 망막 독성 관련 다수 증례 보고"
}
}

View File

@@ -0,0 +1,73 @@
{
"product_id": "MASTER-004",
"apc_code": "0519-SERENIA",
"name": "세레니아 정",
"english_name": "Serenia (Maropitant citrate)",
"manufacturer": "조에티스 (Zoetis)",
"category": "antiemetic",
"category_display": "항구토제",
"target_animal": ["개", "고양이"],
"administration": "경구 (정제)",
"image_url": "/images/serenia.png",
"indication": "급성 구토, 멀미(차멀미) 예방 및 치료",
"mechanism": {
"drug_class": "NK1 수용체 길항제",
"action": "구토중추의 NK1 수용체 차단 → 구토 억제",
"feature": "중추 및 말초 모두 작용"
},
"dosage": {
"acute_vomiting": {
"dose": "2mg/kg 1일 1회",
"duration": "최대 5일 연속"
},
"motion_sickness": {
"dose": "8mg/kg",
"timing": "이동 최소 2시간 전 투여",
"note": "공복 상태 권장 (효과 향상)"
}
},
"dosage_table": [
{"weight": "3kg", "acute": "6mg", "motion": "24mg"},
{"weight": "5kg", "acute": "10mg", "motion": "40mg"},
{"weight": "10kg", "acute": "20mg", "motion": "80mg"},
{"weight": "15kg", "acute": "30mg", "motion": "120mg"},
{"weight": "20kg", "acute": "40mg", "motion": "160mg"}
],
"available_strengths": ["16mg", "24mg", "60mg", "160mg"],
"warnings": [
"⚠️ 16주(4개월) 미만 강아지 금지",
"⚠️ 고양이: 급성 구토에만 사용 (멀미 적응증 없음)",
"⚠️ 5일 이상 연속 투여 금지 (급성 구토)",
"⚠️ 차멀미 예방 시 공복 상태에서 효과적"
],
"contraindications": [
"16주 미만 강아지",
"위장관 폐색 의심 시 (구토 억제가 위험)",
"독소 섭취 후 (구토 유도 필요 시)"
],
"side_effects": {
"common": ["침흘림 (일시적)", "무기력"],
"rare": ["설사", "식욕부진"]
},
"clinical_notes": [
"구토 원인 파악 필수 (단순 증상 억제 아님)",
"위장관 폐색, 독소 섭취 시에는 구토 유도가 필요할 수 있음",
"멀미 예방: 이동 2시간 전 + 공복 = 최대 효과"
],
"storage": "실온 보관",
"source": {
"product_info": "Zoetis Serenia Product Information",
"notes": "FDA 승인 수의용 항구토제"
}
}

View File

@@ -471,6 +471,70 @@
</div>
{% endif %}
{% elif drug.category == 'antibiotic' %}
<!-- 항생제 레이아웃 -->
<div class="dosing-section">
<div class="dosing-title">📋 적응증</div>
<div class="dosing-main">{{ drug.indication }}</div>
</div>
<div class="dosage-table-section">
<div class="coverage-title">⚖️ 체중별 용량 ({{ drug.dosage.standard }})</div>
<div class="dosage-grid">
{% for row in drug.dosage_table %}
<div class="dosage-cell">
<div class="dosage-weight">{{ row.weight }}</div>
<div class="dosage-amount">{{ row.tablets }}</div>
</div>
{% endfor %}
</div>
<div class="dosing-note" style="margin-top:2mm;">
투약 기간: {{ drug.dosage.duration }}
</div>
</div>
{% if drug.cat_warning %}
<div class="contraindication-box">
<div class="contraindication-title">🐱 고양이 특별 주의</div>
<ul class="contraindication-list">
<li>❌ 최대 용량: {{ drug.cat_warning.max_dose }}</li>
<li>❌ 위험: {{ drug.cat_warning.risk }}</li>
</ul>
</div>
{% endif %}
{% elif drug.category == 'antiemetic' %}
<!-- 항구토제 레이아웃 -->
<div class="dosing-section">
<div class="dosing-title">📋 적응증</div>
<div class="dosing-main">{{ drug.indication }}</div>
</div>
<div class="coverage-section">
<div class="coverage-title">💊 용법용량</div>
<div class="coverage-table" style="grid-template-columns: 1fr 1fr;">
<div class="coverage-item covered">
<span class="coverage-name" style="font-weight:700;">급성 구토</span>
<span style="font-size:8pt;">{{ drug.dosage.acute_vomiting.dose }}</span>
<span style="font-size:6pt;">최대 {{ drug.dosage.acute_vomiting.duration }}</span>
</div>
<div class="coverage-item covered">
<span class="coverage-name" style="font-weight:700;">멀미 예방</span>
<span style="font-size:8pt;">{{ drug.dosage.motion_sickness.dose }}</span>
<span style="font-size:6pt;">{{ drug.dosage.motion_sickness.timing }}</span>
</div>
</div>
</div>
{% if drug.clinical_notes %}
<div class="gap-warning">
<div class="gap-warning-title">💡 임상 참고</div>
{% for note in drug.clinical_notes %}
<div class="gap-solution">• {{ note }}</div>
{% endfor %}
</div>
{% endif %}
{% else %}
<!-- 기본 레이아웃 -->
<div class="dosing-section">

70
test_v2_4drugs.py Normal file
View File

@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
"""
v2 API 테스트 - 4개 약품 (2페이지)
"""
import os
import sys
sys.path.insert(0, os.path.dirname(__file__))
from animal_med import AnimalMedRendererV2
def main():
print("=" * 60)
print("v2 API 테스트 - 4개 약품 (2페이지)")
print("=" * 60)
renderer = AnimalMedRendererV2()
# 마스터 약품 목록
print("\n[1] 마스터 약품 목록:")
for drug in renderer.list_drugs():
print(f" {drug['product_id']} - {drug['name']} ({drug['category_display']})")
# 4개 약품 모두 사용
test_ids = ["MASTER-001", "MASTER-002", "MASTER-003", "MASTER-004"]
print(f"\n[2] PDF 렌더링 ({len(test_ids)}개 약품)")
for pid in test_ids:
drug = renderer.get_drug(pid)
if drug:
print(f" - {drug['name']} ({drug['category_display']})")
# PDF 생성
output_dir = os.path.join(os.path.dirname(__file__), 'output')
os.makedirs(output_dir, exist_ok=True)
pdf_path = os.path.join(output_dir, 'v2_4drugs_test.pdf')
print(f"\n[3] PDF 생성 중...")
result = renderer.render_to_pdf(
product_ids=test_ids,
output_path=pdf_path,
patient_name="김보호자",
pet_name="초코",
pet_species="푸들",
pet_age="7세"
)
if result['success']:
print(f" ✅ 성공!")
print(f" 📄 PDF: {result['pdf_path']}")
print(f" 약품: {', '.join(result['drugs'])}")
size = os.path.getsize(pdf_path)
print(f" 크기: {size / 1024:.1f} KB")
import fitz
doc = fitz.open(pdf_path)
print(f" 페이지 수: {len(doc)}")
doc.close()
else:
print(f" ❌ 실패: {result.get('error')}")
print("\n" + "=" * 60)
if __name__ == "__main__":
main()