Mistral Large 3 is een multimodaal MoE-model dat is gebouwd om informatie uit complexe visuele documenten te lezen, erover te redeneren en te structureren. In plaats van grafieken en pdf’s als statische afbeeldingen te behandelen, is het ontworpen om tabellen en inzichten te extraheren en er verzorgde verhalen van te maken.
In deze tutorial gebruiken we het Mistral Large 3-model (mistral-large-2512) om in Streamlit een Multimodal Intelligence Evaluation Hub te bouwen. De flow ziet er zo uit:
Je uploadt een input zoals grafieken, financiële overzichten of meerbladige pdf’s.
Mistral leest tekst en cijfers rechtstreeks uit de afbeelding.
Het reconstrueert zichtbare tabellen naar CSV-strings.
Mistral genereert vervolgens inzichten, risico’s en anomalieën op basis van de input.
Tot slot krijg je korte samenvattingen in meerdere talen terug.
Dit alles gebeurt met één model (mistral-large-2512), één endpoint (/v1/chat/completions) en een strikte JSON-schema om outputs gestructureerd en betrouwbaar te houden.
Ik raad aan ons artikel over Mistral 3 te lezen, waarin de belangrijkste features van de nieuwe modellen worden geïntroduceerd. Je kunt ook in een aparte tutorial leren over fine-tunen van Ministral 3.
Wat is Mistral Large 3?
Mistral Large 3 is een sparse mixture-of-experts (MOE)-architectuur met 41B actieve parameters van in totaal 675B en een visie-encoder met 2,5B parameters voor beeldbegrip.
Hier zijn enkele kern eigenschappen die relevant zijn voor dit model:
Multimodaal: Mistral Large 3 verwerkt zowel tekst als afbeeldingen (grafieken, screenshots, documenten).
Lange context (256k tokens): Het is gemaakt voor lange documenten, RAG-pijplijnen en enterprise-workflows.
Agentisch en gestructureerde output: Het ondersteunt function calling en JSON/JSON Schema-output via de chat-API.
Meertalig: Het Large 3-model van Mistral levert sterke prestaties in 40+ talen, niet alleen in het Engels.
De modelkaart en ecosysteemdocs noemen ook enkele belangrijke kanttekeningen:
Het is geen dedicated reasoning-model; er zijn gespecialiseerde reasoning-varianten die het op zware logica kunnen overtreffen.
Het scoort lager dan visiespecifieke modellen op pure visie-taken, dus preprocessing en goede prompts zijn belangrijk.
Voor vision raadt Mistral aan de beeldverhouding dicht bij 1:1 te houden en extreem smalle of brede afbeeldingen te vermijden. Afbeelden croppen helpt dus om de modelprestatie te verbeteren.
Mistral 3 Large voorbeeldproject: Multimodal Intelligence Evaluation Hub
In deze sectie bouwen we een Multimodal Intelligence Evaluation Hub met Mistral Large 3 verpakt in een Streamlit-app. Op hoofdlijnen doet de uiteindelijke app dit:
Accepteert rapportachtige inputs zoals screenshots van grafieken, losse rapportpagina’s of meerbladige pdf’s met tabellen en grafieken.
Zet pdf’s om naar één gestapelde afbeelding, centre-cropt vervolgens naar ongeveer 1:1 beeldverhouding (volgens de visie-aanbeveling van Mistral Large 3), schaalt naar circa 1024×1024 en codeert het resultaat als een base64 data-URL.
Daarna sturen we de instructies van de gebruiker en de afbeelding naar mistral-large-2512, dat response_format in JSON Schema-modus gebruikt om een gestructureerde JSON-payload terug te krijgen.
Tot slot renderen we de JSON als een interactief dashboard met gereconstrueerde tabellen als DataFrames met downloadbare CSV’s, bullet point-inzichten/risico’s/anomalieën, een post die klaar is voor sociale media en meertalige samenvattingen in uitklappers.
Dit verandert een statisch visueel rapport in een interactieve intelligence-assistent die volledig door Mistral Large 3 wordt aangedreven.
Laten we dit stap voor stap bouwen.
Stap 1: Vereisten en setup
Voordat we onze Streamlit-demo bovenop Mistral Large 3 kunnen bouwen, hebben we een basis lokale omgeving nodig om via de Mistral-API met het model te praten. Begin met het installeren van een paar hulplibraries voor de UI, documenten en configuratie.
pip install streamlit mistralai pillow pdf2image pandas python-dotenvMogelijk gemaakt door
We gebruiken de bovenstaande kernlibraries zoals streamlit voor de interactieve webapp-UI, mistralai om met de Mistral-API te praten, pillow en pdf2image om pdf’s te openen en naar afbeeldingen te converteren, pandas om tabeldata of logs te verwerken, en python-dotenv om omgevingsvariabelen zoals MISTRAL_API_KEY veilig uit een .env-bestand te laden.
Log vervolgens in op het Mistral AI Platform en ga naar het tabblad API Keys.
Stel je standaardworkspace in (indien gevraagd) en klik op Create new key.
Geef je sleutel een betekenisvolle naam en stel eventueel een vervaldatum in.
Kopieer tot slot de gegenereerde sleutel en exporteer die als een omgevingsvariabele als volgt:
Op dit punt is onze omgeving klaar om te authenticeren met de Mistral-API.
Stap 2: De Mistral-client initialiseren
Met de omgeving geconfigureerd en de afhankelijkheden geïnstalleerd, is de volgende stap het initialiseren van de Mistral-client die al onze calls naar het Mistral Large 3-model afhandelt. Dit geeft ons een ingang om prompts vanuit onze Streamlit-app naar Mistral Large 3 te sturen.
MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY")
MODEL_ID ="mistral-large-2512"if MISTRAL_API_KEY isNone:raise RuntimeError("Please set the MISTRAL_API_KEY environment variable.")
client = MistralClient(api_key=MISTRAL_API_KEY)Mogelijk gemaakt door
Bovenstaande code doet drie dingen:
Leest de MISTRAL_API_KEY uit onze omgeving en slaat de modelnaam op in MODEL_ID, zodat we die in de hele app kunnen hergebruiken.
Valideert vervolgens dat de API-sleutel is gezet en geeft een duidelijke fout als die ontbreekt.
Maakt ook een MistralClient-instantie met de officiële mistralai-SDK, die we voor elk volgend verzoek naar het model zullen gebruiken.
Met de client geïnitialiseerd bouwen we vervolgens een paar hulpfuncties die prompts sturen en responses afhandelen binnen de Streamlit-UI.
Stap 3: Vision-preprocessing
Voordat we afbeeldingen of pdf’s naar Mistral Large 3 sturen, moeten we ze “modelvriendelijk” maken. De Vision-API presteert het best wanneer inputs vierkant, redelijk van grootte en in een consistent formaat zijn gecodeerd.
Stap 3.1: Centre-crop
We beginnen met het laden van de geüploade afbeelding en zetten die om naar een vierkante uitsnede.
De bovenstaande code zorgt ervoor dat geüploade grafieken of tabellen worden omgezet naar een vierkante uitsnede voordat ze naar het model gaan, in lijn met Mistrals vision-richtlijnen.
Stap 3.2: Resizen
Vervolgens schalen we de afbeelding naar een maximumformaat (1024×1024) om kwaliteit, latentie en tokencost in balans te houden.
Hier berekenen we een scale-factor die beide afmetingen onder max_size houdt met behoud van de beeldverhouding. Als de afbeelding al klein genoeg is, geven we die ongewijzigd terug. Anders berekenen we de nieuwe dimensies en gebruiken we LANCZOS-resampling voor hoge kwaliteit bij verkleinen.
Deze stap zorgt ervoor dat afbeeldingen je contextwindow niet opblazen of reacties onnodig vertragen.
Stap 3.3: Pdf’s naar gestapelde afbeelding
Voor pdf’s willen we het model vaak meer dan één pagina laten zien. Een simpele truc is om alle pagina’s te renderen en ze verticaal tot één lange afbeelding te stapelen.
De functie stack_images_vertically() neemt een lijst met PIL-afbeeldingen, normaliseert ze naar een gemeenschappelijke breedte met behoud van de beeldverhouding, berekent de totale hoogte en plakt ze onder elkaar op één RGB-canvas. Terwijl de uploaded_file_to_square_base64()-functie vervolgens beslist wat te doen op basis van het MIME-type:
Voor pdf’s: converteert elke pagina naar een afbeelding, stapelt ze verticaal en verkleint het resultaat.
Voor reguliere afbeeldingen: laadt de afbeelding, centre-cropt naar vierkant en verkleint.
In beide gevallen geeft het een genormaliseerde afbeelding terug met een MIME-type voor de laatste encodestap.
Stap 3.4: Encoden naar base64
De Vision-API van Mistral accepteert afbeeldingen als image_url-objecten, die ofwel echte URL’s of data:-URL’s kunnen zijn.
defimage_to_base64_data_url(img: Image.Image, mime_type:str="image/png")->str:buffer= io.BytesIO()if mime_type =="image/jpeg":
img.save(buffer,format="JPEG", quality=90)else:
img.save(buffer,format="PNG")
mime_type ="image/png"
b64 = base64.b64encode(buffer.getvalue()).decode("utf-8")returnf"data:{mime_type};base64,{b64}"Mogelijk gemaakt door
We beginnen met het schrijven van de afbeelding naar een in-memory buffer en kiezen een geschikt formaat (zoals JPEG of PNG), waarna we de bytes base64-encoden.
Tot slot wikkelen we de gecodeerde string in een data:{mime_type};base64-URL die direct als image_url aan de Mistral Vision-API kan worden doorgegeven.
Aan het einde van deze stap doorlopen alle uploads, of het nu een enkele PNG, een brede dashboardafbeelding of een meerbladige pdf is, dezelfde pijplijn van centre-crop, resizen, pdf-stapelen en conversie naar een base64 data-URL.
Stap 4: Multimodale inference-call
In deze stap wikkelen we alles in één hulpfunctie die een request met visie plus tekst verstuurt en het model dwingt in JSON-formaat te antwoorden. Dat doen we door te combineren:
Een systeemprompt die de rol van het model definieert als een Multimodal Intelligence Evaluator,
Een gebruikersbericht dat instructies mengt met de afbeeldingsinhoud, en
Een JSON-schema dat wordt meegegeven via response_format zodat de output gestructureerd en makkelijk te parsen is.
defcall_mistral_large_multimodal(
mime_type:str,
image_data_url:str,
user_instruction:str,
languages: List[str],)-> Dict[str, Any]:
json_schema ={"type":"object","properties":{"csv_tables":{"type":"array","items":{"type":"string"},"description":"Each item is a CSV string representing one table found in the image."},"insights":{"type":"array","items":{"type":"string"},"description":"Up to 5 key insights about the content."},"risks":{"type":"array","items":{"type":"string"},"description":"Up to 5 key risks or red flags."},"anomalies":{"type":"array","items":{"type":"string"},"description":"Any anomalies, outliers, or surprising patterns you detect."},"translations":{"type":"object","properties":{
lang:{"type":"string"}for lang in languages
},"description":"Short high-level summaries in the selected languages."},},"required":["csv_tables","insights","risks"],"additionalProperties":False,}
system_prompt =("You are a Multimodal Intelligence Evaluator using Mistral Large 3.\n""You are given a single document-like image (e.g. chart + table, financial report page).\n\n""Your tasks:\n""1. Read all visible text and numbers directly from the image.\n""2. Reconstruct any clearly visible tables into valid CSV strings.\n"" - Use the first row as headers when possible.\n"" - Use commas as separators and newline per row.\n""3. Derive up to 5 concise INSIGHTS about trends, patterns, or takeaways.\n""4. Derive up to 5 concise RISKS or red flags (business, financial, operational, etc.).\n""5. Detect any anomalies or surprising patterns if present (else return an empty list).\n""6. Provide short summaries in the requested languages.\n\n""You MUST respond ONLY with a JSON object that matches the provided JSON schema.\n""Do not include any extra commentary outside of the JSON.")
messages =[{"role":"system","content":[{"type":"text","text": system_prompt},],},{"role":"user","content":[{"type":"text","text": user_instruction or"Analyze this financial report page.",},{"type":"image_url","image_url": image_data_url,},],},]
response = client.chat(
model=MODEL_ID,
messages=messages,
temperature=0.2,
max_tokens=2048,
response_format={"type":"json_schema","json_schema":{"name":"multimodal_intel_eval","schema": json_schema,"strict":True,},},)
content = response.choices[0].message.content
try:
parsed = json.loads(content)except json.JSONDecodeError:try:
start = content.index("{")
end = content.rindex("}")+1
parsed = json.loads(content[start:end])except Exception:raise ValueError(f"Model did not return valid JSON. Raw content:\n{content}")return parsedMogelijk gemaakt door
De functie call_mistral_large_multimodal() vormt de kernmotor van de multimodale intelligence-demo.
De functie bouwt eerst een JSON-schema dat arrays definieert voor csv_tables, insights, risks, anomalies en een translations-object met keys afgeleid van de languages-lijst.
We definiëren ook een gedetailleerde systeemprompt die het model positioneert als een Multimodal Intelligence Evaluator en het door de taken leidt van cijfers lezen, tabellen als CSV reconstrueren, inzichten, risico’s, anomalieën en meertalige samenvattingen extraheren.
De functie call_mistral_large_multimodal() construeert daarna de berichtenarray in chatformaat door de systeeminstructies te combineren met een gebruikersbericht dat zowel tekstinstructies als de image_url-payload bevat. Hij roept client.chat() aan met MODEL_ID met een lage temperatuur voor deterministische output, en response_format={"type": "json_schema",}, zodat de respons aan het schema voldoet. Tot slot proberen we te parsen met json.loads.
Met dit in place heb je nu een robuuste ingang om een ruwe grafiek- of rapportafbeelding om te zetten in een gestructureerd verhaal.
Stap 5: De Streamlit-UI bouwen
Met de preprocessing-pijplijn en de Mistral-client op hun plaats is de laatste stap om alles in een Streamlit-interface te gieten.
st.set_page_config(
page_title="Multimodal Intelligence Evaluation Hub - Mistral Large 3",
layout="wide",)
st.title("Multimodal Intelligence Evaluation Hub")
st.caption("Powered by **Mistral Large 3**")
col_left, col_right = st.columns([2,1])with col_left:
uploaded_file = st.file_uploader("Upload an image or report (PNG, JPG, WEBP, or PDF)",type=["png","jpg","jpeg","webp","pdf"],)
default_prompt =("Give me 3–5 key insights and risks from this input and export any tables you see as CSV ""Also write down the findings for a professional audience.")
user_instruction = st.text_area("Instruction to Mistral Large 3",
value=default_prompt,
height=120,)with col_right:
st.subheader("Multilingual Options")
languages = st.multiselect("Additional summary languages",
options=["fr","de","es","hi","zh","ja"],
default=["hi"],help="Mistral Large 3 supports dozens of languages; these will receive short summaries.",
label_visibility="collapsed",)
run_button = st.button("Run Analysis",type="primary")if run_button:if uploaded_file isNone:
st.error("Please upload an image or PDF first.")
st.stop()
prep_msg ="Preparing PDF (combining all pages)..."if uploaded_file.type=="application/pdf"else"Preparing image..."with st.spinner(prep_msg):
mime_type, data_url = uploaded_file_to_square_base64(uploaded_file)
mime, b64_part = data_url.split(",",1)
img_bytes = base64.b64decode(b64_part)
st.image(img_bytes, caption="Center-cropped & resized image for the model", width=400)with st.spinner("Processing..."):try:
result = call_mistral_large_multimodal(
mime_type=mime_type,
image_data_url=data_url,
user_instruction=user_instruction,
languages=languages,)except Exception as e:
st.error(f"Error calling Mistral Large 3: {e}")
st.stop()
st.header("Results")
csv_tables = result.get("csv_tables",[])if csv_tables:
st.subheader("Reconstructed Tables (CSV)")for i, csv_str inenumerate(csv_tables):
st.markdown(f"**Table {i+1}**")try:
df = pd.read_csv(io.StringIO(csv_str))
st.dataframe(df, use_container_width=True)except Exception:
st.text_area(f"Raw CSV for Table {i+1}", value=csv_str, height=150)
st.download_button(
label=f"Download Table {i+1} as CSV",
data=csv_str,
file_name=f"table_{i+1}.csv",
mime="text/csv",
key=f"csv_download_{i}",)else:
st.info("No tables were detected or reconstructed.")
insights = result.get("insights",[])
risks = result.get("risks",[])
anomalies = result.get("anomalies",[])
col_ins, col_risk = st.columns(2)with col_ins:
st.subheader("Key Insights")if insights:for bullet in insights:
st.markdown(f"- {bullet}")else:
st.write("_No explicit insights returned._")with col_risk:
st.subheader("Risks")if risks:for bullet in risks:
st.markdown(f"- {bullet}")else:
st.write("_No explicit risks returned._")
st.subheader("Anomalies")if anomalies:for bullet in anomalies:
st.markdown(f"- {bullet}")else:
st.write("_No anomalies reported._")
translations = result.get("translations",{})or{}if translations:
st.subheader(" Multilingual Summaries")for lang_code, summary in translations.items():with st.expander(f"Summary in {lang_code}"):
st.write(summary)else:
st.info("No multilingual summaries were requested or returned.")# Raw JSON (debug)# with st.expander(" Raw JSON (debug)"):# st.json(result)Mogelijk gemaakt door
De bovenstaande Streamlit-UI-code doet een paar belangrijke dingen:
De methode st.set_page_config splitst de layout in twee kolommen. De linkerkant behandelt de kerninputs (bestandenuploader en een bewerkbaar tekstveld met standaardinstructies). De rechterkant biedt meertalige opties via st.multiselect en een primaire Run Analysis-knop. Wanneer op de knop wordt geklikt, valideert de app dat er een bestand is, zet afbeeldingen of pdf’s om naar een base64 data-URL en toont de voorbeeldafbeelding.
Zodra er een resultaat terugkomt, worden de gereconstrueerde CSV-tabellen als dataframes weergegeven, samen met inzichten, risico’s, anomalieën en eventuele meertalige samenvattingen. Optioneel hebben we ook debugweergaven (uitgecommentarieerd) waarmee we tijdens ontwikkeling de ruwe JSON kunnen inspecteren.
Met deze stap voltooid kun je alles opslaan als app.py en de volledige ervaring starten met:
In de onderstaande video zie je een beknopte versie van de workflow in actie met zowel afbeelding- als pdf-inputs:
Conclusie
In deze tutorial hebben we Mistral Large 3 omgevormd van een algemeen multimodaal model tot een gefocuste visuele intelligence-assistent. Met een beetje vision-preprocessing, een strikt JSON-schema en een Streamlit-UI bouwden we een hub die statische grafieken en pdf’s kan omzetten in gestructureerde tabellen, inzichten, risico’s, anomalieën en meertalige samenvattingen.
Hoewel de demo is gericht op grafieken en pdf’s, geldt hetzelfde patroon voor facturen, bonnetjes, wetenschappelijke artikelen, kwartaalcijfers en andere visuele documenten met hoge informatiedichtheid.
Vanaf hier kun je de hub uitbreiden met tekst- en visanalyse, trendsamenvattingen over documenten heen, of hem inpluggen in een grotere RAG. Met een paar extra tools en prompts kun je dit omvormen tot een volledig agentisch rapportagesysteem.
Als je graag verder leert, raad ik deze resources aan:
Waarom gebruik je niet Mistral’s Document AI-/OCR-stack?⌄
De officiële documentatie raadt gespecialiseerde Document AI-modellen aan voor OCR-intensieve workloads, maar hier hebben we het general-purpose Mistral Large 3-model bewust end-to-end stresstests gegeven.
Waarom crop je naar een 1:1-beeldverhouding?⌄
De documentatie van Mistral Large 3 en communityreviews geven aan dat de visie-encoder het best presteert op grofweg vierkante afbeeldingen, en moeite kan hebben met extreem smalle of brede beeldverhoudingen. Croppen naar 1:1 en resizen is een effectieve preprocessing-stap om de consistentie te verbeteren.
Kan ik later een ander model vervangen?⌄
Ja. De architectuur is model-agnostisch zolang het model ondersteunt:
Afbeeldingsinput (image_url)
JSON- of JSON Schema-output
Genoeg context om verschillende documentgroottes aan te kunnen
Je kunt andere multimodale modellen met OpenAI-compatibele API’s met minimale wijzigingen inpluggen.
Hoe groot mogen mijn pdf’s of afbeeldingen zijn?⌄
Praktisch gezien wordt de grootte van de afbeelding of pdf beperkt door:
Het contextvenster van het model (tot 256k tokens)
Afbeeldingsresolutie en -kwaliteit vs. tokencost
Prestaties van Streamlit en pdf2image
Voor zeer grote documenten kun je overwegen:
Beperken tot kernpagina’s
Opsplitsen in stukken en meerdere passes draaien
Tekstgebaseerde OCR combineren met Mistral voor redeneren (indien nodig)
Ik ben een Google Developers Expert in ML (Gen AI), een Kaggle 3x Expert en een Women Techmakers Ambassador met meer dan 3 jaar ervaring in tech. In 2020 heb ik een healthtech-startup mee opgericht en ik volg een master computer science aan Georgia Tech, met als specialisatie machine learning.
Mistral Large 3 is een multimodaal MoE-model dat is gebouwd om informatie uit complexe visuele documenten te lezen, erover te redeneren en te structureren. In plaats van grafieken en pdf’s als statische afbeeldingen te behandelen, is het ontworpen om tabellen en inzichten te extraheren en er verzorgde verhalen van te maken.
In deze tutorial gebruiken we het Mistral Large 3-model (
mistral-large-2512) om in Streamlit een Multimodal Intelligence Evaluation Hub te bouwen. De flow ziet er zo uit:Dit alles gebeurt met één model (
mistral-large-2512), één endpoint (/v1/chat/completions) en een strikte JSON-schema om outputs gestructureerd en betrouwbaar te houden.Ik raad aan ons artikel over Mistral 3 te lezen, waarin de belangrijkste features van de nieuwe modellen worden geïntroduceerd. Je kunt ook in een aparte tutorial leren over fine-tunen van Ministral 3.
Wat is Mistral Large 3?
Mistral Large 3 is een sparse mixture-of-experts (MOE)-architectuur met 41B actieve parameters van in totaal 675B en een visie-encoder met 2,5B parameters voor beeldbegrip.
Hier zijn enkele kern eigenschappen die relevant zijn voor dit model:
De modelkaart en ecosysteemdocs noemen ook enkele belangrijke kanttekeningen:
Mistral 3 Large voorbeeldproject: Multimodal Intelligence Evaluation Hub
In deze sectie bouwen we een Multimodal Intelligence Evaluation Hub met Mistral Large 3 verpakt in een Streamlit-app. Op hoofdlijnen doet de uiteindelijke app dit:
mistral-large-2512, datresponse_formatin JSON Schema-modus gebruikt om een gestructureerde JSON-payload terug te krijgen.Dit verandert een statisch visueel rapport in een interactieve intelligence-assistent die volledig door Mistral Large 3 wordt aangedreven.
Laten we dit stap voor stap bouwen.
Stap 1: Vereisten en setup
Voordat we onze Streamlit-demo bovenop Mistral Large 3 kunnen bouwen, hebben we een basis lokale omgeving nodig om via de Mistral-API met het model te praten. Begin met het installeren van een paar hulplibraries voor de UI, documenten en configuratie.
We gebruiken de bovenstaande kernlibraries zoals streamlit voor de interactieve webapp-UI, mistralai om met de Mistral-API te praten, pillow en pdf2image om pdf’s te openen en naar afbeeldingen te converteren, pandas om tabeldata of logs te verwerken, en python-dotenv om omgevingsvariabelen zoals
MISTRAL_API_KEYveilig uit een.env-bestand te laden.Log vervolgens in op het Mistral AI Platform en ga naar het tabblad API Keys.
Stel je standaardworkspace in (indien gevraagd) en klik op Create new key.
Geef je sleutel een betekenisvolle naam en stel eventueel een vervaldatum in.
Kopieer tot slot de gegenereerde sleutel en exporteer die als een omgevingsvariabele als volgt:
Op dit punt is onze omgeving klaar om te authenticeren met de Mistral-API.
Stap 2: De Mistral-client initialiseren
Met de omgeving geconfigureerd en de afhankelijkheden geïnstalleerd, is de volgende stap het initialiseren van de Mistral-client die al onze calls naar het Mistral Large 3-model afhandelt. Dit geeft ons een ingang om prompts vanuit onze Streamlit-app naar Mistral Large 3 te sturen.
Bovenstaande code doet drie dingen:
MISTRAL_API_KEYuit onze omgeving en slaat de modelnaam op inMODEL_ID, zodat we die in de hele app kunnen hergebruiken.MistralClient-instantie met de officiëlemistralai-SDK, die we voor elk volgend verzoek naar het model zullen gebruiken.Met de client geïnitialiseerd bouwen we vervolgens een paar hulpfuncties die prompts sturen en responses afhandelen binnen de Streamlit-UI.
Stap 3: Vision-preprocessing
Voordat we afbeeldingen of pdf’s naar Mistral Large 3 sturen, moeten we ze “modelvriendelijk” maken. De Vision-API presteert het best wanneer inputs vierkant, redelijk van grootte en in een consistent formaat zijn gecodeerd.
Stap 3.1: Centre-crop
We beginnen met het laden van de geüploade afbeelding en zetten die om naar een vierkante uitsnede.
De bovenstaande code zorgt ervoor dat geüploade grafieken of tabellen worden omgezet naar een vierkante uitsnede voordat ze naar het model gaan, in lijn met Mistrals vision-richtlijnen.
Stap 3.2: Resizen
Vervolgens schalen we de afbeelding naar een maximumformaat (1024×1024) om kwaliteit, latentie en tokencost in balans te houden.
Hier berekenen we een
scale-factor die beide afmetingen ondermax_sizehoudt met behoud van de beeldverhouding. Als de afbeelding al klein genoeg is, geven we die ongewijzigd terug. Anders berekenen we de nieuwe dimensies en gebruiken we LANCZOS-resampling voor hoge kwaliteit bij verkleinen.Deze stap zorgt ervoor dat afbeeldingen je contextwindow niet opblazen of reacties onnodig vertragen.
Stap 3.3: Pdf’s naar gestapelde afbeelding
Voor pdf’s willen we het model vaak meer dan één pagina laten zien. Een simpele truc is om alle pagina’s te renderen en ze verticaal tot één lange afbeelding te stapelen.
De functie
stack_images_vertically()neemt een lijst met PIL-afbeeldingen, normaliseert ze naar een gemeenschappelijke breedte met behoud van de beeldverhouding, berekent de totale hoogte en plakt ze onder elkaar op één RGB-canvas. Terwijl deuploaded_file_to_square_base64()-functie vervolgens beslist wat te doen op basis van het MIME-type:In beide gevallen geeft het een genormaliseerde afbeelding terug met een MIME-type voor de laatste encodestap.
Stap 3.4: Encoden naar base64
De Vision-API van Mistral accepteert afbeeldingen als
image_url-objecten, die ofwel echte URL’s ofdata:-URL’s kunnen zijn.We beginnen met het schrijven van de afbeelding naar een in-memory buffer en kiezen een geschikt formaat (zoals JPEG of PNG), waarna we de bytes base64-encoden.
Tot slot wikkelen we de gecodeerde string in een
data:{mime_type};base64-URL die direct alsimage_urlaan de Mistral Vision-API kan worden doorgegeven.Aan het einde van deze stap doorlopen alle uploads, of het nu een enkele PNG, een brede dashboardafbeelding of een meerbladige pdf is, dezelfde pijplijn van centre-crop, resizen, pdf-stapelen en conversie naar een base64 data-URL.
Stap 4: Multimodale inference-call
In deze stap wikkelen we alles in één hulpfunctie die een request met visie plus tekst verstuurt en het model dwingt in JSON-formaat te antwoorden. Dat doen we door te combineren:
response_formatzodat de output gestructureerd en makkelijk te parsen is.De functie
call_mistral_large_multimodal()vormt de kernmotor van de multimodale intelligence-demo.csv_tables,insights,risks,anomaliesen eentranslations-object met keys afgeleid van delanguages-lijst.call_mistral_large_multimodal()construeert daarna de berichtenarray in chatformaat door de systeeminstructies te combineren met een gebruikersbericht dat zowel tekstinstructies als deimage_url-payload bevat. Hij roeptclient.chat()aan metMODEL_IDmet een lage temperatuur voor deterministische output, enresponse_format={"type": "json_schema",}, zodat de respons aan het schema voldoet. Tot slot proberen we te parsen metjson.loads.Met dit in place heb je nu een robuuste ingang om een ruwe grafiek- of rapportafbeelding om te zetten in een gestructureerd verhaal.
Stap 5: De Streamlit-UI bouwen
Met de preprocessing-pijplijn en de Mistral-client op hun plaats is de laatste stap om alles in een Streamlit-interface te gieten.
De bovenstaande Streamlit-UI-code doet een paar belangrijke dingen:
De methode
st.set_page_configsplitst de layout in twee kolommen. De linkerkant behandelt de kerninputs (bestandenuploader en een bewerkbaar tekstveld met standaardinstructies). De rechterkant biedt meertalige opties viast.multiselecten een primaire Run Analysis-knop. Wanneer op de knop wordt geklikt, valideert de app dat er een bestand is, zet afbeeldingen of pdf’s om naar een base64 data-URL en toont de voorbeeldafbeelding.Zodra er een resultaat terugkomt, worden de gereconstrueerde CSV-tabellen als dataframes weergegeven, samen met inzichten, risico’s, anomalieën en eventuele meertalige samenvattingen. Optioneel hebben we ook debugweergaven (uitgecommentarieerd) waarmee we tijdens ontwikkeling de ruwe JSON kunnen inspecteren.
Met deze stap voltooid kun je alles opslaan als
app.pyen de volledige ervaring starten met:In de onderstaande video zie je een beknopte versie van de workflow in actie met zowel afbeelding- als pdf-inputs: