<?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: Liang Jacky</title>
    <description>The latest articles on DEV Community by Liang Jacky (@liangjacky8921).</description>
    <link>https://dev.to/liangjacky8921</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%2F4179095%2F6bfcef86-7023-429d-b27d-5b2e71a41c01.jpg</url>
      <title>DEV Community: Liang Jacky</title>
      <link>https://dev.to/liangjacky8921</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/liangjacky8921"/>
    <language>en</language>
    <item>
      <title>From Satellite Pixels to Farmer Decisions: What Building FieldLens Taught Me</title>
      <dc:creator>Liang Jacky</dc:creator>
      <pubDate>Tue, 27 Oct 2026 09:05:55 +0000</pubDate>
      <link>https://dev.to/liangjacky8921/from-satellite-pixels-to-farmer-decisions-what-building-fieldlens-taught-me-42a1</link>
      <guid>https://dev.to/liangjacky8921/from-satellite-pixels-to-farmer-decisions-what-building-fieldlens-taught-me-42a1</guid>
      <description>&lt;p&gt;This post is part of the Monthly MLH × DEV Writing Challenge — a look back at what I built, how I built it, and what I'd do differently.&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://dev.to/mlh-hackathon"&gt;Monthly MLH × DEV Writing Challenge&lt;/a&gt; — a look back at what I built, how I built it, and what I'd do differently.*&lt;/p&gt;

&lt;p&gt;The problem nobody asked me to solve&lt;/p&gt;

&lt;p&gt;I grew up around pomelo orchards in Meizhou, Guangdong. Every year, growers there make the same high-stakes guesses: which blocks are underperforming, where to fertilize, whether the irrigation is actually reaching the trees. Satellite data could answer all of this — Sentinel-2 flies over every five days, free for anyone to use. But "free data" and "usable answers" are very different things. No grower I know is going to open Google Earth Engine and write JavaScript.&lt;/p&gt;

&lt;p&gt;There's a part of this origin story I didn't tell in my submission post. In July, I joined the fieldwork for a Guangdong provincial research project — a Natural Science Foundation–funded study of farmland protection, including the "farmland chief" system （田长制）, led by a South China University of Technology team. For a week I walked villages in Fengshun and Jiaoling doing door-to-door farmer interviews and organizing the survey data.&lt;/p&gt;

&lt;p&gt;The farmland chief system is simple to describe and exhausting to run: named local officials are personally responsible for watching specific plots — walking them on foot, checking that nothing illegal gets built and nothing is abandoned. Sitting in farmers' homes, working through a 29-question survey on how this system actually runs, I kept coming back to the same thought: the whole oversight system runs on human legs and human eyes, a few times a month if that. A satellite passes over those same fields every five days, for free.&lt;/p&gt;

&lt;p&gt;And one farmland chief （田长） said the quiet part out loud. He wasn't asking for software — he was just tired of the work. If there were automatic monitoring, he told me, he wouldn't have to go out and check the fields under a blazing sun or in the wind and rain.&lt;/p&gt;

&lt;p&gt;That week is where FieldLens really started: the very person whose job is walking the fields, naming the pain in plain words — and me realising the data that could answer it was already falling from the sky, for free.&lt;/p&gt;

&lt;p&gt;So for Hacktoberfest Week 2 ("Side Hustle"), I built "FieldLens": draw your orchard on a map, get a vigor report that reads like advice from an agronomist, not a data dump. NDVI time series go in; plain-language actions come out — in Chinese for the growers, in English under the hood.&lt;/p&gt;

&lt;p&gt;🎥 Live demo: &lt;a href="https://fieldlens-api.onrender.com/app" rel="noopener noreferrer"&gt;https://fieldlens-api.onrender.com/app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How it works (the honest version)&lt;/p&gt;

&lt;p&gt;The pipeline is deliberately boring where it should be, and interesting where it matters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Draw a polygon on the map (or use the sample orchard — more on that below).&lt;/li&gt;
&lt;li&gt;Sentinel-2 NDVI time series pulled through Google Earth Engine, composited into vigor zones across the block.&lt;/li&gt;
&lt;li&gt;A local Gemma model via Ollama writes the advisory report. This was a deliberate choice, not a gimmick: grower data never leaves the machine, there's no per-report API bill, and it works where connectivity is flaky. The report takes a &lt;code&gt;lang&lt;/code&gt; parameter — Chinese for the actual farmer reading it, English for the code comments and the DEV crowd.&lt;/li&gt;
&lt;li&gt;A 199 RMB/plot/year pricing story, because the Week 2 theme was "build something someone would actually pay for." I priced it like a utility bill, not a SaaS moonshot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two decisions I'm proudest of are both about honesty with data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;During research I found that NDVI ≥ 0.70 is a drone canopy-pixel reference, not a Sentinel-2 block-average threshold. Mixing those up is exactly how ag-tech demos lie to farmers. I added an explicit caveat to the model's prompt so it never presents one as the other.&lt;/li&gt;
&lt;li&gt;Every screenshot and demo polygon is a sample geometry with a visible "Sample" badge. I never drew a real orchard boundary in any public material. Real growers' land stays private, full stop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I learned&lt;/p&gt;

&lt;p&gt;Writing is the product.Hacktoberfest's judging criteria weight writing quality above everything else, and building FieldLens taught me why: the demo took a week; explaining &lt;em&gt;why it matters to a specific person&lt;/em&gt; took longer and mattered more. "A grower in Meizhou deciding where to fertilize this week" beats "a satellite analytics platform" every time.&lt;/p&gt;

&lt;p&gt;Local AI is a feature, not a compromise.Running Gemma locally wasn't just cheaper — it became the trust story. "Your orchard data never leaves your computer" is the sentence that makes a skeptical grower keep listening.&lt;/p&gt;

&lt;p&gt;Cold starts are a design constraint.The demo runs on Render's free tier, which sleeps. Instead of fighting it, I documented it in the post and designed the UI to degrade gracefully. Constraints you name honestly stop being embarrassments.&lt;/p&gt;

&lt;p&gt;First users are slower than code. I reached out to a pomelo-growing relative in Meizhou through a carefully written WeChat message. No reply yet. The code shipped in a week; trust takes a season. That's fine — the field validation is scheduled for November, and the product will be shaped by what actually happens in the orchard, not by what I imagine happens.&lt;/p&gt;

&lt;p&gt;What's next about the future&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Radar-optical fusion. Southern China is cloudy for months; optical imagery alone has gaps. A recent paper hit 93% early-season crop classification by fusing Sentinel-1 radar with optical time series — that's going straight into the FieldLens method library.&lt;/li&gt;
&lt;li&gt;A second software copyright if the November validation works — because in my world, shipped and validated beats shipped and demoed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why open matters here&lt;/p&gt;

&lt;p&gt;None of this works closed. Open satellite data (Sentinel-2), an open-weight model (Gemma) running on my own machine, open tooling throughout. If FieldLens depended on a proprietary API, every report would cost money, every grower's data would travel somewhere, and the whole "199 RMB a year" story would collapse. Open is what makes this deployable, not just demoable.&lt;/p&gt;




&lt;p&gt;Built with open-source AI for Hacktoberfest 2026. If you work on ag-tech, remote sensing, or just like the idea of satellites helping small growers — I'd love to hear what you'd build differently.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>FieldLens: Orchard Vigor Monitoring That a Grower Would Actually Pay For — Sentinel-2 NDVI + Local Gemma</title>
      <dc:creator>Liang Jacky</dc:creator>
      <pubDate>Fri, 16 Oct 2026 13:28:34 +0000</pubDate>
      <link>https://dev.to/liangjacky8921/fieldlens-orchard-vigor-monitoring-that-a-grower-would-actually-pay-for-sentinel-2-ndvi-local-4i0o</link>
      <guid>https://dev.to/liangjacky8921/fieldlens-orchard-vigor-monitoring-that-a-grower-would-actually-pay-for-sentinel-2-ndvi-local-4i0o</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;FieldLens turns a drawn orchard boundary into plain-language growing advice.&lt;/p&gt;

&lt;p&gt;A grower draws a plot on the map. FieldLens pulls Sentinel-2 imagery through Google Earth Engine, computes an NDVI vigor time series for that plot, and a locally running Gemma model turns the curve into a short report: what changed, what it might mean, and what to check in the field. (Where no local model is available, a deterministic rule engine covers the same steps — labeled in-app as a fallback.)&lt;/p&gt;

&lt;p&gt;We're starting with high-value orchards in Meizhou — Dapu honey pomelo and citrus — at 199 yuan per plot per year. The buyer is not a tech company. It's a grower who already walks the orchard and wants to know &lt;em&gt;which block to check first&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Why would a grower pay for this when Sentinel-2 data is free? Because they're not buying data — they're buying a shortcut: instead of walking every block to find the struggling one, the report tells them which block to check first. The 199 yuan isn't priced on our costs (near zero per report, thanks to the local model). It's priced on the grower's decision: cheap enough to say yes to without a meeting.&lt;/p&gt;

&lt;p&gt;What the report deliberately won't do: diagnose a disease, or prescribe pesticide doses. It says what the NDVI curve shows, flags what looks unusual, and tells the grower to go check in person.&lt;/p&gt;

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

&lt;p&gt;Live demo: &lt;a href="https://fieldlens-api.onrender.com/" rel="noopener noreferrer"&gt;https://fieldlens-api.onrender.com/&lt;/a&gt; — the tool page is at &lt;code&gt;/app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note: the demo runs on Render's free tier — if it has been idle a while, the first load may take ~30 seconds to wake up; everything after that is fast.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6gfw8iq903xiy3585l3u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6gfw8iq903xiy3585l3u.gif" alt="Demo run: load the sample field and generate the report, ~30 seconds" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju11nho4u5jb871wke9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju11nho4u5jb871wke9k.png" alt="Landing page" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddxbz76tm7wdkhes60bo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddxbz76tm7wdkhes60bo.png" alt="Empty tool state" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8xiwrrtztl0n0axevay9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8xiwrrtztl0n0axevay9.png" alt="Sample field loaded — 13 cloud-masked scenes, Watch" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faxgc2q0obuziz8l9nm4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faxgc2q0obuziz8l9nm4c.png" alt="Advisory: October note, Variable trend, three 7-day actions" width="549" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fph2901fj3cg0e2cq3p7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fph2901fj3cg0e2cq3p7b.png" alt="Same report in Chinese" width="549" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2oviobrp1ezgbdfz8u3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2oviobrp1ezgbdfz8u3h.png" alt="Every threshold traces to a published source (R1–R6)" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy4son6b8kjmd9539e3z0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy4son6b8kjmd9539e3z0.png" alt="Same flow on a 375px phone" width="800" height="1732"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How to try it in 30 seconds: open the demo, click "Load demo field", then generate the report. No account, no drawing required.&lt;/p&gt;

&lt;p&gt;An honest note on scope: the live demo above runs the UI and the sample field on a transparent rule-engine fallback (labeled in-app as "Rule-based fallback"); the full GEE + local Gemma chain runs on my own machine — setup is in the README. The sample polygon is illustrative, not a real farm's boundary, and every threshold is a literature value cited in the README.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/liangjacky8921/fieldlens" rel="noopener noreferrer"&gt;https://github.com/liangjacky8921/fieldlens&lt;/a&gt; (Public)&lt;/li&gt;
&lt;li&gt;The README covers setup (&lt;code&gt;ollama pull gemma2:2b&lt;/code&gt;, &lt;code&gt;earthengine authenticate&lt;/code&gt;), the &lt;code&gt;/api/ndvi&lt;/code&gt; endpoint, and a data-sources section with a source note on every threshold.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Frontend: map drawing (Leaflet) + bilingual UI (English default, Chinese reports for real growers).&lt;/li&gt;
&lt;li&gt;NDVI: NDVI = (B8 − B4) / (B8 + B4) on COPERNICUS/S2_SR_HARMONIZED, Sentinel-2, ~5-day revisit.&lt;/li&gt;
&lt;li&gt;Interpretation thresholds (all sourced in README, not invented):

&lt;ul&gt;
&lt;li&gt;NDVI ≥ 0.70 = high-vigor canopy (published sweet-orange study).&lt;/li&gt;
&lt;li&gt;NDVI &amp;gt; 0.25 = vegetation vs soil (published sooty-mould study).&lt;/li&gt;
&lt;li&gt;Citrus-orchard NDVI ranges from published studies, including how low values can go under stress or infection — the report treats a drop as a reason to go look, not a diagnosis.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Report: local Gemma (&lt;code&gt;gemma2:2b&lt;/code&gt; via Ollama) with a &lt;code&gt;lang&lt;/code&gt; parameter (English default, Chinese for growers). Alert rules (e.g. drop &amp;gt; 0.10) are project settings, labeled as such — not literature values.&lt;/li&gt;
&lt;li&gt;Sample field: an illustrative polygon inside the real Dapu honey-pomelo geographical-indication protection zone (116°18′–116°56′E, 24°01′–24°41′N). It's labeled "Sample field" in the app — not a real farm's boundary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The NDVI pipeline is one file (&lt;code&gt;app/gee_ndvi.py&lt;/code&gt;). Per-scene mean is computed twice: once with QA60 cloud masking, and once unmasked as a fallback for scenes where cloud cover masks the whole plot. Scene-level means are then reduced to a single value per revisit date, and any scene with a null (fully cloud-masked) mean is dropped rather than counted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Dual-track per-scene NDVI mean: QA60-masked, falling back to unmasked mean
# so a fully cloud-covered scene still contributes instead of being silently dropped.
&lt;/span&gt;&lt;span class="n"&gt;masked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ndvi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduceRegion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reducer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reducer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;unmasked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ndvi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unmask&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;reduceRegion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reducer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reducer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Algorithms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;If&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Algorithms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IsEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;masked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nd&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;unmasked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nd&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;masked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nd&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Open Innovation Matters
&lt;/h2&gt;

&lt;p&gt;All economic, not ideological:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The unit economics only work because the model is local.&lt;/strong&gt; A per-report cloud API bill would eat the 199 yuan/plot/year price. Local Gemma has no per-call charge, so the price can stay low enough for a grower to say yes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The data stays on the farm.&lt;/strong&gt; Plot boundaries and orchard health are business-sensitive. Nothing is uploaded to a vendor server for inference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open data + open weights = auditable numbers.&lt;/strong&gt; Sentinel-2 is open Copernicus data; every threshold in the README carries its source. A grower (or a judge) can check where each number came from.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  First User
&lt;/h2&gt;

&lt;p&gt;We're in talks with a Meizhou pomelo cooperative to run an on-site validation in November — real blocks, real walking, comparing the report's "check this block first" ranking against the grower's own walk order.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — report generation runs on local Gemma 2B via Ollama; the live demo surfaces the labeled fallback path because Ollama can't run on Render's free tier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render&lt;/strong&gt; — frontend + FastAPI backend + GEE-backed NDVI pipeline deployed on Render; &lt;code&gt;/health&lt;/code&gt; reports &lt;code&gt;gee_ready: true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overall (Week 2: Side Hustle)&lt;/strong&gt; — a grower would actually pay for this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr9kmmw80u15y13x02yla.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr9kmmw80u15y13x02yla.gif" alt=" " width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
