Spaces:
Sleeping
Sleeping
| import re | |
| from collections import Counter | |
| import gradio as gr | |
| from pypdf import PdfReader | |
| APP_TITLE = "🧭 SubsidieKompas AI" | |
| MODEL_HINT = ( | |
| "Deze demo werkt zonder API-key met een transparante, regel-gebaseerde analyse. " | |
| "De score is opgebouwd uit zichtbare criteria, zodat het geen black box is." | |
| ) | |
| # -------------------------------------------------- | |
| # Tekstextractie en helpers | |
| # -------------------------------------------------- | |
| def extract_pdf_text(file_obj) -> str: | |
| if file_obj is None: | |
| return "" | |
| try: | |
| reader = PdfReader(file_obj.name) | |
| pages = [] | |
| for page in reader.pages[:30]: | |
| text = page.extract_text() or "" | |
| pages.append(text) | |
| return "\n".join(pages).strip() | |
| except Exception as exc: | |
| return f"[Kon PDF niet lezen: {exc}]" | |
| def clean_text(text: str) -> str: | |
| text = text or "" | |
| text = re.sub(r"\s+", " ", text) | |
| return text.strip() | |
| def count_matches(text: str, keywords: list[str]) -> list[str]: | |
| lowered = text.lower() | |
| return [kw for kw in keywords if kw.lower() in lowered] | |
| def percentage(part: int, total: int) -> int: | |
| if total == 0: | |
| return 0 | |
| return round((part / total) * 100) | |
| def classify_score(score: int) -> str: | |
| if score >= 80: | |
| return "Sterk concept" | |
| if score >= 65: | |
| return "Kansrijk, maar nog aanscherpen" | |
| if score >= 45: | |
| return "Redelijk concept met duidelijke verbeterpunten" | |
| return "Nog onvoldoende uitgewerkt" | |
| def make_markdown_list(items: list[str]) -> str: | |
| if not items: | |
| return "- Geen opvallende onderdelen gevonden." | |
| return "\n".join([f"- {item}" for item in items]) | |
| def tokenize_words(text: str) -> list[str]: | |
| text = text.lower() | |
| words = re.findall(r"[a-zA-ZÀ-ÿ]{4,}", text) | |
| stopwords = { | |
| "deze", "zijn", "voor", "naar", "door", "over", "onder", "wordt", | |
| "worden", "zoals", "heeft", "hebben", "niet", "meer", "maar", | |
| "waar", "daar", "hier", "met", "vanuit", "binnen", "tussen", | |
| "gemeente", "rotterdam", "haag", "aanvraag", "subsidie", | |
| "regeling", "project", "kunnen", "moeten", "zal", "zullen", | |
| "wij", "ons", "onze", "het", "een", "dit", "dat", "die", | |
| "aan", "bij", "uit", "ook", "als", "om", "op", "en", "of", | |
| "in", "te", "is", "zijn", "voor", "met", "tot" | |
| } | |
| return [w for w in words if w not in stopwords] | |
| def top_terms(text: str, n: int = 20) -> list[str]: | |
| words = tokenize_words(text) | |
| counts = Counter(words) | |
| return [word for word, _ in counts.most_common(n)] | |
| def sentence_stats(text: str) -> tuple[int, int]: | |
| sentences = re.split(r"[.!?]+", text) | |
| sentences = [s.strip() for s in sentences if s.strip()] | |
| if not sentences: | |
| return 0, 0 | |
| word_counts = [len(s.split()) for s in sentences] | |
| avg = round(sum(word_counts) / len(word_counts)) | |
| return len(sentences), avg | |
| def tone_label(avg_sentence_length: int) -> str: | |
| if avg_sentence_length >= 24: | |
| return "formeel en beleidsmatig, met relatief lange zinnen" | |
| if avg_sentence_length >= 16: | |
| return "zakelijk en beleidsmatig" | |
| if avg_sentence_length >= 10: | |
| return "toegankelijk en compact" | |
| return "kort en direct" | |
| # -------------------------------------------------- | |
| # Analyse | |
| # -------------------------------------------------- | |
| def analyse_aanvraag( | |
| regeling_pdf, | |
| regeling_plaktekst, | |
| aanvraag_pdf, | |
| aanvraag_plaktekst, | |
| beleid_pdf, | |
| beleid_plaktekst, | |
| thema, | |
| doelgroep, | |
| gemeente, | |
| ): | |
| regeling_text = clean_text( | |
| "\n\n".join([extract_pdf_text(regeling_pdf), regeling_plaktekst or ""]) | |
| ) | |
| aanvraag_text = clean_text( | |
| "\n\n".join([extract_pdf_text(aanvraag_pdf), aanvraag_plaktekst or ""]) | |
| ) | |
| beleid_text = clean_text( | |
| "\n\n".join([extract_pdf_text(beleid_pdf), beleid_plaktekst or ""]) | |
| ) | |
| if not regeling_text and not aanvraag_text: | |
| return ( | |
| "0%", | |
| "Upload of plak eerst een subsidieregeling én een conceptaanvraag.", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "", | |
| ) | |
| if not regeling_text: | |
| return ( | |
| "0%", | |
| "De subsidieregeling ontbreekt. Upload een regeling of plak de tekst.", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "", | |
| ) | |
| if not aanvraag_text: | |
| return ( | |
| "0%", | |
| "De conceptaanvraag ontbreekt. Upload een conceptaanvraag of plak de tekst.", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "", | |
| ) | |
| domein_keywords = [ | |
| "mentale gezondheid", | |
| "ggz", | |
| "wmo", | |
| "welzijn", | |
| "preventie", | |
| "participatie", | |
| "herstel", | |
| "herstelondersteuning", | |
| "dagbesteding", | |
| "arbeid", | |
| "ips", | |
| "jongvolwassenen", | |
| "wijkgericht", | |
| "kwetsbare inwoners", | |
| "beschermd wonen", | |
| "zelfredzaamheid", | |
| "ervaringsdeskundigheid", | |
| "sociaal domein", | |
| "bestaanszekerheid", | |
| "veerkracht", | |
| "vroegsignalering", | |
| "gebiedsgericht", | |
| "samenwerking", | |
| ] | |
| aanvraag_bouwstenen = [ | |
| "aanleiding", | |
| "probleem", | |
| "doel", | |
| "doelstelling", | |
| "doelgroep", | |
| "activiteiten", | |
| "aanpak", | |
| "planning", | |
| "resultaten", | |
| "impact", | |
| "indicatoren", | |
| "kpi", | |
| "monitoring", | |
| "evaluatie", | |
| "begroting", | |
| "kosten", | |
| "samenwerking", | |
| "partners", | |
| "duurzaamheid", | |
| "borging", | |
| "risico", | |
| ] | |
| subsidiecriteria = [ | |
| "doelstelling", | |
| "doelgroep", | |
| "voorwaarden", | |
| "criteria", | |
| "beoordeling", | |
| "activiteiten", | |
| "resultaten", | |
| "begroting", | |
| "cofinanciering", | |
| "deadline", | |
| "subsidieplafond", | |
| "evaluatie", | |
| "monitoring", | |
| "samenwerking", | |
| "impact", | |
| "duurzaamheid", | |
| ] | |
| regeling_criteria_gevonden = count_matches(regeling_text, subsidiecriteria) | |
| aanvraag_bouwstenen_gevonden = count_matches(aanvraag_text, aanvraag_bouwstenen) | |
| domein_in_regeling = count_matches(regeling_text, domein_keywords) | |
| domein_in_aanvraag = count_matches(aanvraag_text, domein_keywords) | |
| overlap_domein = sorted( | |
| list(set(domein_in_regeling).intersection(set(domein_in_aanvraag))) | |
| ) | |
| overlap_criteria = sorted( | |
| list(set(regeling_criteria_gevonden).intersection(set(aanvraag_bouwstenen_gevonden))) | |
| ) | |
| bouwstenen_score = percentage( | |
| len(aanvraag_bouwstenen_gevonden), | |
| len(aanvraag_bouwstenen), | |
| ) | |
| domein_score = percentage( | |
| len(overlap_domein), | |
| max(len(set(domein_in_regeling)), 1), | |
| ) | |
| criteria_score = percentage( | |
| len(overlap_criteria), | |
| max(len(set(regeling_criteria_gevonden)), 1), | |
| ) | |
| aanvraag_lengte_score = min(100, round(len(aanvraag_text.split()) / 12)) | |
| regeling_lengte_score = min(100, round(len(regeling_text.split()) / 10)) | |
| tekstbasis_score = min(aanvraag_lengte_score, regeling_lengte_score) | |
| eindscore = round( | |
| bouwstenen_score * 0.35 | |
| + domein_score * 0.25 | |
| + criteria_score * 0.30 | |
| + tekstbasis_score * 0.10 | |
| ) | |
| oordeel = classify_score(eindscore) | |
| ontbrekende_bouwstenen = [ | |
| item for item in aanvraag_bouwstenen if item not in aanvraag_bouwstenen_gevonden | |
| ] | |
| risico_lijst = [] | |
| if "deadline" in regeling_text.lower() and "deadline" not in aanvraag_text.lower(): | |
| risico_lijst.append( | |
| "De regeling lijkt een deadline te bevatten, maar deze komt niet terug in de aanvraag." | |
| ) | |
| if "begroting" not in aanvraag_text.lower() and "kosten" not in aanvraag_text.lower(): | |
| risico_lijst.append( | |
| "De financiële onderbouwing lijkt nog onvoldoende zichtbaar." | |
| ) | |
| if "evaluatie" not in aanvraag_text.lower() and "monitoring" not in aanvraag_text.lower(): | |
| risico_lijst.append( | |
| "Monitoring en evaluatie zijn nog onvoldoende uitgewerkt." | |
| ) | |
| if "samenwerking" not in aanvraag_text.lower() and "partners" not in aanvraag_text.lower(): | |
| risico_lijst.append( | |
| "Samenwerking met partners komt nog onvoldoende naar voren." | |
| ) | |
| if "impact" not in aanvraag_text.lower() and "resultaten" not in aanvraag_text.lower(): | |
| risico_lijst.append( | |
| "Resultaten en maatschappelijke impact kunnen sterker worden beschreven." | |
| ) | |
| if not overlap_domein: | |
| risico_lijst.append( | |
| "Er is weinig zichtbare inhoudelijke overlap tussen regeling en aanvraag." | |
| ) | |
| if not risico_lijst: | |
| risico_lijst.append("Geen grote risico’s gevonden in deze eerste toets.") | |
| # -------------------------------------------------- | |
| # Tone-of-voice / beleidstaal | |
| # -------------------------------------------------- | |
| beleidstaal_md = "" | |
| if beleid_text: | |
| beleid_terms = top_terms(beleid_text, 20) | |
| aanvraag_terms = top_terms(aanvraag_text, 30) | |
| beleid_overlap = sorted(list(set(beleid_terms).intersection(set(aanvraag_terms)))) | |
| ontbrekende_beleidstermen = [ | |
| term for term in beleid_terms if term not in beleid_overlap | |
| ] | |
| _, beleid_avg_sentence = sentence_stats(beleid_text) | |
| _, aanvraag_avg_sentence = sentence_stats(aanvraag_text) | |
| beleid_tone = tone_label(beleid_avg_sentence) | |
| aanvraag_tone = tone_label(aanvraag_avg_sentence) | |
| beleids_keywords = count_matches(beleid_text, domein_keywords) | |
| aanvraag_beleids_keywords = count_matches(aanvraag_text, beleids_keywords) | |
| ontbrekende_domeintermen = [ | |
| term for term in beleids_keywords if term not in aanvraag_beleids_keywords | |
| ] | |
| beleidstaal_md = f""" | |
| ## Beleidstaal en tone-of-voice | |
| Deze check vergelijkt je conceptaanvraag met een gemeentelijk beleidsdocument of voorbeeldtekst. | |
| ### Stijlindicatie | |
| | Onderdeel | Gemiddelde zinslengte | Indicatie | | |
| |---|---:|---| | |
| | Gemeentelijke tekst | {beleid_avg_sentence} woorden | {beleid_tone} | | |
| | Conceptaanvraag | {aanvraag_avg_sentence} woorden | {aanvraag_tone} | | |
| ### Veelvoorkomende woorden in de gemeentelijke tekst | |
| {make_markdown_list(beleid_terms[:15])} | |
| ### Woorden die ook terugkomen in je aanvraag | |
| {make_markdown_list(beleid_overlap[:15])} | |
| ### Gemeentelijke woorden die nog weinig terugkomen | |
| {make_markdown_list(ontbrekende_beleidstermen[:15])} | |
| ### Beleidsmatige domeintermen uit de gemeente die nog sterker kunnen terugkomen | |
| {make_markdown_list(ontbrekende_domeintermen[:10])} | |
| ### Schrijfadvies | |
| - Gebruik herkenbare woorden uit het gemeentelijke beleidsdocument, maar alleen waar ze inhoudelijk kloppen. | |
| - Sluit aan bij de gemeentelijke beleidstaal zonder de tekst kunstmatig te maken. | |
| - Benoem explicieter hoe je aanvraag aansluit op lokale beleidsdoelen. | |
| - Als de gemeentelijke tekst formeel is, maak je aanvraag iets beleidsmatiger. | |
| - Als de gemeentelijke tekst kort en direct is, vermijd dan lange abstracte zinnen. | |
| ### Voorbeeldformulering | |
| > Met deze aanvraag sluiten wij aan op de gemeentelijke ambitie om kwetsbare inwoners eerder, laagdrempeliger en wijkgericht te ondersteunen. Door herstelondersteuning, participatie en samenwerking met lokale partners te verbinden, draagt het project bij aan duurzame maatschappelijke impact. | |
| """.strip() | |
| else: | |
| beleidstaal_md = """ | |
| ## Beleidstaal en tone-of-voice | |
| Er is nog geen gemeentelijk beleidsdocument of voorbeeldtekst toegevoegd. | |
| Upload bijvoorbeeld: | |
| - een beleidsnota; | |
| - een collegebrief; | |
| - een subsidieregeling; | |
| - een raadsvoorstel; | |
| - een programmabeschrijving. | |
| Daarna kan de tool toetsen of je conceptaanvraag qua taal, begrippen en stijl aansluit op de beleidstaal van de gemeente. | |
| """.strip() | |
| eindoordeel = f""" | |
| ## {oordeel} | |
| De conceptaanvraag scoort **{eindscore}%** op aansluiting met de subsidieregeling. | |
| **Context** | |
| - Gemeente/regio: **{gemeente or "niet ingevuld"}** | |
| - Thema: **{thema or "niet ingevuld"}** | |
| - Doelgroep: **{doelgroep or "niet ingevuld"}** | |
| **Korte interpretatie** | |
| Deze toets vergelijkt de subsidieregeling met de conceptaanvraag op vier onderdelen: | |
| 1. volledigheid van de aanvraag; | |
| 2. inhoudelijke aansluiting; | |
| 3. aansluiting op subsidiecriteria; | |
| 4. hoeveelheid beschikbare tekst. | |
| De uitkomst is bedoeld als eerste toets en niet als definitief subsidieadvies. | |
| """.strip() | |
| criteria_check = f""" | |
| ## Criteria-check | |
| ### Gevonden onderdelen in de subsidieregeling | |
| {make_markdown_list(regeling_criteria_gevonden)} | |
| ### Gevonden onderdelen in de conceptaanvraag | |
| {make_markdown_list(aanvraag_bouwstenen_gevonden)} | |
| ### Overlap tussen regeling en aanvraag | |
| {make_markdown_list(overlap_criteria)} | |
| ### Inhoudelijke overlap | |
| {make_markdown_list(overlap_domein)} | |
| """.strip() | |
| verbeterpunten = f""" | |
| ## Verbeterpunten | |
| ### Ontbrekende of zwak zichtbare onderdelen | |
| {make_markdown_list([item.capitalize() for item in ontbrekende_bouwstenen[:10]])} | |
| ### Advies | |
| - Maak expliciet welke subsidiecriteria de aanvraag raakt. | |
| - Gebruik dezelfde begrippen als in de subsidieregeling. | |
| - Voeg concrete resultaten, indicatoren en meetmomenten toe. | |
| - Werk de begroting en onderbouwing zichtbaar uit. | |
| - Benoem waarom de aanvraag past bij de beleidsdoelen van de regeling. | |
| """.strip() | |
| risico = f""" | |
| ## Risico’s en aandachtspunten | |
| {make_markdown_list(risico_lijst)} | |
| """.strip() | |
| transparantie = f""" | |
| ## Transparantie van de score | |
| De score is als volgt opgebouwd: | |
| | Onderdeel | Weging | Score | | |
| |---|---:|---:| | |
| | Volledigheid conceptaanvraag | 35% | {bouwstenen_score}% | | |
| | Inhoudelijke overlap met regeling | 25% | {domein_score}% | | |
| | Aansluiting op subsidiecriteria | 30% | {criteria_score}% | | |
| | Voldoende tekstbasis | 10% | {tekstbasis_score}% | | |
| ### Wat betekent dit? | |
| - **Volledigheid** kijkt of onderdelen zoals doel, doelgroep, activiteiten, begroting, monitoring en evaluatie aanwezig zijn. | |
| - **Inhoudelijke overlap** kijkt of thema’s uit de regeling terugkomen in de aanvraag. | |
| - **Criteria-aansluiting** kijkt of beoordelingscriteria uit de regeling zichtbaar worden geraakt. | |
| - **Tekstbasis** voorkomt dat een heel korte tekst een te stevige beoordeling krijgt. | |
| ### Belangrijk | |
| Deze versie gebruikt geen verborgen modelredenering. De analyse is gebaseerd op zichtbare trefwoorden, tekststructuur en overlap. Daardoor is de uitkomst uitlegbaar, maar ook beperkt: inhoudelijke kwaliteit en nuance moeten altijd door jou worden beoordeeld. | |
| """.strip() | |
| return ( | |
| f"{eindscore}%", | |
| eindoordeel, | |
| criteria_check, | |
| verbeterpunten, | |
| risico, | |
| beleidstaal_md, | |
| transparantie, | |
| ) | |
| # -------------------------------------------------- | |
| # CSS | |
| # -------------------------------------------------- | |
| custom_css = """ | |
| :root { | |
| --radius-xl: 24px; | |
| } | |
| .gradio-container { | |
| max-width: 1180px !important; | |
| margin: auto !important; | |
| } | |
| .hero { | |
| padding: 34px; | |
| border-radius: var(--radius-xl); | |
| background: #ffffff; | |
| color: #1e293b; | |
| border: 1px solid #e5e7eb; | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.05); | |
| margin-bottom: 24px; | |
| } | |
| .hero h1 { | |
| font-size: 36px; | |
| margin-bottom: 18px; | |
| letter-spacing: -0.04em; | |
| color: #0f172a; | |
| } | |
| .hero h2 { | |
| margin-top: 0; | |
| margin-bottom: 18px; | |
| color: #0f172a; | |
| font-size: 24px; | |
| font-weight: 700; | |
| } | |
| .hero h3 { | |
| margin-top: 24px; | |
| margin-bottom: 10px; | |
| color: #1e293b; | |
| font-size: 20px; | |
| } | |
| .hero p, | |
| .hero li { | |
| color: #475569; | |
| line-height: 1.7; | |
| font-size: 15px; | |
| } | |
| .hero ul { | |
| padding-left: 24px; | |
| margin-bottom: 16px; | |
| } | |
| .footer-note { | |
| color: #64748b; | |
| font-size: 13px; | |
| margin-top: 20px; | |
| } | |
| #scorebox textarea { | |
| font-size: 34px !important; | |
| font-weight: 800 !important; | |
| text-align: center !important; | |
| } | |
| """ | |
| # -------------------------------------------------- | |
| # Interface | |
| # -------------------------------------------------- | |
| with gr.Blocks(css=custom_css, title=APP_TITLE, theme=gr.themes.Soft()) as demo: | |
| gr.HTML( | |
| """ | |
| <div class="hero"> | |
| <h1>🧭 SubsidieKompas AI</h1> | |
| <h2>Over SubsidieKompas AI</h2> | |
| <p> | |
| Ik heb SubsidieKompas AI ontwikkeld om sneller inzicht te krijgen in de | |
| kansrijkheid van concept-subsidieaanvragen. | |
| </p> | |
| <p> | |
| De tool vergelijkt een subsidieregeling met een conceptaanvraag en laat | |
| zien waar de aanvraag al goed aansluit, welke onderdelen ontbreken en | |
| welke risico’s of verbeterpunten aandacht vragen. | |
| </p> | |
| <p> | |
| Daarnaast kun je een gemeentelijke beleidsnota of voorbeeldtekst uploaden. | |
| De tool vergelijkt dan of je aanvraag qua beleidstaal en tone-of-voice | |
| aansluit op de manier waarop de gemeente zelf schrijft. | |
| </p> | |
| <p> | |
| Het doel is niet om automatisch een definitief oordeel te geven, maar om | |
| sneller, transparanter en gestructureerder te toetsen of een aanvraag | |
| voldoende aansluit op de regeling en de gemeentelijke context. | |
| </p> | |
| <h3>Wat doet de tool?</h3> | |
| <ul> | |
| <li>Toetst een conceptaanvraag aan een subsidieregeling</li> | |
| <li>Geeft een indicatieve subsidie-fit score</li> | |
| <li>Laat zien welke criteria zijn gevonden</li> | |
| <li>Signaleert ontbrekende onderdelen</li> | |
| <li>Benoemt risico’s en aandachtspunten</li> | |
| <li>Vergelijkt beleidstaal en tone-of-voice</li> | |
| <li>Toont transparant hoe de score is opgebouwd</li> | |
| </ul> | |
| </div> | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=5): | |
| gr.Markdown("## 1. Invoer") | |
| regeling_pdf = gr.File( | |
| label="Upload subsidieregeling als PDF", | |
| file_types=[".pdf"], | |
| ) | |
| regeling_plaktekst = gr.Textbox( | |
| label="Of plak tekst uit de subsidieregeling", | |
| placeholder="Plak hier voorwaarden, doelstelling, criteria, deadline of beoordelingskader...", | |
| lines=5, | |
| ) | |
| aanvraag_pdf = gr.File( | |
| label="Upload concept subsidieaanvraag als PDF", | |
| file_types=[".pdf"], | |
| ) | |
| aanvraag_plaktekst = gr.Textbox( | |
| label="Of plak tekst uit je concept subsidieaanvraag", | |
| placeholder="Plak hier je conceptaanvraag als je geen PDF wilt uploaden...", | |
| lines=8, | |
| ) | |
| beleid_pdf = gr.File( | |
| label="Optioneel: upload gemeentelijk beleidsdocument of voorbeeldtekst als PDF", | |
| file_types=[".pdf"], | |
| ) | |
| beleid_plaktekst = gr.Textbox( | |
| label="Of plak gemeentelijke beleidstekst / tone-of-voice voorbeeld", | |
| placeholder="Plak hier bijvoorbeeld een beleidsnota, collegebrief, subsidieregeling of raadsvoorstel...", | |
| lines=6, | |
| ) | |
| with gr.Row(): | |
| thema = gr.Dropdown( | |
| choices=[ | |
| "Mentale gezondheid", | |
| "Herstelondersteuning", | |
| "Participatie", | |
| "Dagbesteding", | |
| "Arbeidstoeleiding / IPS", | |
| "Wmo", | |
| "Welzijn", | |
| "Preventie", | |
| "Beschermd wonen", | |
| "Jongvolwassenen", | |
| ], | |
| label="Thema", | |
| value="Herstelondersteuning", | |
| ) | |
| gemeente = gr.Textbox( | |
| label="Gemeente/regio", | |
| value="Rotterdam / Den Haag", | |
| ) | |
| doelgroep = gr.Textbox( | |
| label="Doelgroep", | |
| value="Mensen met psychische kwetsbaarheid", | |
| ) | |
| analyse_btn = gr.Button( | |
| "Toets conceptaanvraag", | |
| variant="primary", | |
| size="lg", | |
| ) | |
| with gr.Column(scale=4): | |
| gr.Markdown("## 2. Resultaat") | |
| score = gr.Textbox(label="Fit-score", elem_id="scorebox") | |
| eindoordeel = gr.Markdown(label="Eindoordeel") | |
| gr.Markdown( | |
| f""" | |
| <div class="footer-note"> | |
| {MODEL_HINT} | |
| </div> | |
| """ | |
| ) | |
| gr.Markdown("## 3. Toetsrapport") | |
| with gr.Tabs(): | |
| with gr.Tab("Criteria-check"): | |
| criteria_check = gr.Markdown() | |
| with gr.Tab("Verbeterpunten"): | |
| verbeterpunten = gr.Markdown() | |
| with gr.Tab("Risico’s"): | |
| risico = gr.Markdown() | |
| with gr.Tab("Beleidstaal"): | |
| beleidstaal = gr.Markdown() | |
| with gr.Tab("Transparantie"): | |
| transparantie = gr.Markdown() | |
| analyse_btn.click( | |
| fn=analyse_aanvraag, | |
| inputs=[ | |
| regeling_pdf, | |
| regeling_plaktekst, | |
| aanvraag_pdf, | |
| aanvraag_plaktekst, | |
| beleid_pdf, | |
| beleid_plaktekst, | |
| thema, | |
| doelgroep, | |
| gemeente, | |
| ], | |
| outputs=[ | |
| score, | |
| eindoordeel, | |
| criteria_check, | |
| verbeterpunten, | |
| risico, | |
| beleidstaal, | |
| transparantie, | |
| ], | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |