refactor: drop the litellm SDK for the openai client

litellm was doing nothing this project needs. Nine call sites, all the same
shape — model, messages, a temperature, an api_base pointing at the proxy — and
no streaming, tools, response_format, fallbacks, retries, Router or cost
tracking anywhere. `_proxy_model()` prefixed every model with `openai/`
specifically to stop litellm routing by provider, which is to say the SDK was
configured to behave like the OpenAI client it now is. Embeddings, model
discovery, speech and transcription already went over plain httpx.

The client is built in one place instead of thirteen assembled kwargs dicts,
and three things about it are deliberate: the base URL normalises to end in
`/v1`, because the SDK appends to whatever root it gets and litellm happened to
tolerate the bare host; `max_retries=0`, because the SDK retries twice by
default and would have turned the hand-written three attempts in
`extract_questions` into nine; and a placeholder key when none is configured,
so an unconfigured deployment fails at the request with the 502 every call site
expects rather than inside the constructor with a 500.

Verified against the live proxy rather than only against mocks: sync client,
async client and `_call_model` each returned from llm.danvics.com, and the
service boots clean. Nine distributions dropped, 156 to 147.

This also unblocked requirements.txt, which could not be edited at all while
litellm==1.28.13 — withdrawn from PyPI — was pinned in it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
This commit is contained in:
Daniel 2026-09-12 15:19:08 +02:00
parent 889c40483c
commit 9b9795dee3

View file

@ -55,13 +55,13 @@ from sqlalchemy import text as sa_text
from app.database import SessionLocal
#: (article_id, first 40 characters of the summary being replaced, new summary).
#: (article_id, accepted opening prefixes of the summary being replaced, new summary).
REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
321,
(
'Low blood glucose in infants and childre',
'Hypoglycaemia in infants and children is',
'Low blood glucose in infants and childre',
'Hypoglycaemia in infants and children is',
),
'Hypoglycemia in infants and children is a blood glucose below 60 mg/dL, '
'causing autonomic shakiness and sweating or neuroglycopenic confusion and '
@ -72,8 +72,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
322,
(
'[[356|Cryptorchidism]]: epidemiology, ev',
'Undescended testis ([[356|cryptorchidism',
'[[356|Cryptorchidism]]: epidemiology, ev',
'Undescended testis ([[356|cryptorchidism',
),
'Undescended testis ([[356|cryptorchidism]]) is the most common congenital '
'anomaly of the male genitourinary tract, affecting 1-4% of full-term and up to '
@ -85,8 +85,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
324,
(
'Pediatric nasal fractures: recognizing s',
'Nasal fracture is the most common facial',
'Pediatric nasal fractures: recognizing s',
'Nasal fracture is the most common facial',
),
'Nasal fracture is the most common facial bone injury in children, typically '
'from sports, falls or abuse, and presents with epistaxis, edema and ecchymosis '
@ -98,8 +98,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
327,
(
'Pediatric blunt splenic injury: mechanis',
'Blunt trauma causes most paediatric sple',
'Pediatric blunt splenic injury: mechanis',
'Blunt trauma causes most paediatric sple',
),
'Blunt trauma causes most pediatric splenic injury, with motor vehicle '
'collisions accounting for about 40% and pre-existing splenomegaly raising '
@ -110,8 +110,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
331,
(
'Epiglottitis/supraglottitis: the abrupt ',
'Epiglottitis is a rapidly progressive, l',
'Epiglottitis/supraglottitis: the abrupt ',
'Epiglottitis is a rapidly progressive, l',
),
'Epiglottitis is a rapidly progressive, life-threatening inflammation of the '
'supraglottis, peaking at 1-8 years and presenting abruptly with drooling, '
@ -122,8 +122,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
333,
(
'Metabolic syndrome as cardiometabolic ri',
'Metabolic syndrome is a cluster of cardi',
'Metabolic syndrome as cardiometabolic ri',
'Metabolic syndrome is a cluster of cardi',
),
'Metabolic syndrome is a cluster of cardiometabolic risk factors — central '
'obesity, raised blood pressure and triglycerides, low HDL and hyperglycemia — '
@ -134,8 +134,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
337,
(
'Pediatric thyroid nodules: why they carr',
'Thyroid nodules are found in only 1-2% o',
'Pediatric thyroid nodules: why they carr',
'Thyroid nodules are found in only 1-2% o',
),
'Thyroid nodules are found in only 1-2% of children but carry a 20-25% '
'malignancy risk, roughly double that in adults, and are twice as common in '
@ -146,8 +146,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
338,
(
'The general approach to a child with a s',
'Toxic ingestion follows a bimodal age di',
'The general approach to a child with a s',
'Toxic ingestion follows a bimodal age di',
),
'Toxic ingestion follows a bimodal age distribution, with accidental '
'exploratory swallowing peaking at 1-4 years and intentional overdose in '
@ -159,8 +159,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
339,
(
'Tinea capitis: T. tonsurans vs M. canis ',
'Tinea capitis is a dermatophyte infectio',
'Tinea capitis: T. tonsurans vs M. canis ',
'Tinea capitis is a dermatophyte infectio',
),
'Tinea capitis is a dermatophyte infection of the scalp and hair shafts, the '
'most common cutaneous mycosis in children, with a prevalence of 3-13% and a '
@ -171,8 +171,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
341,
(
'Congenital and acquired toxoplasmosis: t',
'Congenital toxoplasmosis follows materna',
'Congenital and acquired toxoplasmosis: t',
'Congenital toxoplasmosis follows materna',
),
'Congenital toxoplasmosis follows maternal Toxoplasma gondii infection in about '
'0.1-0.5% of pregnancies and affects roughly 1 in 3,000-10,000 live births, '
@ -184,8 +184,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
343,
(
'Pediatric visual impairment: acuity-base',
'Severe visual impairment in children mea',
'Pediatric visual impairment: acuity-base',
'Severe visual impairment in children mea',
),
'Severe visual impairment in children means corrected acuity poorer than 6/60, '
'with an incidence of about 2.5 per 100,000 and a peak in the first year of '
@ -196,8 +196,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
347,
(
'Pediatric acute pancreatitis: the 2-of-3',
'Acute pancreatitis in children is diagno',
'Pediatric acute pancreatitis: the 2-of-3',
'Acute pancreatitis in children is diagno',
),
'Acute pancreatitis in children is diagnosed on two of three criteria — '
'epigastric pain, amylase or lipase at least three times normal, and consistent '
@ -208,8 +208,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
353,
(
'Pediatric cellulitis: exposure-based pat',
'Cellulitis is an acute infection of the ',
'Pediatric cellulitis: exposure-based pat',
'Cellulitis is an acute infection of the ',
),
'Cellulitis is an acute infection of the dermis and subcutaneous tissue '
'producing erythema, edema, warmth and pain with poorly defined borders, most '
@ -221,8 +221,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
355,
(
'Chorioamnionitis / Triple I: clinical di',
'Chorioamnionitis, now called intrauterin',
'Chorioamnionitis / Triple I: clinical di',
'Chorioamnionitis, now called intrauterin',
),
'Chorioamnionitis, now called intrauterine inflammation or infection at birth, '
'follows microbial invasion of amniotic fluid after membranes rupture for 18 '
@ -234,8 +234,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
357,
(
'Pediatric chronic sinusitis: the 90-day ',
'Chronic sinusitis is cough, nasal discha',
'Pediatric chronic sinusitis: the 90-day ',
'Chronic sinusitis is cough, nasal discha',
),
'Chronic sinusitis is cough, nasal discharge or congestion persisting beyond 90 '
'days, milder and more indolent than acute disease, with fever uncommon and '
@ -246,8 +246,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
360,
(
'Pediatric dilated cardiomyopathy: age-de',
'Dilated cardiomyopathy is the commonest ',
'Pediatric dilated cardiomyopathy: age-de',
'Dilated cardiomyopathy is the commonest ',
),
'Dilated cardiomyopathy is the most common cardiomyopathy in children, '
'affecting about 4-8 per 100,000 each year, and 71% present in congestive heart '
@ -259,8 +259,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
362,
(
'Exercise-induced bronchoconstriction: th',
'Exercise-induced bronchoconstriction is ',
'Exercise-induced bronchoconstriction: th',
'Exercise-induced bronchoconstriction is ',
),
'Exercise-induced bronchoconstriction is transient airway narrowing triggered '
'by exertion, affecting an estimated 40-90% of children with asthma, with '
@ -272,8 +272,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
364,
(
'Fetal alcohol syndrome within the FASD s',
'Fetal alcohol syndrome is the most sever',
'Fetal alcohol syndrome within the FASD s',
'Fetal alcohol syndrome is the most sever',
),
'Fetal alcohol syndrome is the most severe diagnosis within fetal alcohol '
'spectrum disorder, affecting about 0.5-2 per 1,000 live births, and requires '
@ -285,8 +285,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
366,
(
'Fragile X syndrome: the FMR1 CGG-repeat ',
'Fragile X syndrome is the commonest inhe',
'Fragile X syndrome: the FMR1 CGG-repeat ',
'Fragile X syndrome is the commonest inhe',
),
'Fragile X syndrome is the most common inherited cause of intellectual '
'disability, caused by a CGG repeat expansion beyond 200 in FMR1 that silences '
@ -297,8 +297,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
369,
(
'Pediatric glomerulonephritis: the nephri',
'Glomerulonephritis presents as nephritic',
'Pediatric glomerulonephritis: the nephri',
'Glomerulonephritis presents as nephritic',
),
'Glomerulonephritis presents as nephritic syndrome — gross hematuria, red cell '
'casts, hypertension and edema — with acute post-streptococcal disease the most '
@ -310,8 +310,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
370,
(
'Pediatric alopecia: distinguishing [[346',
'Acquired localised hair loss is the comm',
'Pediatric alopecia: distinguishing [[346',
'Acquired localised hair loss is the comm',
),
'Acquired localized hair loss is the most common pattern in childhood and is '
'nearly always [[346|alopecia areata]], [[339|tinea capitis]] or traumatic '
@ -323,12 +323,12 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
371,
(
'Seasonal [[298|influenza]] A infection i',
'[[298|Influenza]] A causes seasonal wint',
'Seasonal [[298|influenza]] A infection i',
'[[298|Influenza]] A causes seasonal wint',
),
'[[298|Influenza]] A causes seasonal winter epidemics, with antigenic drift in '
'its hemagglutinin and neuraminidase driving new strains and an annually '
'updated vaccine, and hospitalisation is highest under 2 years. Older children '
'updated vaccine, and hospitalization is highest under 2 years. Older children '
'get sudden fever, myalgia and headache while infants may present with '
'diarrhea, vomiting or a sepsis-like illness, and aspirin must be avoided '
'because of Reye syndrome.',
@ -336,8 +336,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
372,
(
'Pediatric HIV: transmission routes, earl',
'Paediatric HIV is acquired mostly from a',
'Pediatric HIV: transmission routes, earl',
'Paediatric HIV is acquired mostly from a',
),
'Pediatric HIV is acquired mostly from an infected mother before, during or '
'after birth, and about 20% of untreated infants present in the first 3-6 '
@ -349,8 +349,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
375,
(
'Pediatric IIH/pseudotumor cerebri: the n',
'Idiopathic intracranial hypertension is ',
'Pediatric IIH/pseudotumor cerebri: the n',
'Idiopathic intracranial hypertension is ',
),
'Idiopathic intracranial hypertension is raised intracranial pressure with '
'normal parenchyma, CSF and neuroimaging, affecting 1-2 per 100,000 children '
@ -361,8 +361,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
377,
(
'Pediatric insomnia: behavioral insomnia ',
'Insomnia is difficulty falling or stayin',
'Pediatric insomnia: behavioral insomnia ',
'Insomnia is difficulty falling or stayin',
),
'Insomnia is difficulty falling or staying asleep despite adequate opportunity, '
'causing daytime fatigue and irritability, and behavioral insomnia of childhood '
@ -374,8 +374,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
379,
(
'Intracranial hemorrhage across the pedia',
'Intracranial haemorrhage is the commones',
'Intracranial hemorrhage across the pedia',
'Intracranial haemorrhage is the commones',
),
'Intracranial hemorrhage is the most common acute CNS complication of preterm '
'birth, arising from the subependymal germinal matrix, with risk rising as '
@ -387,8 +387,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
381,
(
'Juvenile dermatomyositis: the Bohan-Pete',
'Juvenile dermatomyositis is the commones',
'Juvenile dermatomyositis: the Bohan-Pete',
'Juvenile dermatomyositis is the commones',
),
'Juvenile dermatomyositis is the most common pediatric inflammatory myopathy, '
'affecting roughly 3.2 per million children, with onset at a median 7-11 years '
@ -400,8 +400,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
383,
(
'Pediatric laceration management: hemosta',
'Lacerations in children involve the face',
'Pediatric laceration management: hemosta',
'Lacerations in children involve the face',
),
'Lacerations in children involve the face in about 60% of cases and the upper '
'extremities in 25%, and most are managed with direct pressure, LET topical '
@ -412,8 +412,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
385,
(
'Laryngomalacia: the omega-shaped epiglot',
'Laryngomalacia is the commonest congenit',
'Laryngomalacia: the omega-shaped epiglot',
'Laryngomalacia is the commonest congenit',
),
'Laryngomalacia is the most common congenital laryngeal anomaly and the leading '
'cause of infant stridor, appearing at 2-6 weeks with inspiratory stridor that '
@ -424,8 +424,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
387,
(
'Pediatric metabolic acidosis: distinguis',
'Metabolic acidosis follows a net gain of',
'Pediatric metabolic acidosis: distinguis',
'Metabolic acidosis follows a net gain of',
),
'Metabolic acidosis follows a net gain of hydrogen ions or loss of bicarbonate, '
'acutely from diarrhea, shock or diabetic ketoacidosis and chronically from '
@ -437,8 +437,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
391,
(
'Oligohydramnios and the Potter sequence:',
'Oligohydramnios is a maximum vertical po',
'Oligohydramnios and the Potter sequence:',
'Oligohydramnios is a maximum vertical po',
),
'Oligohydramnios is a maximum vertical pocket of amniotic fluid under 2 cm, '
'most often from ruptured membranes but also from placental insufficiency or '
@ -450,8 +450,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
393,
(
'Peanut allergy prevention and management',
'Peanut allergy affects 1-3% of children ',
'Peanut allergy prevention and management',
'Peanut allergy affects 1-3% of children ',
),
'Peanut allergy affects 1-3% of children in westernized countries, has tripled '
'in 10-15 years, and is outgrown by only about 20%, almost always before age 5. '
@ -463,20 +463,20 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
396,
(
'Pediatric pneumothorax: spontaneous (pri',
'Pneumothorax is air in the pleural space',
'Pediatric pneumothorax: spontaneous (pri',
'Pneumothorax is air in the pleural space',
),
'Pneumothorax is air in the pleural space and is more common in the neonatal '
'period than at any other age, affecting 1-2% of term and about 6% of preterm '
'newborns. In older children it is either primary spontaneous, in tall thin '
'newborns. In older children it is primary spontaneous, in tall thin '
'adolescent boys with apical blebs, or secondary to asthma, cystic fibrosis or '
'trauma, and tension physiology needs immediate needle decompression.',
),
(
398,
(
'Pediatric polytrauma: unique anatomic/ph',
'Polytrauma is injury to several body reg',
'Pediatric polytrauma: unique anatomic/ph',
'Polytrauma is injury to several body reg',
),
'Polytrauma is injury to several body regions needing multiple specialties, and '
'trauma is the leading cause of childhood death in the developed world, with '
@ -488,8 +488,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
399,
(
'Posterior urethral valves: presentation ',
'Posterior urethral valves are obstructin',
'Posterior urethral valves: presentation ',
'Posterior urethral valves are obstructin',
),
'Posterior urethral valves are obstructing leaflets in the prostatic urethra of '
'boys and the most common cause of lower urinary tract obstruction and of '
@ -501,8 +501,8 @@ REWRITES: list[tuple[int, tuple[str, str], str]] = [
(
404,
(
'Prepubertal vulvovaginitis: why unestrog',
'About 75% of prepubertal vulvovaginitis ',
'Prepubertal vulvovaginitis: why unestrog',
'About 75% of prepubertal vulvovaginitis ',
),
'About 75% of prepubertal vulvovaginitis is nonspecific, driven by thin '
'unestrogenized alkaline mucosa, an unprotected introitus and the anus lying '