{"id":57226,"date":"2025-07-02T13:00:00","date_gmt":"2025-07-02T20:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=57226"},"modified":"2025-07-02T13:00:00","modified_gmt":"2025-07-02T20:00:00","slug":"alttext-generator-csharp-local-models","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/alttext-generator-csharp-local-models\/","title":{"rendered":"Local AI + .NET = AltText Magic in One C# Script"},"content":{"rendered":"<p>Need to generate image descriptions fast? In this post, we\u2019ll show how to combine .NET 10\u2019s new capabilities with local AI models to create smart AltText \u2014 all in one simple C# file. It\u2019s a fun way to explore what AI can do beyond chat.<\/p>\n<h2>AltText Generation with Local AI Models and <code>dotnet run app.cs<\/code><\/h2>\n<h3>\u2728 Intro: Let&#8217;s Talk About AltText<\/h3>\n<p>Accessibility matters \u2014 and one simple but powerful way to improve it is by adding <strong>AltText<\/strong> to images. Alternative text helps screen readers describe images to visually impaired users, improves SEO, and enhances overall UX. But writing descriptive alt text for every image can be repetitive. That\u2019s where AI comes in!<\/p>\n<h3>\ud83e\udd16 Using Local Models with Ollama<\/h3>\n<p>Local models are a game changer. No rate limits, no cloud latency, and full control over the models you use.<\/p>\n<p>In this sample, we will use <strong><a href=\"https:\/\/ollama.com\">Ollama<\/a><\/strong> to run a vision model like <code>gemma3<\/code>, <code>llama3.2-vision<\/code>, or <code>mistral-small3.2<\/code>. These models are great at understanding image content and generating rich natural language descriptions.<\/p>\n<pre><code class=\"language-bash\">ollama run gemma3 \n# or ollama run llama3.2-vision \n# or ollama run mistral-small3.2<\/code><\/pre>\n<p>Once Ollama is running locally (usually on <a href=\"http:\/\/localhost:11434\">http:\/\/localhost:11434<\/a>), you can send requests to analyze an image and receive a natural language description.<\/p>\n<p><div class=\"alert alert-primary\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Coming Soon<\/strong><\/p>AI Foundry Local will provide similar capabilities with local models. Stay tuned!<\/div><\/p>\n<h2>\ud83d\ude80 Run C# as a Script with <code>dotnet run app.cs<\/code><\/h2>\n<p>.NET 10 introduced a cool new feature: you can now run a C# file directly with <code>dotnet run<\/code>. No project scaffolding, no <code>.csproj<\/code> files \u2014 just clean, script-like execution.<\/p>\n<p>Ref: <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-run-app\/\">https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-run-app\/<\/a><\/p>\n<pre><code class=\"language-bash\">dotnet run app.cs<\/code><\/pre>\n<p>This is incredibly convenient for scripting tasks like image processing, quick automation, or dev tooling.<\/p>\n<p>Let\u2019s see it in action!<\/p>\n<h2>\ud83d\udcc2 The Full Code Sample<\/h2>\n<p><script src=\"https:\/\/gist.github.com\/elbruno\/4396c9ee3e56d1c86d280faa33b8f9fe.js\"><\/script><\/p>\n<blockquote>\n<p>\u2728 Source: <a href=\"https:\/\/gist.github.com\/elbruno\/4396c9ee3e56d1c86d280faa33b8f9fe\">https:\/\/gist.github.com\/elbruno\/4396c9ee3e56d1c86d280faa33b8f9fe<\/a><\/p>\n<\/blockquote>\n<p>Save this code as <code>alttext.cs<\/code> and run it  using <code>dotnet run alttext.cs &lt;your image path&gt;<\/code>. Make sure Ollama is running and the image path is correct.<\/p>\n<pre><code class=\"language-csharp\">\/\/ alttext.cs\n#:package OllamaSharp@5.1.19\n\nusing OllamaSharp;\n\n\/\/ set up the client\nvar uri = new Uri(\"http:\/\/localhost:11434\");\nvar ollama = new OllamaApiClient(uri);\nollama.SelectedModel = \"gemma3\";\nvar chat = new Chat(ollama);\n\n\/\/ read the image file from arguments\nbyte[] imageBytes = File.ReadAllBytes(args[0]);\nvar imageBytesEnumerable = new List&lt;IEnumerable&lt;byte&gt;&gt; { imageBytes };\n\n\/\/ generate the alt text\nvar message = \"Generate a complete alt text description for the attached image. The description should be detailed and suitable for visually impaired users. Do not include any information about the image file name or format.\";\nawait foreach (var answerToken in chat.SendAsync(message: message, imagesAsBytes: imageBytesEnumerable))\n    Console.Write(answerToken);\n\n\/\/ done\nConsole.WriteLine($\"&gt;&gt; Ollama done\");;<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/07\/01demorun.png\" alt=\"Screenshot showing Visual Studio Code terminal with AltText generation results from analyzing an image\" \/><\/p>\n<blockquote>\n<p>\u2709 Tip: If your image is large, consider resizing it before encoding. This reduces request size and speeds up inference.<\/p>\n<\/blockquote>\n<h2>\ud83d\udd2e What\u2019s Next?<\/h2>\n<p>With .NET 10 and the power of local AI models like Azure AI Foundry Local Ollama, we&#8217;re no longer limited to &#8220;chat with AI&#8221; scenarios. We can now:<\/p>\n<ul>\n<li>Analyze media<\/li>\n<li>Automate content generation<\/li>\n<li>Build offline-capable AI features<\/li>\n<\/ul>\n<p>This is also a great way to learn! Try switching to different local models, modifying the prompt, or adding a few lines to copy the result to your clipboard. These small tweaks help you experiment and understand how to integrate AI into real-world apps.<\/p>\n<p>To go further:<\/p>\n<ul>\n<li>\ud83d\udcd8 <strong>Learn More<\/strong>: Explore the <a href=\"https:\/\/aka.ms\/genainet\">Generative AI for Beginners (.NET)<\/a> repo for hands-on lessons and sample projects.<\/li>\n<li>\ud83d\udcfa <strong>Watch &amp; Code<\/strong>: Tune in to the <a href=\"https:\/\/dotnet.microsoft.com\/live\/community-standup\">AI &amp; .NET Community StandUp<\/a> to see live demos and join the conversation.<\/li>\n<\/ul>\n<blockquote>\n<p>.NET keeps getting more fun, and AI keeps getting more powerful \u2014 especially when you run it locally \u2728<\/p>\n<\/blockquote>\n<p>Have fun generating smart AltText and making your apps more accessible!<\/p>\n<hr \/>\n<h3>\ud83d\udcc3 Resources<\/h3>\n<ul>\n<li>Blog: <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-run-app\/\">https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-run-app\/<\/a><\/li>\n<li>Gist Code: <a href=\"https:\/\/gist.github.com\/elbruno\/4396c9ee3e56d1c86d280faa33b8f9fe\">https:\/\/gist.github.com\/elbruno\/4396c9ee3e56d1c86d280faa33b8f9fe<\/a><\/li>\n<li>Ollama: <a href=\"https:\/\/ollama.com\">https:\/\/ollama.com<\/a><\/li>\n<li>AI Foundry: <a href=\"https:\/\/aka.ms\/aifoundry\">https:\/\/aka.ms\/aifoundry<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to generate image AltText using .NET 10 and local AI models \u2014 all in a single C# file with dotnet run app.cs. A fun and accessible example of what AI can do beyond chat.<\/p>\n","protected":false},"author":120281,"featured_media":57227,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7781,756],"tags":[7834,568,8050,58,63,8051],"class_list":["post-57226","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-ai","category-csharp","tag-accessibility","tag-ai","tag-alttext","tag-csharp","tag-dotnet","tag-local-models"],"acf":[],"blog_post_summary":"<p>Learn how to generate image AltText using .NET 10 and local AI models \u2014 all in a single C# file with dotnet run app.cs. A fun and accessible example of what AI can do beyond chat.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/57226","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/120281"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=57226"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/57226\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/57227"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=57226"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=57226"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=57226"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}