feat: 약재 효능 태그 시스템 추가

- herb_efficacy_tags 테이블 생성 (효능 마스터)
- herb_item_tags 테이블 생성 (약재-효능 다대다 관계)
- 18개 기본 효능 태그 등록 (보혈, 활혈, 보기 등)
- Git 사용 가이드라인 문서 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
시골약사 2026-02-17 02:57:57 +00:00
parent 3f4b9c816a
commit 037e307637
4 changed files with 1551 additions and 0 deletions

341
add_sample_herb_data.py Normal file
View File

@ -0,0 +1,341 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
한약재 샘플 데이터 추가 스크립트
주요 약재들의 확장 정보와 효능 태그를 추가합니다.
"""
import sqlite3
from datetime import datetime
def get_connection():
"""데이터베이스 연결"""
return sqlite3.connect('database/kdrug.db')
def add_herb_extended_data():
"""약재 확장 정보 추가"""
conn = get_connection()
cursor = conn.cursor()
# 주요 약재들의 확장 정보
herbs_data = [
{
'ingredient_code': '3400H1AHM', # 인삼
'property': '',
'taste': '감,미고',
'meridian_tropism': '비,폐,심',
'main_effects': '대보원기, 보비익폐, 생진지갈, 안신증지',
'indications': '기허증, 비허증, 폐허증, 심기허증, 진액부족, 당뇨병',
'contraindications': '실증, 열증, 음허화왕',
'precautions': '복용 중 무 섭취 금지, 고혈압 환자 주의',
'dosage_range': '3-9g',
'dosage_max': '30g',
'active_compounds': '인삼사포닌(ginsenoside Rb1, Rg1, Rg3), 다당체, 아미노산',
'pharmacological_effects': '면역증강, 항피로, 항산화, 혈당조절, 인지능력개선',
'clinical_applications': '만성피로, 면역력저하, 당뇨병 보조치료, 노인성 인지저하',
'tags': [('보기', 5), ('보양', 4), ('안신', 3), ('진통', 2)]
},
{
'ingredient_code': '3400H1ADL', # 감초
'property': '',
'taste': '',
'meridian_tropism': '비,위,폐,심',
'main_effects': '보비익기, 청열해독, 거담지해, 완급지통, 조화제약',
'indications': '비허증, 해수, 인후통, 소화성궤양, 경련성 통증',
'contraindications': '습증, 수종, 고혈압',
'precautions': '장기복용 시 부종 주의, 칼륨 감소 주의',
'dosage_range': '2-10g',
'dosage_max': '30g',
'active_compounds': 'glycyrrhizin, liquiritin, flavonoid, triterpenoid',
'pharmacological_effects': '항염증, 항궤양, 간보호, 진해거담, 항알레르기',
'clinical_applications': '위염, 위궤양, 기관지염, 약물조화, 간염',
'tags': [('보기', 3), ('청열', 3), ('해독', 4), ('거담', 3), ('항염', 4)]
},
{
'ingredient_code': '3400H1ACD', # 당귀
'property': '',
'taste': '감,신',
'meridian_tropism': '간,심,비',
'main_effects': '보혈활혈, 조경지통, 윤장통변',
'indications': '혈허증, 월경부조, 무월경, 변비, 타박상',
'contraindications': '설사, 습성체질',
'precautions': '과량 복용 시 설사 주의',
'dosage_range': '5-15g',
'dosage_max': '30g',
'active_compounds': 'ligustilide, n-butylidene phthalide, ferulic acid',
'pharmacological_effects': '혈액순환개선, 항혈전, 자궁수축조절, 진정진통',
'clinical_applications': '빈혈, 월경불순, 산후조리, 혈액순환장애',
'tags': [('보혈', 5), ('활혈', 5), ('진통', 3)]
},
{
'ingredient_code': '3400H1AGN', # 황기
'property': '',
'taste': '',
'meridian_tropism': '비,폐',
'main_effects': '보기승양, 고표지한, 이수소종, 탁독배농',
'indications': '기허증, 자한, 부종, 탈항, 자궁탈수',
'contraindications': '표실증, 음허화왕',
'precautions': '감기 초기 금지',
'dosage_range': '10-30g',
'dosage_max': '60g',
'active_compounds': 'astragaloside, polysaccharide, flavonoid',
'pharmacological_effects': '면역조절, 항바이러스, 항산화, 신기능보호',
'clinical_applications': '면역력저하, 만성신장염, 당뇨병, 심부전',
'tags': [('보기', 5), ('이수', 3), ('해표', 2)]
},
{
'ingredient_code': '3400H1AEW', # 작약
'property': '',
'taste': '고,산',
'meridian_tropism': '간,비',
'main_effects': '양혈조경, 유간지통, 렴음지한',
'indications': '혈허증, 월경부조, 간혈부족, 자한도한',
'contraindications': '양허설사',
'precautions': '한성약물과 병용 주의',
'dosage_range': '6-15g',
'dosage_max': '30g',
'active_compounds': 'paeoniflorin, albiflorin, benzoic acid',
'pharmacological_effects': '진정진통, 항경련, 항염증, 면역조절',
'clinical_applications': '월경통, 근육경련, 두통, 자가면역질환',
'tags': [('보혈', 4), ('평간', 4), ('진통', 4)]
},
{
'ingredient_code': '3400H1ACF', # 천궁
'property': '',
'taste': '',
'meridian_tropism': '간,담,심포',
'main_effects': '활혈행기, 거풍지통',
'indications': '혈어증, 두통, 월경불순, 풍습비통',
'contraindications': '음허화왕, 월경과다',
'precautions': '출혈 경향 환자 주의',
'dosage_range': '3-10g',
'dosage_max': '15g',
'active_compounds': 'ligustilide, senkyunolide, ferulic acid',
'pharmacological_effects': '혈관확장, 항혈전, 진정진통, 항염증',
'clinical_applications': '편두통, 혈관성 두통, 어혈증, 월경통',
'tags': [('활혈', 5), ('이기', 4), ('진통', 5)]
},
{
'ingredient_code': '3400H1ACG', # 지황(숙지황)
'property': '',
'taste': '',
'meridian_tropism': '간,신',
'main_effects': '보혈자음, 익정전수',
'indications': '혈허증, 간신음허, 수발조백, 유정도한',
'contraindications': '비허설사, 담습',
'precautions': '소화불량 주의',
'dosage_range': '10-30g',
'dosage_max': '60g',
'active_compounds': 'catalpol, rehmannioside, aucubin',
'pharmacological_effects': '조혈촉진, 면역조절, 혈당강하, 신경보호',
'clinical_applications': '빈혈, 당뇨병, 치매예방, 불임증',
'tags': [('보혈', 5), ('보음', 5)]
},
{
'ingredient_code': '3400H1AFJ', # 백출
'property': '',
'taste': '고,감',
'meridian_tropism': '비,위',
'main_effects': '건비익기, 조습이수, 지한안태',
'indications': '비허증, 식욕부진, 설사, 수종, 자한',
'contraindications': '음허조갈',
'precautions': '진액부족 시 주의',
'dosage_range': '6-15g',
'dosage_max': '30g',
'active_compounds': 'atractylenolide, atractylon',
'pharmacological_effects': '위장운동촉진, 이뇨, 항염증, 항종양',
'clinical_applications': '만성설사, 부종, 임신오조',
'tags': [('보기', 4), ('이수', 4), ('소화', 3)]
},
{
'ingredient_code': '3400H1AGM', # 복령
'property': '',
'taste': '감,담',
'meridian_tropism': '심,비,폐,신',
'main_effects': '이수삼습, 건비안신',
'indications': '수종, 소변불리, 비허설사, 불면, 심계',
'contraindications': '음허진액부족',
'precautions': '이뇨제와 병용 주의',
'dosage_range': '10-15g',
'dosage_max': '30g',
'active_compounds': 'pachymic acid, polysaccharide',
'pharmacological_effects': '이뇨, 진정, 항염증, 면역조절',
'clinical_applications': '부종, 불면증, 만성설사',
'tags': [('이수', 5), ('안신', 3), ('보기', 2)]
},
{
'ingredient_code': '3400H1AGI', # 반하
'property': '',
'taste': '',
'meridian_tropism': '비,위,폐',
'main_effects': '조습화담, 강역지구, 소비산결',
'indications': '습담, 구토, 해수담다, 현훈',
'contraindications': '음허조해, 임신',
'precautions': '임산부 금기, 생품 독성 주의',
'dosage_range': '5-10g',
'dosage_max': '15g',
'active_compounds': 'ephedrine, β-sitosterol',
'pharmacological_effects': '진토, 진해거담, 항종양',
'clinical_applications': '임신오조, 기관지염, 현훈증',
'tags': [('거담', 5), ('소화', 3)]
}
]
for herb in herbs_data:
# herb_master_extended 업데이트
cursor.execute("""
UPDATE herb_master_extended
SET property = ?,
taste = ?,
meridian_tropism = ?,
main_effects = ?,
indications = ?,
contraindications = ?,
precautions = ?,
dosage_range = ?,
dosage_max = ?,
active_compounds = ?,
pharmacological_effects = ?,
clinical_applications = ?,
updated_at = CURRENT_TIMESTAMP
WHERE ingredient_code = ?
""", (
herb['property'], herb['taste'], herb['meridian_tropism'],
herb['main_effects'], herb['indications'], herb['contraindications'],
herb['precautions'], herb['dosage_range'], herb['dosage_max'],
herb['active_compounds'], herb['pharmacological_effects'],
herb['clinical_applications'], herb['ingredient_code']
))
# herb_id 조회
cursor.execute("""
SELECT herb_id FROM herb_master_extended
WHERE ingredient_code = ?
""", (herb['ingredient_code'],))
result = cursor.fetchone()
if result:
herb_id = result[0]
# 효능 태그 매핑
for tag_name, strength in herb.get('tags', []):
# 태그 ID 조회
cursor.execute("""
SELECT tag_id FROM herb_efficacy_tags
WHERE tag_name = ?
""", (tag_name,))
tag_result = cursor.fetchone()
if tag_result:
tag_id = tag_result[0]
# 태그 매핑 추가
cursor.execute("""
INSERT OR REPLACE INTO herb_item_tags
(herb_id, tag_id, strength)
VALUES (?, ?, ?)
""", (herb_id, tag_id, strength))
print(f"{herb['ingredient_code']} 데이터 추가 완료")
conn.commit()
conn.close()
def add_prescription_rules():
"""처방 배합 규칙 추가"""
conn = get_connection()
cursor = conn.cursor()
# 몇 가지 대표적인 배합 규칙 추가
rules = [
# 상수(相須) - 서로 도와서 효과를 증강
{
'herb1': '인삼', 'herb2': '황기',
'relationship': '상수',
'description': '두 약재가 함께 사용되면 보기 효과가 증강됨',
'severity': 0
},
{
'herb1': '당귀', 'herb2': '천궁',
'relationship': '상수',
'description': '혈액순환 개선 효과가 증강됨',
'severity': 0
},
# 상사(相使) - 한 약이 다른 약의 효능을 도움
{
'herb1': '반하', 'herb2': '생강',
'relationship': '상사',
'description': '생강이 반하의 독성을 감소시킴',
'severity': 0
},
# 상반(相反) - 함께 사용하면 독성이나 부작용 발생
{
'herb1': '감초', 'herb2': '감수',
'relationship': '상반',
'description': '십팔반(十八反) - 함께 사용 금기',
'severity': 5,
'is_absolute': True
},
{
'herb1': '인삼', 'herb2': '오령지',
'relationship': '상반',
'description': '십구외(十九畏) - 함께 사용 주의',
'severity': 4,
'is_absolute': False
}
]
for rule in rules:
# herb_id 조회
cursor.execute("""
SELECT herb_id FROM herb_master_extended
WHERE name_korean = ?
""", (rule['herb1'],))
herb1_result = cursor.fetchone()
cursor.execute("""
SELECT herb_id FROM herb_master_extended
WHERE name_korean = ?
""", (rule['herb2'],))
herb2_result = cursor.fetchone()
if herb1_result and herb2_result:
cursor.execute("""
INSERT OR REPLACE INTO prescription_rules
(herb1_id, herb2_id, relationship_type, description,
severity_level, is_absolute)
VALUES (?, ?, ?, ?, ?, ?)
""", (
herb1_result[0], herb2_result[0],
rule['relationship'], rule['description'],
rule['severity'], rule.get('is_absolute', False)
))
print(f"{rule['herb1']} - {rule['herb2']} 규칙 추가")
conn.commit()
conn.close()
def main():
"""메인 실행 함수"""
print("\n" + "="*80)
print("한약재 샘플 데이터 추가")
print("="*80 + "\n")
try:
# 1. 약재 확장 정보 및 태그 추가
print("1. 약재 확장 정보 추가 중...")
add_herb_extended_data()
# 2. 처방 규칙 추가
print("\n2. 처방 배합 규칙 추가 중...")
add_prescription_rules()
print("\n✨ 모든 샘플 데이터가 성공적으로 추가되었습니다!")
except Exception as e:
print(f"\n❌ 오류 발생: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()

300
app.py
View File

@ -2183,6 +2183,306 @@ def complete_survey(survey_token):
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
# ================ 한약재 확장 정보 API ================
@app.route('/api/herbs/<int:herb_id>/extended', methods=['GET'])
def get_herb_extended_info(herb_id):
"""약재 확장 정보 조회"""
try:
with get_db() as conn:
cursor = conn.cursor()
# 기본 정보 + 확장 정보 조회
cursor.execute("""
SELECT
hme.*,
hm.herb_name,
hm.herb_name_hanja
FROM herb_master_extended hme
LEFT JOIN herb_masters hm ON hme.ingredient_code = hm.ingredient_code
WHERE hme.herb_id = ?
""", (herb_id,))
herb_info = cursor.fetchone()
if not herb_info:
return jsonify({'error': '약재 정보를 찾을 수 없습니다'}), 404
# 효능 태그 조회
cursor.execute("""
SELECT
het.tag_name,
het.tag_category,
het.description,
hit.strength
FROM herb_item_tags hit
JOIN herb_efficacy_tags het ON hit.tag_id = het.tag_id
WHERE hit.herb_id = ?
ORDER BY hit.strength DESC, het.tag_category
""", (herb_id,))
tags = []
for row in cursor.fetchall():
tags.append({
'name': row['tag_name'],
'category': row['tag_category'],
'description': row['description'],
'strength': row['strength']
})
# 안전성 정보 조회
cursor.execute("""
SELECT * FROM herb_safety_info
WHERE herb_id = ?
""", (herb_id,))
safety_info = cursor.fetchone()
result = dict(herb_info)
result['efficacy_tags'] = tags
result['safety_info'] = dict(safety_info) if safety_info else None
return jsonify(result)
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/herbs/<int:herb_id>/extended', methods=['PUT'])
def update_herb_extended_info(herb_id):
"""약재 확장 정보 수정"""
try:
data = request.json
with get_db() as conn:
cursor = conn.cursor()
# 업데이트할 필드 동적 생성
update_fields = []
update_values = []
allowed_fields = [
'property', 'taste', 'meridian_tropism',
'main_effects', 'indications', 'contraindications',
'precautions', 'dosage_range', 'dosage_max',
'preparation_method', 'active_compounds',
'pharmacological_effects', 'clinical_applications'
]
for field in allowed_fields:
if field in data:
update_fields.append(f"{field} = ?")
update_values.append(data[field])
if update_fields:
update_values.append(herb_id)
cursor.execute(f"""
UPDATE herb_master_extended
SET {', '.join(update_fields)},
updated_at = CURRENT_TIMESTAMP
WHERE herb_id = ?
""", update_values)
# 변경 로그 기록
cursor.execute("""
INSERT INTO data_update_logs
(update_type, source, target_table, target_id, after_data)
VALUES ('MANUAL', 'API', 'herb_master_extended', ?, ?)
""", (herb_id, json.dumps(data, ensure_ascii=False)))
conn.commit()
return jsonify({'success': True, 'message': '정보가 업데이트되었습니다'})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/herbs/<int:herb_id>/tags', methods=['GET'])
def get_herb_tags(herb_id):
"""약재 효능 태그 조회"""
try:
with get_db() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT
het.tag_id,
het.tag_name,
het.tag_category,
het.description,
hit.strength
FROM herb_item_tags hit
JOIN herb_efficacy_tags het ON hit.tag_id = het.tag_id
WHERE hit.herb_id = ?
ORDER BY hit.strength DESC
""", (herb_id,))
tags = []
for row in cursor.fetchall():
tags.append({
'tag_id': row['tag_id'],
'name': row['tag_name'],
'category': row['tag_category'],
'description': row['description'],
'strength': row['strength']
})
return jsonify(tags)
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/herbs/<int:herb_id>/tags', methods=['POST'])
def add_herb_tag(herb_id):
"""약재에 효능 태그 추가"""
try:
data = request.json
tag_id = data.get('tag_id')
strength = data.get('strength', 3)
with get_db() as conn:
cursor = conn.cursor()
cursor.execute("""
INSERT OR REPLACE INTO herb_item_tags
(herb_id, tag_id, strength)
VALUES (?, ?, ?)
""", (herb_id, tag_id, strength))
conn.commit()
return jsonify({'success': True, 'message': '태그가 추가되었습니다'})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/herbs/search-by-efficacy', methods=['GET'])
def search_herbs_by_efficacy():
"""효능별 약재 검색"""
try:
tag_names = request.args.getlist('tags')
if not tag_names:
return jsonify({'error': '검색할 태그를 지정해주세요'}), 400
with get_db() as conn:
cursor = conn.cursor()
placeholders = ','.join('?' * len(tag_names))
cursor.execute(f"""
SELECT DISTINCT
hme.herb_id,
hme.name_korean,
hme.name_hanja,
hme.main_effects,
GROUP_CONCAT(het.tag_name) as tags
FROM herb_master_extended hme
JOIN herb_item_tags hit ON hme.herb_id = hit.herb_id
JOIN herb_efficacy_tags het ON hit.tag_id = het.tag_id
WHERE het.tag_name IN ({placeholders})
GROUP BY hme.herb_id
ORDER BY hme.name_korean
""", tag_names)
results = []
for row in cursor.fetchall():
results.append({
'herb_id': row['herb_id'],
'name_korean': row['name_korean'],
'name_hanja': row['name_hanja'],
'main_effects': row['main_effects'],
'tags': row['tags'].split(',') if row['tags'] else []
})
return jsonify(results)
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/prescription-check', methods=['POST'])
def check_prescription_safety():
"""처방 안전성 검증"""
try:
data = request.json
herb_ids = data.get('herb_ids', [])
if len(herb_ids) < 2:
return jsonify({'safe': True, 'warnings': []})
with get_db() as conn:
cursor = conn.cursor()
warnings = []
# 약재 조합 규칙 확인
for i in range(len(herb_ids)):
for j in range(i + 1, len(herb_ids)):
cursor.execute("""
SELECT
relationship_type,
description,
severity_level,
is_absolute
FROM prescription_rules
WHERE (herb1_id = ? AND herb2_id = ?)
OR (herb1_id = ? AND herb2_id = ?)
""", (herb_ids[i], herb_ids[j], herb_ids[j], herb_ids[i]))
rule = cursor.fetchone()
if rule:
# 상반(相反), 상살(相殺) 등 위험한 관계 체크
if rule['relationship_type'] in ['상반', '상살']:
warnings.append({
'type': 'danger',
'herbs': [herb_ids[i], herb_ids[j]],
'relationship': rule['relationship_type'],
'description': rule['description'],
'is_absolute': rule['is_absolute']
})
elif rule['relationship_type'] == '상외':
warnings.append({
'type': 'warning',
'herbs': [herb_ids[i], herb_ids[j]],
'relationship': rule['relationship_type'],
'description': rule['description']
})
# 절대 금기 사항이 있으면 안전하지 않음
is_safe = not any(w.get('is_absolute') for w in warnings)
return jsonify({
'safe': is_safe,
'warnings': warnings
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/efficacy-tags', methods=['GET'])
def get_all_efficacy_tags():
"""모든 효능 태그 조회"""
try:
with get_db() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT * FROM herb_efficacy_tags
ORDER BY tag_category, tag_name
""")
tags = []
for row in cursor.fetchall():
tags.append({
'tag_id': row['tag_id'],
'name': row['tag_name'],
'category': row['tag_category'],
'description': row['description']
})
return jsonify(tags)
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
# 데이터베이스 초기화
if not os.path.exists(app.config['DATABASE']):

View File

@ -0,0 +1,462 @@
# 한약재 정보 관리 시스템 (K-Drug Information System)
## 1. 개요
### 1.1 목표
- 양방약 DUR(Drug Utilization Review) 시스템처럼 한약재 정보를 체계적으로 관리
- AI/API를 통한 지속적인 정보 업데이트
- 근거 기반 한의학(Evidence-Based Korean Medicine) 데이터베이스 구축
### 1.2 벤치마킹
- **건강보험심사평가원 의약품안전사용서비스(DUR)**
- **KIMS (대한민국의약정보센터)**
- **Micromedex (미국)**
- **한국한의학연구원 전통의학정보포털**
## 2. 데이터베이스 설계
### 2.1 핵심 테이블 구조
```sql
-- 1. 약재 기본 정보 (확장)
CREATE TABLE herb_master_extended (
herb_id INTEGER PRIMARY KEY,
ingredient_code VARCHAR(10) UNIQUE,
-- 기본 명칭
name_korean VARCHAR(100) NOT NULL,
name_hanja VARCHAR(100),
name_latin VARCHAR(200),
name_english VARCHAR(200),
name_pharmaceutical VARCHAR(200), -- 약전명
-- 분류 정보
family_latin VARCHAR(100), -- 과명
genus_species VARCHAR(200), -- 학명
origin_plant TEXT, -- 기원식물
medicinal_part VARCHAR(100), -- 약용부위
-- 성미귀경
property VARCHAR(50), -- 성(性): 한/열/온/량/평
taste VARCHAR(100), -- 미(味): 고/감/산/신/함/담
meridian_tropism TEXT, -- 귀경: 입경 경락
-- 효능 효과
main_effects TEXT, -- 주요 효능
indications TEXT, -- 적응증
contraindications TEXT, -- 금기증
precautions TEXT, -- 주의사항
-- 용법 용량
dosage_range VARCHAR(50), -- 상용량 (예: "3-12g")
dosage_max VARCHAR(50), -- 극량
preparation_method TEXT, -- 포제법
-- 성분 정보
active_compounds TEXT, -- 주요 성분
chemical_constituents JSON, -- 화학 성분 상세 (JSON)
-- 약리 작용
pharmacological_effects TEXT, -- 약리작용
clinical_applications TEXT, -- 임상응용
-- 상호작용
drug_interactions JSON, -- 약물 상호작용 (JSON)
food_interactions JSON, -- 음식 상호작용 (JSON)
-- 품질 기준
quality_standards TEXT, -- 품질 기준
identification_method TEXT, -- 감별법
-- 메타데이터
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data_source VARCHAR(100), -- 데이터 출처
reliability_score INTEGER, -- 신뢰도 점수 (1-10)
review_status VARCHAR(20) -- 검토 상태
);
-- 2. 약재 연구 문헌
CREATE TABLE herb_research_papers (
paper_id INTEGER PRIMARY KEY,
herb_id INTEGER REFERENCES herb_master_extended(herb_id),
title TEXT NOT NULL,
authors TEXT,
journal VARCHAR(200),
publication_year INTEGER,
volume VARCHAR(50),
pages VARCHAR(50),
doi VARCHAR(100),
pubmed_id VARCHAR(20),
abstract TEXT,
keywords TEXT,
study_type VARCHAR(50), -- RCT, 관찰연구, 리뷰 등
evidence_level INTEGER, -- 근거수준 (1-5)
findings TEXT, -- 주요 발견
clinical_relevance TEXT, -- 임상적 의미
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
indexed_at TIMESTAMP
);
-- 3. 약재 안전성 정보
CREATE TABLE herb_safety_info (
safety_id INTEGER PRIMARY KEY,
herb_id INTEGER REFERENCES herb_master_extended(herb_id),
-- 독성 정보
toxicity_level VARCHAR(20), -- 독성 등급
ld50_value VARCHAR(50), -- 반수치사량
toxic_compounds TEXT, -- 독성 성분
-- 부작용
common_side_effects TEXT, -- 흔한 부작용
rare_side_effects TEXT, -- 드문 부작용
serious_adverse_events TEXT, -- 중대 이상반응
-- 특수 집단
pregnancy_category VARCHAR(10), -- 임신 등급
pregnancy_safety TEXT, -- 임신 안전성
lactation_safety TEXT, -- 수유 안전성
pediatric_use TEXT, -- 소아 사용
geriatric_use TEXT, -- 노인 사용
-- 모니터링
monitoring_parameters TEXT, -- 모니터링 항목
laboratory_tests TEXT, -- 필요 검사
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 4. 처방 구성 규칙
CREATE TABLE prescription_rules (
rule_id INTEGER PRIMARY KEY,
-- 배합 규칙
herb1_id INTEGER,
herb2_id INTEGER,
relationship_type VARCHAR(50), -- 상수/상사/상외/상오/상쇄/상반/상살
description TEXT,
clinical_significance TEXT,
evidence_source TEXT,
severity_level INTEGER, -- 심각도 (1-5)
action_required VARCHAR(50), -- 조치사항
is_absolute BOOLEAN, -- 절대 금기 여부
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 5. 질병-약재 매핑
CREATE TABLE disease_herb_mapping (
mapping_id INTEGER PRIMARY KEY,
disease_code VARCHAR(20), -- KCD 코드
disease_name VARCHAR(200),
herb_id INTEGER REFERENCES herb_master_extended(herb_id),
indication_type VARCHAR(50), -- 주적응증/부적응증
evidence_level INTEGER, -- 근거수준
recommendation_grade VARCHAR(10), -- 권고등급
clinical_notes TEXT,
references TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 6. AI/API 업데이트 로그
CREATE TABLE data_update_logs (
log_id INTEGER PRIMARY KEY,
update_type VARCHAR(50), -- AI/API/MANUAL
source VARCHAR(100), -- 데이터 소스
target_table VARCHAR(50),
target_id INTEGER,
before_data JSON, -- 변경 전 데이터
after_data JSON, -- 변경 후 데이터
update_reason TEXT,
confidence_score FLOAT, -- AI 신뢰도
is_reviewed BOOLEAN DEFAULT FALSE,
reviewed_by VARCHAR(50),
review_notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
## 3. API/AI 연동 방안
### 3.1 외부 데이터 소스
#### 국내 소스
- **한국한의학연구원 API**
- 한약재 데이터베이스
- 처방 데이터베이스
- 임상 연구 자료
- **건강보험심사평가원**
- 한약제제 급여 정보
- 안전성 정보
- **식품의약품안전처**
- 한약재 품질 기준
- 안전성 정보
#### 국제 소스
- **PubMed API**
- 한약재 연구 논문
- 임상시험 결과
- **WHO Traditional Medicine**
- 국제 표준 정보
- 안전성 데이터
- **ClinicalTrials.gov**
- 진행 중인 임상시험
### 3.2 AI 활용 방안
```python
# AI 기반 정보 추출 및 업데이트 예시
class HerbInfoAIUpdater:
def __init__(self):
self.nlp_model = load_korean_medical_nlp()
self.ocr_model = load_medical_ocr()
def extract_from_literature(self, pdf_path):
"""의학 문헌에서 약재 정보 추출"""
text = self.ocr_model.extract_text(pdf_path)
entities = self.nlp_model.extract_entities(text, types=[
'HERB_NAME',
'DOSAGE',
'INDICATION',
'CONTRAINDICATION',
'SIDE_EFFECT',
'INTERACTION'
])
return self.validate_and_structure(entities)
def update_from_clinical_data(self, clinical_records):
"""임상 데이터에서 패턴 분석"""
# 처방 패턴 분석
prescription_patterns = self.analyze_prescription_patterns(clinical_records)
# 효능 검증
efficacy_data = self.validate_efficacy(clinical_records)
# 안전성 모니터링
safety_signals = self.detect_safety_signals(clinical_records)
return {
'patterns': prescription_patterns,
'efficacy': efficacy_data,
'safety': safety_signals
}
def cross_reference_validation(self, herb_info):
"""교차 검증"""
sources = [
self.query_kmri_api(herb_info['name']),
self.query_pubmed(herb_info['latin_name']),
self.query_who_database(herb_info['code'])
]
return self.reconcile_information(sources)
```
## 4. 기능 구현
### 4.1 약재 정보 조회 API
```python
@app.route('/api/herbs/<int:herb_id>/full-info', methods=['GET'])
def get_herb_full_info(herb_id):
"""약재 종합 정보 조회"""
return {
'basic_info': get_basic_info(herb_id),
'pharmacology': get_pharmacology(herb_id),
'safety': get_safety_info(herb_id),
'interactions': get_interactions(herb_id),
'research': get_research_papers(herb_id),
'clinical_use': get_clinical_applications(herb_id)
}
@app.route('/api/herbs/search', methods=['POST'])
def search_herbs_advanced():
"""고급 검색"""
criteria = request.json
# 증상으로 검색
if criteria.get('symptoms'):
return search_by_symptoms(criteria['symptoms'])
# 성분으로 검색
if criteria.get('compounds'):
return search_by_compounds(criteria['compounds'])
# 처방 호환성 검색
if criteria.get('compatibility'):
return check_prescription_compatibility(criteria['herbs'])
```
### 4.2 안전성 검증 시스템
```python
class HerbSafetyChecker:
def check_prescription_safety(self, herbs, patient_info):
"""처방 안전성 종합 검증"""
results = {
'is_safe': True,
'warnings': [],
'contraindications': [],
'interactions': [],
'dosage_alerts': []
}
# 1. 약재 간 상호작용 확인
for herb1, herb2 in combinations(herbs, 2):
interaction = self.check_herb_interaction(herb1, herb2)
if interaction:
results['interactions'].append(interaction)
# 2. 환자 특성별 금기 확인
if patient_info.get('pregnancy'):
self.check_pregnancy_safety(herbs, results)
if patient_info.get('allergies'):
self.check_allergy_risk(herbs, patient_info['allergies'], results)
# 3. 용량 검증
self.validate_dosages(herbs, results)
# 4. 질병-약물 상호작용
if patient_info.get('conditions'):
self.check_disease_interactions(herbs, patient_info['conditions'], results)
return results
```
### 4.3 데이터 품질 관리
```python
class DataQualityManager:
def validate_herb_data(self, herb_data):
"""데이터 품질 검증"""
scores = {
'completeness': self.check_completeness(herb_data),
'accuracy': self.verify_accuracy(herb_data),
'consistency': self.check_consistency(herb_data),
'timeliness': self.check_timeliness(herb_data)
}
herb_data['quality_score'] = sum(scores.values()) / len(scores)
herb_data['quality_details'] = scores
return herb_data
def reconcile_conflicts(self, data_sources):
"""데이터 충돌 해결"""
# 신뢰도 기반 가중 평균
weighted_data = {}
for source in data_sources:
weight = source['reliability_score']
for field, value in source['data'].items():
if field not in weighted_data:
weighted_data[field] = []
weighted_data[field].append((value, weight))
# 최종 값 결정
final_data = {}
for field, values in weighted_data.items():
final_data[field] = self.select_best_value(values)
return final_data
```
## 5. 사용자 인터페이스
### 5.1 약재 정보 대시보드
- 약재 상세 정보 카드
- 효능/효과 시각화
- 안전성 정보 알림
- 연구 논문 목록
- 처방 활용 통계
### 5.2 처방 안전성 검증
- 실시간 DUR 체크
- 약재 조합 검증
- 용량 적정성 평가
- 환자별 맞춤 알림
### 5.3 지식 관리 도구
- 새로운 연구 결과 알림
- 데이터 품질 모니터링
- AI 제안 검토
- 전문가 협업 도구
## 6. 구현 로드맵
### Phase 1: 기반 구축 (1-2개월)
- [ ] 확장 데이터베이스 스키마 구현
- [ ] 기본 CRUD API 개발
- [ ] 데이터 마이그레이션
### Phase 2: 외부 연동 (2-3개월)
- [ ] 한의학연구원 API 연동
- [ ] PubMed API 연동
- [ ] 자동 업데이트 스케줄러
### Phase 3: AI 통합 (3-4개월)
- [ ] NLP 모델 훈련
- [ ] 문헌 자동 분석
- [ ] 패턴 인식 시스템
### Phase 4: 안전성 시스템 (2개월)
- [ ] DUR 체크 시스템
- [ ] 실시간 경고 시스템
- [ ] 보고서 생성
### Phase 5: 고도화 (지속)
- [ ] 사용자 피드백 수집
- [ ] 모델 개선
- [ ] 새로운 데이터 소스 추가
## 7. 기대 효과
1. **근거 기반 처방**
- 최신 연구 결과 반영
- 객관적 데이터 기반 의사결정
2. **환자 안전성 향상**
- 실시간 안전성 검증
- 부작용 예방
3. **업무 효율성**
- 자동화된 정보 관리
- 빠른 정보 검색
4. **지식 축적**
- 체계적인 데이터베이스
- 지속적인 학습 시스템
5. **표준화**
- 한약재 정보 표준화
- 품질 관리 체계화

View File

@ -0,0 +1,448 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
한약재 확장 정보 테이블 추가
- herb_master_extended: 약재 상세 정보
- herb_research_papers: 연구 문헌
- herb_safety_info: 안전성 정보
- prescription_rules: 처방 구성 규칙
- disease_herb_mapping: 질병-약재 매핑
- data_update_logs: AI/API 업데이트 로그
"""
import sqlite3
from datetime import datetime
def get_connection():
"""데이터베이스 연결"""
return sqlite3.connect('../database/kdrug.db')
def create_herb_master_extended():
"""약재 확장 정보 테이블 생성"""
conn = get_connection()
cursor = conn.cursor()
# 기존 테이블 확인
cursor.execute("""
SELECT name FROM sqlite_master
WHERE type='table' AND name='herb_master_extended'
""")
if cursor.fetchone():
print("herb_master_extended 테이블이 이미 존재합니다.")
else:
cursor.execute("""
CREATE TABLE herb_master_extended (
herb_id INTEGER PRIMARY KEY AUTOINCREMENT,
ingredient_code VARCHAR(10) UNIQUE,
-- 기본 명칭
name_korean VARCHAR(100) NOT NULL,
name_hanja VARCHAR(100),
name_latin VARCHAR(200),
name_english VARCHAR(200),
name_pharmaceutical VARCHAR(200), -- 약전명
-- 분류 정보
family_latin VARCHAR(100), -- 과명
genus_species VARCHAR(200), -- 학명
origin_plant TEXT, -- 기원식물
medicinal_part VARCHAR(100), -- 약용부위
-- 성미귀경
property VARCHAR(50), -- (): ////
taste VARCHAR(100), -- (): /////
meridian_tropism TEXT, -- 귀경: 입경 경락
-- 효능 효과
main_effects TEXT, -- 주요 효능
indications TEXT, -- 적응증
contraindications TEXT, -- 금기증
precautions TEXT, -- 주의사항
-- 용법 용량
dosage_range VARCHAR(50), -- 상용량 (: "3-12g")
dosage_max VARCHAR(50), -- 극량
preparation_method TEXT, -- 포제법
-- 성분 정보
active_compounds TEXT, -- 주요 성분
chemical_constituents TEXT, -- 화학 성분 상세 (JSON)
-- 약리 작용
pharmacological_effects TEXT, -- 약리작용
clinical_applications TEXT, -- 임상응용
-- 상호작용
drug_interactions TEXT, -- 약물 상호작용 (JSON)
food_interactions TEXT, -- 음식 상호작용 (JSON)
-- 품질 기준
quality_standards TEXT, -- 품질 기준
identification_method TEXT, -- 감별법
-- 메타데이터
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data_source VARCHAR(100), -- 데이터 출처
reliability_score INTEGER, -- 신뢰도 점수 (1-10)
review_status VARCHAR(20) -- 검토 상태
)
""")
print("✅ herb_master_extended 테이블이 생성되었습니다.")
# 기존 herb_masters 데이터 마이그레이션
cursor.execute("""
INSERT INTO herb_master_extended (
ingredient_code, name_korean, name_hanja, name_latin
)
SELECT
ingredient_code,
herb_name AS name_korean,
herb_name_hanja AS name_hanja,
herb_name_latin AS name_latin
FROM herb_masters
""")
print(f" - {cursor.rowcount}개의 기존 데이터가 마이그레이션되었습니다.")
conn.commit()
conn.close()
def create_herb_research_papers():
"""약재 연구 문헌 테이블 생성"""
conn = get_connection()
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS herb_research_papers (
paper_id INTEGER PRIMARY KEY AUTOINCREMENT,
herb_id INTEGER,
title TEXT NOT NULL,
authors TEXT,
journal VARCHAR(200),
publication_year INTEGER,
volume VARCHAR(50),
pages VARCHAR(50),
doi VARCHAR(100),
pubmed_id VARCHAR(20),
abstract TEXT,
keywords TEXT,
study_type VARCHAR(50), -- RCT, 관찰연구, 리뷰
evidence_level INTEGER, -- 근거수준 (1-5)
findings TEXT, -- 주요 발견
clinical_relevance TEXT, -- 임상적 의미
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
indexed_at TIMESTAMP
)
""")
print("✅ herb_research_papers 테이블이 생성되었습니다.")
conn.commit()
conn.close()
def create_herb_safety_info():
"""약재 안전성 정보 테이블 생성"""
conn = get_connection()
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS herb_safety_info (
safety_id INTEGER PRIMARY KEY AUTOINCREMENT,
herb_id INTEGER,
-- 독성 정보
toxicity_level VARCHAR(20), -- 독성 등급
ld50_value VARCHAR(50), -- 반수치사량
toxic_compounds TEXT, -- 독성 성분
-- 부작용
common_side_effects TEXT, -- 흔한 부작용
rare_side_effects TEXT, -- 드문 부작용
serious_adverse_events TEXT, -- 중대 이상반응
-- 특수 집단
pregnancy_category VARCHAR(10), -- 임신 등급
pregnancy_safety TEXT, -- 임신 안전성
lactation_safety TEXT, -- 수유 안전성
pediatric_use TEXT, -- 소아 사용
geriatric_use TEXT, -- 노인 사용
-- 모니터링
monitoring_parameters TEXT, -- 모니터링 항목
laboratory_tests TEXT, -- 필요 검사
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
print("✅ herb_safety_info 테이블이 생성되었습니다.")
conn.commit()
conn.close()
def create_prescription_rules():
"""처방 구성 규칙 테이블 생성"""
conn = get_connection()
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS prescription_rules (
rule_id INTEGER PRIMARY KEY AUTOINCREMENT,
-- 배합 규칙
herb1_id INTEGER,
herb2_id INTEGER,
relationship_type VARCHAR(50), -- 상수/상사/상외/상오/상쇄/상반/상살
description TEXT,
clinical_significance TEXT,
evidence_source TEXT,
severity_level INTEGER, -- 심각도 (1-5)
action_required VARCHAR(50), -- 조치사항
is_absolute BOOLEAN, -- 절대 금기 여부
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# 인덱스 추가
cursor.execute("""
CREATE INDEX IF NOT EXISTS idx_prescription_rules_herbs
ON prescription_rules(herb1_id, herb2_id)
""")
print("✅ prescription_rules 테이블이 생성되었습니다.")
conn.commit()
conn.close()
def create_disease_herb_mapping():
"""질병-약재 매핑 테이블 생성"""
conn = get_connection()
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS disease_herb_mapping (
mapping_id INTEGER PRIMARY KEY AUTOINCREMENT,
disease_code VARCHAR(20), -- KCD 코드
disease_name VARCHAR(200),
herb_id INTEGER,
indication_type VARCHAR(50), -- 주적응증/부적응증
evidence_level INTEGER, -- 근거수준
recommendation_grade VARCHAR(10), -- 권고등급
clinical_notes TEXT,
references TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# 인덱스 추가
cursor.execute("""
CREATE INDEX IF NOT EXISTS idx_disease_herb_mapping
ON disease_herb_mapping(disease_code, herb_id)
""")
print("✅ disease_herb_mapping 테이블이 생성되었습니다.")
conn.commit()
conn.close()
def create_data_update_logs():
"""AI/API 업데이트 로그 테이블 생성"""
conn = get_connection()
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS data_update_logs (
log_id INTEGER PRIMARY KEY AUTOINCREMENT,
update_type VARCHAR(50), -- AI/API/MANUAL
source VARCHAR(100), -- 데이터 소스
target_table VARCHAR(50),
target_id INTEGER,
before_data TEXT, -- 변경 데이터 (JSON)
after_data TEXT, -- 변경 데이터 (JSON)
update_reason TEXT,
confidence_score REAL, -- AI 신뢰도
is_reviewed BOOLEAN DEFAULT 0,
reviewed_by VARCHAR(50),
review_notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
print("✅ data_update_logs 테이블이 생성되었습니다.")
conn.commit()
conn.close()
def create_herb_efficacy_tags():
"""약재 효능 태그 시스템 테이블 생성"""
conn = get_connection()
cursor = conn.cursor()
# 효능 태그 마스터 테이블
cursor.execute("""
CREATE TABLE IF NOT EXISTS herb_efficacy_tags (
tag_id INTEGER PRIMARY KEY AUTOINCREMENT,
tag_name VARCHAR(50) UNIQUE NOT NULL,
tag_category VARCHAR(30), -- 보익/거사/조리/기타
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# 약재-태그 매핑 테이블
cursor.execute("""
CREATE TABLE IF NOT EXISTS herb_item_tags (
item_tag_id INTEGER PRIMARY KEY AUTOINCREMENT,
herb_id INTEGER,
tag_id INTEGER,
strength INTEGER DEFAULT 3, -- 효능 강도 (1-5)
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(herb_id, tag_id)
)
""")
# 기본 효능 태그 삽입
basic_tags = [
('보혈', '보익', '혈을 보하는 효능'),
('보기', '보익', '기를 보하는 효능'),
('보양', '보익', '양기를 보하는 효능'),
('보음', '보익', '음액을 보하는 효능'),
('활혈', '거사', '혈액순환을 개선하는 효능'),
('거담', '거사', '담을 제거하는 효능'),
('이수', '거사', '수분대사를 개선하는 효능'),
('해표', '거사', '표증을 해소하는 효능'),
('청열', '거사', '열을 내리는 효능'),
('해독', '거사', '독을 해소하는 효능'),
('이기', '조리', '기의 순환을 조절하는 효능'),
('소화', '조리', '소화를 돕는 효능'),
('안신', '조리', '정신을 안정시키는 효능'),
('평간', '조리', '간기능을 조절하는 효능'),
('지혈', '기타', '출혈을 멈추는 효능'),
('진통', '기타', '통증을 완화하는 효능'),
('항염', '기타', '염증을 억제하는 효능'),
('항균', '기타', '균을 억제하는 효능')
]
for tag_name, tag_category, description in basic_tags:
cursor.execute("""
INSERT OR IGNORE INTO herb_efficacy_tags (tag_name, tag_category, description)
VALUES (?, ?, ?)
""", (tag_name, tag_category, description))
print("✅ herb_efficacy_tags 테이블이 생성되었습니다.")
print(f" - {len(basic_tags)}개의 기본 효능 태그가 등록되었습니다.")
conn.commit()
conn.close()
def add_sample_data():
"""샘플 데이터 추가"""
conn = get_connection()
cursor = conn.cursor()
# 인삼 상세 정보 업데이트
cursor.execute("""
UPDATE herb_master_extended
SET
property = '',
taste = '감,미고',
meridian_tropism = '비,폐,심',
main_effects = '대보원기, 보비익폐, 생진지갈, 안신증지',
indications = '기허증, 비허증, 폐허증, 심기허증, 진액부족',
contraindications = '실증, 열증',
precautions = '복용 중 무 섭취 금지',
dosage_range = '3-9g',
dosage_max = '30g',
active_compounds = '인삼사포닌(ginsenoside), 다당체, 아미노산',
pharmacological_effects = '면역증강, 항피로, 항산화, 혈당조절',
clinical_applications = '만성피로, 면역력저하, 당뇨병 보조치료'
WHERE ingredient_code = '3400H1AHM'
""")
# 감초 상세 정보 업데이트
cursor.execute("""
UPDATE herb_master_extended
SET
property = '',
taste = '',
meridian_tropism = '비,위,폐,심',
main_effects = '보비익기, 청열해독, 거담지해, 완급지통, 조화제약',
indications = '비허증, 해수, 인후통, 소화성궤양',
contraindications = '습증, 수종',
precautions = '장기복용 시 부종 주의',
dosage_range = '2-10g',
dosage_max = '30g',
active_compounds = 'glycyrrhizin, flavonoid, triterpenoid',
pharmacological_effects = '항염증, 항궤양, 간보호, 진해거담',
clinical_applications = '위염, 위궤양, 기관지염, 약물조화'
WHERE ingredient_code = '3400H1ADL'
""")
print("✅ 샘플 데이터가 추가되었습니다.")
conn.commit()
conn.close()
def main():
"""메인 실행 함수"""
print("\n" + "="*80)
print("한약재 확장 정보 시스템 테이블 생성")
print("="*80 + "\n")
try:
# 1. 확장 정보 테이블 생성
create_herb_master_extended()
# 2. 연구 문헌 테이블 생성
create_herb_research_papers()
# 3. 안전성 정보 테이블 생성
create_herb_safety_info()
# 4. 처방 규칙 테이블 생성
create_prescription_rules()
# 5. 질병-약재 매핑 테이블 생성
create_disease_herb_mapping()
# 6. 업데이트 로그 테이블 생성
create_data_update_logs()
# 7. 효능 태그 시스템 생성
create_herb_efficacy_tags()
# 8. 샘플 데이터 추가
add_sample_data()
print("\n✨ 모든 테이블이 성공적으로 생성되었습니다!")
except Exception as e:
print(f"\n❌ 오류 발생: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()