<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Ghulam Mujtaba</title>
  <subtitle>Dr. Ghulam Mujtaba is an edge AI and computer vision researcher, Assistant Professor at Regis University in Denver, IEEE Senior Member, and founder of DroSonic, a passive acoustic counter-drone system.</subtitle>
  <link href="https://gmujtaba.com/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://gmujtaba.com/" rel="alternate" type="text/html"/>
  <updated>2026-11-15T19:39:07+00:00</updated>
  <id>https://gmujtaba.com/</id>
  <author>
    <name>Ghulam Mujtaba</name>
    <email>gmujtaba@ieee.org</email>
  </author>
  <generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator>

  
  
    <entry>
      <title type="html">Cleaning Up the LinkedIn Feed with a Tampermonkey Userscript</title>
      <link href="https://gmujtaba.com/blog/linkedin-feed-cleanup-userscript-tampermonkey/" rel="alternate" type="text/html" title="Cleaning Up the LinkedIn Feed with a Tampermonkey Userscript"/>
      <published>2026-10-06T00:00:00+00:00</published>
      <updated>2026-10-06T00:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/linkedin-feed-cleanup-userscript-tampermonkey</id>
      <content type="html">&lt;p&gt;I got tired of scrolling past unrelated content on LinkedIn. Between promoted posts, “Recommended for you” blocks, and posts from people I have never met that showed up only because a stranger reacted to them, most of my home feed had nothing to do with my network. So I wrote a small userscript that cleans it up and keeps what I care about.&lt;/p&gt;

&lt;p&gt;It is free to use, tweak, or fork: &lt;strong&gt;&lt;a href=&quot;https://gist.github.com/iamgmujtaba/15040fed0c5db4fffe0e47ac3b17f622&quot;&gt;LinkedIn Cleanup on GitHub Gist&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;what-it-hides&quot;&gt;What It Hides&lt;/h2&gt;

&lt;p&gt;The script only runs on the home feed (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linkedin.com/&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linkedin.com/feed/&lt;/code&gt;). Profiles, messaging, and search are left alone, and when you navigate away from the feed it restores everything it changed.&lt;/p&gt;

&lt;p&gt;On the feed, it hides:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The right sidebar&lt;/strong&gt;, including LinkedIn News and the puzzles widget.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Promoted and sponsored posts.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Recommendation blocks&lt;/strong&gt; such as “Recommended for you”, “Add to your feed”, and “People you may know”.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Posts whose author is a 2nd or 3rd+ degree connection.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Activity posts&lt;/strong&gt; that appear only because someone “finds this funny”, “finds this curious”, or “follows” someone.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Upsell links&lt;/strong&gt; in the left column, such as “Try Premium Page” and “Advertise on LinkedIn”.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The messaging drawer&lt;/strong&gt; at the bottom of the feed. The “Message” button on profiles still works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-it-keeps&quot;&gt;What It Keeps&lt;/h2&gt;

&lt;p&gt;Hiding everything from outside your network would also remove posts your connections are actively engaging with, which are often the useful ones. So the script keeps a post visible when one of your connections &lt;strong&gt;commented on it, replied to it, or reposted it&lt;/strong&gt;. With the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KEEP_LIKES = true&lt;/code&gt;, a post also stays visible when a connection likes, celebrates, supports, loves, or finds it insightful.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Install the &lt;a href=&quot;https://www.tampermonkey.net/&quot;&gt;Tampermonkey&lt;/a&gt; extension. I tested the script in Chrome.&lt;/li&gt;
  &lt;li&gt;Open the &lt;a href=&quot;https://gist.github.com/iamgmujtaba/15040fed0c5db4fffe0e47ac3b17f622&quot;&gt;gist&lt;/a&gt; and click &lt;strong&gt;Raw&lt;/strong&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linkedin-cleanup.user.js&lt;/code&gt;. Tampermonkey will offer to install it.&lt;/li&gt;
  &lt;li&gt;Reload LinkedIn.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If nothing changes in Chrome, open Tampermonkey’s details page in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chrome://extensions&lt;/code&gt; and turn on &lt;strong&gt;Allow User Scripts&lt;/strong&gt; (on older Chrome versions, turn on &lt;strong&gt;Developer mode&lt;/strong&gt; instead). Chrome requires this before any extension can run userscripts.&lt;/p&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;Every behavior is a flag at the top of the script, so you can switch off anything you want to keep:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HIDE_RIGHT_SIDEBAR&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HIDE_ACTIVITY_POSTS&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// &quot;X finds this funny&quot;, &quot;X follows ...&quot;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;KEEP_LIKES&lt;/span&gt;           &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// keep posts a connection liked/celebrated/supported&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HIDE_DEGREE_POSTS&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// posts whose author is 2nd / 3rd+&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HIDE_PROMOTED&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HIDE_RECOMMENDED&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// &quot;Recommended for you&quot;, &quot;Add to your feed&quot;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HIDE_LEFT_LINKS&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Try Premium Page, Advertise on LinkedIn&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HIDE_MESSAGING&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// feed only&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DRY_RUN&lt;/span&gt;              &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true = hide nothing, only record what WOULD be hidden&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DRY_RUN&lt;/code&gt; is useful when you change a rule and want to see what it would hide before it hides anything.&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;

&lt;p&gt;A few details took more iterations than I expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collapsing instead of removing.&lt;/strong&gt; The obvious approach is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;display: none&lt;/code&gt;. That breaks infinite scroll. LinkedIn loads more posts when its lazy-load observers see the end of the list, and an element with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;display: none&lt;/code&gt; has no box for them to see. Hide enough posts that way and the feed simply stops loading. The script instead collapses hidden posts to zero height with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;visibility: hidden&lt;/code&gt;, so they still exist in the layout and scrolling keeps working. It also collapses the outermost wrapper of each post, so no empty divider or spacer is left behind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Matching on text, not class names.&lt;/strong&gt; LinkedIn’s class names change often. The script looks for stable visible text instead: the “2nd” or “3rd+” badge next to an author’s name, the word “Promoted”, or a header like “finds this funny”. A cheap regular expression filters out almost every text node first, so the more expensive checks only run on the few that could matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Staying fast while you scroll.&lt;/strong&gt; A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MutationObserver&lt;/code&gt; queues every node LinkedIn adds as the feed loads. The queue is processed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requestIdleCallback&lt;/code&gt; slices of about 6 ms, and all measuring happens before any hiding, so the page does not have to recalculate its layout over and over. Posts that are not laid out yet are retried a moment later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private by default.&lt;/strong&gt; The script includes an optional debug report for when LinkedIn changes its markup and something stops matching. It is off by default, it is stored only in your browser, and it records page structure and counts, never names or post text.&lt;/p&gt;

&lt;h2 id=&quot;limitations&quot;&gt;Limitations&lt;/h2&gt;

&lt;p&gt;LinkedIn changes its markup regularly, so a rule that works today may stop matching later. If something stops being hidden, or something you want is hidden, leave a comment on the gist and I will take a look.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Get the script&lt;/strong&gt;: &lt;a href=&quot;https://gist.github.com/iamgmujtaba/15040fed0c5db4fffe0e47ac3b17f622&quot;&gt;gist.github.com/iamgmujtaba&lt;/a&gt;. Connect with me on &lt;a href=&quot;https://www.linkedin.com/in/iamgmujtaba/&quot;&gt;LinkedIn&lt;/a&gt; if you build on it.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">A free, open-source Tampermonkey userscript that hides the LinkedIn sidebar, ads, suggested posts, and posts from 2nd and 3rd degree strangers on the home feed, while keeping posts from your own network.</summary>
      
      
        
          <category term="LinkedIn" />
        
          <category term="Userscript" />
        
          <category term="Tampermonkey" />
        
          <category term="JavaScript" />
        
          <category term="Productivity" />
        
          <category term="Open Source" />
        
      
    </entry>
  
    <entry>
      <title type="html">RegisPortfolio: A Serverless Portfolio Platform for Data Science Students</title>
      <link href="https://gmujtaba.com/blog/regis-portfolio-platform-serverless-student-career-solution/" rel="alternate" type="text/html" title="RegisPortfolio: A Serverless Portfolio Platform for Data Science Students"/>
      <published>2026-02-08T00:00:00+00:00</published>
      <updated>2026-02-08T00:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/regis-portfolio-platform-serverless-student-career-solution</id>
      <content type="html">&lt;p&gt;As a faculty member in &lt;a href=&quot;https://www.regis.edu/&quot;&gt;Regis University’s&lt;/a&gt; Master of Science in Data Science program, I kept seeing the same frustrating pattern. Smart students with impressive projects would graduate, then struggle for months to find jobs that matched their skills. The problem wasn’t their abilities. It was how they presented themselves. Most had scattered GitHub repositories, basic LinkedIn profiles, and maybe a personal website thrown together at the last minute. Recruiters couldn’t easily see how their skills had grown or how their coursework connected to real jobs. So I built &lt;strong&gt;&lt;a href=&quot;https://regisportfolio.com/&quot;&gt;RegisPortfolio.com&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;img src=&quot;/assets/img/blog/PracticumPortfolio-1.gif&quot; alt=&quot;RegisPortfolio: A Serverless Portfolio Platform for Data Science Students&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;great-projects-hard-to-find&quot;&gt;Great projects, hard to find&lt;/h2&gt;

&lt;p&gt;Some examples from our MSDS students:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://regisportfolio.com/profiles/scard659/scard659.html&quot;&gt;Matthew Scardino&lt;/a&gt; built a “Wildlife Image Processing &amp;amp; Semantic Search System V2” that won a Faculty Choice Award. It identifies species using multiple models and integrates MCP and LangGraph.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://regisportfolio.com/profiles/chamel/chamel.html&quot;&gt;Chandon Hamel&lt;/a&gt; won a Faculty Choice Award in Summer 2025 for “3D Denoising Diffusion Video Frame Interpolation,” which uses 3D diffusion models to generate in-between video frames.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://regisportfolio.com/profiles/edisasa/edisasa.html&quot;&gt;Etana Disasa&lt;/a&gt; won a Student Choice Award for “Multimodal Sentiment Analysis for Instagram Posts,” which combines text and images to judge sentiment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before RegisPortfolio, work like this was easy to miss. The pattern was the same every semester:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Students are strong at the technical work but have never had to present it professionally.&lt;/li&gt;
  &lt;li&gt;Good projects get buried in messy GitHub repositories.&lt;/li&gt;
  &lt;li&gt;Every student builds a portfolio differently, and many don’t build one at all.&lt;/li&gt;
  &lt;li&gt;Recruiters can’t see how a student progressed through the program, or how a class project relates to the job they’re hiring for.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;/h2&gt;

&lt;!-- Local video --&gt;
&lt;div class=&quot;video-container text-center video-fluid rounded z-depth-1&quot; itemscope=&quot;&quot; itemtype=&quot;https://schema.org/VideoObject&quot;&gt;
  &lt;meta itemprop=&quot;name&quot; content=&quot;RegisPortfolio.com: Serverless Portfolio Platform for Data Science Students&quot; /&gt;
  &lt;meta itemprop=&quot;description&quot; content=&quot;Demo of RegisPortfolio.com, a serverless portfolio platform that helps Regis MSDS students present their data science projects to recruiters.&quot; /&gt;
  &lt;meta itemprop=&quot;thumbnailUrl&quot; content=&quot;https://gmujtaba.com/assets/img/blog/regis_portfolio_platform.png&quot; /&gt;
  &lt;meta itemprop=&quot;uploadDate&quot; content=&quot;2026-02-08T00:00:00+00:00&quot; /&gt;
  &lt;meta itemprop=&quot;contentUrl&quot; content=&quot;https://gmujtaba.com/assets/video/Practicum_Portfolio_demo.mp4&quot; /&gt;
  &lt;video controls=&quot;&quot; loop=&quot;&quot; class=&quot;img-fluid rounded&quot; itemprop=&quot;video&quot;&gt;
    &lt;source src=&quot;/assets/video/Practicum_Portfolio_demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    &lt;p&gt;Your browser doesn&apos;t support HTML5 video. Here is a &lt;a href=&quot;/assets/video/Practicum_Portfolio_demo.mp4&quot;&gt;link to the video&lt;/a&gt; instead.&lt;/p&gt;
  &lt;/video&gt;
&lt;/div&gt;

&lt;h2 id=&quot;how-it-works-for-students&quot;&gt;How it works for students&lt;/h2&gt;

&lt;p&gt;The idea behind &lt;a href=&quot;https://regisportfolio.com/&quot;&gt;RegisPortfolio.com&lt;/a&gt; is simple: the best portfolios tell a story, not just list projects.&lt;/p&gt;

&lt;p&gt;Students use the &lt;a href=&quot;https://editor.regisportfolio.com/&quot;&gt;portfolio editor&lt;/a&gt; to add projects straight from their coursework. They don’t need to know HTML, CSS, or web development. For each project they write a short reflection connecting it to their career goals, preview exactly what a recruiter will see, and build up a record of their progress semester by semester.&lt;/p&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;img src=&quot;/assets/img/blog/PracticumPortfolio-2.gif&quot; alt=&quot;RegisPortfolio: A Serverless Portfolio Platform for Data Science Students&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;under-the-hood&quot;&gt;Under the hood&lt;/h2&gt;

&lt;h3 id=&quot;why-serverless&quot;&gt;Why serverless&lt;/h3&gt;

&lt;p&gt;Student usage is spiky: heavy at the end of each term, quiet in between. Paying for a server that sits idle most of the year doesn’t make sense. With a serverless setup:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;there’s no server to maintain, and nothing to go down during job search season,&lt;/li&gt;
  &lt;li&gt;it scales automatically when everyone submits at the end of the term,&lt;/li&gt;
  &lt;li&gt;costs follow usage, which keeps it affordable for a university,&lt;/li&gt;
  &lt;li&gt;a content delivery network (CDN) serves portfolios quickly to recruiters anywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;students-own-their-accounts&quot;&gt;Students own their accounts&lt;/h3&gt;

&lt;p&gt;Students sign in with GitHub (OAuth), so each portfolio belongs to the student, not to a university account. They can choose which projects are visible, edit from any device, and keep access after their university email expires.&lt;/p&gt;

&lt;h3 id=&quot;mobile-first&quot;&gt;Mobile first&lt;/h3&gt;

&lt;p&gt;Recruiters often look at portfolios on their phones, so every page is designed for small screens first and still works well on a desktop.&lt;/p&gt;

&lt;h3 id=&quot;version-control-and-automatic-deployment&quot;&gt;Version control and automatic deployment&lt;/h3&gt;

&lt;p&gt;All portfolio content lives in Git, which gives a full history and a backup of every change. When a student saves in the editor, GitHub Actions rebuilds and publishes their public page, usually in under 30 seconds.&lt;/p&gt;

&lt;h2 id=&quot;key-features&quot;&gt;Key features&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Standard forms, professional pages&lt;/strong&gt;: students fill in their project details, and the platform generates consistent, well-designed portfolio pages.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Responsive design&lt;/strong&gt;: pages work on phones, tablets, and desktops.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Built-in SEO&lt;/strong&gt;: every page has meta tags and structured data, so portfolios show up in search.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fast everywhere&lt;/strong&gt;: pages are served through a global CDN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: &lt;a href=&quot;https://regisportfolio.com/profiles/gmujtaba/gmujtaba.html&quot;&gt;my profile on RegisPortfolio&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;h3 id=&quot;ai-features&quot;&gt;AI features&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Automatically categorizing projects and extracting skills, so students type less.&lt;/li&gt;
  &lt;li&gt;Suggesting career paths and job openings based on a student’s projects.&lt;/li&gt;
  &lt;li&gt;Recommending classmates with complementary skills for team projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;alumni&quot;&gt;Alumni&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Letting graduates keep updating their portfolios after they finish the program.&lt;/li&gt;
  &lt;li&gt;Tracking career outcomes over time, which helps the program and shows current students realistic paths.&lt;/li&gt;
  &lt;li&gt;Connecting current students with alumni working in the industries they’re targeting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;want-this-for-your-program&quot;&gt;Want this for your program?&lt;/h2&gt;

&lt;p&gt;RegisPortfolio gives our students one professional place to show their work, and it helps employers see what our graduates can do. If you’d like to talk about the architecture, adapting it for your institution, or collaborating on an open-source version, email me at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gmujtaba@ieee.org&lt;/code&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;See it live&lt;/strong&gt;: browse student portfolios at &lt;a href=&quot;https://regisportfolio.com/&quot;&gt;RegisPortfolio.com&lt;/a&gt;, try the editor at &lt;a href=&quot;https://editor.regisportfolio.com/&quot;&gt;editor.regisportfolio.com&lt;/a&gt;, or connect with me on &lt;a href=&quot;https://linkedin.com/in/iamgmujtaba&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Why I built RegisPortfolio.com, a serverless portfolio platform that helps Regis MSDS students present their projects to recruiters, and how it works under the hood.</summary>
      
      
        
          <category term="Portfolio Platform" />
        
          <category term="Data Science Careers" />
        
          <category term="Serverless" />
        
          <category term="GitHub Actions" />
        
          <category term="Student Success" />
        
      
    </entry>
  
    <entry>
      <title type="html">Regis Applied Practicum Coach: An AI Coach for Data Science Capstone Projects</title>
      <link href="https://gmujtaba.com/blog/regis-applied-practicum-coach-ai-academic-guidance/" rel="alternate" type="text/html" title="Regis Applied Practicum Coach: An AI Coach for Data Science Capstone Projects"/>
      <published>2025-11-30T00:00:00+00:00</published>
      <updated>2025-11-30T00:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/regis-applied-practicum-coach-ai-academic-guidance</id>
      <content type="html">&lt;p&gt;I developed the &lt;strong&gt;Regis Applied Practicum Coach&lt;/strong&gt; to support students in Data Science Practicum/capstone projects at Regis University. It helps with the hardest part of the capstone for most students: coming up with an original, doable, and useful data science project from scratch.&lt;/p&gt;

&lt;p&gt;In a typical practicum, students can only get feedback when their instructor is available. The coach fills the gaps: students can brainstorm and plan with it at any hour, then bring better-formed ideas to our meetings.&lt;/p&gt;

&lt;h2 id=&quot;applied-practicum-coach-preview&quot;&gt;Applied Practicum Coach Preview&lt;/h2&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/practicum_coach_screenshot.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/practicum_coach_screenshot.png&quot; alt=&quot;Regis Applied Practicum Coach: An AI Coach for Data Science Capstone Projects&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;what-the-coach-does&quot;&gt;What the Coach Does&lt;/h2&gt;

&lt;p&gt;The Regis Applied Practicum Coach engages students through structured, conversational sessions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Brainstorm Topics&lt;/strong&gt;: Guides students through discovery questions about their interests, preferred domains, datasets, tools, and complexity levels. Generates 3-6 tailored project ideas with specific datasets, techniques, and expected outcomes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Plan Sessions&lt;/strong&gt;: Helps students structure their work with customized agendas, time blocks, and milestones aligned with course requirements and academic constraints.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Creative Exercises&lt;/strong&gt;: Suggests data science-specific activities like dataset critiques, model-choice debates, bias-analysis exercises, and idea-pitch rounds.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Organize Ideas&lt;/strong&gt;: Recommends prioritization frameworks such as feasibility-impact matrices, MoSCoW method, and practicum-aligned rubrics for unbiased decision-making.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Feedback and Improvement&lt;/strong&gt;: Provides structured feedback on project proposals, session outcomes, and iterative refinement suggestions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Skills Development&lt;/strong&gt;: Assesses students’ brainstorming and planning capabilities through targeted questions, then creates personalized training plans with resources and improvement techniques.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;

&lt;p&gt;The coach asks one question at a time, so the conversation feels like working with a mentor rather than reading a wall of text. It adapts to each student’s academic goals, technical background, and project constraints, ensuring suggestions align with MSDS program requirements and evaluation criteria.&lt;/p&gt;

&lt;p&gt;Students can access the coach through dedicated prompt templates that guide them to specific functionalities: topic brainstorming, session planning, exercise suggestions, idea organization, feedback requests, or skills assessment.&lt;/p&gt;

&lt;h2 id=&quot;privacy-and-access&quot;&gt;Privacy and Access&lt;/h2&gt;

&lt;p&gt;Currently, the Regis Applied Practicum Coach is available exclusively to Anderson College of Business and Computing students at Regis University. The system maintains student privacy while providing personalized guidance throughout the semester.&lt;/p&gt;

&lt;h2 id=&quot;interested-in-implementing-this-for-your-program&quot;&gt;Interested in Implementing This for Your Program?&lt;/h2&gt;

&lt;p&gt;If you’re a faculty member or administrator interested in deploying a similar AI coaching system for your data science or practicum courses, I’m happy to share implementation details, prompt engineering strategies, and customization approaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contact&lt;/strong&gt;: Email me at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gmujtaba@ieee.org&lt;/code&gt; to discuss:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Custom prompt templates for your course structure&lt;/li&gt;
  &lt;li&gt;Integration strategies with your LMS&lt;/li&gt;
  &lt;li&gt;Privacy and access control considerations&lt;/li&gt;
  &lt;li&gt;Pilot program opportunities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to add to human mentorship, not replace it: students become more independent while still having help whenever they need it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Try It&lt;/strong&gt;: Currently, &lt;a href=&quot;https://m365.cloud.microsoft:443/chat/?titleId=T_1cfacfce-5898-fcfc-7fad-e5cc4ff173d9&amp;amp;source=embedded-builder&quot;&gt;Regis Applied Practicum Coach&lt;/a&gt; is available only to enrolled Regis University MSDS students. Use this &lt;a href=&quot;https://m365.cloud.microsoft:443/chat/?titleId=T_1cfacfce-5898-fcfc-7fad-e5cc4ff173d9&amp;amp;source=embedded-builder&quot;&gt;URL&lt;/a&gt; to access it.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">An AI coach that helps Regis MSDS students brainstorm, plan, and refine their data science practicum projects, one question at a time, any time of day.</summary>
      
      
        
          <category term="AI Academic Assistant" />
        
          <category term="Educational Technology" />
        
          <category term="Graduate Student Support" />
        
          <category term="Data Science Education" />
        
          <category term="Human-AI Collaboration" />
        
          <category term="Academic Innovation" />
        
      
    </entry>
  
    <entry>
      <title type="html">A Personal AI Assistant for My Students and Research</title>
      <link href="https://gmujtaba.com/blog/personal-ai-assistant-educational-support-platform/" rel="alternate" type="text/html" title="A Personal AI Assistant for My Students and Research"/>
      <published>2025-11-22T00:00:00+00:00</published>
      <updated>2025-11-22T00:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/personal-ai-assistant-educational-support-platform</id>
      <content type="html">&lt;p&gt;Many of my courses don’t have a teaching assistant, and students’ questions don’t stop when office hours end. So I built an AI assistant that answers questions about my courses, research, and publications at any time of day. Try it at &lt;a href=&quot;https://chat.gmujtaba.com&quot;&gt;chat.gmujtaba.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;what-it-does&quot;&gt;What it does&lt;/h2&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/ai_assistant_screenshot.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/ai_assistant_screenshot.png&quot; alt=&quot;A Personal AI Assistant for My Students and Research&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Answers common questions&lt;/strong&gt; about grading policies, due dates, and course logistics, so students don’t have to dig through long documents.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Points to the right material.&lt;/strong&gt; Instead of a vague answer, it links to the specific reading, lecture, or section that covers the topic.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Covers my research too.&lt;/strong&gt; Visitors can ask about my publications, patents, and projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;

&lt;p&gt;It’s a retrieval-based assistant. I convert my course and research documents into text, split them into chunks, and compute embeddings (numeric representations of meaning) ahead of time. When someone asks a question, the site finds the most relevant chunks and sends them, with the question, to Google Gemini, which writes an answer that cites those sources.&lt;/p&gt;

&lt;p&gt;A few privacy and security choices:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Precomputed embeddings&lt;/strong&gt;: the documents are processed once, offline, and only the text excerpts the assistant needs are served.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No original files exposed&lt;/strong&gt;: the site serves converted text excerpts, never the original PDFs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No secrets in the code&lt;/strong&gt;: API keys aren’t stored in the repository; they’re added at deploy time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;want-one-for-your-program&quot;&gt;Want one for your program?&lt;/h2&gt;

&lt;p&gt;If you’d like to run a short pilot or talk about setting up access and privacy controls, email me at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gmujtaba@ieee.org&lt;/code&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">An AI assistant that answers questions about my courses, research, and publications 24/7, citing the source material. Built with Google Gemini and precomputed embeddings.</summary>
      
      
        
          <category term="AI Assistant" />
        
          <category term="Educational Technology" />
        
          <category term="RAG" />
        
          <category term="Google Gemini" />
        
          <category term="Privacy" />
        
      
    </entry>
  
    <entry>
      <title type="html">Vibe Coding My Academic Website into Jekyll: What AI Did and What I Still Had to Do</title>
      <link href="https://gmujtaba.com/blog/vibe-coding-methodology-academic-website-jekyll/" rel="alternate" type="text/html" title="Vibe Coding My Academic Website into Jekyll: What AI Did and What I Still Had to Do"/>
      <published>2025-08-21T00:00:00+00:00</published>
      <updated>2025-08-21T00:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/vibe-coding-methodology-academic-website-jekyll</id>
      <content type="html">&lt;p&gt;“Vibe coding” means describing what you want and letting an AI assistant write most of the code. I used it to rebuild this website, and here is what worked and what didn’t.&lt;/p&gt;

&lt;h2 id=&quot;the-project&quot;&gt;The project&lt;/h2&gt;

&lt;p&gt;My old academic website was hard to update and wasn’t under version control. I wanted to move it to &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, a static site generator, so that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;every page is a simple Markdown or data file,&lt;/li&gt;
  &lt;li&gt;all changes are tracked in Git,&lt;/li&gt;
  &lt;li&gt;the site is fast and secure, with no database or server code to maintain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First I downloaded a copy of the existing site with HTTrack (a website copier I first used as an undergraduate), which gave me its HTML, CSS, JavaScript, and images. Then I used GitHub Copilot with Claude Sonnet 4 to convert it into a Jekyll site while keeping the content and the responsive design.&lt;/p&gt;

&lt;h2 id=&quot;how-much-did-the-ai-do&quot;&gt;How much did the AI do?&lt;/h2&gt;

&lt;p&gt;About &lt;strong&gt;90%&lt;/strong&gt; of the code the AI generated was usable as is. It was very good at the repetitive work: turning pages into layouts and includes, writing Liquid templates, and moving content into data files. That saved a lot of time.&lt;/p&gt;

&lt;p&gt;The other &lt;strong&gt;10%&lt;/strong&gt; needed me. Quality varied from task to task, so I had to review everything it wrote for correctness, security, performance, and maintainability.&lt;/p&gt;

&lt;h2 id=&quot;where-ai-fell-short&quot;&gt;Where AI fell short&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Debugging.&lt;/strong&gt; When something broke in a non-obvious way, asking the AI to fix it often went in circles. Finding the bug myself was faster.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Site-specific needs.&lt;/strong&gt; Academic websites have their own requirements, such as publication lists and teaching pages, and the AI often didn’t understand them without a lot of explanation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Polish.&lt;/strong&gt; User experience testing, page speed, and accessibility checks still needed human judgment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-id-recommend&quot;&gt;What I’d recommend&lt;/h2&gt;

&lt;p&gt;Use AI to get the structure and first draft in place quickly, then use your own skills to fix, customize, and optimize. AI speeds up a programmer; it doesn’t replace one, and you still need to understand the code to work with it well.&lt;/p&gt;

&lt;p&gt;The result is the site you’re reading now, &lt;a href=&quot;https://gmujtaba.com/&quot;&gt;gmujtaba.com&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">How I converted my academic website to Jekyll with GitHub Copilot and Claude Sonnet 4. AI wrote about 90% of the code; the last 10% still needed a programmer.</summary>
      
      
        
          <category term="vibe-coding" />
        
          <category term="AI-programming" />
        
          <category term="Jekyll" />
        
          <category term="academic-websites" />
        
          <category term="GitHub-Copilot" />
        
          <category term="Claude-Sonnet" />
        
      
    </entry>
  
    <entry>
      <title type="html">LaTeX Template for Data Science Practicum Proposals (IEEE Format)</title>
      <link href="https://gmujtaba.com/blog/professional-latex-data-science-practicum-template/" rel="alternate" type="text/html" title="LaTeX Template for Data Science Practicum Proposals (IEEE Format)"/>
      <published>2025-05-01T15:00:00+00:00</published>
      <updated>2025-05-01T15:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/professional-latex-data-science-practicum-template</id>
      <content type="html">&lt;p&gt;I made this &lt;a href=&quot;https://github.com/iamgmujtaba/practicum_proposal_template.git&quot;&gt;LaTeX template&lt;/a&gt; for my &lt;strong&gt;Master of Science in Data Science&lt;/strong&gt; practicum students. It gives every proposal the same IEEE-style layout and the same sections, with short instructions in each section explaining what to write. Students can focus on their project instead of formatting, and I can review proposals faster because they all follow the same structure.&lt;/p&gt;

&lt;h2 id=&quot;whats-included&quot;&gt;What’s included&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;IEEE-style formatting&lt;/li&gt;
  &lt;li&gt;Writing guidance in every section&lt;/li&gt;
  &lt;li&gt;Works in Overleaf or a local LaTeX install&lt;/li&gt;
  &lt;li&gt;Ready-made examples of citations, figures, tables, algorithms, and code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sections&quot;&gt;Sections&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Abstract&lt;/strong&gt;: project summary (250 words max)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Introduction / Background&lt;/strong&gt;: context and motivation&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Problem Statement&lt;/strong&gt;: the data science problem you’re solving&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Related Work&lt;/strong&gt;: what others have done&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Methodology / Approach&lt;/strong&gt;: your technical and analytical plan&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data Analysis&lt;/strong&gt;: data source, preparation, and ethical considerations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Expected Outcomes&lt;/strong&gt;: what you expect to find and why it matters&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Timeline&lt;/strong&gt;: milestones and phases&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: summary&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;preview&quot;&gt;Preview&lt;/h2&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/Data_Science_Practicum_Proposal_Template_Page1.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/Data_Science_Practicum_Proposal_Template_Page1.jpg&quot; alt=&quot;LaTeX Template for Data Science Practicum Proposals (IEEE Format)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/Data_Science_Practicum_Proposal_Template_Page2.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/Data_Science_Practicum_Proposal_Template_Page2.jpg&quot; alt=&quot;LaTeX Template for Data Science Practicum Proposals (IEEE Format)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;under-the-hood&quot;&gt;Under the hood&lt;/h2&gt;

&lt;p&gt;The template uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEEEtran&lt;/code&gt; document class and includes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Math equations&lt;/li&gt;
  &lt;li&gt;Pseudocode with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;algorithm2e&lt;/code&gt; package&lt;/li&gt;
  &lt;li&gt;Figures and tables&lt;/li&gt;
  &lt;li&gt;A BibTeX bibliography&lt;/li&gt;
  &lt;li&gt;Code listings with syntax highlighting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-to-use-it&quot;&gt;How to use it&lt;/h2&gt;

&lt;h3 id=&quot;in-overleaf-easiest&quot;&gt;In Overleaf (easiest)&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Download the &lt;a href=&quot;https://github.com/iamgmujtaba/practicum_proposal_template.git&quot;&gt;GitHub repository&lt;/a&gt; as a ZIP file.&lt;/li&gt;
  &lt;li&gt;In &lt;a href=&quot;https://www.overleaf.com/&quot;&gt;Overleaf&lt;/a&gt;, choose &lt;strong&gt;New Project&lt;/strong&gt; &amp;gt; &lt;strong&gt;Upload Project&lt;/strong&gt; and select the ZIP.&lt;/li&gt;
  &lt;li&gt;Replace the placeholder text with your proposal.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Recompile&lt;/strong&gt; to generate the PDF.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;on-your-own-computer&quot;&gt;On your own computer&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Clone the repository:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iamgmujtaba/practicum_proposal_template.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.tex&lt;/code&gt; in your LaTeX editor.&lt;/li&gt;
  &lt;li&gt;Edit and compile with your LaTeX distribution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;files&quot;&gt;Files&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;main.tex&lt;/strong&gt;: the template&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;IEEEtran.cls&lt;/strong&gt;: the IEEE document class&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;references.bib&lt;/strong&gt;: sample bibliography&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;customizing&quot;&gt;Customizing&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Put your name and your advisor’s name in the preamble.&lt;/li&gt;
  &lt;li&gt;Add, remove, or rename sections to match your program’s requirements.&lt;/li&gt;
  &lt;li&gt;Adjust formatting if your department has its own guidelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEEEtran&lt;/code&gt; document class is provided by IEEE.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">A free IEEE-style LaTeX template for MSDS practicum proposals, with guidance text in every section. Works in Overleaf or a local LaTeX install.</summary>
      
      
        
          <category term="Data Science Education" />
        
          <category term="LaTeX" />
        
          <category term="IEEE Format" />
        
          <category term="Graduate Research" />
        
          <category term="Academic Writing" />
        
          <category term="Practicum" />
        
      
    </entry>
  
    <entry>
      <title type="html">Run DeepSeek-R1 Locally with Ollama and Open WebUI (Even on a Jetson Orin Nano)</title>
      <link href="https://gmujtaba.com/blog/deepseek-webui-demo-minimal-installation/" rel="alternate" type="text/html" title="Run DeepSeek-R1 Locally with Ollama and Open WebUI (Even on a Jetson Orin Nano)"/>
      <published>2025-01-28T15:00:00+00:00</published>
      <updated>2025-01-28T15:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/deepseek-webui-demo-minimal-installation</id>
      <content type="html">&lt;h2 id=&quot;what-youll-set-up&quot;&gt;What you’ll set up&lt;/h2&gt;

&lt;p&gt;This guide runs the DeepSeek-R1 reasoning model on your own computer using &lt;a href=&quot;https://ollama.com&quot;&gt;Ollama&lt;/a&gt; (which downloads and runs models) and &lt;a href=&quot;https://github.com/open-webui/open-webui&quot;&gt;Open WebUI&lt;/a&gt; (a ChatGPT-style interface in your browser). Nothing is sent to the cloud. At the end I show the small 1.5B model running on an NVIDIA Jetson Orin Nano.&lt;/p&gt;

&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Python 3.11 or newer&lt;/li&gt;
  &lt;li&gt;Conda (see my &lt;a href=&quot;/blog/conda-management-guide-data-science/&quot;&gt;conda cheat sheet&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Admin rights to install software&lt;/li&gt;
  &lt;li&gt;At least 8 GB of RAM (16 GB or more for the larger models)&lt;/li&gt;
  &lt;li&gt;Tested on Ubuntu Linux&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;step-1-create-a-conda-environment&quot;&gt;Step 1: Create a conda environment&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda create &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; webui &lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3.11 &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; conda activate webui 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-2-install-ollama&quot;&gt;Step 2: Install Ollama&lt;/h2&gt;

&lt;h4 id=&quot;linux&quot;&gt;Linux&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh

&lt;span class=&quot;c&quot;&gt;# Check it installed&lt;/span&gt;
ollama &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;macos&quot;&gt;macOS&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;Download Ollama from &lt;a href=&quot;https://ollama.com/download/mac&quot;&gt;ollama.com/download/mac&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Open the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.dmg&lt;/code&gt; and drag Ollama into Applications.&lt;/li&gt;
  &lt;li&gt;Start Ollama from Applications.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;windows&quot;&gt;Windows&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;Download the installer from &lt;a href=&quot;https://ollama.com/download/windows&quot;&gt;ollama.com/download/windows&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Run it and follow the steps.&lt;/li&gt;
  &lt;li&gt;Start Ollama from the Start menu.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;step-3-install-open-webui&quot;&gt;Step 3: Install Open WebUI&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;open-webui
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-4-download-a-deepseek-r1-model&quot;&gt;Step 4: Download a DeepSeek-R1 model&lt;/h2&gt;

&lt;p&gt;Start with the smallest model. It runs on almost any machine:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# DeepSeek-R1-Distill-Qwen-1.5B (smallest, good for edge devices)&lt;/span&gt;
ollama run deepseek-r1:1.5b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Larger models give better answers but need much more memory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# DeepSeek-R1-Distill-Qwen-7B&lt;/span&gt;
ollama run deepseek-r1:7b

&lt;span class=&quot;c&quot;&gt;# DeepSeek-R1-Distill-Llama-8B&lt;/span&gt;
ollama run deepseek-r1:8b

&lt;span class=&quot;c&quot;&gt;# DeepSeek-R1-Distill-Qwen-14B&lt;/span&gt;
ollama run deepseek-r1:14b

&lt;span class=&quot;c&quot;&gt;# DeepSeek-R1-Distill-Qwen-32B&lt;/span&gt;
ollama run deepseek-r1:32b

&lt;span class=&quot;c&quot;&gt;# DeepSeek-R1-Distill-Llama-70B&lt;/span&gt;
ollama run deepseek-r1:70b

&lt;span class=&quot;c&quot;&gt;# Full DeepSeek-R1 (671B, needs server-class hardware)&lt;/span&gt;
ollama run deepseek-r1:671b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-5-start-open-webui&quot;&gt;Step 5: Start Open WebUI&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;open-webui serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8080&lt;/code&gt; in your browser, pick the DeepSeek model, and start chatting.&lt;/p&gt;

&lt;h3 id=&quot;demo&quot;&gt;Demo&lt;/h3&gt;

&lt;div class=&quot;row mt-3&quot;&gt;
    &lt;div class=&quot;col-sm mt-3 mt-md-0&quot;&gt;
        &lt;!-- Video include for blog posts --&gt;



  
    &lt;!-- YouTube embed --&gt;
    &lt;div class=&quot;video-container text-center img-fluid rounded z-depth-1&quot; style=&quot;max-width: 80%;&quot; itemscope=&quot;&quot; itemtype=&quot;https://schema.org/VideoObject&quot;&gt;
      &lt;meta itemprop=&quot;name&quot; content=&quot;Run DeepSeek-R1 Locally with Ollama and Open WebUI (Even on a Jetson Orin Nano)&quot; /&gt;
      &lt;meta itemprop=&quot;description&quot; content=&quot;Install DeepSeek-R1 locally with Ollama and Open WebUI for a private, ChatGPT-style chat in your browser. Choose a model size, and run the 1.5B model on an NVIDIA Jetson Orin Nano.&quot; /&gt;
      &lt;meta itemprop=&quot;thumbnailUrl&quot; content=&quot;https://img.youtube.com/vi/s_miZeP7YEs/maxresdefault.jpg&quot; /&gt;
      &lt;meta itemprop=&quot;uploadDate&quot; content=&quot;2025-01-28T15:00:00+00:00&quot; /&gt;
      &lt;meta itemprop=&quot;embedUrl&quot; content=&quot;https://www.youtube.com/embed/s_miZeP7YEs&quot; /&gt;
      &lt;div class=&quot;ratio ratio-16x9&quot;&gt;
        &lt;iframe src=&quot;https://www.youtube.com/embed/s_miZeP7YEs&quot; class=&quot;rounded&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; itemprop=&quot;contentUrl&quot;&gt;&lt;/iframe&gt;
      &lt;/div&gt;
      
    &lt;/div&gt;
  


    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;running-it-on-an-nvidia-jetson-orin-nano&quot;&gt;Running it on an NVIDIA Jetson Orin Nano&lt;/h2&gt;

&lt;p&gt;I also ran the 1.5B model on an NVIDIA Jetson Orin Nano with 8 GB of memory, and it ran smoothly. Small reasoning models like this are practical on edge devices when you need AI without an internet connection.&lt;/p&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/deepseek_jetson_nano_1.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/deepseek_jetson_nano_1.jpg&quot; alt=&quot;Run DeepSeek-R1 Locally with Ollama and Open WebUI (Even on a Jetson Orin Nano)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/deepseek_jetson_nano_2.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/deepseek_jetson_nano_2.jpg&quot; alt=&quot;Run DeepSeek-R1 Locally with Ollama and Open WebUI (Even on a Jetson Orin Nano)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Install DeepSeek-R1 locally with Ollama and Open WebUI for a private, ChatGPT-style chat in your browser. Choose a model size, and run the 1.5B model on an NVIDIA Jetson Orin Nano.</summary>
      
      
        
          <category term="AI" />
        
          <category term="DeepSeek" />
        
          <category term="DeepSeek-R1" />
        
          <category term="Open WebUI" />
        
          <category term="Ollama" />
        
          <category term="NVIDIA Jetson" />
        
          <category term="Local AI" />
        
          <category term="Edge AI" />
        
      
    </entry>
  
    <entry>
      <title type="html">Run DeepSeek-R1 Locally in Your Browser with WebGPU</title>
      <link href="https://gmujtaba.com/blog/deepseek-r1-webgpu-local-reasoning-architecture/" rel="alternate" type="text/html" title="Run DeepSeek-R1 Locally in Your Browser with WebGPU"/>
      <published>2025-01-21T15:00:00+00:00</published>
      <updated>2025-01-21T15:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/deepseek-r1-webgpu-local-reasoning-architecture</id>
      <content type="html">&lt;h2 id=&quot;what-it-is&quot;&gt;What it is&lt;/h2&gt;

&lt;p&gt;This project runs DeepSeek-R1, a reasoning model, directly in your web browser. It uses the small 1.5-billion-parameter version and your computer’s GPU through WebGPU, a browser feature that lets web pages use the graphics card. Under the hood it uses &lt;a href=&quot;https://github.com/huggingface/transformers.js&quot;&gt;Transformers.js&lt;/a&gt; and ONNX Runtime Web.&lt;/p&gt;

&lt;p&gt;In my tests it generated about 60 tokens per second.&lt;/p&gt;

&lt;h2 id=&quot;why-run-a-model-in-the-browser&quot;&gt;Why run a model in the browser&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Privacy&lt;/strong&gt;: your prompts never leave your computer. There’s no server and no API key.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Works offline&lt;/strong&gt;: once the model has downloaded, you can disconnect from the internet.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No cloud costs&lt;/strong&gt;: your own GPU does the work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The catch is that only small models fit in a browser, so answers won’t match large hosted models. For experiments, teaching, and privacy-sensitive use, it works well.&lt;/p&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iamgmujtaba/deepseek-r1.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;deepseek-r1
bash run.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The app opens at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8000&lt;/code&gt;. The first load downloads the model, which takes a few minutes; after that it loads from the browser cache.&lt;/p&gt;

&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;/h2&gt;

&lt;div class=&quot;row mt-3&quot;&gt;
    &lt;div class=&quot;col-sm mt-3 mt-md-0&quot;&gt;
        &lt;!-- Video include for blog posts --&gt;



  
    &lt;!-- Local video --&gt;
    &lt;div class=&quot;video-container text-center img-fluid rounded z-depth-1&quot; itemscope=&quot;&quot; itemtype=&quot;https://schema.org/VideoObject&quot;&gt;
      &lt;meta itemprop=&quot;name&quot; content=&quot;Run DeepSeek-R1 Locally in Your Browser with WebGPU&quot; /&gt;
      &lt;meta itemprop=&quot;description&quot; content=&quot;Run the DeepSeek-R1 1.5B reasoning model entirely in your browser with WebGPU, Transformers.js, and ONNX Runtime Web. No server, works offline, and your data never leaves your device.&quot; /&gt;
      &lt;meta itemprop=&quot;thumbnailUrl&quot; content=&quot;https://gmujtaba.com/assets/img/profile_pic.webp&quot; /&gt;
      &lt;meta itemprop=&quot;uploadDate&quot; content=&quot;2025-01-21T15:00:00+00:00&quot; /&gt;
      &lt;meta itemprop=&quot;contentUrl&quot; content=&quot;https://gmujtaba.com/assets/video/deepseek_demo.webm&quot; /&gt;
      &lt;video controls=&quot;&quot; class=&quot;img-fluid rounded&quot; itemprop=&quot;video&quot;&gt;
        &lt;source src=&quot;/assets/video/deepseek_demo.webm&quot; type=&quot;video/mp4&quot; /&gt;
        &lt;p&gt;Your browser doesn&apos;t support HTML5 video. Here is a &lt;a href=&quot;/assets/video/deepseek_demo.webm&quot;&gt;link to the video&lt;/a&gt; instead.&lt;/p&gt;
      &lt;/video&gt;
      
    &lt;/div&gt;
  


    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;caption&quot;&gt;
    DeepSeek-R1 running in the browser with WebGPU.
&lt;/div&gt;

&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;A browser with WebGPU support (recent Chrome or Edge)&lt;/li&gt;
  &lt;li&gt;Tested on macOS and Linux (Ubuntu)&lt;/li&gt;
  &lt;li&gt;At least 4 GB of RAM&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;

&lt;p&gt;This project builds on the &lt;a href=&quot;https://github.com/huggingface/transformers.js-examples&quot;&gt;Hugging Face Transformers.js examples&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Run the DeepSeek-R1 1.5B reasoning model entirely in your browser with WebGPU, Transformers.js, and ONNX Runtime Web. No server, works offline, and your data never leaves your device.</summary>
      
      
        
          <category term="AI" />
        
          <category term="DeepSeek" />
        
          <category term="DeepSeek-R1" />
        
          <category term="WebGPU" />
        
          <category term="Transformers.js" />
        
          <category term="Privacy" />
        
          <category term="Local AI" />
        
          <category term="Edge AI" />
        
      
    </entry>
  
    <entry>
      <title type="html">Conda Cheat Sheet: Create, Remove, and Export Environments</title>
      <link href="https://gmujtaba.com/blog/conda-management-guide-data-science/" rel="alternate" type="text/html" title="Conda Cheat Sheet: Create, Remove, and Export Environments"/>
      <published>2025-01-14T15:00:00+00:00</published>
      <updated>2025-01-14T15:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/conda-management-guide-data-science</id>
      <content type="html">&lt;p&gt;A quick reference for the conda commands I use most, written for my data science students. It covers creating and removing environments, installing packages, channels, and sharing environments with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;environment.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;install-conda&quot;&gt;Install conda&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.conda.io/en/latest/miniconda.html&quot;&gt;Miniconda&lt;/a&gt;: just conda and Python. This is what I recommend (see the comparison at the end).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.anaconda.com/products/individual&quot;&gt;Anaconda Distribution&lt;/a&gt;: conda plus hundreds of preinstalled data science packages.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://conda.io&quot;&gt;conda documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;why-use-conda&quot;&gt;Why use conda&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Separate environments per project.&lt;/strong&gt; Each project gets its own Python version and packages, so upgrading one project never breaks another.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Works the same on Windows, macOS, and Linux.&lt;/strong&gt; An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;environment.yml&lt;/code&gt; file recreates the same setup on a teammate’s machine.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;More than Python packages.&lt;/strong&gt; Conda can also install R, system libraries, and compiled tools that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt; can’t.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;key-terms&quot;&gt;Key terms&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Environment&lt;/strong&gt;: an isolated folder with its own Python and packages.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Channel&lt;/strong&gt;: a source of packages, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defaults&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda-forge&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;environment.yml&lt;/strong&gt;: a text file listing an environment’s packages, used to recreate it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;commands&quot;&gt;Commands&lt;/h2&gt;

&lt;h3 id=&quot;check-your-setup&quot;&gt;Check your setup&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda info                    &lt;span class=&quot;c&quot;&gt;# Show conda configuration and paths&lt;/span&gt;
conda &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;               &lt;span class=&quot;c&quot;&gt;# Show the installed conda version&lt;/span&gt;
conda update conda            &lt;span class=&quot;c&quot;&gt;# Update Conda itself&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;environments&quot;&gt;Environments&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda create &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; myenv         &lt;span class=&quot;c&quot;&gt;# Create a new environment (-n is short for --name)&lt;/span&gt;
conda create &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; myenv &lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3.10 &lt;span class=&quot;c&quot;&gt;# Create an environment with a specific Python version&lt;/span&gt;
conda activate myenv              &lt;span class=&quot;c&quot;&gt;# Activate an environment&lt;/span&gt;
conda deactivate                  &lt;span class=&quot;c&quot;&gt;# Deactivate current environment&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;env &lt;/span&gt;list                    &lt;span class=&quot;c&quot;&gt;# List all environments&lt;/span&gt;
conda remove &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; myenv &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;# Delete an environment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;packages&quot;&gt;Packages&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda list                    &lt;span class=&quot;c&quot;&gt;# List installed packages&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;packagename     &lt;span class=&quot;c&quot;&gt;# Install a package&lt;/span&gt;
conda update packagename      &lt;span class=&quot;c&quot;&gt;# Update a specific package&lt;/span&gt;
conda update &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;            &lt;span class=&quot;c&quot;&gt;# Update all packages&lt;/span&gt;
conda remove packagename      &lt;span class=&quot;c&quot;&gt;# Remove a package&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;channels-package-sources&quot;&gt;Channels (package sources)&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda config &lt;span class=&quot;nt&quot;&gt;--show&lt;/span&gt; channels                &lt;span class=&quot;c&quot;&gt;# Show configured channels&lt;/span&gt;
conda config &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; channels channelname     &lt;span class=&quot;c&quot;&gt;# Add a channel&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; channelname packagename    &lt;span class=&quot;c&quot;&gt;# Install from specific channel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;share-an-environment&quot;&gt;Share an environment&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda &lt;span class=&quot;nb&quot;&gt;env export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; environment.yml                    &lt;span class=&quot;c&quot;&gt;# Export full environment&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;env export&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--from-history&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; environment.yml     &lt;span class=&quot;c&quot;&gt;# Export Minimal environment&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;env &lt;/span&gt;create &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; environment.yml                   &lt;span class=&quot;c&quot;&gt;# Import environment from file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;specific-versions-and-cleanup&quot;&gt;Specific versions and cleanup&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3.10             &lt;span class=&quot;c&quot;&gt;# Install specific Python version&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;package&amp;gt;2.5,&amp;lt;3.2&quot;&lt;/span&gt;      &lt;span class=&quot;c&quot;&gt;# Version range installation&lt;/span&gt;
conda clean &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;                     &lt;span class=&quot;c&quot;&gt;# Remove unused packages and caches&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;common-workflows&quot;&gt;Common Workflows&lt;/h2&gt;

&lt;p&gt;Starting a New Project&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda create &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; projectname &lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3.10   &lt;span class=&quot;c&quot;&gt;# Create environment&lt;/span&gt;
conda activate projectname                    &lt;span class=&quot;c&quot;&gt;# Activate it&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;required-packages               &lt;span class=&quot;c&quot;&gt;# Install needs&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;env export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; environment.yml            &lt;span class=&quot;c&quot;&gt;# Save configuration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sharing a Project&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda &lt;span class=&quot;nb&quot;&gt;env export&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--from-history&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; environment.yml   &lt;span class=&quot;c&quot;&gt;# For cross-platform sharing&lt;/span&gt;
conda &lt;span class=&quot;nb&quot;&gt;env export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; environment.yml                  &lt;span class=&quot;c&quot;&gt;# For exact reproduction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;troubleshooting-tips&quot;&gt;Troubleshooting Tips&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda list&lt;/code&gt; to verify installed packages&lt;/li&gt;
  &lt;li&gt;Check channel priorities with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda config --show&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Clear package caches with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda clean --all&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Review environment history with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda list --revisions&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Restore previous states with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda install --revision&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;best-practices--tips&quot;&gt;Best Practices &amp;amp; Tips&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PyTorch no longer publishes conda packages on its own channel.&lt;/strong&gt; Maintaining conda builds cost too much compared to how few people downloaded them versus PyPI. As part of the deprecation timeline, PyTorch will stop providing nightly builds for its core and domain libraries starting &lt;strong&gt;November 18, 2024&lt;/strong&gt; &lt;a href=&quot;https://github.com/pytorch/pytorch/issues/138506&quot;&gt;PyTorch Issue #138506&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To accommodate users affected by this change, PyTorch recommends switching to its official wheel packages available on &lt;a href=&quot;https://download.pytorch.org&quot;&gt;download.pytorch.org&lt;/a&gt; or PyPI, which are actively supported. For users who prefer conda, PyTorch suggests transitioning to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pytorch-cpu&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pytorch-gpu&lt;/code&gt; packages available through &lt;a href=&quot;https://conda-forge.org/&quot;&gt;conda-forge&lt;/a&gt;. If you currently depend on the deprecated binaries, it is advised to migrate to pip wheels, which offer equivalent functionality and are more sustainable to maintain &lt;a href=&quot;https://dev-discuss.pytorch.org/t/pytorch-deprecation-of-conda-nightly-builds/2590&quot;&gt;PyTorch Discussion: Deprecation of Conda Nightly Builds&lt;/a&gt;.&lt;/p&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/2024_12_conda_torch.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/2024_12_conda_torch.png&quot; alt=&quot;Source: [Twitter](https://x.com/PyTorch/status/1857500664831635882)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
  &lt;figcaption class=&quot;figure-caption&quot;&gt;Source: &lt;a href=&quot;https://x.com/PyTorch/status/1857500664831635882&quot;&gt;Twitter&lt;/a&gt;
&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Use Miniconda:&lt;/strong&gt; it takes far less disk space. Miniconda gives you conda and Python, while Anaconda preinstalls hundreds of packages you may never use &lt;a href=&quot;https://docs.anaconda.com/getting-started/&quot;&gt;Miniconda vs Anaconda - Anaconda Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Feature&lt;/th&gt;
      &lt;th&gt;Anaconda Distribution&lt;/th&gt;
      &lt;th&gt;Miniconda&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Created by&lt;/td&gt;
      &lt;td&gt;Anaconda&lt;/td&gt;
      &lt;td&gt;Anaconda&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Has conda&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Has Anaconda Navigator&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;No&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Number of packages&lt;/td&gt;
      &lt;td&gt;300+&lt;/td&gt;
      &lt;td&gt;&amp;lt; 70&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Install space required&lt;/td&gt;
      &lt;td&gt;~4.4 GB&lt;/td&gt;
      &lt;td&gt;~480 MB&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Name Environments Meaningfully:&lt;/strong&gt; Use descriptive names for easy identification&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;One Environment Per Project:&lt;/strong&gt; Create separate environments for different projects&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Export Regularly:&lt;/strong&gt; Keep environment files in version control&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Update Strategically:&lt;/strong&gt; Test updates in a clone of your environment first (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda create --name myenv-test --clone myenv&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Use Environment Files:&lt;/strong&gt; Store environment configurations in version control&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;my-recommendation&quot;&gt;My recommendation&lt;/h2&gt;

&lt;p&gt;Use Miniconda to create environments (it works well with &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VS Code&lt;/a&gt;), then install packages with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt; inside the environment. Pick one installer per environment: mixing conda and pip installs of the same packages &lt;a href=&quot;https://stackoverflow.com/questions/56134588/is-it-a-bad-idea-to-use-conda-and-pip-install-on-the-same-environment&quot;&gt;can cause conflicts&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Conda cheat sheet for data science: conda create -n myenv python=3.10, conda remove --name myenv --all, install packages, manage channels, and export environment.yml.</summary>
      
      
        
          <category term="Conda" />
        
          <category term="package-management" />
        
          <category term="data-science-tools" />
        
          <category term="Python-environments" />
        
          <category term="Anaconda" />
        
          <category term="development-workflow" />
        
          <category term="cross-platform-development" />
        
      
    </entry>
  
    <entry>
      <title type="html">Git &amp; GitHub Cheat Sheet: Essential Commands (git add -A vs git commit -a)</title>
      <link href="https://gmujtaba.com/blog/github-workflow-mastery-command-reference/" rel="alternate" type="text/html" title="Git &amp; GitHub Cheat Sheet: Essential Commands (git add -A vs git commit -a)"/>
      <published>2024-12-22T13:00:00+00:00</published>
      <updated>2024-12-22T13:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/github-workflow-mastery-command-reference</id>
      <content type="html">&lt;p&gt;A one-page reference for the Git commands I use most, and the ones my students ask about. It starts with setup and goes through staging, branches, remotes, and fixing mistakes.&lt;/p&gt;

&lt;h2 id=&quot;install-git&quot;&gt;Install Git&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://desktop.github.com&quot;&gt;GitHub Desktop&lt;/a&gt; for Windows and macOS, if you prefer a graphical app&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://git-scm.com&quot;&gt;Git for the command line&lt;/a&gt; for Windows, macOS, and Linux&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;key-terms&quot;&gt;Key terms&lt;/h2&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/2024_12_github_cheatsheet_github_flow.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/2024_12_github_cheatsheet_github_flow.png&quot; alt=&quot;Source: [GitHub Education](https://github.com/education)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
  &lt;figcaption class=&quot;figure-caption&quot;&gt;Source: &lt;a href=&quot;https://github.com/education&quot;&gt;GitHub Education&lt;/a&gt;
&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Git&lt;/strong&gt;: the version control tool that runs on your computer.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: a website that hosts Git repositories and adds collaboration tools.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Commit&lt;/strong&gt;: a saved snapshot of your project.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Branch&lt;/strong&gt;: a separate line of work, so you can try changes without touching &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clone&lt;/strong&gt;: a full local copy of a repository, including its history.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Remote&lt;/strong&gt;: a copy of the repository on a server, usually called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fork&lt;/strong&gt;: your own copy of someone else’s repository on GitHub.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pull request&lt;/strong&gt;: a request to merge your branch, with a place for review and discussion.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;HEAD&lt;/strong&gt;: the commit you currently have checked out.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;first-time-setup&quot;&gt;First-time setup&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; user.name &lt;span class=&quot;s2&quot;&gt;&quot;[Your Name]&quot;&lt;/span&gt;      &lt;span class=&quot;c&quot;&gt;# Name shown on your commits&lt;/span&gt;
git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; user.email &lt;span class=&quot;s2&quot;&gt;&quot;[you@email.com]&quot;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# Email shown on your commits&lt;/span&gt;
git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; color.ui auto                &lt;span class=&quot;c&quot;&gt;# Colored output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;start-a-repository&quot;&gt;Start a repository&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git init                   &lt;span class=&quot;c&quot;&gt;# Turn the current folder into a Git repository&lt;/span&gt;
git clone &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;repository-url] &lt;span class=&quot;c&quot;&gt;# Download a repository with its full history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;stage-and-commit-changes&quot;&gt;Stage and commit changes&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git status                 &lt;span class=&quot;c&quot;&gt;# What&apos;s modified, staged, and untracked&lt;/span&gt;
git add &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;file]             &lt;span class=&quot;c&quot;&gt;# Stage a file for the next commit&lt;/span&gt;
git reset &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;file]           &lt;span class=&quot;c&quot;&gt;# Unstage a file (keeps your edits)&lt;/span&gt;
git diff                   &lt;span class=&quot;c&quot;&gt;# Changes you haven&apos;t staged yet&lt;/span&gt;
git diff &lt;span class=&quot;nt&quot;&gt;--staged&lt;/span&gt;          &lt;span class=&quot;c&quot;&gt;# Changes staged for the next commit&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;[message]&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# Commit what&apos;s staged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;git-add--a-vs-git-add--vs-git-add--u-vs-git-commit--a&quot;&gt;git add -A vs git add . vs git add -u vs git commit -a&lt;/h3&gt;

&lt;p&gt;These four look similar but stage different things. The key question is whether &lt;strong&gt;untracked (new) files&lt;/strong&gt; and &lt;strong&gt;deletions&lt;/strong&gt; are included.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Command&lt;/th&gt;
      &lt;th&gt;New (untracked) files&lt;/th&gt;
      &lt;th&gt;Modified files&lt;/th&gt;
      &lt;th&gt;Deleted files&lt;/th&gt;
      &lt;th&gt;Scope&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add -A&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Whole repository&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add .&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Current directory and below&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add -u&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Whole repository&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit -a&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Yes&lt;/td&gt;
      &lt;td&gt;Whole repository (stages and commits in one step)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git add &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt;                 &lt;span class=&quot;c&quot;&gt;# Stage everything: new, modified, and deleted files&lt;/span&gt;
git add &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt;                 &lt;span class=&quot;c&quot;&gt;# Stage modified and deleted tracked files only (no new files)&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;msg&quot;&lt;/span&gt;     &lt;span class=&quot;c&quot;&gt;# Auto-stage modified/deleted TRACKED files, then commit&lt;/span&gt;
git add new_file.py &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;msg&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# New files must be added first&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Common gotcha:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit -a&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; commit untracked files. A file you just created is ignored until you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add&lt;/code&gt; on it once. After that, Git tracks it and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit -a&lt;/code&gt; picks up its future changes.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;branches&quot;&gt;Branches&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch                 &lt;span class=&quot;c&quot;&gt;# List local branches (* marks the current one)&lt;/span&gt;
git branch &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;              &lt;span class=&quot;c&quot;&gt;# List local AND remote-tracking branches (e.g. remotes/origin/main)&lt;/span&gt;
git branch &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt;              &lt;span class=&quot;c&quot;&gt;# List remote-tracking branches only&lt;/span&gt;
git branch &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;name]          &lt;span class=&quot;c&quot;&gt;# Create a branch&lt;/span&gt;
git checkout &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;name]        &lt;span class=&quot;c&quot;&gt;# Switch to a branch (newer Git: git switch [name])&lt;/span&gt;
git merge &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;branch]         &lt;span class=&quot;c&quot;&gt;# Merge another branch into the current one&lt;/span&gt;
git log                    &lt;span class=&quot;c&quot;&gt;# Commit history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;inspect-history&quot;&gt;Inspect history&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log                     &lt;span class=&quot;c&quot;&gt;# Full commit history&lt;/span&gt;
git log branchB..branchA    &lt;span class=&quot;c&quot;&gt;# Commits in branchA that aren&apos;t in branchB&lt;/span&gt;
git log &lt;span class=&quot;nt&quot;&gt;--follow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;file]     &lt;span class=&quot;c&quot;&gt;# History of one file, including renames&lt;/span&gt;
git diff branchB...branchA  &lt;span class=&quot;c&quot;&gt;# Changes on branchA since it split from branchB&lt;/span&gt;
git show &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;commit-SHA]       &lt;span class=&quot;c&quot;&gt;# Details and changes of one commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;work-with-remotes&quot;&gt;Work with remotes&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git remote add &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;url]   &lt;span class=&quot;c&quot;&gt;# Add a remote (usually &quot;origin&quot;)&lt;/span&gt;
git fetch &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;              &lt;span class=&quot;c&quot;&gt;# Download new commits without merging&lt;/span&gt;
git merge &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/[branch]     &lt;span class=&quot;c&quot;&gt;# Merge a fetched remote branch&lt;/span&gt;
git push &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;branch]      &lt;span class=&quot;c&quot;&gt;# Upload your commits&lt;/span&gt;
git pull                       &lt;span class=&quot;c&quot;&gt;# Fetch and merge in one step&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;move-and-delete-files&quot;&gt;Move and delete files&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;file]               &lt;span class=&quot;c&quot;&gt;# Delete a file and stage the deletion&lt;/span&gt;
git &lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;old-path] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;new-path] &lt;span class=&quot;c&quot;&gt;# Move or rename a file and stage it&lt;/span&gt;
git log &lt;span class=&quot;nt&quot;&gt;--stat&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt;           &lt;span class=&quot;c&quot;&gt;# History showing renamed and moved files&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;rewrite-history-and-save-work-for-later&quot;&gt;Rewrite history and save work for later&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git rebase &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;branch]         &lt;span class=&quot;c&quot;&gt;# Replay your commits on top of another branch&lt;/span&gt;
git reset &lt;span class=&quot;nt&quot;&gt;--hard&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;commit]   &lt;span class=&quot;c&quot;&gt;# Go back to a commit and DISCARD everything after it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset --hard&lt;/code&gt; deletes uncommitted work permanently. Use it carefully.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git stash                   &lt;span class=&quot;c&quot;&gt;# Put your uncommitted changes aside&lt;/span&gt;
git stash list              &lt;span class=&quot;c&quot;&gt;# See saved stashes&lt;/span&gt;
git stash pop               &lt;span class=&quot;c&quot;&gt;# Bring back the latest stash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ignore-files&quot;&gt;Ignore files&lt;/h2&gt;

&lt;p&gt;List files and folders Git should ignore in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; file at the root of your repository:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;logs/
*.notes
pattern*/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To ignore files in every repository on your computer:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; core.excludesfile &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;path-to-ignore-file]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-six-commands-youll-use-every-day&quot;&gt;The six commands you’ll use every day&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;git clone&lt;/strong&gt;: get a copy of a repository&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;git status&lt;/strong&gt;: see what changed&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;git add&lt;/strong&gt;: stage changes&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;git commit&lt;/strong&gt;: save a snapshot&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;git push&lt;/strong&gt;: upload your commits&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;git pull&lt;/strong&gt;: download others’ commits&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;good-habits&quot;&gt;Good habits&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Write clear commit messages&lt;/strong&gt; that say what changed and why.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Do new work on a branch&lt;/strong&gt;, not directly on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;, and merge through a pull request.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Automate checks with GitHub Actions&lt;/strong&gt; so tests run on every push.&lt;/li&gt;
&lt;/ul&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Git and GitHub cheat sheet: setup, staging, commits, branches, and remotes. Explains git add -A vs git add -u vs git commit -a, and why untracked files are skipped.</summary>
      
      
        
          <category term="Git" />
        
          <category term="GitHub" />
        
          <category term="Cheat Sheet" />
        
          <category term="Version Control" />
        
          <category term="Software Development" />
        
      
    </entry>
  
    <entry>
      <title type="html">A Simple Web UI for LLaMA 3.2 Multimodal (Text + Images) with Ollama</title>
      <link href="https://gmujtaba.com/blog/llama-3-2-multimodal-web-interface-ollama/" rel="alternate" type="text/html" title="A Simple Web UI for LLaMA 3.2 Multimodal (Text + Images) with Ollama"/>
      <published>2024-09-28T13:00:00+00:00</published>
      <updated>2024-09-28T13:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/llama-3-2-multimodal-web-interface-ollama</id>
      <content type="html">&lt;h2 id=&quot;what-it-is&quot;&gt;What it is&lt;/h2&gt;

&lt;p&gt;Meta’s LLaMA 3.2 includes a multimodal version that understands both text and images. &lt;a href=&quot;https://ollama.com&quot;&gt;Ollama&lt;/a&gt; makes it easy to run locally, but its default interface is the command line. I built a small web interface so you can chat with the model in a browser, upload images, and read nicely formatted answers. Everything runs on your own machine.&lt;/p&gt;

&lt;p&gt;I tested it on Ubuntu.&lt;/p&gt;

&lt;h2 id=&quot;features&quot;&gt;Features&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Text and image input&lt;/strong&gt;: ask a question, attach an image, or both.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Formatted answers&lt;/strong&gt;: code comes back syntax-highlighted.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Copy button&lt;/strong&gt;: copy any code snippet with one click.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Works on any screen&lt;/strong&gt;: desktop, tablet, or phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Install Ollama from &lt;a href=&quot;https://ollama.com&quot;&gt;ollama.com&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Clone the repository and go into the folder:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iamgmujtaba/llama3.2-webUI
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;llama3.2-webUI
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Start the app:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bash run.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The script starts a local server. Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8000&lt;/code&gt; in your browser. Check the repository README for the exact model to pull with Ollama.&lt;/p&gt;

&lt;h2 id=&quot;using-it&quot;&gt;Using it&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Type a question in the input box and press send.&lt;/li&gt;
  &lt;li&gt;To ask about an image, upload it along with your question (for example, “What’s in this picture?” or “Explain this chart”).&lt;/li&gt;
  &lt;li&gt;Use the copy button on any code block to grab the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;screenshots&quot;&gt;Screenshots&lt;/h2&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/home_webui.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/home_webui.png&quot; alt=&quot;A Simple Web UI for LLaMA 3.2 Multimodal (Text + Images) with Ollama&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/home_webui_res.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/home_webui_res.png&quot; alt=&quot;A Simple Web UI for LLaMA 3.2 Multimodal (Text + Images) with Ollama&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;contributing-and-license&quot;&gt;Contributing and license&lt;/h2&gt;

&lt;p&gt;Contributions are welcome through pull requests. The project uses the MIT License; see the &lt;a href=&quot;https://github.com/iamgmujtaba/llama3.2-webUI/blob/main/LICENSE&quot;&gt;LICENSE&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;The code is on &lt;a href=&quot;https://github.com/iamgmujtaba/llama3.2-webUI&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">A lightweight web interface for chatting with Meta&apos;s LLaMA 3.2 multimodal model through Ollama. Send text and images, get formatted answers and copyable code, all running locally.</summary>
      
      
        
          <category term="Large Language Model" />
        
          <category term="LLM" />
        
          <category term="LLaMA 3.2" />
        
          <category term="Ollama" />
        
          <category term="Multimodal AI" />
        
          <category term="Web Interface" />
        
          <category term="Local AI" />
        
      
    </entry>
  
    <entry>
      <title type="html">Generate Thumbnail Containers (Seek Preview Sprites) from Videos with Python and FFmpeg</title>
      <link href="https://gmujtaba.com/blog/generate-thumbnail-containers-from-videos/" rel="alternate" type="text/html" title="Generate Thumbnail Containers (Seek Preview Sprites) from Videos with Python and FFmpeg"/>
      <published>2024-04-15T13:00:00+00:00</published>
      <updated>2024-04-15T13:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/generate-thumbnail-containers-from-videos</id>
      <content type="html">&lt;h2 id=&quot;what-a-thumbnail-container-is&quot;&gt;What a thumbnail container is&lt;/h2&gt;

&lt;p&gt;When you hover over the progress bar on YouTube, a small preview of that moment appears. Those previews don’t come from the video itself. The player loads a &lt;strong&gt;thumbnail container&lt;/strong&gt;: a single image holding a grid of small frames taken at regular intervals (for example, a 5×5 grid with one frame every few seconds). Showing the right tile of that grid is instant, so scrubbing feels smooth without downloading any video.&lt;/p&gt;

&lt;p&gt;Thumbnail containers are also the core of my research on lightweight video summarization. Because they’re tiny compared to the video, a phone or edge device can analyze them to find the interesting parts of a long video.&lt;/p&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/thumb_sample.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/thumb_sample.png&quot; alt=&quot;Generate Thumbnail Containers (Seek Preview Sprites) from Videos with Python and FFmpeg&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;A thumbnail container (left) and how YouTube uses one to show seek previews (right).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post shows how to generate thumbnail containers, plus HLS video segments, from your own videos with my tool &lt;a href=&quot;https://github.com/iamgmujtaba/vid2tc&quot;&gt;vid2tc&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;p&gt;Clone the repository:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iamgmujtaba/vid2tc.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;vid2tc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a conda environment and install the requirements:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda create &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; vid2tc &lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3.8 &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
conda activate vid2tc
pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You also need FFmpeg installed and on your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt;. My &lt;a href=&quot;/blog/configure-hls-server-on-windows/&quot;&gt;HLS server guide&lt;/a&gt; covers installing it on Windows.&lt;/p&gt;

&lt;h2 id=&quot;options&quot;&gt;Options&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python .&lt;span class=&quot;se&quot;&gt;\m&lt;/span&gt;ain.py &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt;, &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;                         Show &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; INP_PATH, &lt;span class=&quot;nt&quot;&gt;--inp_path&lt;/span&gt; INP_PATH   Folder with your input videos
  &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; OUT_PATH, &lt;span class=&quot;nt&quot;&gt;--out_path&lt;/span&gt; OUT_PATH   Folder &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;the output
  &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; SEG_LEN,  &lt;span class=&quot;nt&quot;&gt;--seg_len&lt;/span&gt; SEG_LEN     Video segment length &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;seconds
  &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; AUDIO,    &lt;span class=&quot;nt&quot;&gt;--audio&lt;/span&gt; AUDIO         Extract audio &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;True/False&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; FRAMES,   &lt;span class=&quot;nt&quot;&gt;--frames&lt;/span&gt; FRAMES       Extract video frames &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;True/False&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--thumb_width&lt;/span&gt; THUMB_WIDTH          Width of each thumbnail &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;pixels
  &lt;span class=&quot;nt&quot;&gt;--thumb_height&lt;/span&gt; THUMB_HEIGHT        Height of each thumbnail &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;pixels
  &lt;span class=&quot;nt&quot;&gt;--thumb_interval&lt;/span&gt; THUMB_INTERVAL    Seconds between thumbnails
  &lt;span class=&quot;nt&quot;&gt;--thumb_container&lt;/span&gt; THUMB_CONTAINER  Grid size of each container &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;default: 5x5&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;example&quot;&gt;Example&lt;/h2&gt;

&lt;p&gt;Put your videos in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt; folder and run:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python .&lt;span class=&quot;se&quot;&gt;\m&lt;/span&gt;ain.py &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; .&lt;span class=&quot;se&quot;&gt;\i&lt;/span&gt;nput&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; .&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;utput&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;output&lt;/code&gt; folder will contain the thumbnail containers and the video segments for each video. To stream the segments, follow my &lt;a href=&quot;/blog/configure-hls-server-on-windows/&quot;&gt;HLS server guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code is on &lt;a href=&quot;https://github.com/iamgmujtaba/vid2tc&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h5 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;/h5&gt;
&lt;p&gt;The base code comes from &lt;a href=&quot;https://github.com/flavioribeiro/video-thumbnail-generator&quot;&gt;Video Thumbnail Generator&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Create YouTube-style thumbnail containers (sprite sheets of preview frames) and HLS video segments from your videos with vid2tc, a Python and FFmpeg tool.</summary>
      
      
        
          <category term="Video Processing" />
        
          <category term="Thumbnail Containers" />
        
          <category term="Python" />
        
          <category term="FFmpeg" />
        
          <category term="Video Streaming" />
        
      
    </entry>
  
    <entry>
      <title type="html">How to Set Up an HLS Streaming Server on Windows (IIS + FFmpeg)</title>
      <link href="https://gmujtaba.com/blog/configure-hls-server-on-windows/" rel="alternate" type="text/html" title="How to Set Up an HLS Streaming Server on Windows (IIS + FFmpeg)"/>
      <published>2024-02-15T13:00:00+00:00</published>
      <updated>2024-02-15T13:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/configure-hls-server-on-windows</id>
      <content type="html">&lt;h2 id=&quot;what-this-guide-sets-up&quot;&gt;What this guide sets up&lt;/h2&gt;

&lt;p&gt;HTTP Live Streaming (HLS) is the streaming format Apple introduced in 2009. It’s now supported by most players, browsers, and phones. HLS cuts a video into short segments (usually 6–10 seconds) and lists them in a playlist file ending in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.m3u8&lt;/code&gt;. The player downloads the playlist, then fetches the segments one after another. Everything goes over plain HTTP, so any web server can host it, and it passes through firewalls and CDNs without special setup.&lt;/p&gt;

&lt;p&gt;The trade-off is latency: live HLS streams typically run 15–30 seconds behind real time. For video on demand that doesn’t matter, which is why HLS is so widely used.&lt;/p&gt;

&lt;p&gt;This guide sets up an HLS server on Windows 10/11 with IIS (the web server built into Windows) and FFmpeg, then plays a test video in VLC and on an iPhone. If you need MPEG-DASH instead, see my &lt;a href=&quot;/blog/configure-dash-server-windows/&quot;&gt;DASH server guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;step-1-turn-on-iis&quot;&gt;Step 1: Turn on IIS&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Press &lt;strong&gt;Windows Key + S&lt;/strong&gt; and search for &lt;strong&gt;Turn Windows features on or off&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Tick &lt;strong&gt;Internet Information Services&lt;/strong&gt; and wait for it to install, then close the window.&lt;/li&gt;
  &lt;li&gt;Open a browser and go to &lt;strong&gt;127.0.0.1&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;You should see the IIS welcome page. If not, restart your computer.&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/iis_home.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/iis_home.jpg&quot; alt=&quot;How to Set Up an HLS Streaming Server on Windows (IIS + FFmpeg)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;step-2-change-the-web-root-optional&quot;&gt;Step 2: Change the web root (optional)&lt;/h2&gt;

&lt;p&gt;By default IIS serves files from &lt;strong&gt;C:\inetpub\wwwroot\&lt;/strong&gt;. Skip this step if that’s fine.&lt;/p&gt;

&lt;p&gt;Open &lt;strong&gt;IIS Manager&lt;/strong&gt; (Windows Key + S, type &lt;strong&gt;IIS&lt;/strong&gt;). Right-click &lt;strong&gt;Default Web Site&lt;/strong&gt; and choose &lt;strong&gt;Manage Website&lt;/strong&gt; &amp;gt; &lt;strong&gt;Advanced Settings&lt;/strong&gt;. This window shows the site’s settings, including its folder (the “document root”), protocols, and bindings. Click &lt;strong&gt;Physical Path&lt;/strong&gt;, then the button on the right, to pick a different folder.&lt;/p&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/iis_path.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/iis_path.jpg&quot; alt=&quot;How to Set Up an HLS Streaming Server on Windows (IIS + FFmpeg)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;step-3-enable-cors&quot;&gt;Step 3: Enable CORS&lt;/h2&gt;

&lt;p&gt;Web players often load the stream from a different site, and browsers block that unless your server allows it. This permission is called cross-origin resource sharing (CORS).&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open &lt;strong&gt;IIS Manager&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Select &lt;strong&gt;Default Web Site&lt;/strong&gt; and double-click &lt;strong&gt;HTTP Response Headers&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;. Enter &lt;strong&gt;Access-Control-Allow-Origin&lt;/strong&gt; as the name and &lt;strong&gt;*&lt;/strong&gt; as the value.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt; again. Enter &lt;strong&gt;Access-Control-Allow-Headers&lt;/strong&gt; as the name and &lt;strong&gt;Range&lt;/strong&gt; as the value.&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/hrs_page.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/hrs_page.jpg&quot; alt=&quot;How to Set Up an HLS Streaming Server on Windows (IIS + FFmpeg)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;step-4-add-the-hls-mime-types&quot;&gt;Step 4: Add the HLS MIME types&lt;/h2&gt;

&lt;p&gt;IIS won’t serve file types it doesn’t recognize, and it doesn’t know &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.m3u8&lt;/code&gt; by default.&lt;/p&gt;

&lt;p&gt;In IIS Manager, click your server and double-click &lt;strong&gt;MIME Types&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Type &lt;strong&gt;.m3u8&lt;/strong&gt; for File name extension; type &lt;strong&gt;application/vnd.apple.mpegurl&lt;/strong&gt; for MIME-type. Press OK.&lt;/li&gt;
  &lt;li&gt;Add a second entry: &lt;strong&gt;.ts&lt;/strong&gt; for File name extension; type &lt;strong&gt;video/mp2t&lt;/strong&gt; for MIME-type. Press OK. (Skip this if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ts&lt;/code&gt; is already listed.)&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;HLS MIME types:&lt;/strong&gt; playlists (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.m3u8&lt;/code&gt;) use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/vnd.apple.mpegurl&lt;/code&gt; (some servers use the older &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/x-mpegURL&lt;/code&gt;, which players also accept), and MPEG-TS segments (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ts&lt;/code&gt;) use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;video/mp2t&lt;/code&gt;. A wrong MIME type is the most common reason an HLS stream won’t play from IIS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you’re done, the MIME Types list in IIS should include:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;File name extension&lt;/th&gt;
      &lt;th&gt;MIME type&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.m3u8&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/vnd.apple.mpegurl&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ts&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;video/mp2t&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;step-5-install-ffmpeg&quot;&gt;Step 5: Install FFmpeg&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Download a Windows build of FFmpeg from &lt;a href=&quot;https://www.ffmpeg.org/download.html#build-windows&quot;&gt;ffmpeg.org&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Extract it to &lt;strong&gt;C:\ffmpeg&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Copy the path of the &lt;strong&gt;bin&lt;/strong&gt; folder (&lt;strong&gt;C:\ffmpeg\bin&lt;/strong&gt;).&lt;/li&gt;
  &lt;li&gt;Open &lt;strong&gt;System Properties&lt;/strong&gt; &amp;gt; &lt;strong&gt;Advanced System Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Environment Variables&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Under System variables, select &lt;strong&gt;Path&lt;/strong&gt; and click &lt;strong&gt;Edit&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;New&lt;/strong&gt;, paste the path, and click OK.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To check, open a new Command Prompt and type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt;. If it prints version information, it’s installed.&lt;/p&gt;

&lt;h2 id=&quot;step-6-create-the-hls-segments&quot;&gt;Step 6: Create the HLS segments&lt;/h2&gt;

&lt;p&gt;You can use my &lt;a href=&quot;https://github.com/iamgmujtaba/vid2tc&quot;&gt;vid2tc&lt;/a&gt; tool to create video segments (and thumbnail containers) from your own videos, or follow these steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Download the &lt;a href=&quot;https://download.blender.org/demo/movies/BBB/bbb_sunflower_1080p_30fps_normal.mp4.zip&quot;&gt;Big Buck Bunny&lt;/a&gt; sample video.&lt;/li&gt;
  &lt;li&gt;Rename it to &lt;strong&gt;input.mp4&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;In that folder, run:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ffmpeg &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; input.mp4 &lt;span class=&quot;nt&quot;&gt;-force_key_frames&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;expr:gte(t,n_forced*10)&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-strict&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-2&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;:a aac &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;:v libx264 &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; segment &lt;span class=&quot;nt&quot;&gt;-segment_list_type&lt;/span&gt; m3u8 &lt;span class=&quot;nt&quot;&gt;-segment_list_size&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;-segment_time&lt;/span&gt; 10.0 &lt;span class=&quot;nt&quot;&gt;-segment_time_delta&lt;/span&gt; 0.1 &lt;span class=&quot;nt&quot;&gt;-segment_list&lt;/span&gt; out.m3u8 out%02d.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This cuts the video into 10-second &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ts&lt;/code&gt; segments and writes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out.m3u8&lt;/code&gt; playlist.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a folder named &lt;strong&gt;bbb&lt;/strong&gt; in your web root (for example &lt;strong&gt;C:\inetpub\wwwroot\bbb&lt;/strong&gt;). Copy every generated file into it, but not &lt;strong&gt;input.mp4&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To convert several videos at once, use my script:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iamgmujtaba/hls-server.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then run:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python .&lt;span class=&quot;se&quot;&gt;\m&lt;/span&gt;ain.py &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; .&lt;span class=&quot;se&quot;&gt;\i&lt;/span&gt;nput&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; .&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;utput&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-7-test-playback&quot;&gt;Step 7: Test playback&lt;/h2&gt;

&lt;h3 id=&quot;find-your-ip-address&quot;&gt;Find your IP address&lt;/h3&gt;

&lt;p&gt;Open Command Prompt and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipconfig&lt;/code&gt;. Note the &lt;strong&gt;IPv4 Address&lt;/strong&gt; (something like 192.168.x.x).&lt;/p&gt;

&lt;h3 id=&quot;play-in-vlc&quot;&gt;Play in VLC&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Install &lt;a href=&quot;https://www.videolan.org/vlc/download-windows.html&quot;&gt;VLC&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Press &lt;strong&gt;Ctrl+N&lt;/strong&gt; to open a network stream.&lt;/li&gt;
  &lt;li&gt;Enter &lt;strong&gt;http://192.XXX.XXX.XXX/bbb/out.m3u8&lt;/strong&gt;, using your own IP address.&lt;/li&gt;
  &lt;li&gt;Press &lt;strong&gt;Play&lt;/strong&gt;. If the video plays, your HLS server works.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;play-on-an-iphone-or-ipad&quot;&gt;Play on an iPhone or iPad&lt;/h3&gt;

&lt;p&gt;Safari plays HLS natively. Connect the device to the same Wi-Fi network and open &lt;strong&gt;http://192.XXX.XXX.XXX/bbb/out.m3u8&lt;/strong&gt; in Safari.&lt;/p&gt;

&lt;h3 id=&quot;play-in-a-browser-ubuntu-jetson-or-any-device&quot;&gt;Play in a browser (Ubuntu, Jetson, or any device)&lt;/h3&gt;

&lt;p&gt;Most desktop browsers need a JavaScript player for HLS. Use &lt;a href=&quot;https://github.com/video-dev/hls.js/&quot;&gt;hls.js&lt;/a&gt; and follow its &lt;a href=&quot;https://github.com/video-dev/hls.js/#getting-started-with-development&quot;&gt;getting started&lt;/a&gt; instructions.&lt;/p&gt;

&lt;p&gt;The code is on &lt;a href=&quot;https://github.com/iamgmujtaba/hls-server&quot;&gt;GitHub&lt;/a&gt;. Open an issue there if you run into problems.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Step-by-step guide to an HLS streaming server on Windows 10/11 with IIS and FFmpeg: enable IIS and CORS, add the .m3u8 MIME type, segment video, and test playback.</summary>
      
      
        
          <category term="HLS" />
        
          <category term="HTTP Live Streaming" />
        
          <category term="IIS" />
        
          <category term="Adaptive Streaming" />
        
          <category term="FFmpeg" />
        
          <category term="Windows" />
        
          <category term="Video Streaming" />
        
      
    </entry>
  
    <entry>
      <title type="html">How to Set Up an MPEG-DASH Streaming Server on Windows (IIS + FFmpeg)</title>
      <link href="https://gmujtaba.com/blog/configure-dash-server-windows/" rel="alternate" type="text/html" title="How to Set Up an MPEG-DASH Streaming Server on Windows (IIS + FFmpeg)"/>
      <published>2024-02-09T13:00:00+00:00</published>
      <updated>2024-02-09T13:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/configure-dash-server-windows</id>
      <content type="html">&lt;h2 id=&quot;what-this-guide-sets-up&quot;&gt;What this guide sets up&lt;/h2&gt;

&lt;p&gt;MPEG-DASH (Dynamic Adaptive Streaming over HTTP) splits a video into short segments at several quality levels and lists them in a manifest file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.mpd&lt;/code&gt;). The player picks the quality that fits the viewer’s connection and switches as it changes. Because everything is plain HTTP, any web server can host it.&lt;/p&gt;

&lt;p&gt;This guide sets up a DASH server on Windows 10/11 using IIS (the web server built into Windows) and FFmpeg. At the end you’ll stream a test video to VLC. If you need HLS instead, see my &lt;a href=&quot;/blog/configure-hls-server-on-windows/&quot;&gt;HLS server guide&lt;/a&gt;; the IIS steps are almost the same.&lt;/p&gt;

&lt;h2 id=&quot;step-1-turn-on-iis&quot;&gt;Step 1: Turn on IIS&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Press &lt;strong&gt;Windows Key + S&lt;/strong&gt; and search for &lt;strong&gt;Turn Windows features on or off&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Tick &lt;strong&gt;Internet Information Services&lt;/strong&gt; and wait for it to install, then close the window.&lt;/li&gt;
  &lt;li&gt;Open a browser and go to &lt;strong&gt;127.0.0.1&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;You should see the IIS welcome page. If not, restart your computer.&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/iis_home.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/iis_home.jpg&quot; alt=&quot;How to Set Up an MPEG-DASH Streaming Server on Windows (IIS + FFmpeg)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;step-2-change-the-web-root-optional&quot;&gt;Step 2: Change the web root (optional)&lt;/h2&gt;

&lt;p&gt;By default IIS serves files from &lt;strong&gt;C:\inetpub\wwwroot\&lt;/strong&gt;. Skip this step if that’s fine.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open &lt;strong&gt;IIS Manager&lt;/strong&gt; (Windows Key + S, type &lt;strong&gt;IIS&lt;/strong&gt;).&lt;/li&gt;
  &lt;li&gt;Right-click &lt;strong&gt;Default Web Site&lt;/strong&gt;, then choose &lt;strong&gt;Manage Website&lt;/strong&gt; &amp;gt; &lt;strong&gt;Advanced Settings&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Physical Path&lt;/strong&gt; and pick a different folder.&lt;/li&gt;
  &lt;li&gt;Make sure IIS has permission to read that folder.&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/iis_path.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/iis_path.jpg&quot; alt=&quot;How to Set Up an MPEG-DASH Streaming Server on Windows (IIS + FFmpeg)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;step-3-enable-cors&quot;&gt;Step 3: Enable CORS&lt;/h2&gt;

&lt;p&gt;Browser-based players load the stream from another origin, so the server must allow cross-origin requests (CORS).&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open &lt;strong&gt;IIS Manager&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Select &lt;strong&gt;Default Web Site&lt;/strong&gt; and double-click &lt;strong&gt;HTTP Response Headers&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;. Enter &lt;strong&gt;Access-Control-Allow-Origin&lt;/strong&gt; as the name and &lt;strong&gt;*&lt;/strong&gt; as the value.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt; again. Enter &lt;strong&gt;Access-Control-Allow-Headers&lt;/strong&gt; as the name and &lt;strong&gt;Range&lt;/strong&gt; as the value.&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/hrs_page.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/hrs_page.jpg&quot; alt=&quot;How to Set Up an MPEG-DASH Streaming Server on Windows (IIS + FFmpeg)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;step-4-add-the-dash-mime-types&quot;&gt;Step 4: Add the DASH MIME types&lt;/h2&gt;

&lt;p&gt;IIS won’t serve file types it doesn’t recognize, and it doesn’t know the DASH extensions by default.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;In IIS Manager, click your server and double-click &lt;strong&gt;MIME Types&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Add &lt;strong&gt;.mpd&lt;/strong&gt; with MIME type &lt;strong&gt;application/dash+xml&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Add &lt;strong&gt;.m4s&lt;/strong&gt; with MIME type &lt;strong&gt;video/mp4&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/mime_dash.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/mime_dash.jpg&quot; alt=&quot;How to Set Up an MPEG-DASH Streaming Server on Windows (IIS + FFmpeg)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;step-5-install-ffmpeg&quot;&gt;Step 5: Install FFmpeg&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Download a Windows build of FFmpeg from &lt;a href=&quot;https://www.ffmpeg.org/download.html#build-windows&quot;&gt;ffmpeg.org&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Extract it to &lt;strong&gt;C:\ffmpeg&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Copy the path of the &lt;strong&gt;bin&lt;/strong&gt; folder (&lt;strong&gt;C:\ffmpeg\bin&lt;/strong&gt;).&lt;/li&gt;
  &lt;li&gt;Open &lt;strong&gt;System Properties&lt;/strong&gt; &amp;gt; &lt;strong&gt;Advanced System Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Environment Variables&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Under System variables, select &lt;strong&gt;Path&lt;/strong&gt; and click &lt;strong&gt;Edit&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;New&lt;/strong&gt;, paste the path, and click OK.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To check, open a new Command Prompt and type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt;. If it prints version information, it’s installed.&lt;/p&gt;

&lt;h2 id=&quot;step-6-create-the-dash-segments&quot;&gt;Step 6: Create the DASH segments&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Download the &lt;a href=&quot;https://download.blender.org/demo/movies/BBB/bbb_sunflower_1080p_30fps_normal.mp4.zip&quot;&gt;Big Buck Bunny&lt;/a&gt; sample video.&lt;/li&gt;
  &lt;li&gt;Rename it to &lt;strong&gt;input.mp4&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;In that folder, run:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ffmpeg &lt;span class=&quot;nt&quot;&gt;-re&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; input.mp4 &lt;span class=&quot;nt&quot;&gt;-map&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;-map&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;:a copy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;:v libx264 &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt;:v:0 800k &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt;:v:1 300k &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;:v:1 320x170 &lt;span class=&quot;nt&quot;&gt;-profile&lt;/span&gt;:v:1 baseline &lt;span class=&quot;nt&quot;&gt;-profile&lt;/span&gt;:v:0 main &lt;span class=&quot;nt&quot;&gt;-bf&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;-keyint_min&lt;/span&gt; 120 &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 120 &lt;span class=&quot;nt&quot;&gt;-sc_threshold&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;-b_strategy&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;-ar&lt;/span&gt;:a:1 22050 &lt;span class=&quot;nt&quot;&gt;-use_timeline&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;-use_template&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;-window_size&lt;/span&gt; 5 &lt;span class=&quot;nt&quot;&gt;-adaptation_sets&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;id=0,streams=v id=1,streams=a&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; dash out.mpd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This creates two video qualities (800 kbps and 300 kbps), the audio, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out.mpd&lt;/code&gt; manifest.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a folder named &lt;strong&gt;bbb_dash&lt;/strong&gt; in your web root (for example &lt;strong&gt;C:\inetpub\wwwroot\bbb_dash&lt;/strong&gt;). Copy every generated file into it, but not &lt;strong&gt;input.mp4&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To convert several videos at once, use my script:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iamgmujtaba/dash-server.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then run:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python .&lt;span class=&quot;se&quot;&gt;\m&lt;/span&gt;ain.py &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; .&lt;span class=&quot;se&quot;&gt;\i&lt;/span&gt;nput&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; .&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;utput&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-7-test-playback&quot;&gt;Step 7: Test playback&lt;/h2&gt;

&lt;h3 id=&quot;find-your-ip-address&quot;&gt;Find your IP address&lt;/h3&gt;

&lt;p&gt;Open Command Prompt and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipconfig&lt;/code&gt;. Note the &lt;strong&gt;IPv4 Address&lt;/strong&gt; (something like 192.168.x.x).&lt;/p&gt;

&lt;h3 id=&quot;play-in-vlc&quot;&gt;Play in VLC&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Install &lt;a href=&quot;https://www.videolan.org/vlc/download-windows.html&quot;&gt;VLC&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Press &lt;strong&gt;Ctrl+N&lt;/strong&gt; to open a network stream.&lt;/li&gt;
  &lt;li&gt;Enter &lt;strong&gt;http://192.XXX.XXX.XXX/bbb_dash/out.mpd&lt;/strong&gt;, using your own IP address.&lt;/li&gt;
  &lt;li&gt;Press &lt;strong&gt;Play&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the video plays, your DASH server works.&lt;/p&gt;

&lt;h3 id=&quot;play-in-a-browser-ubuntu-jetson-or-any-device&quot;&gt;Play in a browser (Ubuntu, Jetson, or any device)&lt;/h3&gt;

&lt;p&gt;For a web player, use &lt;a href=&quot;https://github.com/Dash-Industry-Forum/dash.js&quot;&gt;dash.js&lt;/a&gt; and follow its &lt;a href=&quot;https://github.com/Dash-Industry-Forum/dash.js#getting-started&quot;&gt;getting started&lt;/a&gt; instructions.&lt;/p&gt;

&lt;p&gt;The code is on &lt;a href=&quot;https://github.com/iamgmujtaba/dash-server&quot;&gt;GitHub&lt;/a&gt;. Open an issue there if you run into problems.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Step-by-step MPEG-DASH server on Windows 10/11 with IIS and FFmpeg: enable IIS and CORS, add the .mpd and .m4s MIME types, create DASH segments, and test playback.</summary>
      
      
        
          <category term="DASH" />
        
          <category term="MPEG-DASH" />
        
          <category term="IIS" />
        
          <category term="Adaptive Streaming" />
        
          <category term="FFmpeg" />
        
          <category term="Windows" />
        
          <category term="Video Streaming" />
        
      
    </entry>
  
    <entry>
      <title type="html">Install FFmpeg on NVIDIA Jetson with Hardware Encoding (jetson-ffmpeg, h264_nvmpi)</title>
      <link href="https://gmujtaba.com/blog/ffmpeg-installation-jetson-tx2/" rel="alternate" type="text/html" title="Install FFmpeg on NVIDIA Jetson with Hardware Encoding (jetson-ffmpeg, h264_nvmpi)"/>
      <published>2023-12-15T13:00:00+00:00</published>
      <updated>2023-12-15T13:00:00+00:00</updated>
      <id>https://gmujtaba.com/blog/ffmpeg-installation-jetson-tx2</id>
      <content type="html">&lt;!-- Figure include for blog posts --&gt;

&lt;figure class=&quot;figure text-center img-fluid rounded z-depth-1&quot;&gt;
  &lt;picture&gt;&lt;source srcset=&quot;/assets/img/blog/ffmpeg_jetson.webp&quot; type=&quot;image/webp&quot; /&gt;&lt;img src=&quot;/assets/img/blog/ffmpeg_jetson.jpg&quot; alt=&quot;Install FFmpeg on NVIDIA Jetson with Hardware Encoding (jetson-ffmpeg, h264_nvmpi)&quot; class=&quot;figure-img img-fluid rounded&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; /&gt;&lt;/picture&gt;

  
&lt;/figure&gt;

&lt;h2 id=&quot;why-build-ffmpeg-yourself-on-a-jetson&quot;&gt;Why build FFmpeg yourself on a Jetson&lt;/h2&gt;

&lt;p&gt;NVIDIA doesn’t ship an FFmpeg build that uses the Jetson’s hardware video encoder and decoder. The stock FFmpeg from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; runs everything on the CPU, which is slow on a Jetson. The open-source &lt;a href=&quot;https://github.com/jocover/jetson-ffmpeg&quot;&gt;jetson-ffmpeg&lt;/a&gt; project adds an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvmpi&lt;/code&gt; codec that talks to the Jetson’s hardware. Once it’s built in, you get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h264_nvmpi&lt;/code&gt; for fast H.264 encoding and decoding.&lt;/p&gt;

&lt;p&gt;I tested these steps on a Jetson TX2 with JetPack 4.3.&lt;/p&gt;

&lt;h2 id=&quot;step-1-install-the-build-dependencies&quot;&gt;Step 1: Install the build dependencies&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt build-dep ffmpeg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you get the error &lt;em&gt;“You must put some ‘source’ URIs in your sources.list”&lt;/em&gt;, source repositories are turned off. Open the sources list:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Uncomment every line that starts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deb-src&lt;/code&gt;, save (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:wq&lt;/code&gt;), then try again:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt update
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt build-dep ffmpeg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-2-build-the-jetson-ffmpeg-library&quot;&gt;Step 2: Build the jetson-ffmpeg library&lt;/h2&gt;

&lt;p&gt;This builds the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvmpi&lt;/code&gt; library that FFmpeg will use to reach the hardware encoder and decoder:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone https://github.com/jocover/jetson-ffmpeg.git
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;jetson-ffmpeg
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;build
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;build
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cmake ..
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;ldconfig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-3-patch-and-build-ffmpeg&quot;&gt;Step 3: Patch and build FFmpeg&lt;/h2&gt;

&lt;p&gt;Download FFmpeg 4.2, apply the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvmpi&lt;/code&gt; patch, and build it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--enable-nvmpi&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone git://source.ffmpeg.org/ffmpeg.git &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; release/4.2 &lt;span class=&quot;nt&quot;&gt;--depth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ffmpeg
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;wget https://github.com/jocover/jetson-ffmpeg/raw/master/ffmpeg_nvmpi.patch
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git apply ffmpeg_nvmpi.patch
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./configure &lt;span class=&quot;nt&quot;&gt;--enable-nvmpi&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make &lt;span class=&quot;nt&quot;&gt;-j4&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;tee &lt;/span&gt;make.log
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The build takes a while on the TX2. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make.log&lt;/code&gt; keeps the output in case something fails.&lt;/p&gt;

&lt;h2 id=&quot;step-4-check-that-h264_nvmpi-is-available&quot;&gt;Step 4: Check that h264_nvmpi is available&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;which ffmpeg
/usr/local/bin/ffmpeg
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ffmpeg &lt;span class=&quot;nt&quot;&gt;-codecs&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;264
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h264_nvmpi&lt;/code&gt; listed as both a decoder and an encoder:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ffmpeg version 3eedf15 Copyright &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 2000-2019 the FFmpeg developers
  built with gcc 7 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Ubuntu/Linaro 7.5.0-3ubuntu1~18.04&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  configuration: &lt;span class=&quot;nt&quot;&gt;--enable-nvmpi&lt;/span&gt;
  libavutil 56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
 DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;decoders: h264 h264_v4l2m2m h264_nvmpi &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;encoders: h264_nvmpi h264_v4l2m2m h264_vaapi &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;which ffmpeg&lt;/code&gt; points somewhere other than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin/ffmpeg&lt;/code&gt;, you’re still running the old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; version. Remove it or call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin/ffmpeg&lt;/code&gt; directly.&lt;/p&gt;

&lt;h2 id=&quot;using-the-hardware-encoder&quot;&gt;Using the hardware encoder&lt;/h2&gt;

&lt;p&gt;To encode with the hardware, pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h264_nvmpi&lt;/code&gt; as the video codec:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ffmpeg &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; input.mp4 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;:v h264_nvmpi output.mp4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I first published this guide &lt;a href=&quot;https://iamgmujtaba.medium.com/ffmpegs-installation-on-the-jetson-tx2-66b5a3f21d02&quot;&gt;on Medium&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
        <name>Ghulam Mujtaba</name>
        <email>gmujtaba@ieee.org</email>
      </author>
      
      <summary type="html">Build FFmpeg with jetson-ffmpeg (NVMPI) on Jetson TX2 / JetPack 4.3 for hardware H.264 encoding and decoding, then verify the h264_nvmpi encoder and decoder.</summary>
      
      
        
          <category term="FFmpeg" />
        
          <category term="NVIDIA Jetson TX2" />
        
          <category term="Hardware Acceleration" />
        
          <category term="Video Processing" />
        
          <category term="Edge Computing" />
        
          <category term="NVENC" />
        
          <category term="NVDEC" />
        
      
    </entry>
  
</feed>
