import lxml.etree as ET from fastapi import FastAPI, Response from fastapi.middleware.cors import CORSMiddleware from formex_viewer.formex4 import FormexArticleConverter from formex_viewer.main import ( CellarClient, CellarIdentifier, ContentType, Language, SystemName, ) origins = [ "http://localhost:5173", ] app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) type CacheKey = tuple[str, Language] CACHE: dict[CacheKey, str] = {} def _get_fmx4_data(celex_id: str, language: Language) -> str: """ Fetch the FMX4 data from the server. """ if (celex_id, language) in CACHE: return CACHE[(celex_id, language)] client = CellarClient(language) cellar_id = CellarIdentifier( system_name=SystemName.CELEX, system_id=celex_id, ) fmx4_data = client.publication_text(cellar_id, ContentType.ZIP_FMX4) CACHE[(celex_id, language)] = fmx4_data return fmx4_data @app.get("/{celex_id}/articles") def article_ids(celex_id: str, language: Language = Language.ENG): """ Fetch the article IDs from the server. """ fmx4_data = _get_fmx4_data(celex_id, language) xml = ET.fromstring(fmx4_data.encode("utf-8")) article_xpath = "//ARTICLE/@IDENTIFIER" article_ids = xml.xpath(article_xpath) article_ids = [int(article_id.lstrip("0")) for article_id in article_ids] article_ids.sort() return article_ids @app.get("/{celex_id}/toc/{language}") def toc(celex_id: str, language: Language = Language.ENG): """ Fetch the table of contents from the server. """ fmx4_data = _get_fmx4_data(celex_id, language) xml = ET.fromstring(fmx4_data.encode("utf-8")) toc = [] for division in xml.xpath("//DIVISION"): print(division) title = ti_el[0] if (ti_el := division.xpath("TITLE/TI//text()")) else "" subtitle = sti_el[0] if (sti_el := division.xpath("TITLE/STI//text()")) else "" articles = [] for article in division.xpath("ARTICLE") or []: art_id = article.get("IDENTIFIER") if not art_id: continue art_title = ti_el[0] if (ti_el := article.xpath("TI.ART//text()")) else "" art_subtitle = ( sti_el[0] if (sti_el := article.xpath("STI.ART//text()")) else "" ) articles.append( { "id": int(art_id.lstrip("0")), "type": "article", "title": art_title, "subtitle": art_subtitle, } ) toc.append( { "title": title, "type": "division", "subtitle": subtitle, "articles": articles, } ) return toc @app.get("/{celex_id}/articles/{article_id}/{language}") def article(celex_id: str, article_id: int, language: Language = Language.ENG): """ Fetch an article from the server. """ fmx4_data = _get_fmx4_data(celex_id, language) xml = ET.fromstring(fmx4_data.encode("utf-8")) article_xpath = "//ARTICLE" articles = xml.xpath(article_xpath) for article in articles: num = article.get("IDENTIFIER").lstrip("0") if num == str(article_id): return Response( FormexArticleConverter().convert_article(article), media_type="text/html", )