<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matheus Ferreira</title>
    <description>The latest articles on DEV Community by Matheus Ferreira (@mathfe).</description>
    <link>https://dev.to/mathfe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4158690%2Faf2e39b2-2132-4226-84e2-737988a8ecc7.jpg</url>
      <title>DEV Community: Matheus Ferreira</title>
      <link>https://dev.to/mathfe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mathfe"/>
    <language>en</language>
    <item>
      <title>Papel Claro: a local Gemma that explains my grandmother's bank letters in plain Portuguese</title>
      <dc:creator>Matheus Ferreira</dc:creator>
      <pubDate>Mon, 05 Oct 2026 00:02:41 +0000</pubDate>
      <link>https://dev.to/mathfe/papel-claro-a-local-gemma-that-explains-my-grandmothers-bank-letters-in-plain-portuguese-1l63</link>
      <guid>https://dev.to/mathfe/papel-claro-a-local-gemma-that-explains-my-grandmothers-bank-letters-in-plain-portuguese-1l63</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/devteam/join-the-hacktoberfest-weekend-challenge-build-for-a-friend-2450-in-prizes-across-17-winners-1aj5"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;My grandmother gets letters from her bank that she cannot make sense of. It is not one letter, it keeps happening. Each time she does one of three things: she ignores it, she pays without understanding what she is paying for, or she asks someone to read it to her.&lt;/p&gt;

&lt;p&gt;A regular chatbot was never going to help. She does not know how to use one, she does not trust them, and she is afraid of exposing her data on the internet.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Papel Claro&lt;/strong&gt; ("clear paper") for her. You paste the text of a difficult document, or take a photo of it, and it answers the questions a person actually has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is this?&lt;/strong&gt; The type of document and a summary in two to four short sentences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What do I have to do?&lt;/strong&gt; A numbered list of actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;By when, and how much?&lt;/strong&gt; Dates and amounts, copied as they are written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What should I watch out for?&lt;/strong&gt; Fines, interest, a name sent to a credit bureau.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What do these words mean?&lt;/strong&gt; A small glossary of the hard words in the document.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that you can ask follow-up questions ("can I pay this in instalments?"), and the app answers only from the document. If the document does not say, it tells you so. There is also a button that reads the explanation aloud.&lt;/p&gt;

&lt;p&gt;Brazilian contracts and bank letters are written in &lt;em&gt;juridiquês&lt;/em&gt;, a dialect of Portuguese that seems designed to be read by lawyers only. A sentence like "o não pagamento poderá ensejar o vencimento antecipado das parcelas vincendas" means "if you do not pay, the bank can demand all the remaining instalments at once". Nobody should need a lawyer to learn that.&lt;/p&gt;

&lt;p&gt;Her fear about her data is reasonable. These letters carry a full name, an address, a CPF (the Brazilian tax ID) and the exact size of a debt. That is the last text I want my grandmother to paste into a website. So the model runs on a computer at home, and she opens the page on her phone over the home Wi-Fi. The document never leaves the house.&lt;/p&gt;

&lt;p&gt;She has already used it that way, and she thought it was wonderful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/YcdQQh9F-SI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The app runs locally, so there is no hosted link. The video shows it running on my own computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/MathFe" rel="noopener noreferrer"&gt;
        MathFe
      &lt;/a&gt; / &lt;a href="https://github.com/MathFe/papel-claro" rel="noopener noreferrer"&gt;
        papel-claro
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Explains difficult documents in plain Brazilian Portuguese, running Gemma locally through Ollama.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Papel Claro&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Paste a confusing document, or take a photo of it, and get it explained in plain Brazilian Portuguese.&lt;/strong&gt;
Everything runs on your own computer with &lt;a href="https://ai.google.dev/gemma" rel="nofollow noopener noreferrer"&gt;Gemma&lt;/a&gt; through &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt;. The document never leaves the machine.&lt;/p&gt;
&lt;p&gt;Built for the DEV &lt;a href="https://dev.to/devteam/join-the-hacktoberfest-weekend-challenge-build-for-a-friend-2450-in-prizes-across-17-winners-1aj5" rel="nofollow"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Bank letters, rental contracts, collection notices and official notifications in Brazil are written in dense legal Portuguese ("juridiquês"). Papel Claro reads the document and answers the questions a person actually has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is this?&lt;/strong&gt; The type of document and a summary in two to four short sentences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What do I have to do?&lt;/strong&gt; A numbered list of actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;By when, and how much?&lt;/strong&gt; Dates and amounts, copied exactly as they appear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What should I watch out for?&lt;/strong&gt; Fines, interest, automatic renewal, and common signs of a scam.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What do these words mean?&lt;/strong&gt; A small glossary of the hard…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/MathFe/papel-claro" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed. To run it you need Java 17 or newer and &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma3:4b
./mvnw spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;code&gt;http://localhost:8080&lt;/code&gt;, or &lt;code&gt;http://&amp;lt;computer-ip&amp;gt;:8080&lt;/code&gt; from a phone on the same Wi-Fi.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser  -&amp;gt;  Spring Boot  -&amp;gt;  Spring AI ChatClient  -&amp;gt;  Ollama  -&amp;gt;  Gemma 3 (4B)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stack is deliberately boring: Java, Spring Boot 4.1, Spring AI 2.0, and a page in plain HTML, CSS and JavaScript. There is no database, because there is nothing to keep.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One model does everything.&lt;/strong&gt; &lt;code&gt;gemma3:4b&lt;/code&gt; reads images as well as text, so a photo of a letter goes straight to the model. There is no separate OCR step, no second model, and no extra service to install. The same model writes the summary, extracts dates and amounts, and answers the follow-up questions. It is a 3.3 GB download, and on my machine (an AMD RX 9060 XT and 16 GB of RAM) an explanation takes 6 to 10 seconds and a follow-up answer 1 to 3 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The answer is a Java record, not a blob of text.&lt;/strong&gt; Spring AI asks the model for JSON and maps it onto records, so the screen can show actions, dates and amounts in separate blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;EXPLAIN_TEMPLATE&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;param&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"document"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;documentText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;attachImage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;})&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DocumentExplanation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The document goes in as a template parameter, so a contract full of &lt;code&gt;{braces}&lt;/code&gt; is never read as template syntax.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What a real run taught me.&lt;/strong&gt; The first version was written against the documentation and had never been compiled. The first time it ran against a real model, four things came up that no documentation would have told me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A closed Ollama froze the page for minutes.&lt;/strong&gt; Spring AI retries failed calls up to ten times with a growing wait. For a developer that is resilience. For my grandmother, tapping a button on her phone while Ollama happens to be closed on the computer, it is a screen that never answers. With a single retry attempt, the page now says "open Ollama and try again" in about two seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A log line broke the privacy promise.&lt;/strong&gt; When the model returned JSON in the wrong shape, the exception message quoted the offending value, and that value was a sentence from the document. The code was logging that message. Now the log records only the kind of failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An empty answer looked like success.&lt;/strong&gt; A small model sometimes returns JSON with none of the expected fields. The records filled in defaults and the screen showed an empty explanation. That now counts as a failure and triggers a second try.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The prompt was putting ideas in the model's head.&lt;/strong&gt; The system prompt listed signs of a scam: requests for a password, PIX to a private person, strange links. The 4B model started warning about PIX in documents that never mentioned it. A list of examples is a list of suggestions to a small model. The rule now says "only mention a scam if the document itself shows one of these signs", and each field is told what to copy and from where. The invented warnings stopped.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last one is the main thing I learned about prompting a 4B model: be literal, say where each value comes from, and never offer an example you would not want to see in the output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honest limits.&lt;/strong&gt; A 4B model is not a lawyer, and the app says so on every result.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A photo of a full page in small print is not reliable.&lt;/strong&gt; In testing, a photo of a whole A4 page produced an amount that was not in the document. A close-up of one paragraph was read correctly. So the advice is: photograph the part you want to understand, from close.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The glossary can be wrong.&lt;/strong&gt; It explained "pro rata die" incorrectly every time. Dates and amounts come from the document; definitions come from the model's memory, and that is the weaker part.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text is limited to 16,000 characters&lt;/strong&gt;, which fits the 8,192-token context with room for the answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because of who this is for.&lt;/p&gt;

&lt;p&gt;With a hosted model, helping my grandmother would mean sending a document with her name, address, CPF and debt to a company, under terms neither of us would read. I would be solving one unreadable contract by agreeing to another. It would also be the exact thing she is afraid of. With an open-weight model on a computer at home, the document travels from her phone to that computer over the home Wi-Fi and nowhere else. The app has no database, keeps nothing once the request is answered, and does not log document content.&lt;/p&gt;

&lt;p&gt;Open weights also make this something I can give away. There is no API key to pay for, no account to create, no usage limit, and it keeps working without internet once the model is downloaded. My grandmother does not depend on me keeping a subscription alive, or on a company deciding to keep a product running.&lt;/p&gt;

&lt;p&gt;And it can be checked. The prompts are in the repository, in Portuguese, next to the code. If the explanation is wrong, anyone can see exactly what the model was asked. For a tool that tells people what a legal document means, I think that matters more than it does for most software.&lt;/p&gt;

&lt;p&gt;None of the pieces here are mine: Gemma, Ollama, Spring AI and Spring Boot are all open. My part was choosing the problem and spending a weekend getting them to work together for one person. That is the point of open innovation for me. The distance between "someone I love has a problem" and "here is a tool for it" has become short enough to cover in a weekend.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I did not build this alone, and I would rather say so plainly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First version.&lt;/strong&gt; I chose the stack (Java, Spring Boot, a local Gemma) and the problem to solve. Claude wrote the first version of the code in the Claude desktop app while I followed along and it explained each decision. That session could not reach Maven Central, so the code was written against the Spring AI 2.0 documentation and had never been compiled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review.&lt;/strong&gt; Before submitting, I asked Claude Code to review the project on my machine. It ran the first real build, downloaded the model, called the app with text and photo documents, and found the four problems described above, plus the photo limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This article&lt;/strong&gt; was drafted with Claude too. Everything in it about my grandmother is mine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Gemma.&lt;/strong&gt; Gemma is the whole product, not a feature of it. A single &lt;code&gt;gemma3:4b&lt;/code&gt;, running locally through Ollama, does three jobs: it reads the photo of the document, it turns legal Portuguese into structured plain-language output, and it answers follow-up questions grounded in that document. Its size is what makes the privacy argument real: it is small enough to run on an ordinary home computer, so the document never has to leave the house.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
    </item>
  </channel>
</rss>
