From 773f35a1694eb21e7dbf994a936db1f3a2413388 Mon Sep 17 00:00:00 2001 From: 99hyuk Date: Mon, 12 May 2025 23:05:18 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[FEAT]=20=EC=9E=90=EA=B0=80=EC=A7=84?= =?UTF-8?q?=EB=8B=A8=20=EB=A7=A4=ED=95=91,=20=EB=B3=91=EC=9B=90=20QnA,=20?= =?UTF-8?q?=EC=83=81=ED=99=A9=EB=B3=84=20=EA=B0=80=EC=9D=B4=EB=93=9C=20jso?= =?UTF-8?q?n=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/data/medical_qna.json | 436 ++++ .../resources/data/medical_visit_guide.json | 291 +++ .../data/symptom_department_mapping.json | 1948 +++++++++++++++++ 3 files changed, 2675 insertions(+) create mode 100644 src/main/resources/data/medical_qna.json create mode 100644 src/main/resources/data/medical_visit_guide.json create mode 100644 src/main/resources/data/symptom_department_mapping.json diff --git a/src/main/resources/data/medical_qna.json b/src/main/resources/data/medical_qna.json new file mode 100644 index 0000000..521cefb --- /dev/null +++ b/src/main/resources/data/medical_qna.json @@ -0,0 +1,436 @@ +[ + { + "category": { + "ko": "의료 시스템 이해", + "en": "Understanding the System" + }, + "question": { + "ko": "의사보다 간호사가 먼저 보는 경우가 있나요?", + "en": "Do nurses examine patients before doctors?" + }, + "answer": { + "ko": "초진 시 간호사가 먼저 기초 문진을 하고, 이후 의사 진료가 진행될 수 있습니다.", + "en": "Yes, in many cases, a nurse will first conduct a basic interview before the doctor sees the patient." + } + }, + { + "category": { + "ko": "의료 시스템 이해", + "en": "Understanding the System" + }, + "question": { + "ko": "진료 시간은 보통 얼마나 걸리나요?", + "en": "How long is a typical consultation?" + }, + "answer": { + "ko": "일반적으로 5~10분 내외이며, 대형병원은 짧을 수 있습니다.", + "en": "Usually about 5–10 minutes. In large hospitals, it may be even shorter." + } + }, + { + "category": { + "ko": "의료 시스템 이해", + "en": "Understanding the System" + }, + "question": { + "ko": "당일에 검사(MRI, CT 등)도 가능한가요?", + "en": "Can I get an MRI or CT scan on the same day?" + }, + "answer": { + "ko": "가능하지만 대부분 사전 예약이 필요하며 당일 시행은 드뭅니다.", + "en": "It's possible, but most hospitals require an appointment. Same-day procedures are rare." + } + }, + { + "category": { + "ko": "의료 시스템 이해", + "en": "Understanding the System" + }, + "question": { + "ko": "진료 후 약은 병원에서 받나요?", + "en": "Do I receive medicine directly from the hospital?" + }, + "answer": { + "ko": "아니요. 병원에서 처방전을 받고 외부 약국에서 약을 수령합니다.", + "en": "No. You will receive a prescription and must go to a pharmacy to get your medicine." + } + }, + { + "category": { + "ko": "의료 시스템 이해", + "en": "Understanding the System" + }, + "question": { + "ko": "진료과를 직접 선택할 수 있나요?", + "en": "Can I choose my own department?" + }, + "answer": { + "ko": "경증인 경우 가능하지만, 종합병원은 접수 시 안내에 따라 지정됩니다.", + "en": "At small clinics, yes. At general hospitals, staff usually decide based on your symptoms." + } + }, + { + "category": { + "ko": "보험 및 비용", + "en": "Insurance & Costs" + }, + "question": { + "ko": "건강보험이 없으면 병원비가 비싸나요?", + "en": "Is it expensive without Korean health insurance?" + }, + "answer": { + "ko": "보험 미가입 시 전액 본인 부담으로 상대적으로 비쌉니다.", + "en": "Yes. Without insurance, you must pay the full amount, which can be costly." + } + }, + { + "category": { + "ko": "보험 및 비용", + "en": "Insurance & Costs" + }, + "question": { + "ko": "진료비는 어떤 기준으로 계산되나요?", + "en": "How are medical fees calculated?" + }, + "answer": { + "ko": "진찰료, 검사비, 투약료 등으로 구분되어 청구됩니다.", + "en": "Fees are based on consultation, tests, medications, and other services." + } + }, + { + "category": { + "ko": "보험 및 비용", + "en": "Insurance & Costs" + }, + "question": { + "ko": "해외 보험은 병원에서 직접 처리해주나요?", + "en": "Do hospitals handle overseas insurance directly?" + }, + "answer": { + "ko": "보통 직접 청구해야 하며, 병원에서 영수증과 진단서를 요청해야 합니다.", + "en": "Usually not. You must file the claim yourself with receipts and certificates." + } + }, + { + "category": { + "ko": "보험 및 비용", + "en": "Insurance & Costs" + }, + "question": { + "ko": "영수증 재발급은 어떻게 하나요?", + "en": "Can I get another copy of my receipt?" + }, + "answer": { + "ko": "수납 창구에서 요청하면 재발급 가능합니다.", + "en": "Yes. Ask at the payment counter for a reprint." + } + }, + { + "category": { + "ko": "보험 및 비용", + "en": "Insurance & Costs" + }, + "question": { + "ko": "진단서는 무료인가요?", + "en": "Is a medical certificate free?" + }, + "answer": { + "ko": "아니요. 발급 시 별도 수수료가 부과됩니다.", + "en": "No. There is a separate fee for issuing medical certificates." + } + }, + { + "category": { + "ko": "응급 상황", + "en": "Emergencies" + }, + "question": { + "ko": "응급 상황 시 119에서 영어 통역 가능한가요?", + "en": "Can I speak English when calling 119?" + }, + "answer": { + "ko": "네. 요청 시 영어 통역사 연결이 가능합니다.", + "en": "Yes. English interpreters are available through 119." + } + }, + { + "category": { + "ko": "응급 상황", + "en": "Emergencies" + }, + "question": { + "ko": "야간 진료 가능한 병원은 어디서 찾나요?", + "en": "Where can I find hospitals open at night?" + }, + "answer": { + "ko": "응급실이 있는 병원 또는 지역 보건소 홈페이지에서 확인 가능합니다.", + "en": "Emergency rooms or local health center websites provide this info." + } + }, + { + "category": { + "ko": "응급 상황", + "en": "Emergencies" + }, + "question": { + "ko": "응급실에서 바로 입원할 수 있나요?", + "en": "Can I be admitted directly from the ER?" + }, + "answer": { + "ko": "가능하나 병상 상황에 따라 제한될 수 있습니다.", + "en": "It’s possible, but depends on bed availability." + } + }, + { + "category": { + "ko": "응급 상황", + "en": "Emergencies" + }, + "question": { + "ko": "119 이용은 유료인가요?", + "en": "Is calling 119 free?" + }, + "answer": { + "ko": "아니요. 구조 및 이송은 무료입니다.", + "en": "Yes. Emergency response and transport are free of charge." + } + }, + { + "category": { + "ko": "응급 상황", + "en": "Emergencies" + }, + "question": { + "ko": "응급실에 가면 바로 진료받을 수 있나요?", + "en": "Do I get treated immediately at the ER?" + }, + "answer": { + "ko": "위급 정도에 따라 대기 시간이 달라질 수 있습니다.", + "en": "It depends on how urgent your condition is. You may have to wait." + } + }, + { + "category": { + "ko": "약국 및 약물", + "en": "Pharmacy & Medication" + }, + "question": { + "ko": "처방전 없이 약을 살 수 있나요?", + "en": "Can I buy medicine without a prescription?" + }, + "answer": { + "ko": "일부 일반의약품은 가능하나, 대부분은 처방전이 필요합니다.", + "en": "Some basic medicine is available over the counter, but most require a prescription." + } + }, + { + "category": { + "ko": "약국 및 약물", + "en": "Pharmacy & Medication" + }, + "question": { + "ko": "약 복용 방법이 이해되지 않으면 어떻게 하나요?", + "en": "What if I don’t understand how to take the medicine?" + }, + "answer": { + "ko": "약사에게 영어 설명을 요청하거나 통역 기능을 활용하세요.", + "en": "Ask the pharmacist for an English explanation or use a translation app." + } + }, + { + "category": { + "ko": "약국 및 약물", + "en": "Pharmacy & Medication" + }, + "question": { + "ko": "부작용이 생기면 어떻게 하나요?", + "en": "What should I do if I experience side effects?" + }, + "answer": { + "ko": "즉시 약 복용을 중단하고 병원이나 약사에게 문의하세요.", + "en": "Stop taking the medicine and consult a doctor or pharmacist." + } + }, + { + "category": { + "ko": "약국 및 약물", + "en": "Pharmacy & Medication" + }, + "question": { + "ko": "같은 성분의 외국 약을 복용 중인데 대체 가능한가요?", + "en": "Can I replace my foreign medication with a Korean one?" + }, + "answer": { + "ko": "약사와 상담 후 국내 대체 약을 권장받을 수 있습니다.", + "en": "Yes. Bring your original medication and ask a pharmacist for alternatives." + } + }, + { + "category": { + "ko": "약국 및 약물", + "en": "Pharmacy & Medication" + }, + "question": { + "ko": "약은 병원비에 포함되나요?", + "en": "Is medicine included in the hospital bill?" + }, + "answer": { + "ko": "별도 약국 결제 항목이며 병원비와는 분리됩니다.", + "en": "No. You must pay for it separately at the pharmacy." + } + }, + { + "category": { + "ko": "문화 & 커뮤니케이션", + "en": "Culture & Communication" + }, + "question": { + "ko": "진료 중 통역 앱을 써도 되나요?", + "en": "Can I use a translation app during the consultation?" + }, + "answer": { + "ko": "네. 통역 앱이나 종이 문서 등을 활용해 의사소통 가능합니다.", + "en": "Yes. Using an app or written notes is helpful and acceptable." + } + }, + { + "category": { + "ko": "문화 & 커뮤니케이션", + "en": "Culture & Communication" + }, + "question": { + "ko": "의사에게 질문을 많이 해도 되나요?", + "en": "Is it okay to ask the doctor many questions?" + }, + "answer": { + "ko": "네. 한국에서도 환자의 질문은 당연한 권리입니다.", + "en": "Yes. It’s your right as a patient to ask questions." + } + }, + { + "category": { + "ko": "문화 & 커뮤니케이션", + "en": "Culture & Communication" + }, + "question": { + "ko": "간호사가 설명을 대신하는 경우가 많은가요?", + "en": "Do nurses often explain things instead of doctors?" + }, + "answer": { + "ko": "대형병원에서는 간호사의 안내가 주요 정보를 대신하는 경우가 많습니다.", + "en": "At large hospitals, nurses often provide detailed instructions." + } + }, + { + "category": { + "ko": "문화 & 커뮤니케이션", + "en": "Culture & Communication" + }, + "question": { + "ko": "의사 성별을 요청할 수 있나요?", + "en": "Can I request a doctor of a specific gender?" + }, + "answer": { + "ko": "사전에 요청 가능하지만, 상황에 따라 조정이 어려울 수도 있습니다.", + "en": "Yes, you can ask in advance, but it may not always be possible." + } + }, + { + "category": { + "ko": "문화 & 커뮤니케이션", + "en": "Culture & Communication" + }, + "question": { + "ko": "진료 중 가족과 통화하면서 통역해도 되나요?", + "en": "Can I talk to my family on the phone for interpretation?" + }, + "answer": { + "ko": "가능하나 병원 방침에 따라 제한될 수 있으므로 미리 양해를 구하세요.", + "en": "Usually yes, but ask the hospital staff beforehand to be sure." + } + }, + { + "category": { + "ko": "여성 전용", + "en": "Women" + }, + "question": { + "ko": "산부인과 의사가 남성일 경우 변경 요청 가능한가요?", + "en": "Can I ask for a female doctor at the gynecology department?" + }, + "answer": { + "ko": "가능하며, 미리 접수 시 요청하면 조율될 수 있습니다.", + "en": "Yes. Make the request at registration, and they will try to accommodate you." + } + }, + { + "category": { + "ko": "여성 전용", + "en": "Women" + }, + "question": { + "ko": "생리통, 피임약 관련 상담도 받을 수 있나요?", + "en": "Can I talk about menstrual pain or contraception?" + }, + "answer": { + "ko": "네. 일반 내과 또는 산부인과에서 가능합니다.", + "en": "Yes. These are common issues and can be discussed openly." + } + }, + { + "category": { + "ko": "여성 전용", + "en": "Women" + }, + "question": { + "ko": "여성 전용 진료 공간이 따로 있나요?", + "en": "Are there female-only clinics or departments?" + }, + "answer": { + "ko": "일부 병원에는 별도 공간이 마련되어 있습니다.", + "en": "Some hospitals offer separate women’s clinics or dedicated spaces." + } + }, + { + "category": { + "ko": "장애인/취약 계층", + "en": "Accessibility" + }, + "question": { + "ko": "휠체어로 진입 가능한 병원이 많은가요?", + "en": "Are most hospitals accessible for wheelchairs?" + }, + "answer": { + "ko": "대부분의 병원은 휠체어 접근이 가능하도록 설계되어 있습니다.", + "en": "Yes. Most hospitals have ramps and elevators for wheelchair access." + } + }, + { + "category": { + "ko": "장애인/취약 계층", + "en": "Accessibility" + }, + "question": { + "ko": "청각장애인을 위한 안내 수단이 있나요?", + "en": "Are there services for hearing-impaired patients?" + }, + "answer": { + "ko": "일부 병원은 자막 안내 모니터나 수화 통역을 제공합니다.", + "en": "Some hospitals provide caption screens or sign language interpretation." + } + }, + { + "category": { + "ko": "언어 지원", + "en": "Language Support" + }, + "question": { + "ko": "영어 외 다른 언어 지원도 있나요?", + "en": "Do hospitals support languages other than English?" + }, + "answer": { + "ko": "일부 병원은 중국어, 베트남어 등 다국어 통역 서비스를 제공합니다.", + "en": "Yes. Some offer services in Chinese, Vietnamese, and other languages." + } + } +] \ No newline at end of file diff --git a/src/main/resources/data/medical_visit_guide.json b/src/main/resources/data/medical_visit_guide.json new file mode 100644 index 0000000..387f031 --- /dev/null +++ b/src/main/resources/data/medical_visit_guide.json @@ -0,0 +1,291 @@ +[ + { + "step": 1, + "title": { + "ko": "접수", + "en": "Reception" + }, + "icon": "🏥", + "purpose": { + "ko": "병원 접수 창구에서 진료 접수를 합니다.", + "en": "Check in at the hospital front desk." + }, + "whatToExpect": [ + { + "ko": "여권이나 외국인등록증 제시를 요청받습니다.", + "en": "You will be asked to show your passport or ARC." + }, + { + "ko": "방문 목적 또는 증상에 대해 간단히 물어봅니다.", + "en": "Staff may ask about your reason for visit or symptoms." + }, + { + "ko": "보통 진료 과목 선택은 하지 않아도 되며, 증상에 따라 병원이 지정합니다.", + "en": "You usually don’t need to select a department. The hospital will guide you." + } + ], + "keyPhrases": [ + { + "ko": "진료받고 싶어요", + "en": "I’d like to see a doctor." + }, + { + "ko": "여기 처음 방문했어요", + "en": "This is my first time here." + }, + { + "ko": "예약이 필요한가요?", + "en": "Do I need to make an appointment?" + } + ], + "actionGuide": [ + { + "ko": "여권 또는 외국인등록증 제시", + "en": "Show your passport or ARC." + }, + { + "ko": "증상을 간단히 설명 (통역 기능 활용 가능)", + "en": "Briefly explain your symptoms." + }, + { + "ko": "접수 번호표 또는 대기표 수령", + "en": "Receive a queue number or waiting slip." + } + ], + "tips": [ + { + "ko": "동네 병원은 예약 없이도 방문 가능. 대형병원은 사전 예약 필수인 경우 많음.", + "en": "Small clinics usually accept walk-ins. Big hospitals often require a prior appointment." + } + ] + }, + { + "step": 2, + "title": { + "ko": "대기실", + "en": "Waiting Room" + }, + "icon": "🪑", + "purpose": { + "ko": "진료 호출 전까지 대기합니다.", + "en": "Wait to be called to the consultation room." + }, + "whatToExpect": [ + { + "ko": "대기 구역에서 순서를 기다립니다.", + "en": "You’ll wait in a seating area." + }, + { + "ko": "번호 또는 이름이 화면에 표시되거나 방송으로 호출됩니다.", + "en": "Your name or number will be displayed on a screen or announced over a speaker." + } + ], + "keyPhrases": [ + { + "ko": "기다리는 시간은 얼마나 되나요?", + "en": "How long is the wait?" + }, + { + "ko": "화장실 가도 괜찮나요? 제 차례 놓치지 않나요?", + "en": "Can I go to the restroom? Will I miss my turn?" + } + ], + "actionGuide": [ + { + "ko": "본인 번호 기억 또는 확인", + "en": "Remember your queue number." + }, + { + "ko": "이름/번호 호출 확인", + "en": "Watch or listen for your turn." + }, + { + "ko": "진료실로 이동", + "en": "Proceed to the consultation room when called." + } + ], + "tips": [] + }, + { + "step": 3, + "title": { + "ko": "진료", + "en": "Consultation" + }, + "icon": "👩‍⚕️", + "purpose": { + "ko": "의사에게 증상을 설명하고 진단을 받습니다.", + "en": "Describe your symptoms to the doctor and receive a diagnosis." + }, + "whatToExpect": [ + { + "ko": "일부 의사는 영어가 유창하지 않을 수 있습니다.", + "en": "Some doctors may not speak fluent English." + }, + { + "ko": "간단한 표현이나 통역 기능을 사용하세요.", + "en": "Use simple English or the app’s interpreter tool." + } + ], + "keyPhrases": [ + { + "ko": "목이 아프고 열이 있어요", + "en": "I have a sore throat and a fever." + }, + { + "ko": "3일째 이 증상이 있어요", + "en": "I've had this pain for 3 days." + }, + { + "ko": "페니실린에 알레르기가 있어요", + "en": "I'm allergic to penicillin." + } + ], + "possibleQuestions": [ + { + "ko": "어디가 아픈가요?", + "en": "Where does it hurt?" + }, + { + "ko": "기저질환이 있나요?", + "en": "Do you have any medical history?" + }, + { + "ko": "현재 복용 중인 약이 있나요?", + "en": "Are you taking any medications?" + } + ], + "actionGuide": [ + { + "ko": "필요시 통역 기능(음성/텍스트) 사용", + "en": "Use translation features if needed." + }, + { + "ko": "증상 기록이나 사진 보여주기 (약 복용 기록 등)", + "en": "Show notes, photos, or lists if helpful." + }, + { + "ko": "처방전 발급 및 안내 받기", + "en": "Receive diagnosis and prescription from the doctor." + } + ], + "tips": [ + { + "ko": "짧고 명확하게 설명하고, 통역 기능을 적극 활용하세요.", + "en": "Speak clearly and use simple terms. Let the app assist when needed." + } + ] + }, + { + "step": 4, + "title": { + "ko": "수납", + "en": "Payment" + }, + "icon": "💳", + "purpose": { + "ko": "진료비를 결제하고 영수증 및 처방전을 받습니다.", + "en": "Pay the consultation fee and receive any documents." + }, + "whatToExpect": [ + { + "ko": "별도의 수납창구로 이동하여 결제합니다.", + "en": "Move to the payment counter." + }, + { + "ko": "영수증 및 처방전은 이곳에서 받습니다.", + "en": "You will receive a receipt and prescription here." + } + ], + "keyPhrases": [ + { + "ko": "카드로 결제할 수 있나요?", + "en": "Can I pay with card?" + }, + { + "ko": "보험 청구용 영수증 받을 수 있나요?", + "en": "Can I get a receipt for insurance?" + }, + { + "ko": "국민건강보험이 적용되었나요?", + "en": "Is national insurance applied?" + } + ], + "actionGuide": [ + { + "ko": "결제 금액 확인", + "en": "Confirm payment amount." + }, + { + "ko": "카드 또는 현금으로 결제", + "en": "Pay by card or cash." + }, + { + "ko": "영수증과 처방전 수령", + "en": "Receive your receipt and prescription slip." + } + ], + "tips": [ + { + "ko": "해외 보험 청구를 위해 '영수증'과 '진단서'를 요청하세요.", + "en": "Ask for a medical certificate if you plan to file an insurance claim." + } + ] + }, + { + "step": 5, + "title": { + "ko": "약국", + "en": "Pharmacy" + }, + "icon": "💊", + "purpose": { + "ko": "병원에서 받은 처방전을 가지고 약을 받습니다.", + "en": "Use the prescription to get your medication." + }, + "whatToExpect": [ + { + "ko": "대부분 병원 근처에 약국이 있습니다.", + "en": "Pharmacies are usually located near the hospital or clinic." + }, + { + "ko": "처방전 제출이 필요합니다.", + "en": "You must show your prescription slip." + } + ], + "keyPhrases": [ + { + "ko": "이 처방전을 조제받고 싶어요", + "en": "I’d like to get this prescription filled." + }, + { + "ko": "약 복용 방법은 어떻게 되나요?", + "en": "How do I take this medicine?" + }, + { + "ko": "부작용이 있나요?", + "en": "Are there any side effects?" + } + ], + "actionGuide": [ + { + "ko": "약국에 처방전 제출", + "en": "Go to a nearby pharmacy and present the prescription." + }, + { + "ko": "복용 방법 설명 듣기", + "en": "Ask for dosage instructions." + }, + { + "ko": "약 수령 및 결제", + "en": "Pay and receive your medicine." + } + ], + "tips": [ + { + "ko": "필요시 영어 설명 요청 가능. 일부 약국은 외국인 대응이 가능합니다.", + "en": "Some pharmacies may offer basic English service. Don’t hesitate to ask for help." + } + ] + } +] \ No newline at end of file diff --git a/src/main/resources/data/symptom_department_mapping.json b/src/main/resources/data/symptom_department_mapping.json new file mode 100644 index 0000000..e0ecae2 --- /dev/null +++ b/src/main/resources/data/symptom_department_mapping.json @@ -0,0 +1,1948 @@ +[ + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "속쓰림", + "en": "Heartburn" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "속쓰림 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Heartburn' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "설사", + "en": "Diarrhea" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "설사 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Diarrhea' is typically treated in the Internal Medicine department." + } + }, + { + "type": "three-step", + "system": { + "ko": "호흡기", + "en": "Respiratory" + }, + "symptom": { + "ko": "기침", + "en": "Cough" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "기침 증상은 가래 있음, 열 동반일 경우 내과에서 진료받는 것이 적절합니다.", + "en": "The symptom 'Cough' with condition 'With phlegm and fever' is typically treated in the Internal Medicine department." + }, + "condition": { + "ko": "가래 있음, 열 동반", + "en": "With phlegm and fever" + } + }, + { + "type": "two-step", + "system": { + "ko": "심혈관", + "en": "Cardiovascular" + }, + "symptom": { + "ko": "가슴 답답함", + "en": "Chest tightness" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "가슴 답답함 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Chest tightness' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "복부", + "en": "Digestive" + }, + "symptom": { + "ko": "오른쪽 아랫배 통증", + "en": "Lower right abdominal pain" + }, + "departments": [ + { + "ko": "외과", + "en": "General Surgery" + } + ], + "note": { + "ko": "오른쪽 아랫배 통증 증상은 일반적으로 외과에서 진료받습니다.", + "en": "The symptom 'Lower right abdominal pain' is typically treated in the General Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "외상", + "en": "Injury" + }, + "symptom": { + "ko": "상처", + "en": "Wound" + }, + "departments": [ + { + "ko": "외과", + "en": "General Surgery" + } + ], + "note": { + "ko": "상처 증상은 일반적으로 외과에서 진료받습니다.", + "en": "The symptom 'Wound' is typically treated in the General Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "피부 종기", + "en": "Skin boil" + }, + "departments": [ + { + "ko": "외과", + "en": "General Surgery" + } + ], + "note": { + "ko": "피부 종기 증상은 일반적으로 외과에서 진료받습니다.", + "en": "The symptom 'Skin boil' is typically treated in the General Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "관절", + "en": "Joints" + }, + "symptom": { + "ko": "무릎 통증", + "en": "Knee pain" + }, + "departments": [ + { + "ko": "정형외과", + "en": "Orthopedic Surgery" + } + ], + "note": { + "ko": "무릎 통증 증상은 일반적으로 정형외과에서 진료받습니다.", + "en": "The symptom 'Knee pain' is typically treated in the Orthopedic Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "관절", + "en": "Joints" + }, + "symptom": { + "ko": "어깨 통증", + "en": "Shoulder pain" + }, + "departments": [ + { + "ko": "정형외과", + "en": "Orthopedic Surgery" + } + ], + "note": { + "ko": "어깨 통증 증상은 일반적으로 정형외과에서 진료받습니다.", + "en": "The symptom 'Shoulder pain' is typically treated in the Orthopedic Surgery department." + } + }, + { + "type": "three-step", + "system": { + "ko": "척추", + "en": "Spine" + }, + "symptom": { + "ko": "허리 통증", + "en": "Lower back pain" + }, + "departments": [ + { + "ko": "정형외과", + "en": "Orthopedic Surgery" + } + ], + "note": { + "ko": "허리 통증 증상은 자고 일어난 뒤 악화일 경우 정형외과에서 진료받는 것이 적절합니다.", + "en": "The symptom 'Lower back pain' with condition 'Worse after sleep' is typically treated in the Orthopedic Surgery department." + }, + "condition": { + "ko": "자고 일어난 뒤 악화", + "en": "Worse after sleep" + } + }, + { + "type": "three-step", + "system": { + "ko": "신경계", + "en": "Neurological" + }, + "symptom": { + "ko": "두통", + "en": "Headache" + }, + "departments": [ + { + "ko": "신경외과", + "en": "Neurosurgery" + } + ], + "note": { + "ko": "두통 증상은 갑작스러움, 구토 동반일 경우 신경외과에서 진료받는 것이 적절합니다.", + "en": "The symptom 'Headache' with condition 'Sudden with vomiting' is typically treated in the Neurosurgery department." + }, + "condition": { + "ko": "갑작스러움, 구토 동반", + "en": "Sudden with vomiting" + } + }, + { + "type": "three-step", + "system": { + "ko": "척추", + "en": "Spine" + }, + "symptom": { + "ko": "허리 통증", + "en": "Lower back pain" + }, + "departments": [ + { + "ko": "신경외과", + "en": "Neurosurgery" + } + ], + "note": { + "ko": "허리 통증 증상은 다리 저림 동반일 경우 신경외과에서 진료받는 것이 적절합니다.", + "en": "The symptom 'Lower back pain' with condition 'Accompanied by leg numbness' is typically treated in the Neurosurgery department." + }, + "condition": { + "ko": "다리 저림 동반", + "en": "Accompanied by leg numbness" + } + }, + { + "type": "two-step", + "system": { + "ko": "신경계", + "en": "Neurological" + }, + "symptom": { + "ko": "팔 저림", + "en": "Arm numbness" + }, + "departments": [ + { + "ko": "신경외과", + "en": "Neurosurgery" + } + ], + "note": { + "ko": "팔 저림 증상은 일반적으로 신경외과에서 진료받습니다.", + "en": "The symptom 'Arm numbness' is typically treated in the Neurosurgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "질 분비물", + "en": "Vaginal discharge" + }, + "departments": [ + { + "ko": "산부인과", + "en": "Obstetrics & Gynecology" + } + ], + "note": { + "ko": "질 분비물 증상은 일반적으로 산부인과에서 진료받습니다.", + "en": "The symptom '' is typically treated in the Obstetrics & Gynecology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "생리통", + "en": "Menstrual pain" + }, + "departments": [ + { + "ko": "산부인과", + "en": "Obstetrics & Gynecology" + } + ], + "note": { + "ko": "생리통 증상은 일반적으로 산부인과에서 진료받습니다.", + "en": "The symptom '' is typically treated in the Obstetrics & Gynecology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "임신 관련", + "en": "Pregnancy" + }, + "symptom": { + "ko": "생리 지연", + "en": "Delayed menstruation" + }, + "departments": [ + { + "ko": "산부인과", + "en": "Obstetrics & Gynecology" + } + ], + "note": { + "ko": "생리 지연 증상은 일반적으로 산부인과에서 진료받습니다.", + "en": "The symptom '' is typically treated in the Obstetrics & Gynecology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소아", + "en": "Pediatrics" + }, + "symptom": { + "ko": "고열", + "en": "High fever" + }, + "departments": [ + { + "ko": "소아청소년과", + "en": "Pediatrics" + } + ], + "note": { + "ko": "고열 증상은 일반적으로 소아청소년과에서 진료받습니다.", + "en": "The symptom 'High fever' is typically treated in the Pediatrics department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소아", + "en": "Pediatrics" + }, + "symptom": { + "ko": "복통", + "en": "Abdominal pain" + }, + "departments": [ + { + "ko": "소아청소년과", + "en": "Pediatrics" + } + ], + "note": { + "ko": "복통 증상은 일반적으로 소아청소년과에서 진료받습니다.", + "en": "The symptom '' is typically treated in the Pediatrics department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소아", + "en": "Pediatrics" + }, + "symptom": { + "ko": "성장 지연", + "en": "Growth delay" + }, + "departments": [ + { + "ko": "소아청소년과", + "en": "Pediatrics" + } + ], + "note": { + "ko": "성장 지연 증상은 일반적으로 소아청소년과에서 진료받습니다.", + "en": "The symptom '' is typically treated in the Pediatrics department." + } + }, + { + "type": "two-step", + "system": { + "ko": "정신", + "en": "Mental Health" + }, + "symptom": { + "ko": "불면증", + "en": "Insomnia" + }, + "departments": [ + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "불면증 증상은 일반적으로 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Insomnia' is typically treated in the Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "정신", + "en": "Mental Health" + }, + "symptom": { + "ko": "무기력", + "en": "Fatigue" + }, + "departments": [ + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "무기력 증상은 일반적으로 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Fatigue' is typically treated in the Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "정신", + "en": "Mental Health" + }, + "symptom": { + "ko": "불안감", + "en": "Anxiety" + }, + "departments": [ + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "불안감 증상은 일반적으로 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Anxiety' is typically treated in the Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "가려움", + "en": "Itching" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "가려움 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Itching' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "여드름", + "en": "Acne" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "여드름 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Acne' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "건선", + "en": "Psoriasis" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "건선 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Psoriasis' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "코/목", + "en": "Nose/Throat" + }, + "symptom": { + "ko": "코막힘", + "en": "Nasal congestion" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "코막힘 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Nasal congestion' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "코/목", + "en": "Nose/Throat" + }, + "symptom": { + "ko": "목 아픔", + "en": "Sore throat" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "목 아픔 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Sore throat' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "귀", + "en": "Ear" + }, + "symptom": { + "ko": "귀통증", + "en": "Ear pain" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "귀통증 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Ear pain' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "눈", + "en": "Eye" + }, + "symptom": { + "ko": "눈 가려움", + "en": "Itchy eyes" + }, + "departments": [ + { + "ko": "안과", + "en": "Ophthalmology" + } + ], + "note": { + "ko": "눈 가려움 증상은 일반적으로 안과에서 진료받습니다.", + "en": "The symptom 'Itchy eyes' is typically treated in the Ophthalmology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "눈", + "en": "Eye" + }, + "symptom": { + "ko": "시야 흐림", + "en": "Blurred vision" + }, + "departments": [ + { + "ko": "안과", + "en": "Ophthalmology" + } + ], + "note": { + "ko": "시야 흐림 증상은 일반적으로 안과에서 진료받습니다.", + "en": "The symptom 'Blurred vision' is typically treated in the Ophthalmology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "눈", + "en": "Eye" + }, + "symptom": { + "ko": "눈물 과다", + "en": "Excessive tearing" + }, + "departments": [ + { + "ko": "안과", + "en": "Ophthalmology" + } + ], + "note": { + "ko": "눈물 과다 증상은 일반적으로 안과에서 진료받습니다.", + "en": "The symptom 'Excessive tearing' is typically treated in the Ophthalmology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "소변 시 통증", + "en": "Painful urination" + }, + "departments": [ + { + "ko": "비뇨의학과", + "en": "Urology" + } + ], + "note": { + "ko": "소변 시 통증 증상은 일반적으로 비뇨의학과에서 진료받습니다.", + "en": "The symptom 'Painful urination' is typically treated in the Urology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "소변색 진함", + "en": "Dark urine" + }, + "departments": [ + { + "ko": "비뇨의학과", + "en": "Urology" + } + ], + "note": { + "ko": "소변색 진함 증상은 일반적으로 비뇨의학과에서 진료받습니다.", + "en": "The symptom 'Dark urine' is typically treated in the Urology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "야간 빈뇨", + "en": "Frequent urination at night" + }, + "departments": [ + { + "ko": "비뇨의학과", + "en": "Urology" + } + ], + "note": { + "ko": "야간 빈뇨 증상은 일반적으로 비뇨의학과에서 진료받습니다.", + "en": "The symptom 'Frequent urination at night' is typically treated in the Urology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "재활", + "en": "Rehabilitation" + }, + "symptom": { + "ko": "사지 약화", + "en": "Weakness in limbs" + }, + "departments": [ + { + "ko": "재활의학과", + "en": "Rehabilitation Medicine" + } + ], + "note": { + "ko": "사지 약화 증상은 일반적으로 재활의학과에서 진료받습니다.", + "en": "The symptom 'Weakness in limbs' is typically treated in the Rehabilitation Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "재활", + "en": "Rehabilitation" + }, + "symptom": { + "ko": "보행 불편", + "en": "Difficulty walking" + }, + "departments": [ + { + "ko": "재활의학과", + "en": "Rehabilitation Medicine" + } + ], + "note": { + "ko": "보행 불편 증상은 일반적으로 재활의학과에서 진료받습니다.", + "en": "The symptom 'Difficulty walking' is typically treated in the Rehabilitation Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "치아", + "en": "Teeth" + }, + "symptom": { + "ko": "치통", + "en": "Toothache" + }, + "departments": [ + { + "ko": "치과", + "en": "Dentistry" + } + ], + "note": { + "ko": "치통 증상은 일반적으로 치과에서 진료받습니다.", + "en": "The symptom 'Toothache' is typically treated in the Dentistry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "치아", + "en": "Teeth" + }, + "symptom": { + "ko": "잇몸 출혈", + "en": "Gum bleeding" + }, + "departments": [ + { + "ko": "치과", + "en": "Dentistry" + } + ], + "note": { + "ko": "잇몸 출혈 증상은 일반적으로 치과에서 진료받습니다.", + "en": "The symptom 'Gum bleeding' is typically treated in the Dentistry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "호흡기", + "en": "Respiratory" + }, + "symptom": { + "ko": "숨참", + "en": "Shortness of breath" + }, + "departments": [ + { + "ko": "흉부외과", + "en": "Thoracic Surgery" + } + ], + "note": { + "ko": "숨참 증상은 일반적으로 흉부외과에서 진료받습니다.", + "en": "The symptom 'Shortness of breath' is typically treated in the Thoracic Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "외상", + "en": "Injury" + }, + "symptom": { + "ko": "심한 출혈", + "en": "Severe bleeding" + }, + "departments": [ + { + "ko": "응급의학과", + "en": "Emergency Medicine" + } + ], + "note": { + "ko": "심한 출혈 증상은 일반적으로 응급의학과에서 진료받습니다.", + "en": "The symptom 'Severe bleeding' is typically treated in the Emergency Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "외상", + "en": "Injury" + }, + "symptom": { + "ko": "얼굴 상처", + "en": "Facial wound" + }, + "departments": [ + { + "ko": "성형외과", + "en": "Plastic Surgery" + } + ], + "note": { + "ko": "얼굴 상처 증상은 일반적으로 성형외과에서 진료받습니다.", + "en": "The symptom 'Facial wound' is typically treated in the Plastic Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "점 제거", + "en": "Mole removal" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + }, + { + "ko": "성형외과", + "en": "Plastic Surgery" + } + ], + "note": { + "ko": "점 제거는 일반적으로 피부과에서 진료받지만, 미용 목적일 경우 성형외과도 가능합니다.", + "en": "Mole removal is usually treated in dermatology, but plastic surgery is also possible for cosmetic reasons." + } + }, + { + "type": "three-step", + "system": { + "ko": "호흡기", + "en": "Respiratory" + }, + "symptom": { + "ko": "기침", + "en": "Cough" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + }, + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "기침 증상은 가래 없음, 열 없음일 경우 내과, 이비인후과에서 진료받는 것이 적절합니다.", + "en": "The symptom 'Cough' with condition '' is typically treated in the Internal Medicine, Otorhinolaryngology (ENT) department." + }, + "condition": { + "ko": "가래 없음, 열 없음", + "en": "No phlegm or fever" + } + }, + { + "type": "three-step", + "system": { + "ko": "신경계", + "en": "Neurological" + }, + "symptom": { + "ko": "두통", + "en": "Headache" + }, + "departments": [ + { + "ko": "신경외과", + "en": "Neurosurgery" + }, + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "두통 증상은 장기간 지속, 스트레스 동반일 경우 신경외과, 정신건강의학과에서 진료받는 것이 적절합니다.", + "en": "The symptom 'Headache' with condition '' is typically treated in the Neurosurgery, Psychiatry department." + }, + "condition": { + "ko": "장기간 지속, 스트레스 동반", + "en": "Persistent with stress" + } + }, + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "상복부 통증", + "en": "Upper abdominal pain" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + }, + { + "ko": "외과", + "en": "General Surgery" + } + ], + "note": { + "ko": "상복부 통증 증상은 일반적으로 내과, 외과에서 진료받습니다.", + "en": "The symptom 'Upper abdominal pain' is typically treated in the Internal Medicine, General Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "복부 팽만감", + "en": "Abdominal bloating" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "복부 팽만감 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Abdominal bloating' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "잦은 트림", + "en": "Frequent belching" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "잦은 트림 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Frequent belching' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "변비", + "en": "Constipation" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "변비 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Constipation' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "호흡기", + "en": "Respiratory" + }, + "symptom": { + "ko": "천명음", + "en": "Wheezing" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "천명음 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Wheezing' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "호흡기", + "en": "Respiratory" + }, + "symptom": { + "ko": "마른기침", + "en": "Dry cough" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + }, + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "마른기침 증상은 일반적으로 내과, 이비인후과에서 진료받습니다.", + "en": "The symptom 'Dry cough' is typically treated in the Internal Medicine, Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "심혈관", + "en": "Cardiovascular" + }, + "symptom": { + "ko": "심계항진", + "en": "Palpitations" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + }, + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "심계항진 증상은 일반적으로 내과, 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Palpitations' is typically treated in the Internal Medicine, Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "심혈관", + "en": "Cardiovascular" + }, + "symptom": { + "ko": "혈압 상승", + "en": "High blood pressure" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "혈압 상승 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'High blood pressure' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "두드러기", + "en": "Hives" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "두드러기 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Hives' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "손발 트러블", + "en": "Hand/foot rash" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "손발 트러블 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Hand/foot rash' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "손톱 이상", + "en": "Nail abnormalities" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "손톱 이상 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Nail abnormalities' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "정신", + "en": "Mental Health" + }, + "symptom": { + "ko": "공황발작", + "en": "Panic attack" + }, + "departments": [ + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "공황발작 증상은 일반적으로 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Panic attack' is typically treated in the Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "정신", + "en": "Mental Health" + }, + "symptom": { + "ko": "강박 행동", + "en": "Obsessive behavior" + }, + "departments": [ + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "강박 행동 증상은 일반적으로 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Obsessive behavior' is typically treated in the Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "관절", + "en": "Joints" + }, + "symptom": { + "ko": "손가락 통증", + "en": "Finger joint pain" + }, + "departments": [ + { + "ko": "정형외과", + "en": "Orthopedic Surgery" + } + ], + "note": { + "ko": "손가락 통증 증상은 일반적으로 정형외과에서 진료받습니다.", + "en": "The symptom 'Finger joint pain' is typically treated in the Orthopedic Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "관절", + "en": "Joints" + }, + "symptom": { + "ko": "발목 통증", + "en": "Ankle pain" + }, + "departments": [ + { + "ko": "정형외과", + "en": "Orthopedic Surgery" + } + ], + "note": { + "ko": "발목 통증 증상은 일반적으로 정형외과에서 진료받습니다.", + "en": "The symptom 'Ankle pain' is typically treated in the Orthopedic Surgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "신경계", + "en": "Neurological" + }, + "symptom": { + "ko": "손 떨림", + "en": "Hand tremor" + }, + "departments": [ + { + "ko": "신경외과", + "en": "Neurosurgery" + } + ], + "note": { + "ko": "손 떨림 증상은 일반적으로 신경외과에서 진료받습니다.", + "en": "The symptom 'Hand tremor' is typically treated in the Neurosurgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "신경계", + "en": "Neurological" + }, + "symptom": { + "ko": "입술 마비", + "en": "Lip numbness" + }, + "departments": [ + { + "ko": "신경외과", + "en": "Neurosurgery" + } + ], + "note": { + "ko": "입술 마비 증상은 일반적으로 신경외과에서 진료받습니다.", + "en": "The symptom 'Lip numbness' is typically treated in the Neurosurgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "배뇨 곤란", + "en": "Difficult urination" + }, + "departments": [ + { + "ko": "비뇨의학과", + "en": "Urology" + } + ], + "note": { + "ko": "배뇨 곤란 증상은 일반적으로 비뇨의학과에서 진료받습니다.", + "en": "The symptom 'Difficult urination' is typically treated in the Urology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "허리 통증", + "en": "Flank pain" + }, + "departments": [ + { + "ko": "비뇨의학과", + "en": "Urology" + }, + { + "ko": "신경외과", + "en": "Neurosurgery" + } + ], + "note": { + "ko": "허리 통증 증상은 일반적으로 비뇨의학과, 신경외과에서 진료받습니다.", + "en": "The symptom 'Flank pain' is typically treated in the Urology, Neurosurgery department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소아", + "en": "Pediatrics" + }, + "symptom": { + "ko": "야뇨증", + "en": "Bedwetting" + }, + "departments": [ + { + "ko": "소아청소년과", + "en": "Pediatrics" + } + ], + "note": { + "ko": "야뇨증 증상은 일반적으로 소아청소년과에서 진료받습니다.", + "en": "The symptom 'Bedwetting' is typically treated in the Pediatrics department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소아", + "en": "Pediatrics" + }, + "symptom": { + "ko": "기침 발작", + "en": "Coughing fit" + }, + "departments": [ + { + "ko": "소아청소년과", + "en": "Pediatrics" + } + ], + "note": { + "ko": "기침 발작 증상은 일반적으로 소아청소년과에서 진료받습니다.", + "en": "The symptom 'Coughing fit' is typically treated in the Pediatrics department." + } + }, + { + "type": "two-step", + "system": { + "ko": "코/목", + "en": "Nose/Throat" + }, + "symptom": { + "ko": "후각 저하", + "en": "Loss of smell" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "후각 저하 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Loss of smell' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "코/목", + "en": "Nose/Throat" + }, + "symptom": { + "ko": "인후 이물감", + "en": "Throat lump sensation" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + }, + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "인후 이물감 증상은 일반적으로 이비인후과, 내과에서 진료받습니다.", + "en": "The symptom 'Throat lump sensation' is typically treated in the Otorhinolaryngology (ENT), Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "눈", + "en": "Eye" + }, + "symptom": { + "ko": "빛 번짐", + "en": "Glare" + }, + "departments": [ + { + "ko": "안과", + "en": "Ophthalmology" + } + ], + "note": { + "ko": "빛 번짐 증상은 일반적으로 안과에서 진료받습니다.", + "en": "The symptom 'Glare' is typically treated in the Ophthalmology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "눈", + "en": "Eye" + }, + "symptom": { + "ko": "이물감", + "en": "Foreign body sensation" + }, + "departments": [ + { + "ko": "안과", + "en": "Ophthalmology" + } + ], + "note": { + "ko": "이물감 증상은 일반적으로 안과에서 진료받습니다.", + "en": "The symptom 'Foreign body sensation' is typically treated in the Ophthalmology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "귀", + "en": "Ear" + }, + "symptom": { + "ko": "이명", + "en": "Tinnitus" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "이명 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Tinnitus' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "재활", + "en": "Rehabilitation" + }, + "symptom": { + "ko": "균형 장애", + "en": "Balance disorder" + }, + "departments": [ + { + "ko": "재활의학과", + "en": "Rehabilitation Medicine" + } + ], + "note": { + "ko": "균형 장애 증상은 일반적으로 재활의학과에서 진료받습니다.", + "en": "The symptom 'Balance disorder' is typically treated in the Rehabilitation Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "치아", + "en": "Teeth" + }, + "symptom": { + "ko": "구취", + "en": "Halitosis" + }, + "departments": [ + { + "ko": "치과", + "en": "Dentistry" + } + ], + "note": { + "ko": "구취 증상은 일반적으로 치과에서 진료받습니다.", + "en": "The symptom 'Halitosis' is typically treated in the Dentistry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "메스꺼움", + "en": "Nausea" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "메스꺼움 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Nausea' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소화기", + "en": "Digestive" + }, + "symptom": { + "ko": "식욕 부진", + "en": "Loss of appetite" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "식욕 부진 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Loss of appetite' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "호흡기", + "en": "Respiratory" + }, + "symptom": { + "ko": "가래", + "en": "Phlegm" + }, + "departments": [ + { + "ko": "내과", + "en": "Internal Medicine" + } + ], + "note": { + "ko": "가래 증상은 일반적으로 내과에서 진료받습니다.", + "en": "The symptom 'Phlegm' is typically treated in the Internal Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "호흡기", + "en": "Respiratory" + }, + "symptom": { + "ko": "코피", + "en": "Nosebleed" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "코피 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Nosebleed' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "홍반", + "en": "Red patches" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "홍반 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Red patches' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "피부", + "en": "Skin" + }, + "symptom": { + "ko": "물집", + "en": "Blisters" + }, + "departments": [ + { + "ko": "피부과", + "en": "Dermatology" + } + ], + "note": { + "ko": "물집 증상은 일반적으로 피부과에서 진료받습니다.", + "en": "The symptom 'Blisters' is typically treated in the Dermatology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "정신", + "en": "Mental Health" + }, + "symptom": { + "ko": "망상", + "en": "Delusions" + }, + "departments": [ + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "망상 증상은 일반적으로 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Delusions' is typically treated in the Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "정신", + "en": "Mental Health" + }, + "symptom": { + "ko": "환청", + "en": "Auditory hallucination" + }, + "departments": [ + { + "ko": "정신건강의학과", + "en": "Psychiatry" + } + ], + "note": { + "ko": "환청 증상은 일반적으로 정신건강의학과에서 진료받습니다.", + "en": "The symptom 'Auditory hallucination' is typically treated in the Psychiatry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "혈뇨", + "en": "Hematuria" + }, + "departments": [ + { + "ko": "비뇨의학과", + "en": "Urology" + } + ], + "note": { + "ko": "혈뇨 증상은 일반적으로 비뇨의학과에서 진료받습니다.", + "en": "The symptom 'Hematuria' is typically treated in the Urology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "비뇨생식기", + "en": "Urogenital" + }, + "symptom": { + "ko": "소변 냄새 심함", + "en": "Strong urine odor" + }, + "departments": [ + { + "ko": "비뇨의학과", + "en": "Urology" + } + ], + "note": { + "ko": "소변 냄새 심함 증상은 일반적으로 비뇨의학과에서 진료받습니다.", + "en": "The symptom 'Strong urine odor' is typically treated in the Urology department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소아", + "en": "Pediatrics" + }, + "symptom": { + "ko": "발진", + "en": "Rash" + }, + "departments": [ + { + "ko": "소아청소년과", + "en": "Pediatrics" + } + ], + "note": { + "ko": "발진 증상은 일반적으로 소아청소년과에서 진료받습니다.", + "en": "The symptom 'Rash' is typically treated in the Pediatrics department." + } + }, + { + "type": "two-step", + "system": { + "ko": "소아", + "en": "Pediatrics" + }, + "symptom": { + "ko": "토함", + "en": "Vomiting" + }, + "departments": [ + { + "ko": "소아청소년과", + "en": "Pediatrics" + } + ], + "note": { + "ko": "토함 증상은 일반적으로 소아청소년과에서 진료받습니다.", + "en": "The symptom 'Vomiting' is typically treated in the Pediatrics department." + } + }, + { + "type": "two-step", + "system": { + "ko": "코/목", + "en": "Nose/Throat" + }, + "symptom": { + "ko": "목소리 변화", + "en": "Voice change" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "목소리 변화 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Voice change' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "코/목", + "en": "Nose/Throat" + }, + "symptom": { + "ko": "입냄새", + "en": "Bad breath" + }, + "departments": [ + { + "ko": "이비인후과", + "en": "Otorhinolaryngology (ENT)" + } + ], + "note": { + "ko": "입냄새 증상은 일반적으로 이비인후과에서 진료받습니다.", + "en": "The symptom 'Bad breath' is typically treated in the Otorhinolaryngology (ENT) department." + } + }, + { + "type": "two-step", + "system": { + "ko": "재활", + "en": "Rehabilitation" + }, + "symptom": { + "ko": "근력 저하", + "en": "Muscle weakness" + }, + "departments": [ + { + "ko": "재활의학과", + "en": "Rehabilitation Medicine" + } + ], + "note": { + "ko": "근력 저하 증상은 일반적으로 재활의학과에서 진료받습니다.", + "en": "The symptom 'Muscle weakness' is typically treated in the Rehabilitation Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "재활", + "en": "Rehabilitation" + }, + "symptom": { + "ko": "보행 비대칭", + "en": "Gait asymmetry" + }, + "departments": [ + { + "ko": "재활의학과", + "en": "Rehabilitation Medicine" + } + ], + "note": { + "ko": "보행 비대칭 증상은 일반적으로 재활의학과에서 진료받습니다.", + "en": "The symptom 'Gait asymmetry' is typically treated in the Rehabilitation Medicine department." + } + }, + { + "type": "two-step", + "system": { + "ko": "치아", + "en": "Teeth" + }, + "symptom": { + "ko": "잇몸 붓기", + "en": "Gum swelling" + }, + "departments": [ + { + "ko": "치과", + "en": "Dentistry" + } + ], + "note": { + "ko": "잇몸 붓기 증상은 일반적으로 치과에서 진료받습니다.", + "en": "The symptom 'Gum swelling' is typically treated in the Dentistry department." + } + }, + { + "type": "two-step", + "system": { + "ko": "치아", + "en": "Teeth" + }, + "symptom": { + "ko": "이 시림", + "en": "Tooth sensitivity" + }, + "departments": [ + { + "ko": "치과", + "en": "Dentistry" + } + ], + "note": { + "ko": "이 시림 증상은 일반적으로 치과에서 진료받습니다.", + "en": "The symptom 'Tooth sensitivity' is typically treated in the Dentistry department." + } + } +] \ No newline at end of file From 3fd1d9a08c3a39c532088317409515357f55a5d1 Mon Sep 17 00:00:00 2001 From: 99hyuk Date: Thu, 15 May 2025 15:01:52 +0900 Subject: [PATCH 2/7] =?UTF-8?q?[FEAT]=20=EC=9E=90=EA=B0=80=EC=A7=84?= =?UTF-8?q?=EB=8B=A8=20=EC=95=8C=EA=B3=A0=EB=A6=AC=EC=A6=98=20API=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DiagnosisAlgorithmController.java | 41 ++++++++++++++++ .../request/DiagnosisRequest.java | 21 +++++++++ .../response/DiagnosisAlgorithmMapping.java | 44 +++++++++++++++++ .../DiagnosisAlgorithmService.java | 47 +++++++++++++++++++ ..._mapping.json => diagnosis_algorithm.json} | 0 .../{medical_qna.json => ouch_guide.json} | 0 6 files changed, 153 insertions(+) create mode 100644 src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java create mode 100644 src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisRequest.java create mode 100644 src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/DiagnosisAlgorithmMapping.java create mode 100644 src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java rename src/main/resources/data/{symptom_department_mapping.json => diagnosis_algorithm.json} (100%) rename src/main/resources/data/{medical_qna.json => ouch_guide.json} (100%) diff --git a/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java new file mode 100644 index 0000000..6aae0ec --- /dev/null +++ b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java @@ -0,0 +1,41 @@ +package com.onebridge.ouch.controller.selfDiagnosis; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisRequest; +import com.onebridge.ouch.dto.selfDiagnosis.response.DiagnosisAlgorithmMapping; +import com.onebridge.ouch.service.selfDiagnosis.DiagnosisAlgorithmService; + +@Tag(name = "자가진단 알고리즘 API", description = "Json 형식의 자가진단 알고리즘 API 입니다. 전체 조희 기반으로 필요한 항목만 매핑해서 사용하는 식으로 사용하시면 됩니다." + + " 현재 한국어와 영어를 제공하며, 추후 다국어 지원 예정입니다.") +@RestController +@RequestMapping("/diagnosis-algorithm") +@RequiredArgsConstructor +public class DiagnosisAlgorithmController { + + private final DiagnosisAlgorithmService diagnosisService; + + @Operation(summary = "자가진단 알고리즘 전체 조회 API", description = "자가진단 알고리즘 내용 전체를 Json 형식으로 조회합니다.") + @GetMapping + public List getAllMappings() { + return diagnosisService.getAll(); + } + + @Operation(summary = "증상 기반 관련 진료과 찾기 API", description = "1차 System, 2차 Symptom, 3차 Condition(증상따라 없을 수도 있음)을 기반으로 관련 진료과를 찾습니다. ") + @PostMapping + public ResponseEntity getDiagnosis(@RequestBody DiagnosisRequest request) { + return diagnosisService.findMatch( + request.getLanguage(), + request.getSystem(), + request.getSymptom(), + request.getCondition()) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } +} diff --git a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisRequest.java b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisRequest.java new file mode 100644 index 0000000..0e42982 --- /dev/null +++ b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisRequest.java @@ -0,0 +1,21 @@ +package com.onebridge.ouch.dto.selfDiagnosis.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class DiagnosisRequest { + @Schema(description = "언어 설정", example = "en") + private String language; // "ko" or "en" + + @Schema(description = "시스템", example = "Digestive") + private String system; + + @Schema(description = "증상", example = "Diarrhea") + private String symptom; + + @Schema(example = "null", nullable = true) + private String condition; // nullable +} diff --git a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/DiagnosisAlgorithmMapping.java b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/DiagnosisAlgorithmMapping.java new file mode 100644 index 0000000..9426545 --- /dev/null +++ b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/DiagnosisAlgorithmMapping.java @@ -0,0 +1,44 @@ +package com.onebridge.ouch.dto.selfDiagnosis.response; + +import lombok.Getter; +import java.util.List; + +@Getter +public class DiagnosisAlgorithmMapping { + private String type; + private DiagnosisAlgorithmSystem system; + private DiagnosisAlgorithmSymptom symptom; + private DiagnosisAlgorithmCondition condition; // nullable + private List departments; + private DiagnosisAlgorithmNote note; + + @Getter + public static class DiagnosisAlgorithmSystem { + private String ko; + private String en; + } + + @Getter + public static class DiagnosisAlgorithmSymptom { + private String ko; + private String en; + } + + @Getter + public static class DiagnosisAlgorithmCondition { + private String ko; + private String en; + } + + @Getter + public static class DiagnosisAlgorithmDepartment { + private String ko; + private String en; + } + + @Getter + public static class DiagnosisAlgorithmNote { + private String ko; + private String en; + } +} diff --git a/src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java b/src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java new file mode 100644 index 0000000..b9d7f5f --- /dev/null +++ b/src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java @@ -0,0 +1,47 @@ +package com.onebridge.ouch.service.selfDiagnosis; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onebridge.ouch.dto.selfDiagnosis.response.DiagnosisAlgorithmMapping; + +import jakarta.annotation.PostConstruct; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import java.io.InputStream; +import java.util.List; +import java.util.Optional; + +@Service +public class DiagnosisAlgorithmService { + + private List mappings; + + @PostConstruct + public void init() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + InputStream input = new ClassPathResource("data/diagnosis_algorithm.json").getInputStream(); + mappings = mapper.readValue(input, new TypeReference<>() {}); + } + + public List getAll() { + return mappings; + } + + public Optional findMatch(String lang, String system, String symptom, String condition) { + return mappings.stream() + .filter(e -> getByLang(e.getSystem().getKo(), e.getSystem().getEn(), lang).equals(system)) + .filter(e -> getByLang(e.getSymptom().getKo(), e.getSymptom().getEn(), lang).equals(symptom)) + .filter(e -> { + if ("three-step".equals(e.getType()) && e.getCondition() != null) { + return getByLang(e.getCondition().getKo(), e.getCondition().getEn(), lang).equals(condition); + } + return true; + }) + .findFirst(); + } + + private String getByLang(String ko, String en, String lang) { + return "en".equalsIgnoreCase(lang) ? en : ko; + } +} diff --git a/src/main/resources/data/symptom_department_mapping.json b/src/main/resources/data/diagnosis_algorithm.json similarity index 100% rename from src/main/resources/data/symptom_department_mapping.json rename to src/main/resources/data/diagnosis_algorithm.json diff --git a/src/main/resources/data/medical_qna.json b/src/main/resources/data/ouch_guide.json similarity index 100% rename from src/main/resources/data/medical_qna.json rename to src/main/resources/data/ouch_guide.json From 0b7a2d22143d34f6f497a64217807b0910a93cbf Mon Sep 17 00:00:00 2001 From: 99hyuk Date: Thu, 15 May 2025 15:47:55 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[REFACT]=20=EC=9E=90=EA=B0=80=EC=A7=84?= =?UTF-8?q?=EB=8B=A8=20=EB=8F=84=EB=A9=94=EC=9D=B8=EC=9D=B4=20Symptom=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=EC=9D=84=20=EC=B0=B8=EC=A1=B0?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EA=B3=A0=20String=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9E=85=EB=A0=A5=EB=B0=9B=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EB=B0=8F=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20Symptom=EA=B3=BC=20=EA=B4=80=EB=A0=A8=EB=90=9C=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20API=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EA=B0=81=EC=A3=BC=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?,=20=EC=9E=90=EA=B0=80=EC=A7=84=EB=8B=A8=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=EC=8B=9C=20=EC=83=88=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=98=EC=97=AC=20createdAt=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=EA=B0=80=20null=EC=9D=B4=20=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EC=83=81=ED=99=A9=EC=9D=84=20=ED=95=B4=EA=B2=B0=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4=20=EC=83=88=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EB=8C=80=EC=8B=A0=20dirty=20checking?= =?UTF-8?q?=20=ED=99=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DiagnosisAlgorithmController.java | 4 +- .../SelfDiagnosisController.java | 45 +++--- .../controller/symptom/SymptomController.java | 18 +-- .../converter/SelfDiagnosisConverter.java | 55 ++++--- .../onebridge/ouch/domain/SelfDiagnosis.java | 10 +- ...st.java => DiagnosisAlgorithmRequest.java} | 2 +- .../request/DiagnosisUpdateRequest.java | 32 ---- ...Request.java => SelfDiagnosisRequest.java} | 8 +- .../GetDiagnosisByUserIdResponse.java | 2 +- .../response/GetDiagnosisResponse.java | 2 +- .../selfDiagnosis/SelfDiagnosisService.java | 148 +++++++++--------- .../ouch/service/user/UserService.java | 2 +- 12 files changed, 145 insertions(+), 183 deletions(-) rename src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/{DiagnosisRequest.java => DiagnosisAlgorithmRequest.java} (89%) delete mode 100644 src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisUpdateRequest.java rename src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/{DiagnosisCreateRequest.java => SelfDiagnosisRequest.java} (84%) diff --git a/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java index 6aae0ec..6424e2b 100644 --- a/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java +++ b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java @@ -8,7 +8,7 @@ import java.util.List; -import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisRequest; +import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisAlgorithmRequest; import com.onebridge.ouch.dto.selfDiagnosis.response.DiagnosisAlgorithmMapping; import com.onebridge.ouch.service.selfDiagnosis.DiagnosisAlgorithmService; @@ -29,7 +29,7 @@ public List getAllMappings() { @Operation(summary = "증상 기반 관련 진료과 찾기 API", description = "1차 System, 2차 Symptom, 3차 Condition(증상따라 없을 수도 있음)을 기반으로 관련 진료과를 찾습니다. ") @PostMapping - public ResponseEntity getDiagnosis(@RequestBody DiagnosisRequest request) { + public ResponseEntity getDiagnosis(@RequestBody DiagnosisAlgorithmRequest request) { return diagnosisService.findMatch( request.getLanguage(), request.getSystem(), diff --git a/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/SelfDiagnosisController.java b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/SelfDiagnosisController.java index 115f44b..69bb4ca 100644 --- a/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/SelfDiagnosisController.java +++ b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/SelfDiagnosisController.java @@ -13,12 +13,9 @@ import org.springframework.web.bind.annotation.RestController; import com.onebridge.ouch.apiPayload.ApiResponse; -import com.onebridge.ouch.dto.selfDiagnosis.request.AddSymptomsToDiagnosisRequest; -import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisCreateRequest; -import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisUpdateRequest; +import com.onebridge.ouch.dto.selfDiagnosis.request.SelfDiagnosisRequest; import com.onebridge.ouch.dto.selfDiagnosis.response.GetDiagnosisByUserIdResponse; import com.onebridge.ouch.dto.selfDiagnosis.response.GetDiagnosisResponse; -import com.onebridge.ouch.dto.selfDiagnosis.response.GetSymptomsOfDiagnosisResponse; import com.onebridge.ouch.security.authorization.UserId; import com.onebridge.ouch.service.selfDiagnosis.SelfDiagnosisService; @@ -39,7 +36,7 @@ public class SelfDiagnosisController { @Operation(summary = "자가진단표 생성 API", description = "자가진단표 생성 API 입니다.") @PostMapping public ResponseEntity> createDiagnosis( //request dto 에 userid 지우기 - @RequestBody @Valid DiagnosisCreateRequest request, + @RequestBody @Valid SelfDiagnosisRequest request, @UserId Long userId ) { selfDiagnosisService.createDiagnosis(request, userId); @@ -78,21 +75,21 @@ public ResponseEntity> deleteDiagnosis(@PathVariable Long diag } //특정 자가진단표의 증상 목록 조회 - @Operation(summary = "특정 자가진단표의 증상 목록 조회 API", description = "특정 자가진단표의 증상 목록 조회 API 입니다.") - @GetMapping("/{diagnosisId}/symptoms") - public ResponseEntity> getSymptomsOfDiagnosis( - @PathVariable Long diagnosisId, - @UserId Long userId - ) { - GetSymptomsOfDiagnosisResponse response = selfDiagnosisService.getSymptomsOfDiagnosis(diagnosisId, userId); - return ResponseEntity.ok(ApiResponse.success(response)); - } + // @Operation(summary = "특정 자가진단표의 증상 목록 조회 API", description = "특정 자가진단표의 증상 목록 조회 API 입니다.") + // @GetMapping("/{diagnosisId}/symptoms") + // public ResponseEntity> getSymptomsOfDiagnosis( + // @PathVariable Long diagnosisId, + // @UserId Long userId + // ) { + // GetSymptomsOfDiagnosisResponse response = selfDiagnosisService.getSymptomsOfDiagnosis(diagnosisId, userId); + // return ResponseEntity.ok(ApiResponse.success(response)); + // } //자가진단표 수정 @Operation(summary = "자가진단표 수정 API", description = "자가진단표 수정 API 입니다.") @PutMapping("/{diagnosisId}") public ResponseEntity> updateDiagnosis(@PathVariable Long diagnosisId, - @RequestBody @Valid DiagnosisUpdateRequest request, + @RequestBody @Valid SelfDiagnosisRequest request, @UserId Long userId ) { selfDiagnosisService.updateDiagnosis(diagnosisId, userId, request); @@ -100,13 +97,13 @@ public ResponseEntity> updateDiagnosis(@PathVariable Long diag } //자가진단표에 증상 추가 - @Operation(summary = "특정 자가진단표에 증상 추가 API", description = "특정 자가진단표에 증상 추가 API 입니다.") - @PostMapping("/{diagnosisId}/symptoms") - public ResponseEntity> addSymptomsToSelfDiagnosis(@PathVariable Long diagnosisId, - @RequestBody @Valid AddSymptomsToDiagnosisRequest request, - @UserId Long userId - ) { - selfDiagnosisService.addSymptomsToSelfDiagnosis(diagnosisId, request, userId); - return ResponseEntity.ok(ApiResponse.successWithNoData()); - } + // @Operation(summary = "특정 자가진단표에 증상 추가 API", description = "특정 자가진단표에 증상 추가 API 입니다.") + // @PostMapping("/{diagnosisId}/symptoms") + // public ResponseEntity> addSymptomsToSelfDiagnosis(@PathVariable Long diagnosisId, + // @RequestBody @Valid AddSymptomsToDiagnosisRequest request, + // @UserId Long userId + // ) { + // selfDiagnosisService.addSymptomsToSelfDiagnosis(diagnosisId, request, userId); + // return ResponseEntity.ok(ApiResponse.successWithNoData()); + // } } diff --git a/src/main/java/com/onebridge/ouch/controller/symptom/SymptomController.java b/src/main/java/com/onebridge/ouch/controller/symptom/SymptomController.java index ce40010..37b4214 100644 --- a/src/main/java/com/onebridge/ouch/controller/symptom/SymptomController.java +++ b/src/main/java/com/onebridge/ouch/controller/symptom/SymptomController.java @@ -15,19 +15,19 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -@Tag(name = "증상 API", description = "증상 API 입니다.") -@RestController -@RequestMapping("/symptoms") +// @Tag(name = "증상 API", description = "증상 API 입니다.") +// @RestController +// @RequestMapping("/symptoms") @RequiredArgsConstructor public class SymptomController { private final SymptomService symptomService; //증상 목록 조회 - @Operation(summary = "증상 목록 조회 API", description = "증상 목록 조회 API 입니다.") - @GetMapping - public ResponseEntity>> getSymptomsList() { - List list = symptomService.getSymptomsList(); - return ResponseEntity.ok(ApiResponse.success(list)); - } + // @Operation(summary = "증상 목록 조회 API", description = "증상 목록 조회 API 입니다.") + // @GetMapping + // public ResponseEntity>> getSymptomsList() { + // List list = symptomService.getSymptomsList(); + // return ResponseEntity.ok(ApiResponse.success(list)); + // } } diff --git a/src/main/java/com/onebridge/ouch/converter/SelfDiagnosisConverter.java b/src/main/java/com/onebridge/ouch/converter/SelfDiagnosisConverter.java index ec22dc0..95eca96 100644 --- a/src/main/java/com/onebridge/ouch/converter/SelfDiagnosisConverter.java +++ b/src/main/java/com/onebridge/ouch/converter/SelfDiagnosisConverter.java @@ -9,8 +9,7 @@ import com.onebridge.ouch.domain.Symptom; import com.onebridge.ouch.domain.User; import com.onebridge.ouch.domain.mapping.DiagnosisSymptom; -import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisCreateRequest; -import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisUpdateRequest; +import com.onebridge.ouch.dto.selfDiagnosis.request.SelfDiagnosisRequest; import com.onebridge.ouch.dto.selfDiagnosis.response.GetDiagnosisByUserIdResponse; import com.onebridge.ouch.dto.selfDiagnosis.response.GetDiagnosisResponse; import com.onebridge.ouch.dto.selfDiagnosis.response.GetSymptomsOfDiagnosisResponse; @@ -19,58 +18,58 @@ public class SelfDiagnosisConverter { public GetDiagnosisResponse diagnosisToGetDiagnosisResponse(SelfDiagnosis diagnosis) { - List symptoms = symptomListForResponseDto(diagnosis); - return new GetDiagnosisResponse(diagnosis.getUser().getId(), diagnosis.getVisitType(), symptoms, + //List symptoms = symptomListForResponseDto(diagnosis); + return new GetDiagnosisResponse(diagnosis.getUser().getId(), diagnosis.getVisitType(), diagnosis.getSymptom(), diagnosis.getDuration(), diagnosis.getPainSeverity(), diagnosis.getAdditionalNote(), diagnosis.getCreatedAt().toString()); } public GetDiagnosisByUserIdResponse diagnosisToGetDiagnosisByUserIdResponse(SelfDiagnosis diagnosis) { - List symptoms = symptomListForResponseDto(diagnosis); - return new GetDiagnosisByUserIdResponse(diagnosis.getId(), diagnosis.getVisitType(), symptoms, + //List symptoms = symptomListForResponseDto(diagnosis); + return new GetDiagnosisByUserIdResponse(diagnosis.getId(), diagnosis.getVisitType(), diagnosis.getSymptom(), diagnosis.getDuration(), diagnosis.getPainSeverity(), diagnosis.getAdditionalNote(), diagnosis.getCreatedAt().toString()); } - public GetSymptomsOfDiagnosisResponse diagnosisToGetSymptomsOfDiagnosisResponse(SelfDiagnosis diagnosis) { - List symptoms = symptomListForResponseDto(diagnosis); - return new GetSymptomsOfDiagnosisResponse(symptoms); - } + // public GetSymptomsOfDiagnosisResponse diagnosisToGetSymptomsOfDiagnosisResponse(SelfDiagnosis diagnosis) { + // List symptoms = symptomListForResponseDto(diagnosis); + // return new GetSymptomsOfDiagnosisResponse(symptoms); + // } - public SelfDiagnosis diagnosisCreateRequestToSelfDiagnosis(DiagnosisCreateRequest request, User user) { + public SelfDiagnosis diagnosisCreateRequestToSelfDiagnosis(SelfDiagnosisRequest request, User user) { return SelfDiagnosis.builder() .user(user) .visitType(request.getVisitType()) - .diagnosisSymptomList(new ArrayList<>()) + .symptom(request.getSymptom()) .duration(request.getDuration()) .painSeverity(request.getPainSeverity()) .additionalNote(request.getAdditionalNote()) .build(); } - public DiagnosisSymptom buildDiagnosisSymptom(SelfDiagnosis selfDiagnosis, Symptom foundSymptom) { - return DiagnosisSymptom.builder() - .selfDiagnosis(selfDiagnosis) - .symptom(foundSymptom) - .build(); - } + // public DiagnosisSymptom buildDiagnosisSymptom(SelfDiagnosis selfDiagnosis, Symptom foundSymptom) { + // return DiagnosisSymptom.builder() + // .selfDiagnosis(selfDiagnosis) + // .symptom(foundSymptom) + // .build(); + // } public SelfDiagnosis diagnosisUpdateRequestToSelfDiagnosis(SelfDiagnosis diagnosis, User user, - DiagnosisUpdateRequest request) { + SelfDiagnosisRequest request) { return diagnosis.toBuilder() .visitType(request.getVisitType()) - .diagnosisSymptomList(new ArrayList<>()) + .symptom(request.getSymptom()) .duration(request.getDuration()) .painSeverity(request.getPainSeverity()) .additionalNote(request.getAdditionalNote()) .build(); } - - public List symptomListForResponseDto(SelfDiagnosis selfDiagnosis) { - List symptoms = new ArrayList<>(); - for (DiagnosisSymptom symptom : selfDiagnosis.getDiagnosisSymptomList()) { - symptoms.add(symptom.getSymptom().getName()); - } - return symptoms; - } + // + // public List symptomListForResponseDto(SelfDiagnosis selfDiagnosis) { + // List symptoms = new ArrayList<>(); + // for (DiagnosisSymptom symptom : selfDiagnosis.getDiagnosisSymptomList()) { + // symptoms.add(symptom.getSymptom().getName()); + // } + // return symptoms; + // } } diff --git a/src/main/java/com/onebridge/ouch/domain/SelfDiagnosis.java b/src/main/java/com/onebridge/ouch/domain/SelfDiagnosis.java index 927183b..3ead815 100644 --- a/src/main/java/com/onebridge/ouch/domain/SelfDiagnosis.java +++ b/src/main/java/com/onebridge/ouch/domain/SelfDiagnosis.java @@ -27,11 +27,13 @@ public class SelfDiagnosis extends BaseEntity { @JoinColumn(name = "user_id") private User user; - @Column(columnDefinition = "TEXT") - private String contents; + // @Column(columnDefinition = "TEXT") + // private String contents; + + // @OneToMany(mappedBy = "selfDiagnosis", cascade = CascadeType.ALL, orphanRemoval = true) + // private List diagnosisSymptomList = new ArrayList<>(); - @OneToMany(mappedBy = "selfDiagnosis", cascade = CascadeType.ALL, orphanRemoval = true) - private List diagnosisSymptomList = new ArrayList<>(); + private String symptom; private VisitType visitType; diff --git a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisRequest.java b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisAlgorithmRequest.java similarity index 89% rename from src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisRequest.java rename to src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisAlgorithmRequest.java index 0e42982..b462066 100644 --- a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisRequest.java +++ b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisAlgorithmRequest.java @@ -6,7 +6,7 @@ @Getter @Setter -public class DiagnosisRequest { +public class DiagnosisAlgorithmRequest { @Schema(description = "언어 설정", example = "en") private String language; // "ko" or "en" diff --git a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisUpdateRequest.java b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisUpdateRequest.java deleted file mode 100644 index 22680b7..0000000 --- a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisUpdateRequest.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.onebridge.ouch.dto.selfDiagnosis.request; - -import java.util.List; - -import com.onebridge.ouch.domain.enums.SymptomDuration; -import com.onebridge.ouch.domain.enums.VisitType; - -import jakarta.validation.constraints.Max; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; - -@Getter -public class DiagnosisUpdateRequest { - - @NotNull(message = "Visit type is required.") - private VisitType visitType; - - @NotEmpty(message = "At least one symptom is required.") - private List symptoms; - - @NotNull(message = "Symptom duration is required.") - private SymptomDuration duration; - - @NotNull(message = "Pain severity is required.") - @Min(value = 0, message = "통증 정도는 최소 0 이상이어야 합니다.") - @Max(value = 10, message = "통증 정도는 최대 10 이하여야 합니다.") - private Integer painSeverity; - - private String additionalNote; -} diff --git a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisCreateRequest.java b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/SelfDiagnosisRequest.java similarity index 84% rename from src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisCreateRequest.java rename to src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/SelfDiagnosisRequest.java index 142964b..14028c2 100644 --- a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/DiagnosisCreateRequest.java +++ b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/request/SelfDiagnosisRequest.java @@ -1,7 +1,5 @@ package com.onebridge.ouch.dto.selfDiagnosis.request; -import java.util.List; - import com.onebridge.ouch.domain.enums.SymptomDuration; import com.onebridge.ouch.domain.enums.VisitType; @@ -12,13 +10,13 @@ import lombok.Getter; @Getter -public class DiagnosisCreateRequest { +public class SelfDiagnosisRequest { @NotNull(message = "Visit type is required.") private VisitType visitType; - @NotEmpty(message = "At least one symptom is required.") - private List symptoms; + @NotEmpty(message = "증상을 입력해주세요") + private String symptom; @NotNull(message = "Symptom duration is required.") private SymptomDuration duration; diff --git a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisByUserIdResponse.java b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisByUserIdResponse.java index 33aceeb..ec59c0a 100644 --- a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisByUserIdResponse.java +++ b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisByUserIdResponse.java @@ -14,7 +14,7 @@ public class GetDiagnosisByUserIdResponse { private Long diagnosisId; private VisitType visitType; - private List symptoms; + private String symptoms; private SymptomDuration duration; private Integer painSeverity; private String additionalNote; diff --git a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisResponse.java b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisResponse.java index 6efdeb1..5e761cf 100644 --- a/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisResponse.java +++ b/src/main/java/com/onebridge/ouch/dto/selfDiagnosis/response/GetDiagnosisResponse.java @@ -14,7 +14,7 @@ public class GetDiagnosisResponse { private Long userId; private VisitType visitType; - private List symptoms; + private String symptoms; private SymptomDuration duration; private Integer painSeverity; private String additionalNote; diff --git a/src/main/java/com/onebridge/ouch/service/selfDiagnosis/SelfDiagnosisService.java b/src/main/java/com/onebridge/ouch/service/selfDiagnosis/SelfDiagnosisService.java index 274a626..7df9d97 100644 --- a/src/main/java/com/onebridge/ouch/service/selfDiagnosis/SelfDiagnosisService.java +++ b/src/main/java/com/onebridge/ouch/service/selfDiagnosis/SelfDiagnosisService.java @@ -16,12 +16,9 @@ import com.onebridge.ouch.domain.Symptom; import com.onebridge.ouch.domain.User; import com.onebridge.ouch.domain.mapping.DiagnosisSymptom; -import com.onebridge.ouch.dto.selfDiagnosis.request.AddSymptomsToDiagnosisRequest; -import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisCreateRequest; -import com.onebridge.ouch.dto.selfDiagnosis.request.DiagnosisUpdateRequest; +import com.onebridge.ouch.dto.selfDiagnosis.request.SelfDiagnosisRequest; import com.onebridge.ouch.dto.selfDiagnosis.response.GetDiagnosisByUserIdResponse; import com.onebridge.ouch.dto.selfDiagnosis.response.GetDiagnosisResponse; -import com.onebridge.ouch.dto.selfDiagnosis.response.GetSymptomsOfDiagnosisResponse; import com.onebridge.ouch.repository.Symptom.SymptomRepository; import com.onebridge.ouch.repository.selfDiagnosis.SelfDiagnosisRepository; import com.onebridge.ouch.repository.user.UserRepository; @@ -39,30 +36,30 @@ public class SelfDiagnosisService { //자가진단표 생성 @Transactional - public void createDiagnosis(DiagnosisCreateRequest request, Long userId) { + public void createDiagnosis(SelfDiagnosisRequest request, Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new OuchException(CommonErrorCode.MEMBER_NOT_FOUND)); //일단 증상 리스트는 비워둔 채로 SelfDiagnosis 객체 생성 SelfDiagnosis selfDiagnosis = selfDiagnosisConverter.diagnosisCreateRequestToSelfDiagnosis(request, user); - List symptomNames = request.getSymptoms(); - List foundSymptoms = symptomRepository.findByNameIn(symptomNames); + // List symptomNames = request.getSymptoms(); + // List foundSymptoms = symptomRepository.findByNameIn(symptomNames); // 이름으로 빠르게 찾기 위해 Map 으로 변환 - Map symptomMap = foundSymptoms.stream() - .collect(Collectors.toMap(Symptom::getName, s -> s)); - - for (String symptomName : symptomNames) { - Symptom foundSymptom = symptomMap.get(symptomName); - if (foundSymptom == null) { - throw new OuchException(DiagnosisErrorCode.SYMPTOM_NOT_FOUND); - } - - DiagnosisSymptom diagnosisSymptom = selfDiagnosisConverter.buildDiagnosisSymptom(selfDiagnosis, - foundSymptom); - selfDiagnosis.getDiagnosisSymptomList().add(diagnosisSymptom); - } + // Map symptomMap = foundSymptoms.stream() + // .collect(Collectors.toMap(Symptom::getName, s -> s)); + + // for (String symptomName : symptomNames) { + // Symptom foundSymptom = symptomMap.get(symptomName); + // if (foundSymptom == null) { + // throw new OuchException(DiagnosisErrorCode.SYMPTOM_NOT_FOUND); + // } + // + // DiagnosisSymptom diagnosisSymptom = selfDiagnosisConverter.buildDiagnosisSymptom(selfDiagnosis, + // foundSymptom); + // selfDiagnosis.getDiagnosisSymptomList().add(diagnosisSymptom); + // } selfDiagnosisRepository.save(selfDiagnosis); } @@ -98,72 +95,73 @@ public void deleteDiagnosis(Long diagnosisId, Long userId) { selfDiagnosisRepository.delete(diagnosis); } - //특정 자가진단표의 증상 목록 조회 - @Transactional(readOnly = true) - public GetSymptomsOfDiagnosisResponse getSymptomsOfDiagnosis(Long diagnosisId, Long userId) { - SelfDiagnosis diagnosis = selfDiagnosisRepository.findByIdAndUserId(diagnosisId, userId) - .orElseThrow(() -> new OuchException(DiagnosisErrorCode.DIAGNOSIS_NOT_FOUND)); - - return selfDiagnosisConverter.diagnosisToGetSymptomsOfDiagnosisResponse(diagnosis); - } - //자가진단표 수정 @Transactional - public void updateDiagnosis(Long diagnosisId, Long userId, DiagnosisUpdateRequest request) { + public void updateDiagnosis(Long diagnosisId, Long userId, SelfDiagnosisRequest request) { SelfDiagnosis diagnosis = selfDiagnosisRepository.findByIdAndUserId(diagnosisId, userId) .orElseThrow(() -> new OuchException(DiagnosisErrorCode.DIAGNOSIS_NOT_FOUND)); User user = userRepository.findById(userId) .orElseThrow(() -> new OuchException(CommonErrorCode.MEMBER_NOT_FOUND)); - SelfDiagnosis updatedDiagnosis = selfDiagnosisConverter.diagnosisUpdateRequestToSelfDiagnosis(diagnosis, user, - request); - - List symptomNames = request.getSymptoms(); - List foundSymptoms = symptomRepository.findByNameIn(symptomNames); - - // 이름으로 빠르게 찾기 위해 Map 으로 변환 - Map symptomMap = foundSymptoms.stream() - .collect(Collectors.toMap(Symptom::getName, s -> s)); - - for (String symptomName : symptomNames) { - Symptom foundSymptom = symptomMap.get(symptomName); - if (foundSymptom == null) { - throw new OuchException(DiagnosisErrorCode.SYMPTOM_NOT_FOUND); - } - - DiagnosisSymptom diagnosisSymptom = selfDiagnosisConverter.buildDiagnosisSymptom(updatedDiagnosis, - foundSymptom); - updatedDiagnosis.getDiagnosisSymptomList().add(diagnosisSymptom); - } - - selfDiagnosisRepository.save(updatedDiagnosis); + selfDiagnosisConverter.diagnosisUpdateRequestToSelfDiagnosis(diagnosis, user, request); + // SelfDiagnosis updatedDiagnosis = selfDiagnosisConverter.diagnosisUpdateRequestToSelfDiagnosis(diagnosis, user, + // request); + + // List symptomNames = request.getSymptoms(); + // List foundSymptoms = symptomRepository.findByNameIn(symptomNames); + // + // // 이름으로 빠르게 찾기 위해 Map 으로 변환 + // Map symptomMap = foundSymptoms.stream() + // .collect(Collectors.toMap(Symptom::getName, s -> s)); + // + // for (String symptomName : symptomNames) { + // Symptom foundSymptom = symptomMap.get(symptomName); + // if (foundSymptom == null) { + // throw new OuchException(DiagnosisErrorCode.SYMPTOM_NOT_FOUND); + // } + // + // DiagnosisSymptom diagnosisSymptom = selfDiagnosisConverter.buildDiagnosisSymptom(updatedDiagnosis, + // foundSymptom); + // updatedDiagnosis.getDiagnosisSymptomList().add(diagnosisSymptom); + // } + + // selfDiagnosisRepository.save(updatedDiagnosis); } - //특정 자가진단표에 증상 추가 - @Transactional - public void addSymptomsToSelfDiagnosis(Long diagnosisId, AddSymptomsToDiagnosisRequest request, Long userId) { - - SelfDiagnosis diagnosis = selfDiagnosisRepository.findByIdAndUserId(diagnosisId, userId) - .orElseThrow(() -> new OuchException(DiagnosisErrorCode.DIAGNOSIS_NOT_FOUND)); - - for (String symptom : request.getSymptoms()) { - - if (diagnosis.getDiagnosisSymptomList() - .stream() - .anyMatch(diagnosisSymptom -> diagnosisSymptom.getSymptom().getName().equals(symptom))) { - throw new OuchException(DiagnosisErrorCode.SYMPTOM_ALREADY_ADDED); - } + // //특정 자가진단표의 증상 목록 조회 + // @Transactional(readOnly = true) + // public GetSymptomsOfDiagnosisResponse getSymptomsOfDiagnosis(Long diagnosisId, Long userId) { + // SelfDiagnosis diagnosis = selfDiagnosisRepository.findByIdAndUserId(diagnosisId, userId) + // .orElseThrow(() -> new OuchException(DiagnosisErrorCode.DIAGNOSIS_NOT_FOUND)); + // + // return selfDiagnosisConverter.diagnosisToGetSymptomsOfDiagnosisResponse(diagnosis); + // } - Symptom foundSymptom = symptomRepository.findByName(symptom) - .orElseThrow(() -> new OuchException(DiagnosisErrorCode.SYMPTOM_NOT_FOUND)); - - DiagnosisSymptom diagnosisSymptom = selfDiagnosisConverter.buildDiagnosisSymptom(diagnosis, foundSymptom); - - diagnosis.getDiagnosisSymptomList().add(diagnosisSymptom); - - } - } + //특정 자가진단표에 증상 추가 + // @Transactional + // public void addSymptomsToSelfDiagnosis(Long diagnosisId, AddSymptomsToDiagnosisRequest request, Long userId) { + // + // SelfDiagnosis diagnosis = selfDiagnosisRepository.findByIdAndUserId(diagnosisId, userId) + // .orElseThrow(() -> new OuchException(DiagnosisErrorCode.DIAGNOSIS_NOT_FOUND)); + // + // for (String symptom : request.getSymptoms()) { + // + // if (diagnosis.getDiagnosisSymptomList() + // .stream() + // .anyMatch(diagnosisSymptom -> diagnosisSymptom.getSymptom().getName().equals(symptom))) { + // throw new OuchException(DiagnosisErrorCode.SYMPTOM_ALREADY_ADDED); + // } + // + // Symptom foundSymptom = symptomRepository.findByName(symptom) + // .orElseThrow(() -> new OuchException(DiagnosisErrorCode.SYMPTOM_NOT_FOUND)); + // + // DiagnosisSymptom diagnosisSymptom = selfDiagnosisConverter.buildDiagnosisSymptom(diagnosis, foundSymptom); + // + // diagnosis.getDiagnosisSymptomList().add(diagnosisSymptom); + // + // } + // } } diff --git a/src/main/java/com/onebridge/ouch/service/user/UserService.java b/src/main/java/com/onebridge/ouch/service/user/UserService.java index a2de4f5..d90f75b 100644 --- a/src/main/java/com/onebridge/ouch/service/user/UserService.java +++ b/src/main/java/com/onebridge/ouch/service/user/UserService.java @@ -77,7 +77,7 @@ public void updateUserNation(Long userId, String nationCode) { .orElseThrow(() -> new OuchException(CommonErrorCode.MEMBER_NOT_FOUND)); Nation nation = nationRepository.findByCode(nationCode) - .orElseThrow(() -> new OuchException(CommonErrorCode.LANGUAGE_NOT_FOUND)); + .orElseThrow(() -> new OuchException(CommonErrorCode.NATION_NOT_FOUND)); user.updateNation(nation); } From 88fecfb9168f31a3fe56628bec581248347d646c Mon Sep 17 00:00:00 2001 From: 99hyuk Date: Thu, 15 May 2025 16:17:56 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[FIX]=20User,=20HealthStatus,=20MedicalReco?= =?UTF-8?q?rd=20Service=20=EB=A1=9C=EC=A7=81=20=EC=A4=91=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=B6=80=EB=B6=84=EC=9D=B4=20?= =?UTF-8?q?=EC=83=88=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1=EC=9D=B4=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20dirty=20checking=EC=9D=84=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/onebridge/ouch/domain/User.java | 4 ++++ .../ouch/service/healthStatus/HealthStatusService.java | 5 +---- .../ouch/service/medicalRecord/MedicalRecordService.java | 8 +------- .../java/com/onebridge/ouch/service/user/UserService.java | 6 +----- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/onebridge/ouch/domain/User.java b/src/main/java/com/onebridge/ouch/domain/User.java index ba7cfa7..b5e9e6b 100644 --- a/src/main/java/com/onebridge/ouch/domain/User.java +++ b/src/main/java/com/onebridge/ouch/domain/User.java @@ -111,4 +111,8 @@ public void updateLanguage(Language language) { public void updateNation(Nation nation) { this.nation = nation; } + + public void deactivate() { + this.status = UserStatus.INACTIVE; + } } diff --git a/src/main/java/com/onebridge/ouch/service/healthStatus/HealthStatusService.java b/src/main/java/com/onebridge/ouch/service/healthStatus/HealthStatusService.java index badab7f..f00272a 100644 --- a/src/main/java/com/onebridge/ouch/service/healthStatus/HealthStatusService.java +++ b/src/main/java/com/onebridge/ouch/service/healthStatus/HealthStatusService.java @@ -57,10 +57,7 @@ public void updateHealthStatus(HealthStatusUpdateRequest request, Long userId) { HealthStatus healthStatus = healthStatusRepository.findByUserId(userId) .orElseThrow(() -> new OuchException(HealthStatusErrorCode.HEALTH_STATUS_NOT_FOUND)); - HealthStatus updatedHealthStatus = healthStatusConverter - .healthStatusUpdateRequestToHealthStatus(healthStatus, request); - - healthStatusRepository.save(updatedHealthStatus); + healthStatusConverter.healthStatusUpdateRequestToHealthStatus(healthStatus, request); } // //특정 건강상태 삭제 diff --git a/src/main/java/com/onebridge/ouch/service/medicalRecord/MedicalRecordService.java b/src/main/java/com/onebridge/ouch/service/medicalRecord/MedicalRecordService.java index 56bac37..f5b8974 100644 --- a/src/main/java/com/onebridge/ouch/service/medicalRecord/MedicalRecordService.java +++ b/src/main/java/com/onebridge/ouch/service/medicalRecord/MedicalRecordService.java @@ -86,12 +86,6 @@ public void updateMedicalRecord(@Valid MedicalRecordUpdateRequest request, .contents_summary(request.getTreatmentSummary()) .build(); - MedicalRecord updatedMedicalRecord = medicalRecordConverter.medicalRecordUpdateRequestToMedicalRecord( - medicalRecord, - request, - summary); - - medicalRecordRepository.save(updatedMedicalRecord); + medicalRecordConverter.medicalRecordUpdateRequestToMedicalRecord(medicalRecord, request, summary); } - } diff --git a/src/main/java/com/onebridge/ouch/service/user/UserService.java b/src/main/java/com/onebridge/ouch/service/user/UserService.java index d90f75b..0202938 100644 --- a/src/main/java/com/onebridge/ouch/service/user/UserService.java +++ b/src/main/java/com/onebridge/ouch/service/user/UserService.java @@ -43,11 +43,7 @@ public void deactivateUser(Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new OuchException(CommonErrorCode.MEMBER_NOT_FOUND)); - User deactivatedUser = user.toBuilder() - .status(UserStatus.INACTIVE) - .build(); - - userRepository.save(deactivatedUser); + user.deactivate(); } @Transactional From 680d85f0471000da3871b8105fb6105e6896c311 Mon Sep 17 00:00:00 2001 From: 99hyuk Date: Thu, 15 May 2025 16:28:53 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[FEAT]=20=ED=86=B5=EC=97=AD=20=EC=8B=9C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8A=94=20=EC=A7=84=EB=A3=8C=20?= =?UTF-8?q?=EA=B0=80=EC=9D=B4=EB=93=9C=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../guide/MedicalVisitGuideController.java | 35 ++++++++++++++++++ .../ouch/dto/guide/MedicalVisitGuideStep.java | 23 ++++++++++++ .../guide/MedicalVisitGuideService.java | 36 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java create mode 100644 src/main/java/com/onebridge/ouch/dto/guide/MedicalVisitGuideStep.java create mode 100644 src/main/java/com/onebridge/ouch/service/guide/MedicalVisitGuideService.java diff --git a/src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java b/src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java new file mode 100644 index 0000000..ceff22a --- /dev/null +++ b/src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java @@ -0,0 +1,35 @@ +package com.onebridge.ouch.controller.guide; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import com.onebridge.ouch.dto.guide.MedicalVisitGuideStep; +import com.onebridge.ouch.service.guide.MedicalVisitGuideService; + +@Tag(name = "통역 상황 속 진료 가이드 API", description = "통역 도중 사용하는 Json 형식의 진료 가이드 API 입니다. 전체 조희 기반으로 필요한 항목만 매핑해서 사용하는 식으로 사용하시면 됩니다." + + " 현재 한국어와 영어를 제공하며, 추후 다국어 지원 예정입니다.") +@RestController +@RequestMapping("/guide") +@RequiredArgsConstructor +public class MedicalVisitGuideController { + + private final MedicalVisitGuideService guideService; + + @Operation(summary = "통역 상황 속 진료 가이드 전체 조회 API", description = "진료 가이드 내용 전체를 Json 형식으로 조회합니다.") + @GetMapping + public List getAllSteps() { + return guideService.getAllSteps(); + } + + @Operation(summary = "통역 상황 속 진료 가이드 스탭 별(step=1~5) 제공 API", description = "진료 가이드를 스탭(1~5) 별로 조회합니다.") + @GetMapping("/{step}") + public ResponseEntity getStep(@PathVariable int step) { + MedicalVisitGuideStep result = guideService.getStepByNumber(step); + return result != null ? ResponseEntity.ok(result) : ResponseEntity.notFound().build(); + } +} diff --git a/src/main/java/com/onebridge/ouch/dto/guide/MedicalVisitGuideStep.java b/src/main/java/com/onebridge/ouch/dto/guide/MedicalVisitGuideStep.java new file mode 100644 index 0000000..4ff48e2 --- /dev/null +++ b/src/main/java/com/onebridge/ouch/dto/guide/MedicalVisitGuideStep.java @@ -0,0 +1,23 @@ +package com.onebridge.ouch.dto.guide; + +import lombok.Getter; +import java.util.List; + +@Getter +public class MedicalVisitGuideStep { + private int step; + private LocalizedText title; + private String icon; + private LocalizedText purpose; + private List whatToExpect; + private List keyPhrases; + private List actionGuide; + private List possibleQuestions; // nullable + private List tips; + + @Getter + public static class LocalizedText { + private String ko; + private String en; + } +} diff --git a/src/main/java/com/onebridge/ouch/service/guide/MedicalVisitGuideService.java b/src/main/java/com/onebridge/ouch/service/guide/MedicalVisitGuideService.java new file mode 100644 index 0000000..72ee8bd --- /dev/null +++ b/src/main/java/com/onebridge/ouch/service/guide/MedicalVisitGuideService.java @@ -0,0 +1,36 @@ +package com.onebridge.ouch.service.guide; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onebridge.ouch.dto.guide.MedicalVisitGuideStep; + +import jakarta.annotation.PostConstruct; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import java.io.InputStream; +import java.util.List; + +@Service +public class MedicalVisitGuideService { + + private List steps; + + @PostConstruct + public void loadGuideSteps() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + InputStream input = new ClassPathResource("data/medical_visit_guide.json").getInputStream(); + steps = mapper.readValue(input, new TypeReference<>() {}); + } + + public List getAllSteps() { + return steps; + } + + public MedicalVisitGuideStep getStepByNumber(int stepNumber) { + return steps.stream() + .filter(step -> step.getStep() == stepNumber) + .findFirst() + .orElse(null); + } +} From 6792b5b379b8860b09fd791ab497c23c2ebbf382 Mon Sep 17 00:00:00 2001 From: 99hyuk Date: Thu, 15 May 2025 17:11:35 +0900 Subject: [PATCH 6/7] =?UTF-8?q?[FEAT]=20Ouch=20Guide=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(=EC=A0=84=EC=B2=B4=20=EC=A1=B0=ED=9A=8C,=20?= =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=EB=B3=84=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C,=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../guide/MedicalVisitGuideController.java | 2 +- .../controller/guide/OuchGuideController.java | 49 ++++++++++++++++ .../ouch/dto/guide/OuchGuideEntry.java | 16 +++++ .../ouch/service/guide/OuchGuideService.java | 58 +++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/onebridge/ouch/controller/guide/OuchGuideController.java create mode 100644 src/main/java/com/onebridge/ouch/dto/guide/OuchGuideEntry.java create mode 100644 src/main/java/com/onebridge/ouch/service/guide/OuchGuideService.java diff --git a/src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java b/src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java index ceff22a..30d3f32 100644 --- a/src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java +++ b/src/main/java/com/onebridge/ouch/controller/guide/MedicalVisitGuideController.java @@ -14,7 +14,7 @@ @Tag(name = "통역 상황 속 진료 가이드 API", description = "통역 도중 사용하는 Json 형식의 진료 가이드 API 입니다. 전체 조희 기반으로 필요한 항목만 매핑해서 사용하는 식으로 사용하시면 됩니다." + " 현재 한국어와 영어를 제공하며, 추후 다국어 지원 예정입니다.") @RestController -@RequestMapping("/guide") +@RequestMapping("/guide/visit") @RequiredArgsConstructor public class MedicalVisitGuideController { diff --git a/src/main/java/com/onebridge/ouch/controller/guide/OuchGuideController.java b/src/main/java/com/onebridge/ouch/controller/guide/OuchGuideController.java new file mode 100644 index 0000000..42c7ad6 --- /dev/null +++ b/src/main/java/com/onebridge/ouch/controller/guide/OuchGuideController.java @@ -0,0 +1,49 @@ +package com.onebridge.ouch.controller.guide; + +import com.onebridge.ouch.dto.guide.OuchGuideEntry; +import com.onebridge.ouch.service.guide.OuchGuideService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name = "Ouch Guide API", description = "홈 화면에서 접근하는 Ouch Guide API입니다. 한국 의료 시스템이나 Ouch 서비스에 대해 자주 묻는 질문과 답변을 제공합니다. 카테고리별 필터링도 가능하며, 현재 한국어와 영어를 지원합니다.") +@RestController +@RequestMapping("/guide/ouch") +@RequiredArgsConstructor +public class OuchGuideController { + + private final OuchGuideService guideService; + + @Operation(summary = "전체 참고 질문/답변 조회", description = "진료 중 자주 묻는 질문 및 답변 전체를 JSON 형태로 조회합니다.") + @GetMapping + public List getAll() { + return guideService.getAll(); + } + + @Operation(summary = "카테고리별 참고 질문/답변 조회", description = "카테고리명(한글 또는 영어)과 언어 코드(ko/en)를 기반으로 해당 항목을 필터링하여 조회합니다.") + @GetMapping("/filter") + public ResponseEntity> getByCategory( + @Parameter(description = "카테고리 이름 (예: 보험 및 비용 / Insurance & Costs", example = "Insurance & Costs") + @RequestParam String category, + + @Parameter(description = "언어 코드 (ko 또는 en)", example = "en") + @RequestParam String languageCode + ) { + List result = guideService.getByCategory(category, languageCode); + return result.isEmpty() ? ResponseEntity.notFound().build() : ResponseEntity.ok(result); + } + + @Operation(summary = "카테고리 목록 조회", description = "언어(ko/en) 기준으로 카테고리 이름 목록을 조회합니다.") + @GetMapping("/categories") + public ResponseEntity> getCategories( + @RequestParam(name = "languageCode", defaultValue = "en") String languageCode + ) { + return ResponseEntity.ok(guideService.getAllCategories(languageCode)); + } +} diff --git a/src/main/java/com/onebridge/ouch/dto/guide/OuchGuideEntry.java b/src/main/java/com/onebridge/ouch/dto/guide/OuchGuideEntry.java new file mode 100644 index 0000000..62ad8fc --- /dev/null +++ b/src/main/java/com/onebridge/ouch/dto/guide/OuchGuideEntry.java @@ -0,0 +1,16 @@ +package com.onebridge.ouch.dto.guide; + +import lombok.Getter; + +@Getter +public class OuchGuideEntry { + private LocalizedText category; + private LocalizedText question; + private LocalizedText answer; + + @Getter + public static class LocalizedText { + private String ko; + private String en; + } +} diff --git a/src/main/java/com/onebridge/ouch/service/guide/OuchGuideService.java b/src/main/java/com/onebridge/ouch/service/guide/OuchGuideService.java new file mode 100644 index 0000000..cdf6b06 --- /dev/null +++ b/src/main/java/com/onebridge/ouch/service/guide/OuchGuideService.java @@ -0,0 +1,58 @@ +package com.onebridge.ouch.service.guide; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onebridge.ouch.apiPayload.code.error.CommonErrorCode; +import com.onebridge.ouch.apiPayload.code.error.ErrorCode; +import com.onebridge.ouch.apiPayload.exception.OuchException; +import com.onebridge.ouch.dto.guide.OuchGuideEntry; +import jakarta.annotation.PostConstruct; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import java.io.InputStream; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class OuchGuideService { + + private List allGuides; + + @PostConstruct + public void init() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + InputStream input = new ClassPathResource("data/ouch_guide.json").getInputStream(); + allGuides = mapper.readValue(input, new TypeReference<>() {}); + } + + public List getAll() { + return allGuides; + } + + public List getByCategory(String category, String languageCode) { + return allGuides.stream() + .filter(e -> { + String localizedCategory = "en".equalsIgnoreCase(languageCode) + ? e.getCategory().getEn() + : e.getCategory().getKo(); + return localizedCategory.equalsIgnoreCase(category); + }) + .collect(Collectors.toList()); + } + + public List getAllCategories(String languageCode) { + if (!"ko".equalsIgnoreCase(languageCode) && !"en".equalsIgnoreCase(languageCode)) { + throw new OuchException(CommonErrorCode.LANGUAGE_NOT_FOUND); + } + + return allGuides.stream() + .map(e -> "en".equalsIgnoreCase(languageCode) + ? e.getCategory().getEn() + : e.getCategory().getKo()) + .distinct() + .sorted() + .collect(Collectors.toList()); + } +} From 068e9648a2e4ff9dbbca6a473aae1f2a62718ab8 Mon Sep 17 00:00:00 2001 From: 99hyuk Date: Thu, 15 May 2025 17:58:59 +0900 Subject: [PATCH 7/7] =?UTF-8?q?[FEAT]=20=EC=9E=90=EA=B0=80=EC=A7=84?= =?UTF-8?q?=EB=8B=A8=20=EC=95=8C=EA=B3=A0=EB=A6=AC=EC=A6=98=EC=97=90?= =?UTF-8?q?=EC=84=9C=201=EC=B0=A8,=202=EC=B0=A8,=203=EC=B0=A8=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=8B=A4=EC=9D=8C=20?= =?UTF-8?q?=EC=A6=9D=EC=83=81=20=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=ED=95=98=EB=8A=94=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../code/error/CommonErrorCode.java | 4 ++ .../DiagnosisAlgorithmController.java | 44 ++++++++++++++-- .../DiagnosisAlgorithmService.java | 51 ++++++++++++++++++- 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/onebridge/ouch/apiPayload/code/error/CommonErrorCode.java b/src/main/java/com/onebridge/ouch/apiPayload/code/error/CommonErrorCode.java index 70bfe8e..dd4beb9 100644 --- a/src/main/java/com/onebridge/ouch/apiPayload/code/error/CommonErrorCode.java +++ b/src/main/java/com/onebridge/ouch/apiPayload/code/error/CommonErrorCode.java @@ -29,6 +29,10 @@ public enum CommonErrorCode implements ErrorCode { // For test TEMP_EXCEPTION(HttpStatus.BAD_REQUEST, "TEMP4001", "이거는 테스트"), + //자가진단 알고리즘 + SYSTEM_SYMPTOM_NOT_FOUND(HttpStatus.NOT_FOUND, "DIAG404", "해당 system/symptom 조합이 존재하지 않습니다."), + CONDITION_NOT_AVAILABLE(HttpStatus.NOT_FOUND, "DIAG404", "해당 조합은 condition 단계가 없는 two-step 항목입니다."), + //회원가입 LANGUAGE_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON404", "관련된 언어 데이터가 없습니다."), NATION_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON404", "관련된 국가 데이터가 없습니다."); diff --git a/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java index 6424e2b..8582acd 100644 --- a/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java +++ b/src/main/java/com/onebridge/ouch/controller/selfDiagnosis/DiagnosisAlgorithmController.java @@ -1,6 +1,7 @@ package com.onebridge.ouch.controller.selfDiagnosis; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -12,8 +13,8 @@ import com.onebridge.ouch.dto.selfDiagnosis.response.DiagnosisAlgorithmMapping; import com.onebridge.ouch.service.selfDiagnosis.DiagnosisAlgorithmService; -@Tag(name = "자가진단 알고리즘 API", description = "Json 형식의 자가진단 알고리즘 API 입니다. 전체 조희 기반으로 필요한 항목만 매핑해서 사용하는 식으로 사용하시면 됩니다." - + " 현재 한국어와 영어를 제공하며, 추후 다국어 지원 예정입니다.") +@Tag(name = "자가진단 알고리즘 API", description = "JSON 기반의 자가진단 알고리즘 API입니다. 단계별 선택지(1차 system, 2차 symptom, 3차 condition)를 활용하여 진료과를 추천받을 수 있습니다. " + + "현재 한국어(ko)와 영어(en)를 지원합니다.") @RestController @RequestMapping("/diagnosis-algorithm") @RequiredArgsConstructor @@ -21,13 +22,13 @@ public class DiagnosisAlgorithmController { private final DiagnosisAlgorithmService diagnosisService; - @Operation(summary = "자가진단 알고리즘 전체 조회 API", description = "자가진단 알고리즘 내용 전체를 Json 형식으로 조회합니다.") + @Operation(summary = "전체 알고리즘 데이터 조회", description = "모든 자가진단 알고리즘 항목을 JSON 배열로 조회합니다.") @GetMapping public List getAllMappings() { return diagnosisService.getAll(); } - @Operation(summary = "증상 기반 관련 진료과 찾기 API", description = "1차 System, 2차 Symptom, 3차 Condition(증상따라 없을 수도 있음)을 기반으로 관련 진료과를 찾습니다. ") + @Operation(summary = "증상 기반 진료과 추천", description = "1차 System, 2차 Symptom, 3차 Condition을 기반으로 관련 진료과를 추천합니다. Condition은 'type = three-step'일 경우에만 입력합니다.") @PostMapping public ResponseEntity getDiagnosis(@RequestBody DiagnosisAlgorithmRequest request) { return diagnosisService.findMatch( @@ -38,4 +39,39 @@ public ResponseEntity getDiagnosis(@RequestBody Diagn .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } + + @Operation(summary = "1차 시스템 목록 조회", description = "자가진단 알고리즘에서 사용 가능한 'system' 리스트를 언어 코드 기준으로 조회합니다.") + @GetMapping("/systems") + public ResponseEntity> getSystems( + @Parameter(description = "언어 코드 (ko 또는 en)", example = "en") + @RequestParam(defaultValue = "en") String languageCode) { + return ResponseEntity.ok(diagnosisService.getUniqueSystems(languageCode)); + } + + @Operation(summary = "2차 증상 목록 조회", description = "선택한 'system'에 해당하는 'symptom' 리스트를 조회합니다.") + @GetMapping("/symptoms") + public ResponseEntity> getSymptoms( + @Parameter(description = "언어 코드 (ko 또는 en)", example = "en") + @RequestParam(defaultValue = "en") String languageCode, + + @Parameter(description = "1차 시스템 이름", example = "Digestive") + @RequestParam String system + ) { + return ResponseEntity.ok(diagnosisService.getSymptomsBySystem(system, languageCode)); + } + + @Operation(summary = "3차 조건 목록 조회", description = "'system'과 'symptom' 조합에 해당하는 'condition' 리스트를 조회합니다. 'three-step' 항목일 경우에만 존재합니다.") + @GetMapping("/conditions") + public ResponseEntity> getConditions( + @Parameter(description = "언어 코드 (ko 또는 en)", example = "en") + @RequestParam(defaultValue = "en") String languageCode, + + @Parameter(description = "1차 시스템 이름", example = "Digestive") + @RequestParam String system, + + @Parameter(description = "2차 증상 이름", example = "Heartburn") + @RequestParam String symptom + ) { + return ResponseEntity.ok(diagnosisService.getConditionsBySystemAndSymptom(system, symptom, languageCode)); + } } diff --git a/src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java b/src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java index b9d7f5f..c29782e 100644 --- a/src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java +++ b/src/main/java/com/onebridge/ouch/service/selfDiagnosis/DiagnosisAlgorithmService.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.onebridge.ouch.apiPayload.code.error.CommonErrorCode; +import com.onebridge.ouch.apiPayload.exception.OuchException; import com.onebridge.ouch.dto.selfDiagnosis.response.DiagnosisAlgorithmMapping; import jakarta.annotation.PostConstruct; @@ -41,7 +43,52 @@ public Optional findMatch(String lang, String system, .findFirst(); } - private String getByLang(String ko, String en, String lang) { - return "en".equalsIgnoreCase(lang) ? en : ko; + public List getUniqueSystems(String lang) { + return mappings.stream() + .map(e -> getByLang(e.getSystem().getKo(), e.getSystem().getEn(), lang)) + .distinct() + .sorted() + .toList(); + } + + public List getSymptomsBySystem(String system, String lang) { + return mappings.stream() + .filter(e -> getByLang(e.getSystem().getKo(), e.getSystem().getEn(), lang).equals(system)) + .map(e -> getByLang(e.getSymptom().getKo(), e.getSymptom().getEn(), lang)) + .distinct() + .sorted() + .toList(); + } + + public List getConditionsBySystemAndSymptom(String system, String symptom, String lang) { + List matched = mappings.stream() + .filter(e -> getByLang(e.getSystem().getKo(), e.getSystem().getEn(), lang).equals(system)) + .filter(e -> getByLang(e.getSymptom().getKo(), e.getSymptom().getEn(), lang).equals(symptom)) + .toList(); + + if (matched.isEmpty()) { + throw new OuchException(CommonErrorCode.SYSTEM_SYMPTOM_NOT_FOUND); + } + + List conditions = matched.stream() + .filter(e -> "three-step".equals(e.getType())) + .map(e -> getByLang(e.getCondition().getKo(), e.getCondition().getEn(), lang)) + .distinct() + .sorted() + .toList(); + + if (conditions.isEmpty()) { + throw new OuchException(CommonErrorCode.CONDITION_NOT_AVAILABLE); + } + + return conditions; + } + + private String getByLang(String ko, String en, String languageCode) { + return switch (languageCode.toLowerCase()) { + case "ko" -> ko; + case "en" -> en; + default -> throw new OuchException(CommonErrorCode.LANGUAGE_NOT_FOUND); + }; } }