<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Jeremy's Programming Blog]]></title><description><![CDATA[My blog About Software Development]]></description><link>https://www.jeremymorgan.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1649352221946/oTvfKLiJA.png</url><title>Jeremy&apos;s Programming Blog</title><link>https://www.jeremymorgan.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 09 May 2026 23:52:30 GMT</lastBuildDate><atom:link href="https://www.jeremymorgan.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I attended POST/CON 2025. Here are my thoughts]]></title><description><![CDATA[I just returned from POST/CON 25, and I’m left with one big impression: Postman gets it.
They get that we’re not just managing APIs. We’re building complex systems, and increasingly, those systems involve AI. And as AI technologies race ahead Postman...]]></description><link>https://www.jeremymorgan.dev/i-attended-postcon-2025-here-are-my-thoughts</link><guid isPermaLink="true">https://www.jeremymorgan.dev/i-attended-postcon-2025-here-are-my-thoughts</guid><category><![CDATA[Postman]]></category><category><![CDATA[#PostmanAPI]]></category><category><![CDATA[PostmanTesting]]></category><category><![CDATA[APIs]]></category><category><![CDATA[AI]]></category><category><![CDATA[mcp]]></category><category><![CDATA[mcp server]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Mon, 16 Jun 2025 17:09:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750093669529/f6bcd66d-088e-4828-b052-3d40106cc1e9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I just returned from POST/CON 25, and I’m left with one big impression: Postman gets it.</p>
<p>They get that we’re not just managing APIs. We’re building complex systems, and increasingly, those systems involve AI. And as AI technologies race ahead Postman is right there to help you keep up.</p>
<p>I’ve been using Postman for years, and I was thrilled to be invited to POST/CON 2025 in Los Angeles. It was an amazing experience, and I want to share some of the highlights.</p>
<p>If you want the full rundown of the conference, you can <a target="_blank" href="https://fnf.dev/4mSSgP1">check out the official recap here</a>. I want to share my personal highlights and thoughts on the event.</p>
<h2 id="heading-day-1-full-day-workshop-mastering-ai-agent-automation-with-postman-flows">Day 1: Full day workshop - “Mastering AI agent Automation with Postman Flows”</h2>
<p><img src="https://www.jeremymorgan.com/images/blog/programming/postcon-2025-highlights/postcon-2025-highlights-00.webp" alt="Postman POST/CON 2025 Highlights" /></p>
<p>There I learned:</p>
<p>🔥 How easy it is to connect things together with flow</p>
<p>🔥 How to tie together AI agents into a seamless workflow and deploy it</p>
<p>🔥 Learn best practices for design</p>
<p>Then a fireside chat with Ryan Reynolds and Justine Davis that had almost nothing to do with code and everything to do with building great products that solve real problems, and taking care of people.</p>
<p><img src="https://www.jeremymorgan.com/images/blog/programming/postcon-2025-highlights/postcon-2025-highlights-01.webp" alt="Postman POST/CON 2025 Highlights" /></p>
<h2 id="heading-day-2-keynote-and-sessions">Day 2: Keynote and Sessions</h2>
<p>Attended the Keynote where I learned about</p>
<p>🛠️ Postman VS code extensions</p>
<p>🛠️ GitHub Integration</p>
<p>🛠️ Postman Insights (lots of great analytics)</p>
<p>🛠️ AI Agent Builder</p>
<p>🛠️ Model Comparison Template</p>
<p>🛠️ MCP Server Generator (REALLY)</p>
<p>and so much more. You can <a target="_blank" href="https://fnf.dev/4mSSgP1">get all the details here</a>.</p>
<h3 id="heading-sessions">Sessions</h3>
<p>I attended some amazing sessions, where I learned a ton about</p>
<p>🧠 Agent Orchestration using API-driven workflows</p>
<p>🧠 Building multi-agent experiences with Agent Builder</p>
<p>🧠 Automating API Testing in CI/CD pipelines with CircleCI and Postman</p>
<p>🧠 Composable API Ecosystems and the MCP Protocol</p>
<p>and tons of great lightning talks.</p>
<h2 id="heading-one-of-the-best-conferences-ive-attended">One of the best conferences I’ve attended</h2>
<p><img src="https://www.jeremymorgan.com/images/blog/programming/postcon-2025-highlights/postcon-2025-highlights-02.webp" alt="Postman POST/CON 2025 Highlights" /></p>
<p>The energy at this conference was amazing. It’s one of the best I’ve attended. Postman is at the forefront of tech. They’ve created great tools to keep YOU ahead of the game. They focus on building their product well and help you create your best products, too.</p>
<p>I highly suggest going to the next POST/CON. If you do, let me know and let’s meet up!</p>
<p>Thank you so much to Postman for sending me to this conference. Now, if you’ll excuse me, I have some new tools to try out!</p>
<p>– Jeremy</p>
]]></content:encoded></item><item><title><![CDATA[Review: The New NVIDIA Jetson Orin Nano]]></title><description><![CDATA[Hello, friends! If you’re a reader of this blog you’ve probably heard about NVIDIA’s Jetson. It’s a great platform for prototyping apps and putting AI at the edge.
I got lucky and got my hands on the newest, very affordable Jetson, the Jetson Orin Na...]]></description><link>https://www.jeremymorgan.dev/review-the-new-nvidia-jetson-orin-nano</link><guid isPermaLink="true">https://www.jeremymorgan.dev/review-the-new-nvidia-jetson-orin-nano</guid><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[Deep Learning]]></category><category><![CDATA[generative ai]]></category><category><![CDATA[large language models]]></category><category><![CDATA[iot]]></category><category><![CDATA[edgecomputing]]></category><category><![CDATA[ Edge AI]]></category><category><![CDATA[NVIDIA]]></category><category><![CDATA[GPU, NVIDIA, AMD]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Thu, 26 Dec 2024 02:51:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735181275493/7d3100e4-ad12-4fe6-9bcc-e819100daf1c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello, friends! If you’re a reader of this blog you’ve probably heard about NVIDIA’s Jetson. It’s a great platform for prototyping apps and putting AI at the edge.</p>
<p>I got lucky and got my hands on the newest, very affordable Jetson, the Jetson Orin Nano.</p>
<p>Today, we’ll dive into everything from unboxing this little gem to testing its performance with AI models. Ready to explore what makes this device so cool? Let’s get started!</p>
<p>If you’d rather see a video version of this review <a target="_blank" href="https://www.youtube.com/watch?v=JRhAMHxlo3E">here it is</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=JRhAMHxlo3E">https://www.youtube.com/watch?v=JRhAMHxlo3E</a></div>
<p> </p>
<h3 id="heading-whats-inside-the-box">What’s Inside the Box?</h3>
<p><img src="https://www.jeremymorgan.com/images/blog/tech/nvidia-jetson-orin-nano/nvidia-jetson-orin-nano-00.webp" alt="“NVIDIA Jetson Orin Nano”" /></p>
<p>First impressions matter, and the Orin Nano’s packaging is as clean and straightforward as you’d expect. Here’s what you get:</p>
<ul>
<li><p>A robust power supply with both European and American plugs.</p>
</li>
<li><p>A quick start manual (kinda)</p>
</li>
<li><p>And, of course, the star of the show: the Jetson Orin Nano.</p>
</li>
</ul>
<p>You do need to purchase an SD card for it, aas it’s not shipped with one.</p>
<p>The device is sleek, lightweight, and full of potential. It includes HDMI, USB, Ethernet, GPIO, and video input ports. Whether you’re making an AI robot or building computer vision stuff (I know I will), this device has you covered.</p>
<hr />
<h3 id="heading-the-specs-why-its-called-a-raspberry-pi-on-steroids">The Specs: Why It’s Called a “Raspberry Pi on Steroids”</h3>
<p><img src="https://www.jeremymorgan.com/images/blog/tech/nvidia-jetson-orin-nano/nvidia-jetson-orin-nano-01.webp" alt="“NVIDIA Jetson Orin Nano”" /></p>
<p>Let’s talk hardware. Look at what’s packed into this small device:</p>
<ul>
<li><p><strong>CPU</strong>: A six-core ARM Cortex 64-bit processor.</p>
</li>
<li><p><strong>GPU</strong>: NVIDIA Ampere architecture, tuned for AI workloads.</p>
</li>
<li><p><strong>RAM</strong>: 8 GB of high-speed memory.</p>
</li>
<li><p><strong>Connectivity</strong>: Ethernet and wireless ready.</p>
</li>
<li><p><strong>Storage Options</strong>: NVMe support for all your AI model needs.</p>
</li>
</ul>
<p>Think of it as a supercharged Raspberry Pi with a serious focus on AI.</p>
<hr />
<h3 id="heading-setting-it-up-the-good-the-tricky-and-the-rewarding">Setting It Up: The Good, The Tricky, and The Rewarding</h3>
<p><img src="https://www.jeremymorgan.com/images/blog/tech/nvidia-jetson-orin-nano/nvidia-jetson-orin-nano-02.webp" alt="“NVIDIA Jetson Orin Nano”" /></p>
<p>Getting the Orin Nano up and running wasn’t exactly plug-and-play, but it wasn’t rocket science either. Here’s how it went down:</p>
<ol>
<li><p><strong>Firmware Update</strong>: Before diving in, I updated the firmware to version 36.x. This step required temporarily installing Jetpack 5.1.3. Then, you update the firmware from there. (Pro tip: don’t skip this. You want the new firmware and Jetpack)</p>
</li>
<li><p><strong>Jetpack 6.1 Installation</strong>: After the firmware update, I installed Jetpack 6.1, NVIDIA’s tailored OS for the Jetson lineup. It’s smooth, intuitive, and optimized for AI tasks.</p>
</li>
</ol>
<p>If you’re purchasing this devcie, then burning SD cards and flashing firmware shouldn’t be a problem.</p>
<hr />
<h3 id="heading-performance-tests-how-does-it-handle-ai-models">Performance Tests: How Does It Handle AI Models?</h3>
<p><img src="https://www.jeremymorgan.com/images/blog/tech/nvidia-jetson-orin-nano/nvidia-jetson-orin-nano-03.webp" alt="“NVIDIA Jetson Orin Nano”" /></p>
<p>Here’s where the fun begins—I tested the Orin Nano with AI models using <strong>Ollama</strong>, a platform designed for running large language models (LLMs).</p>
<p><a target="_blank" href="https://ollama.com/">Check out Ollama here</a></p>
<p>Here’s what I discovered:</p>
<ul>
<li><p><strong>1 Billion Parameter Models</strong>: Smooth sailing! These models ran effortlessly, perfect for tasks like chatbots or real-time applications.</p>
</li>
<li><p><strong>3 Billion Parameter Models</strong>: Still impressive, though with slightly longer loading times.</p>
</li>
<li><p><strong>7 Billion Parameter Models</strong>: Houston, we have a problem. The Orin Nano hit its limits here, occasionally freezing or locking up.</p>
</li>
</ul>
<p>While it’s not designed for massive models, this performance is impressive for a device in this price range.</p>
<p>You can view the <a target="_blank" href="https://youtu.be/JRhAMHxlo3E?si=sWhFLwRx5Dgu7bO4&amp;t=768">performance tests I did in this video</a>.</p>
<hr />
<h3 id="heading-pros-and-cons-the-real-deal">Pros and Cons: The Real Deal</h3>
<p><strong>What I Loved</strong>:</p>
<ol>
<li><p><strong>Compact and Lightweight</strong>: Perfect for edge AI projects where space is a premium.</p>
</li>
<li><p><strong>Impressive Performance</strong>: At $250, you’re getting serious bang for your buck.</p>
</li>
<li><p><strong>Quiet Operation</strong>: Even under load, it’s quiet—a big plus for home projects.</p>
</li>
<li><p><strong>User-Friendly OS</strong>: Jetpack is intuitive and packed with features.</p>
</li>
</ol>
<p><strong>What Needs Improvement</strong>:</p>
<ol>
<li><p><strong>Limits on Larger Models</strong>: It’s not a deal-breaker, but don’t expect it to handle anything beyond 7 billion parameters comfortably.</p>
</li>
<li><p><strong>Occasional Glitches</strong>: Some random lockups and an odd “system throttled due to overcurrent” error. I’m looking into it. Manageable, but worth noting.</p>
</li>
</ol>
<hr />
<h3 id="heading-final-verdict-is-it-worth-it">Final Verdict: Is It Worth It?</h3>
<p><img src="https://www.jeremymorgan.com/images/blog/tech/nvidia-jetson-orin-nano/nvidia-jetson-orin-nano-04.webp" alt="“NVIDIA Jetson Orin Nano”" /></p>
<p>Absolutely. The NVIDIA Jetson Orin Nano is a fantastic choice for developers exploring AI at the edge or prototyping innovative solutions.</p>
<p>It’s not built for heavy-duty production workloads, but for $250, it’s hard to beat the value and potential.</p>
<hr />
<h3 id="heading-whats-next">What’s Next?</h3>
<p>I’ll explore the Orin Nano’s features more in upcoming projects, so stay tuned. If you’re interested in edge AI or want to try out large language models, this device is a perfect start.</p>
<p>Have questions or suggestions for tests? Just drop a comment or message me on social media. Let’s see what this small device can really do!</p>
<p>Happy experimenting! 🚀</p>
<p>You can order the NVIDIA Jetson Orin Nano from the following places (Though right now there is no stock, check back!)</p>
<ul>
<li><p><a target="_blank" href="https://amzn.to/4gq4QS8">Amazon</a></p>
</li>
<li><p><a target="_blank" href="https://www.arrow.com/en/products/945-13766-0000-000/nvidia?nvid=em-945-13766-0005-000">Arrow Electronics</a></p>
</li>
<li><p><a target="_blank" href="https://www.sparkfun.com/products/22098?nvid=em-945-13766-0005-000">Sparkfun</a></p>
</li>
<li><p><a target="_blank" href="https://www.seeedstudio.com/NVIDIAr-Jetson-Orintm-Nano-Developer-Kit-p-5617.html?nvid=em-945-13766-0005-000">Seeed Studio</a></p>
</li>
</ul>
<p>Questions, comments? Want more details? <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Yell at me</a>!!</p>
]]></content:encoded></item><item><title><![CDATA[How to Make a Retro 2D JavaScript Game Part 3]]></title><description><![CDATA[Note: If you'd rather have a video tutorial, here it is:


Let’s make the game more fun with scoring and difficulty progression.
1. Adding a Score
Modify the create function to display a score:
this.score = 0;
this.scoreText = this.add.text(16, 16, '...]]></description><link>https://www.jeremymorgan.dev/how-to-make-a-retro-2d-javascript-game-part-3</link><guid isPermaLink="true">https://www.jeremymorgan.dev/how-to-make-a-retro-2d-javascript-game-part-3</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[how to build games]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[Games]]></category><category><![CDATA[how-to]]></category><category><![CDATA[phaser]]></category><category><![CDATA[2D Games]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[#beginners #learningtocode #100daysofcode]]></category><category><![CDATA[beginner]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Sun, 22 Dec 2024 22:07:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734905546943/e758cd73-af73-4532-b9c7-0a1e5d0654e4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Note: If you'd rather have a video tutorial, here it is:</em></p>
<iframe class="youtubevid" src="https://www.youtube.com/embed/rCgDvYNoaoc"></iframe>

<p>Let’s make the game more fun with scoring and difficulty progression.</p>
<h3 id="heading-1-adding-a-score"><strong>1. Adding a Score</strong></h3>
<p>Modify the <code>create</code> function to display a score:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">this</span>.score = <span class="hljs-number">0</span>;
<span class="hljs-built_in">this</span>.scoreText = <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-string">'Score: 0'</span>, { <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'24px'</span>, <span class="hljs-attr">fill</span>: <span class="hljs-string">'#fff'</span> });
</code></pre>
<p>Now you'll see a score in the upper left hand corner of the screen:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734904806967/3be1a2f8-cb83-4474-b676-ce50fa28df03.png" alt /></p>
<p>Let’s update the score when the player catches an item. In the update function where we created collision detection, add the following to update the score:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">this</span>.score += <span class="hljs-number">10</span>;
<span class="hljs-built_in">this</span>.scoreText.setText(<span class="hljs-string">'Score: '</span> + <span class="hljs-built_in">this</span>.score);
</code></pre>
<p>So change this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (Phaser.Geom.Intersects.RectangleToRectangle(<span class="hljs-built_in">this</span>.player.getBounds(), <span class="hljs-built_in">this</span>.item.getBounds())) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Caught an item!'</span>);
        <span class="hljs-built_in">this</span>.item.y = <span class="hljs-number">50</span>;
        <span class="hljs-built_in">this</span>.item.x = Phaser.Math.Between(<span class="hljs-number">50</span>, <span class="hljs-number">750</span>);
}
</code></pre>
<p>to this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (Phaser.Geom.Intersects.RectangleToRectangle(<span class="hljs-built_in">this</span>.player.getBounds(), <span class="hljs-built_in">this</span>.item.getBounds())) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Caught an item!'</span>);
        <span class="hljs-built_in">this</span>.item.y = <span class="hljs-number">50</span>;
        <span class="hljs-built_in">this</span>.item.x = Phaser.Math.Between(<span class="hljs-number">50</span>, <span class="hljs-number">750</span>);
        <span class="hljs-built_in">this</span>.score += <span class="hljs-number">10</span>;
        <span class="hljs-built_in">this</span>.scoreText.setText(<span class="hljs-string">'Score: '</span> + <span class="hljs-built_in">this</span>.score);
}
</code></pre>
<p>And now every time you catch a block, the score updates:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734904845293/1131fadf-2780-4a74-a976-4d818e9746c0.png" alt /></p>
<h3 id="heading-2-increasing-difficulty"><strong>2. Increasing Difficulty</strong></h3>
<p>Let's make this more difficult and make the items fall faster as the score increases:</p>
<p>In our create function, add this:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">this</span>.itemSpeed = <span class="hljs-number">3</span>;
</code></pre>
<p>in our update() function, delete this:</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Move falling item</span>
    <span class="hljs-built_in">this</span>.item.y += <span class="hljs-number">3</span>;
</code></pre>
<p>And replace it with this:</p>
<pre><code class="lang-javascript">  <span class="hljs-built_in">this</span>.item.y += <span class="hljs-built_in">this</span>.itemSpeed;

    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.score &gt; <span class="hljs-number">0</span> &amp;&amp; <span class="hljs-built_in">this</span>.score % <span class="hljs-number">500</span> === <span class="hljs-number">0</span>) {
        <span class="hljs-built_in">this</span>.itemSpeed += <span class="hljs-number">0.5</span>;
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Going faster! Speed is now: '</span> + <span class="hljs-built_in">this</span>.itemSpeed);
    }
</code></pre>
<p>Now, every time you get 500 points, your speed increases, and it gets more difficult!</p>
<h3 id="heading-3-retro-feel-enhancements"><strong>3. Retro Feel Enhancements</strong></h3>
<p>So let's add some graphics to this to make it more exciting.</p>
<p>I just drew up these images, don't judge me.</p>
<p><em>You can</em> <a target="_blank" href="https://github.com/JeremyMorgan/Catch-The-Apples"><em>download the pail.png from here</em></a></p>
<p>in preload, add the following:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Load the player sprite</span>
<span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'player'</span>, <span class="hljs-string">'pail.png'</span>);
</code></pre>
<p>Then remove this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Player (Blue rectangle)</span>
<span class="hljs-built_in">this</span>.player = <span class="hljs-built_in">this</span>.add.rectangle(<span class="hljs-number">400</span>, <span class="hljs-number">550</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">0x0000ff</span>);
</code></pre>
<p>And replace it with this:</p>
<pre><code class="lang-javascript">   <span class="hljs-comment">// Replace rectangle with sprite</span>
    <span class="hljs-built_in">this</span>.player = <span class="hljs-built_in">this</span>.add.sprite(<span class="hljs-number">400</span>, <span class="hljs-number">550</span>, <span class="hljs-string">'player'</span>);
    <span class="hljs-built_in">this</span>.player.setScale(<span class="hljs-number">1</span>); <span class="hljs-comment">// Adjust this value if needed to match desired size</span>
</code></pre>
<p>Let's turn the falling objects into apples.</p>
<p><em>You can</em> <a target="_blank" href="https://github.com/JeremyMorgan/Catch-The-Apples"><em>download the apple.png from here</em></a></p>
<p>In preload(), add:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'apple'</span>, <span class="hljs-string">'apple.png'</span>);  <span class="hljs-comment">// Loa</span>
</code></pre>
<p>In create(), delete this:</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Falling item (Green rectangle)</span>
    <span class="hljs-built_in">this</span>.item = <span class="hljs-built_in">this</span>.add.rectangle(<span class="hljs-number">400</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">0x00ff00</span>);
</code></pre>
<p>and replace it with this:</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Apple sprite</span>
    <span class="hljs-built_in">this</span>.item = <span class="hljs-built_in">this</span>.add.sprite(<span class="hljs-number">400</span>, <span class="hljs-number">50</span>, <span class="hljs-string">'apple'</span>);
    <span class="hljs-built_in">this</span>.item.setScale(<span class="hljs-number">1</span>); <span class="hljs-comment">// Adjust scale if needed</span>
</code></pre>
<p>And now you'll see a different look!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734904861042/849761ea-0298-40e3-a180-8719eb92e51c.png" alt /></p>
<p>Now we see an apple and a pail, but it's in a dark room. Let's enhance our look by adding in a background.</p>
<p><em>You can</em> <a target="_blank" href="https://github.com/JeremyMorgan/Catch-The-Apples"><em>download the background.png from here</em></a></p>
<p>In preload():</p>
<pre><code class="lang-javascript"> <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'background'</span>, <span class="hljs-string">'background.png'</span>);  <span class="hljs-comment">// Load background image</span>
</code></pre>
<p>and in create():</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Add background first so it appears behind other sprites</span>
    <span class="hljs-built_in">this</span>.add.image(<span class="hljs-number">400</span>, <span class="hljs-number">300</span>, <span class="hljs-string">'background'</span>);  <span class="hljs-comment">// Position at center of game (800/2, 600/2)</span>
</code></pre>
<p>And let's make the score black so we can see it:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">this</span>.scoreText = <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-string">'Score: 0'</span>, { <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'24px'</span>, <span class="hljs-attr">fill</span>: <span class="hljs-string">'#fff'</span> });
</code></pre>
<p>Now save it and reload it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734904895553/58378674-d8f1-4a44-aea5-d9ed59fe877e.png" alt class="image--center mx-auto" /></p>
<p>Hey that looks awesome!</p>
<h2 id="heading-final-thoughts"><strong>Final Thoughts</strong></h2>
<p>Congratulations! 🎉 You’ve built a working <em>"Catch the Items"</em> game using Phaser 3. Here’s <a target="_blank" href="https://jeremymorgan.itch.io/catch-the-apples">a playable version of it</a> as well.</p>
<h3 id="heading-next-steps-to-try-on-your-own"><strong>Next Steps to try on your own:</strong></h3>
<ul>
<li><p>Customize the shapes with images or sprites.</p>
</li>
<li><p>Add sound effects.</p>
</li>
<li><p>Experiment with game parameters like speed and item spawn rates.</p>
</li>
</ul>
<p>Keep practicing, and have fun creating your games. The possibilities are endless—go make something awesome! 🚀</p>
<p><em>Note: If you'd rather have a video tutorial, here it is:</em></p>
<iframe class="youtubevid" src="https://www.youtube.com/embed/rCgDvYNoaoc"></iframe>]]></content:encoded></item><item><title><![CDATA[How to Make a Retro 2D JavaScript Game Part 2]]></title><description><![CDATA[Let’s make this game interactive! We’ll add a player, movement controls, and falling items.
Note: If you'd rather have a video tutorial, here it is:


The full source code is here. Here’s a playable version of the final game.
1. Adding Placeholder Gr...]]></description><link>https://www.jeremymorgan.dev/how-to-make-a-retro-2d-javascript-game-part-2</link><guid isPermaLink="true">https://www.jeremymorgan.dev/how-to-make-a-retro-2d-javascript-game-part-2</guid><category><![CDATA[how to build games]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[Games]]></category><category><![CDATA[how-to]]></category><category><![CDATA[phaser]]></category><category><![CDATA[2D Games]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[#beginners #learningtocode #100daysofcode]]></category><category><![CDATA[beginner]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Sun, 22 Dec 2024 21:56:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734904596905/89e83aff-e059-4ed4-846f-9707f29c0ff0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let’s make this game interactive! We’ll add a player, movement controls, and falling items.</p>
<p><em>Note: If you'd rather have a video tutorial, here it is:</em></p>
<iframe class="youtubevid" src="https://www.youtube.com/embed/gFrix6Bz-C0"></iframe>

<p>The <a target="_blank" href="https://github.com/JeremyMorgan/Catch-The-Apples"><strong>full source code is here</strong></a>. <a target="_blank" href="https://github.com/JeremyMorgan/Catch-The-Apples">Here’s a <strong>playable versi</strong></a><a target="_blank" href="https://jeremymorgan.itch.io/catch-the-apples"><strong>on</strong></a> <a target="_blank" href="https://jeremymorgan.itch.io/catch-the-apples">of the final gam</a>e.</p>
<h3 id="heading-1-adding-placeholder-graphics"><strong>1. Adding Placeholder Graphics</strong></h3>
<p>Update the <code>create</code> function to add shapes representing the player and falling items:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Player (Blue rectangle)</span>
    <span class="hljs-built_in">this</span>.player = <span class="hljs-built_in">this</span>.add.rectangle(<span class="hljs-number">400</span>, <span class="hljs-number">550</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">0x0000ff</span>);

    <span class="hljs-comment">// Falling item (Green rectangle)</span>
    <span class="hljs-built_in">this</span>.item = <span class="hljs-built_in">this</span>.add.rectangle(<span class="hljs-number">400</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">0x00ff00</span>);

    <span class="hljs-comment">// Enable physics</span>
    <span class="hljs-built_in">this</span>.physics.add.existing(<span class="hljs-built_in">this</span>.player);
    <span class="hljs-built_in">this</span>.physics.add.existing(<span class="hljs-built_in">this</span>.item);

    <span class="hljs-comment">// Player controls</span>
    <span class="hljs-built_in">this</span>.cursors = <span class="hljs-built_in">this</span>.input.keyboard.createCursorKeys();
}
</code></pre>
<h3 id="heading-2-moving-the-player-left-and-right"><strong>2. Moving the Player Left and Right</strong></h3>
<p>Add movement logic to the <code>update</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Move player left</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.cursors.left.isDown) {
        <span class="hljs-built_in">this</span>.player.x -= <span class="hljs-number">5</span>;
    }
    <span class="hljs-comment">// Move player right</span>
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.cursors.right.isDown) {
        <span class="hljs-built_in">this</span>.player.x += <span class="hljs-number">5</span>;
    }
}
</code></pre>
<ul>
<li>The player can now move left and right using arrow keys!</li>
</ul>
<h3 id="heading-3-adding-simple-collision-logic"><strong>3. Adding Simple Collision Logic</strong></h3>
<p>We need to update our config:</p>
<p>change:</p>
<pre><code class="lang-javascript">   type: Phaser.AUTO, <span class="hljs-comment">// Auto-detect WebGL or Canvas</span>
   <span class="hljs-attr">width</span>: <span class="hljs-number">800</span>,        <span class="hljs-comment">// Game width</span>
   <span class="hljs-attr">height</span>: <span class="hljs-number">600</span>,       <span class="hljs-comment">// Game height</span>
</code></pre>
<p>To this, to add physics and gravity to our scene.</p>
<pre><code class="lang-javascript">type: Phaser.AUTO,
            <span class="hljs-attr">width</span>: <span class="hljs-number">800</span>,
            <span class="hljs-attr">height</span>: <span class="hljs-number">600</span>,
            <span class="hljs-attr">physics</span>: {
                <span class="hljs-attr">default</span>: <span class="hljs-string">'arcade'</span>,
                <span class="hljs-attr">arcade</span>: {
                    <span class="hljs-attr">gravity</span>: { <span class="hljs-attr">y</span>: <span class="hljs-number">0</span> }
                }
            },
</code></pre>
<p>Make the falling item reset its position when it reaches the bottom:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Move falling item</span>
    <span class="hljs-built_in">this</span>.item.y += <span class="hljs-number">3</span>;

    <span class="hljs-comment">// Reset item position</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.item.y &gt; <span class="hljs-number">600</span>) {
        <span class="hljs-built_in">this</span>.item.y = <span class="hljs-number">50</span>;
        <span class="hljs-built_in">this</span>.item.x = Phaser.Math.Between(<span class="hljs-number">50</span>, <span class="hljs-number">750</span>); <span class="hljs-comment">// Random x-position</span>
    }

    <span class="hljs-comment">// Check for overlap</span>
    <span class="hljs-keyword">if</span> (Phaser.Geom.Intersects.RectangleToRectangle(<span class="hljs-built_in">this</span>.player.getBounds(), <span class="hljs-built_in">this</span>.item.getBounds())) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Caught an item!'</span>);
        <span class="hljs-built_in">this</span>.item.y = <span class="hljs-number">50</span>;
        <span class="hljs-built_in">this</span>.item.x = Phaser.Math.Between(<span class="hljs-number">50</span>, <span class="hljs-number">750</span>);
    }
}
</code></pre>
<p>Now you'll see a screen that looks like this: and you should see green blocks falling. You can also move the player with your arrow keys:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734904382453/afa6187f-0bf4-4472-a530-0435b609592a.png" alt /></p>
<blockquote>
<p>📝 <strong>Recap</strong>: You added player movement, falling items, and basic collision detection. Your game is interactive! Now on to part 3</p>
</blockquote>
<p><em>Note: If you'd rather have a video tutorial,</em> <a target="_blank" href="https://www.youtube.com/watch?v=gFrix6Bz-C0"><em>it’s available here</em></a><em>.</em></p>
]]></content:encoded></item><item><title><![CDATA[How to Make a Retro 2D JavaScript Game Part 1]]></title><description><![CDATA[Welcome, aspiring game developers! 🚀 In this beginner-friendly guide, we’ll build a simple, retro-themed "Catch the Items" game using Phaser 3, a powerful JavaScript game development framework. This series of tutorials is designed for absolute begin...]]></description><link>https://www.jeremymorgan.dev/how-to-make-a-retro-2d-javascript-game-part-1</link><guid isPermaLink="true">https://www.jeremymorgan.dev/how-to-make-a-retro-2d-javascript-game-part-1</guid><category><![CDATA[how to build games]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[Games]]></category><category><![CDATA[how-to]]></category><category><![CDATA[phaser]]></category><category><![CDATA[2D Games]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[#beginners #learningtocode #100daysofcode]]></category><category><![CDATA[beginner]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Sun, 22 Dec 2024 21:49:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734903796173/c02eca55-febe-4555-9abe-62db97470a29.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome, aspiring game developers! 🚀 In this beginner-friendly guide, we’ll build a simple, retro-themed <em>"Catch the Items"</em> game using <strong>Phaser 3</strong>, a powerful JavaScript game development framework. This series of tutorials is designed for absolute beginners, so don’t worry if you’re new to coding or Phaser—you’re in good hands.</p>
<p><em>Note: If you'd rather have a video tutorial, here it is:</em></p>
<iframe class="youtubevid" src="https://www.youtube.com/embed/WkiZSpFJozM"></iframe>

<hr />
<p>The <a target="_blank" href="https://github.com/JeremyMorgan/Catch-The-Apples">full source code is here</a>. Here’s a <a target="_blank" href="https://jeremymorgan.itch.io/catch-the-apples">playable version</a> of the final game.</p>
<h2 id="heading-tutorial-1-project-setup-amp-basics"><strong>Tutorial 1: Project Setup &amp; Basics</strong></h2>
<p>Let’s start by setting up the environment, introducing key JavaScript concepts, and creating our first Phaser scene.</p>
<blockquote>
<p><em>Note:</em> In many of our tutorials we use Node/Vite to set up our games. But I want to keep this as simple as possible. To run this you can install the <a target="_blank" href="https://www.npmjs.com/package/serve">NPM package serve</a> or just open the document with Chrome.</p>
</blockquote>
<h3 id="heading-1-what-is-phaser-3"><strong>1. What is Phaser 3?</strong></h3>
<p>Phaser 3 is a popular <strong>2D game development framework</strong> for creating browser-based games using JavaScript. It’s beginner-friendly, flexible, and powerful—perfect for making retro-inspired games like this one!</p>
<hr />
<h3 id="heading-2-setting-up-your-development-environment"><strong>2. Setting Up Your Development Environment</strong></h3>
<p>To keep things simple, we’ll use Phaser via its <strong>CDN link</strong>. Here’s the setup:</p>
<ol>
<li><p><strong>Create a project folder</strong>:</p>
<ul>
<li><p>Make a new folder on your computer, e.g., <code>catch-game</code>.</p>
</li>
<li><p>Inside the folder, create a file named <code>index.html</code>.</p>
</li>
</ul>
</li>
<li><p><strong>Add the basic HTML structure</strong>: Paste the following code into your <code>index.html</code> file:</p>
</li>
</ol>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Catch the Items<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
        <span class="hljs-comment">// Phaser Game Configuration</span>
        <span class="hljs-keyword">const</span> config = {
            <span class="hljs-attr">type</span>: Phaser.AUTO, <span class="hljs-comment">// Auto-detect WebGL or Canvas</span>
            <span class="hljs-attr">width</span>: <span class="hljs-number">800</span>,        <span class="hljs-comment">// Game width</span>
            <span class="hljs-attr">height</span>: <span class="hljs-number">600</span>,       <span class="hljs-comment">// Game height</span>
            <span class="hljs-attr">scene</span>: {
                <span class="hljs-attr">preload</span>: preload,
                <span class="hljs-attr">create</span>: create,
                <span class="hljs-attr">update</span>: update
            }
        };

        <span class="hljs-keyword">const</span> game = <span class="hljs-keyword">new</span> Phaser.Game(config);

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">preload</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-comment">// Preload assets (none yet)</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-comment">// Add game objects here</span>
            <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">300</span>, <span class="hljs-number">250</span>, <span class="hljs-string">'Hello, Phaser!'</span>, { <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'32px'</span>, <span class="hljs-attr">fill</span>: <span class="hljs-string">'#fff'</span> });
        }

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-comment">// Game loop (empty for now)</span>
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<ol start="3">
<li><p><strong>Run your game</strong>:</p>
<ul>
<li><p>Open the <code>index.html</code> file in any browser (Chrome is recommended).</p>
</li>
<li><p>You should see a simple canvas with the text <strong>"Hello, Phaser!"</strong>.</p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734903726567/9cd5fba5-d8f1-41cb-9de3-28aeee1980ac.png" alt /></p>
<blockquote>
<p>🎉 <strong>Congratulations</strong>! You’ve set up Phaser and displayed your first scene!</p>
</blockquote>
<hr />
<h3 id="heading-3-javascript-basics-for-phaser"><strong>3. JavaScript Basics for Phaser</strong></h3>
<p>Before diving deeper, let’s quickly review some JavaScript concepts:</p>
<ul>
<li><p><strong>Variables</strong>: Store data.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">let</span> playerName = <span class="hljs-string">'PhaserHero'</span>;
</code></pre>
</li>
<li><p><strong>Functions</strong>: Reusable blocks of code.</p>
<pre><code class="lang-javascript">  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greetPlayer</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Welcome to the game!'</span>);
  }
  greetPlayer();
</code></pre>
</li>
<li><p><strong>Objects</strong>: Collections of properties and methods.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">let</span> player = {
      <span class="hljs-attr">name</span>: <span class="hljs-string">'Hero'</span>,
      <span class="hljs-attr">score</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">jump</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Player jumps!'</span>);
      }
  };
  player.jump();
</code></pre>
</li>
</ul>
<p>You’ll use these concepts as you develop your game in Phaser.</p>
<hr />
<h3 id="heading-4-creating-a-minimal-phaser-scene"><strong>4. Creating a Minimal Phaser Scene</strong></h3>
<p>Modify the <code>create</code> function to display a basic game canvas and some text:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">300</span>, <span class="hljs-number">250</span>, <span class="hljs-string">'Catch the Items!'</span>, { <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'32px'</span>, <span class="hljs-attr">fill</span>: <span class="hljs-string">'#fff'</span> });
    <span class="hljs-built_in">this</span>.add.rectangle(<span class="hljs-number">400</span>, <span class="hljs-number">300</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">0xff0000</span>); <span class="hljs-comment">// Red square</span>
}
</code></pre>
<ul>
<li>Reload the browser—you should see a red square in the center of the screen.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734903749862/6cf4e363-ac07-45a7-ae06-3fee530acb59.png" alt /></p>
<h3 id="heading-what-does-create-mean">What does create() mean?</h3>
<p>Phaser uses three core functions to manage the game lifecycle: preload, create, and update.</p>
<p>Let's break down what each function does:</p>
<ul>
<li><p><strong>preload()</strong>: This function is called before the game starts. It's where you load your game assets like images, sounds, and more.</p>
</li>
<li><p><strong>create()</strong>: This function is called after the assets are loaded. It's where you create your game objects, set up the game world, and define initial game settings.</p>
</li>
<li><p><strong>update()</strong>: This function is called repeatedly throughout the game loop. It's where you update the game state, handle user input, and make things happen in your game world.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734903763187/5831ee96-5eaf-4af4-adc4-a0701a3f5b5f.png" alt /></p>
<p>This diagram may not make sense now but it will as you get deeper into Phaser.</p>
<p>We'll be using these functions extensively as we build our games in this tutorial and future tutorials.</p>
<blockquote>
<p>📝 <strong>Recap</strong>: You’ve set up a Phaser game, learned some JavaScript basics, and displayed simple shapes on the canvas. Great start! Now on to Part 2!</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Getting Started with Python]]></title><description><![CDATA[Hey there, fellow geeks and future coders! Welcome to Part 1 of our series, "Learn Python"! If you've ever wanted to learn Python but felt overwhelmed by where to start, you’re in the right place. We’re going to break it down in easy, bite-sized chun...]]></description><link>https://www.jeremymorgan.dev/getting-started-with-python</link><guid isPermaLink="true">https://www.jeremymorgan.dev/getting-started-with-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[python projects]]></category><category><![CDATA[python tutorial]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Mon, 16 Dec 2024 18:54:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734375115349/a211a7da-f3ca-42e2-b397-3124cbc5f69c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey there, fellow geeks and future coders! Welcome to <strong>Part 1</strong> of our series, "Learn Python"! If you've ever wanted to learn Python but felt overwhelmed by where to start, you’re in the right place. We’re going to break it down in easy, bite-sized chunks, walking you through each concept step by step. So grab your coffee (or energy drink of choice), and let’s dive right in!</p>
<h2 id="heading-why-python">Why Python?</h2>
<p>First off, why should you learn Python? Well, Python is one of the easiest programming languages to get started with. It’s used everywhere—web development, data science, automation, artificial intelligence, you name it! Whether you’re automating boring tasks or building the next big app, Python has your back.</p>
<p>But the best part? <strong>Python is super beginner-friendly</strong>. Its syntax (fancy word for how code is written) is clean and straightforward, so you can focus more on <em>what</em> you want to do rather than <em>how</em> to do it.</p>
<p>Pretty cool, right?</p>
<h3 id="heading-what-can-you-build-with-python">What Can You Build with Python?</h3>
<ul>
<li><p>Websites (ever heard of Django or Flask?)</p>
</li>
<li><p>Automation scripts (goodbye repetitive tasks!)</p>
</li>
<li><p>Data analysis and machine learning models</p>
</li>
<li><p>Games (even 2D ones like the classics!)</p>
</li>
<li><p>IoT projects (you know, like controlling lights with a Raspberry Pi)</p>
</li>
</ul>
<p>Okay, enough hype—let’s get started!</p>
<h2 id="heading-step-1-setting-up-python">Step 1: Setting Up Python</h2>
<p>Before we can write any Python code, we need to set up our environment. Don’t worry, this is easier than it sounds.</p>
<h3 id="heading-install-python">Install Python</h3>
<p>First, you'll need to install Python if you don't have it already. Go to the official Python website <a target="_blank" href="http://python.org">python.org</a>, download the latest version, and follow the instructions.</p>
<p><strong>For Windows</strong>: During installation, make sure to check the box that says “Add Python to PATH.” This will let you run Python from anywhere on your system.</p>
<p><strong>For macOS/Linux</strong>: Python usually comes pre-installed, but if you need the latest version, you can install it via a package manager like Homebrew (<code>brew install python3</code>).</p>
<p>If you want, you can also <a target="_blank" href="https://www.jeremymorgan.com/tools/run-python/">run Python in a Web Browser</a> here.</p>
<h3 id="heading-verify-the-installation">Verify the Installation</h3>
<p>Once installed, open a terminal (or Command Prompt on Windows) and type:</p>
<pre><code class="lang-bash">python --version
</code></pre>
<p>If you see something like <code>Python 3.x.x</code>, congratulations! Python is ready to roll.</p>
<h3 id="heading-running-python-code">Running Python Code</h3>
<p>You can run Python code in two ways:</p>
<ol>
<li><p><strong>Interactive Mode</strong>: Just type <code>python</code> in your terminal, and you can start writing Python code line-by-line. This is great for quick tests.</p>
<p> <em>Demo idea:</em> Try it out right now! Type <code>python</code> in your terminal and then type:</p>
<pre><code class="lang-python"> print(<span class="hljs-string">"Testing in interactive mode!"</span>)
</code></pre>
<p> Hit enter, and you’ll see the result immediately. This is a fun way to experiment.</p>
</li>
<li><p><strong>Script Mode</strong>: Write your Python code in a <code>.py</code> file (like <a target="_blank" href="http://hello.py"><code>hello.py</code></a>), then run it by typing:</p>
<pre><code class="lang-bash"> python hello.py
</code></pre>
</li>
</ol>
<h2 id="heading-step-2-your-first-python-program">Step 2: Your First Python Program</h2>
<p>Alright, let’s write your very first Python program. We’re going to create the classic “Hello, World!” program.</p>
<h3 id="heading-write-your-code">Write Your Code</h3>
<p>Open your favorite text editor (VSCode, Sublime, or even Notepad), and type the following:</p>
<pre><code class="lang-python">print(<span class="hljs-string">"Hello, World!"</span>)
</code></pre>
<p>Save the file as <a target="_blank" href="http://hello.py"><code>hello.py</code></a>, then run it from the terminal:</p>
<pre><code class="lang-bash">python hello.py
</code></pre>
<p>Boom! You should see:</p>
<pre><code class="lang-python">Hello, World!
</code></pre>
<p>🎉 <strong>Congrats, you just wrote your first Python program!</strong> 🎉</p>
<h3 id="heading-make-it-interactive-optional-demo">Make It Interactive (Optional Demo)</h3>
<p>Want to take this a step further? Try prompting the user for input:</p>
<pre><code class="lang-python">name = input(<span class="hljs-string">"What's your name? "</span>)
print(<span class="hljs-string">"Nice to meet you, "</span> + name + <span class="hljs-string">"!"</span>)
</code></pre>
<p>Save it as <code>hello_</code><a target="_blank" href="http://interactive.py"><code>interactive.py</code></a> and run it. When prompted, type your name and see how Python responds! This little demo shows how Python can interact with users, making it feel more like a conversation and less like static code.</p>
<h2 id="heading-step-3-understanding-the-basics">Step 3: Understanding the Basics</h2>
<p>Let’s go over some fundamental concepts in Python. These are building blocks that we’ll use in the next parts of this series.</p>
<h3 id="heading-variables">Variables</h3>
<p>Think of variables as boxes where you can store information, like numbers or text.</p>
<pre><code class="lang-python"><span class="hljs-comment"># This is a variable storing a number</span>
age = <span class="hljs-number">30</span>

<span class="hljs-comment"># This is a variable storing a string (text)</span>
name = <span class="hljs-string">"Alice"</span>
</code></pre>
<p>You can use these variables later in your code:</p>
<pre><code class="lang-python">print(<span class="hljs-string">"My name is"</span>, name)
print(<span class="hljs-string">"I am"</span>, age, <span class="hljs-string">"years old"</span>)
</code></pre>
<h3 id="heading-data-types">Data Types</h3>
<p>Python has several data types you’ll use frequently:</p>
<ul>
<li><p><strong>Integers</strong>: Whole numbers (e.g., <code>42</code>)</p>
</li>
<li><p><strong>Floats</strong>: Decimal numbers (e.g., <code>3.14</code>)</p>
</li>
<li><p><strong>Strings</strong>: Text (e.g., <code>"Hello, World!"</code>)</p>
</li>
<li><p><strong>Booleans</strong>: <code>True</code> or <code>False</code></p>
</li>
</ul>
<p>You can even check the type of any variable with:</p>
<pre><code class="lang-python">print(type(age))  <span class="hljs-comment"># Outputs: &lt;class 'int'&gt;</span>
print(type(name)) <span class="hljs-comment"># Outputs: &lt;class 'str'&gt;</span>
</code></pre>
<h3 id="heading-comments">Comments</h3>
<p>Sometimes you need to add notes to your code. Python ignores comments, so they’re just for you (or anyone else reading the code).</p>
<pre><code class="lang-python"><span class="hljs-comment"># This is a comment. Python won't run this.</span>
</code></pre>
<h3 id="heading-math-operations">Math Operations</h3>
<p>Python can handle math like a calculator:</p>
<pre><code class="lang-python">x = <span class="hljs-number">10</span>
y = <span class="hljs-number">5</span>

print(x + y)  <span class="hljs-comment"># Addition</span>
print(x - y)  <span class="hljs-comment"># Subtraction</span>
print(x * y)  <span class="hljs-comment"># Multiplication</span>
print(x / y)  <span class="hljs-comment"># Division</span>
</code></pre>
<h3 id="heading-make-a-simple-calculator-demo">Make a Simple Calculator (Demo)</h3>
<p>Now that you know variables and math, let’s make a tiny calculator program:</p>
<pre><code class="lang-python">num1 = int(input(<span class="hljs-string">"Enter a number: "</span>))
num2 = int(input(<span class="hljs-string">"Enter another number: "</span>))
print(<span class="hljs-string">"Sum:"</span>, num1 + num2)
print(<span class="hljs-string">"Product:"</span>, num1 * num2)
</code></pre>
<p>Run this, and you can quickly see Python doing something practical—performing math operations on the fly!</p>
<h3 id="heading-a-quick-variable-experiment">A Quick Variable Experiment</h3>
<p>Try this short experiment to understand how strings can be combined:</p>
<pre><code class="lang-python">message = <span class="hljs-string">"Hello"</span>
message += <span class="hljs-string">", World!"</span>
print(message)
</code></pre>
<p>This shows you how variables can evolve as your program runs.</p>
<h2 id="heading-step-4-next-steps">Step 4: Next Steps</h2>
<p>Now that you've got Python set up and written your first program, you're ready to take the next step. In <strong>Part 2</strong> of this series, we’ll explore <strong>conditions and loops</strong>, where Python will start making decisions for you and performing repetitive tasks. It’s going to be fun!</p>
<h3 id="heading-practice-challenge">Practice Challenge</h3>
<p>Before we wrap up, try writing a Python script that does the following:</p>
<ul>
<li><p>Stores your name in a variable.</p>
</li>
<li><p>Prints a greeting like "Hello, [Your Name]!"</p>
</li>
<li><p>Multiplies two numbers and prints the result.</p>
</li>
</ul>
<p>Here’s a hint for the multiplication part:</p>
<pre><code class="lang-python">result = <span class="hljs-number">8</span> * <span class="hljs-number">7</span>
print(result)
</code></pre>
<p>Got it? Awesome! You’re on your way to becoming a Python pro. 🚀</p>
<p>See you in <strong>Part 2</strong>, where we’ll make Python even more powerful!</p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[AI New Hotness December 13th 2024]]></title><description><![CDATA[Welcome to this week’s edition of the AI New Hotness Newsletter, where we talk about new and exciting stuff to happen in the world of Generative AI, particularly for software developers. It’s a fast moving, wacky world for sure.
Reminder: This is als...]]></description><link>https://www.jeremymorgan.dev/ai-new-hotness-december-13th-2024</link><guid isPermaLink="true">https://www.jeremymorgan.dev/ai-new-hotness-december-13th-2024</guid><category><![CDATA[AI]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[claude.ai]]></category><category><![CDATA[Apple]]></category><category><![CDATA[Apple Intelligence]]></category><category><![CDATA[AI News and Updates]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Sat, 14 Dec 2024 05:34:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734154344814/d2b061ba-d027-48e9-a96f-1034735fe876.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to this week’s edition of the AI New Hotness Newsletter, where we talk about new and exciting stuff to happen in the world of Generative AI, particularly for software developers. It’s a fast moving, wacky world for sure.</p>
<p><strong>Reminder:</strong> This is also <a target="_blank" href="https://www.linkedin.com/pulse/ai-new-hotness-december-13th-2024-jeremy-morgan-8c4kc/">available on LinkedIn</a> if you’d rather receive it there.</p>
<h2 id="heading-ai-in-the-news">AI in the News</h2>
<p><img src="https://www.jeremymorgan.com/images/newsletter/ai-news.png" alt="“AI in the News”" /></p>
<h3 id="heading-introducing-chatgpt-pro">Introducing ChatGPT Pro</h3>
<p><em>OpenAI releases ChatGPT Pro, a subscription service with powerful new features</em></p>
<p>OpenAI has released a new subscription service called ChatGPT Pro. This service provides unlimited access to OpenAI’s most advanced models, including o1, o1-mini, GPT-4o, and Advanced Voice. It also includes o1 pro mode, which uses more compute to provide more reliable and accurate answers to difficult questions. ChatGPT Pro is designed for researchers, engineers, and other professionals who need to use AI for complex tasks.</p>
<p><strong>Details:</strong></p>
<p>ChatGPT Pro provides unlimited access to OpenAI’s most advanced models, including o1, o1-mini, GPT-4o, and Advanced Voice. It also includes o1 pro mode, which uses more compute to provide more reliable and accurate answers to difficult questions. ChatGPT Pro is designed for researchers, engineers, and other professionals who need to use AI for complex tasks.</p>
<p><strong>Why it Matters:</strong></p>
<p>ChatGPT Pro is a powerful new tool that can be used for a variety of tasks, including writing, research, and development. With its unlimited access to OpenAI’s most advanced models, ChatGPT Pro can help you to be more productive and creative.</p>
<h3 id="heading-click-here-to-read-morehttpsopenaicomindexintroducing-chatgpt-pro"><a target="_blank" href="https://openai.com/index/introducing-chatgpt-pro/">Click here to read more</a></h3>
<hr />
<h3 id="heading-make-movies-with-text-this-ai-writes-videos-for-you">Make Movies with Text! This AI Writes Videos for You</h3>
<p>OpenAI Unveils Sora, a Powerful New Video Generation Model</p>
<p>OpenAI has released a new AI model called Sora that can create realistic videos from just a text description. This means you can create movies, explainer videos, or even home videos using just your imagination and some text!</p>
<p><strong>Details:</strong></p>
<p>Sora can generate videos in a variety of styles, from photorealistic to cartoonish. It can also be used to create videos with special effects or to animate existing images.</p>
<p><strong>Why it Matters:</strong></p>
<p>Sora is a powerful new tool that could revolutionize the way videos are created. It could make it possible for anyone to create professional-quality videos, even if they don’t have any filmmaking experience.</p>
<h3 id="heading-click-here-to-read-morehttpsopenaicomindexsora-is-here"><a target="_blank" href="https://openai.com/index/sora-is-here/">Click here to read more</a></h3>
<hr />
<h3 id="heading-unleash-your-creativity-with-amazon-nova-the-powerful-new-ai">Unleash Your Creativity with Amazon Nova, the Powerful New AI</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/www_aboutamazon_com_amazon-nova-artificial-intelligence-bedrock-aws.jpg" alt="Article Image" /></p>
<p><strong>Generate Stunning Videos and Images, and More!</strong></p>
<p>Do you ever feel limited by your imagination? Amazon Nova is here to help! This new generation of AI can be used to generate all sorts of creative content, from videos and images to who-knows-what-else. Amazon Nova is also being used to improve the customer shopping experience on Amazon. Keep reading to learn more about how Amazon Nova can help you!</p>
<p><strong>Details:</strong></p>
<ul>
<li><p>Amazon Nova is a new generation of foundation models that can be used to generate creative content.</p>
</li>
<li><p>Amazon Nova is also being used to improve the customer shopping experience on Amazon.</p>
</li>
</ul>
<p><strong>Why it Matters:</strong></p>
<p>Amazon Nova is a powerful new tool that can be used to generate creative content and improve the customer shopping experience. If you’re looking for a way to boost your creativity or make shopping on Amazon even easier, then Amazon Nova is definitely worth checking out.</p>
<h3 id="heading-click-here-to-read-morehttpswwwaboutamazoncomnewsawsamazon-nova-artificial-intelligence-bedrock-aws"><a target="_blank" href="https://www.aboutamazon.com/news/aws/amazon-nova-artificial-intelligence-bedrock-aws">Click here to read more</a></h3>
<hr />
<h3 id="heading-google-releases-revolutionary-ai-model-gemini-20">Google Releases Revolutionary AI Model, Gemini 2.0</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/blog_google_google-gemini-ai-update-december-2024.jpg" alt="Article Image" /></p>
<p>Google unveils its latest AI model, Gemini 2.0, promising to revolutionize the field of AI agent creation. Gemini 2.0 boasts advanced capabilities that push the boundaries of what’s possible in AI. But with great power comes great responsibility, and Google emphasizes its commitment to developing AI responsibly, with safety and security at the forefront.</p>
<p><strong>Details:</strong></p>
<ul>
<li><p>Gemini 2.0 is more capable than previous versions, with native image and audio output and tool use.</p>
</li>
<li><p>Gemini 2.0 Flash is available to developers and trusted testers, with wider availability planned for early next year.</p>
</li>
<li><p>Google is exploring agentic experiences with Gemini 2.0, including Project Astra, Project Mariner, and Jules.</p>
</li>
<li><p>Google is committed to building AI responsibly, with safety and security as key priorities.</p>
</li>
</ul>
<p><strong>Why it Matters:</strong></p>
<p>Gemini 2.0 has the potential to revolutionize various fields by enabling the creation of powerful and intelligent AI agents. Google’s commitment to responsible AI development ensures these advancements are made with safety and security in mind.</p>
<h3 id="heading-click-here-to-read-morehttpsbloggoogletechnologygoogle-deepmindgoogle-gemini-ai-update-december-2024"><a target="_blank" href="https://blog.google/technology/google-deepmind/google-gemini-ai-update-december-2024/">Click here to read more</a></h3>
<hr />
<h3 id="heading-apples-new-ai-can-turn-your-thoughts-into-emojis">Apple’s New AI Can Turn Your Thoughts Into Emojis!</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/www_apple_com_apple-intelligence-now-features-image-playground-genmoji-and-more.jpg" alt="Article Image" /></p>
<p>Tired of boring emojis? Apple Intelligence has just received a major upgrade, bringing you Image Playground and Genmoji to revolutionize the way you express yourself.</p>
<p>Image Playground lets you unleash your creativity and create unique images using your imagination. It’s like having a mini art studio right on your device!</p>
<p>Genmoji takes emojis to a whole new level. Generate custom emojis that perfectly capture your mood or personality.</p>
<p>Apple Intelligence is available now as a free software update, so you can start creating and expressing yourself in exciting new ways. But hurry, this update is only available for iPhone 16 and later, iPad with A17 Pro or M1 and later, and Mac with M1 and later!</p>
<p><strong>Why it Matters:</strong></p>
<p>Apple Intelligence’s new features offer a fun and creative way to express yourself through images and emojis. It’s a free update available for compatible devices, so there’s no reason not to try it out!</p>
<h3 id="heading-click-here-to-read-morehttpswwwapplecomnewsroom202412apple-intelligence-now-features-image-playground-genmoji-and-more"><a target="_blank" href="https://www.apple.com/newsroom/2024/12/apple-intelligence-now-features-image-playground-genmoji-and-more/">Click here to read more</a></h3>
<hr />
<h3 id="heading-apple-secretly-developing-ai-chip-to-rival-nvidia">Apple Secretly Developing AI Chip to Rival NVIDIA</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/finance_yahoo_com_apple-working-ai-chip-broadcom-141956432.jpg" alt="Article Image" /></p>
<p>Apple is reportedly working with Broadcom to develop its own AI chip, code-named Baltra, to power its AI services and reduce reliance on Nvidia. This move positions Apple alongside other tech giants like Google in the race to develop cutting-edge AI hardware.</p>
<p><strong>Details:</strong></p>
<ul>
<li><p>Apple is developing its first server chip specifically for AI processing.</p>
</li>
<li><p>This move aims to reduce reliance on Nvidia’s high-priced and often unavailable processors.</p>
</li>
<li><p>Baltra is expected to be ready for mass production by 2026.</p>
</li>
<li><p>Apple and Broadcom have a history of collaboration, including a recent multi-billion-dollar deal for 5G components.</p>
</li>
<li><p>This development highlights the growing importance of AI hardware and the increasing competition in the AI chip market.</p>
</li>
</ul>
<h3 id="heading-click-here-to-read-morehttpsfinanceyahoocomnewsapple-working-ai-chip-broadcom-141956432html"><a target="_blank" href="https://finance.yahoo.com/news/apple-working-ai-chip-broadcom-141956432.html">Click here to read more</a></h3>
<hr />
<h3 id="heading-talk-to-santa-and-see-him-lives">Talk to Santa AND See Him Live!s</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/www_youtube_com_watch.jpg" alt="Article Image" /></p>
<p>OpenAI just dropped a major update for the holiday season! You can now chat with Santa Claus in real-time using video calls and screen sharing. This new “Advanced Voice Mode” feature allows you to:</p>
<ul>
<li><p>Ask Santa anything: Get advice on beard care, hear about life at the North Pole, or have him tell you a story!</p>
</li>
<li><p>See Santa’s jolly face: Experience the magic of Christmas firsthand with live video chat.</p>
</li>
<li><p>Get help with tricky responses: Brainstorm the perfect reply to a friend’s Christmas message using screen sharing.</p>
</li>
<li><p>This feature is rolling out now:</p>
</li>
</ul>
<p>Available on mobile apps first, then desktop apps and web. Free for everyone to chat with Santa on the first try, even if you’ve used your voice limit. Full access to video and screen sharing for Plus, Pro, and Teams users (Europe rollout coming soon). Enterprise and EDU plans get access early next year.</p>
<h3 id="heading-click-here-to-read-morehttpswwwyoutubecomwatchvniqdnwlwyyqq"><a target="_blank" href="https://www.youtube.com/watch?v=NIQDnWlwYyQQ">Click here to read more</a></h3>
<hr />
<h3 id="heading-anthropics-new-ai-model-is-it-worth-the-hype-and-the-higher-price">Anthropic’s New AI Model: Is it Worth the Hype (and the Higher Price)?</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/techcrunch_com_anthropics-3-5-haiku-model-comes-to-claude-users.jpg" alt="Article Image" /></p>
<p>Claude 3.5 Haiku is here, but does it live up to the promise?</p>
<p>Anthropic has released Claude 3.5 Haiku, a powerful new AI model that boasts improved coding, data analysis, and content moderation capabilities. However, this upgrade comes with a higher price tag, sparking debate among developers.</p>
<p><strong>Details:</strong></p>
<p>Claude 3.5 Haiku surpasses its predecessor, 3 Opus, in key areas, offering enhanced performance in coding, data extraction, and content moderation.</p>
<p>It can generate longer pieces of text and boasts a more up-to-date knowledge base. However, 3.5 Haiku lacks image analysis capabilities, limiting its versatility compared to other Anthropic models. The model’s release was initially met with controversy due to an unexpected price increase.</p>
<h3 id="heading-click-here-to-read-morehttpstechcrunchcom20241212anthropics-3-5-haiku-model-comes-to-claude-users"><a target="_blank" href="https://techcrunch.com/2024/12/12/anthropics-3-5-haiku-model-comes-to-claude-users/">Click here to read more</a></h3>
<hr />
<h2 id="heading-ai-tools">AI Tools</h2>
<p><img src="https://www.jeremymorgan.com/images/newsletter/ai-tools.png" alt="“AI Tools”" /></p>
<h3 id="heading-create-engaging-video-training-content-in-minutes-with-lupo">Create Engaging Video Training Content in Minutes with Lupo</h3>
<p>Lupo is a platform that helps businesses create high-quality video training content quickly and easily. With Lupo, you can use Markdown and Marp to create courses, and even leverage their agency services if needed.</p>
<p><strong>Why you might need this tool:</strong></p>
<ul>
<li><p>Create high-quality video training content quickly and easily</p>
</li>
<li><p>Use Markdown and Marp to create courses</p>
</li>
<li><p>Leverage their agency services if needed</p>
</li>
</ul>
<h3 id="heading-click-here-to-read-morehttpslupoai"><a target="_blank" href="https://lupo.ai/">Click here to read more</a></h3>
<hr />
<h3 id="heading-want-to-build-ai-tools-like-a-pro-this-low-code-platform-makes-it-easy-even-without-coding-skills">Want to Build AI Tools Like a Pro? This Low-Code Platform Makes it Easy (Even Without Coding Skills!)</h3>
<p>AISmartCube is a low-code AI tool platform that allows users to build AI tools without any coding required. The platform provides access to global large models, various plugins, a shared knowledge base, and ready-to-use tools and assistants. It also offers flexible pricing with points and a free credit allowance.</p>
<h3 id="heading-click-here-to-read-morehttpsaismartcubecom"><a target="_blank" href="https://aismartcube.com/">Click here to read more</a></h3>
<hr />
<h3 id="heading-want-to-run-any-program-automatically">Want to run any program automatically?</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/pinokio_computer_.jpg" alt="Article Image" /></p>
<p>Pinokio is a browser that lets you install, run, and programmatically control any application, automatically. You can use Pinokio scripts, which are shared by the community, to automate tasks or create new functionalities.</p>
<p><strong>Why you might need this tool:</strong></p>
<p>With Pinokio, you can:</p>
<ul>
<li><p>Automate repetitive tasks</p>
</li>
<li><p>Create custom functionalities for your favorite applications</p>
</li>
<li><p>Be more productive by letting Pinokio handle the boring stuff</p>
</li>
</ul>
<h3 id="heading-click-here-to-read-morehttpspinokiocomputer"><a target="_blank" href="https://pinokio.computer/">Click here to read more</a></h3>
<hr />
<h3 id="heading-build-stunning-websites-in-3d-without-code-dora">Build Stunning Websites in 3D, Without Code - Dora!</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/www_dora_run_.jpg" alt="Article Image" /></p>
<p>Dora is a no-code platform that allows you to create 3D animated websites. With Dora, you can create beautiful and engaging websites without having to write any code.</p>
<p><strong>Why you might need this tool:</strong></p>
<p>Create stunning and unique websites that will stand out from the competition. No coding required, so even those with no coding experience can create professional websites. Large community of users to help you learn and grow.</p>
<h3 id="heading-click-here-to-read-morehttpswwwdorarun"><a target="_blank" href="https://www.dora.run/">Click here to read more</a></h3>
<hr />
<h3 id="heading-build-websites-and-landing-pages-in-minutes-no-coding-required">Build Websites and Landing Pages in Minutes - No Coding Required!</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/www_sitekick_ai_.jpg" alt="Article Image" /></p>
<p>Sitekick AI is an AI-powered tool that allows you to create landing pages and websites easily. It can generate text, images, and code for your website, so you don’t need any coding or design skills.</p>
<p><strong>Why you might need this tool:</strong></p>
<p><strong>Easy to use</strong>: Sitekick AI does not require any coding or design skills, so it is perfect for people who do not have any experience with web development. <strong>Affordable</strong>: Sitekick AI is affordable, and it has a 30-day money-back guarantee, so you can try it out risk-free. <strong>Saves time</strong>: Sitekick AI can help you create websites and landing pages quickly and easily, so you can save time and focus on other important tasks.</p>
<h3 id="heading-click-here-to-read-morehttpswwwsitekickai"><a target="_blank" href="https://www.sitekick.ai/">Click here to read more</a></h3>
<hr />
<h2 id="heading-learn-about-ai">Learn about AI</h2>
<p><img src="https://www.jeremymorgan.com/images/newsletter/learn-ai.png" alt="“Learn about AI”" /></p>
<h3 id="heading-learn-anything-faster-with-the-power-of-ai">Learn Anything Faster with the Power of AI</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/kodekloud_com_ai.jpg" alt="Article Image" /></p>
<p>KodeKloud has recently released an AI tutor that can personalize the training for you, providing real-time feedback and guides to craft a custom learning sequence just for you. Each task is validated for accuracy and it supports multiple languages.</p>
<p><strong>Personalized learning</strong>: The AI-powered learning suite tailors the learning experience to your individual needs and goals.</p>
<p><strong>Real-time feedback</strong>: The AI Assistant provides real-time feedback on your progress, so you can identify and address any areas of difficulty.</p>
<p><strong>Custom learning sequences</strong>: The AI Tutor creates a custom learning sequence for any tech topic you want to master.</p>
<p><strong>Accuracy validation</strong>: Each task is validated for accuracy, so you can be sure that you are learning the correct information.</p>
<p><strong>Multilingual support</strong>: The AI Assistant supports multiple languages, so you can learn in your preferred language.</p>
<h3 id="heading-click-here-to-read-morehttpskodekloudcomai"><a target="_blank" href="https://kodekloud.com/ai">Click here to read more</a></h3>
<hr />
<h3 id="heading-build-a-multimodal-ai-agent-with-gemini-20">Build a Multimodal AI Agent with Gemini 2.0</h3>
<p>In this tutorial, we’ll build a Multimodal AI Agent using Google’s Gemini 2.0 Flash model that can simultaneously analyze videos and conduct web searches. This powerful combination allows the agent to provide comprehensive responses by understanding both visual content and related web information.</p>
<h3 id="heading-click-here-to-read-morehttpswwwtheunwindaicompbuild-a-multimodal-ai-agent-with-gemini-2-0"><a target="_blank" href="https://www.theunwindai.com/p/build-a-multimodal-ai-agent-with-gemini-2-0">Click here to read more</a></h3>
<hr />
<h3 id="heading-learn-ai-assisted-development">Learn AI Assisted Development</h3>
<p><img src="https://www.jeremymorgan.com/images/newsletter/12-13-24/kodekloud_com_ai-assisted-development.jpg" alt="Article Image" /></p>
<p>A course built by yours truly, you can learn AI-assisted programming, project planning, backend and frontend development, plus documentation using tools like ChatGPT, GitHub Copilot, BlackboxAI, Tabnine, and Cursor</p>
<h3 id="heading-click-here-to-read-morehttpskodekloudcomcoursesai-assisted-development"><a target="_blank" href="https://kodekloud.com/courses/ai-assisted-development">Click here to read more</a></h3>
<hr />
<p>Thanks for reading!!</p>
<p>I started this newsletter to share all the cool stuff I’m finding in AI over time. Keep updated on the latest stuff with this newsletter. I’m glad you’re here.</p>
<p>Share this on your LinkedIn page if you think your friends might be interested in this stuff.</p>
<p>BTW Check out <a target="_blank" href="https://bit.ly/JMYouTubeLive">my YouTube Channel</a> for more cool stuff with Generative AI. Tips, tutorials, reviews of AI tools and more.</p>
]]></content:encoded></item><item><title><![CDATA[Python Basic Syntax and Indentation: The Complete Beginner's Guide]]></title><description><![CDATA[When you’re first learning to program, Python stands out for a special reason: it’s designed to be read almost like English. Unlike other programming languages that use lots of symbols and brackets, Python relies on simple, clean formatting that make...]]></description><link>https://www.jeremymorgan.dev/python-basic-syntax-and-indentation-the-complete-beginners-guide</link><guid isPermaLink="true">https://www.jeremymorgan.dev/python-basic-syntax-and-indentation-the-complete-beginners-guide</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[python projects]]></category><category><![CDATA[python programming]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Programming Tutorials]]></category><category><![CDATA[how-to]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Thu, 12 Dec 2024 07:44:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733989193407/1bb7a454-bc11-4bcf-86cc-d1110b37cdac.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you’re first learning to program, Python stands out for a special reason: it’s designed to be read almost like English. Unlike other programming languages that use lots of symbols and brackets, Python relies on simple, clean formatting that makes your code look like a well-organized document.</p>
<p>Think of Python’s syntax like the grammar rules of a language. Just as English has rules about how to structure sentences to make meaning clear, Python has rules about how to write code so both humans and computers can understand it.</p>
<h2 id="heading-understanding-pythons-basic-syntax"><strong>Understanding Python’s Basic Syntax</strong></h2>
<h3 id="heading-the-building-blocks"><strong>The Building Blocks</strong></h3>
<p>Let’s start with the simplest elements of Python syntax:</p>
<pre><code class="lang-python"><span class="hljs-comment"># This is a comment - Python ignores anything after the '#' symbol</span>
student_name = <span class="hljs-string">"Alice"</span>    <span class="hljs-comment"># A variable holding text (string)</span>
student_age = <span class="hljs-number">15</span>         <span class="hljs-comment"># A variable holding a number (integer)</span>
<span class="hljs-comment"># Using variables in a sentence (string formatting)</span>
print(<span class="hljs-string">f"Hello, my name is <span class="hljs-subst">{student_name}</span> and I'm <span class="hljs-subst">{student_age}</span> years old."</span>)
</code></pre>
<p>In this example, we’re using several basic elements of Python:</p>
<ul>
<li><p>Comments (lines starting with #)</p>
</li>
<li><p>Variables (student_name and student_age)</p>
</li>
<li><p>String formatting (the f”…” syntax)</p>
</li>
<li><p>The print function</p>
</li>
</ul>
<h3 id="heading-basic-operations"><strong>Basic Operations</strong></h3>
<p>Python can perform calculations and comparisons just like a calculator:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Basic math operations</span>
total_score = <span class="hljs-number">95</span> + <span class="hljs-number">87</span>    <span class="hljs-comment"># Addition</span>
average = total_score / <span class="hljs-number">2</span> <span class="hljs-comment"># Division</span>
<span class="hljs-comment"># Comparisons</span>
<span class="hljs-keyword">if</span> student_age &gt;= <span class="hljs-number">15</span>:
    print(<span class="hljs-string">f"<span class="hljs-subst">{student_name}</span> can take advanced classes"</span>)
</code></pre>
<h2 id="heading-the-heart-of-python-understanding-indentation"><strong>The Heart of Python: Understanding Indentation</strong></h2>
<p>Here’s where Python gets truly unique: instead of using brackets or special symbols to group code together, Python uses indentation. This might seem strange at first, but it makes Python code exceptionally clear and readable.</p>
<h3 id="heading-how-indentation-creates-structure"><strong>How Indentation Creates Structure</strong></h3>
<p>Think of indentation like the way you might organize a detailed outline:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">make_sandwich</span>():</span>
    print(<span class="hljs-string">"1. Get two slices of bread"</span>)  <span class="hljs-comment"># First level</span>
    <span class="hljs-keyword">if</span> has_cheese:
        print(<span class="hljs-string">"2. Add cheese"</span>)           <span class="hljs-comment"># Second level</span>
        print(<span class="hljs-string">"3. Add tomatoes"</span>)         <span class="hljs-comment"># Still second level</span>
    <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">"2. Add butter"</span>)           <span class="hljs-comment"># Second level in else block</span>
    print(<span class="hljs-string">"4. Put the slices together"</span>)  <span class="hljs-comment"># Back to first level</span>
</code></pre>
<p>Each indented block tells Python “these lines belong together.” It’s like creating a sub-list in an outline — everything indented under “if has_cheese:” is part of that condition.</p>
<h3 id="heading-the-rules-of-indentation"><strong>The Rules of Indentation</strong></h3>
<p>Let’s look at the key rules for Python indentation:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_grade</span>(<span class="hljs-params">score</span>):</span>
    <span class="hljs-comment"># Rule 1: Use exactly 4 spaces for each indentation level</span>
    <span class="hljs-keyword">if</span> score &gt;= <span class="hljs-number">90</span>:
        print(<span class="hljs-string">"Excellent!"</span>)
        <span class="hljs-keyword">if</span> score == <span class="hljs-number">100</span>:
            print(<span class="hljs-string">"Perfect score!"</span>)
<span class="hljs-comment"># Rule 2: Aligned blocks work together</span>
    <span class="hljs-keyword">elif</span> score &gt;= <span class="hljs-number">80</span>:
        print(<span class="hljs-string">"Good job!"</span>)
        print(<span class="hljs-string">"Keep it up!"</span>)  <span class="hljs-comment"># This line is part of the elif block</span>
    <span class="hljs-comment"># Rule 3: Unindented lines end the block</span>
    print(<span class="hljs-string">"Processing complete"</span>)  <span class="hljs-comment"># This runs regardless of score</span>
</code></pre>
<h3 id="heading-nested-indentation-going-deeper"><strong>Nested Indentation: Going Deeper</strong></h3>
<p>As your programs get more complex, you’ll often need multiple levels of indentation:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_weather</span>(<span class="hljs-params">temperature, is_raining</span>):</span>
    <span class="hljs-comment"># First level: inside function</span>
    <span class="hljs-keyword">if</span> temperature &gt; <span class="hljs-number">70</span>:
        <span class="hljs-comment"># Second level: inside if</span>
        <span class="hljs-keyword">if</span> is_raining:
            <span class="hljs-comment"># Third level: nested condition</span>
            print(<span class="hljs-string">"It's warm but raining"</span>)
            print(<span class="hljs-string">"Take an umbrella"</span>)
        <span class="hljs-keyword">else</span>:
            print(<span class="hljs-string">"It's a warm, sunny day"</span>)
            print(<span class="hljs-string">"Perfect for outdoors"</span>)
    <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">"It's cool outside"</span>)
        print(<span class="hljs-string">"Take a jacket"</span>)
</code></pre>
<h2 id="heading-complex-structures-and-indentation"><strong>Complex Structures and Indentation</strong></h2>
<p>Let’s look at a more complex example that shows how indentation helps organize code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_student_grades</span>(<span class="hljs-params">students</span>):</span>
    <span class="hljs-keyword">for</span> student <span class="hljs-keyword">in</span> students:            <span class="hljs-comment"># First level loop</span>
        print(<span class="hljs-string">f"Checking <span class="hljs-subst">{student[<span class="hljs-string">'name'</span>]}</span>'s grades..."</span>)
total = <span class="hljs-number">0</span>
        <span class="hljs-keyword">for</span> grade <span class="hljs-keyword">in</span> student[<span class="hljs-string">'grades'</span>]: <span class="hljs-comment"># Second level loop</span>
            <span class="hljs-keyword">if</span> grade &gt; <span class="hljs-number">90</span>:              <span class="hljs-comment"># Third level condition</span>
                print(<span class="hljs-string">"Outstanding!"</span>)
            total += grade
        average = total / len(student[<span class="hljs-string">'grades'</span>])
        <span class="hljs-comment"># Back to first loop level</span>
        <span class="hljs-keyword">if</span> average &gt;= <span class="hljs-number">90</span>:
            print(<span class="hljs-string">"Honor Roll"</span>)
            <span class="hljs-keyword">if</span> student[<span class="hljs-string">'attendance'</span>] &gt; <span class="hljs-number">95</span>:  <span class="hljs-comment"># Another level</span>
                print(<span class="hljs-string">"Perfect Attendance Award"</span>)
</code></pre>
<h2 id="heading-common-patterns-and-best-practices"><strong>Common Patterns and Best Practices</strong></h2>
<h3 id="heading-handling-multiple-conditions"><strong>Handling Multiple Conditions</strong></h3>
<pre><code class="lang-python"><span class="hljs-comment"># Good: Clear and easy to follow</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_eligibility</span>(<span class="hljs-params">age, grade, attendance</span>):</span>
    <span class="hljs-keyword">if</span> age &lt; <span class="hljs-number">18</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Too young"</span>
<span class="hljs-keyword">if</span> grade &lt; <span class="hljs-number">70</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Grades too low"</span>
    <span class="hljs-keyword">if</span> attendance &lt; <span class="hljs-number">80</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Attendance too low"</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Eligible"</span>
<span class="hljs-comment"># Avoid: Too many nested levels</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_eligibility_nested</span>(<span class="hljs-params">age, grade, attendance</span>):</span>
    <span class="hljs-keyword">if</span> age &gt;= <span class="hljs-number">18</span>:
        <span class="hljs-keyword">if</span> grade &gt;= <span class="hljs-number">70</span>:
            <span class="hljs-keyword">if</span> attendance &gt;= <span class="hljs-number">80</span>:
                <span class="hljs-keyword">return</span> <span class="hljs-string">"Eligible"</span>
            <span class="hljs-keyword">else</span>:
                <span class="hljs-keyword">return</span> <span class="hljs-string">"Attendance too low"</span>
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Grades too low"</span>
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Too young"</span>
</code></pre>
<h3 id="heading-working-with-functions-and-classes"><strong>Working with Functions and Classes</strong></h3>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name</span>):</span>
        self.name = name
        self.grades = []
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_grade</span>(<span class="hljs-params">self, grade</span>):</span>
        <span class="hljs-comment"># Notice the consistent indentation in methods</span>
        <span class="hljs-keyword">if</span> isinstance(grade, (int, float)):
            <span class="hljs-keyword">if</span> <span class="hljs-number">0</span> &lt;= grade &lt;= <span class="hljs-number">100</span>:
                self.grades.append(grade)
                print(<span class="hljs-string">f"Grade <span class="hljs-subst">{grade}</span> added"</span>)
            <span class="hljs-keyword">else</span>:
                print(<span class="hljs-string">"Grade must be between 0 and 100"</span>)
        <span class="hljs-keyword">else</span>:
            print(<span class="hljs-string">"Grade must be a number"</span>)
</code></pre>
<h2 id="heading-common-mistakes-and-how-to-fix-them"><strong>Common Mistakes and How to Fix Them</strong></h2>
<h3 id="heading-indentation-errors"><strong>Indentation Errors</strong></h3>
<pre><code class="lang-python"><span class="hljs-comment"># WRONG - Inconsistent indentation</span>
<span class="hljs-keyword">if</span> score &gt; <span class="hljs-number">90</span>:
print(<span class="hljs-string">"Great job!"</span>)    <span class="hljs-comment"># Error: no indentation</span>
    print(<span class="hljs-string">"Keep it up!"</span>)   <span class="hljs-comment"># Error: inconsistent indentation</span>
<span class="hljs-comment"># RIGHT - Proper indentation</span>
<span class="hljs-keyword">if</span> score &gt; <span class="hljs-number">90</span>:
    print(<span class="hljs-string">"Great job!"</span>)
    print(<span class="hljs-string">"Keep it up!"</span>)
</code></pre>
<h3 id="heading-mixing-tabs-and-spaces"><strong>Mixing Tabs and Spaces</strong></h3>
<pre><code class="lang-python"><span class="hljs-comment"># WRONG - Mixed tabs and spaces (don't do this!)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_average</span>(<span class="hljs-params">numbers</span>):</span>
    total = <span class="hljs-number">0</span>
    count = <span class="hljs-number">0</span>    <span class="hljs-comment"># This line uses a tab</span>
    <span class="hljs-keyword">for</span> num <span class="hljs-keyword">in</span> numbers:    <span class="hljs-comment"># This line uses spaces</span>
        total += num
</code></pre>
<h3 id="heading-practice-exercise-putting-it-all-together"><strong>Practice Exercise: Putting It All Together</strong></h3>
<p>Try writing this program to practice indentation and syntax:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">grade_assignment</span>(<span class="hljs-params">score, late_days</span>):</span>
    <span class="hljs-comment"># Start with the base score</span>
    final_score = score
<span class="hljs-comment"># Check if the assignment is late</span>
    <span class="hljs-keyword">if</span> late_days &gt; <span class="hljs-number">0</span>:
        <span class="hljs-keyword">if</span> late_days &lt;= <span class="hljs-number">5</span>:
            <span class="hljs-comment"># Deduct 2 points per late day</span>
            final_score -= (late_days * <span class="hljs-number">2</span>)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-comment"># Maximum lateness penalty</span>
            final_score -= <span class="hljs-number">10</span>
    <span class="hljs-comment"># Ensure score doesn't go below 0</span>
    <span class="hljs-keyword">if</span> final_score &lt; <span class="hljs-number">0</span>:
        final_score = <span class="hljs-number">0</span>
    <span class="hljs-comment"># Determine letter grade</span>
    <span class="hljs-keyword">if</span> final_score &gt;= <span class="hljs-number">90</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"A"</span>, final_score
    <span class="hljs-keyword">elif</span> final_score &gt;= <span class="hljs-number">80</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"B"</span>, final_score
    <span class="hljs-keyword">elif</span> final_score &gt;= <span class="hljs-number">70</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"C"</span>, final_score
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"F"</span>, final_score
<span class="hljs-comment"># Test the function</span>
score = <span class="hljs-number">95</span>
late_days = <span class="hljs-number">2</span>
letter_grade, final_score = grade_assignment(score, late_days)
print(<span class="hljs-string">f"Original Score: <span class="hljs-subst">{score}</span>"</span>)
print(<span class="hljs-string">f"Late Days: <span class="hljs-subst">{late_days}</span>"</span>)
print(<span class="hljs-string">f"Final Score: <span class="hljs-subst">{final_score}</span>"</span>)
print(<span class="hljs-string">f"Letter Grade: <span class="hljs-subst">{letter_grade}</span>"</span>)
</code></pre>
<h2 id="heading-key-takeaways"><strong>Key Takeaways</strong></h2>
<ol>
<li><p>Python uses indentation to understand code structure</p>
</li>
<li><p>Always use 4 spaces for each level of indentation</p>
</li>
<li><p>Be consistent with your indentation throughout your code</p>
</li>
<li><p>Simpler, flatter code structure is usually better than deeply nested code</p>
</li>
<li><p>Proper indentation makes code more readable and helps prevent errors</p>
</li>
</ol>
<h2 id="heading-next-steps"><strong>Next Steps</strong></h2>
<p>Now that you understand Python’s basic syntax and indentation:</p>
<ul>
<li><p>Practice writing simple programs focusing on proper indentation</p>
</li>
<li><p>Learn about different data types (strings, numbers, lists)</p>
</li>
<li><p>Explore functions and classes</p>
</li>
<li><p>Study loops and control structures</p>
</li>
<li><p>Start working with Python modules and libraries</p>
</li>
</ul>
<p>Remember: Good indentation habits form the foundation of becoming a skilled Python programmer. Take your time to master these concepts, and the rest will follow naturally!</p>
]]></content:encoded></item><item><title><![CDATA[Python Syntax and Variables]]></title><description><![CDATA[Hey there, Python enthusiasts! If you’re diving into the world of Python or brushing up your skills, mastering Python’s syntax and variables is a fantastic place to start. Python is known for its simplicity and readability, making it a top choice for...]]></description><link>https://www.jeremymorgan.dev/python-syntax-and-variables</link><guid isPermaLink="true">https://www.jeremymorgan.dev/python-syntax-and-variables</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Python]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[how-to]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Tue, 03 Dec 2024 19:29:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733254088766/8ddd7a9d-d5f8-44c0-bcd2-36bad16f0242.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey there, Python enthusiasts! If you’re diving into the world of Python or brushing up your skills, mastering Python’s syntax and variables is a fantastic place to start. Python is known for its simplicity and readability, making it a top choice for developers of all levels. In this guide, we’ll unravel the basics of Python syntax and variables with plenty of practical examples and best practices. So, grab a coffee (or your favorite beverage) and let’s dive in!</p>
<hr />
<h2 id="heading-why-this-matters">Why This Matters</h2>
<p>First things first—why should we care about syntax and variables in Python? Here’s the deal:</p>
<ul>
<li><p><strong>Readability</strong>: Python’s clean, intuitive syntax means less time decoding code and more time solving problems.</p>
</li>
<li><p><strong>Efficiency</strong>: Proper use of variables keeps your code efficient and streamlined.</p>
</li>
<li><p><strong>Debugging</strong>: A solid grasp of syntax helps you pinpoint errors faster than a debugger.</p>
</li>
<li><p><strong>Scalability</strong>: Writing clear, organized code ensures that your projects can grow without turning into a tangled mess.</p>
</li>
</ul>
<p>Convinced? Great. Let’s start with the basics.</p>
<hr />
<h2 id="heading-python-syntax-basics">Python Syntax Basics</h2>
<h3 id="heading-indentation-pythons-secret-sauce">Indentation: Python’s Secret Sauce</h3>
<p>In Python, indentation isn’t just for looks—it’s how you define blocks of code. Forget braces (<code>{}</code>) and semicolons—just align your code with consistent spacing.</p>
<p>Here’s an example:</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> <span class="hljs-literal">True</span>:
    print(<span class="hljs-string">"Hello, Python!"</span>)
</code></pre>
<p>That’s it. The <code>print</code> statement is indented to show it belongs to the <code>if</code> block. Forget to indent, or mix spaces and tabs, and Python will call you out with a syntax error.</p>
<h3 id="heading-comments-talk-to-your-future-self">Comments: Talk to Your Future Self</h3>
<p>Comments in your code are lifesavers when you revisit it months (or years) later. Python supports:</p>
<ul>
<li><p><strong>Single-line comments</strong>: Start with <code>#</code>.</p>
</li>
<li><p><strong>Multi-line comments</strong>: Enclose with triple quotes (<code>'''</code> or <code>"""</code>).</p>
</li>
</ul>
<p>Here’s how:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Single-line comment</span>
<span class="hljs-string">"""
Multi-line comment
spanning several lines.
"""</span>
</code></pre>
<h3 id="heading-python-is-case-sensitive">Python is Case-Sensitive</h3>
<p>Python distinguishes between <code>Variable</code>, <code>variable</code>, and <code>VARIABLE</code>. Keep this in mind to avoid pesky bugs.</p>
<hr />
<h2 id="heading-variables-in-python">Variables in Python</h2>
<h3 id="heading-what-are-variables">What Are Variables?</h3>
<p>Think of variables as labeled storage containers for your data. Python is dynamically typed, so you don’t need to declare types upfront. Here’s a quick example:</p>
<pre><code class="lang-python">x = <span class="hljs-number">10</span>  <span class="hljs-comment"># Integer</span>
y = <span class="hljs-number">3.14</span>  <span class="hljs-comment"># Float</span>
z = <span class="hljs-string">"Hello, World!"</span>  <span class="hljs-comment"># String</span>
</code></pre>
<h3 id="heading-naming-variables">Naming Variables</h3>
<p>To keep your code clean and readable, follow these rules:</p>
<ul>
<li><p><strong>Rules</strong>:</p>
<ul>
<li><p>Start with a letter or underscore, not a number.</p>
</li>
<li><p>Use only letters, numbers, and underscores—no spaces or special characters.</p>
</li>
<li><p>Avoid Python keywords like <code>if</code>, <code>class</code>, or <code>def</code>.</p>
</li>
</ul>
</li>
<li><p><strong>Conventions</strong>:</p>
<ul>
<li><p>Use <strong>snake_case</strong> (e.g., <code>user_name</code>).</p>
</li>
<li><p>Choose meaningful names—<code>score</code> is better than <code>s</code>.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-assigning-values">Assigning Values</h3>
<p>Assigning values is as simple as:</p>
<pre><code class="lang-python">a, b, c = <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>  <span class="hljs-comment"># Multiple assignments</span>
</code></pre>
<hr />
<h2 id="heading-common-python-data-types">Common Python Data Types</h2>
<p>Here’s a rundown of Python’s built-in data types:</p>
<ul>
<li><p><strong>Numeric</strong>:</p>
<ul>
<li><p><code>int</code>: Whole numbers (e.g., <code>42</code>)</p>
</li>
<li><p><code>float</code>: Decimal numbers (e.g., <code>3.14</code>)</p>
</li>
</ul>
</li>
<li><p><strong>Strings</strong>: Enclosed in single, double, or triple quotes:</p>
<pre><code class="lang-python">  greeting = <span class="hljs-string">"Hello, Python!"</span>
</code></pre>
</li>
<li><p><strong>Booleans</strong>: <code>True</code> or <code>False</code></p>
<pre><code class="lang-python">  is_active = <span class="hljs-literal">True</span>
</code></pre>
</li>
<li><p><strong>Lists</strong>: Ordered, mutable collections:</p>
<pre><code class="lang-python">  fruits = [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"banana"</span>, <span class="hljs-string">"cherry"</span>]
</code></pre>
</li>
<li><p><strong>Dictionaries</strong>: Key-value pairs:</p>
<pre><code class="lang-python">  person = {<span class="hljs-string">"name"</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">25</span>}
</code></pre>
</li>
</ul>
<hr />
<h2 id="heading-performing-operations-with-variables">Performing Operations with Variables</h2>
<h3 id="heading-arithmetic">Arithmetic</h3>
<p>Python handles math like a champ:</p>
<pre><code class="lang-python">x = <span class="hljs-number">10</span>
y = <span class="hljs-number">3</span>

print(x + y)  <span class="hljs-comment"># Addition</span>
print(x - y)  <span class="hljs-comment"># Subtraction</span>
print(x * y)  <span class="hljs-comment"># Multiplication</span>
print(x / y)  <span class="hljs-comment"># Division</span>
</code></pre>
<h3 id="heading-strings">Strings</h3>
<p>You can concatenate or repeat strings easily:</p>
<pre><code class="lang-python">name = <span class="hljs-string">"Alice"</span>
print(name + <span class="hljs-string">" Smith"</span>)  <span class="hljs-comment"># Alice Smith</span>
print(name * <span class="hljs-number">3</span>)  <span class="hljs-comment"># AliceAliceAlice</span>
</code></pre>
<h3 id="heading-logical-operations">Logical Operations</h3>
<p>Logical operators (<code>and</code>, <code>or</code>, <code>not</code>) are super handy:</p>
<pre><code class="lang-python">x = <span class="hljs-literal">True</span>
y = <span class="hljs-literal">False</span>

print(x <span class="hljs-keyword">and</span> y)  <span class="hljs-comment"># False</span>
print(x <span class="hljs-keyword">or</span> y)  <span class="hljs-comment"># True</span>
print(<span class="hljs-keyword">not</span> x)  <span class="hljs-comment"># False</span>
</code></pre>
<hr />
<h2 id="heading-best-practices">Best Practices</h2>
<p>Write clean, efficient Python by following these tips:</p>
<ul>
<li><p><strong>Descriptive Names</strong>: Use meaningful variable names.</p>
</li>
<li><p><strong>DRY Principle</strong>: Don’t Repeat Yourself—reuse your code.</p>
</li>
<li><p><strong>Follow PEP 8</strong>: Stick to Python’s style guide.</p>
</li>
<li><p><strong>Comment Smartly</strong>: Explain <em>why</em>, not <em>what</em>.</p>
</li>
<li><p><strong>Avoid Globals</strong>: Keep variables local to their functions when possible.</p>
</li>
</ul>
<hr />
<h2 id="heading-common-pitfalls-and-how-to-avoid-them">Common Pitfalls (And How to Avoid Them)</h2>
<ol>
<li><p><strong>Indentation Errors</strong>: Stick to spaces or tabs (not both), and use four spaces per level.</p>
</li>
<li><p><strong>Scope Issues</strong>: Know the difference between local and global variables.</p>
</li>
<li><p><strong>Type Mismatches</strong>: Python doesn’t mix types:</p>
<pre><code class="lang-python"> x = <span class="hljs-string">"5"</span>
 y = <span class="hljs-number">10</span>
 print(x + y)  <span class="hljs-comment"># TypeError</span>
</code></pre>
</li>
</ol>
<hr />
<h2 id="heading-faq">FAQ</h2>
<p><strong>Q: What’s the difference between variables and constants?</strong></p>
<p>Variables can change; constants stay fixed. Use all caps to indicate constants (e.g., <code>PI = 3.14</code>).</p>
<p><strong>Q: How can I check a variable’s type?</strong></p>
<p>Use <code>type()</code>:</p>
<pre><code class="lang-python">x = <span class="hljs-number">10</span>
print(type(x))  <span class="hljs-comment"># &lt;class 'int'&gt;</span>
</code></pre>
<p><strong>Q: Can I change a variable’s type?</strong></p>
<p>Sure can! Python allows dynamic typing:</p>
<pre><code class="lang-python">x = <span class="hljs-number">10</span>
x = <span class="hljs-string">"Now a string"</span>
</code></pre>
<hr />
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Mastering Python syntax and variables is your gateway to writing cleaner, more effective code. With practice, these basics will become second nature. In our next article, we’ll dive into conditional statements (<code>if</code>/<code>else</code>) and explore how they can help you write more dynamic and responsive code.</p>
]]></content:encoded></item><item><title><![CDATA[The Ultimate Guide to Running Local LLMs on Your Mac]]></title><description><![CDATA[Hello Friends! Want to run LLM (large language models) locally on your Mac? Here's your guide! We'll explore three powerful tools for running LLMs directly on your Mac without relying on cloud services or expensive subscriptions.
Whether you are a be...]]></description><link>https://www.jeremymorgan.dev/the-ultimate-guide-to-running-local-llms-on-your-mac</link><guid isPermaLink="true">https://www.jeremymorgan.dev/the-ultimate-guide-to-running-local-llms-on-your-mac</guid><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[llm]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[chatbot]]></category><category><![CDATA[Local LLM]]></category><category><![CDATA[ollama]]></category><category><![CDATA[lmstudio]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[tutorials]]></category><category><![CDATA[#howtos]]></category><category><![CDATA[macOS]]></category><category><![CDATA[apple silicon]]></category><category><![CDATA[large language models]]></category><category><![CDATA[huggingface]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Thu, 17 Oct 2024 17:33:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729186248882/5226778a-c75c-496b-9dd0-9d3ddbd485fd.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello Friends! Want to run LLM (large language models) locally on your Mac? Here's your guide! We'll explore three powerful tools for running LLMs directly on your Mac without relying on cloud services or expensive subscriptions.</p>
<p>Whether you are a beginner or an experienced developer, you'll be up and running in no time. This is a great way to evaluate different open-source models or create a sandbox to write AI applications on your own machine.</p>
<p>We'll go from easy to use to a solution that requires programming.</p>
<h2 id="heading-products-were-using">Products we're using:</h2>
<ol>
<li><p><a class="post-section-overview" href="#lm-studio-user-friendly-ai-for-everyone">LM Studio: User-Friendly AI for Everyone</a></p>
</li>
<li><p><a class="post-section-overview" href="#Ollama-efficient-and-developer-friendly">Ollama: Efficient and Developer-Friendly</a></p>
</li>
<li><p><a class="post-section-overview" href="#hugging-face-transformers-advanced-model-access">Hugging Face Transformers: Advanced Model Access</a></p>
</li>
</ol>
<p>If you'd rather watch a video of this tutorial, here it is:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=e5iaYkSNrhY">https://www.youtube.com/watch?v=e5iaYkSNrhY</a></div>
<p> </p>
<h2 id="heading-1-lm-studio-user-friendly-ai-for-everyone">1. LM Studio: User-Friendly AI for Everyone</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185798612/f454f823-b121-410b-8052-e34158c2366c.webp" alt /></p>
<p>LM Studio is an excellent starting point for both beginners and experts. It provides an intuitive interface for exploring and using various AI models.</p>
<h3 id="heading-getting-started-with-lm-studio">Getting Started with LM Studio</h3>
<ol>
<li><p>Visit <a target="_blank" href="https://lmstudio.ai">lmstudio.ai</a> and download the appropriate version for your Mac.</p>
</li>
<li><p>Install LM Studio by dragging the downloaded file into your Applications folder.</p>
</li>
<li><p>Launch LM Studio and accept any security prompts.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185812561/e25bf60d-5f95-4c8e-87bd-e897c5aadc46.webp" alt /></p>
<h3 id="heading-exploring-models">Exploring Models</h3>
<ol>
<li>In the main interface, click "Load a model" or select a model from the "New and Noteworthy" list.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185823221/d761cf3a-48b5-4c89-8a9d-53744afab82c.webp" alt /></p>
<ol start="2">
<li><p>we'll use the "llama2 3B" model for this tutorial. Click on it to download.</p>
</li>
<li><p>Once downloaded, click "Load model" to activate it.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185833708/3350fd51-e791-41db-8c40-39eada2d1f46.webp" alt /></p>
<h3 id="heading-using-the-chat-interface">Using the Chat Interface</h3>
<ol>
<li><p>With the model loaded, you can start interacting with it in the chat interface.</p>
</li>
<li><p>Try asking a question like "Tell me a funny joke about Python."</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185842754/3ef5b3f9-c910-4d07-aa15-2dbffbc38541.webp" alt /></p>
<ol start="3">
<li>Observe the model's response and the performance metrics (tokens per second, context usage).</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185853962/9743de8c-949e-4d24-9290-410e51c7ca01.webp" alt /></p>
<h3 id="heading-utilizing-the-api-server">Utilizing the API Server</h3>
<p>LM Studio also provides an OpenAI-compatible API server, making it easy to integrate with your applications:</p>
<ol>
<li><p>Click on the server icon in the left sidebar.</p>
</li>
<li><p>Start the server by clicking the "Start Server" button. [6]</p>
</li>
<li><p>Copy the provided server address (usually <code>http://localhost:1234</code>).</p>
</li>
</ol>
<p>You can see a set of endpoints available:</p>
<pre><code class="lang-plaintext">GET http://localhost:1234/v1/models
POST http://localhost:1234/v1/chat/completions
POST http://localhost:1234/v1/completions
POST http://localhost:1234/v1/embeddings
</code></pre>
<p>You can now use this address to send requests to the model using tools like Postman or your own code. Here's an example using Postman:</p>
<ol>
<li><p>Create a new POST request to <code>http://localhost:1234/v1/chat/completions</code>.</p>
</li>
<li><p>Set the body to raw JSON with the following content:</p>
</li>
</ol>
<pre><code class="lang-json">{
        <span class="hljs-attr">"model"</span>: <span class="hljs-string">"lmstudio-community/Qwen2.5-14B-Instruct-GGUF/Qwen2.5-14B-Instruct-Q4_K_M.gguf"</span>,
        <span class="hljs-attr">"messages"</span>: [
            {
                <span class="hljs-attr">"role"</span>: <span class="hljs-string">"system"</span>,
                <span class="hljs-attr">"content"</span>: <span class="hljs-string">"You are a helpful jokester who knows a lot about Python"</span>
            },
            {
                <span class="hljs-attr">"role"</span>: <span class="hljs-string">"user"</span>,
                <span class="hljs-attr">"content"</span>: <span class="hljs-string">"Tell me a funny Python joke."</span>
            }
        ],
        <span class="hljs-attr">"response_format"</span>: {
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"json_schema"</span>,
            <span class="hljs-attr">"json_schema"</span>: {
                <span class="hljs-attr">"name"</span>: <span class="hljs-string">"joke_response"</span>,
                <span class="hljs-attr">"strict"</span>: <span class="hljs-string">"true"</span>,
                <span class="hljs-attr">"schema"</span>: {
                    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"object"</span>,
                    <span class="hljs-attr">"properties"</span>: {
                        <span class="hljs-attr">"joke"</span>: {
                            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"string"</span>
                        }
                    },
                    <span class="hljs-attr">"required"</span>: [
                        <span class="hljs-string">"joke"</span>
                    ]
                }
            }
        },
        <span class="hljs-attr">"temperature"</span>: <span class="hljs-number">0.7</span>,
        <span class="hljs-attr">"max_tokens"</span>: <span class="hljs-number">50</span>,
        <span class="hljs-attr">"stream"</span>: <span class="hljs-literal">false</span>
    }
</code></pre>
<ol start="3">
<li>Send the request and observe the model's response.</li>
</ol>
<p>LM Studio is perfect for quickly testing different models and integrating them into your projects with minimal setup.</p>
<h2 id="heading-2-ollama-efficient-and-developer-friendly">2. Ollama: Efficient and Developer-Friendly</h2>
<p>Ollama is a lightweight and powerful tool for deploying LLMs, which is ideal for developers who prefer working from the command line.</p>
<h3 id="heading-installing-ollama">Installing Ollama</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185879057/81499b4f-2392-43e1-8f11-29907722d534.webp" alt /></p>
<ol>
<li><p>Visit the Ollama website and download the Mac version.</p>
</li>
<li><p>Install Ollama by dragging the downloaded file into your Applications folder.</p>
</li>
<li><p>Launch Ollama and accept any security prompts.</p>
</li>
</ol>
<h3 id="heading-using-ollama-from-the-terminal">Using Ollama from the Terminal</h3>
<ol>
<li><p>Open a terminal window.</p>
</li>
<li><p>List available models by running: <code>Ollama list</code></p>
</li>
<li><p>To download and run a model, use: <code>Ollama run &lt;model-name&gt;</code>    For example: <code>Ollama run qwen2.5-14b</code></p>
</li>
<li><p>Once the model is loaded, you can interact directly with it in the terminal.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185898550/7634dce8-4a48-4818-b28a-445da444ec13.webp" alt /></p>
<h3 id="heading-ollama-commands-and-features">Ollama Commands and Features</h3>
<ul>
<li><p>Use <code>/?</code> to see available commands within a model session.</p>
</li>
<li><p>Exit a model session with <code>/bye</code>.</p>
</li>
<li><p>Run models with verbose output using <code>--verbose</code> flag.</p>
</li>
</ul>
<h3 id="heading-using-ollamas-api">Using Ollama's API</h3>
<p>Ollama also provides an API for integration with your applications:</p>
<ol>
<li><p>Ensure Ollama is running (you'll see the icon in your menu bar).</p>
</li>
<li><p>Send POST requests to <code>http://localhost:11434/api/generate</code>.</p>
</li>
</ol>
<p>Example using Postman:</p>
<pre><code class="lang-json">{
      <span class="hljs-attr">"model"</span>: <span class="hljs-string">"qwen2.5:14b"</span>,
      <span class="hljs-attr">"prompt"</span>: <span class="hljs-string">"Tell me a funny joke about Python"</span>,
      <span class="hljs-attr">"stream"</span>: <span class="hljs-literal">false</span>
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185910643/7c789ec1-f5fe-419e-94d2-377915748285.webp" alt /></p>
<h3 id="heading-ollama-python-library">Ollama Python Library</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185920604/da06d712-7016-4569-a192-731aa7e57b9f.webp" alt /></p>
<p>For Python developers, Ollama offers a convenient library:</p>
<ol>
<li><p>Install the library: <code>pip install ollama</code></p>
</li>
<li><p>Use it in your Python scripts:</p>
</li>
</ol>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> ollama
response = ollama.chat(model=<span class="hljs-string">'qwen2.5:14b'</span>, messages=[
  {
    <span class="hljs-string">'role'</span>: <span class="hljs-string">'user'</span>,
    <span class="hljs-string">'content'</span>: <span class="hljs-string">'Tell me a funny joke about Golang!'</span>,
  },
])
print(response[<span class="hljs-string">'message'</span>][<span class="hljs-string">'content'</span>])
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185930442/2aee8e02-0309-4957-8b1f-6d75d2ce4629.webp" alt /></p>
<p>Ollama provides a great balance between ease of use and flexibility, making it an excellent choice for developers building AI-powered applications.</p>
<h2 id="heading-3-hugging-face-transformers-advanced-model-access">3. Hugging Face Transformers: Advanced Model Access</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185941012/99a88d2e-aa21-429e-b0ff-0d9f60542d60.webp" alt /></p>
<p>Hugging Face Transformers is a powerful library that gives you access to many models and more control over their usage.</p>
<h3 id="heading-setting-up-hugging-face-transformers">Setting Up Hugging Face Transformers</h3>
<ol>
<li>Create a new Python virtual environment:</li>
</ol>
<pre><code class="lang-bash">python -m venv env    <span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<ol start="2">
<li>Install required libraries:</li>
</ol>
<pre><code class="lang-bash">pip install torch transformers accelerate
</code></pre>
<ol start="3">
<li>Install Hugging Face CLI:</li>
</ol>
<pre><code class="lang-bash">pip install -U huggingface_hub[cli]`
</code></pre>
<ol start="4">
<li>Log in to Hugging Face:</li>
</ol>
<pre><code class="lang-bash">huggingface-cli login
</code></pre>
<p>(You'll need to create a <a target="_blank" href="https://huggingface.co/docs/hub/en/security-tokens">user access token</a> on the Hugging Face website)</p>
<h3 id="heading-using-a-model-with-transformers">Using a Model with Transformers</h3>
<p>Here's a simple example using the LLaMA 3.2 3B model:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> torch
<span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> pipeline

model_id = <span class="hljs-string">"meta-llama/Llama-3.2-3B-Instruct"</span>
pipe = pipeline(
    <span class="hljs-string">"text-generation"</span>,
    model=model_id,
    torch_dtype=torch.bfloat16,
    device_map=<span class="hljs-string">"auto"</span>,
)
messages = [
    {<span class="hljs-string">"role"</span>: <span class="hljs-string">"system"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">"You are a pirate chatbot who always responds in pirate speak!"</span>},
    {<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">"Who are you?"</span>},
]
outputs = pipe(
    messages,
    max_new_tokens=<span class="hljs-number">256</span>,
)
print(outputs[<span class="hljs-number">0</span>][<span class="hljs-string">"generated_text"</span>][<span class="hljs-number">-1</span>])
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185966469/d374263b-2406-4749-a522-8c61838be389.webp" alt /></p>
<h3 id="heading-advantages-of-hugging-face-transformers">Advantages of Hugging Face Transformers</h3>
<ol>
<li><p>Access to a vast library of models</p>
</li>
<li><p>Fine-grained control over model parameters</p>
</li>
<li><p>Ability to fine-tune models for specific tasks</p>
</li>
<li><p>Integration with popular deep learning frameworks</p>
</li>
</ol>
<p>While Hugging Face Transformers requires more coding knowledge, it offers unparalleled flexibility and access to cutting-edge AI models.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729185982831/c8c4d33b-e61d-44d2-b163-2fca3a58410c.webp" alt /></p>
<p>We've explored three powerful tools for running AI models locally on your Mac:</p>
<ol>
<li><p>LM Studio: Perfect for beginners and quick experimentation</p>
</li>
<li><p>Ollama: Ideal for developers who prefer command-line interfaces and simple API integration</p>
</li>
<li><p>Hugging Face Transformers: Best for advanced users who need access to a wide range of models and fine-grained control</p>
</li>
</ol>
<p>Each tool has its strengths, and the choice depends on your specific needs and technical expertise. By running these models locally, you gain more control over your AI applications, ensure data privacy, and avoid the costs associated with cloud-based services.</p>
<p>Consider your Mac's specifications when working with larger models, as they can be resource-intensive. Start with smaller models and work up as you become more familiar with the tools and your hardware capabilities.</p>
<p>Happy coding, and enjoy exploring the world of local AI on your Mac!</p>
<p>If you have any questions or feedback feel free to <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">reach out</a> or leave a comment below.</p>
]]></content:encoded></item><item><title><![CDATA[The Top 10 Conversational AI Models for 2024]]></title><description><![CDATA[Like you, I use Generative AI nearly every single day. One common request I get is when folks have wet their feet with ChatGPT and ask me “What else is out there?” I send them a list of links and a little blurb about the sites. I decided to share tha...]]></description><link>https://www.jeremymorgan.dev/the-top-10-conversational-ai-models-for-2024</link><guid isPermaLink="true">https://www.jeremymorgan.dev/the-top-10-conversational-ai-models-for-2024</guid><category><![CDATA[generative ai]]></category><category><![CDATA[AI]]></category><category><![CDATA[aitools]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[chatbot]]></category><category><![CDATA[claude.ai]]></category><category><![CDATA[copilot]]></category><category><![CDATA[tools]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Fri, 30 Aug 2024 20:24:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725049363983/8865d963-df2c-424d-b9d5-ae977e202dc0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Like you, I use Generative AI nearly every single day. One common request I get is when folks have wet their feet with ChatGPT and ask me “What else is out there?” I send them a list of links and a little blurb about the sites. I decided to share that list and insights with you.</p>
<p>Bookmark this page because it will be updated frequently. I’ll also do this with some other tools I use (image generation, code generation, video, etc.).</p>
<p>Am I missing anything? Feel free to <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">reach out to me</a>!</p>
<p>Here are the top conversational AI tools out there right now.</p>
<h1 id="heading-perplexity"><strong>Perplexity</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*9BCOASn1fHy6Of40k5CSKQ.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://www.perplexity.ai/">https://www.perplexity.ai/</a></p>
</li>
<li><p><strong>Title:</strong> Perplexity AI</p>
</li>
<li><p><strong>Description:</strong> Perplexity — Where Knowledge Begins</p>
</li>
<li><p><strong>Why it’s awesome:</strong> It pulls from different sources to verify the information presented. Very magic.</p>
</li>
</ul>
<h1 id="heading-claude"><strong>Claude</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*eMGJLZ72TX3jVYMlG9En4Q.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://claude.ai/">https://claude.ai</a></p>
</li>
<li><p><strong>Title:</strong> Claude</p>
</li>
<li><p><strong>Description:</strong> Talk with Claude, an AI assistant from Anthropic</p>
</li>
<li><p><strong>Why it’s awesome:</strong> Excels in writing, and analysys.</p>
</li>
</ul>
<h1 id="heading-globe-explorer"><strong>Globe Explorer</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*Wg-65zbLYR5fS7oP9NsvNw.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://explorer.globe.engineer/">https://explorer.globe.engineer/</a></p>
</li>
<li><p><strong>Title:</strong> Globe Explorer</p>
</li>
<li><p><strong>Description:</strong> No description found</p>
</li>
<li><p><strong>Why it’s awesome:</strong> It pulls from many different sources to really deep dive into a subject.</p>
</li>
</ul>
<h1 id="heading-poe"><strong>Poe</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*c1Un0HUrgi3o6h4noKz4DQ.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://poe.com/">https://poe.com/</a></p>
</li>
<li><p><strong>Title:</strong> Poe — Fast, Helpful AI Chat</p>
</li>
<li><p><strong>Description:</strong> Poe lets you ask questions, get instant answers, and have back-and-forth conversations with AI. It gives access to GPT-4, GPT-3.5-turbo, Claude from Anthropic, and various other bots.</p>
</li>
<li><p><strong>Why it’s awesome:</strong> There are so many connections to other services, and the interface is very cohesive.</p>
</li>
</ul>
<h1 id="heading-grok"><strong>Grok</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*V8UO79xc6GB60hPgfI8jfg.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://x.com/i/grok">https://x.com/i/grok</a></p>
</li>
<li><p><strong>Title:</strong> x.com</p>
</li>
<li><p><strong>Description:</strong> AI Assistant, powered by X</p>
</li>
<li><p><strong>Why it’s awesome:</strong> It uses X as an additional source, and it is very up to date.</p>
</li>
</ul>
<h1 id="heading-gemini"><strong>Gemini</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*mavxLZwjxDllSsWMUALvIw.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://gemini.google.com/app">https://gemini.google.com/app</a></p>
</li>
<li><p><strong>Title:</strong> Gemini — chat to supercharge your ideas</p>
</li>
<li><p><strong>Description:</strong> Bard is now Gemini. Get help with writing, planning, learning, and more from Google AI.</p>
</li>
<li><p><strong>Why it’s awesome:</strong> Backed by Google, exciting and factual results.</p>
</li>
</ul>
<h1 id="heading-groq"><strong>Groq</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*k_BIsp2iJdwb6T3Kdg3aeQ.jpeg" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://groq.com/">https://groq.com/</a></p>
</li>
<li><p><strong>Title:</strong> Groq is Fast AI Inference</p>
</li>
<li><p><strong>Description:</strong> The LPU™ Inference Engine by Groq is a hardware and software platform that delivers exceptional compute speed, quality, and energy efficiency. Groq provides cloud and on-prem solutions at scale for AI applications.</p>
</li>
<li><p><strong>Why it’s awesome:</strong> Screaming fast and smart, great for applications.</p>
</li>
</ul>
<h1 id="heading-chatgpt"><strong>ChatGPT</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*m_4mFOpX0tgGsCfBLryg5A.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://openai.com/chatgpt/">https://openai.com/chatgpt/</a></p>
</li>
<li><p><strong>Title:</strong> ChatGPT by OpenAI</p>
</li>
<li><p><strong>Description:</strong> A conversational AI system that listens, learns, and challenges</p>
</li>
<li><p><strong>Why it’s awesome:</strong> It’s the OG, and Custom GPTs are awesome</p>
</li>
</ul>
<h1 id="heading-hugging-face-chat-models"><strong>Hugging Face Chat Models</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/0*NJgcpGX8gU2XGQvs.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://huggingface.co/chat/models">https://huggingface.co/chat/models</a></p>
</li>
<li><p><strong>Title:</strong> HuggingChat — Models</p>
</li>
<li><p><strong>Description:</strong> The first open source alternative to ChatGPT.</p>
</li>
<li><p><strong>Why it’s awesome:</strong> A wide variety of models to choose from</p>
</li>
</ul>
<h1 id="heading-bing-ai-copilot"><strong>Bing AI (Copilot)</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:945/1*jBa9BeOS1az33LpAt50MZg.png" alt /></p>
<ul>
<li><p><strong>URL:</strong> <a target="_blank" href="https://www.bing.com/chat">https://www.bing.com/chat</a></p>
</li>
<li><p><strong>Title:</strong> Microsoft Copilot in Bing</p>
</li>
<li><p><strong>Description:</strong> Chat, get answers, create amazing content, and discover information effortlessly with Bing’s AI-powered chat. Transform the way you search and get answers with Microsoft Copilot in Bing.</p>
</li>
<li><p><strong>Why it’s awesome:</strong> Fast and great for programming/coding stuff.</p>
</li>
</ul>
<h1 id="heading-conclusion"><strong>Conclusion</strong></h1>
<p>This is the list of Conversational AI models I use constantly. I will update this as I go. If you can think of one I’m missing out on, <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Contact me!</a></p>
<p>A<strong><em>lso if you’re into Computer Vision and other cool AI tech, you should subscribe to my</em></strong> <a target="_blank" href="https://mailchi.mp/4961a415a64f/learn-ai-newsletter"><strong><em>AI Architect Newsletter</em></strong></a> <strong><em>to keep up with the latest stuff!</em></strong></p>
]]></content:encoded></item><item><title><![CDATA[The Complete Guide to Image Compression with OpenCV]]></title><description><![CDATA[Image compression is a critical technology in computer vision that allows us to store and transmit images more efficiently while maintaining visual quality. Ideally, we’d love to have small files with the best quality. However, we must make the trade...]]></description><link>https://www.jeremymorgan.dev/the-complete-guide-to-image-compression-with-opencv</link><guid isPermaLink="true">https://www.jeremymorgan.dev/the-complete-guide-to-image-compression-with-opencv</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Computer Vision]]></category><category><![CDATA[opencv]]></category><category><![CDATA[opencv-python]]></category><category><![CDATA[image processing]]></category><category><![CDATA[Python]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[python projects]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[tutorials]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Tue, 20 Aug 2024 04:39:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128561552/ac34af23-b95d-4db9-b048-a795e41cc067.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Image compression is a critical technology in computer vision that allows us to store and transmit images more efficiently while maintaining visual quality. Ideally, we’d love to have small files with the best quality. However, we must make the tradeoff and decide which is more important.</p>
<p>This tutorial will help you learn about image compression with OpenCV, covering theory and practical applications. By the end, you’ll understand how to compress photos successfully for computer vision projects (or any other projects you might have).</p>
<h2 id="heading-what-is-image-compression">What is Image Compression?</h2>
<p>Image compression is reducing an image’s file size while maintaining an acceptable level of visual quality. There are two main types of compression:</p>
<ol>
<li><p><strong>Lossless compression:</strong> Preserves all original data, allowing exact image reconstruction.</p>
</li>
<li><p><strong>Lossy compression:</strong> Discards some data to achieve smaller file sizes, potentially reducing image quality.</p>
</li>
</ol>
<h3 id="heading-why-compress-images">Why Compress Images?</h3>
<p>If “disk space is cheap,” as we often hear, then why compress images at all? At a small scale, image compression doesn’t matter much, but at a large scale, it’s crucial.</p>
<p>For instance, if you have a few images on your hard drive, you can compress them and save a few megabytes of data. This is not much of an impact when hard drives are measured in Terabytes. But what if you had 100,000 images on your hard drive? Some basic compression saves real time and money. From a performance perspective, it’s the same. If you have a website with a lot of images and 10,000 people visit your website a day, compression matters.</p>
<p>Here’s why we do it:</p>
<ul>
<li><p><strong>Reduced storage requirements</strong>: Store more images in the same space</p>
</li>
<li><p><strong>Faster transmission</strong>: Ideal for web applications and bandwidth-constrained scenarios</p>
</li>
<li><p><strong>Improved processing speed</strong>: Smaller images are quicker to load and process</p>
</li>
</ul>
<h2 id="heading-theory-behind-image-compression">Theory Behind Image Compression</h2>
<p>Image compression techniques exploit two types of redundancies:</p>
<ol>
<li><p><strong>Spatial redundancy</strong>: Correlation between neighboring pixels</p>
</li>
<li><p><strong>Color redundancy</strong>: Similarity of color values in adjacent regions</p>
</li>
</ol>
<p><strong>Spatial redundancy</strong> takes advantage of the fact that neighboring pixels tend to have similar values in most natural images. This creates smooth transitions. Many photos “look real” because there is a natural flow from one area to the other. When the neighboring pixels have wildly different values, you get “noisy” images. Pixels changed to make those transitions less “smooth” by grouping pixels into a single color, making the image smaller.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128180075/ad66353a-fdd8-42e7-bd95-83a63fc413ed.webp" alt class="image--center mx-auto" /></p>
<p><strong>Color redundancy</strong>, on the other hand, focuses on how adjacent areas in an image often share similar colors. Think of a blue sky or a green field—large portions of the image might have very similar color values. They can also be grouped together and made into a single color to save space.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128201050/a5bc6556-b752-4701-8816-0697039952cc.webp" alt class="image--center mx-auto" /></p>
<p>OpenCV offers solid tools for working with these ideas. Using spatial redundancy, OpenCV’s <code>cv2.inpaint()</code> function, for example, fills in missing or damaged areas of a picture using information from nearby pixels. OpenCV lets developers use <code>cv2.cvtColor()</code> to translate images between several color spaces regarding color redundancy. This can be somewhat helpful as a preprocessing step in many compression techniques since some color spaces are more effective than others in encoding particular kinds of images.</p>
<p>We’ll test out some of this theory now. Let’s play with it.</p>
<h2 id="heading-hands-on-image-compression">Hands on Image Compression</h2>
<p>Let’s explore how to compress images using OpenCV’s Python bindings. Write out this code or copy it:<br />(you can also <a target="_blank" href="https://github.com/JeremyMorgan/OpenCV_Compress_Image_Tutorial">download the source code here</a>)</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> cv2
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compress_image</span>(<span class="hljs-params">image_path, quality=<span class="hljs-number">90</span></span>):</span>
    <span class="hljs-comment"># Read the image</span>
 img = cv2.imread(image_path)

    <span class="hljs-comment"># Encode the image with JPEG compression</span>
 encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
 _, encoded_img = cv2.imencode(<span class="hljs-string">'.jpg'</span>, img, encode_param)

    <span class="hljs-comment"># Decode the compressed image</span>
 decoded_img = cv2.imdecode(encoded_img, cv2.IMREAD_COLOR)

    <span class="hljs-keyword">return</span> decoded_img

<span class="hljs-comment"># Example usage</span>
original_img = cv2.imread(<span class="hljs-string">'original_image.jpg'</span>)
compressed_img = compress_image(<span class="hljs-string">'original_image.jpg'</span>, quality=<span class="hljs-number">50</span>)

<span class="hljs-comment"># Display results</span>
cv2.imshow(<span class="hljs-string">'Original'</span>, original_img)
cv2.imshow(<span class="hljs-string">'Compressed'</span>, compressed_img)
cv2.waitKey(<span class="hljs-number">0</span>)
cv2.destroyAllWindows()
</code></pre>
<p>This example contains a <code>compress_image</code> function that takes two parameters:</p>
<ul>
<li><p>Image path (where the image is located)</p>
</li>
<li><p>Quality (the quality of the image desired)</p>
</li>
</ul>
<p>Then, we’ll load the original image into <code>original_img</code>. We then compress that same image by 50% and load it into a new instance, <code>compressed_image</code>.</p>
<p>Then we’ll show the original and compressed images so you can view them side by side.</p>
<p>We then calculate and display the compression ratio.</p>
<p>This example demonstrates how to compress an image using JPEG compression in OpenCV. The <code>quality</code> parameter controls file size and image quality tradeoff.</p>
<p>Let’s run it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128230359/929e5828-b8d9-4b5b-a358-e36303796624.webp" alt class="image--center mx-auto" /></p>
<p>While initially looking at the images, you see little difference. However, zooming in shows you the difference in the quality:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128253097/77a3ea3c-c8a6-4808-8b86-dae99f15ed87.webp" alt class="image--center mx-auto" /></p>
<p>And after closing the windows and looking at the files, we can see the file was reduced in size dramatically:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128273465/2d4c3d32-a2b7-4815-8acf-db86d8495127.webp" alt class="image--center mx-auto" /></p>
<p>Also, if we take it down further, we can change our quality to 10%</p>
<pre><code class="lang-plaintext">compressed_img = compress_image('sampleimage.jpg', quality=10)
</code></pre>
<p>And the results are much more drastic:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128296834/83ac7ac9-0ab0-476d-95a3-3d978c207cf5.webp" alt class="image--center mx-auto" /></p>
<p>And the file size results are more drastic as well:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128316420/59f100e6-24a1-4db0-9231-5a93eb284a9e.webp" alt class="image--center mx-auto" /></p>
<p>You can adjust these parameters quite easily and achieve the desired balance between quality and file size.</p>
<h2 id="heading-evaluating-compression-quality">Evaluating Compression Quality</h2>
<p>To assess the impact of compression, we can use metrics like:</p>
<ol>
<li><strong>Mean Squared Error (MSE)</strong></li>
</ol>
<p>Mean Squared Error (MSE) measures how different two images are from each other. When you compress an image, MSE helps you determine how much the compressed image has changed compared to the original.</p>
<p>It does this by sampling the differences between the colors of corresponding pixels in the two images, squaring those differences, and averaging them. The result is a single number: a lower MSE means the compressed image is closer to the original. In comparison, a higher MSE means there’s a more noticeable loss of quality.</p>
<p>Here’s some Python code to measure that:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_mse</span>(<span class="hljs-params">img1, img2</span>):</span>
    <span class="hljs-keyword">return</span> np.mean((img1 - img2) ** <span class="hljs-number">2</span>)

mse = calculate_mse(original_img, compressed_img)
print(<span class="hljs-string">f"Mean Squared Error: <span class="hljs-subst">{mse:<span class="hljs-number">.2</span>f}</span>"</span>)
</code></pre>
<p>Here’s what our demo image compression looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128337705/ce5460d7-9ca6-48d1-89b9-74ebf8e616e9.webp" alt class="image--center mx-auto" /></p>
<ol>
<li><strong>Peak Signal-to-Noise Ratio (PSNR)</strong></li>
</ol>
<p>Peak Signal-to-Noise Ratio (PSNR) is a measure that shows how much an image’s quality has degraded after compression. This is often visible with your eyes, but it assigns a set value. It compares the original image to the compressed one and expresses the difference as a ratio.</p>
<p>A higher PSNR value means the compressed image is closer in quality to the original, indicating less loss of quality. A lower PSNR means more visible degradation. PSNR is often used alongside MSE, with PSNR providing an easier-to-interpret scale where higher is better.</p>
<p>Here is some Python code that measures that:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_psnr</span>(<span class="hljs-params">img1, img2</span>):</span>
 mse = calculate_mse(img1, img2)
    <span class="hljs-keyword">if</span> mse == <span class="hljs-number">0</span>:
        <span class="hljs-keyword">return</span> float(<span class="hljs-string">'inf'</span>)
 max_pixel = <span class="hljs-number">255.0</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">20</span> * np.log10(max_pixel / np.sqrt(mse))

psnr = calculate_psnr(original_img, compressed_img)
print(<span class="hljs-string">f"PSNR: <span class="hljs-subst">{psnr:<span class="hljs-number">.2</span>f}</span> dB"</span>)
</code></pre>
<p>Here’s what our demo image compression looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128363995/979e35c7-5c1d-468c-8a99-a48580f6d466.webp" alt class="image--center mx-auto" /></p>
<p>“Eyeballing” your images after compression to determine quality is fine; however, at a large scale, having scripts do this is a much easier way to set standards and ensure the images follow them.</p>
<p>Let’s look at a couple other techniques:</p>
<h2 id="heading-advanced-compression-techniques">Advanced Compression Techniques</h2>
<p>For more advanced compression, OpenCV supports various algorithms:</p>
<ol>
<li><strong>PNG Compression</strong>:</li>
</ol>
<p>You can convert your images to PNG format, which has many advantages. Use the following line of code, and you can set your compression from 0 to 9, depending on your needs. 0 means no compression whatsoever, and 9 is maximum. Keep in mind that PNGs are a “lossless” format, so even at maximum compression, the image should remain intact. The big trade-off is file size and compression time.</p>
<p>Here is the code to use PNG compression with OpenCV:</p>
<pre><code class="lang-python">cv2.imwrite(<span class="hljs-string">'compressed.png'</span>, img, [cv2.IMWRITE_PNG_COMPRESSION, <span class="hljs-number">9</span>])
</code></pre>
<p>And here is our result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128386171/ef336b61-e53e-4f62-9fb2-4a77e1cd3a26.webp" alt class="image--center mx-auto" /></p>
<p><em>Note: You may notice sometimes that PNG files are actually larger in size, depending on the image.</em></p>
<ol>
<li><strong>WebP Compression</strong>:</li>
</ol>
<p>You can also convert your images to .webp format. This is a newer method of compression that’s gaining in popularity. I have been using this compression on the images on my blog for years.</p>
<p>In the following code, we can write our image to a webp file and set the compression level from 0 to 100. It’s the opposite of PNG’s scale because 0, because we’re setting <em>quality</em> instead of <em>compression</em>. This small distinction matters, because a setting of 0 is the lowest possible quality, with a small file size and significant loss. 100 is the highest quality, which means large files with the best image quality.</p>
<p>Here’s the Python code to make that happen:</p>
<pre><code class="lang-python">cv2.imwrite(<span class="hljs-string">'compressed.webp'</span>, img, [cv2.IMWRITE_WEBP_QUALITY, <span class="hljs-number">80</span>])
</code></pre>
<p>And here is our result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724128407734/491bee37-d938-454b-9b0a-14cb1fd08437.webp" alt class="image--center mx-auto" /></p>
<p>These two techniques are great for compressing large amounts of data. You can write scripts to compress thousands or hundreds of thousands of images automatically.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Image compression is fantastic. It’s essential for computer vision tasks in many ways, especially when saving space or increasing processing speed. There are also many use cases outside of computer vision anytime you want to reduce hard drive space or save bandwidth. Image compression can help a lot.</p>
<p>By understanding the theory behind it and applying it, you can do some powerful things with your projects.</p>
<p>Remember, the key to effective compression is finding the sweet spot between file size reduction and maintaining acceptable visual quality for your application.</p>
<p>Thanks for reading, and feel free to <a target="_blank" href="https://www.linkedin.com/in/jeremycmorgan/">reach out</a> if you have any comments or questions!</p>
<blockquote>
<p>Also if you're into Computer Vision and other cool AI tech, you should subscribe to my <a target="_blank" href="https://mailchi.mp/4961a415a64f/learn-ai-newsletter">AI Architect Newsletter</a> to keep up with the latest stuff!</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Running an LLM Locally on Your Own Machine]]></title><description><![CDATA[So, you want to run a ChatGPT-like chatbot on your own computer? Want to learn more LLMs or just be free to chat away without others seeing what you’re saying? This is an excellent option for doing just that.
I’ve been running several LLMs and other ...]]></description><link>https://www.jeremymorgan.dev/running-an-llm-locally-on-your-own-machine</link><guid isPermaLink="true">https://www.jeremymorgan.dev/running-an-llm-locally-on-your-own-machine</guid><category><![CDATA[generative ai]]></category><category><![CDATA[large language models]]></category><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Developer]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[chatbot]]></category><category><![CDATA[Chat-GPT]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[transformers]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Wed, 06 Dec 2023 15:56:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1701878038360/93367706-143a-47b3-972b-a90fcf8f6930.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, you want to run a ChatGPT-like chatbot on your own computer? Want to learn more LLMs or just be free to chat away without others seeing what you’re saying? This is an excellent option for doing just that.</p>
<p>I’ve been running several LLMs and other generative AI tools on my computer lately. I’ve discovered <a target="_blank" href="https://github.com/oobabooga/text-generation-webui/tree/main">this web UI from oobabooga</a> for running models, and it’s incredible. You have a ton of options, and it works great.</p>
<p>That’s what we will set up today in this tutorial.</p>
<h2 id="heading-the-easy-way">The easy way</h2>
<p>If you’re in Windows using WSL, you can run a simple batch file, and it might work great. Super easy.</p>
<p>Clone the repo:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/oobabooga/text-generation-webui.git
</code></pre>
<p>Then run the batch file:</p>
<pre><code class="lang-bash">start_wsl.bat
</code></pre>
<p>It will ask you to choose your GPU/platform setup:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-wsl.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>And it’s up and running:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-wsl-01.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>If this works, skip to the <strong>Run the WebUI</strong> step.</p>
<p>But if it fails (which I’ve seen), you must do it manually. Below are the instructions to install it manually in WSL. It’s also the instructions to install this in regular old Linux. Let’s get started.</p>
<h2 id="heading-install-anaconda">Install Anaconda</h2>
<p>I’m using Ubuntu in WSL. So here are the commands we’ll run:</p>
<pre><code class="lang-bash">sudo apt-get update
</code></pre>
<p>Always a good idea.</p>
<pre><code class="lang-bash">sudo apt-get install wget
</code></pre>
<p>Change into the tmp directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /tmp
</code></pre>
<p>Then, we want to get the latest version of the installation script from this directory. At the time of this writing, this is the most current version for Linux-x86_64:</p>
<pre><code class="lang-bash">wget https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh
</code></pre>
<p>This script is <em>huge</em>. After it’s done downloading, you should see something like this:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-00.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Then you’ll want to validate it:</p>
<pre><code class="lang-bash">sha256sum Anaconda3-2023.09-0-Linux-x86_64.sh
</code></pre>
<p>and if you don’t see any errors, you’re good to go:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-01.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Now it’s time to run it!</p>
<pre><code class="lang-bash">bash Anaconda3-2023.09-0-Linux-x86_64.sh
</code></pre>
<p>Accept the license terms (if you want to use it) and press enter.</p>
<p>It will ask where you want to install it. I chose the default location:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-02.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Then, grab a beverage and wait a while. I prefer ice water with lemon.</p>
<p>It’s going to ask if you want to initialize Conda automatically. I do a ton of Python stuff, so I select yes. Choose whatever works best for you.</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-03.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Now exit the shell and restart your WSL window.</p>
<h3 id="heading-install-the-text-ui">Install the Text UI</h3>
<p>Next, we will install the Web UI interface for our models. This is a Gradio web UI for Large Language Models.</p>
<p>As stated in the repo, their goal is to become the <a target="_blank" href="https://github.com/AUTOMATIC1111/stable-diffusion-webui">AUTOMATIC1111/stable-diffusion-webui</a> of text generation.</p>
<p>Clone it into a folder you’ll want to work in:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/oobabooga/text-generation-webui.git
</code></pre>
<p>Now type in</p>
<p><code>conda deactivate</code></p>
<p>If you have a base version running. We’ll then create a new environment:</p>
<pre><code class="lang-bash">conda create -n textgen python=3.11
conda activate textgen
</code></pre>
<p>If you see (textgen) in front of your prompt, it’s working.</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-04.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Now, we need to install PyTorch. I’m using an NVidia card, so I type in:</p>
<pre><code class="lang-bash">pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
</code></pre>
<p>If you aren’t using an NVidia card and want to do CPU only, use this:</p>
<pre><code class="lang-bash">pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
</code></pre>
<p>You’ll see a lot of this:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-05.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Wait for it to finish. If you are running an NVidia card, you may need to do this:</p>
<pre><code class="lang-bash">conda install -y -c <span class="hljs-string">"nvidia/label/cuda-12.1.0"</span> cuda-runtime
</code></pre>
<p>Next, we need to install some more dependencies. This will depend on your machine.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> text-generation-webui
pip install -r &lt;requirements file according to table below&gt;
</code></pre>
<p>Requirements file to use:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>GPU</td><td>CPU</td><td>requirements file to use</td></tr>
</thead>
<tbody>
<tr>
<td>NVIDIA</td><td>has AVX2</td><td><code>requirements.txt</code></td></tr>
<tr>
<td>NVIDIA</td><td>no AVX2</td><td><code>requirements_noavx2.txt</code></td></tr>
<tr>
<td>AMD</td><td>has AVX2</td><td><code>requirements_amd.txt</code></td></tr>
<tr>
<td>AMD</td><td>no AVX2</td><td><code>requirements_amd_noavx2.txt</code></td></tr>
<tr>
<td>CPU only</td><td>has AVX2</td><td><code>requirements_cpu_only.txt</code></td></tr>
<tr>
<td>CPU only</td><td>no AVX2</td><td><code>requirements_cpu_only_noavx2.txt</code></td></tr>
</tbody>
</table>
</div><p>(this comes from the instructions)</p>
<p>After everything is installed, you should be ready to run the WebUI.</p>
<h2 id="heading-run-the-webui">Run the WebUI</h2>
<p>Now we’re ready to run! In the <code>text-generation-webui</code> directory, run the following:</p>
<pre><code class="lang-bash">python server.py
</code></pre>
<p>And you should see this:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-06.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Awesome! Let’s load it up in the web browser:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-07.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>If you see this, you’re golden! However, you can’t do anything with it yet. You’ll need a model.</p>
<h2 id="heading-downloading-an-llm-model">Downloading an LLM model</h2>
<p>Your models will be downloaded and placed in the <code>text-generation-webui/models</code> folder. There are several ways to download the models, but the easiest way is in the web UI.</p>
<p>Click on “Model” in the top menu:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-08.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Here, you can click on “Download model or Lora” and put in the URL for a model hosted on <a target="_blank" href="https://huggingface.co/models?pipeline_tag=text-generation&amp;sort=downloads">Hugging Face</a>.</p>
<p>There are tons to choose from. The first one I will load up is the <a target="_blank" href="https://huggingface.co/TheBloke/Nous-Hermes-13B-GPTQ">Hermes 13B GPTQ</a>.</p>
<p>I only need to place the username/model path from Hugging Face to do this.</p>
<pre><code class="lang-plaintext">TheBloke/Nous-Hermes-13B-GPTQ
</code></pre>
<p>And I can then download it through the web interface.</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-09.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>After I click refresh, I can see the new model available:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-10.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Select it, and press load. Now we’re ready to go!</p>
<h2 id="heading-having-a-chat">Having a Chat</h2>
<p>There are a ton of parameters you can adjust. You can get lost in the settings, and once I learn more about it, I’ll certainly share it here.</p>
<p>Here was my test chat:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-11.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Hey! It works! Awesome, and it’s running locally on my machine.</p>
<p>I decided to ask it about a coding problem:</p>
<p><img src="https://www.jeremymorgan.com/images/blog/generative-ai/how-to-run-chat-gpt-like-llm-locally/how-to-run-chat-gpt-like-llm-locally-12.webp" alt="“How to run a ChatGPT like LLM locally”" /></p>
<p>Okay, not quite as good as GitHub Copilot or ChatGPT, but it’s an answer! I’ll play around with this and share what I’ve learned soon.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You may want to run a large language model locally on your own machine for many reasons. I’m doing it because I want to understand LLMs better and understand how to tune and train them. I am deeply curious about the process and love playing with it. You may have your own reasons for doing it, such as content generation or a chatbot to joke around with. The fact that you don’t have to be connected to the internet or pay a monthly fee is awesome.</p>
<p>What are you doing with LLMs today? <a target="_blank" href="https://www.twitter.com/JeremyCMorgan">Let me know! Let’s talk</a>.</p>
<p>Also if you have any questions or comments, feel free to reach out.</p>
<p>Happy hacking!</p>
<p><strong>If you're into Computer Vision and other cool AI tech, you should subscribe to my</strong> <a target="_blank" href="https://mailchi.mp/4961a415a64f/learn-ai-newsletter"><strong>AI Architect Newsletter</strong></a> <strong>to keep up with the latest stuff!</strong></p>
]]></content:encoded></item><item><title><![CDATA[How to Read Text From an Image with Python]]></title><description><![CDATA[If you want to read text from an image with a simple Python script, this tutorial is for you. Thanks to the work of many great people over the last few decades, you can read the text from an image with a few lines of code. Really! Let’s jump in.

Wha...]]></description><link>https://www.jeremymorgan.dev/how-to-read-text-from-an-image-with-python</link><guid isPermaLink="true">https://www.jeremymorgan.dev/how-to-read-text-from-an-image-with-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[python projects]]></category><category><![CDATA[AI]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[image processing]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Mon, 23 Oct 2023 16:46:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698079502862/d3e88328-9e11-4ddf-9f2c-4c5470c39259.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you want to read text from an image with a simple Python script, this tutorial is for you. Thanks to the work of many great people over the last few decades, you can read the text from an image with a few lines of code. Really! Let’s jump in.</p>
<p><img src="https://www.jeremymorgan.com/images/tutorials/python-tutorials/read-text-from-image/read-text-from-image-00.webp" alt="How to read text from an image with Python" /></p>
<h2 id="heading-what-is-ocr-tesseract">What is OCR? Tesseract?</h2>
<p>Optical Character Recognition, or OCR has <a target="_blank" href="https://www.docsumo.com/blog/optical-character-recognition-history">been around for a long time</a>. It's a technique that “reads” different types of documents into editable and searchable text. It works by recognizing characters in the image and converting them into machine-readable text. It’s a lot of magic, but it works well.</p>
<p><a target="_blank" href="https://github.com/tesseract-ocr/tesseract">Tesseract</a> is an open-source OCR engine developed by Google. It is highly accurate and supports multiple languages. This library will do all the heavy lifting for us. We’ll use it in this tutorial to quickly read the text in some images.</p>
<h3 id="heading-step-1-set-up-your-python-environment">Step 1: Set up your Python Environment</h3>
<p>First, you’ll need to make sure Python is installed. We’re going to create a virtual environment.</p>
<ul>
<li><p><a target="_blank" href="https://www.pythonhelp.org/learn/introduction/setting-up-development-environment-windows/">How to install Python and set up a virtual environment in Windows</a></p>
</li>
<li><p><a target="_blank" href="https://www.pythonhelp.org/learn/introduction/setting-up-development-environment-mac/">How to set up your Python environment on a Mac</a></p>
</li>
<li><p><a target="_blank" href="https://www.pythonhelp.org/learn/introduction/setting-up-development-environment-linux/">How to setup Python environment in Linux</a></p>
</li>
</ul>
<p>I’m using Linux, so I’ll create a directory named <code>textreader</code> and type in</p>
<pre><code class="lang-plaintext">python -m venv textreader
</code></pre>
<p>Then</p>
<pre><code class="lang-plaintext">source textreader/bin/activate
</code></pre>
<h3 id="heading-step-2-install-the-required-libraries">Step 2: Install the Required Libraries</h3>
<p>First, we’ll need to install Tesseract on your system. Here are the <a target="_blank" href="https://tesseract-ocr.github.io/tessdoc/Installation.html">instructions to install Tesseract</a> on your chosen operating system.</p>
<p>Make sure Tesseract is installed by typing:</p>
<pre><code class="lang-plaintext">tesseract -v
</code></pre>
<p>and you should see output that looks like this:</p>
<p><img src="https://www.jeremymorgan.com/images/tutorials/python-tutorials/read-text-from-image/read-text-from-image-01.webp" alt="How to read text from an image with Python" /></p>
<p>Then, we’ll install a couple of Python libraries.</p>
<p><a target="_blank" href="https://pypi.org/project/pytesseract/">Pytesseract</a> is a Python library that is a wrapper for the Tesseract OCR engine. This makes it easy to use in Python applications. We’ll install that and Pillow.</p>
<p><a target="_blank" href="https://pypi.org/project/Pillow/">Pillow</a> is the Python Image Library. It’s used for image processing and manipulation. It’s used to pre-process images before applying OCR techniques. It does things like image thresholding and other steps to the image to enhance the accuracy of the reading.</p>
<p>Next, we’ll install Pytesseract and Pillow together for our first application:</p>
<pre><code class="lang-plaintext">pip install pytesseract
pip install pillow
</code></pre>
<p>Your output should look something like this:</p>
<p><img src="https://www.jeremymorgan.com/images/tutorials/python-tutorials/read-text-from-image/read-text-from-image-02.webp" alt="How to read text from an image with Python" /></p>
<p>In some cases, like above, it may say the requirement is already satisfied for Pillow.</p>
<p>And we’re ready to go.</p>
<h3 id="heading-step-3-select-your-image">Step 3: Select your Image</h3>
<p>To start, I’m going to choose something easy. I’ll use a screenshot from my website. This will be clear, easy-to-read text that should work great.</p>
<p><img src="https://www.jeremymorgan.com/images/tutorials/python-tutorials/read-text-from-image/read-text-from-image-03.webp" alt="How to read text from an image with Python" /></p>
<p>I’ll save that as image-1.jpg in my folder.</p>
<h3 id="heading-step-4-write-the-script">Step 4: Write the Script</h3>
<p>Now, we’re ready to build our Python script to read the text from that image and output it to the screen.</p>
<p>First, we’ll import the libraries:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pytesseract
<span class="hljs-keyword">from</span> PIL <span class="hljs-keyword">import</span> Image
</code></pre>
<p>Then open the image:</p>
<pre><code class="lang-python">image = Image.open(<span class="hljs-string">'image-1.jpg'</span>)
</code></pre>
<p>And then, we’ll use Tesseract to convert the text in the image to a string. Didn’t I say this library does <em>all</em> the heavy lifting for us?</p>
<pre><code class="lang-python">text = pytesseract.image_to_string(image)
</code></pre>
<p>Finally, we’ll print it out:</p>
<pre><code class="lang-python">print(text)
</code></pre>
<p>Let’s run it and see what it looks like.</p>
<h3 id="heading-step-5-watch-the-magic-happen">Step 5: Watch the Magic Happen</h3>
<p>We run our script and get this:</p>
<p><img src="https://www.jeremymorgan.com/images/tutorials/python-tutorials/read-text-from-image/read-text-from-image-04.webp" alt="How to read text from an image with Python" /></p>
<p>Awesome! So it’s not perfect, but it’s pretty darn good. You can read the text from the image we sent, and it’s somewhat formatted the way it is in the image. That’s awesome!</p>
<p>Congrats! You can now read the text from images in Python. Next, we’ll look at some more advanced stuff.</p>
<h3 id="heading-learning-the-limitations">Learning the Limitations</h3>
<p>In our first example, we had a very clear image. The text is formatted and crisp in that image, so it’s easy to read. Let’s step it up a bit.</p>
<p>I picked a more challenging image, one from <a target="_blank" href="https://www.pexels.com/photo/welcome-to-our-home-print-brown-wooden-wall-decor-163046/">Pexels</a>, that isn’t quite so easy.</p>
<p><img src="https://www.jeremymorgan.com/images/tutorials/python-tutorials/read-text-from-image/read-text-from-image-05.webp" alt="How to read text from an image with Python" /></p>
<p>Let’s see what the output is when reading this image:</p>
<p><img src="https://www.jeremymorgan.com/images/tutorials/python-tutorials/read-text-from-image/read-text-from-image-06.webp" alt="How to read text from an image with Python" /></p>
<p>Oof. Nothing. I included this because it’s important to know the limitations of this process. Unusual fonts and different angles will affect how well this works. There isn’t much we can do to read this image without some extensive work.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this tutorial, we learned how to use Tesseract to read text from an image and put it into a machine-readable form. We can read many other things with OCR, and we’ll deep dive into some of this stuff in future articles.</p>
<p>Feel free to play around with this and see what you can come up with! In a future tutorial, we’ll use OpenCV to refine things and do more pre-processing of the images we’ll read from. It will be fun.</p>
<p>Bookmark this blog and come back for more cool Python tutorials.</p>
<p>Questions? Comments? <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Yell at me!</a></p>
<p><strong>If you're into Computer Vision and other cool AI tech, you should subscribe to my</strong> <a target="_blank" href="https://mailchi.mp/4961a415a64f/learn-ai-newsletter"><strong>AI Architect Newsletter</strong></a> <strong>to keep up with the latest stuff!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Dall-E 3 vs Midjourney - Which is better?]]></title><description><![CDATA[OpenAI recently released the third version of DALL-E. Of course, the biggest news from this is the integration with ChatGPT. This could be a huge step forward in prompt creation. But we’re not going to focus on that part today. We will examine the ou...]]></description><link>https://www.jeremymorgan.dev/dall-e-3-vs-midjourney-which-is-better</link><guid isPermaLink="true">https://www.jeremymorgan.dev/dall-e-3-vs-midjourney-which-is-better</guid><category><![CDATA[AI]]></category><category><![CDATA[midjourney]]></category><category><![CDATA[dall-e3]]></category><category><![CDATA[generative ai]]></category><category><![CDATA[generative art]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Midjourney ai]]></category><category><![CDATA[Prompt Engineering]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Thu, 19 Oct 2023 17:14:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1697735633314/d3224ce2-f6a8-4637-bf20-2053f6071ad1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>OpenAI recently released the third version of DALL-E. Of course, the biggest news from this is the integration with ChatGPT. This could be a huge step forward in prompt creation. But we’re not going to focus on that part today. We will examine the output of <a target="_blank" href="https://labs.openai.com/">Dall-E 3</a> and see if it’s better than <a target="_blank" href="https://www.midjourney.com/app/">Midjourney</a>.</p>
<p>Recently, I’ve been using Midjourney more for image generation. Dall-E 2 was good, but not as good as Midjourney. Has that changed? Let’s throw a few simple prompts at it to see.</p>
<h2 id="heading-prompt-a-realistic-portrait-of-a-cat-wearing-a-wizards-hat">Prompt: A realistic portrait of a cat wearing a wizard’s hat</h2>
<h4 id="heading-dall-e-3">Dall-E 3</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/76ae88be9e5ee4c6def94347a555285fb71e3680/b86e3/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-00.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<h4 id="heading-midjourney">Midjourney</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/6cd20456b413998d48d72b2acd1690738c2c3303/25f68/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-01.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<p>This first example is clear. Midjourney definitely looks better. More realistic and detailed. Our prompt may be too simplistic. Let’s try something else.</p>
<h4 id="heading-prompt-a-red-tesla-roadster-driving-down-a-highway-illustrated-in-the-style-of-looney-tunes-in-the-background-is-a-typical-looney-tunes-city-however-the-car-is-a-modern-tesla">Prompt: <em>A red Tesla Roadster driving down a highway. Illustrated in the style of Looney Tunes. In the background is a typical Looney Tunes city. However, the car is a modern Tesla.</em></h4>
<h4 id="heading-dall-e-3-1">Dall-E 3</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/a7bda24b609e338e95f45362896450008cb247d9/ad741/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-02.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<h4 id="heading-midjourney-1">Midjourney</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/3929a7a351541dfb8af32bee3c9dab445ebfd01c/c57c6/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-03.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<p>Okay, once again, Midjourney is blowing Dall-E out of the water. Neither look like a Looney Tunes cartoon, but Midjourney certainly comes closer.</p>
<p>Let’s take some prompts from <a target="_blank" href="https://mspoweruser.com/best-dall-e-2-prompts/">“The 30 best Dall-E 2 prompts for amazing results”</a> and see what we can come up with.</p>
<h4 id="heading-prompt-whimsical-painting-of-an-enchanted-forest-with-mythical-creatures-vibrant-colors-and-intricate-details">Prompt: <em>Whimsical painting of an enchanted forest with mythical creatures, vibrant colors, and intricate details.</em></h4>
<h4 id="heading-dall-e-3-2">Dall-E 3</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/48ce317cad777b65a64aefcfa75a892a66d31895/ec74d/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-04.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<h4 id="heading-midjourney-2">Midjourney</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/15e7ff3aaccde83f75ddeb38abd9a882eaa392e1/2de22/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-05.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<h4 id="heading-prompt-victorian-era-painting-of-a-masquerade-ball-with-elaborate-costumes-contrasting-colors-and-soft-lighting">Prompt: <em>Victorian-era painting of a masquerade ball with elaborate costumes, contrasting colors, and soft lighting.</em></h4>
<h4 id="heading-dall-e-3-3">Dall-E 3</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/a3530647431713b781f9d2ba81a6aa4775a2e962/b2776/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-06.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<h4 id="heading-midjourney-3">Midjourney</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/1a61abd92e0de2ec15ba8c324584dbdbf43e5e7d/0eb1e/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-07.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<p>This one is a little closer. I like the Midjourney one better, but only because of the paintings’ additional detail and different framing. The angles and framing of the Dall-E renderings are dull, and the subject isn’t clear. But it’s fairly close.</p>
<p>Let’s try the #1 best prompt according to that article.</p>
<h4 id="heading-prompt-realistic-painting-of-a-dystopian-industrial-city-with-towering-factories-pollution-filled-air-and-a-gloomy-sky">Prompt: <em>Realistic painting of a dystopian industrial city with towering factories, pollution-filled air, and a gloomy sky.</em></h4>
<h4 id="heading-dall-e-3-4">Dall-E 3</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/7967bb9be92c14a7c0814d20586e681f8a80bbe4/00e0d/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-08.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<h4 id="heading-midjourney-4">Midjourney</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/05ecf92fadacae1db58338d54ff9eadd4ab0a5ae/e000a/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-09.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<p>With this one, the style and the rendering of Dall-E 3 aren’t bad. It looks more like an actual painting. However, the Midjourney one is far more exciting and engaging.</p>
<p>Let’s try one of my favorite prompts: putting a 2005 Mustang GT <a target="_blank" href="https://www.instagram.com/p/CgdCa-AICed/">Like mine</a> in different settings.</p>
<h4 id="heading-prompt-a-3d-render-of-a-red-2005-ford-mustang-gt-on-a-deserted-country-highway">Prompt: <em>a 3D render of a red 2005 Ford Mustang GT on a deserted country highway</em></h4>
<h4 id="heading-dall-e-3-5">Dall-E 3</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/1af4627b078d0b71339104178848110493d72853/cf982/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-10.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<h4 id="heading-midjourney-5">Midjourney</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/9c06b3318d12fdd0369b2df82ab74269feed2342/50c91/images/blog/generative-ai/dall-e-3-vs-midjourney/dall-e-3-vs-midjourney-11.webp" alt="“Dall-E 3 vs Midjourney”" /></p>
<p>The difference here is drastic. One certainly looks more like a 3D rendering than the other.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Midjourney still produces better images overall than Dall-E. However, this is my experience, and with enough prompt tuning, I’m confident someone can make a fool of me and generate a much better image with Dall-E. Also, the ChatGPT integration is a nice bonus. Being able to tweak prompts using advanced techniques makes all the difference.</p>
<p>What has your experience been like? <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Let me know!</a></p>
<p><strong>If you're into Computer Vision and other cool AI tech, you should subscribe to my</strong> <a target="_blank" href="https://mailchi.mp/4961a415a64f/learn-ai-newsletter"><strong>AI Architect Newsletter</strong></a> <strong>to keep up with the latest stuff!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Generating AI Images from your own PC]]></title><description><![CDATA[You want to create AI-generated images. You’ve probably signed up with Dall-E, or Bing, or Midjourney. You’ve created some cool stuff. If you’re reading this, you want to generate those images on your own computer. There is no website or discord to d...]]></description><link>https://www.jeremymorgan.dev/generating-ai-images-from-your-own-pc</link><guid isPermaLink="true">https://www.jeremymorgan.dev/generating-ai-images-from-your-own-pc</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[generative ai]]></category><category><![CDATA[generative art]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[stable diffusion]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Mon, 02 Oct 2023 17:49:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696268838147/49abddc6-cfd2-42c7-a13a-374329a393e3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You want to create AI-generated images. You’ve probably signed up with Dall-E, or Bing, or Midjourney. You’ve created some cool stuff. If you’re reading this, you want to generate those images on your <em>own computer</em>. There is no website or discord to deal with. Running locally on your machine.</p>
<p>Why would anyone do this? Here are a few reasons:</p>
<ul>
<li><p>It’s educational</p>
</li>
<li><p>You can generate as many images as you want</p>
</li>
<li><p>It’s free</p>
</li>
</ul>
<p>With this tutorial’s help, you can generate images with AI on your own computer with <a target="_blank" href="https://github.com/Stability-AI/stablediffusion">Stable Diffusion</a>.</p>
<p>Let’s get started.</p>
<h2 id="heading-step-1-requirements">Step 1: Requirements</h2>
<p>There are some requirements for doing this on your own machine. It must have:</p>
<h3 id="heading-hardware">Hardware:</h3>
<ul>
<li><p>A modern AMD or Intel CPU</p>
</li>
<li><p>16 Gigabytes of RAM</p>
</li>
<li><p>SATA or NVMe solid state drive</p>
</li>
<li><p>NVidia GeForce GPU with at least 8 gigabytes of GDDR6 RAM</p>
</li>
</ul>
<h3 id="heading-software">Software:</h3>
<ul>
<li><p>You must have Python installed (<a target="_blank" href="https://www.pythonhelp.org/learn/introduction/setting-up-development-environment-windows/">How to install Python in Windows 11</a>).</p>
</li>
<li><p>You can use Anaconda if you want (<a target="_blank" href="https://www.jeremymorgan.com/tutorials/python-tutorials/how-to-install-anaconda-windows/">How to install Anaconda in Windows 11</a>).</p>
</li>
<li><p>You must have Git Installed (<a target="_blank" href="https://www.simplilearn.com/tutorials/git-tutorial/git-installation-on-windows">How to install Git in Windows 11</a>).</p>
</li>
<li><p>You need an account at <a target="_blank" href="https://huggingface.co/">HuggingFace</a> (it’s a free account)</p>
</li>
</ul>
<p>Check your Python version to make sure it’s up to snuff:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/2165b556678b83c8a3ef8f13bff8bbffd125f8f7/df3d3/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-00.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>And make sure Git is installed:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/c2f1dcc2497f0f420406760117484bf43d8edfa0/d99eb/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-01.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>And you’re ready to go.</p>
<h2 id="heading-step-2-install-stable-diffusion-web-ui">Step 2: Install Stable Diffusion Web UI</h2>
<p>Create a folder somewhere where you want the software to live. Go to that folder:</p>
<p><code>cd /your/project/directory</code></p>
<p>(for me it’s C:\Users\jerem\Projects)</p>
<p>Then clone the repository:</p>
<p><code>git clone</code> <a target="_blank" href="https://github.com/AUTOMATIC1111/stable-diffusion-webui.git"><code>https://github.com/AUTOMATIC1111/stable-diffusion-webui.git</code></a> <code>stable-diffusion-demo</code></p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/f1034dc1c6ce5bc42f6ac2b7f265f2d50a474cc0/b57af/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-02.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>You should see the folder you just created:</p>
<p><code>stable-diffusion-demo</code></p>
<p>Now we need to go into the models folder:</p>
<p><code>cd stable-diffusion-demo\models\Stable-diffusion</code></p>
<p>It should look like this:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/a76eccef4acadd6c6db176bd1b7ca92bee17ddc9/20598/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-03.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>This is where we’ll put the Stable Diffusion models when we download them.</p>
<h2 id="heading-step-3-download-the-model-from-hugging-face">Step 3: Download the Model from Hugging Face</h2>
<p>Next, we need a stable diffusion model, and we can get one from <a target="_blank" href="https://huggingface.co/">Hugging Face</a>.</p>
<p>Let’s try the <a target="_blank" href="https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.ckpt">v1-5-pruned-emaonly.ckpt</a> model. Download it to the <code>stable-diffusion-demo/models/Stable-diffusion</code> folder:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/837589a9170d2be610ac837120bb7e7f5d2363d9/45ff3/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-04.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>It might take a while to download (4GB at the time of this article).</p>
<p>Ok, now.. you’re ready to run the web app!</p>
<h3 id="heading-step-4-run-the-stable-diffusion-web-ui">Step 4: Run the Stable Diffusion Web UI</h3>
<p>At your command prompt, make sure you’re in the folder you created in step 2.</p>
<p><code>cd stable-diffusion-demo</code></p>
<p>Then run <code>webui-user.bat</code></p>
<p>The first time you do this, it will install everything needed, so it may take a few minutes.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/2920c9c72da639463ba53cd3b6b18a4333acd423/62f55/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-05.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>Once it’s completed, your command prompt will look something like this:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/fb54d7872bdb841a4b3f369c9cb8e82b61b89e3c/ef950/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-06.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>And the web server will be up and running.</p>
<h3 id="heading-step-5-the-web-interface">Step 5: The Web Interface</h3>
<p>Load up the following URL in your web browser:</p>
<p><a target="_blank" href="http://127.0.0.1:7860/"><code>http://127.0.0.1:7860/</code></a></p>
<p>It may load up automatically in the browser as well. But you’ll see a full web interface you can use to generate images:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/9aa3e3236917a548f6f710412ca8d23961b997cc/d6d42/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-07.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>Awesome! Let’s try it out!</p>
<p>The sampling method is the first thing you might notice in the generation tab. There are a LOT of them:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/edbdf0a6363469508b2969e8df57de82f2829e08/89cf9/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-08.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>I suggest spending some time adjusting and playing with this. But for now, we’ll use <code>DPM++ 2M Karras</code> that’s selected as default.</p>
<p>Here are some settings to pay attention to:</p>
<ul>
<li><p><strong>Sampling steps</strong> - This will repeatedly try to improve the image as it generates. Low values will be low quality, but fast. High values will be higher quality and slower to generate.</p>
</li>
<li><p><strong>Width and height</strong> - These will control the size of the generated image. Like above, larger images will look better and take longer.</p>
</li>
<li><p><strong>CFG Scale</strong> - This will change how “random” the result is. A higher value will attempt to take the prompt as literally as possible. Lower values will produce more creative results.</p>
</li>
<li><p><strong>Seed</strong> - This value determines the output of the random number generator. You can use it as a key. If you use the same prompt with the same seed, you’ll get the same image. You can create many variations from the same “key”.</p>
</li>
</ul>
<p>So today, I will leave everything at the default settings. The only thing I will do is create a <code>seed</code> to progressively improve the same image as we go.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/4d9c9c4d1203bd6dcc828cd8290941a484891228/b494d/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-09.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>And I’ll add in a prompt to make something silly.</p>
<p>‘a photo of an anthropomorphic frog riding a skateboard in Times Square`</p>
<p>It took about a minute to generate this image. (Laptop with RTX 3060)</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/211861faf97f96a3ca908bc9ba70d4459d53cb94/303ca/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-10.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>And it’s pretty cool! It’s impressive, considering it’s being run on my local machine. Let’s improve this image!</p>
<h3 id="heading-step-6-improving-images">Step 6: Improving Images</h3>
<p>Here’s the actual image I produced:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/cf45eea77cb7ade627ac65068687276f72748f18/cde76/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-11.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>Let’s mess with the settings to see what we can improve. Let’s change the Sampling steps. This is how often it goes through the image and tries to improve it. The default setting is <code>20</code>. Let’s set it to the maximum number of <code>150</code>. This will take more than a minute to produce now.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/485d519cdcafe319d851874e2800002e16eb7a6b/2e310/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-12.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>I will leave the prompt and the seed the same and click “Generate” again.</p>
<p>I’ll warn you: it can work the GPU when you do this.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/556e5962c8ff7d50e0476946a150ec7aa3b67cd7/0ca64/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-13.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>Here is the result after <strong>150</strong> sampling steps:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/7054d90a1f483164bb9dda770f70c0aa31a8b907/77895/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-14.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>So it’s certainly different, but not in a significant way. We don’t want to scale up our generating time by 10x for this small change. I’ll change it back to <code>20</code> and change <code>CFG Scale</code> to <code>5</code>. This will make the model more “creative”.</p>
<p>Here are the settings:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/ddd5ab9ab7493d74782ff6d2931d8bc770a30a0a/99819/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-15.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>And here is the result:</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/d77e6a8879cb925ae0c6cd12152a6e11e6cefdf1/ce11f/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-16.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>Ok, that’s too creative. But you can see the changes that occur when you adjust it. You can also use different sampling methods as well:</p>
<h4 id="heading-dpm-sde-karras">DPM++ SDE Karras</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/d3ab144195a526361b2e571d85b8060ce6aa1eb2/c24f2/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-17.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>This model’s output is kind of neat because it shows the frog skateboarding better.</p>
<h4 id="heading-euler">Euler</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/ee55b16362b7d63dd0e3608a2d1d29031be1337a/1cd62/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-18.webp" alt="“How to Install Free AI image Generator”" /></p>
<h4 id="heading-dpm-3m-sde">DPM++ 3M SDE</h4>
<p><img src="https://d33wubrfki0l68.cloudfront.net/4cd78ca3bf1784f2a9eab03476e80737918caf10/8a72b/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-19.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>When attempting to draw things in cartoon, especially anthropomorphic models, it can come out very bizarre.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/5ac40456a9a656c01cfd3afcf6c9c4575a183332/758fe/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-20.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>But that’s all there is to it!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we:</p>
<ul>
<li><p>Installed the Stable Diffusion Web UI</p>
</li>
<li><p>Downloaded a model</p>
</li>
<li><p>Generated AI images</p>
</li>
<li><p>Modified the output</p>
</li>
</ul>
<p>All from our local machine! Here are the benefits and downsides of this method compared to something like Midjourney:</p>
<p>Pros:</p>
<ul>
<li><p>It’s free!</p>
</li>
<li><p>Generate as many images as you like</p>
</li>
<li><p>Runs locally and is not dependent on an internet connection</p>
</li>
</ul>
<p>Cons:</p>
<ul>
<li><p>Nowhere near the level of quality as Midjourney and others</p>
</li>
<li><p>You need a good machine to run this</p>
</li>
<li><p>It may take longer to generate images</p>
</li>
</ul>
<p><img src="https://d33wubrfki0l68.cloudfront.net/c9881832c004cf75e5e5469a553a356d8d7a56f4/950e0/images/tutorials/generative-ai/how-to-create-ai-images/how-to-create-ai-images-21.webp" alt="“How to Install Free AI image Generator”" /></p>
<p>So there you have it! Now, you can generate images on your machine and show your creations to the world. We are barely getting started with the possibilities available from this model. We’ll explore it more in the coming weeks.</p>
<p>If you have any questions, feel free to reach out!</p>
<p>– Jeremy</p>
<p>Questions? Comments? <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Yell at me!</a></p>
<p><strong>If you're into Computer Vision and other cool AI tech, you should subscribe to my</strong> <a target="_blank" href="https://mailchi.mp/4961a415a64f/learn-ai-newsletter"><strong>AI Architect Newsletter</strong></a> <strong>to keep up with the latest stuff!</strong></p>
]]></content:encoded></item><item><title><![CDATA[The Ultimate Guide to Calling a Function in Python]]></title><description><![CDATA[Python is one of my favorite programming languages. It’s simple and versatile. There’s a reason it’s so popular. It’s fun to use, and you can get a lot of work done without writing a ton of code.

“I’ll just write a quick Python script for this” - me...]]></description><link>https://www.jeremymorgan.dev/the-ultimate-guide-to-calling-a-function-in-python</link><guid isPermaLink="true">https://www.jeremymorgan.dev/the-ultimate-guide-to-calling-a-function-in-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[python projects]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Fri, 08 Sep 2023 17:54:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694195460188/7aee4090-9525-4b0f-b6d1-2e0d504b8751.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Python is one of my favorite programming languages. It’s simple and versatile. There’s a reason it’s so popular. It’s fun to use, and you can get a lot of work done without writing a ton of code.</p>
<blockquote>
<p><em>“I’ll just write a quick Python script for this”</em> - me, a bunch of times</p>
</blockquote>
<p>One of the things Python does well is abstracting complexity. One example of that is the Python function. A function is a reusable set of instructions to perform a task. Functions aren’t unique to Python; they work mostly the same as in other languages.</p>
<p>If you want to know how to write and call a function in Python, here’s a step-by-step guide.</p>
<h2 id="heading-the-anatomy-of-a-python-function">The Anatomy of a Python Function</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694195242311/ca051a81-b5cf-4a85-b171-807e564ac330.webp" alt class="image--center mx-auto" /></p>
<p>Before you can call a function, you have to write a function. Thankfully, that’s easy. Let’s look at the main components of a function.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">function_name</span>(<span class="hljs-params">parameters</span>):</span>
    <span class="hljs-comment"># Your code goes here</span>
    <span class="hljs-keyword">return</span>
</code></pre>
<p>The keyword ‘def’ refers to a <em>function definition</em> followed by your chosen function name and parentheses enclosing optional parameters. Parameters are anything you want to put into the function.</p>
<p>The action happens in the <em>function body</em> (Where it says your code goes here). This is where we put statements that make the function do work.</p>
<p>The <em>return</em> keyword allows you to send data <em>out</em> of the function. Note: You don’t always need to return a value. It’s optional.</p>
<p>So the main parts are</p>
<ul>
<li><p>definition (def keyword)</p>
</li>
<li><p>function name</p>
</li>
<li><p>parameters</p>
</li>
<li><p>body (what the function does)</p>
</li>
<li><p>return value</p>
</li>
</ul>
<p>All of these, put together, form a function.</p>
<h2 id="heading-calling-a-python-function">Calling a Python Function</h2>
<p>Once we’ve defined a function, calling it is as straightforward as writing the function’s name followed by parentheses. If our function requires <em>parameters</em>, we place these inside the parentheses. These are optional.</p>
<p>Let’s build a simple function to display Hello World whenever we call it.</p>
<pre><code class="lang-plaintext">def hello_world():
    print("Hello, World!")
</code></pre>
<p>Even though there are no parameters or a return value, this is a function in Python. The “output” of the function is printing Hello World.</p>
<p>We can call this function with this line of code:</p>
<pre><code class="lang-python">hello_world()
</code></pre>
<p><img src="https://d33wubrfki0l68.cloudfront.net/0803006d0cb4d62d204d3f3afb86e4a8013ea47c/dded8/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-01.webp" alt="“How to call a function in Python”" /></p>
<p>And this will output “Hello, World!” to your console whenever we call it.</p>
<p>In fact, if we call it five times:</p>
<pre><code class="lang-python">hello_world()
hello_world()
hello_world()
hello_world()
hello_world()
</code></pre>
<p>It will display the same thing five times.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/54e5811b77528e3ba6fd097ea509373067553c8a/7bb8f/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-02.webp" alt="“How to call a function in Python”" /></p>
<p>Congratulations, you’ve just written your first function in Python.</p>
<h2 id="heading-the-power-of-function-parameters-in-python">The Power of Function Parameters in Python</h2>
<p><img src="https://d33wubrfki0l68.cloudfront.net/74b83a2fca5dcf29cdb67d6738e1ace6de4a512e/e3ae8/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-03.webp" alt="“How to call a function in Python”" /></p>
<p>Parameters are pieces of data we <em>pass into</em> the function. The work of the function depends on what we pass into it. Parameters enable us to make our Python functions dynamic and reusable. We can define a function that takes parameters, allowing us to pass different arguments each time we call the function.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">greet</span>(<span class="hljs-params">name</span>):</span>
    print(<span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>)

greet(<span class="hljs-string">"Jeremy"</span>)
greet(<span class="hljs-string">"Susie"</span>)
greet(<span class="hljs-string">"Jim"</span>)
</code></pre>
<p>Here, the <code>greet()</code> function takes one parameter, ‘name’. When we call the function, we can pass any name we wish to greet.</p>
<h2 id="heading-dealing-with-multiple-parameters">Dealing with Multiple Parameters</h2>
<p>Python functions can accept multiple parameters, allowing us to add dynamic inputs to our function calls.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">greet</span>(<span class="hljs-params">name, city</span>):</span>
    print(<span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">" from "</span> + city + <span class="hljs-string">"!"</span>)

greet(<span class="hljs-string">"Jeremy"</span>, <span class="hljs-string">"Gaston"</span>)
greet(<span class="hljs-string">"Susie"</span>, <span class="hljs-string">"Forest Grove"</span>)
greet(<span class="hljs-string">"Jim"</span>, <span class="hljs-string">"Cornelius"</span>)
</code></pre>
<p>Now <code>greet()</code> takes two parameters, ‘name’ and ‘city’.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/fd67e56ac2f36f2557edf279e55478efc7ccdd15/fc906/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-04.webp" alt="“How to call a function in Python”" /></p>
<p>And it’s that easy. Congrats, you can now pass data into a function in Python.</p>
<h2 id="heading-leveraging-default-parameters-in-python-functions">Leveraging Default Parameters in Python Functions</h2>
<p><img src="https://d33wubrfki0l68.cloudfront.net/822e7a17bee5f915195c278aaf5ef24293432f35/71f63/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-05.webp" alt="“How to call a function in Python”" /></p>
<p>Sometimes, you want to set a value for a parameter as a default. This allows the function to be called even if no data was passed. Rather than throwing an error, it will populate the value with anything you specify.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">greet</span>(<span class="hljs-params">name=<span class="hljs-string">"User"</span></span>):</span>
    print(<span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>)

greet()
greet(<span class="hljs-string">"Alice"</span>)
</code></pre>
<p>Here, ‘greet()’ function has a default parameter ‘name’ set to ‘User’. If no argument is passed, the function greets ‘User’. If we provide a name, it greets that name instead.</p>
<p><img src="https://d33wubrfki0l68.cloudfront.net/bcf771e3caee5ac3f39a5be6ffaa588e37d6f586/b4ad2/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-06.webp" alt="“How to call a function in Python”" /></p>
<p>It’s a good way to set defaults.</p>
<h2 id="heading-python-return-statement">Python Return Statement</h2>
<p>The ‘return’ statement exits a function and returns a value. With it, we can store the output of a function in a variable for future use.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">square</span>(<span class="hljs-params">number</span>):</span>
    <span class="hljs-keyword">return</span> number * number

result = square(<span class="hljs-number">5</span>)
print(result)
</code></pre>
<p><img src="https://d33wubrfki0l68.cloudfront.net/c6d29beed2070a434ac6515c2d72e85990bb20c4/76012/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-07.webp" alt="“How to call a function in Python”" /></p>
<p>In this case, <code>square()</code> function returns the square of the input number. The output can be stored in a variable and used later.</p>
<p>The return keyword is used to push values out of the function to use in your program.</p>
<h2 id="heading-functions-are-awesome">Functions are awesome!</h2>
<p><img src="https://d33wubrfki0l68.cloudfront.net/13258187931f220292da323e187ba451c6dacafc/5cc5b/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-08.webp" alt="“How to call a function in Python”" /></p>
<p>Python functions are a powerful tool in a programmer’s arsenal. They encapsulate code blocks for specific tasks, enhancing the readability and maintainability of the code. Understanding how to call a function in Python, employ parameters, and leverage the ‘return’ statement is fundamental to proficient Python programming.</p>
<p>Remember, practice is key! The more you use this, the more second nature it will be for you.</p>
<h2 id="heading-the-versatility-of-variable-arguments-in-python">The Versatility of Variable Arguments in Python</h2>
<p>Python introduces an interesting feature in functions: variable-length arguments. Sometimes we don’t know how many arguments will be passed to a function. Python’s variable arguments (*args and **kwargs) solve this problem.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_numbers</span>(<span class="hljs-params">*args</span>):</span>
    <span class="hljs-keyword">return</span> sum(args)

print(add_numbers(<span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-number">7</span>, <span class="hljs-number">9</span>))
</code></pre>
<p><img src="https://d33wubrfki0l68.cloudfront.net/4070e4dd5542e6a021e5412a91bfb25315f12d88/8c5b1/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-09.webp" alt="“How to call a function in Python”" /></p>
<p>In the example, <code>add_numbers()</code> uses <code>*args</code> to accept any number of parameters. The function then sums up all the numbers and returns the total.</p>
<h2 id="heading-in-depth-with-python-keyword-arguments">In-Depth with Python Keyword Arguments</h2>
<p>Python functions also allow keyword arguments, which enable us to identify arguments by name. This can be extremely handy when a function has many parameters, and it improves the readability of our code.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">describe_pet</span>(<span class="hljs-params">pet_name, animal_type=<span class="hljs-string">'dog'</span></span>):</span>
    print(<span class="hljs-string">"I have a "</span> + animal_type + <span class="hljs-string">"."</span>)
    print(<span class="hljs-string">"My "</span> + animal_type + <span class="hljs-string">"'s name is "</span> + pet_name + <span class="hljs-string">"."</span>)

describe_pet(pet_name=<span class="hljs-string">'Willie'</span>)
</code></pre>
<p><img src="https://d33wubrfki0l68.cloudfront.net/39d47f165bc30c2352df3875055e6801ba003644/158e2/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-10.webp" alt="“How to call a function in Python”" /></p>
<p>In this scenario, ‘describe_pet()’ is called with the ‘pet_name’ keyword argument. The function also includes a default argument, ‘animal_type’, set to ‘dog’.</p>
<h2 id="heading-grasping-anonymous-functions-in-python-lambda">Grasping Anonymous Functions in Python: Lambda</h2>
<p><img src="https://d33wubrfki0l68.cloudfront.net/554072dea3c67d77f48b95f92692f33810d7e3f5/ac0d8/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-11.webp" alt="“How to call a function in Python”" /></p>
<p>Python’s ‘lambda’ function is a small, anonymous function defined with the ‘lambda’ keyword, rather than ‘def’. Lambda functions can accept any number of arguments but only have one expression.</p>
<pre><code class="lang-python">multiply = <span class="hljs-keyword">lambda</span> x, y: x * y

print(multiply(<span class="hljs-number">5</span>, <span class="hljs-number">4</span>))
</code></pre>
<p><img src="https://d33wubrfki0l68.cloudfront.net/d5988619ac00c8718d13bc42e03af80eef41dfc3/a2546/images/tutorials/python-tutorials/how-to-call-function-python/how-to-call-function-python-12.webp" alt="“How to call a function in Python”" /></p>
<p>In the code above, a lambda function is defined to multiply two numbers, and it’s called with two arguments: 5 and 4. The function returns the result of the multiplication.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations, you now know how to work with functions in Python. We have covered:</p>
<ul>
<li><p>The main parts of a function</p>
</li>
<li><p>Calling a Python function</p>
</li>
<li><p>Using function parameters</p>
</li>
<li><p>Using multiple parameters</p>
</li>
<li><p>Creating default parameters</p>
</li>
<li><p>Returning data with the return statement</p>
</li>
<li><p>Using variable parameters</p>
</li>
<li><p>Leveraging lambda functions</p>
</li>
</ul>
<p>Functions in Python provide a way of organizing and reusing code to create cleaner programming solutions.</p>
<p>As a next step, we recommend you delve deeper into advanced Python function topics such as recursive functions, decorators, and generator functions. I’ll be adding more content like this to this blog very soon.</p>
<p><a target="_blank" href="https://www.jeremymorgan.dev">Bookmark this blog</a> and come back for more cool Python tutorials.</p>
<p>Questions? Comments? <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Yell at me!</a></p>
]]></content:encoded></item><item><title><![CDATA[A Guide to Blurring Images with OpenCV and Python]]></title><description><![CDATA[If you're reading this, you're probably curious about computer vision or just starting out. You've come to the right place. In this tutorial, we'll learn to blur images using OpenCV and Python. This is one of many OpenCV tutorials I have here.
What i...]]></description><link>https://www.jeremymorgan.dev/how-to-blur-images-with-opencv-and-python</link><guid isPermaLink="true">https://www.jeremymorgan.dev/how-to-blur-images-with-opencv-and-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[python projects]]></category><category><![CDATA[Computer Vision]]></category><category><![CDATA[opencv-python]]></category><category><![CDATA[opencv]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Mon, 10 Apr 2023 16:30:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681144130718/fcb658af-173b-4a74-b020-c679e188e497.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you're reading this, you're probably curious about computer vision or just starting out. You've come to the right place. In this tutorial, we'll learn to blur images using <a target="_blank" href="https://opencv.org">OpenCV</a> and Python. This is one of many <a target="_blank" href="/tags/opencv/">OpenCV tutorials</a> I have here.</p>
<h2 id="heading-what-is-blurring">What is Blurring?</h2>
<p>First off, let's understand what blurring is. Blurring is a process where we reduce the sharpness of an image by blending the colors of neighboring pixels. Basically, we smooth out the image, which can be useful for reducing noise, improving the overall look, or creating artistic effects.</p>
<h2 id="heading-how-does-blurring-work">How Does Blurring Work?</h2>
<p>To blur an image, we need to apply a filter, which is simply a small matrix of numbers called a kernel. Don't worry if you don't know what a matrix is. Think of it as a grid of numbers. The kernel moves across the image, and for each pixel, it calculates the weighted average of the neighboring pixels' colors using the kernel values.</p>
<p>There are different types of kernels, and today we'll explore two common ones: the Gaussian blur and the Median blur.</p>
<h2 id="heading-lets-write-some-code">Let's Write Some Code!</h2>
<p>Before we start coding, make sure you have Python installed, and OpenCV set up. I prefer to use Python virtual environments for my projects, and it's easy to setup.</p>
<pre><code class="lang-bash">python -m venv opencvdemo
</code></pre>
<p>Here I am naming my environment <code>opencvdemo</code> but you can name it whatever you like.</p>
<p>Then, activate OpenCV:</p>
<p>In Linux or Mac:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> opencvdemo/bin/activate
</code></pre>
<p>In Windows:</p>
<pre><code class="lang-powershell">.\opencvdemo\Scripts\activate
</code></pre>
<p>You'll need to install OpenCV. You can do that by using pip:</p>
<pre><code class="lang-bash">pip install opencv-python
</code></pre>
<p>Now, let's create a Python file and import the necessary libraries.</p>
<p>I named my script <a target="_blank" href="http://blurring.py"><code>blurring.py</code></a>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> cv2
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np
</code></pre>
<h2 id="heading-loading-the-image">Loading the Image</h2>
<p>We'll begin by loading an image from your computer. Replace 'sampleimage.png' with the actual path to your image. (It can also be .jpg if you like).</p>
<pre><code class="lang-python">image = cv2.imread(<span class="hljs-string">'sampleimage.png'</span>)
</code></pre>
<p>Here's the sample I'm using. Feel free to use it yourself. <a target="_blank" href="https://www.jeremymorgan.com/images/tutorials/opencv/how-to-blur-image/how-to-blur-image-00.png">Download it here</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681143885711/fe68406f-7a06-4ea0-8614-77fe35a54f7d.png" alt class="image--center mx-auto" /></p>
<p><em>I generated it with Dall-E, so I don't own it.</em></p>
<h2 id="heading-gaussian-blur">Gaussian Blur</h2>
<p>Let's start with the Gaussian blur. This kernel uses the <strong>Gaussian</strong> function, a bell-shaped curve that spreads the blur evenly around the pixel, making it look more natural.</p>
<p>To apply the Gaussian blur, we'll use OpenCV's <code>GaussianBlur()</code> function, which takes three arguments:</p>
<ul>
<li><p>The input image.</p>
</li>
<li><p>The kernel size (width and height). They must be odd numbers.</p>
</li>
<li><p>The standard deviation (0 means it will be calculated automatically).</p>
</li>
</ul>
<pre><code class="lang-python">gaussian_blur_image = cv2.GaussianBlur(image, (<span class="hljs-number">11</span>, <span class="hljs-number">11</span>), <span class="hljs-number">0</span>)
</code></pre>
<p>Now, let's display the original image and the blurred one side by side:</p>
<pre><code class="lang-python">cv2.imshow(<span class="hljs-string">'Original Image'</span>, image)
cv2.imshow(<span class="hljs-string">'Gaussian Blurred Image'</span>, gaussian_blur_image)
cv2.waitKey(<span class="hljs-number">0</span>)
cv2.destroyAllWindows()
</code></pre>
<p>And it looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681143941481/c0117950-e0f4-40e0-ac06-cdef14afcb20.webp" alt /></p>
<p>Awesome, right? Just a few lines of code, and you can blur images.</p>
<h2 id="heading-median-blur">Median Blur</h2>
<p>Now let's do a Median blur. This kernel takes the median value (the middle value in a sorted list) of the neighboring pixels' colors, which reduces noise while preserving edges.</p>
<p>We'll use OpenCV's <code>medianBlur()</code> function to apply the Median blur, which takes two arguments: the input image and the kernel size (an odd number).</p>
<pre><code class="lang-plaintext">median_blur_image = cv2.medianBlur(image, 11)
</code></pre>
<p>And once again, let's display the original and blurred images:</p>
<pre><code class="lang-plaintext">cv2.imshow('Original Image', image)
cv2.imshow('Median Blurred Image', median_blur_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
</code></pre>
<p>Let's run it!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681143961729/b556a2cf-f20f-4c10-ad59-4edb5ab5d8a6.webp" alt /></p>
<p>This is a different kind of blur you may want to use.</p>
<p>It's pretty easy stuff.</p>
<h2 id="heading-saving-your-images">Saving Your Images</h2>
<p>We know how to display these images on the screen, but that's only part of it. What if you want to save them? It's easy with this one line of code:</p>
<pre><code class="lang-python">cv2.imwrite(<span class="hljs-string">"output.png"</span>, median_blur_image)
</code></pre>
<p>Of course, you can change <code>output.png</code> to whatever you want.</p>
<p>We used the cv2.imread() function to read the image, then performed some modifications to it, and use cv.imwrite() to write it to a new image. Chances are, you'll want to use this later.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this tutorial, we learned about</p>
<ul>
<li><p>Blurring - what it is and how it works</p>
</li>
<li><p>Loading images with OpenCV</p>
</li>
<li><p>Gaussian blurs</p>
</li>
<li><p>Median blurs</p>
</li>
<li><p>Saving image after modification</p>
</li>
</ul>
<p>Go ahead and experiment with this code. Change the kernel sizes and standard deviations to see how they affect blurring.</p>
<p>Remember, practice makes perfect.</p>
<p>You've unlocked a powerful skill in computer vision, and this is just the beginning! Often you'll want to apply a blur or other modifications before performing operations on an image, so now you know how.</p>
<p>There's much more to explore, like edge detection, object recognition, and even facial recognition. I'll be covering all these in future tutorials. The possibilities are endless.</p>
<p>Questions? Comments? <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Yell at me!</a></p>
<p><strong>If you're into Computer Vision and other cool AI tech, you should subscribe to my</strong> <a target="_blank" href="https://mailchi.mp/4961a415a64f/learn-ai-newsletter"><strong>AI Architect Newsletter</strong></a> <strong>to keep up with the latest stuff!</strong></p>
]]></content:encoded></item><item><title><![CDATA[How to Resize an Image with OpenCV]]></title><description><![CDATA[So you want to resize an image with OpenCV? You've found your answer. This tutorial will walk you through all the steps needed to do this.
I will use Python in this example, but it's a similar process in many different languages. I often work with Op...]]></description><link>https://www.jeremymorgan.dev/how-to-resize-an-image-with-opencv</link><guid isPermaLink="true">https://www.jeremymorgan.dev/how-to-resize-an-image-with-opencv</guid><category><![CDATA[Python]]></category><category><![CDATA[Computer Vision]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[image processing]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[opencv]]></category><category><![CDATA[opencv-python]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Fri, 03 Feb 2023 18:34:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675448887416/3f427b40-71c3-4593-9a18-d92ed9f666a4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So you want to resize an image with OpenCV? You've found your answer. This tutorial will walk you through all the steps needed to do this.</p>
<p>I will use Python in this example, but it's a similar process in many different languages. I often work with OpenCV in Go and C# as well. But let's stay on topic here.</p>
<p>This will be a step-by-step guide to quickly resize and save an image using OpenCV.</p>
<h2 id="heading-step-1-create-a-python-virtual-environment">Step 1: Create a Python Virtual Environment</h2>
<p>Whenever I do anything with Python, I create a Virtual Environment. It's like a container for your Python application. It makes it portable and easy to manage dependencies. I'm using Linux for this, but it's the same commands in other operating systems.</p>
<p>Open up a terminal window and choose the directory you'll be building your application under. I'm using a directory named "imageresizer" because I'm great at naming things creatively.</p>
<p>Type in:</p>
<pre><code class="lang-plaintext">python -m venv imageresizer
</code></pre>
<p>I'm going to name the Virtual Environment as "imageresizer". Again creativity. Let's activate the environment:</p>
<pre><code class="lang-plaintext">source imageresizer/bin/activate
</code></pre>
<p>Great! Your Virtual Environment is ready to use.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449004846/ee0e57b6-10db-4c9e-9da3-367743eabf13.webp" alt /></p>
<h2 id="heading-step-2-select-your-image">Step 2: Select your Image</h2>
<p>For this tutorial, I'm going to download a Photo by <a target="_blank" href="https://unsplash.com/@pj_visual?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Philip Jahn</a> from <a target="_blank" href="https://unsplash.com/photos/RkU0A-yHQUo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a>.</p>
<p>It's a beautiful photo and looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449024282/143cb87f-e86b-4bd1-b7fc-6398095a3cd7.webp" alt class="image--center mx-auto" /></p>
<p>And as you can see, it's quite large:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449035013/128b479d-caf7-4779-88e1-40a893a405e3.webp" alt /></p>
<p>5304x7592 is excellent for printing. Not so much for the web. So how can we resize this thing without making it look funny?</p>
<p>We can use OpenCV! Keep reading.</p>
<h2 id="heading-step-3-install-opencv">Step 3: Install OpenCV</h2>
<p>Next, we'll need to install OpenCV in our Virtual Environment.</p>
<p>Type in:</p>
<pre><code class="lang-plaintext">pip install opencv-python
</code></pre>
<p>And of course, I need to update pip. Just like it says, you type in:</p>
<pre><code class="lang-plaintext">pip install --upgrade pip
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449045093/8366bae5-9532-453d-ad54-3c1fdf4af879.webp" alt /></p>
<p>Ok, now OpenCV is installed. Let's build our script.</p>
<h2 id="heading-step-4-create-a-python-script">Step 4: Create a Python Script</h2>
<p>Let's create the Python Script using OpenCV to resize the images.</p>
<p>The first line imports our library.</p>
<pre><code class="lang-Python"><span class="hljs-keyword">import</span> cv2
</code></pre>
<p>Then we need to load the image we want to resize.</p>
<pre><code class="lang-Python">image = cv2.imread(<span class="hljs-string">'original.jpg'</span>)
</code></pre>
<p>Now let's get the original dimensions of the image:</p>
<pre><code class="lang-Python">height, width = image.shape[:<span class="hljs-number">2</span>]
</code></pre>
<p>This uses the shape function and stores the width and height of the image.</p>
<p>Now we need to set the output size of the image. This determines the size you want the <em>new</em> image to be.</p>
<pre><code class="lang-Python">output_size = (<span class="hljs-number">400</span>, <span class="hljs-number">400</span>)
</code></pre>
<p>One thing to note, OpenCV will scale this. So the larger dimension of the image will be 400, and the smaller dimension will be scaled with a factor.</p>
<p>We need to calculate that scaling factor. Since the original dimensions are not square, resizing it to a square will distort the image. This will scale the smaller dimension appropriately.</p>
<pre><code class="lang-Python">scaling_factor = min(output_size[<span class="hljs-number">0</span>]/width, output_size[<span class="hljs-number">1</span>]/height)
</code></pre>
<p>This divides the original image dimensions by the intended dimensions, then picks the smaller result for your scaling factor.</p>
<p>Now, we'll resize the image. We'll pass in the original image, x and y scaling factors, and set interpolation to cv2.INTER_AREA:</p>
<pre><code class="lang-Python">resized_image = cv2.resize(image, <span class="hljs-literal">None</span>, fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_AREA)
</code></pre>
<p>Finally, we'll write the file.</p>
<pre><code class="lang-Python">cv2.imwrite(<span class="hljs-string">'output.jpg'</span>, resized_image)
</code></pre>
<p>Awesome. Let's run it!</p>
<h2 id="heading-step-5-run-the-script">Step 5: Run the Script</h2>
<p>At the prompt, type in:</p>
<pre><code class="lang-Python">python resize.py
</code></pre>
<p>If it's successful, you won't see any output.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449059036/33688259-b29c-48eb-97b6-9529e2dc5bf7.webp" alt /></p>
<p>Now you can inspect your images. If you check the directory, you will see different file sizes, which tells you the image has changed:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449067360/dd8bc789-48b4-4225-b445-72bf03216e2b.webp" alt /></p>
<p>Now, if we open the image, we can see it's 267x400! Quite a bit smaller.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449074737/f3e94817-d83f-45a4-b444-d1b8b59188d9.webp" alt /></p>
<p>Congratulations! You just resized an image with OpenCV!</p>
<p>Here is the final code:</p>
<pre><code class="lang-Python"><span class="hljs-keyword">import</span> cv2

<span class="hljs-comment"># Load the image</span>
image = cv2.imread(<span class="hljs-string">'original.jpg'</span>)

<span class="hljs-comment"># Get current image size</span>
height, width = image.shape[:<span class="hljs-number">2</span>]

<span class="hljs-comment"># Set your output size</span>
output_size = (<span class="hljs-number">400</span>, <span class="hljs-number">400</span>)

<span class="hljs-comment"># Set the scaling factor</span>
scaling_factor = min(output_size[<span class="hljs-number">0</span>]/width, output_size[<span class="hljs-number">1</span>]/height)

<span class="hljs-comment"># Resize the image in memory</span>
resized_image = cv2.resize(image, <span class="hljs-literal">None</span>, fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_AREA)

<span class="hljs-comment"># Write it to a new file</span>
cv2.imwrite(<span class="hljs-string">'output.jpg'</span>, resized_image)
</code></pre>
<h2 id="heading-extra-credit">Extra Credit</h2>
<p>We can make this script more useful. Let's take in a parameter for the image name and the size we'd like to make it.</p>
<p>add the following line to the top:</p>
<pre><code class="lang-Python"><span class="hljs-keyword">import</span> sys
</code></pre>
<p>Then, indent all the lines of code one tab.</p>
<p>Then add:</p>
<pre><code class="lang-Python"><span class="hljs-keyword">if</span> len(sys.argv) &gt; <span class="hljs-number">1</span>:
</code></pre>
<p>This statement says if arguments are passed to the command line, run the statements we just wrote to modify the image.</p>
<p>and change:</p>
<pre><code class="lang-Python">image = cv2.imread(<span class="hljs-string">'original.jpg'</span>)
</code></pre>
<p>to</p>
<pre><code class="lang-Python">image = cv2.imread(sys.argv[<span class="hljs-number">1</span>])
</code></pre>
<p>Then at the bottom of the script, add the following:</p>
<pre><code class="lang-Python"><span class="hljs-keyword">else</span>:
    print(<span class="hljs-string">"You must provide a filename of the original image"</span>)
</code></pre>
<p>Now when you run the script, you can put in any image name you want:</p>
<pre><code class="lang-plaintext">python resize.py original.jpg
</code></pre>
<p>If you don't enter a filename, the script will ask you to:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675449087231/7a6b0f59-f661-428e-a8f3-d5b5f01ae8bd.webp" alt /></p>
<p>There you go! Have fun playing around with this!</p>
<h2 id="heading-summary">Summary</h2>
<p>In this tutorial, we learned how to resize images with OpenCV. It's pretty straightforward once you get the hang of it. It can get very complicated, however.</p>
<p>This is one of many tutorials I'll be doing to help you get started with OpenCV. Bookmark my blog and come back for more!</p>
<p>Questions? Comments? <a target="_blank" href="https://x.com/intent/follow?screen_name=JeremyCMorgan">Yell at me!</a></p>
]]></content:encoded></item><item><title><![CDATA[Build and Deploy a Blazor App Without Touching a Windows Machine]]></title><description><![CDATA[Do you want to try out  Blazor, but you're not a Windows person? Strictly a Linux developer? We'll you're in luck. One of the goals of .NET Core is to be cross platform, so today we'll see just how "cross platform" it really is with Blazor, Microsoft...]]></description><link>https://www.jeremymorgan.dev/build-and-deploy-a-blazor-app-without-touching-a-windows-machine</link><guid isPermaLink="true">https://www.jeremymorgan.dev/build-and-deploy-a-blazor-app-without-touching-a-windows-machine</guid><category><![CDATA[C#]]></category><category><![CDATA[Blazor ]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Jeremy Morgan]]></dc:creator><pubDate>Tue, 19 Apr 2022 16:00:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649609869993/rejqiOvgi.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Do you want to try out  <a target="_blank" href="https://pluralsight.pxf.io/9WEPYY">Blazor</a>, but you're not a Windows person? Strictly a Linux developer? We'll you're in luck. One of the goals of .NET Core is to be cross platform, so today we'll see just how "cross platform" it really is with Blazor, Microsoft's hot new front end development project.</p>
<p>Follow along with me while we develop a Blazor app and deploy it without ever using a Windows machine. Here's what we're going to do:</p>
<ul>
<li>Set up our (Linux) developer machine</li>
<li>Build a small Blazor app</li>
<li>Deploy it to a Linux VM</li>
</ul>
<p>So let's get started.</p>
<h2 id="heading-1-setup-your-desktop">1. Setup Your Desktop</h2>
<p>First, we have to set up a developer environment. To do this, I will start with a fresh Ubuntu desktop install, it's never had anything done to it so we can include all the steps you need to get started.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383353880/UXTB-7CnM.jpg" alt="Blazor in Linux" /></p>
<h3 id="heading-install-git">Install Git</h3>
<p>The first thing we want to do is install Git. You probably already have it, but it's one of the steps needed. Open up a terminal and type:</p>
<pre><code><span class="hljs-attribute">sudo</span> apt install git
</code></pre><p>Once we have Git installed, we need to get some sort of IDE. I recommend Visual Studio Code, and that's what I'll be using in this tutorial.</p>
<h3 id="heading-install-visual-studio-code">Install Visual Studio Code</h3>
<p>First, we need to install some dependencies:</p>
<pre><code>sudo apt update
sudo apt install software<span class="hljs-operator">-</span>properties<span class="hljs-operator">-</span>common apt<span class="hljs-operator">-</span>transport<span class="hljs-operator">-</span>https wget
</code></pre><p>Then we'll import the Microsoft GPG Key:</p>
<pre><code>wget -q https://packages.microsoft.com/keys/microsoft.<span class="hljs-keyword">asc</span> -O- | sudo apt-key <span class="hljs-keyword">add</span> -
</code></pre><p>Next, we'll enable the VSCode repository:</p>
<pre><code>sudo add<span class="hljs-operator">-</span>apt<span class="hljs-operator">-</span>repository <span class="hljs-string">"deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main"</span>
</code></pre><p>and then install it:</p>
<pre><code>sudo apt <span class="hljs-keyword">update</span>
sudo apt <span class="hljs-keyword">install</span> code
</code></pre><p>And now you have Visual Studio Code installed.</p>
<p>Before you send me hate mail, yes I know you can go into the software manager and install VS Code. I am showing how to do it manually for a reason, always know what's going on with your Linux system and install things intentionally so you have full control. If you want to click the button in the software manager, that's cool too.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383452723/5NUExFrEp.jpg" alt="Blazor in Linux" /></p>
<h3 id="heading-install-net-core">Install .NET Core</h3>
<p>To make Blazor work you must install .NET Core on your local machine. There are a few ways to do this. We're going to install the .NET Core SDK and Runtime, <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/core/install/linux-package-manager-ubuntu-1904">straight from the directions at Microsoft</a>. Depending on the version of Linux you're using it may be different. See <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/core/install/">the instructions</a> for your distro.</p>
<p>First you'll need to register the Microsoft key and feed:</p>
<pre><code>wget <span class="hljs-operator">-</span>q https:<span class="hljs-comment">//packages.microsoft.com/config/ubuntu/19.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb</span>
sudo dpkg <span class="hljs-operator">-</span>i packages<span class="hljs-operator">-</span>microsoft<span class="hljs-operator">-</span>prod.deb
</code></pre><p>Then we'll install the .NET Core SDK</p>
<pre><code>sudo apt-get <span class="hljs-keyword">update</span>
sudo apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">install</span> <span class="hljs-keyword">dotnet</span>-sdk<span class="hljs-number">-3.1</span>
</code></pre><p>You can verify your install is correct by typing in:</p>
<pre><code>dotnet <span class="hljs-operator">-</span><span class="hljs-operator">-</span>version
</code></pre><p>It should look like this: (though the version may be newer later)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383482691/p-B1bJnOW.jpg" alt="Blazor in Linux" /></p>
<p>You've got the SDK Installed! Now we're ready to create a Blazor project on our local machine.</p>
<h2 id="heading-2-create-a-blazor-app-webassembly">2. Create A Blazor App (WebAssembly)</h2>
<p>So you've probably seen a few tutorials about creating Blazor apps, and most of them are Visual Studio in a Windows environment. It's super easy and the push of a button. However, in Linux or Mac you don't have a suitable version of Visual Studio, but you have the dotnet CLI, and it's nearly just as easy to create a Blazor app here.</p>
<p><strong>Important Note</strong></p>
<p>There are two ways we can run a Blazor application.  From Microsoft:</p>
<blockquote>
<p>Blazor is a web framework designed to run client-side in the browser on a WebAssembly-based .NET runtime (<strong>Blazor WebAssembly</strong>) or server-side in ASP.NET Core (<strong>Blazor Server)</strong></p>
</blockquote>
<p>We will run it client side first, which means:</p>
<ul>
<li>The Blazor app, its dependencies, and the .NET runtime are downloaded to the browser.</li>
<li>The app is executed directly on the browser UI thread.</li>
</ul>
<p>We will deploy it as a standalone deployment.</p>
<blockquote>
<p><strong>Standalone deployment</strong> - <em>A standalone deployment serves the Blazor WebAssembly app as a set of static files that are requested directly by clients. Any static file server is able to serve the Blazor app.</em></p>
</blockquote>
<p>There are some downsides to this method and we'll discuss those, but for now we want to build this so it can be hosted on any static server.</p>
<p>Blazor server is included in .NET Core 3.0, but WebAssembly is still in preview. So we need to install a template for it.</p>
<p>You can grab the template with the following command:</p>
<pre><code><span class="hljs-attribute">dotnet</span> new -i Microsoft.AspNetCore.Blazor.Templates::<span class="hljs-number">3</span>.<span class="hljs-number">1</span>.<span class="hljs-number">0</span>-preview<span class="hljs-number">4</span>.<span class="hljs-number">19579</span>.<span class="hljs-number">2</span>
</code></pre><p>Next we'll create a new Blazor WebAssembly App</p>
<pre><code>dotnet <span class="hljs-keyword">new</span> blazorwasm <span class="hljs-operator">-</span>o BlazorDemo
</code></pre><p>Go into the directory and run it:</p>
<pre><code><span class="hljs-built_in">cd</span> BlazorDemo
dotnet run
</code></pre><p>Your terminal window should look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383530885/V5jggEQ2i.jpg" alt="Blazor in Linux" /></p>
<p>Now you can open it up in a web browser and view the page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383550691/iMjObe24l.jpg" alt="Blazor in Linux" /></p>
<p>Open it up in VS Code and make your own modifications and play around with it.</p>
<p>So now we'll take this basic Blazor app and deploy it in different places.</p>
<h2 id="heading-3-deploy-it-to-a-linux-server-webassembly">3. Deploy it to a Linux Server (WebAssembly)</h2>
<p>Let's see what it will take to push this to a regular Linux hosting server. For this I will use a <a target="_blank" href="http://bit.ly/DigitalOcean5Dollar">Digital Ocean $5 special</a> server. I'm creating it from scratch, again to show all the steps needed to get it up and running. We'll run CentOS 7 on it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383572779/Z5QkuBx65.jpg" alt="Blazor in Linux" /></p>
<h3 id="heading-set-up-our-server">Set up our Server</h3>
<p>To set this up, I'm just going to update it:</p>
<pre><code>sudo yum <span class="hljs-keyword">update</span>
</code></pre><p>Then I'll install Nginx on it to serve up our static files.</p>
<pre><code>sudo yum <span class="hljs-keyword">install</span> epel-<span class="hljs-keyword">release</span>
sudo yum <span class="hljs-keyword">install</span> nginx
</code></pre><p><em>If you already have a web server set up that serves static files, you don't have to follow these steps.</em></p>
<p>I'll then start up our Nginx server:</p>
<pre><code>sudo systemctl <span class="hljs-keyword">start</span> nginx
</code></pre><p>And it's ready to go.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383598139/DwqSCHpGt.jpg" alt="Blazor in Linux" /></p>
<h3 id="heading-build-a-deployment-webassembly">Build a Deployment (WebAssembly)</h3>
<p>Now we want to deploy our application.</p>
<p>Now open a command prompt to the home folder of your application and run the following:</p>
<pre><code>dotnet publish <span class="hljs-operator">-</span>c Release <span class="hljs-operator">-</span>r linux<span class="hljs-operator">-</span>x64
</code></pre><p>And we'll go into our publish folder and look for the dist folder:</p>
<pre><code>cd bin<span class="hljs-operator">/</span>Release<span class="hljs-operator">/</span>netstandard2<span class="hljs-number">.1</span><span class="hljs-operator">/</span>linux<span class="hljs-operator">-</span>x64<span class="hljs-operator">/</span>publish<span class="hljs-operator">/</span>BlazorDemo<span class="hljs-operator">/</span>dist
</code></pre><p>Here I can see a listing of files.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383625251/nsxVvglgH.jpg" alt="Blazor in Linux" /></p>
<p>I will copy these over to my new Linux server. I'm using SCP, but you can use whatever method you feel works:</p>
<pre><code>scp <span class="hljs-operator">-</span>r <span class="hljs-operator">*</span> web@sillyblazordemo.jeremymorgan.com:<span class="hljs-operator">/</span>usr<span class="hljs-operator">/</span>share<span class="hljs-operator">/</span>nginx<span class="hljs-operator">/</span>html
</code></pre><p>And now I load it up in my web browser:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383647029/AHIC0X3qs.jpg" alt="Blazor in Linux" /></p>
<p>Well, that's pretty cool! So this .NET Core application has been turned into static files I can host anywhere. I can put this on IIS, or S3, or wherever and it will work great. You can even <a target="_blank" href="https://blazor-demo.github.io/">Host it on Github Pages!</a>.</p>
<p>This is great because C# and Razor files are compiled into .NET assemblies, and Blazor WebAssembly bootstraps the .NET runtime and loads the assemblies all right there in the browser.</p>
<p>But it requires modern browsers and has a huge payload to download to the browser to do that.</p>
<p>To truly leverage the power of Blazor we should set up a Blazor Server package. If you really want to know the <a target="_blank" href="https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-3.1">differences, you can learn more here</a>.</p>
<h2 id="heading-4-create-a-blazor-app-blazor-server">4. Create a Blazor App (Blazor Server)</h2>
<p>Now we will to create a Blazor Server application.</p>
<pre><code>dotnet <span class="hljs-keyword">new</span> blazorserver <span class="hljs-operator">-</span>o BlazorServerDemo
</code></pre><p>This creates another Blazor application, and we type in</p>
<pre><code><span class="hljs-attribute">dotnet</span> run
</code></pre><p>and it spins up our local application:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383668576/V7PMdt4ZX.jpg" alt="Blazor in Linux" /></p>
<p>and it looks pretty familiar. Only now I don't have the rabbit head.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383684782/vGy30MNeu.jpg" alt="Blazor in Linux" /></p>
<p>So let's publish it. We will publish this as a self-contained application, so we can run it on our Nginx server without installing the .NET Framework.</p>
<pre><code>dotnet publish <span class="hljs-operator">-</span>c Release <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-built_in">self</span><span class="hljs-operator">-</span>contained <span class="hljs-operator">-</span>r linux<span class="hljs-operator">-</span>x64
</code></pre><p>Then we'll go into our publish directory:</p>
<pre><code>cd bin<span class="hljs-operator">/</span>Release<span class="hljs-operator">/</span>netcoreapp3<span class="hljs-number">.1</span><span class="hljs-operator">/</span>linux<span class="hljs-operator">-</span>x64<span class="hljs-operator">/</span>publish<span class="hljs-operator">/</span>
</code></pre><p>And we'll copy those over to an app directory created on the host (yours may vary)</p>
<pre><code>scp <span class="hljs-operator">-</span>r <span class="hljs-operator">*</span> web@sillyblazordemo.jeremymorgan.com:<span class="hljs-operator">/</span>home<span class="hljs-operator">/</span>web<span class="hljs-operator">/</span>apps<span class="hljs-operator">/</span>BlazorServerDemo
</code></pre><h3 id="heading-5-set-up-the-server-for-net-core">5. Set up the Server for .NET Core</h3>
<p>To run .NET Core applications (even self-contained) there are some dependencies. We will install the following for CentOS, if you're using a different OS, you can <a target="_blank" href>check what dependencies you need here</a>.</p>
<p>Here's the command to install the needed dependencies with Yum:</p>
<pre><code>sudo yum install lttng<span class="hljs-operator">-</span>ust libcurl openssl<span class="hljs-operator">-</span>libs krb5<span class="hljs-operator">-</span>libs libicu zlib
</code></pre><p>Next, there's an SELinux setting you need to change that might hang you up:</p>
<pre><code><span class="hljs-attribute">setsebool</span> -P httpd_can_network_connect <span class="hljs-number">1</span>
</code></pre><p>Now we can just run the executable:</p>
<pre><code>./BlazorServerDemo <span class="hljs-operator">-</span><span class="hljs-operator">-</span>urls http:<span class="hljs-comment">//0.0.0.0:5000</span>
</code></pre><p>And we have a server up and ready at port 5000:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383708738/pzjTIGTw9.jpg" alt="Blazor in Linux" /></p>
<p>And we can load it up in our Web Browser!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383725785/v2azuEoZd.jpg" alt="Blazor in Linux" /></p>
<p>We're now up and running, but we don't want to just run it listening on a port like this, so let's use Nginx as a reverse proxy.  Shut down the process.</p>
<p>Then let's run this in the background, by adding the ampersand at the end:</p>
<pre><code>./BlazorServerDemo <span class="hljs-operator">-</span><span class="hljs-operator">-</span>urls http:<span class="hljs-comment">//0.0.0.0:5000 &amp;</span>
</code></pre><p>Now if you type in "jobs" you should see it running.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383745204/y7wU3WJTk.jpg" alt="Blazor in Linux" /></p>
<p>Now, create the following two folders:</p>
<pre><code>sudo mkdir <span class="hljs-operator">/</span>etc<span class="hljs-operator">/</span>nginx<span class="hljs-operator">/</span>sites<span class="hljs-operator">-</span>available
sudo mkdir <span class="hljs-operator">/</span>etc<span class="hljs-operator">/</span>nginx<span class="hljs-operator">/</span>sites<span class="hljs-operator">-</span>enabled
</code></pre><p>And then edit your default file</p>
<pre><code>vi <span class="hljs-operator">/</span>etc<span class="hljs-operator">/</span>nginx<span class="hljs-operator">/</span>sites<span class="hljs-operator">-</span>available<span class="hljs-operator">/</span>default
</code></pre><p>And add in the following into your server directive:</p>
<pre><code><span class="hljs-attribute">location</span> / {
    <span class="hljs-attribute">proxy_pass</span>         http://localhost:5000;
    <span class="hljs-attribute">proxy_http_version</span> <span class="hljs-number">1</span>.<span class="hljs-number">1</span>;
    <span class="hljs-attribute">proxy_set_header</span>   Upgrade <span class="hljs-variable">$http_upgrade</span>;
    <span class="hljs-attribute">proxy_set_header</span>   Connection keep-alive;
    <span class="hljs-attribute">proxy_set_header</span>   Host <span class="hljs-variable">$host</span>;
    <span class="hljs-attribute">proxy_cache_bypass</span> <span class="hljs-variable">$http_upgrade</span>;
    <span class="hljs-attribute">proxy_set_header</span>   X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
    <span class="hljs-attribute">proxy_set_header</span>   X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;
}
</code></pre><p>Now restart nginx:</p>
<pre><code><span class="hljs-attribute">sudo</span> systemctl reload nginx
</code></pre><p>Now you see your new page up and running!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650383768277/51qFPX_gI.jpg" alt="Blazor in Linux" /></p>
<p>Now you have a full fledged Blazor server on a Linux VM instance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>So in this tutorial, we built a Blazor application (both WebAssembly and Blazor Server) on an Ubuntu machine and pushed it up to a CentOS machine. We didn't need any Windows machines to do it.</p>
<p>My intent was to show how easy it is to develop Blazor and .NET Core applications if you're a Linux developer. I started out as a Linux developer, fell in love with C#/.NET, and now I can do both things together and I love it. You will to.</p>
<p>.NET Core is amazing, and I think Blazor will be too. I'm excited to develop more Blazor applications and push the limits of it.</p>
<p>If you want to learn more about Blazor, Pluralsight has just released some really cool courses on it.</p>
<ul>
<li><strong><a target="_blank" href="https://pluralsight.pxf.io/9WEPYY">Blazor - The Big Picture</a></strong></li>
<li><strong><a target="_blank" href="https://pluralsight.pxf.io/jWm3Lb">Blazor - Getting Started</a></strong></li>
<li><strong><a target="_blank" href="https://pluralsight.pxf.io/5bnQNo">Blazor - Authentication and Authorization</a></strong></li>
</ul>
<p>So try it out! <a target="_blank" href="http://bit.ly/JeremyCMorgan">Let me know</a> what you think of Blazor and share your experiences in the comments!</p>
]]></content:encoded></item></channel></rss>