<?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: Veditha</title>
    <description>The latest articles on DEV Community by Veditha (@veditha08).</description>
    <link>https://dev.to/veditha08</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%2F4157264%2F4cc19d1e-2f70-46c5-ae0a-d8cebc34ff06.jpg</url>
      <title>DEV Community: Veditha</title>
      <link>https://dev.to/veditha08</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/veditha08"/>
    <language>en</language>
    <item>
      <title>RepurposeAI- a local content repurposer built on Ollama</title>
      <dc:creator>Veditha</dc:creator>
      <pubDate>Sat, 17 Oct 2026 09:15:29 +0000</pubDate>
      <link>https://dev.to/veditha08/repurposeai-a-local-content-repurposer-built-on-ollama-2jh1</link>
      <guid>https://dev.to/veditha08/repurposeai-a-local-content-repurposer-built-on-ollama-2jh1</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;h1&gt;
  
  
  RepurposeAI: Repurpose Content with Local AI Models
&lt;/h1&gt;

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

&lt;p&gt;&lt;strong&gt;RepurposeAI&lt;/strong&gt; converts a blog post or video transcript into platform-specific content for Twitter/X, LinkedIn, newsletters, Instagram, and Reddit.&lt;/p&gt;

&lt;p&gt;Paste your source content, choose a format, and watch the output stream directly to the page, token by token, from a model running on your local machine.&lt;/p&gt;

&lt;p&gt;The intended user is someone who publishes regularly across multiple platforms and has to manually rewrite the same content several times a week. It's a repetitive task, and many content tools offer AI-powered alternatives through paid subscriptions.&lt;/p&gt;

&lt;p&gt;RepurposeAI takes a different approach: it uses a local model through Ollama instead of a paid AI API. The trade-off is that users must install Ollama and download a model themselves. Once the model is available locally, there are no per-generation API charges, and the content sent to the model stays on the user's machine.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Run Locally
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Node.js and &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pull a model and start Ollama:&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 llama3.2
ollama serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a separate terminal, clone and run the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Veditha08/repurpose-ai
&lt;span class="nb"&gt;cd &lt;/span&gt;repurpose-ai
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt; in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code and Architecture
&lt;/h2&gt;

&lt;p&gt;The project uses a small React frontend with a dedicated module for communicating with Ollama.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── App.jsx       # UI and application state
├── ollama.js     # Ollama client and prompt templates
├── index.css     # Styles
└── main.jsx      # Application entry point
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Streaming Responses from Ollama
&lt;/h3&gt;

&lt;p&gt;The core of the Ollama integration is an asynchronous generator that reads the streaming NDJSON response from the API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;streamGenerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:11434/api/generate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Ignore malformed or incomplete lines.&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&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;p&gt;The React application consumes the generator using &lt;code&gt;for await...of&lt;/code&gt; and appends incoming text to the output state as it arrives. This makes the generation process visible instead of keeping the user waiting for the entire response.&lt;/p&gt;

&lt;p&gt;There is no application backend. The browser communicates directly with Ollama running on the same machine.&lt;/p&gt;

&lt;p&gt;Each output format has its own prompt template. For example, the newsletter template requests a subject line, an introductory paragraph, three bullet points, and a call-to-action paragraph. The prompts also incorporate the selected niche, tone, and output language to tailor the result to the intended audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ollama:&lt;/strong&gt; Runs local language models and exposes a REST API for generation and model discovery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-weight models:&lt;/strong&gt; Users can select from models installed in Ollama, such as Llama 3.2, Qwen 2.5, or Mistral, provided the selected model is compatible with the requested generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React + Vite:&lt;/strong&gt; Powers the frontend and development server. The application does not require its own backend, database, or authentication layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;localStorage:&lt;/strong&gt; Stores generation history in the browser, with up to 30 entries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture is intentionally simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React frontend
     |
     | POST /api/generate
     v
Ollama running locally
     |
     | Streaming response
     v
React state → UI updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Building this project with open-weight models made three things possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cost Structure
&lt;/h3&gt;

&lt;p&gt;Hosted AI APIs can charge per token or request. For someone who frequently repurposes content, those costs can accumulate.&lt;/p&gt;

&lt;p&gt;With local inference, there are no per-generation API charges. The trade-off is that users need suitable hardware, and running models still consumes electricity and other computing resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Data Control
&lt;/h3&gt;

&lt;p&gt;Content being repurposed may belong to clients, contain unreleased material, or be subject to confidentiality requirements.&lt;/p&gt;

&lt;p&gt;Because RepurposeAI sends generation requests to Ollama running locally rather than to a hosted AI inference provider, the source content does not need to be sent to a third-party AI API. This reduces external data exposure, although the privacy of the overall setup also depends on the user's environment and configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Model Flexibility
&lt;/h3&gt;

&lt;p&gt;Different models can produce different results depending on the content, niche, and task.&lt;/p&gt;

&lt;p&gt;With Ollama, users can switch between compatible installed models without integrating a new hosted AI API or managing separate API credentials. The application discovers available models and lets users choose which one to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and Trade-offs
&lt;/h2&gt;

&lt;p&gt;The main limitation is setup complexity.&lt;/p&gt;

&lt;p&gt;Ollama is relatively straightforward to install, but asking a non-technical user to download a model, start the local service, and configure their environment introduces friction. Model performance and generation speed also depend on the chosen model and available hardware.&lt;/p&gt;

&lt;p&gt;A hosted-API version could be easier to access, but it would introduce different costs and data-handling considerations.&lt;/p&gt;

&lt;p&gt;For this project, I chose local inference to explore how open-weight models can make content-generation tools more accessible to people who prefer to run AI on their own machines.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>RepurposeAI — a local content repurposer built on Ollama</title>
      <dc:creator>Veditha</dc:creator>
      <pubDate>Sat, 17 Oct 2026 09:12:05 +0000</pubDate>
      <link>https://dev.to/veditha08/repurposeai-a-local-content-repurposer-built-on-ollama-1ag6</link>
      <guid>https://dev.to/veditha08/repurposeai-a-local-content-repurposer-built-on-ollama-1ag6</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;h1&gt;
  
  
  RepurposeAI: Repurpose Content with Local AI Models
&lt;/h1&gt;

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

&lt;p&gt;&lt;strong&gt;RepurposeAI&lt;/strong&gt; converts a blog post or video transcript into platform-specific content for Twitter/X, LinkedIn, newsletters, Instagram, and Reddit.&lt;/p&gt;

&lt;p&gt;Paste your source content, choose a format, and watch the output stream directly to the page, token by token, from a model running on your local machine.&lt;/p&gt;

&lt;p&gt;The intended user is someone who publishes regularly across multiple platforms and has to manually rewrite the same content several times a week. It's a repetitive task, and many content tools offer AI-powered alternatives through paid subscriptions.&lt;/p&gt;

&lt;p&gt;RepurposeAI takes a different approach: it uses a local model through Ollama instead of a paid AI API. The trade-off is that users must install Ollama and download a model themselves. Once the model is available locally, there are no per-generation API charges, and the content sent to the model stays on the user's machine.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Run Locally
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Node.js and &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pull a model and start Ollama:&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 llama3.2
ollama serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a separate terminal, clone and run the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Veditha08/repurpose-ai
&lt;span class="nb"&gt;cd &lt;/span&gt;repurpose-ai
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt; in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code and Architecture
&lt;/h2&gt;

&lt;p&gt;The project uses a small React frontend with a dedicated module for communicating with Ollama.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── App.jsx       # UI and application state
├── ollama.js     # Ollama client and prompt templates
├── index.css     # Styles
└── main.jsx      # Application entry point
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Streaming Responses from Ollama
&lt;/h3&gt;

&lt;p&gt;The core of the Ollama integration is an asynchronous generator that reads the streaming NDJSON response from the API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;streamGenerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:11434/api/generate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Ignore malformed or incomplete lines.&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&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;p&gt;The React application consumes the generator using &lt;code&gt;for await...of&lt;/code&gt; and appends incoming text to the output state as it arrives. This makes the generation process visible instead of keeping the user waiting for the entire response.&lt;/p&gt;

&lt;p&gt;There is no application backend. The browser communicates directly with Ollama running on the same machine.&lt;/p&gt;

&lt;p&gt;Each output format has its own prompt template. For example, the newsletter template requests a subject line, an introductory paragraph, three bullet points, and a call-to-action paragraph. The prompts also incorporate the selected niche, tone, and output language to tailor the result to the intended audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ollama:&lt;/strong&gt; Runs local language models and exposes a REST API for generation and model discovery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-weight models:&lt;/strong&gt; Users can select from models installed in Ollama, such as Llama 3.2, Qwen 2.5, or Mistral, provided the selected model is compatible with the requested generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React + Vite:&lt;/strong&gt; Powers the frontend and development server. The application does not require its own backend, database, or authentication layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;localStorage:&lt;/strong&gt; Stores generation history in the browser, with up to 30 entries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture is intentionally simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React frontend
     |
     | POST /api/generate
     v
Ollama running locally
     |
     | Streaming response
     v
React state → UI updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Building this project with open-weight models made three things possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cost Structure
&lt;/h3&gt;

&lt;p&gt;Hosted AI APIs can charge per token or request. For someone who frequently repurposes content, those costs can accumulate.&lt;/p&gt;

&lt;p&gt;With local inference, there are no per-generation API charges. The trade-off is that users need suitable hardware, and running models still consumes electricity and other computing resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Data Control
&lt;/h3&gt;

&lt;p&gt;Content being repurposed may belong to clients, contain unreleased material, or be subject to confidentiality requirements.&lt;/p&gt;

&lt;p&gt;Because RepurposeAI sends generation requests to Ollama running locally rather than to a hosted AI inference provider, the source content does not need to be sent to a third-party AI API. This reduces external data exposure, although the privacy of the overall setup also depends on the user's environment and configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Model Flexibility
&lt;/h3&gt;

&lt;p&gt;Different models can produce different results depending on the content, niche, and task.&lt;/p&gt;

&lt;p&gt;With Ollama, users can switch between compatible installed models without integrating a new hosted AI API or managing separate API credentials. The application discovers available models and lets users choose which one to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and Trade-offs
&lt;/h2&gt;

&lt;p&gt;The main limitation is setup complexity.&lt;/p&gt;

&lt;p&gt;Ollama is relatively straightforward to install, but asking a non-technical user to download a model, start the local service, and configure their environment introduces friction. Model performance and generation speed also depend on the chosen model and available hardware.&lt;/p&gt;

&lt;p&gt;A hosted-API version could be easier to access, but it would introduce different costs and data-handling considerations.&lt;/p&gt;

&lt;p&gt;For this project, I chose local inference to explore how open-weight models can make content-generation tools more accessible to people who prefer to run AI on their own machines.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>TraiLens: An Offline-First AI Nature Journal</title>
      <dc:creator>Veditha</dc:creator>
      <pubDate>Tue, 06 Oct 2026 16:10:35 +0000</pubDate>
      <link>https://dev.to/veditha08/trailens-an-offline-first-ai-nature-journal-1jen</link>
      <guid>https://dev.to/veditha08/trailens-an-offline-first-ai-nature-journal-1jen</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;TraiLens&lt;/strong&gt;, a local Python tool that automatically generates a Markdown nature journal from your hiking photos using a local open-weight vision model. &lt;/p&gt;

&lt;p&gt;Most outdoor apps require you to stare at your screen on the trail. TraiLens flips that: it encourages you to put your phone on airplane mode. You go outside, enjoy the trek, and simply snap photos of interesting plants, geology, or landscapes. When you get home, you drop the photos into a folder on your laptop. TraiLens runs them through an open-weight vision model and generates a beautiful, documented field diary of what you saw, complete with EXIF metadata extraction. &lt;/p&gt;

&lt;p&gt;The screen time happens &lt;em&gt;after&lt;/em&gt; the hike, not during it.&lt;/p&gt;

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

&lt;p&gt;Here is TrailLens running locally and analyzing my photos completely offline:&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%2Fr338ixueuurow5y3ngfn.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%2Fr338ixueuurow5y3ngfn.png" alt=" " width="756" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is the beautiful field guide it automatically generates:&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%2Fmnknvd1yv8tx9svzxu59.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%2Fmnknvd1yv8tx9svzxu59.png" alt=" " width="800" height="661"&gt;&lt;/a&gt;&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/Veditha08" rel="noopener noreferrer"&gt;
        Veditha08
      &lt;/a&gt; / &lt;a href="https://github.com/Veditha08/trailens" rel="noopener noreferrer"&gt;
        trailens
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;🌲 TraiLens&lt;/h1&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;An offline-first, local-inference field naturalist journal built for the Hacktoberfest "Touch Grass" AI Challenge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TrailLens eliminates screen time on the trail. Put your phone in airplane mode, hike screen-free, and take photos of flora, fauna, and geology. When you return, TrailLens processes your photos locally using &lt;strong&gt;Moondream&lt;/strong&gt; via &lt;strong&gt;Ollama&lt;/strong&gt;, extracting EXIF metadata and generating an automated Markdown field journal with zero cloud API dependencies.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;100% Offline &amp;amp; Private:&lt;/strong&gt; Zero telemetry or cloud calls. GPS and photos stay on your device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Vision Inference:&lt;/strong&gt; Powered by Moondream via Ollama.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EXIF Extraction:&lt;/strong&gt; Automatically retrieves capture timestamps and GPS markers.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt; and pull the model:
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ollama pull moondream&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Veditha08/trailens" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


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

&lt;p&gt;TrailLens is built in &lt;strong&gt;Python&lt;/strong&gt; and relies entirely on local edge inference. &lt;/p&gt;

&lt;p&gt;Instead of sending my photos to a paid cloud API, I used &lt;strong&gt;Ollama&lt;/strong&gt; to run &lt;strong&gt;Moondream&lt;/strong&gt; (a lightweight, highly capable open-source vision model). The Python script loops through a local directory of images, extracts the GPS and timestamp EXIF data using the &lt;code&gt;Pillow&lt;/code&gt; library, and then prompts the local Moondream model to act as a master naturalist, identifying the flora and terrain. Finally, it compiles everything into a formatted Markdown file (&lt;code&gt;TRAIL_JOURNAL.md&lt;/code&gt;).&lt;/p&gt;

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

&lt;p&gt;This project only makes sense with open-source AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Total Privacy:&lt;/strong&gt; Hiking photos contain metadata and exact GPS coordinates of where you have been. Sending a camera roll to a closed API is a massive privacy risk. Running Moondream locally guarantees your location history never leaves your laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Cost:&lt;/strong&gt; Passing high-res images to a cloud vision API costs money per token. A heavy hiker might take 100 photos on a weekend trip. Local inference makes processing bulk image data completely free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disconnection:&lt;/strong&gt; Because the processing happens locally on my laptop after the hike, I am not tempted to look for a cell signal on the trail to see what an app thinks I'm looking at. Open, offline models let nature actually be nature.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Grand Prize Track (Touch Grass):&lt;/strong&gt; Engineered specifically to get people off screens while on the trail, utilizing local inference to process the data only after the outdoor experience is finished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Local Inference:&lt;/strong&gt; The core of the project relies on Ollama and Moondream to analyze images without an internet connection.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>ai</category>
      <category>hacktoberfest</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
