update search
This commit is contained in:
+488
-231
@@ -1,94 +1,139 @@
|
||||
[
|
||||
{
|
||||
"path": "docs_md/articles/facial-nerve-in-temporal-bone_21dccac8-d73d-4ef3-859b-73e013ec15cc.md",
|
||||
"title": "Facial Nerve in Temporal Bone",
|
||||
"docid": "21dccac8-d73d-4ef3-859b-73e013ec15cc",
|
||||
"path": "docs_md/articles/adrenal_082ca43c-db5c-4770-aeed-0c6ea317e8fc.md",
|
||||
"title": "Adrenal",
|
||||
"docid": "082ca43c-db5c-4770-aeed-0c6ea317e8fc",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Genitourinary",
|
||||
"Anatomy",
|
||||
"Temporal Bone",
|
||||
"Facial Nerve in Temporal Bone"
|
||||
"Adrenal"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "b2e6dabb-ee1c-42a4-a332-9f0814c1c607",
|
||||
"value": "Surjith Vattoth, MD, FRCR"
|
||||
"key": "c1df94ab-4a9f-44c4-add7-1f174fb9ac45",
|
||||
"value": "Siva P. Raman, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Anatomy, Temporal Bone, Facial Nerve in Temporal Bone",
|
||||
"pageKeywords": "Genitourinary, Anatomy, Adrenal",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
"Content"
|
||||
],
|
||||
"snippet": ""
|
||||
"snippet": "...hrine) into bloodstream - **Vessels**,**nerves**, and **lymphatics** - Arteries - **Superior adrenal arteries**: Typic..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/cnvii-facial-nerve_98cb2d45-e64c-4295-9662-3470cd46513a.md",
|
||||
"title": "CNVII (Facial Nerve)",
|
||||
"docid": "98cb2d45-e64c-4295-9662-3470cd46513a",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Anatomy",
|
||||
"Cranial Nerves",
|
||||
"CNVII (Facial Nerve)"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "1fa14dfd-71ea-4960-908e-e720313bc63a",
|
||||
"value": "Santhosh Gaddikeri, MD"
|
||||
},
|
||||
{
|
||||
"key": "94f835c8-fa13-4e8a-995b-53048e6b0605",
|
||||
"value": "Philip R. Chapman, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Anatomy, Cranial Nerves, CNVII (Facial Nerve)",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
],
|
||||
"snippet": ""
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/facial-nerve-cnvii_2f4818dd-6438-405b-8561-5cbbb9c91562.md",
|
||||
"title": "Facial Nerve (CNVII)",
|
||||
"docid": "2f4818dd-6438-405b-8561-5cbbb9c91562",
|
||||
"breadcrumbs": [
|
||||
"Brain",
|
||||
"Anatomy",
|
||||
"Skull Base and Cranial Nerves",
|
||||
"Facial Nerve (CNVII)"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "94f835c8-fa13-4e8a-995b-53048e6b0605",
|
||||
"value": "Philip R. Chapman, MD"
|
||||
},
|
||||
{
|
||||
"key": "b0a6efa4-ad68-430c-b5da-f5c904adf809",
|
||||
"value": "Ryan P. Cabeen, PhD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Brain, Anatomy, Skull Base and Cranial Nerves, Facial Nerve (CNVII)",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
],
|
||||
"snippet": ""
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/peripheral-facial-nerve-paralysis_4da52ac4-c03c-4711-ae7e-bb4f2f7c5ab8.md",
|
||||
"title": "Peripheral Facial Nerve Paralysis",
|
||||
"docid": "4da52ac4-c03c-4711-ae7e-bb4f2f7c5ab8",
|
||||
"path": "docs_md/articles/sensorineural-hearing-loss-in-child_08c895da-f2aa-4076-abf0-af9aca1677cd.md",
|
||||
"title": "Sensorineural Hearing Loss in Child",
|
||||
"docid": "08c895da-f2aa-4076-abf0-af9aca1677cd",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Differential Diagnosis",
|
||||
"Temporal Bone",
|
||||
"CPA-IAC and Posterior Fossa",
|
||||
"Clinically Based Differentials",
|
||||
"Peripheral Facial Nerve Paralysis"
|
||||
"Sensorineural Hearing Loss in Child"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "d19354f3-7ff2-495a-ad3f-064122e45602",
|
||||
"value": "Bernadette L. Koch, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Differential Diagnosis, CPA-IAC and Posterior Fossa, Clinically Based Differentials, Sensorineural Hearing Loss in Child",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...lar deficiency on CT - Look for large endolymphatic sac/duct ± cochlear malformation & modiolar deficiency on MR - **Conge..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/segmental-colonic-narrowing_c193bc86-43d2-4932-8378-5db8001d755e.md",
|
||||
"title": "Segmental Colonic Narrowing",
|
||||
"docid": "c193bc86-43d2-4932-8378-5db8001d755e",
|
||||
"breadcrumbs": [
|
||||
"Gastrointestinal",
|
||||
"Differential Diagnosis",
|
||||
"Colon",
|
||||
"Generic Imaging Patterns",
|
||||
"Segmental Colonic Narrowing"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "6c5a9e0e-9dea-461b-9ad4-c00f5c4c2bbf",
|
||||
"value": "Atif Zaheer, MD, FSAR"
|
||||
},
|
||||
{
|
||||
"key": "e987d3d3-1206-48d6-824b-3347c2968855",
|
||||
"value": "Michael P. Federle, MD, FACR"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Gastrointestinal, Differential Diagnosis, Colon, Generic Imaging Patterns, Segmental Colonic Narrowing",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...etastases and Lymphoma** - Can be hematogenous or lymphatic spread or direct invasion - e.g., from duodenum, stomach, kidn..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/normal-pressure-hydrocephalus_ba3f857d-58de-4f21-8463-1631b4cb9972.md",
|
||||
"title": "Normal-Pressure Hydrocephalus",
|
||||
"docid": "ba3f857d-58de-4f21-8463-1631b4cb9972",
|
||||
"breadcrumbs": [
|
||||
"Brain",
|
||||
"Diagnosis",
|
||||
"Anatomy-Based Diagnoses",
|
||||
"Ventricles and Cisterns",
|
||||
"Hydrocephalus",
|
||||
"Normal-Pressure Hydrocephalus"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "a25c450b-3d34-4f64-bba3-cc0834813df6",
|
||||
"value": "Miral D. Jhaveri, MD, MBA"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Brain, Diagnosis, Anatomy-Based Diagnoses, Ventricles and Cisterns, Hydrocephalus, Normal-Pressure Hydrocephalus",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...oval of neurotoxic compounds (β-amyloid & tau) - Glymphatic system - Facilitates brain fluid clearance & waste removal du..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/peritoneal-cavity_6691f48d-ac34-477b-8ec1-b9dd731a14a8.md",
|
||||
"title": "Peritoneal Cavity",
|
||||
"docid": "6691f48d-ac34-477b-8ec1-b9dd731a14a8",
|
||||
"breadcrumbs": [
|
||||
"Gastrointestinal",
|
||||
"Anatomy",
|
||||
"Gastrointestinal Tract and Abdominal Cavity",
|
||||
"Peritoneal Cavity"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "6c5a9e0e-9dea-461b-9ad4-c00f5c4c2bbf",
|
||||
"value": "Atif Zaheer, MD, FSAR"
|
||||
},
|
||||
{
|
||||
"key": "c1df94ab-4a9f-44c4-add7-1f174fb9ac45",
|
||||
"value": "Siva P. Raman, MD"
|
||||
},
|
||||
{
|
||||
"key": "e987d3d3-1206-48d6-824b-3347c2968855",
|
||||
"value": "Michael P. Federle, MD, FACR"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Gastrointestinal, Anatomy, Gastrointestinal Tract and Abdominal Cavity, Peritoneal Cavity",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...ntains **superior mesenteric artery and vein**, nerves, and lymphatics - **Transverse mesocolon**crosses almost horizontally in front of pancreas,..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/sensorineural-hearing-loss-in-adult_08d468da-fbc3-44f8-8212-6480e0a152c4.md",
|
||||
"title": "Sensorineural Hearing Loss in Adult",
|
||||
"docid": "08d468da-fbc3-44f8-8212-6480e0a152c4",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Differential Diagnosis",
|
||||
"CPA-IAC and Posterior Fossa",
|
||||
"Clinically Based Differentials",
|
||||
"Sensorineural Hearing Loss in Adult"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
@@ -96,13 +141,33 @@
|
||||
"value": "Nicholas A. Koontz, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Differential Diagnosis, Temporal Bone, Clinically Based Differentials, Peripheral Facial Nerve Paralysis",
|
||||
"pageKeywords": "Head and Neck, Differential Diagnosis, CPA-IAC and Posterior Fossa, Clinically Based Differentials, Sensorineural Hearing Loss in Adult",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
"Content"
|
||||
],
|
||||
"snippet": ""
|
||||
"snippet": "...ove; fat saturation suppresses fat signal - **Large Endolymphatic Sac Anomaly (IP-2)** - Most common lesion found in children with bilat..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/abdominal-lymph-nodes_3ca98d42-20ef-48fe-9265-ebfe570ba54b.md",
|
||||
"title": "Abdominal Lymph Nodes",
|
||||
"docid": "3ca98d42-20ef-48fe-9265-ebfe570ba54b",
|
||||
"breadcrumbs": [
|
||||
"Ultrasound",
|
||||
"Anatomy",
|
||||
"Abdomen",
|
||||
"Abdominal Lymph Nodes"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "07469ec4-05aa-4d65-a788-08b4d64048af",
|
||||
"value": "Jade Wong-You-Cheong, MBChB, MRCP, FRCR, FSRU, FSAR"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Ultrasound, Anatomy, Abdomen, Abdominal Lymph Nodes",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "# GROSS ANATOMY - ## Overview - Major lymphatic vessels and nodal chains lie along major blood vessels [aorta, inferior vena cav..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/temporal-bone-facial-nerve-venous-malformation-hemangioma_dcd6a44e-cbe6-457c-9b03-598a2b874ece.md",
|
||||
@@ -128,157 +193,158 @@
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Diagnosis, Temporal Bone, Intratemporal Facial Nerve, Benign and Malignant Tumors, Temporal Bone Facial Nerve Venous Malformation (Hemangioma)",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
"Content"
|
||||
],
|
||||
"snippet": ""
|
||||
"snippet": "...* staining utilizing D2-40 antibody **negativity** excludes lymphatic malformation - ## Clinical Issues - Intratemporal FNVM produces **peri..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/middle-ear-prolapsing-facial-nerve_61f6bcaa-f073-4385-b895-dc420ddc8a1e.md",
|
||||
"title": "Middle Ear Prolapsing Facial Nerve",
|
||||
"docid": "61f6bcaa-f073-4385-b895-dc420ddc8a1e",
|
||||
"path": "docs_md/articles/colonic-wall-thickening_71ca9b30-6186-4129-957b-3b686b91b327.md",
|
||||
"title": "Colonic Wall Thickening",
|
||||
"docid": "71ca9b30-6186-4129-957b-3b686b91b327",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Diagnosis",
|
||||
"Temporal Bone",
|
||||
"Intratemporal Facial Nerve",
|
||||
"Pseudolesions",
|
||||
"Middle Ear Prolapsing Facial Nerve"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "94f835c8-fa13-4e8a-995b-53048e6b0605",
|
||||
"value": "Philip R. Chapman, MD"
|
||||
},
|
||||
{
|
||||
"key": "33151213-01b2-4542-9105-342e006b3915",
|
||||
"value": "H. Ric Harnsberger, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Diagnosis, Temporal Bone, Intratemporal Facial Nerve, Pseudolesions, Middle Ear Prolapsing Facial Nerve",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
],
|
||||
"snippet": ""
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/facial-muscles-and-superficial-musculoaponeurotic-system_80a3629d-d41e-4efd-9dac-4f19bbdea9db.md",
|
||||
"title": "Facial Muscles and Superficial Musculoaponeurotic System",
|
||||
"docid": "80a3629d-d41e-4efd-9dac-4f19bbdea9db",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Anatomy",
|
||||
"Face",
|
||||
"Facial Muscles and Superficial Musculoaponeurotic System"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "b2e6dabb-ee1c-42a4-a332-9f0814c1c607",
|
||||
"value": "Surjith Vattoth, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Anatomy, Face, Facial Muscles and Superficial Musculoaponeurotic System",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
],
|
||||
"snippet": ""
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/temporal-bone-facial-nerve-schwannoma_cf2bcc82-4a1b-4989-adeb-f4e82116111b.md",
|
||||
"title": "Temporal Bone Facial Nerve Schwannoma",
|
||||
"docid": "cf2bcc82-4a1b-4989-adeb-f4e82116111b",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Diagnosis",
|
||||
"Temporal Bone",
|
||||
"Intratemporal Facial Nerve",
|
||||
"Benign and Malignant Tumors",
|
||||
"Temporal Bone Facial Nerve Schwannoma"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "07a2c087-6202-49e7-870b-7aa162d18f06",
|
||||
"value": "Bronwyn E. Hamilton, MD"
|
||||
},
|
||||
{
|
||||
"key": "33151213-01b2-4542-9105-342e006b3915",
|
||||
"value": "H. Ric Harnsberger, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Diagnosis, Temporal Bone, Intratemporal Facial Nerve, Benign and Malignant Tumors, Temporal Bone Facial Nerve Schwannoma",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
],
|
||||
"snippet": ""
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/intratemporal-facial-nerve-enhancement_a3569ec5-a566-411d-877f-41ad832e3fd2.md",
|
||||
"title": "Intratemporal Facial Nerve Enhancement",
|
||||
"docid": "a3569ec5-a566-411d-877f-41ad832e3fd2",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Diagnosis",
|
||||
"Temporal Bone",
|
||||
"Intratemporal Facial Nerve",
|
||||
"Pseudolesions",
|
||||
"Intratemporal Facial Nerve Enhancement"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "94f835c8-fa13-4e8a-995b-53048e6b0605",
|
||||
"value": "Philip R. Chapman, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Diagnosis, Temporal Bone, Intratemporal Facial Nerve, Pseudolesions, Intratemporal Facial Nerve Enhancement",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
],
|
||||
"snippet": ""
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/hemifacial-spasm_1b390143-1212-4447-beb3-ed9e85ef34e4.md",
|
||||
"title": "Hemifacial Spasm",
|
||||
"docid": "1b390143-1212-4447-beb3-ed9e85ef34e4",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Gastrointestinal",
|
||||
"Differential Diagnosis",
|
||||
"CPA-IAC and Posterior Fossa",
|
||||
"Clinically Based Differentials",
|
||||
"Hemifacial Spasm"
|
||||
"Colon",
|
||||
"Generic Imaging Patterns",
|
||||
"Colonic Wall Thickening"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "eef2f839-5706-47b9-89c3-60d8315b2b3a",
|
||||
"value": "Nicholas A. Koontz, MD"
|
||||
"key": "6c5a9e0e-9dea-461b-9ad4-c00f5c4c2bbf",
|
||||
"value": "Atif Zaheer, MD, FSAR"
|
||||
},
|
||||
{
|
||||
"key": "e987d3d3-1206-48d6-824b-3347c2968855",
|
||||
"value": "Michael P. Federle, MD, FACR"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Differential Diagnosis, CPA-IAC and Posterior Fossa, Clinically Based Differentials, Hemifacial Spasm",
|
||||
"pageKeywords": "Gastrointestinal, Differential Diagnosis, Colon, Generic Imaging Patterns, Colonic Wall Thickening",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
"Content"
|
||||
],
|
||||
"snippet": ""
|
||||
"snippet": "...n with regional adenopathy (strong predictor of cancer with lymphatic spread) - Look for hepatic and peritoneal metastases - **Portal Hy..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/cpa-iac-facial-nerve-schwannoma_9db01630-23a4-4f42-ad83-0ec399503495.md",
|
||||
"title": "CPA-IAC Facial Nerve Schwannoma",
|
||||
"docid": "9db01630-23a4-4f42-ad83-0ec399503495",
|
||||
"path": "docs_md/articles/lymphangioma-mesenteric-cyst_bb42a128-c819-4368-a085-232b6db3434c.md",
|
||||
"title": "Lymphangioma (Mesenteric Cyst)",
|
||||
"docid": "bb42a128-c819-4368-a085-232b6db3434c",
|
||||
"breadcrumbs": [
|
||||
"Gastrointestinal",
|
||||
"Diagnosis",
|
||||
"Peritoneum, Mesentery, and Abdominal Wall",
|
||||
"Benign Neoplasms",
|
||||
"Lymphangioma (Mesenteric Cyst)"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "c1df94ab-4a9f-44c4-add7-1f174fb9ac45",
|
||||
"value": "Siva P. Raman, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Gastrointestinal, Diagnosis, Peritoneum, Mesentery, and Abdominal Wall, Benign Neoplasms, Lymphangioma (Mesenteric Cyst)",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...ymphoepithelial cyst, cystic lymphangioma, mesenteric cyst, lymphatic malformation - ## Definitions - Generic descriptive term used for beni..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/vertebral-body-t1-hypointense-signal-diffuse_5f4ceb8f-867f-4b4d-8149-57a906489453.md",
|
||||
"title": "Vertebral Body, T1-Hypointense Signal, Diffuse",
|
||||
"docid": "5f4ceb8f-867f-4b4d-8149-57a906489453",
|
||||
"breadcrumbs": [
|
||||
"Spine",
|
||||
"Differential Diagnosis",
|
||||
"Vertebral Body, Posterior Elements",
|
||||
"Modality-Specific Imaging Findings",
|
||||
"Vertebral Body, T1-Hypointense Signal, Diffuse"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "bee1f359-33fb-4cba-9e6b-ed1ca1842439",
|
||||
"value": "Jeffrey S. Ross, MD"
|
||||
},
|
||||
{
|
||||
"key": "99e1aff7-f42c-43a0-95ae-d89c8551aa01",
|
||||
"value": "Kevin R. Moore, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Spine, Differential Diagnosis, Vertebral Body, Posterior Elements, Modality-Specific Imaging Findings, Vertebral Body, T1-Hypointense Signal, Diffuse",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...nation (arterial or venous via Batson plexus) > perineural, lymphatic, CSF spread - Marrow initially infiltrated, trabeculae destroy..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/penetrating-atherosclerotic-ulcer_63f6cba2-2200-456a-8d03-ac3111e420c8.md",
|
||||
"title": "Penetrating Atherosclerotic Ulcer",
|
||||
"docid": "63f6cba2-2200-456a-8d03-ac3111e420c8",
|
||||
"breadcrumbs": [
|
||||
"Cardiac",
|
||||
"Diagnosis",
|
||||
"Aorta",
|
||||
"Penetrating Atherosclerotic Ulcer"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "9ad9af12-61a1-44d6-af52-0ee1f38eb298",
|
||||
"value": "Davis Vigneault, MD, DPhil"
|
||||
},
|
||||
{
|
||||
"key": "5de0df07-7b3e-4678-8767-1519e1153f29",
|
||||
"value": "Dominik Fleischmann, MD"
|
||||
},
|
||||
{
|
||||
"key": "10bb95ac-a27a-4ebe-833b-e59fea07734b",
|
||||
"value": "Santiago Martínez-Jiménez, MD, FACR"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Cardiac, Diagnosis, Aorta, Penetrating Atherosclerotic Ulcer",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": ".../ANATOMY:a7a252f0-2ac6-402a-8c87-cfce8adc799b ### Vessels, Lymphatic System, and Nerves, Abdominal Gastrointestinal/ANATOMY:0c38fd49-88e7-4272-960f-b..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/mycotic-aneurysm_20616d0a-7e0b-48d9-9be9-1af29e3dd6da.md",
|
||||
"title": "Mycotic Aneurysm",
|
||||
"docid": "20616d0a-7e0b-48d9-9be9-1af29e3dd6da",
|
||||
"breadcrumbs": [
|
||||
"Cardiac",
|
||||
"Diagnosis",
|
||||
"Aorta",
|
||||
"Mycotic Aneurysm"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "ee6ece9d-ad74-458c-a8df-11628ae7f879",
|
||||
"value": "Arzu Canan, MD"
|
||||
},
|
||||
{
|
||||
"key": "3d1e4c57-c1cf-4c89-b0f0-5d82b29a31e1",
|
||||
"value": "Suhny Abbara, MD, FACR, MSCCT, FNASCI"
|
||||
},
|
||||
{
|
||||
"key": "501b57b9-1723-4b1e-b21e-d4516655fac8",
|
||||
"value": "Sanjeeva P. Kalva, MD, FSIR, FCIRSE"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Cardiac, Diagnosis, Aorta, Mycotic Aneurysm",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...nal infection or intraabdominal abscess - Lymphatic spread - *Burkholderia pseudomallei* (causing melioidosis), endemic in..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/otosclerosis_ddc7b884-3c17-4834-9e96-d985c6b618a9.md",
|
||||
"title": "Otosclerosis",
|
||||
"docid": "ddc7b884-3c17-4834-9e96-d985c6b618a9",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Diagnosis",
|
||||
"CPA-IAC",
|
||||
"Benign and Malignant Tumors",
|
||||
"CPA-IAC Facial Nerve Schwannoma"
|
||||
"Temporal Bone",
|
||||
"Inner Ear",
|
||||
"Infectious and Inflammatory Lesions",
|
||||
"Otosclerosis"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
@@ -286,41 +352,232 @@
|
||||
"value": "Bronwyn E. Hamilton, MD"
|
||||
},
|
||||
{
|
||||
"key": "33151213-01b2-4542-9105-342e006b3915",
|
||||
"value": "H. Ric Harnsberger, MD"
|
||||
"key": "4b6589b0-9b8d-4467-8a90-01a0a59742fc",
|
||||
"value": "Troy A. Hutchins, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Diagnosis, CPA-IAC, Benign and Malignant Tumors, CPA-IAC Facial Nerve Schwannoma",
|
||||
"pageKeywords": "Head and Neck, Diagnosis, Temporal Bone, Inner Ear, Infectious and Inflammatory Lesions, Otosclerosis",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
"Content"
|
||||
],
|
||||
"snippet": ""
|
||||
"snippet": "...kaida T et al: Magnetic resonance imaging evaluation of endolymphatic hydrops in cases with otosclerosis. Otol Neurotol. 36(7):1146-50, 2015](http://w..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/facial-nerve-lesion-temporal-bone_1428754b-a8ee-48a0-98f8-4faeebf8dbab.md",
|
||||
"title": "Facial Nerve Lesion, Temporal Bone",
|
||||
"docid": "1428754b-a8ee-48a0-98f8-4faeebf8dbab",
|
||||
"path": "docs_md/articles/adrenal-cyst_c5d717a3-3d6e-4e86-9efe-1ad0ec14740f.md",
|
||||
"title": "Adrenal Cyst",
|
||||
"docid": "c5d717a3-3d6e-4e86-9efe-1ad0ec14740f",
|
||||
"breadcrumbs": [
|
||||
"Genitourinary",
|
||||
"Diagnosis",
|
||||
"Adrenal",
|
||||
"Benign Neoplasms",
|
||||
"Adrenal Cyst"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "c3463c5c-31d3-4489-bbfe-6b895abdb86d",
|
||||
"value": "Mitchell Tublin, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Genitourinary, Diagnosis, Adrenal, Benign Neoplasms, Adrenal Cyst",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...om preexisting vascular malformation or obstructed, ectatic lymphatic channels - Thin rim calcification typical - Epitheli..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/hydrocephalus_e9481739-278e-4682-ab1e-4326a77c3d0c.md",
|
||||
"title": "Hydrocephalus",
|
||||
"docid": "e9481739-278e-4682-ab1e-4326a77c3d0c",
|
||||
"breadcrumbs": [
|
||||
"Pediatrics",
|
||||
"Diagnosis",
|
||||
"Pediatric Neuroradiology",
|
||||
"Brain",
|
||||
"Anatomy-Based Diagnoses",
|
||||
"Ventricles and Cisterns",
|
||||
"Hydrocephalus"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "838e1722-2479-4fbd-a5fe-d965980a1a2c",
|
||||
"value": "Blaise V. Jones, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Pediatrics, Diagnosis, Pediatric Neuroradiology, Brain, Anatomy-Based Diagnoses, Ventricles and Cisterns, Hydrocephalus",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...Extracellular, extravascular fluid in brain is managed by glymphatic system - CSF circulates from within ventricles → subarachnoid space →..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/inner-ear-lesion-adult_e5bbf757-d77a-4546-a848-d1a1a64cb230.md",
|
||||
"title": "Inner Ear Lesion, Adult",
|
||||
"docid": "e5bbf757-d77a-4546-a848-d1a1a64cb230",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Differential Diagnosis",
|
||||
"Temporal Bone",
|
||||
"Anatomically Based Differentials",
|
||||
"Facial Nerve Lesion, Temporal Bone"
|
||||
"Inner Ear Lesion, Adult"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "eef2f839-5706-47b9-89c3-60d8315b2b3a",
|
||||
"value": "Nicholas A. Koontz, MD"
|
||||
"key": "d19354f3-7ff2-495a-ad3f-064122e45602",
|
||||
"value": "Bernadette L. Koch, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Differential Diagnosis, Temporal Bone, Anatomically Based Differentials, Facial Nerve Lesion, Temporal Bone",
|
||||
"pageKeywords": "Head and Neck, Differential Diagnosis, Temporal Bone, Anatomically Based Differentials, Inner Ear Lesion, Adult",
|
||||
"reasons": [
|
||||
"Breadcrumbs",
|
||||
"Keywords",
|
||||
"Title"
|
||||
"Content"
|
||||
],
|
||||
"snippet": ""
|
||||
"snippet": "...ochlear turns - Usually with enlarged endolymphatic sac/duct - Literature suggests dysplastic osseous spiral lamin..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/ventricles-and-cisterns-overview_ad860c4f-fe9a-4469-8eca-a7ccd5cff70f.md",
|
||||
"title": "Ventricles and Cisterns Overview",
|
||||
"docid": "ad860c4f-fe9a-4469-8eca-a7ccd5cff70f",
|
||||
"breadcrumbs": [
|
||||
"Brain",
|
||||
"Diagnosis",
|
||||
"Anatomy-Based Diagnoses",
|
||||
"Ventricles and Cisterns",
|
||||
"Ventricles and Cisterns Overview"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "a25c450b-3d34-4f64-bba3-cc0834813df6",
|
||||
"value": "Miral D. Jhaveri, MD, MBA"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Brain, Diagnosis, Anatomy-Based Diagnoses, Ventricles and Cisterns, Ventricles and Cisterns Overview",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...lli along the superior sagittal sinus. CSF also drains into lymphatic vessels around the cranial cavity and spinal canal. - **Updated model of CSF and..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/takayasu-arteritis_d35eb6f3-bfd3-4121-8781-325a93ccc197.md",
|
||||
"title": "Takayasu Arteritis",
|
||||
"docid": "d35eb6f3-bfd3-4121-8781-325a93ccc197",
|
||||
"breadcrumbs": [
|
||||
"Cardiac",
|
||||
"Diagnosis",
|
||||
"Aorta",
|
||||
"Takayasu Arteritis"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "ee6ece9d-ad74-458c-a8df-11628ae7f879",
|
||||
"value": "Arzu Canan, MD"
|
||||
},
|
||||
{
|
||||
"key": "3d1e4c57-c1cf-4c89-b0f0-5d82b29a31e1",
|
||||
"value": "Suhny Abbara, MD, FACR, MSCCT, FNASCI"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Cardiac, Diagnosis, Aorta, Takayasu Arteritis",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": ".../ANATOMY:551f4b47-fac1-44f9-b800-09ce766fedd9 ### Vessels, Lymphatic System, and Nerves, Abdominal Gastrointestinal/ANATOMY:0c38fd49-88e7-4272-960f-b..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/peritoneal-spaces-and-structures_9c50ad6a-e96b-44a1-93d1-a4e7de5212c2.md",
|
||||
"title": "Peritoneal Spaces and Structures",
|
||||
"docid": "9c50ad6a-e96b-44a1-93d1-a4e7de5212c2",
|
||||
"breadcrumbs": [
|
||||
"Ultrasound",
|
||||
"Anatomy",
|
||||
"Abdomen",
|
||||
"Peritoneal Spaces and Structures"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "07469ec4-05aa-4d65-a788-08b4d64048af",
|
||||
"value": "Jade Wong-You-Cheong, MBChB, MRCP, FRCR, FSRU, FSAR"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Ultrasound, Anatomy, Abdomen, Peritoneal Spaces and Structures",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...to right; contains superior mesenteric vessels, nerves, and lymphatics - Transverse mesocolon crosses almost horizontally in front of pancreas, du..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/cpa-iac-lipoma_37ef2fb6-7d7e-48dc-b786-16ed4475b26e.md",
|
||||
"title": "CPA-IAC Lipoma",
|
||||
"docid": "37ef2fb6-7d7e-48dc-b786-16ed4475b26e",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Diagnosis",
|
||||
"CPA-IAC",
|
||||
"Congenital Lesions",
|
||||
"CPA-IAC Lipoma"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "318f80ab-6abb-4067-a809-2ebdaa5a30c9",
|
||||
"value": "Kalen Riley, MD, MBA"
|
||||
},
|
||||
{
|
||||
"key": "e0282a62-994d-4550-a127-1eb773b1e920",
|
||||
"value": "Blair A. Winegar, MD"
|
||||
},
|
||||
{
|
||||
"key": "94f835c8-fa13-4e8a-995b-53048e6b0605",
|
||||
"value": "Philip R. Chapman, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Diagnosis, CPA-IAC, Congenital Lesions, CPA-IAC Lipoma",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...ant CPA-IAC lipoma with inner ear second fatty focus in endolymphatic duct-sac.\\n\\nThree axial CT (#1-3) and 3 axial MR (#4-6) images reveal an obviou..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/cystic-cpa-mass_6c60db6d-8093-4df5-8cbb-c6f6570ae167.md",
|
||||
"title": "Cystic CPA Mass",
|
||||
"docid": "6c60db6d-8093-4df5-8cbb-c6f6570ae167",
|
||||
"breadcrumbs": [
|
||||
"Head and Neck",
|
||||
"Differential Diagnosis",
|
||||
"CPA-IAC and Posterior Fossa",
|
||||
"Generic Imaging Patterns",
|
||||
"Cystic CPA Mass"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "07a2c087-6202-49e7-870b-7aa162d18f06",
|
||||
"value": "Bronwyn E. Hamilton, MD"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Head and Neck, Differential Diagnosis, CPA-IAC and Posterior Fossa, Generic Imaging Patterns, Cystic CPA Mass",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...chnoid, & neurenteric cysts; neurocysticercosis & large endolymphatic sac anomaly - Many solid CPA tumors may have either intramural cysts,..."
|
||||
},
|
||||
{
|
||||
"path": "docs_md/articles/cranial-meninges_3210cf7d-5be6-4741-a11d-dd7f8c1bc286.md",
|
||||
"title": "Cranial Meninges",
|
||||
"docid": "3210cf7d-5be6-4741-a11d-dd7f8c1bc286",
|
||||
"breadcrumbs": [
|
||||
"Brain",
|
||||
"Anatomy",
|
||||
"Scalp, Skull, and Meninges",
|
||||
"Cranial Meninges"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"key": "5cff4116-3654-4b3a-bb75-5ebe0b8c9850",
|
||||
"value": "Anne G. Osborn, MD, FACR"
|
||||
}
|
||||
],
|
||||
"pageKeywords": "Brain, Anatomy, Scalp, Skull, and Meninges, Cranial Meninges",
|
||||
"reasons": [
|
||||
"Content"
|
||||
],
|
||||
"snippet": "...along penetrating arteries - Key part of brain \"glymphatic\" system ## GROSS ANATOMY - ### Overview - Brain encased by 3 meninge..."
|
||||
}
|
||||
]
|
||||
+147
-107
@@ -249,11 +249,33 @@ def match_author(authors: List[Dict[str, Any]], q: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: List[str] = None) -> List[Dict[str, Any]]:
|
||||
def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: List[str] = None, or_queries: List[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
|
||||
out = []
|
||||
|
||||
# Helper to test if a string/list/dict matches under the chosen mode
|
||||
def value_matches(query: str, target_val: Any) -> bool:
|
||||
# Normalize queries list
|
||||
if not or_queries:
|
||||
or_queries = [{
|
||||
'qkey': qkey,
|
||||
'qval': qval,
|
||||
'mode': mode,
|
||||
'targets': targets
|
||||
}]
|
||||
|
||||
normalized_specs = []
|
||||
for spec in or_queries:
|
||||
qk = spec.get('qkey') or 'global'
|
||||
qv = spec.get('qval') or ''
|
||||
m = spec.get('mode') or 'exact'
|
||||
t = spec.get('targets')
|
||||
normalized_specs.append({
|
||||
'qkey': qk,
|
||||
'qval': qv,
|
||||
'mode': m,
|
||||
'targets': t
|
||||
})
|
||||
|
||||
# Helper to test if a string/list/dict matches under a specific mode
|
||||
def value_matches(query: str, target_val: Any, mode_val: str) -> bool:
|
||||
if target_val is None:
|
||||
return False
|
||||
|
||||
@@ -261,15 +283,15 @@ def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: Li
|
||||
for item in target_val:
|
||||
if isinstance(item, dict):
|
||||
for k, v in item.items():
|
||||
if value_matches(query, v):
|
||||
if value_matches(query, v, mode_val):
|
||||
return True
|
||||
else:
|
||||
if value_matches(query, item):
|
||||
if value_matches(query, item, mode_val):
|
||||
return True
|
||||
return False
|
||||
elif isinstance(target_val, dict):
|
||||
for k, v in target_val.items():
|
||||
if value_matches(query, v):
|
||||
if value_matches(query, v, mode_val):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -277,9 +299,9 @@ def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: Li
|
||||
if not s_val:
|
||||
return False
|
||||
|
||||
if mode == 'stemming':
|
||||
if mode_val == 'stemming':
|
||||
return match_stemming(query, s_val)
|
||||
elif mode == 'fuzzy':
|
||||
elif mode_val == 'fuzzy':
|
||||
return match_fuzzy(query, s_val)
|
||||
else:
|
||||
# Exact substring or wildcard match
|
||||
@@ -303,108 +325,126 @@ def run_search(root: str, qkey: str, qval: str, mode: str = 'exact', targets: Li
|
||||
reasons = []
|
||||
snippet = ""
|
||||
|
||||
# Normalise query key. If none or global/all/empty, search all
|
||||
k_lower = (qkey or '').strip().lower()
|
||||
if not k_lower or k_lower in ('global', 'all', 'any'):
|
||||
# Determine which targets to test
|
||||
if targets:
|
||||
target_set = {t.lower() for t in targets}
|
||||
else:
|
||||
target_set = {'title', 'docid', 'breadcrumbs', 'authors', 'keywords', 'category', 'type', 'content'}
|
||||
for spec in normalized_specs:
|
||||
qk = spec['qkey']
|
||||
qv = spec['qval']
|
||||
m = spec['mode']
|
||||
t = spec['targets']
|
||||
|
||||
# Single search box mode / global search:
|
||||
# 1. Title
|
||||
if 'title' in target_set:
|
||||
for f in ['title', 'enhancedTitle', 'pageTitle']:
|
||||
if value_matches(qval, fm.get(f)):
|
||||
matched = True
|
||||
reasons.append('Title')
|
||||
break
|
||||
# 2. DocID
|
||||
if 'docid' in target_set:
|
||||
if value_matches(qval, fm.get('docid')):
|
||||
matched = True
|
||||
reasons.append('DocID')
|
||||
# 3. Breadcrumbs
|
||||
if 'breadcrumbs' in target_set:
|
||||
bcs = fm.get('breadcrumbs') or []
|
||||
if isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
|
||||
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
|
||||
if not qv:
|
||||
continue # skip empty queries
|
||||
|
||||
spec_matched = False
|
||||
spec_reasons = []
|
||||
spec_snippet = ""
|
||||
|
||||
k_lower = (qk or '').strip().lower()
|
||||
if not k_lower or k_lower in ('global', 'all', 'any'):
|
||||
# Determine which targets to test
|
||||
if t:
|
||||
target_set = {x.lower() for x in t}
|
||||
else:
|
||||
bcs_list = bcs
|
||||
if '>' in qval:
|
||||
query_parts = [p.strip() for p in qval.split('>') if p.strip()]
|
||||
if match_breadcrumbs(bcs_list, query_parts):
|
||||
matched = True
|
||||
reasons.append('Breadcrumbs')
|
||||
else:
|
||||
if value_matches(qval, bcs_list):
|
||||
matched = True
|
||||
reasons.append('Breadcrumbs')
|
||||
# 4. Authors
|
||||
if 'authors' in target_set:
|
||||
if value_matches(qval, fm.get('authors')):
|
||||
matched = True
|
||||
reasons.append('Authors')
|
||||
# 5. PageKeywords
|
||||
if 'keywords' in target_set or 'pagekeywords' in target_set:
|
||||
if value_matches(qval, fm.get('pageKeywords')):
|
||||
matched = True
|
||||
reasons.append('Keywords')
|
||||
# 6. Category
|
||||
if 'category' in target_set:
|
||||
if value_matches(qval, fm.get('category')):
|
||||
matched = True
|
||||
reasons.append('Category')
|
||||
# 7. Type
|
||||
if 'type' in target_set:
|
||||
if value_matches(qval, fm.get('type')):
|
||||
matched = True
|
||||
reasons.append('Type')
|
||||
# 8. Content
|
||||
if 'content' in target_set:
|
||||
if value_matches(qval, content):
|
||||
matched = True
|
||||
reasons.append('Content')
|
||||
snippet = get_content_snippet(content, qval)
|
||||
else:
|
||||
# Specific key search
|
||||
if k_lower == 'breadcrumbs':
|
||||
bcs = fm.get('breadcrumbs') or []
|
||||
if bcs and isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
|
||||
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
|
||||
else:
|
||||
bcs_list = bcs
|
||||
if '>' in qval:
|
||||
query_parts = [p.strip() for p in qval.split('>') if p.strip()]
|
||||
matched = match_breadcrumbs(bcs_list, query_parts)
|
||||
else:
|
||||
matched = value_matches(qval, bcs_list)
|
||||
if matched:
|
||||
reasons.append('Breadcrumbs')
|
||||
elif k_lower == 'authors':
|
||||
matched = value_matches(qval, fm.get('authors'))
|
||||
if matched:
|
||||
reasons.append('Authors')
|
||||
elif k_lower == 'pagekeywords':
|
||||
matched = value_matches(qval, fm.get('pageKeywords'))
|
||||
if matched:
|
||||
reasons.append('Keywords')
|
||||
elif k_lower == 'content':
|
||||
matched = value_matches(qval, content)
|
||||
if matched:
|
||||
reasons.append('Content')
|
||||
snippet = get_content_snippet(content, qval)
|
||||
elif k_lower in ('title', 'enhancedtitle', 'pagetitle'):
|
||||
for f in ['title', 'enhancedTitle', 'pageTitle']:
|
||||
if value_matches(qval, fm.get(f)):
|
||||
matched = True
|
||||
reasons.append('Title')
|
||||
break
|
||||
target_set = {'title', 'docid', 'breadcrumbs', 'authors', 'keywords', 'category', 'type', 'content'}
|
||||
|
||||
# 1. Title
|
||||
if 'title' in target_set:
|
||||
for f in ['title', 'enhancedTitle', 'pageTitle']:
|
||||
if value_matches(qv, fm.get(f), m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Title')
|
||||
break
|
||||
# 2. DocID
|
||||
if 'docid' in target_set:
|
||||
if value_matches(qv, fm.get('docid'), m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('DocID')
|
||||
# 3. Breadcrumbs
|
||||
if 'breadcrumbs' in target_set:
|
||||
bcs = fm.get('breadcrumbs') or []
|
||||
if isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
|
||||
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
|
||||
else:
|
||||
bcs_list = bcs
|
||||
if '>' in qv:
|
||||
query_parts = [p.strip() for p in qv.split('>') if p.strip()]
|
||||
if match_breadcrumbs(bcs_list, query_parts):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Breadcrumbs')
|
||||
else:
|
||||
if value_matches(qv, bcs_list, m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Breadcrumbs')
|
||||
# 4. Authors
|
||||
if 'authors' in target_set:
|
||||
if value_matches(qv, fm.get('authors'), m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Authors')
|
||||
# 5. PageKeywords
|
||||
if 'keywords' in target_set or 'pagekeywords' in target_set:
|
||||
if value_matches(qv, fm.get('pageKeywords'), m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Keywords')
|
||||
# 6. Category
|
||||
if 'category' in target_set:
|
||||
if value_matches(qv, fm.get('category'), m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Category')
|
||||
# 7. Type
|
||||
if 'type' in target_set:
|
||||
if value_matches(qv, fm.get('type'), m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Type')
|
||||
# 8. Content
|
||||
if 'content' in target_set:
|
||||
if value_matches(qv, content, m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Content')
|
||||
spec_snippet = get_content_snippet(content, qv)
|
||||
else:
|
||||
matched = value_matches(qval, fm.get(qkey))
|
||||
if matched:
|
||||
reasons.append(qkey.capitalize())
|
||||
# Specific key search
|
||||
if k_lower == 'breadcrumbs':
|
||||
bcs = fm.get('breadcrumbs') or []
|
||||
if bcs and isinstance(bcs, list) and bcs and isinstance(bcs[0], dict):
|
||||
bcs_list = [d.get('name') or d.get('slug') or '' for d in bcs]
|
||||
else:
|
||||
bcs_list = bcs
|
||||
if '>' in qv:
|
||||
query_parts = [p.strip() for p in qv.split('>') if p.strip()]
|
||||
spec_matched = match_breadcrumbs(bcs_list, query_parts)
|
||||
else:
|
||||
spec_matched = value_matches(qv, bcs_list, m)
|
||||
if spec_matched:
|
||||
spec_reasons.append('Breadcrumbs')
|
||||
elif k_lower == 'authors':
|
||||
spec_matched = value_matches(qv, fm.get('authors'), m)
|
||||
if spec_matched:
|
||||
spec_reasons.append('Authors')
|
||||
elif k_lower == 'pagekeywords':
|
||||
spec_matched = value_matches(qv, fm.get('pageKeywords'), m)
|
||||
if spec_matched:
|
||||
spec_reasons.append('Keywords')
|
||||
elif k_lower == 'content':
|
||||
spec_matched = value_matches(qv, content, m)
|
||||
if spec_matched:
|
||||
spec_reasons.append('Content')
|
||||
spec_snippet = get_content_snippet(content, qv)
|
||||
elif k_lower in ('title', 'enhancedtitle', 'pagetitle'):
|
||||
for f in ['title', 'enhancedTitle', 'pageTitle']:
|
||||
if value_matches(qv, fm.get(f), m):
|
||||
spec_matched = True
|
||||
spec_reasons.append('Title')
|
||||
break
|
||||
else:
|
||||
spec_matched = value_matches(qv, fm.get(qk), m)
|
||||
if spec_matched:
|
||||
spec_reasons.append(qk.capitalize())
|
||||
|
||||
if spec_matched:
|
||||
matched = True
|
||||
spec_reasons_clean = [str(x) for x in spec_reasons]
|
||||
reasons.extend(spec_reasons_clean)
|
||||
if spec_snippet and not snippet:
|
||||
snippet = spec_snippet
|
||||
|
||||
if matched:
|
||||
out.append({
|
||||
|
||||
+97
-40
@@ -169,41 +169,82 @@ def search_page() -> None: # build UI
|
||||
with ui.row().classes('gap-2'):
|
||||
ui.button('Open Output Dir', icon='folder', on_click=lambda: open_output_dir(), color='secondary').props('outline')
|
||||
|
||||
# Main Search Box Card
|
||||
with ui.card().classes('w-full p-6 shadow-xl'):
|
||||
with ui.row().classes('w-full items-center gap-4'):
|
||||
# Single search box
|
||||
qval_input = ui.input(
|
||||
label='Search Query',
|
||||
placeholder='Type search terms...'
|
||||
).classes('flex-grow').props('outlined label-slot')
|
||||
qval_input.add_slot('append', '<q-icon name="search" />')
|
||||
|
||||
# Match mode select
|
||||
mode_select = ui.select(
|
||||
options={'exact': 'Exact Match', 'fuzzy': 'Fuzzy Match', 'stemming': 'Stemming (Related Words)'},
|
||||
value='exact',
|
||||
label='Match Mode'
|
||||
).classes('w-56').props('outlined')
|
||||
|
||||
# Targets select
|
||||
targets_select = ui.select(
|
||||
options={
|
||||
'Title': 'Title',
|
||||
'Content': 'Content',
|
||||
'Breadcrumbs': 'Breadcrumbs',
|
||||
'Authors': 'Authors',
|
||||
'Keywords': 'Keywords',
|
||||
'Category': 'Category',
|
||||
'Type': 'Type'
|
||||
},
|
||||
value=['Title', 'Content', 'Breadcrumbs', 'Keywords', 'Category', 'Type'],
|
||||
label='Search Targets',
|
||||
multiple=True
|
||||
).classes('w-80').props('outlined use-chips')
|
||||
|
||||
# Search button
|
||||
search_btn = ui.button('Search', icon='search', on_click=lambda: asyncio.create_task(run_search_handler())).classes('bg-blue-600 hover:bg-blue-700 text-white font-semibold py-4 px-8 rounded-lg shadow-md transition-all duration-300')
|
||||
# Main Search card
|
||||
queries = [
|
||||
{
|
||||
'qval': '',
|
||||
'mode': 'exact',
|
||||
'targets': ['Title', 'Content', 'Breadcrumbs', 'Keywords', 'Category', 'Type']
|
||||
}
|
||||
]
|
||||
|
||||
with ui.card().classes('w-full p-6 shadow-xl gap-4'):
|
||||
query_blocks_container = ui.column().classes('w-full gap-4')
|
||||
|
||||
def render_query_blocks():
|
||||
query_blocks_container.clear()
|
||||
with query_blocks_container:
|
||||
for idx, q in enumerate(queries):
|
||||
with ui.row().classes('w-full items-center gap-4 border border-slate-800 p-4 rounded-lg bg-slate-900/40 relative'):
|
||||
label_text = "Query 1 (Primary)" if idx == 0 else f"OR Query {idx + 1}"
|
||||
ui.label(label_text).classes('text-blue-400 font-semibold w-36')
|
||||
|
||||
# Bind value and update on change
|
||||
qval_input = ui.input(
|
||||
label='Search Query',
|
||||
placeholder='Type search terms...',
|
||||
value=q['qval'],
|
||||
on_change=lambda e, q=q: q.update({'qval': e.value})
|
||||
).classes('flex-grow').props('outlined dense').on('keydown.enter', lambda: asyncio.create_task(run_search_handler()))
|
||||
|
||||
mode_select = ui.select(
|
||||
options={'exact': 'Exact Match', 'fuzzy': 'Fuzzy Match', 'stemming': 'Stemming (Related Words)'},
|
||||
value=q['mode'],
|
||||
label='Match Mode',
|
||||
on_change=lambda e, q=q: q.update({'mode': e.value})
|
||||
).classes('w-48').props('outlined dense')
|
||||
|
||||
targets_select = ui.select(
|
||||
options={
|
||||
'Title': 'Title',
|
||||
'Content': 'Content',
|
||||
'Breadcrumbs': 'Breadcrumbs',
|
||||
'Authors': 'Authors',
|
||||
'Keywords': 'Keywords',
|
||||
'Category': 'Category',
|
||||
'Type': 'Type'
|
||||
},
|
||||
value=q['targets'],
|
||||
label='Search Targets',
|
||||
multiple=True,
|
||||
on_change=lambda e, q=q: q.update({'targets': e.value})
|
||||
).classes('w-72').props('outlined dense use-chips')
|
||||
|
||||
if idx > 0:
|
||||
ui.button(
|
||||
icon='delete',
|
||||
on_click=lambda _, idx=idx: remove_query_block(idx)
|
||||
).classes('text-red-400 hover:text-red-500').props('flat round dense')
|
||||
|
||||
def add_query_block():
|
||||
queries.append({
|
||||
'qval': '',
|
||||
'mode': 'exact',
|
||||
'targets': ['Title', 'Content', 'Breadcrumbs', 'Keywords', 'Category', 'Type']
|
||||
})
|
||||
render_query_blocks()
|
||||
|
||||
def remove_query_block(idx: int):
|
||||
if 0 < idx < len(queries):
|
||||
queries.pop(idx)
|
||||
render_query_blocks()
|
||||
|
||||
# Render initial query blocks
|
||||
render_query_blocks()
|
||||
|
||||
with ui.row().classes('w-full justify-between items-center gap-4 mt-2'):
|
||||
ui.button('Add OR Query', icon='add', on_click=add_query_block).classes('text-blue-400 border border-blue-800').props('outline dense')
|
||||
search_btn = ui.button('Search', icon='search', on_click=lambda: asyncio.create_task(run_search_handler())).classes('bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-8 rounded-lg shadow-md transition-all duration-300')
|
||||
|
||||
# Advanced Criteria Expansion Box
|
||||
with ui.expansion('Advanced Configurations', icon='settings').classes('w-full text-slate-300 border border-slate-800 rounded-lg p-2'):
|
||||
@@ -283,7 +324,12 @@ def search_page() -> None: # build UI
|
||||
''')
|
||||
|
||||
async def run_search_handler():
|
||||
if not qval_input.value:
|
||||
has_query = False
|
||||
for q in queries:
|
||||
if q['qval'].strip():
|
||||
has_query = True
|
||||
break
|
||||
if not has_query:
|
||||
ui.notify('Please enter a search query', color='warning')
|
||||
return
|
||||
|
||||
@@ -291,13 +337,24 @@ def search_page() -> None: # build UI
|
||||
search_btn.set_enabled(False)
|
||||
|
||||
try:
|
||||
or_queries_param = []
|
||||
for q in queries:
|
||||
if q['qval'].strip():
|
||||
or_queries_param.append({
|
||||
'qkey': key_select.value,
|
||||
'qval': q['qval'],
|
||||
'mode': q['mode'],
|
||||
'targets': [t.lower() for t in q['targets']]
|
||||
})
|
||||
|
||||
results = await anyio.to_thread.run_sync(
|
||||
search_md.run_search,
|
||||
root_input.value,
|
||||
key_select.value,
|
||||
qval_input.value,
|
||||
mode_select.value,
|
||||
targets_select.value
|
||||
'global',
|
||||
'',
|
||||
'exact',
|
||||
None,
|
||||
or_queries_param
|
||||
)
|
||||
|
||||
table.rows = results
|
||||
|
||||
Reference in New Issue
Block a user