<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Chanin Nantasenamat on Medium]]></title>
        <description><![CDATA[Stories by Chanin Nantasenamat on Medium]]></description>
        <link>https://medium.com/@data-professor?source=rss-f94b47c3cfca------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*Rya_n9Xr32DLR1RgrKv1_g.png</url>
            <title>Stories by Chanin Nantasenamat on Medium</title>
            <link>https://medium.com/@data-professor?source=rss-f94b47c3cfca------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 01:32:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@data-professor/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How Agentic Engineering Changed the Way I Build Streamlit Apps]]></title>
            <link>https://blog.streamlit.io/how-agentic-engineering-changed-the-way-i-build-streamlit-apps-27bb1c95134e?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/27bb1c95134e</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[streamlit]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[agentic-ai]]></category>
            <category><![CDATA[ai-applications]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Tue, 31 Mar 2026 03:52:46 GMT</pubDate>
            <atom:updated>2026-03-31T03:52:46.198Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Pj-wTC-bGtcbKWHqxpnhCw.png" /></figure><p>When you’re building tutorial content, good data is hard to come by. You need something real enough to tell a story, rich enough to be interesting, and relevant enough that developers actually care.</p><p>So when Joe Reis had just published his <a href="https://joereis.github.io/practical_data_data_eng_survey/">2026 State of Data Engineering</a> report (<em>i.e.</em> 1,136 survey responses from data engineering practitioners across the globe) I knew I had something worth building on. Columns on everything from orchestration tools to AI adoption to the bottlenecks keeping teams up at night.</p><p>I also had an idea: turn this static CSV into an interactive data exploration app where anyone could slice the data by role, industry, region, and org size. Not a single dashboard page, but a full multipage Streamlit app with distinct analysis angles spanning personas, tech stacks, AI adoption, organizational dynamics, pain points, education gaps, and practitioner voices.</p><p>A project like this would normally take a few months to build out. Back in 2023, I built the <a href="https://state-of-llm.streamlit.app/">State of LLM Apps 2023</a> in about 3 months.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GW-Ad_u4kx6Et8FZtXVwaA.png" /></figure><p>With agentic engineering in Cortex Code, using custom agent skills, an AGENTS.md file with app design patterns, and an app.md planning doc for ideation, I built a similar app over the course of about a week, working in focused sessions between other tasks. That&#39;s 12 weeks compressed into a week! Here&#39;s how that played out.</p><h3>From vibe coding to agentic engineering</h3><p>But before we dive into the specifics, let’s take a moment to explore the shift from vibe coding to agentic engineering.</p><p>“AI-assisted coding” is the catch-all term for any coding activity that uses AI. It spans everything from vibe coding to agentic engineering and whatever comes next. Within that spectrum, the approaches differ sharply in how much control you hand over and how much structure you bring.</p><p>In early 2025, Andrej Karpathy coined <a href="https://x.com/karpathy/status/1886192184808149383">“vibe coding”</a> to describe the free-form, prompt-driven way people were generating software with AI: type a prompt, accept the output, “forget that the code even exists.” It captured the excitement of the moment. But for anything beyond a quick prototype, vibes alone produce fragile apps that need heavy rework. You end up spending more time debugging AI-generated code than you saved writing it.</p><p>A year later, Karpathy introduced a new term: <a href="https://x.com/karpathy/status/2019137879310836075">agentic engineering</a>. The distinction matters. “Agentic,” he writes, “because the new default is that you are not writing the code directly 99% of the time, you are orchestrating agents who do and acting as oversight. Engineering to emphasize that there is an art &amp; science and expertise to it. It’s something you can learn and become better at, with its own depth of a different kind.”</p><p>Simon Willison builds on this in his <a href="https://simonwillison.net/guides/agentic-engineering-patterns/what-is-agentic-engineering/">Agentic Engineering Patterns</a> guide: you define a goal, the coding agent generates and executes code in a loop until that goal is met, and your job is figuring out <em>what</em> to build, navigating tradeoffs, verifying results, and updating instructions so the agent learns from past mistakes. Vibe coding, Willison argues, is more useful in its original definition as a term for “unreviewed, prototype-quality LLM-generated code” rather than a catch-all for AI-assisted development.</p><p>This project was agentic engineering, not vibe coding.</p><p>Here’s how:</p><ul><li>The app.md planning doc defined the goals.</li><li>The AGENTS.md file and a custom streamlit-design-patterns skill provided the constraints and patterns.</li><li>I reviewed every page the agent produced, caught edge cases it missed, and refined the instructions for the next session.</li><li>The agent wrote the code.</li><li>I drove the architecture, the editorial decisions, and the quality bar.</li></ul><h3>Start with the story, not the code</h3><p>The instinct with vibe coding is to jump straight into prompting: “build me a dashboard.” I’ve learned the hard way that this produces generic apps that need heavy rework through several iterations.</p><p>Instead, I started by writing a planning document. Not code. A markdown file called app.md that laid out every page I wanted, what data each page needed, and the story each page should tell. I used the AI to help brainstorm page ideas and analysis angles, then curated and refined the best ones into the plan. The AI Paradox page, for example, needed to answer one question: <em>&quot;82% of practitioners use AI daily, but only 10% have it embedded organizationally. What explains the gap?&quot;</em></p><p>I spent nearly a day on planning alone. But every session after that was faster because of it.</p><h4>Excerpt from app.md (plan before code)</h4><p>The planning file lived in an app.md file and was written as a full build specification file (purpose, audience, repo layout, and navigation) before any implementation of the app. It opened like this:</p><pre># State of Data Engineering 2026 - Interactive Explorer App<br><br>An app building plan for creating an interactive Streamlit application to explore the 2026 State of Data Engineering survey data, following BioCurator design patterns.<br><br>---<br><br>## 1. App Overview<br><br>### Purpose<br>Transform static survey findings into an interactive exploration tool where users can discover insights relevant to their specific role, industry, and technology stack.<br><br>### Target Users<br>- Data Engineers benchmarking their organization<br>- Data Leaders making strategic decisions<br>- Recruiters understanding the talent landscape<br>- Vendors understanding market adoption<br><br>---<br><br>## 2. App Structure<br><br>state-of-engineering-app/<br>├── app.py                          # Main entry point (navigation + session state)<br>├── data_utils.py                   # Shared data loading, filtering, caching<br>├── chart_utils.py                  # Reusable chart components<br>├── pages/<br>│   ├── home.py                     # Overview dashboard with key stats<br>│   │<br>│   │   # Persona &amp; Benchmarking<br>│   ├── persona_matcher.py          # Find Your Tribe Persona Matcher<br>│   ├── regional_benchmark.py       # Regional Benchmark Tool<br>│   ├── solo_practitioner.py        # Solo Practitioner Experience<br>│   │<br>│   │   # Technology Stack &amp; Architecture  <br>│   ├── stack_explorer.py           # Technology Stack Explorer<br>│   ...                             # (additional page modules in the full doc)</pre><p>The full app.md went on to spell out navigation (st.navigation groupings), session state, sidebar filters, per-page specs, phased implementation order, and widget–chart pairings—so every later prompt could point at a single source of truth.</p><h3>Architecture: shared utilities, independent pages</h3><p>With the plan in hand, I asked Cortex Code to build the foundation first: a data_utils.py for loading and filtering survey data, and a chart_utils.py with reusable chart functions including donut charts, lollipop charts, diverging bars, Sankey diagrams, radar charts, and heatmaps.</p><p>This was a deliberate choice. Every page imports from the same two utility files, which means consistent styling, consistent data handling, and zero copy-paste drift across 17 pages. When I later tweaked the color palette from defaults to a custom rainbow scheme (#8B5CF6, #3B82F6, #10B981, #FACC15, #F59E0B, #EF4444), every chart across every page updated at once.</p><p>The main app.py handles navigation using st.navigation() with grouped sections (Persona, Tech Stack, AI Adoption, Organization, Pain Points, Skills) and a sidebar with global filters. Every page reads from get_filtered_df(), so when you filter to &quot;Finance, 1000+ employees&quot; in the sidebar, all 17 pages reflect that slice.</p><h3>Building pages with agent skills</h3><p>Once the foundation was solid, I started requesting pages in focused sessions, typically knocking out two or three pages per sitting. This is where the agentic engineering approach really paid off. I had a custom streamlit-design-patterns skill loaded into Cortex Code and an AGENTS.md file encoding app design patterns (layout conventions, charting preferences, Streamlit idioms). The agent didn&#39;t start from scratch each time; it worked from established patterns.</p><p>Each prompt followed a pattern:</p><p><em>Build the AI Paradox page. It should show personal AI usage vs organizational adoption as side-by-side donut charts, then filter to the “gap cohort” (daily AI users with low org adoption) and show their bottlenecks and industries. Add a select slider that lets users explore characteristics at each adoption level. End with a segment comparison that shows the personal-vs-org gap by industry, role, or region.</em></p><p>Cortex Code would generate the page, I’d review the output, and we’d iterate. The typical cycle was: generate, run, spot an issue, fix, move on. Most pages took a few rounds of iterations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IzDvJ149xVZY1j122ku9BQ.png" /></figure><p>Some patterns I noticed working well:</p><p><strong>Giving the AI the data schema up front.</strong> The survey had columns like ai_usage_frequency, ai_adoption, biggest_bottleneck, and modeling_pain_points (comma-separated multi-select). When I included these column names and their possible values in my prompts, the generated code was far more accurate.</p><p><strong>Requesting specific chart types.</strong> “Use a lollipop chart for bottlenecks” produced better results than “visualize the bottlenecks.” The AI knew exactly which chart_utils function to call.</p><p><strong>Adding insight captions programmatically.</strong> Each chart section ends with a dynamically generated st.caption() that highlights the top findings. For example: &quot;Legacy/Tech Debt leads at 24%, followed by Lack of leadership direction at 21%.&quot; These aren&#39;t hardcoded strings. They&#39;re dynamically computed from the filtered data, so they update as users apply filters.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XD0sgDPt0QouWUMzaBnFMw.png" /></figure><h3>Tricky parts</h3><p>Not everything was smooth. Here’s a few lessons from the rough edges:</p><p><strong>Multi-select columns need preprocessing.</strong> The modeling_pain_points column contained comma-separated values like &quot;Pressure to move fast, Lack of ownership.&quot; I needed an explode_multiselect() utility to properly count and cross-tabulate these values. The AI initially tried to treat them as single categories.</p><p><strong>Global filter state management was fiddly.</strong> I wanted an “All Roles” option that auto-deselects when you pick specific roles, and auto-reselects when you clear everything. This required a custom init_multiselect_state() function that tracks previous selections via a shadow key in st.session_state. Getting this right took the most back-and-forth.</p><p><strong>Altair’s </strong><strong>labelLimit defaults truncate long labels.</strong> Survey responses like &quot;Lack of leadership direction / unclear business strategy&quot; would get cut off. Setting axis=alt.Axis(labelLimit=0) on every Y axis became a global pattern I enforced across all pages.</p><h3>What I’d do differently</h3><p>If I were starting over, I’d add the about.py page first instead of last. It provides context that helps users understand the data source, methodology, and limitations. Building it last meant I had to go back and verify all my assumptions about column meanings.</p><p>I’d also create a FILTERS.md or constants file defining all the ordered category lists (org sizes from &quot;&lt; 50 employees&quot; to &quot;10,000+&quot;, AI adoption from &quot;No meaningful adoption&quot; to &quot;AI embedded&quot;) in one place. I ended up defining these in data_utils.py, but having them as a separate reference would have made prompts cleaner.</p><h3>Result</h3><p>The final app has 17 interactive pages, 20 Python files, a shared color system, global sidebar filters, and dynamically generated insight text. Every chart responds to the global filters. The persona matcher computes similarity scores across four dimensions. The firefighting predictor cross-tabulates modeling approach, orchestration, and org size against firefighting rates.</p><p>Here’s what the completed app looked like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*E99EB66HcWArIUlpSY94RQ.gif" /></figure><p>All from one CSV file, one planning document, and about a week of iterative prompting sessions using the agentic engineering workflow. Essentially, the provided prompts provided the intent that the agent skills used to guide it during the coding phase. This took us to a reasonably good starting point that required a few more iterations to fine-tune the app.</p><p>You can see the <a href="https://www.linkedin.com/feed/update/urn:li:ugcPost:7428522366877716480">LinkedIn video walkthrough</a> showing the app in action.</p><p><a href="https://www.linkedin.com/feed/update/urn:li:ugcPost:7428522366877716480/">2026 State of Data Engineering Survey Interactive Explorer | Chanin Nantasenamat posted on the topic | LinkedIn</a></p><h3>Takeaway</h3><p>Agentic engineering isn’t vibe coding. As Karpathy puts it, you’re orchestrating agents and acting as oversight, not hoping a single prompt produces something usable. As Willison describes, you define goals, verify results, and update your instructions so the agent improves over time. In practice, that meant giving the AI structured context to work from.</p><p>An app.md for ideation, an AGENTS.md for design patterns, custom skills for domain knowledge, and reusable utility modules for consistency. I handled the editorial decisions, including what story each page tells, what data supports it, and what the user should take away. The agent handled the execution, grounded in patterns I&#39;d defined.</p><p>The planning document was worth more than any individual prompt. If you’re building something beyond a single-page prototype, invest in the context layer first. Your agent will build better software because of it.</p><h3>Conclusion</h3><p>The week-long build only worked because the unglamorous decisions (<em>i.e.</em> what to call each page, how files fit together, which chart library to standardize on) were settled in app.md before the first serious line of app code is written.</p><p>The product was not something the agent dreamed up, it was the implementation of a plan that I had already thought through on paper. Early on, a workflow like this can feel sluggish: you spend time on markdown, skills, and guardrails instead of visible UI. Treat that as front-loaded cost, not waste. What you buy is alignment: page seventeen still feels like the same app as page one, and a structure you can navigate and debug on your own, long after the session ends.</p><p>This is how I build Streamlit apps in the age of agentic AI. How do you build Streamlit apps?</p><p>Happy Streamlit-ing! 🎈</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=27bb1c95134e" width="1" height="1" alt=""><hr><p><a href="https://blog.streamlit.io/how-agentic-engineering-changed-the-way-i-build-streamlit-apps-27bb1c95134e">How Agentic Engineering Changed the Way I Build Streamlit Apps</a> was originally published in <a href="https://blog.streamlit.io/">Streamlit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vibe code Streamlit apps with AI using AGENTS.md]]></title>
            <link>https://blog.streamlit.io/vibe-code-streamlit-apps-with-ai-using-agents-md-04b7480f754e?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/04b7480f754e</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[streamlit]]></category>
            <category><![CDATA[ai-applications]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Wed, 14 Jan 2026 15:02:06 GMT</pubDate>
            <atom:updated>2026-01-14T15:02:06.450Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LQj3YkCaJBmHeS2xhnAisQ.png" /></figure><h3>Introduction</h3><p>If you’ve ever worked with AI coding assistants like Cursor, GitHub Copilot, or Claude Code, you know they can be incredibly powerful, but also inconsistent. Sometimes it nails your code style, sometimes it forgets everything you’ve established.</p><p>This is where <a href="https://agents.md/">AGENTS.md</a> comes in. It’s an open standard for guiding AI coding agents. Think of it as a README for AI, a dedicated file that provides context, conventions, and instructions that help AI assistants work effectively on your coding projects.</p><p>In this article, I’ll show you how to use this AGENTS.md file to build Streamlit apps across all deployment targets: local development, Streamlit Community Cloud, and Streamlit in Snowflake (SiS).</p><h3>What is AGENTS.md?</h3><p>AGENTS.md is a simple, open format adopted by over 60,000 open-source projects, including repositories from OpenAI, Apache, and Google. It emerged from collaborative efforts across the AI software development ecosystem.</p><p>The key insight is that README.md files are for humans, while AGENTS.md is for AI agents. It contains the detailed context that AI coding assistants need: build commands, code conventions, testing patterns, and domain-specific knowledge.</p><h3>Where These Patterns Come From</h3><p>The Streamlit AGENTS.md isn’t theoretical. It’s built from real-world experience:</p><ul><li><a href="https://30daysofai.streamlit.app/"><strong>30 Days of AI</strong></a>: A 30-day learning series teaching AI app development with Streamlit and Snowflake Cortex (<a href="https://github.com/streamlit/30daysofai">GitHub</a>). Each day’s lesson contributed battle-tested patterns for chatbots, RAG systems, streaming responses, and agent orchestration.</li><li><strong>Experience in Streamlit Development</strong>: Patterns refined from building dozens of Streamlit applications over 2024–2025, including data dashboards, cheminformatics tools, ML apps, and enterprise applications deployed to Streamlit in Snowflake.</li></ul><p>Every pattern in this AGENTS.md has been validated in production. The AI_COMPLETE function, the universal connection pattern, the streaming chat interface: all emerged from solving real-world problems across different deployment environments.</p><h3>Why This Works</h3><p>The AGENTS.md approach works because:</p><ol><li><strong>Minimal friction</strong>: One file reference, a few questions, complete app</li><li><strong>Smart defaults</strong>: Caching, error handling, and UI components are inferred</li><li><strong>Environment-aware</strong>: Automatically handles SiS vs Community Cloud differences</li><li><strong>Complete output</strong>: Every app includes app.py, requirements.txt, README.md</li><li><strong>Consistent patterns</strong>: Same proven code patterns every time</li></ol><h3>Download AGENTS.md</h3><p>To proceed further, download the Streamlit AGENTS.md file from this <a href="https://github.com/dataprofessor/streamlit/blob/main/AGENTS.md">GitHub repo</a>:</p><p><a href="https://github.com/dataprofessor/streamlit/blob/main/AGENTS.md">streamlit/AGENTS.md at main · dataprofessor/streamlit</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XY13xDtrD0jvv0lfWpKDTA.png" /></figure><h3>Getting Started in Using Streamlit AGENTS.md</h3><p>The Streamlit AGENTS.md supports two modes of operation, making it effortless to get started.</p><p>To start, <a href="https://github.com/dataprofessor/streamlit/blob/main/AGENTS.md">download</a> and copy the Streamlit <a href="https://github.com/dataprofessor/streamlit/blob/main/AGENTS.md">AGENTS.md</a> to your project.</p><h4>Mode 1: Quick Start with Instructions</h4><p>If you know what you want, just tell the AI:</p><pre>@AGENTS.md build me a chatbot using Snowflake Cortex</pre><p>Here’s how it looks like in Cursor:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*m_1_R_HoFNopBtc_v0VopA.png" /></figure><p>In a nutshell, the AI will:</p><ul><li>Use your instruction as the starting point</li><li>Infer reasonable defaults</li><li>Ask only 1–2 clarifying questions if critical info is missing</li><li>Build the complete app with all files</li></ul><p>Here’s the first question and our corresponding answer:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3IRU6svPLdsghoJvE-Z-tA.png" /></figure><p>After a few moments, the AI is getting to work:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DJw4n-8eW_cul4cD6OeL2A.png" /></figure><p>After about a minute or so, completed app is completed and the app structure and its core features are summarized:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*49UJyuFpAlwbl8Lke5A0ag.png" /></figure><p>This is followed by instructions on how to run the app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ulXWy1MA6hRs-ATaD225oA.png" /></figure><p>And it doesn’t stop there, you can ask follow-up questions to assist you in understanding the created app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NKjzrjDDEHpgcwHUSapKdg.png" /></figure><p>Or you can also continue to vibe code and make incremental improvements to the app.</p><h4>Mode 2: Guided Sequential Questions</h4><p>If you’re not sure what you need, just reference the file:</p><pre>@AGENTS.md</pre><p>Here’s what it looks like in Cursor:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dmpXNIvU4cC9ctWXDGyeKA.png" /></figure><p>The AI will guide you through questions <strong>one at a time</strong>:</p><ol><li><strong>“What would you like to build?”</strong> → chatbot, dashboard, data tool</li><li><strong>“Where will it run?”</strong> → local, Community Cloud, Snowflake</li><li><strong>“What’s your data source?”</strong> → CSV, Snowflake, APIs</li><li><strong>“Which LLM?”</strong> (only if you mentioned AI) → Cortex or OpenAI</li></ol><p>Then it builds, inferring UI components from app type and adding caching automatically.</p><p>Here’s our first question:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kYnUH6Nl7K3oZZx7-cSZxQ.png" /></figure><p>The second question:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BW6OuOBQjAxw5sxm6hE6YA.png" /></figure><p>The third question:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*m4SUVPowl9c6TGoQUcEYbw.png" /></figure><p>And that’s all, it’ll proceed to building the app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ouDTYraIpBQYJE0Mlmtkvg.png" /></figure><p>Once it’s completed, we get a summary of what’s been built:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tgMC5rdUy3-8jaEYbunXzA.png" /></figure><p>Along with instructions on deployment:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7YUndjbXjICnpo7o3d6AiA.png" /></figure><h3>What Gets Created</h3><p>When you build an app with the AGENTS.md, you get a complete, deployment-ready project:</p><pre>my_app/<br>├── app.py                      # Main application<br>├── requirements.txt            # Dependencies with versions<br>├── README.md                   # GitHub-ready documentation<br>└── .streamlit/<br>    └── secrets.toml.example    # Credentials template (if needed)</pre><h3>The README.md</h3><p>Every app includes a README with:</p><ul><li><strong>TLDR</strong>: One sentence describing the app</li><li><strong>Features</strong>: Bullet list of capabilities</li><li><strong>Run Locally</strong>: Step-by-step commands</li><li><strong>Deploy to Community Cloud</strong>: 5-step guide</li><li><strong>Deploy to SiS</strong>: 3-step guide</li></ul><p>No more creating documentation manually!</p><h3>Example Apps</h3><p>Two complete example apps were built using the AGENTS.md guided flow. Both are available in the examples/ folder.</p><h4>Example 1: Chatbot</h4><p>A conversational AI chatbot powered by Snowflake Cortex.</p><p><strong>The Q&amp;A Flow:</strong></p><p>Here’s the questions and answers:</p><ul><li><strong>What would you like to build?</strong> Simple chatbot</li><li><strong>Where will it run?</strong> Community Cloud</li><li><strong>Which LLM?</strong> Cortex</li></ul><p><strong>What Got Created:</strong></p><pre>examples/chatbot_app/<br>├── app.py              # Chat interface with streaming<br>├── requirements.txt    # streamlit, snowflake-snowpark-python<br>└── README.md           # Deployment instructions</pre><p><strong>Features:</strong> Chat interface, model selector (Claude/Llama/Mistral), conversation history, response caching.</p><p>A few questions. Complete app. Ready to deploy.</p><h4>Example 2: Stock Dashboard</h4><p>A real-time stock dashboard using the Yahoo Finance data.</p><p><strong>The Q&amp;A Flow:</strong></p><p>Here’s the questions and answers:</p><ul><li><strong>What would you like to build?</strong> Dashboard</li><li><strong>Where will it run?</strong> Snowflake</li><li><strong>What’s your data source?</strong> yfinance</li></ul><p><strong>What Got Created:</strong></p><pre>examples/stock_dashboard/<br>├── app.py              # Dashboard with Plotly charts<br>├── requirements.txt    # streamlit, yfinance, plotly<br>└── README.md           # Deployment instructions</pre><p><strong>Features:</strong> Candlestick charts, volume analysis, key metrics, time period selector.</p><p>Three questions. The AI knew not to ask about LLMs (dashboards don’t need them) and automatically omitted st.set_page_config() for SiS compatibility as it is an <a href="https://docs.snowflake.com/en/developer-guide/streamlit/limitations#unsupported-streamlit-features">unsupported feature on SiS</a>.</p><h3>Key Patterns that AGENTS.md Teaches AI</h3><h4>1. Universal Database Connection</h4><p>Works across all three deployment environments:</p><pre>@st.cache_resource<br>def get_session():<br>    try:<br>        from snowflake.snowpark.context import get_active_session<br>        return get_active_session()<br>    except:<br>        from snowflake.snowpark import Session<br>        return Session.builder.configs(<br>            st.secrets[&quot;connections&quot;][&quot;snowflake&quot;]<br>        ).create()</pre><h4>2. Snowflake Cortex LLM with AI_COMPLETE</h4><p>The recommended pattern for universal compatibility:</p><pre>import json<br>from snowflake.snowpark.functions import ai_complete<br><br>@st.cache_data(show_spinner=False)<br>def call_llm(prompt: str, model: str = &quot;claude-3-5-sonnet&quot;) -&gt; str:<br>    df = session.range(1).select(<br>        ai_complete(model=model, prompt=prompt).alias(&quot;response&quot;)<br>    )<br>    response_raw = df.collect()[0][0]<br>    response_json = json.loads(response_raw)<br>    <br>    if isinstance(response_json, dict) and &quot;choices&quot; in response_json:<br>        return response_json[&quot;choices&quot;][0][&quot;messages&quot;]<br>    return str(response_json)</pre><h4>3. Chat Interface with Streaming</h4><pre>st.session_state.setdefault(&quot;messages&quot;, [])<br><br>for msg in st.session_state.messages:<br>    with st.chat_message(msg[&quot;role&quot;]):<br>        st.markdown(msg[&quot;content&quot;])<br><br>if prompt := st.chat_input(&quot;Your message&quot;):<br>    st.session_state.messages.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: prompt})<br>    with st.chat_message(&quot;user&quot;):<br>        st.markdown(prompt)<br>    <br>    with st.chat_message(&quot;assistant&quot;):<br>        response = st.write_stream(stream_response(prompt))<br>    <br>    st.session_state.messages.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: response})</pre><h4>4. SiS-Aware Code</h4><p>The AI automatically knows:</p><ul><li><strong>SiS deployment</strong> → No st.set_page_config()</li><li><strong>Community Cloud</strong> → Include st.set_page_config()</li><li><strong>Both</strong> → Use the universal connection pattern</li></ul><h3>Pattern Selection Guide</h3><p>Based on what you ask for, the AI selects the right patterns:</p><pre>+-------------------------+---------------------------------------------+<br>| You Say                 | AI Uses                                     |<br>+-------------------------+---------------------------------------------+<br>| chatbot, AI assistant   | Chat Interface + Streaming + AI_COMPLETE    |<br>+-------------------------+---------------------------------------------+<br>| dashboard,              | Basic App + Plotly/Altair Charts            |<br>| visualization           |                                             |<br>+-------------------------+---------------------------------------------+<br>| data analysis           | File Upload + DataFrame Styling             |<br>+-------------------------+---------------------------------------------+<br>| RAG, search documents   | Chat + Cortex Search + AI_COMPLETE          |<br>+-------------------------+---------------------------------------------+<br>| multipage               | st.navigation + Session State               |<br>+-------------------------+---------------------------------------------+<br>| Snowflake, SiS          | Omit st.set_page_config + Cortex patterns   |<br>+-------------------------+---------------------------------------------+</pre><p>Caching is added automatically wherever beneficial.</p><h3>Common Pitfalls Prevented</h3><p>The AGENTS.md teaches the AI to avoid common mistakes:</p><h4>1. Duplicate Widget Keys</h4><pre># AI learns to always add unique keys<br>st.text_input(&quot;Name:&quot;, key=&quot;first_name&quot;)<br>st.text_input(&quot;Name:&quot;, key=&quot;last_name&quot;)</pre><h4>2. Page Config in SiS</h4><pre># AI omits st.set_page_config() when targeting SiS<br># (it&#39;s not supported)</pre><h4>3. Session State in Multipage Apps</h4><pre># AI initializes in main app.py, not individual pages<br>st.session_state.setdefault(&quot;df&quot;, None)<br>pg = st.navigation(...)<br>pg.run()</pre><h3>Conclusion</h3><p>Building a Streamlit app couldn’t be easier. With the AGENTS.md file, you can truly vibe code. Just describe what you want, answer a few questions, and watch your app come to life.</p><p>Instead of explaining patterns in detail, going through several rounds of promptings and hoping that AI gets it right.</p><p>Here’s what you get from using AGENTS.md:</p><ul><li><strong>Two modes</strong>: Quick instructions or guided questions</li><li><strong>Sequential flow</strong>: One question at a time, not overwhelming</li><li><strong>Smart inference</strong>: UI components and caching handled automatically</li><li><strong>Complete projects</strong>: App, requirements, and README ready to deploy</li><li><strong>Environment-aware</strong>: SiS compatibility built in</li></ul><p>Check out the examples/ folder in the <a href="https://github.com/dataprofessor/streamlit">repo</a> to see the chatbot and dashboard apps created using this exact flow.</p><h3>Resources</h3><ul><li><a href="https://agents.md/">AGENTS.md Official Website</a></li><li><a href="https://docs.streamlit.io/">Streamlit Documentation</a></li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/aisql">Snowflake Cortex AI</a></li><li><a href="https://docs.snowflake.com/en/developer-guide/streamlit/about-streamlit">Streamlit in Snowflake</a></li><li><a href="https://github.com/dataprofessor/streamlit/tree/main/examples">Example Apps</a>: Example apps built with AGENTS.md</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=04b7480f754e" width="1" height="1" alt=""><hr><p><a href="https://blog.streamlit.io/vibe-code-streamlit-apps-with-ai-using-agents-md-04b7480f754e">Vibe code Streamlit apps with AI using AGENTS.md</a> was originally published in <a href="https://blog.streamlit.io/">Streamlit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[10 Principles for Keeping the Vibe while Coding Streamlit Apps]]></title>
            <link>https://blog.streamlit.io/10-principles-for-keeping-the-vibe-while-coding-streamlit-apps-b5e62cc8497d?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/b5e62cc8497d</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[streamlit]]></category>
            <category><![CDATA[vibe-coding]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Thu, 18 Dec 2025 00:58:16 GMT</pubDate>
            <atom:updated>2025-12-18T16:56:15.524Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LBorob3fim-OfFGch8NJBw.png" /><figcaption>Image generated by Author using the ideogram-ai/ideogram-v2-turbo model on Replicate.</figcaption></figure><p>Vibe coding has changed how we build apps. You describe what you want, and after a few seconds, AI generates the code. After a few rounds of iteration and you have a working Streamlit dashboard app. It’s genuinely magical.</p><p>But here’s the catch, without understanding how Streamlit actually works under the hood, that rapid progress can hit a wall. Your app suddenly behaves strangely. Data disappears. Buttons don’t seem to work. Performance grinds to a halt.</p><p>After spending considerable time on the<a href="https://discuss.streamlit.io/"> Streamlit Community Forum</a> and reviewing countless questions from beginners (some of whom were vibe coding their first apps), I started noticing patterns. The same confusions kept surfacing. The same “why isn’t this working?!” moments.</p><p>The good news? Most of these issues stem from a handful of core misunderstandings about how Streamlit actually works under the hood. Once you internalize these concepts, the framework clicks into place and you can vibe code with confidence instead of crossing your fingers every time you hit save.</p><p>Rather than cataloging every possible mistake (that list would be quite extensive), I’ve distilled these into <strong>10 core principles</strong>. Master these, and you’re on your way to building Streamlit apps with confidence.</p><p>Let’s dive in!</p><h3>1. Understand that your script reruns completely on every interaction</h3><p>This is the concept. The one that explains 80% of the unexpected behavior that you’ll encounter. If you only internalize one thing from this entire post, make it this:</p><p>Every button click, slider move, or text input triggers a complete rerun of your script from top to bottom. Not a partial update. Not a diff. The whole thing, starting from import streamlit as st and all the way down.</p><pre># ❌ This resets to 0 on every interaction<br>counter = 0<br>if st.button(&quot;Add&quot;):<br>    counter += 1<br>st.write(counter)  # Always shows 0 or 1<br><br># ✅ Use session state for persistence<br>if &quot;counter&quot; not in st.session_state:<br>    st.session_state.counter = 0<br>if st.button(&quot;Add&quot;):<br>    st.session_state.counter += 1<br>st.write(st.session_state.counter)  # Accumulates correctly</pre><p>Here are some common symptoms that we may see if not understanding this concept:</p><ul><li>Variables “reset” unexpectedly</li><li>Buttons seem to “not work”</li><li>Data disappears after clicking something else</li><li>Chat history vanishes</li></ul><p><strong>The fix: </strong><strong>st.session_state</strong></p><p>Session state is a dictionary that persists across reruns for each user session. The key pattern to memorize:</p><pre># Always initialize before using<br>if &quot;counter&quot; not in st.session_state:<br>    st.session_state.counter = 0</pre><p>This check ensures you only set the default once (on the first run), and subsequent reruns use the existing value. Skip this check, and you’ll reset your variable on every interaction.</p><p>When to use session state:</p><ul><li>Counters, toggles, and flags</li><li>User inputs you need to preserve</li><li>Chat message history</li><li>Multi-step form data</li><li>Any value that should survive a rerun</li></ul><p>Once this pattern becomes second nature, most “mysterious” Streamlit behavior suddenly makes perfect sense.</p><h3>2. Cache expensive operations, always</h3><p>Remember that rerun behavior from Principle 1? Here’s where it becomes a performance nightmare if you’re not careful.</p><p>If your code takes time to run (loading files, API calls, ML models), it will run on <em>every single interaction</em> unless you cache it. Your users don’t want to wait 10 seconds every time they adjust a slider.</p><pre># ❌ Loads 500MB file on every click<br>data = pd.read_csv(&quot;large_file.csv&quot;)<br><br># ✅ Cache it - runs once, reuses result<br>@st.cache_data<br>def load_data():<br>    return pd.read_csv(&quot;large_file.csv&quot;)<br><br>data = load_data()</pre><p><strong>The two decorators:</strong></p><ul><li>@st.cache_data: For data (DataFrames, lists, API responses). Returns a copy.</li><li>@st.cache_resource: For resources (DB connections, ML models). Returns the same object.</li></ul><p>Add TTL for data that updates frequently:</p><pre>@st.cache_data(ttl=300)  # Refresh every 5 minutes<br>def get_live_data():<br>    return api.fetch()</pre><p>Why does this work? The decorator stores the function’s return value in memory, keyed by the function’s input arguments. On subsequent calls with the same arguments, Streamlit returns the cached result instead of re-executing the function. This means your 10-second data load happens only once, on that initial run, and not on every interaction.</p><h3>3. Never hardcode secrets: use st.secrets</h3><p>This one isn’t about convenience. It’s about not accidentally publishing your API keys to GitHub for the world to see.</p><p>Yes, bots can actively scan for this. And yes, your keys will get compromised within minutes.</p><p>This principle has no exceptions. “Just for testing” is how secrets can end up in the commit history forever.</p><pre># ❌ NEVER do this<br>api_key = &quot;sk-1234567890&quot;<br><br># ✅ Use .streamlit/secrets.toml (with gitignored!)<br>api_key = st.secrets[&quot;openai&quot;][&quot;api_key&quot;]</pre><p>Here’s what to do instead:</p><ul><li>Create .streamlit/secrets.toml for local development</li><li>Add .streamlit/secrets.toml to .gitignore before your first commit</li><li>Add secrets via the UI in the secrets management when deploying to Community Cloud</li></ul><h3>4. Handle empty and error states gracefully</h3><p>Your app will encounter None values. It will receive empty lists. APIs will fail. Files won’t upload.</p><p>The difference between a frustrating app and a delightful one is often just how gracefully it handles these situations. Never assume that data exists; always check before processing.</p><pre># ❌ Crashes if no file was uploaded<br>uploaded = st.file_uploader(&quot;Upload&quot;)<br>df = pd.read_csv(uploaded)<br><br># ✅ Check first, guide the user<br>uploaded = st.file_uploader(&quot;Upload&quot;)<br>if uploaded is not None:<br>    df = pd.read_csv(uploaded)<br>    st.dataframe(df)<br>else:<br>    st.info(&quot;👆 Upload a CSV to get started&quot;)</pre><p>Apply this pattern everywhere:</p><ul><li>File uploads → check with is not None</li><li>API calls → wrap in try / except</li><li>Filtered data → check if result is empty</li><li>Selectbox options → verify that list isn’t empty</li></ul><p>Here’s an example for select boxes:</p><pre># Empty options can crash selectbox<br>options = [x for x in items if x.startswith(&quot;A&quot;)]<br>if options:<br>    selected = st.selectbox(&quot;Choose&quot;, options)<br>else:<br>    st.warning(&quot;No matching items found&quot;)</pre><p>Why does this matters? Streamlit apps often start in an “empty” state before the user provides input. Your code needs to handle this gracefully. Think of it as defensive coding: assume nothing exists until you’ve verified that it does.</p><h3>5. Use forms when you need to batch inputs</h3><p>Here’s a scenario: you have a form with name, email, and phone fields. Without Streamlit forms, your app might start processing (triggering a rerun of the app) after the user starts typing their name, before they’ve even gotten to their email. As a result, the app may rerun multiple times by the time that you’re finished with filling in the input fields.</p><p>Forms let users fill out multiple fields and submit them together as a batch, thereby giving you control over when the processing actually happens.</p><pre># ❌ Processing might trigger on partial input<br>name = st.text_input(&quot;Name&quot;)<br>email = st.text_input(&quot;Email&quot;)<br><br>if name:<br>    process1(name)<br>if email:<br>    process2(email)<br><br># ✅ Forms batch until explicit submit<br>with st.form(&quot;user_form&quot;):<br>    name = st.text_input(&quot;Name&quot;)<br>    email = st.text_input(&quot;Email&quot;)<br>    submitted = st.form_submit_button(&quot;Submit&quot;)<br><br>if submitted:<br>    if name and email:  # Only process if both are filled<br>        process1(name)<br>        process2(email)<br>    else:<br>        st.error(&quot;Please fill out all fields&quot;)</pre><p>Use forms when:</p><ul><li>You have multiple related inputs</li><li>You want to prevent premature processing</li><li>You’re building data entry interfaces</li></ul><p>Forms create a boundary that prevents reruns until the user explicitly clicks submit. All widgets inside the form collect input without triggering the script, then submit sends everything at once. This gives you a clean “before” and “after” moment instead of continuous partial updates.</p><h3>6. Add unique keys to widgets in loops</h3><p>DuplicateWidgetID is one of those error messages that makes perfect sense once you understand it, and is completely baffling before that moment.</p><p>When creating widgets dynamically (in loops or conditionally), Streamlit needs unique identifiers to tell them apart. No key? Streamlit guesses. Multiple widgets with the same guess? Chaos.</p><pre># ❌ DuplicateWidgetID error<br>for item in items:<br>    st.checkbox(item)<br><br># ✅ Add unique keys<br>for i, item in enumerate(items):<br>    st.checkbox(item, key=f&quot;checkbox_{i}&quot;)</pre><p>Also remember:</p><ul><li>Capture widget return values: value=st.slider(&quot;...&quot;)</li><li>Widgets with keys automatically sync to st.session_state</li></ul><p>Let’s take a look at an example:</p><pre># ✅ Captures the return value from a stored variable<br>temperature = st.slider(&quot;Temperature&quot;, 0, 100, 72)<br>st.write(f&quot;Current: {temperature}°F&quot;)<br><br># ✅ A key is automatically stored in session_state<br>st.slider(&quot;Humidity&quot;, 0, 100, 50, key=&quot;humidity&quot;)<br>st.write(f&quot;Humidity: {st.session_state.humidity}%&quot;)</pre><p>Direct capture: The slider returns its current value, which we store in the temperature variable. This is the simplest approach when you just need to use the value immediately.</p><p>Using a key: When you add a key parameter, Streamlit automatically stores the widget’s value in st.session_state under that key name. You can access it as st.session_state.humidity anywhere in your app. This is useful when you need to access the value in multiple places or modify it programmatically.</p><p>Streamlit identifies widgets by generating an ID from their type, label, and position in the code. In a loop, multiple widgets can end up with identical IDs and thus give rise to an error! The key parameter overrides this auto-generated ID with your own unique identifier, letting Streamlit distinguish between them. As a bonus, any widget with a key automatically syncs its value to st.session_state, making it accessible throughout your app.</p><h3>7. Show progress for long operations</h3><p>A frozen screen is a source of anxiety for users. “Did it crash? Should I refresh? Is my data lost?” These are not the questions you want people asking.</p><p>The fix is simple: show them something is happening. Streamlit makes this almost very easy.</p><pre># ❌ User sees frozen screen, thinks app crashed<br>result = slow_api_call()<br>st.write(result)<br><br># ✅ Show a spinner for single operations<br>with st.spinner(&quot;Generating response...&quot;):<br>    result = slow_api_call()<br>st.write(result)<br><br># ✅ Use st.status for multi-step operations<br>with st.status(&quot;Processing...&quot;, expanded=True) as status:<br>    st.write(&quot;Step 1: Loading data...&quot;)<br>    data = load_data()<br>    <br>    st.write(&quot;Step 2: Analyzing...&quot;)<br>    analysis = analyze(data)<br>    <br>    st.write(&quot;Step 3: Generating report...&quot;)<br>    report = generate_report(analysis)<br>    <br>    status.update(label=&quot;Complete!&quot;, state=&quot;complete&quot;)</pre><p>For LLM apps, streaming responses can provide users with real-time feedback.</p><p>Here’s how we could implement streaming using OpenAI:</p><pre>from openai import OpenAI<br>import streamlit as st<br><br>client = OpenAI(api_key=st.secrets[&quot;openai&quot;][&quot;api_key&quot;])<br><br>stream = client.chat.completions.create(<br>    model=&quot;gpt-4o&quot;,<br>    max_tokens=1024,<br>    messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;Write a poem about snowflakes.&quot;}],<br>    stream=True<br>)<br><br>st.write_stream(stream)  # Shows tokens as they arrive</pre><p>And here’s how with Anthropic:</p><pre>from anthropic import Anthropic<br>import streamlit as st<br><br>client = Anthropic(api_key=st.secrets[&quot;anthropic&quot;][&quot;api_key&quot;])<br><br># Stream responses for real-time feedback<br>with client.messages.stream(<br>    model=&quot;claude-sonnet-4-5&quot;,<br>    max_tokens=1024,<br>    messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;Write a poem about snowflakes.&quot;}]<br>) as stream:<br>    st.write_stream(stream.text_stream)  # Shows tokens as they arrive</pre><p>Why does this matter? Users are surprisingly patient when they can see progress. A 10-second wait with a spinner feels faster than a 5-second frozen screen. It’s not about speed, it’s about communication.</p><h3>8. Use @st.fragment for partial reruns</h3><p>This is the “I wish I’d known this sooner” feature for anyone building apps with both expensive visualizations and interactive elements.</p><p>By default, the entire script reruns on every interaction. Got a chart that takes 5 seconds to render? Every widget interaction would cause the user to wait for another 5 more seconds as the app reruns. Fragments let you break this cycle by isolating sections that should rerun independently from the rest.</p><pre># ❌ Expensive operation reruns on every interaction<br>st.title(&quot;Dashboard&quot;)<br><br># This takes 5 seconds<br>plot_expensive_chart(data)<br><br># Every button click reruns the expensive chart!<br>if st.button(&quot;Increment Counter&quot;):<br>    st.session_state.count = st.session_state.get(&quot;count&quot;, 0) + 1<br>st.write(f&quot;Count: {st.session_state.get(&#39;count&#39;, 0)}&quot;)<br><br># ✅ Fragment isolates the counter from the expensive chart<br>st.title(&quot;Dashboard&quot;)<br><br>plot_expensive_chart(data)  # Only runs on full page rerun<br><br>@st.fragment<br>def counter_section():<br>    if st.button(&quot;Increment Counter&quot;):<br>        st.session_state.count = st.session_state.get(&quot;count&quot;, 0) + 1<br>    st.write(f&quot;Count: {st.session_state.get(&#39;count&#39;, 0)}&quot;)<br><br>counter_section()  # This section reruns independently</pre><p>Use fragments when:</p><ul><li>Mixing expensive calculations with lightweight interactions</li><li>Any section that updates frequently while others stay static</li></ul><p>Why this works: The @st.fragment decorator creates an isolated execution scope that allows only a specific function to re-execute, not the entire script. Everything outside the fragment stays untouched, thereby preserving your expensive computations.</p><h3>9. Structure your project for deployment from the start</h3><p>“I’ll organize it later” is the lie we tell ourselves right before our app.py hits 2,000 lines and we can’t find anything.</p><p>Future you will thank present you for taking 5 minutes to set up a proper project structure. Don’t wait until deployment to organize your code.</p><pre>my_app/<br>├── app.py                 # Entry point<br>├── requirements.txt       # Pin versions!<br>├── .gitignore            # Include secrets.toml<br>├── .streamlit/<br>│   ├── config.toml       # Theme settings<br>│   └── secrets.toml      # Local secrets (gitignored)<br>├── pages/                # Multipage app<br>│   └── 1_📊_Dashboard.py<br>└── utils/                # Shared code<br>    └── data.py</pre><p>Why pin versions? An unpinned requirements.txt is a ticking time bomb. Your app works perfectly today, but six months from now when you redeploy or reinstall dependencies, a new library version might introduce breaking changes. Pinning versions (pandas==2.1.0 instead of just pandas) ensures your app behaves the same way every time (like putting your app in a time capsule).</p><p>Deployment checklist:</p><ul><li>requirements.txt with pinned versions (pandas==2.1.0)</li><li>Relative file paths only (use assets/ as oppossed to /Users/chanin/dashboard_app/assets)</li><li>Secrets in secrets.toml, not hard-coded in the code</li><li>Test your deployment early and often</li></ul><h3>10. Use Streamlit’s built-in features before custom solutions</h3><p>Before you spend an hour crafting custom CSS for a metrics display, check if Streamlit already has a widget for that.</p><p>It probably does and LLMs may be trained on an older version of Streamlit</p><p>The framework has grown significantly, and many common UI patterns now have first-class support. Using built-ins means less code to maintain, better performance, and a more consistent look.</p><pre>+----------------------+------------------------------------------+<br>| Need                 | Use This                                 |<br>+----------------------+------------------------------------------+<br>| Show loading state   | with st.spinner(&quot;Loading...&quot;)            |<br>| Display KPIs         | st.metric(label, value, delta)           |<br>| Organize content     | st.columns(), st.tabs(), st.expander()   |<br>| Database connections | st.connection()                          |<br>| Long operations      | st.status() for multi-step progress      |<br>| Chat interfaces      | st.chat_message(), st.chat_input()       |<br>| Stream LLM responses | st.write_stream()                        |<br>| Partial reruns       | @st.fragment                             |<br>+----------------------+------------------------------------------+</pre><p>Let’s say that you want to display metrics in your dashboard app, instead of manually using st.write() you could instead leverage st.metric(), which comes with the metric name and values as well as any recent positive/negative changes.</p><pre># ❌ Manual KPI formatting<br>st.write(f&quot;Revenue: ${revenue:,}&quot;)<br>st.write(f&quot;Change: {change:+.1%}&quot;)<br><br># ✅ Use st.metric<br>st.metric(&quot;Revenue&quot;, f&quot;${revenue:,}&quot;, f&quot;{change:+.1%}&quot;)</pre><p>If Streamlit doesn’t have it built-in, check these before building custom solutions:</p><ol><li><a href="https://extras.streamlit.app/"><strong>Streamlit Extras</strong></a>: A curated collection of additional components including card layouts, annotated text, clickable images, and more. Maintained by members of the Streamlit data science team.</li><li><a href="https://streamlit.io/components"><strong>Streamlit Components Gallery</strong></a>: Third-party extensions for bringing in additional functionality to your Streamlit app!</li></ol><p>The hierarchy: <strong>Built-in → Streamlit Extras → Third-party → Custom code</strong>. Each step down means more maintenance burden, so only go custom when you truly need something unique.</p><h3>Wrapping Up</h3><p>There you have it, 10 principles that address the root causes of most Streamlit beginner struggles. The beautiful thing about these principles is that once they click, they become second nature. You’ll start writing Streamlit code that “just works” because you understand <em>why</em> it works.</p><p>Vibe coding isn’t about blindly accepting AI suggestions. It’s about knowing enough to guide the conversation productively. The AI handles the syntax; you bring the architectural intuition.</p><p>If you’re looking to put these principles into practice, check out the upcoming <a href="https://30daysofai.streamlit.app/"><strong>30 Days of AI</strong></a><strong> </strong>in January 2026. This challenge focuses on teaching learners to build LLM-powered apps, taking you from connecting to an LLM, building basic chat interfaces to features for production-ready AI apps. It’s a free learning challenge, one day at a time.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2F30daysofai.streamlit.app%2F%3Fembed%3Dtrue&amp;display_name=Streamlit&amp;url=https%3A%2F%2F30daysofai.streamlit.app&amp;image=https%3A%2F%2Fstorage.googleapis.com%2Fs4a-prod-share-preview%2Fdefault%2Fst_app_screenshot_image%2F30e25ad4-9a5f-4f45-9221-6da6c366c319%2FHome_Page.png&amp;type=text%2Fhtml&amp;schema=streamlit" width="560" height="630" frameborder="0" scrolling="no"><a href="https://medium.com/media/48373b274280e87e948022aef1910248/href">https://medium.com/media/48373b274280e87e948022aef1910248/href</a></iframe><p>Happy Streamlit-ing! 🎈</p><h3>Resources</h3><p>If you’re ready to dive deeper into the specifics, here are additional resources to help you.</p><ol><li>Reruns &amp; Session State: <a href="https://docs.streamlit.io/develop/concepts/architecture/session-state">Adding Statefulness to Apps</a></li><li>Caching: <a href="https://docs.streamlit.io/develop/concepts/architecture/caching">Caching Overview</a></li><li>Secrets: <a href="https://docs.streamlit.io/develop/concepts/connections/secrets-management">Secrets Management</a></li><li>Error Handling: <a href="https://docs.streamlit.io/get-started/fundamentals/main-concepts">Basic Concepts of Streamlit</a></li><li>Forms: <a href="https://docs.streamlit.io/develop/concepts/architecture/forms">Using forms</a></li><li>Widget Keys: <a href="https://docs.streamlit.io/develop/concepts/architecture/widget-behavior">Widget Behavior</a></li><li>Progress Indicators: <a href="https://docs.streamlit.io/develop/api-reference/status/st.spinner">st.spinner</a>, <a href="https://docs.streamlit.io/develop/api-reference/status/st.status">st.status</a>, <a href="https://docs.streamlit.io/develop/api-reference/status/st.progress">st.progress</a></li><li>Fragments: <a href="https://docs.streamlit.io/develop/concepts/architecture/fragments">Working with Fragments</a></li><li>Project Structure: <a href="https://docs.streamlit.io/deploy/streamlit-community-cloud/deploy-your-app/app-dependencies">App Dependencies</a>, <a href="https://docs.streamlit.io/develop/concepts/multipage-apps/overview">Multipage Apps</a></li><li>Built-in Features: <a href="https://docs.streamlit.io/develop/api-reference">API Reference</a>, <a href="https://extras.streamlit.app/">Streamlit Extras</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b5e62cc8497d" width="1" height="1" alt=""><hr><p><a href="https://blog.streamlit.io/10-principles-for-keeping-the-vibe-while-coding-streamlit-apps-b5e62cc8497d">10 Principles for Keeping the Vibe while Coding Streamlit Apps</a> was originally published in <a href="https://blog.streamlit.io/">Streamlit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fast Prototyping of GenAI Apps with Streamlit]]></title>
            <link>https://blog.streamlit.io/fast-prototyping-of-genai-apps-with-streamlit-065cc822d9b5?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/065cc822d9b5</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[streamlit]]></category>
            <category><![CDATA[genai]]></category>
            <category><![CDATA[vibe-coding]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Wed, 24 Sep 2025 20:40:43 GMT</pubDate>
            <atom:updated>2025-09-24T20:40:43.181Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q7ualTsIxfrTyXJerNXvAA.png" /></figure><h4>A course to help you learn to build and ship GenAI apps fast</h4><p><a href="https://www.coursera.org/learn/fast-prototyping-of-genai-apps-with-streamlit?ref=blog.streamlit.io"><em>Fast Prototyping of GenAI Apps with Streamlit</em></a> is created as part of a Snowflake × DeepLearning.AI collaboration.</p><p>The course tackles a costly problem: app ideas lose momentum when they linger in discussions, drawn-out specifications, and intangibles that slow down the decision-making process. In a field where new GenAI capabilities surface every week, the teams that can show working demos <em>first</em> are the ones that influence roadmaps and win resources.</p><h3>What you’ll learn</h3><p>This course gives you that speed advantage.</p><p>We’ll first kick off with an insightful conversation between Chanin Nantasenamat, PhD (the course instructor) and Professor Andrew Ng. We discussed how GenAI has fundamentally changed app development by enabling developers to build and test ideas faster than ever before.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-aK6DefavLY0P6GI.png" /></figure><p>You’ll explore how GenAI streamlines the prototyping workflow, facilitates rapid iteration and validation of product-market fit, and allows anyone, regardless of coding experience, to participate in the application development process.</p><p>You’ll learn how to turn a few lines of Python into a shareable <a href="https://streamlit.io/?ref=blog.streamlit.io">Streamlit</a> web app, cut down iteration time from weeks to hours using Snowflake’s secure data and coding copilot, and improve the performance of your application easily using <a href="https://www.snowflake.com/en/product/features/cortex/?ref=blog.streamlit.io">Snowflake’s Cortex AI</a>, a fully managed suite of LLMs, RAG, and text-to-SQL services (free 120-day trial included).</p><p>You’ll start with a basic chatbot, layer on prompt engineering and RAG, and publish the result to Snowflake or Streamlit Community Cloud for real-time feedback.</p><p>By the end of the course, you’ll leave with a working GenAI app, a repeatable MVP-first framework, and the skills to validate any new idea as soon as it strikes.</p><h3>How to enroll</h3><p>Enroll <a href="https://www.coursera.org/learn/fast-prototyping-of-genai-apps-with-streamlit?ref=blog.streamlit.io">here</a> to start building!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=065cc822d9b5" width="1" height="1" alt=""><hr><p><a href="https://blog.streamlit.io/fast-prototyping-of-genai-apps-with-streamlit-065cc822d9b5">Fast Prototyping of GenAI Apps with Streamlit</a> was originally published in <a href="https://blog.streamlit.io/">Streamlit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Overview of Snowsight: Snowflake’s Web Interface]]></title>
            <link>https://medium.com/snowflake/overview-of-snowsight-snowflakes-web-interface-c32d42e546ba?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/c32d42e546ba</guid>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[data-analytics]]></category>
            <category><![CDATA[snowflake]]></category>
            <category><![CDATA[snowsight]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Tue, 12 Aug 2025 17:14:15 GMT</pubDate>
            <atom:updated>2025-08-12T17:14:15.273Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*APeZRpDwGv0US97SOb2Vug.png" /></figure><p>Are you still jumping between multiple tools to manage your data? What if there was one unified platform to ingest, query, analyze and even build apps directly from your browser?</p><p>Whether you’re a data analyst, an engineer, or a business user, understanding Snowsight is crucial for maximizing your productivity and managing your data like a pro.</p><p>Briefly, we’ll explore Snowflake’s Snowsight web interface, covering everything from basic navigation to advanced data management features. While our primary focus is on mastering Snowsight, we’ll also explore how it fits within the broader Snowflake ecosystem, including how it compares to and integrates with command-line tools, code editors, and third-party applications.</p><p>By the end of this article, you’ll have a complete understanding of how Snowsight fits into the broader Snowflake ecosystem and how to leverage it for your specific data needs.</p><h3>Applications and tools for connecting to Snowflake</h3><p>Snowflake provides several different applications and tools that you can use to access databases stored on the Snowflake platform.</p><h4>User Interfaces</h4><p>Snowsight is Snowflake’s web interface. It distills Snowflake’s powerful SQL support into a unified, easy-to-use experience. Use Snowsight to perform your critical Snowflake operations all with SQL as well as Python, Java and Scala.</p><h4>Command-line Clients</h4><p>While Snowsight provides an intuitive web-based experience, many users also prefer working directly from the command line for automation and scripting purposes.</p><p><strong>Snowflake CLI: </strong>Use the command line to create, manage, update, and view apps running on Snowflake across workloads.</p><p><strong>SnowSQL: </strong>Provides detailed instructions for installing, configuring, and using the Snowflake command-line client.</p><h4>Extensions for Code Editors</h4><p>Beyond standalone interfaces, developers often need to integrate Snowflake capabilities directly into their development workflows and favorite code editors.</p><p><strong>Snowflake Extension for Visual Studio Code </strong>can be used to connect to Snowflake within Visual Studio Code and perform SQL operations.</p><h4>Third-party Database Systems</h4><p>Snowflake Connectors provide native integration of third-party applications and database systems in Snowflake. The connectors provide instant access to current data without the need to manually integrate against API endpoints. Data automatically refreshes, based on your desired frequency, in your Snowflake account. The connectors support both the initial load of historical data as well as incremental changes.</p><p>Snowflake Connectors for:</p><ul><li>Google Analytics Raw &amp; Aggregate Data</li><li>Google Looker Studio</li><li>ServiceNow</li></ul><p>Snowflake Database Connectors for:</p><ul><li>MySQL</li><li>PostgreSQL</li><li>SharePoint</li></ul><p>These connectors represent just a fraction of the broader ecosystem of tools and platforms that integrate seamlessly with Snowflake.</p><h4>Third-party Softwares | Snowflake Ecosystem</h4><p>And on to, the Snowflake ecosystem is designed to be highly interoperable, offering a wide array of possibilities for connecting to various third-party tools as well as Snowflake-provided clients.</p><ul><li>Data Integration</li><li>Business Intelligence</li><li>Machine Learning &amp; Data Science</li><li>Security, Governance &amp; Observability</li><li>SQL Development &amp; Management</li><li>Native Programmatic Interfaces</li></ul><p>Here’s a diagram categorizing all the interoperable tools into the above mentioned topics.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/0*RoEnjvqlMmlhn4I6" /></figure><p>Understanding these resources is crucial for maximizing your efficiency and leveraging the full potential of Snowflake for diverse data-related tasks. For instance, users can effectively manage their data lifecycle, from ingestion and transformation to analysis and app development, all within the robust and scalable Snowflake ecosystem.</p><p>When third-party tools don’t meet your specific requirements, or when you need to build custom applications, Snowflake’s comprehensive suite of drivers and APIs provides the foundation for direct programmatic access.</p><h4>Drivers and Libraries</h4><p>Snowflake provides various drivers and APIs for connecting applications to its data cloud.</p><p>These include JDBC, ODBC, Python, Go, and Node.js drivers for direct database interaction. Additionally, specialized APIs like Snowflake SQL API, Snowpipe API, and External Functions API enable serverless integration, continuous data loading, and custom logic execution. Snowflake also supports stored procedures for in-database logic.</p><p>Additionally, there are Snowflake connectors for Kafka, Python and Spark as well as Snowflake APIs for Python, REST and SQL.</p><h3>Getting Started</h3><p>To try out Snowsight, sign up for a free trial account by going to <a href="https://signup.snowflake.com/">https://signup.snowflake.com/</a></p><p>After a successful signup, you should receive a confirmation email that provide details on logging in. Most likely this will point you to <a href="https://app.snowflake.com/">https://app.snowflake.com/</a></p><p>Watch this great getting started video by <a href="https://www.linkedin.com/in/gilberto-hernandez/">Gilberto Hernandez</a> to get up to speed with the basics of Snowflake:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FHIff0No7wrM%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DHIff0No7wrM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FHIff0No7wrM%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/08c779fcd11b36c77fba7514e3a24ee1/href">https://medium.com/media/08c779fcd11b36c77fba7514e3a24ee1/href</a></iframe><h3>Accessing Snowsight</h3><p>You can access Snowsight from an internet browser in one of 2 ways:</p><ol><li>Public internet with an internet browser of your choice (<em>e.g.</em> Chrome, Safari, Opera, etc.)</li><li>Private Link — establishes a secure, private connection between your organization’s network (or cloud environment) and your Snowflake account, bypassing the public internet entirely. The primary benefit of Private Link is significantly enhanced security and compliance, as all data traffic remains on the cloud provider’s private network (<em>e.g.</em> AWS, Azure, or GCP backbone). This reduces the risk of data exposure to external threats and often provides lower latency and more stable connections compared to public internet routes.</li></ol><h3>Anatomy of the Snowsight UI</h3><p>Snowsight serves as the central hub for interacting with your Snowflake data, offering a comprehensive and intuitive web interface. It provides a unified experience, whether you prefer working with SQL or Python, and empowers users to perform a wide array of data-related tasks.</p><p>After signing in, you should see something like the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5KIufsFpxbOZfgB3jKAbGQ.png" /></figure><p>Let’s dissect each highlighted segment:</p><ul><li><strong>Navigation menu</strong> — this is where you’ll be able to ingest, query, and work with your data. It’s here that you’ll be able to access Workspaces, Worksheets, Snowflake Notebooks, Streamlit in Snowflake apps, Snowpark Container Services, Databases, Marketplace, etc.</li><li><strong>Profile settings</strong> — enables configuration of your interface to be light/dark mode, configure multifactor authentication, access settings, etc.</li><li><strong>Search bar</strong> — enter a few keywords and you’ll have access to relevant resource pages</li><li><strong>Shortcuts</strong> — provide quick access to common tasks like file uploads,data query, user invite, etc.</li><li><strong>Recent files</strong> — list of recent files that you have been working on, so you can resume work in an instant!</li></ul><h3>Core Functionalities</h3><p>Snowsight is designed to cater to various aspects of data analysis, development, and collaboration.</p><p>Here’s a detailed look at its core functionalities:</p><ul><li><strong>Data ingestion:</strong> Getting data into Snowflake can be done through many ways. There’s the traditional migration through Snowflake’s SnowConvert AI that guides you through the process of migrating data from an external platform to Snowflake. Then there’s the smaller batch approach by reading data from a CSV file, from the cloud (e.g. AWS S3 bucket, Google Cloud, etc.).</li><li><strong>Worksheets:</strong> Need to quickly test a query or perform ad-hoc analysis? Worksheets are your go-to. They provide a flexible environment for writing, executing, and refining your SQL queries. This allows users to directly interact with their data, perform <em>ad-hoc</em> analysis, and develop complex data transformations.</li><li><strong>Snowflake Notebooks: </strong>Building a complete ML pipeline from data prep to deployment? Notebooks let you do it all in one place. Write SQL and Python, train models, and deploy them without ever leaving Snowflake’s scalable environment. And once you’re done, you can share what you’ve learned with your colleagues.</li><li><strong>Snowflake Copilot: </strong>Stuck on a tricky SQL query or need quick insights? Copilot acts as your intelligent assistant, helping you generate queries, uncover patterns, and navigate your data analysis with ease.</li><li><strong>Snowpark Python: </strong>Want to use your favorite Python libraries without moving data around? Snowpark brings pandas, scikit-learn, and other familiar frameworks directly into Snowflake, so you can build advanced applications right where your data lives.</li><li><strong>Monitoring Query Performance and History:</strong> Need to figure out why that query is running slow? Track performance metrics and dive into your execution history to spot bottlenecks, optimize efficiency, and keep your queries running smoothly.</li><li><strong>Worksheet Management with Sharing and Folders:</strong> To facilitate collaboration and organization, Snowsight allows users to manage their worksheets through sharing options and folder structures. This ensures that teams can easily collaborate on projects, share insights, and maintain a tidy workspace. This is made possible with the recent rollout of Workspaces which is available for preview.</li><li><strong>Visualizing Worksheet Results with Charts:</strong> Beyond raw data, Snowsight enables users to visualize worksheet results through various chart types. This transformation of data into visual representations makes it easier to understand trends, patterns, and anomalies, aiding in data-driven decision-making.</li><li><strong>Creating Dashboards with Built-in Visualizations:</strong> For a consolidated view of key metrics and data insights, Snowsight offers the ability to create interactive dashboards using its built-in visualization tools. These dashboards serve as powerful tools for monitoring business performance and communicating data stories.</li><li><strong>Creating and Running Streamlit Apps:</strong> Snowsight integrates with Streamlit, allowing users to build and deploy interactive data applications directly within the Snowflake environment. This empowers users to create engaging data experiences and share them with a broader audience.</li><li><strong>Developing and Sharing Snowflake Native Apps:</strong> Snowsight provides the tools necessary to develop and share Snowflake Native Apps. These applications are built and run entirely within Snowflake, offering a secure and efficient way to deliver data-driven solutions to other Snowflake accounts.</li><li><strong>Sharing Data and Apps via Snowflake Marketplace:</strong> The platform facilitates seamless data and application sharing with other Snowflake accounts and publicly on the Snowflake Marketplace. This enables data providers to monetize their data assets and applications, fostering a vibrant data economy.</li></ul><h3>Managing Your Snowflake Deployment and Operations</h3><p>Beyond data analysis and development, Snowsight is an indispensable tool for performing critical Snowflake operations and managing your entire deployment.</p><ul><li><strong>Cost Management Views:</strong> Users can effectively manage and monitor their Snowflake costs through dedicated cost management views. This provides transparency into credit usage, storage costs, and other expenditures, allowing for optimized resource allocation and budget control.</li><li><strong>Trust Center for Security Monitoring:</strong> Snowsight allows users to monitor and evaluate their account for security risks. This proactive approach to security helps identify vulnerabilities, ensure compliance, and protect sensitive data.</li><li><strong>Budget Monitoring for Credit Usage:</strong> To help control expenditures, Snowsight allows users to monitor their credit usage against predefined budgets. This feature provides alerts and insights, enabling users to stay within their allocated resources.</li><li><strong>Monitoring Data Loading Activity:</strong> Tracking data loading activity is crucial for data pipeline management. Snowsight provides comprehensive monitoring tools to observe the progress and status of data ingestion processes.</li><li><strong>Monitoring Data Transformation Tasks and Debugging Task Graphs:</strong> For complex data transformations, Snowsight offers robust monitoring of tasks and the ability to debug task graphs. This helps identify and resolve issues in data pipelines, ensuring data accuracy and timely processing.</li><li><strong>User Management:</strong> Administrators can easily create and manage users within their Snowflake account through Snowsight. This includes setting up new user accounts, managing user profiles, and defining authentication methods.</li><li><strong>Role Management and Privilege Control:</strong> Snowsight provides comprehensive tools for creating and managing roles, as well as granting and revoking privileges. This granular access control ensures that users only have access to the data and functionalities they need, enhancing security and compliance.</li><li><strong>User Profile Management:</strong> Each user can manage their personal profile within Snowsight, including preferences and account settings, for a personalized experience.</li></ul><p>In essence, Snowsight is more than just a web interface; it’s a powerful and integrated platform that empowers users to unlock the full potential of their Snowflake data, from advanced analytics and application development to comprehensive account management and operational oversight.</p><h3>Highlights</h3><p>As there are so many features to consider, let’s highlight a few important ones that you can use from Snowsight.</p><h4>Workspaces</h4><p>The predecessor of Workspaces is Worksheets, which acts as only the code editor. Spinning up a Worksheet is very much like creating a new file in VS Code.</p><p>Let’s take a look at the anatomy of a typical Worksheet (sometimes called a SQL Worksheet).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IZDjHIrr3KK2QMa3QStblg.png" /></figure><p>Recently Workspaces has been introduced as a Public Preview as of May 2025. And is expected to be Generally Available soon. This feature transforms this experience into more of an IDE where there are additional bells and whistles.</p><p><strong><em>What is Workspaces?</em></strong></p><p>At its core, workspaces is comprised of worksheets but with several additional upgrades.</p><p>As a result, it now works very much like an IDE (aka integrated development environment or code editor). Briefly, it is a file-based modern development environment for authoring, organizing, and running Snowflake code artifacts and data, using familiar IDE and source control conventions.</p><p><strong><em>Why Workspaces?</em></strong></p><p>There are several benefits to this upgrade from Worksheets to Workspaces</p><ul><li>Stability and reliability issues with worksheets, and a long tail of feature requests</li><li>No source control for SQL and Python worksheets</li><li>Limited support for more complex development workloads</li><li>Inflexible organization and management of code artifacts</li><li>Limited private development and collaboration controls</li></ul><p>It’s also noteworthy that you can import your dbt projects into Snowflake. Check out this video for details:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fw7C7OkmYPFs%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dw7C7OkmYPFs&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fw7C7OkmYPFs%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/945b0f0da24ba7111436e572afc6f1cb/href">https://medium.com/media/945b0f0da24ba7111436e572afc6f1cb/href</a></iframe><h4>Snowflake Notebooks</h4><p>Snowflake Notebooks offer a powerful and interactive environment for data scientists and analysts to perform complex data analysis and machine learning workflows directly within Snowsight. These notebooks combine the flexibility of a traditional notebook interface with the scalability and performance of Snowflake’s data cloud. Users can write and execute SQL and Python code, visualize results, and manage their data projects collaboratively, all within a single, integrated platform.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0copp38f8j7XkZ5D.png" /></figure><h4>Streamlit in Snowflake</h4><p>Streamlit is an open-source Python library that makes it incredibly easy to build and share interactive data apps.</p><p>In the diagram below, you can see that a data app can be easily built with Python. This example app can read in CSV data followed by the creation of a line chart.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*iG0qRGlQ7BuiTtyS.png" /></figure><p>Streamlit in Snowflake allows users to build, deploy, and share interactive data apps using Snowflake data via the Snowsight interface. This integration provides a seamless experience for data scientists and developers to transform data insights into shareable apps, fostering collaboration and empowering business users with interactive data exploration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*og6sN6D_b-uYpvMI.png" /></figure><h4>Snowflake Cortex</h4><p>On the AI front, we have Snowflake Cortex, a comprehensive suite of artificial intelligence features designed to empower users with advanced analytical capabilities and intelligent assistance. Snowflake Cortex leverages the power of large language models (LLMs) to unlock insights from unstructured data, enabling users to ask freeform questions and receive accurate, contextually relevant answers.</p><p>Here’s a diagram summarizing the capabilties of Cortex AI:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*H_w32vabqX4LSbtt" /></figure><p>Particularly, Snowflake Cortex comprises several powerful components:</p><ul><li><a href="https://docs.snowflake.com/user-guide/snowflake-cortex/aisql"><strong>Snowflake Cortex AISQL</strong></a><strong> (including LLM functions):</strong> This feature allows users to interact with their data using natural language queries, transforming complex questions into actionable SQL commands. It integrates advanced LLM functions to perform sophisticated data analysis and manipulation.</li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-copilot"><strong>Snowflake Copilot</strong></a><strong>:</strong> Acting as an intelligent assistant, Snowflake Copilot helps users navigate the Snowflake environment, providing guidance, automating tasks, and suggesting optimal approaches for data management and analysis.</li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/document-ai/overview"><strong>Document AI</strong></a><strong>:</strong> This specialized component enables the extraction, analysis, and understanding of information from diverse unstructured documents, such as PDFs, scanned images, and text files. It automates data entry, identifies key entities, and facilitates intelligent document processing.</li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-finetuning"><strong>Cortex Fine-tuning</strong></a><strong>:</strong> This feature provides the capability to customize and optimize pre-trained LLMs with domain-specific data, ensuring higher accuracy and relevance for particular business needs and use cases.</li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-search/cortex-search-overview"><strong>Cortex Search</strong></a><strong>:</strong> This powerful search engine allows users to efficiently discover and retrieve relevant information from vast datasets, leveraging semantic understanding and contextual relevance to deliver precise results.</li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst"><strong>Cortex Analyst</strong></a><strong>:</strong> Designed to augment human analysts, Cortex Analyst automates repetitive analytical tasks, identifies patterns, and generates insights from data, allowing human experts to focus on higher-level strategic analysis.</li></ul><h4>Snowflake ML</h4><p>On the ML front, we have <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/overview"><strong>Snowflake ML</strong></a>, which is an integrated set of capabilities for end-to-end machine learning in a single platform on top of your governed data. This is a unified environment for ML development and productionization that is optimized for large-scale distributed feature engineering, model training and inference on CPU and GPU compute without manual tuning or configuration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/816/1*UWwycAmq8OPGeswUVhgdzA.png" /></figure><p>Scaling end-to-end ML workflows in Snowflake is seamless. You can do the following:</p><ul><li>Prepare data and use <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/dataset">Snowflake Datasets</a> provide an immutable, versioned snapshot of your data suitable for ingestion by your machine learning models</li><li>Create and use features with the <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/feature-store/overview">Snowflake Feature Store</a></li><li>Train models with CPUs or GPUs using any open-source package from <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/container-runtime-ml">Snowflake Notebooks on Container Runtime</a>. Use <a href="https://docs.snowflake.com/en/guides-overview-ml-functions">ML Functions</a> for common scenarios such as forecasting and anomaly detection</li><li>Operationalize your pipelines using <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/ml-jobs/overview">Snowflake ML Jobs</a></li><li>Deploy your model for inference at scale with the <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/model-registry/overview">Snowflake Model Registry</a></li><li>Monitor your production models with <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/model-registry/model-observability">ML Observability</a> and Explainability</li><li>Use <a href="https://docs.snowflake.com/en/developer-guide/snowflake-ml/ml-lineage">ML Lineage</a> provides to track the source data to features, datasets, and models throughout the ML pipeline</li></ul><p>Snowflake ML is also flexible and modular. You can deploy the models that you’ve developed in Snowflake outside of Snowflake and externally-trained models can easily be brought into Snowflake for inference.</p><h3>Conclusion</h3><p>Snowsight is Snowflake’s primary web interface that integrates data operations from ingestion and transformation to analysis and app development. It also provide essential features for cost management, security, and user administration. Supported by a rich ecosystem of tools and APIs as well as advanced AI/ML capabilities, Snowsight enable users to efficiently and securely manage and leverage data within a unified platform.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c32d42e546ba" width="1" height="1" alt=""><hr><p><a href="https://medium.com/snowflake/overview-of-snowsight-snowflakes-web-interface-c32d42e546ba">Overview of Snowsight: Snowflake’s Web Interface</a> was originally published in <a href="https://medium.com/snowflake">Snowflake Builders Blog: Data Engineers, App Developers, AI, &amp; Data Science</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Developer’s Guide to Modin and Snowflake Cortex]]></title>
            <link>https://medium.com/snowflake/developers-guide-to-modin-and-snowflake-cortex-c8e7b694eb16?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/c8e7b694eb16</guid>
            <category><![CDATA[snowflake]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[data-wrangling]]></category>
            <category><![CDATA[data-analytics]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Fri, 25 Jul 2025 19:01:49 GMT</pubDate>
            <atom:updated>2025-07-25T19:01:49.747Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hHL-uF7ik58HPI3pi-bvqQ.png" /></figure><h4>Build an AI-Powered Data Processing Pipeline</h4><p>Have you ever wanted to supercharge your data processing with AI while working in a familiar pandas environment? Many data teams struggle with integrating advanced AI capabilities into their existing data workflows without compromising performance or requiring complex infrastructure changes.</p><p>Snowflake Cortex provides a solution by enabling seamless integration of powerful AI capabilities directly into Modin DataFrames within the unified Snowflake ecosystem.</p><p>In this blog, we’ll build an end-to-end data processing pipeline that loads product catalog data, applies various AI transformations using Cortex, and visualizes the results with Streamlit.</p><p>Readers will learn how to:</p><ul><li>Load and process data using Modin DataFrames for improved performance</li><li>Apply Cortex AI functions for text classification, translation, and sentiment analysis</li><li>Create interactive visualizations with Streamlit</li><li>Write and read data within the Snowflake ecosystem</li></ul><h3>1. Overview of Snowflake Cortex AI</h3><p>Before we dive deeper into specific AI functions, let’s take a moment to appreciate the comprehensive power of Snowflake Cortex AI. It’s not just a collection of functions; it’s a fully integrated ecosystem designed to bring advanced AI capabilities directly to your data, without the complexity of moving it.</p><p>This diagram illustrates the key components that make up Snowflake Cortex AI, showing how it supports everything from data ingestion and processing to model deployment and governance.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qK5Xow9hsk2w5WvA.png" /></figure><h3>2. Getting Started</h3><p>Before beginning, ensure you have:</p><ul><li>Access to a <a href="https://signup.snowflake.com/">Snowflake account</a></li><li>Basic familiarity with Python and pandas</li></ul><h3>3. Setup</h3><h4>Retrieve the Notebook</h4><p>Ready to dive in? To follow along with every step of this quickstart, you can click on <a href="https://github.com/Snowflake-Labs/snowflake-demo-notebooks/blob/main/Process-Modin-DataFrame-with-Cortex/Process-DataFrame-with-Modin-and-Cortex.ipynb">Process-DataFrame-with-Modin-and-Cortex.ipynb</a> to download the companion Notebook from GitHub.</p><h4>Required Packages</h4><p>Snowflake Notebooks comes pre-loaded with a fantastic array of common Python libraries for data science and machine learning, including numpy, pandas, and matplotlib. However, for this particular journey into AI-powered data processing, we&#39;ll need to bring in a few specialized tools:</p><ul><li>modin: Your secret weapon for scaling those familiar pandas operations to handle larger datasets with ease.</li><li>snowflake-ml-python: This is your gateway to unlocking the powerful Cortex LLM functions directly within your Python environment.</li><li>snowflake-snowpark-python: Essential for seamless interaction with Snowpark functionality, bridging your Python code with Snowflake&#39;s robust capabilities.</li></ul><p>Adding these packages is a breeze! Just head over to the Packages dropdown, located in the top right corner of your Snowflake Notebook interface, and add them there.</p><h4>Import Prerequisite Libraries</h4><p>Let’s start by importing the necessary libraries and establishing a connection to Snowflake:</p><pre># Import Python packages<br>import modin.pandas as pd<br>import snowflake.snowpark.modin.plugin<br><br># Connecting to Snowflake<br>from snowflake.snowpark.context import get_active_session<br>session = get_active_session()</pre><p>This code imports Modin’s pandas implementation and connects to your active Snowflake session.</p><h3>4. Load Data</h3><h4>Store Data into a Snowflake Stage</h4><p>Before we can unleash the power of AI on our data, we need a place for it to live within Snowflake. Think of a stage as a secure, internal landing zone for your external data.</p><p>We’ll create one to seamlessly bring in our product catalog data from an S3 bucket:</p><pre>CREATE OR REPLACE STAGE AVALANCHE<br>    URL = &#39;s3://sfquickstarts/misc/avalanche/csv/&#39;;</pre><p>You should see the following status message the stage is created successfully:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2BxiAdKnYFOkb205.png" /></figure><h4>List Stage Contents</h4><p>Just to be sure our data has landed safely and is ready for action, let’s quickly list the contents of our newly created stage. This helps us verify that everything is accessible before we proceed:</p><pre>ls @avalanche/</pre><p>This command should display the files available in the stage, including our target file product-catalog.csv.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-TQN0IBfseLIqb5t.png" /></figure><h4>Read CSV Data</h4><p>Now for the exciting part! We’ll read that CSV data directly into a Modin DataFrame. This is where your familiar pandas operations get a significant performance boost, thanks to Modin’s scalability.</p><pre>df = pd.read_csv(&quot;@avalanche/product-catalog.csv&quot;)<br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vVcH5qablZQhy9Tz.png" /></figure><p>Once loaded, your DataFrame will feature three key columns, ready for the forthcoming AI magic:</p><ul><li>name: Product name</li><li>description: Product description</li><li>price: Product price</li></ul><h3>5. Classify Text</h3><h4>Classify Text with Cortex</h4><p>This is where Snowflake Cortex truly shines! It offers powerful AI capabilities that you can apply directly to your data, transforming raw text into structured insights.</p><p>Let’s use the ClassifyText function to categorize our products:</p><pre>from snowflake.cortex import ClassifyText<br><br>df[&quot;label&quot;] = df[&quot;name&quot;].apply(ClassifyText, categories=[&quot;Apparel&quot;,&quot;Accessories&quot;])<br>df[&quot;label2&quot;] = df[&quot;description&quot;].apply(ClassifyText, categories=[&quot;Apparel&quot;,&quot;Accessories&quot;])<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*PSEMrHKKHL5tbGvM.gif" /></figure><p>Did you notice something interesting? We’re classifying products in two distinct ways: once based on the concise product name, and again using the more detailed product description.</p><p>This is a fantastic way to see how different inputs can lead to nuanced classification results, giving you a richer understanding of your data.</p><h4>Extract Classification Labels</h4><p>Cortex’s ClassifyText function returns its results as dictionaries, which is great for comprehensive output. But for our analysis, we just need the clean category values without the label keys. Let&#39;s quickly extract those values and then tidy up our DataFrame by dropping the intermediate columns:</p><pre>df[&quot;category&quot;] = df[&quot;label&quot;].apply(lambda x: x.get(&#39;label&#39;))<br>df[&quot;category2&quot;] = df[&quot;label2&quot;].apply(lambda x: x.get(&#39;label&#39;))<br><br>df.drop([&quot;label&quot;, &quot;label2&quot;], axis=1, inplace=True)<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*eZNm7udd6rxlAMhC.gif" /></figure><p>And just like that, we have beautifully clean category columns, perfectly ready for deeper analysis and visualization. No more manual sorting or tagging!</p><h3>6. Translate Text</h3><p>Snowflake Cortex makes language translation incredibly simple. Let’s leverage Cortex’s powerful Translate function to instantly localize our product information from English into German:</p><pre>from snowflake.cortex import Translate<br><br>df[&quot;name_de&quot;] = df[&quot;name&quot;].apply(Translate, from_language=&quot;en&quot;, to_language=&quot;de&quot;)<br>df[&quot;description_de&quot;] = df[&quot;description&quot;].apply(Translate, from_language=&quot;en&quot;, to_language=&quot;de&quot;)<br>df[&quot;category_de&quot;] = df[&quot;category&quot;].apply(Translate, from_language=&quot;en&quot;, to_language=&quot;de&quot;)<br>df[&quot;category2_de&quot;] = df[&quot;category2&quot;].apply(Translate, from_language=&quot;en&quot;, to_language=&quot;de&quot;)<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*Dc7SP_Fc8ZGnwgzi.gif" /></figure><p>With just a few lines of code, you can localize your entire product catalog, opening doors to new markets and ensuring your data speaks every language your business needs.</p><h3>7. Process Text</h3><h4>Analyze Sentiment</h4><p>Beyond classification and translation, Cortex offers even more sophisticated text capabilities. Let’s unlock deeper insights from our product descriptions, starting with understanding the emotions they convey.</p><p>Ever wondered how your product descriptions are perceived? Are they overwhelmingly positive, or do they carry a hint of negativity? Let’s use Cortex’s Sentiment function to assign a numerical score to each description, instantly revealing its emotional tone:</p><pre>from snowflake.cortex import Sentiment<br><br>df[&quot;sentiment_score&quot;] = df[&quot;description&quot;].apply(Sentiment)<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*Pu8NqzeTgEOOGwKJ.gif" /></figure><p>This sentiment score provides a powerful numerical value, giving you an immediate indication of the positivity or negativity embedded within each description. Imagine using this to quickly identify descriptions that might need a rewrite!</p><h4>Summarize Text</h4><p>Long descriptions can be overwhelming. What if you could get the gist of a product description in a single, concise sentence? Cortex’s Summarize function makes this a reality, helping you distill lengthy text into digestible summaries:</p><pre>from snowflake.cortex import Summarize<br><br>df[&quot;description_summary&quot;] = df[&quot;description&quot;].apply(Summarize)<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*PfpIL6Rct_KQ5shr.gif" /></figure><p>This is incredibly useful for quick reviews or for generating short snippets for other applications.</p><h4>Extract Specific Information</h4><p>Sometimes, you need to pull out very specific pieces of information from unstructured text. Cortex’s ExtractAnswer function acts like a smart assistant, answering questions directly from your text. Let&#39;s use it to identify the exact product mentioned in each name:</p><pre>from snowflake.cortex import ExtractAnswer<br><br>df[&quot;product&quot;] = df[&quot;name&quot;].apply(ExtractAnswer, question=&quot;What product is being mentioned?&quot;)<br>df[&quot;product&quot;] = [x[0][&quot;answer&quot;] for x in df[&#39;product&#39;]]<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*wHTvncGFk6yztopW.gif" /></figure><p>This demonstrates how you can use Cortex to extract structured information from unstructured text.</p><h3>8. Post-Process Data</h3><p>Our data has been enriched with powerful AI insights, but before we finalize it, a little post-processing goes a long way to ensure accurate and reliable subsequent data analysis and visualization.</p><h4>Clean Price Data</h4><p>Our price column currently contains dollar signs, which isn&#39;t ideal for numerical calculations. Let&#39;s quickly clean this up by removing the ‘$&#39; symbol and then converting the column to a proper numeric type. This ensures our financial data is ready for any mathematical operations or aggregations.</p><pre># For the price column, remove $ symbol and convert to numeric<br>df[&quot;price&quot;] = df[&quot;price&quot;].str.replace(&quot;$&quot;, &quot;&quot;, regex=False)<br>df[&quot;price&quot;] = pd.to_numeric(df[&quot;price&quot;])<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*S-6u3XhhFZyWpV0m.gif" /></figure><h4>Convert Column Types</h4><p>To maintain data integrity and ensure compatibility with various tools (especially when writing back to Snowflake), it’s good practice to standardize our column types. Let’s make sure all our text-based columns are explicitly set as string types, while leaving our numerical columns (like price and sentiment_score) as they are.</p><pre># Convert all other columns to the string type<br>for col_name in df.columns:<br>    if col_name != &quot;price&quot; and col_name != &quot;sentiment_score&quot;:<br>        df[col_name] = df[col_name].astype(str)<br><br>df</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*TjA65vE6n-YO0zf7.gif" /></figure><p>With these quick clean-up steps, our DataFrame is now perfectly structured and ready for its final destination!</p><h3>9. Data Operations</h3><p>Now that our data is transformed, enriched, and polished, it’s time to persist these valuable insights. The beauty of working within the Snowflake ecosystem is the seamless ability to write your processed data directly back into a Snowflake table, making it available for countless other applications and analyses.</p><h4>Write to a Snowflake Table</h4><p>Let’s write our processed DataFrame to a Snowflake table:</p><pre>df.to_snowflake(&quot;avalanche_products&quot;, if_exists=&quot;replace&quot;, index=False)</pre><h4>Read Data with SQL</h4><p>Let’s quickly confirm your data is there and looks as expected. We can query our new table using the following SQL query:</p><pre>SELECT * FROM CHANINN_DEMO_DATA.PUBLIC.AVALANCHE_PRODUCTS</pre><h4>Read Data with Python</h4><p>And of course, if you ever need to pull this data back into a DataFrame for further Python-based analysis or application development, it’s just as straightforward:</p><pre>pd.read_snowflake(&quot;avalanche_products&quot;)</pre><h3>9. Build a Streamlit Dashboard</h3><p>What’s the point of all this incredible AI-powered data processing if you can’t easily share and interact with the insights? This is where Streamlit steps in, allowing you to transform your data into a beautiful, interactive web application with just a few lines of Python code. Let’s build a simple yet powerful dashboard to visualize our newly enriched product data!</p><pre>import streamlit as st<br><br>df = pd.read_snowflake(&quot;avalanche_products&quot;)<br><br>st.header(&quot;Product Category Distribution&quot;)<br><br># Selectbox for choosing the category column<br>selected_category_column = st.selectbox(<br>    &quot;Select Category Type:&quot;,<br>    (&quot;category&quot;, &quot;category2&quot;)<br>)<br><br># Count the occurrences of each category based on the selected column<br>category_counts = df[selected_category_column].value_counts().reset_index()<br>category_counts.columns = [&#39;Category&#39;, &#39;Count&#39;]<br><br>st.bar_chart(category_counts, x=&#39;Category&#39;, y=&#39;Count&#39;, color=&#39;Category&#39;)<br><br>st.header(&quot;Product Sentiment Analysis&quot;)<br><br># Calculate metrics<br>st.write(&quot;Overall Sentiment Scores:&quot;)<br><br>cols = st.columns(4)<br><br>with cols[0]:<br>    st.metric(&quot;Mean Sentiment&quot;, df[&#39;sentiment_score&#39;].mean() )<br>with cols[1]:<br>    st.metric(&quot;Min Sentiment&quot;, df[&#39;sentiment_score&#39;].min() )<br>with cols[2]:<br>    st.metric(&quot;Max Sentiment&quot;, df[&#39;sentiment_score&#39;].max() )<br>with cols[3]:<br>    st.metric(&quot;Standard Deviation&quot;, df[&#39;sentiment_score&#39;].std() )<br><br># Create a bar chart showing sentiment scores for all products<br>st.write(&quot;Individual Product Sentiment Scores:&quot;)<br>option = st.selectbox(&quot;Color bar by&quot;, (&quot;name&quot;, &quot;sentiment_score&quot;))<br>st.bar_chart(df[[&#39;name&#39;, &#39;sentiment_score&#39;]], x=&#39;name&#39;, y=&#39;sentiment_score&#39;, color=option)</pre><p>And there you have it! This intuitive Streamlit app instantly provides:</p><p>1. Dynamic Category Insights: A clear bar chart showcasing the distribution of product categories, with the flexibility to switch between classification methods.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*vtC-ToDaBFzGrBPT.gif" /></figure><p>2. At-a-Glance Sentiment Metrics: Key statistical metrics that summarize the overall sentiment across your product descriptions.</p><p>3. Granular Sentiment Visualization: A bar chart that lets you explore the sentiment score for each individual product, helping you pinpoint outliers or trends.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*CGtHRRxL41FUv0Ru.gif" /></figure><p>This isn’t just a visualization; it’s an interactive AI-powered data app that empower users to perform self-serve analytics!</p><h3>Conclusion And Resources</h3><p>Congratulations!</p><p>You’ve not just followed a tutorial; you’ve successfully engineered a powerful, end-to-end data processing pipeline. You’ve harnessed the scalability of Modin DataFrames and the cutting-edge AI capabilities of Snowflake Cortex to transform raw data into actionable intelligence. From loading external data to applying sophisticated AI transformations like classification, translation, sentiment analysis, and text summarization, you’ve done it all. And to top it off, you’ve brought your insights to life with a dynamic, interactive Streamlit dashboard!</p><p>This quickstart truly showcases the immense power and seamless integration of the Snowflake ecosystem. You’ve seen firsthand how you can perform sophisticated data processing and advanced AI operations without ever needing to move your data outside the platform. This isn’t just about convenience; it’s about unlocking unparalleled performance, robust security, and a streamlined workflow for your data projects.</p><h4>What You Learned</h4><ul><li>Loaded data from an S3 bucket into a Snowflake stage</li><li>Processed data using Modin DataFrames for improved performance</li><li>Applied Cortex AI functions for text classification, translation, and sentiment analysis</li><li>Extracted structured information from unstructured text</li><li>Created an interactive dashboard with Streamlit</li><li>Wrote and read data within the Snowflake ecosystem</li></ul><h4>Related Resources</h4><p>Want to dive deeper or explore related topics? Check out these valuable resources:</p><p><strong>Articles:</strong></p><ul><li><a href="https://docs.snowflake.com/en/developer-guide/snowpark/python/pandas-on-snowflake">pandas on Snowflake</a></li><li><a href="https://docs.snowflake.com/en/developer-guide/snowpark/python/pandas-on-snowflake#using-snowflake-cortex-llm-functions-with-snowpark-pandas">Using Snowflake Cortex LLM functions with Snowpark pandas</a></li><li><a href="https://www.snowflake.com/en/product/features/cortex/">Snowflake Cortex AI</a></li></ul><p><strong>Documentation:</strong></p><ul><li><a href="https://docs.snowflake.com/">Snowflake Documentation</a></li><li><a href="https://docs.streamlit.io/">Streamlit Documentation</a></li><li><a href="https://modin.readthedocs.io/">Modin Documentation</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c8e7b694eb16" width="1" height="1" alt=""><hr><p><a href="https://medium.com/snowflake/developers-guide-to-modin-and-snowflake-cortex-c8e7b694eb16">Developer’s Guide to Modin and Snowflake Cortex</a> was originally published in <a href="https://medium.com/snowflake">Snowflake Builders Blog: Data Engineers, App Developers, AI, &amp; Data Science</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Developer’s Guide to Snowflake Cortex Agent]]></title>
            <link>https://medium.com/snowflake/developers-guide-to-snowflake-cortex-agent-46b52ea4aceb?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/46b52ea4aceb</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[snowflake]]></category>
            <category><![CDATA[data]]></category>
            <category><![CDATA[data-analytics]]></category>
            <category><![CDATA[llm]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Fri, 13 Jun 2025 15:20:47 GMT</pubDate>
            <atom:updated>2025-06-13T15:20:47.035Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EphHxftJnbUB4LZID2MgPg.png" /></figure><p>Ever wondered how to make your enterprise data work smarter, not just harder? Snowflake is stepping up its game in enterprise AI with <strong>Snowflake Intelligence</strong>. You can think of it as a powerful platform that empowers developers to build clever data agents that can analyze, summarize, and even take action on your company’s valuable data.</p><p>It’s all built on Snowflake’s robust data foundation and AI services powered by <strong>Cortex AI</strong>. This fully managed AI engine provides enterprise-grade data agents that not only streamline your workflows but also rigorously protect your data integrity and intellectual property. Inside Cortex AI, you’ll find tools like <strong>Cortex Search</strong> for diving into unstructured data and <strong>Cortex Analyst</strong> for querying your structured datasets.</p><p>At its heart, a <strong>Snowflake Cortex Agent</strong> is your personal AI data assistant. It’s engineered to automate those complex data workflows and unlock hidden business insights through natural, conversational interactions.</p><p>The really cool part? It uses an <strong>agentic AI</strong> paradigm. This means that it can plan and execute multi-step processes, intelligently pulling from diverse data sources and wielding various AI tools to fulfill your requests. Just to be clear, agentic AI refers to an AI system’s ability to make decisions, perform tasks, and adapt to its environment without constant human intervention, thereby leading to automation of a wider range of tasks with minimal supervision. So, whether you’re dealing with structured Snowflake tables or unstructured PDFs in object storage, the agent brings it all together to give you unified and comprehensive answers.</p><h3>Overview of Cortex AI</h3><p>Here’s a visual representation of the Snowflake Cortex AI ecosystem, illustrating its architectural components and capabilities. The diagram systematically organizes the platform’s features into key functional areas: Agents &amp; Insights, core Processing &amp; Retrieval mechanisms, diverse Data sources, integrated AI Models, and comprehensive Governance frameworks. This overview highlights how Snowflake Cortex AI provides a unified environment for developing and managing AI-powered data solutions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-Yd-Mf2kjyythwsC" /></figure><h3><strong>What an AI Agent Brings to Your Business Intelligence</strong></h3><p>Ready to see how an AI Agent can transform your BI? Here are some core advantages:</p><ul><li><strong>Self-serve data exploration:</strong> Imagine generating charts and getting instant answers just by asking natural language questions. No more waiting for custom dashboards or deep technical expertise. This capability is all about cutting down on data request bottlenecks and maximizing how you utilize your data across the organization.</li><li><strong>Democratized intelligence:</strong> This agent grants you access to and analysis of thousands of data sources simultaneously. It’s a game-changer for transforming scattered information into clear, actionable business insights for everyone.</li><li><strong>Contextual deep analytical research:</strong> This isn’t just surface-level stuff. The agent uses advanced reasoning and analytical methods across both structured and unstructured data. It tackles complex queries head-on, delivering truly comprehensive insights crucial for strategic decision-making.</li></ul><h3><strong>Breaking Down Data Silos</strong></h3><p>One of the biggest headaches in business? Data silos.</p><p>A Snowflake Cortex Agent is here to help consolidate your enterprise knowledge:</p><ul><li><strong>Comprehensive integration:</strong> It seamlessly analyzes structured and unstructured data together. Think about connecting insights from spreadsheets, documents, images, and databases all at once. This helps you build a holistic, 360-degree view of your entire business ecosystem.</li><li><strong>Enterprise-wide knowledge sharing:</strong> The agent makes it easier for everyone to access and utilize company knowledge across all departments. This means transforming isolated information into actionable intelligence that benefits the whole organization.</li></ul><p>Under the hood, a Cortex Agent integrates several technical capabilities to power its intelligent functionalities:</p><ul><li><strong>Tool Utilization:</strong> It’s smart enough to pick the right tool for the job. This includes specialized tools like Cortex Analyst for generating SQL queries and Cortex Search for semantic searches within text data.</li><li><strong>Large Language Models (LLMs):</strong> These are the brains behind its reasoning. LLMs help the agent understand and process your complex natural language requests.</li><li><strong>Multi-step Reasoning:</strong> Got a tricky request? The agent can break it down into smaller, manageable sub-tasks. It even handles clarifications, showing a sophisticated, step-by-step problem-solving approach.</li></ul><h3><strong>Security by Design: Trusted Agent Framework</strong></h3><p>Security is non-negotiable, right? The Snowflake Cortex Agent operates within a robust framework where security is a fundamental principle, ensuring compliant and reliable operations:</p><ul><li><strong>Automatic security:</strong> Good news here! Your existing Snowflake security controls, including role-based access and data masking, automatically apply to all AI interactions and conversations. This means users only ever see answers based on their defined access permissions.</li><li><strong>Complete transparency:</strong> Ever wonder how an AI got to an answer? With a Cortex Agent, you can trace data sources, validate insights, and understand the derivation process, bringing full explainability to the forefront.</li><li><strong>Centralized control:</strong> All permissions are managed centrally through Snowflake. Plus, you get integrated usage monitoring and relevance tracking functionalities for continuous operational oversight.</li></ul><h3><strong>Real-World Scenarios: Use Cases for a Cortex Agent</strong></h3><p>The Snowflake Cortex Agent is super versatile and can be applied across a wide range of business scenarios. Here are a few examples:</p><ul><li><strong>Executive Decision Support:</strong> Need quick summaries from sales, finance, or audit reports? The agent can compile them to support executive decision-making processes.</li><li><strong>Financial Services:</strong> Imagine getting comprehensive client insights by pulling and analyzing data from claims databases, customer correspondence logs, and more.</li><li><strong>Healthcare and Life Sciences:</strong> Researchers can get a huge boost by having the agent aggregate data on adverse reactions and scan extensive medical literature.</li><li><strong>Operational Automation:</strong> It’s not just for insights! The agent can automate routine operational tasks, like detecting anomalies and sending automated notifications to the right teams.</li></ul><p>So, in a nutshell, a Snowflake Cortex Agent is designed to supercharge your data-driven operations. It provides intelligent, automated assistance for data analysis and information retrieval across industries, all while prioritizing security and transparency.</p><h3><strong>The Cortex Agent Workflow: Four Core Components</strong></h3><p>Understanding how a Cortex Agent operates internally helps appreciate its sophisticated approach to handling complex data requests. The workflow consists of four essential components that work together to deliver intelligent responses:</p><ol><li><strong>Planning</strong> forms the foundation of every interaction. When you ask a question, the agent doesn’t just jump to an answer — it first analyzes your request to understand what type of data sources are needed. Whether you’re asking about top distributors by revenue (structured data) or inquiring about contract details (unstructured documents), the agent orchestrates a comprehensive plan to tackle your query systematically.</li><li><strong>Tool Use</strong> is where the real work happens. Armed with a clear plan, the agent selects and deploys the right tools for the job. Cortex Search dives into unstructured sources like documents and PDFs, while Cortex Analyst generates precise SQL queries for your structured datasets. This dual capability ensures no data source is left untapped in finding your answer.</li><li><strong>Reflection</strong> ensures accuracy and completeness. After each tool execution, the agent evaluates the results to determine next steps. It might ask for clarification, iterate on the approach, or synthesize information from multiple sources before generating the final response. This self-assessment capability prevents incomplete or inaccurate answers from reaching you.</li><li><strong>Monitor and Iterate</strong> extends beyond individual queries to continuous improvement. Once deployed, the system tracks performance metrics and refines behavior based on real-world usage patterns. This ongoing optimization means your agent becomes more effective over time, learning from interactions while maintaining strict security and compliance standards.</li></ol><h3><strong>Utilizing the Snowflake Cortex Agent API</strong></h3><p>Developers, listen up! The Cortex Agent REST API simplifies building interactive chat applications by giving you a direct interface for agent interaction. Here’s a quick look at how it works:</p><p><strong>Request Structure: </strong>To interact with a Cortex Agent via its API, developers construct a POST request containing specific parameters that define the conversation and desired actions.</p><ul><li><strong>Endpoint:</strong> You’ll send POST requests to &lt;account_url&gt;/api/v2/cortex/agent:run.</li><li><strong>Headers:</strong> Don’t forget your authorization token for authentication and setting application/json as your Content-Type.</li><li><strong>Request Body:</strong> This is where you tell the agent what you need. Include parameters like the model name, specific response instructions, experimental flags, a list of available tools, tool-specific resources, tool selection configuration, and your conversational message history.</li></ul><p><strong>Supported Tool Types:</strong> The API allows the agent to call various tools to get things done, covering a wide range of functionalities:</p><ul><li>cortex_search: Great for semantic search operations.</li><li>cortex_analyst_text_to_sql: Perfect for turning natural language questions into SQL queries.</li><li>sql_exec: For executing SQL commands directly.</li><li>data_to_chart: If you need to generate data visualizations. Each tool type comes with its own configuration options.</li></ul><p><strong>Response Handling:</strong> The agent’s response can be anything from plain text to charts or tables. Plus, the API supports streaming via Server-Sent Events (SSE). This means you get incremental message chunks or error events in real-time, making your applications feel snappier and more dynamic.</p><p>This API is your gateway to seamlessly integrating Snowflake Cortex Agent capabilities into your custom applications, letting you build truly powerful conversational AI experiences.</p><h3>Building a Cortex Agent App</h3><p>Check out this demo app created by Anna Filippova showing how to integrate the Cortex Agent API into a Streamlit app. This app features a chat interface where business users can ask natural language questions about sales information.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*wVRlbq_zP9Uq9Qno" /></figure><p>What makes this implementation particularly elegant is how the agent automatically determines whether to query structured sales databases or search through unstructured conversation transcripts, removing the complexity of data source selection from the user.</p><p>Here’s the entire Python in 170 lines of code:</p><pre>import json<br>import requests<br>import streamlit as st<br>import snowflake.connector<br>import sseclient <br><br><br># replace these values in your .streamlit.toml file, not here!<br>HOST = st.secrets[&quot;snowflake&quot;][&quot;host&quot;]<br>ACCOUNT = st.secrets[&quot;snowflake&quot;][&quot;account&quot;]<br>USER =st.secrets[&quot;snowflake&quot;][&quot;user&quot;]<br>PASSWORD = st.secrets[&quot;snowflake&quot;][&quot;password&quot;]<br>ROLE = st.secrets[&quot;snowflake&quot;][&quot;role&quot;]<br>WAREHOUSE= &quot;SALES_INTELLIGENCE_WH&quot;<br><br># variables shared across pages<br><br>AGENT_API_ENDPOINT = &quot;/api/v2/cortex/agent:run&quot;<br>API_TIMEOUT = 50000  # in milliseconds<br><br>CORTEX_SEARCH_SERVICES = &quot;sales_intelligence.data.sales_conversation_search&quot;<br>SEMANTIC_MODELS = &quot;@sales_intelligence.data.models/sales_metrics_model.yaml&quot; <br><br>def run_snowflake_query(query):<br>    try:<br>        df = session.sql(query.replace(&#39;;&#39;,&#39;&#39;))<br>        <br>        return df<br><br>    except Exception as e:<br>        st.error(f&quot;Error executing SQL: {str(e)}&quot;)<br>        return None, None<br><br>def agent_api_call(query: str, limit: int = 10):<br><br>    text = &quot;&quot;<br>    sql = &quot;&quot;<br>    citations = []<br>    <br>    payload = {<br>        &quot;model&quot;: &quot;llama3.1-70b&quot;,<br>        &quot;messages&quot;: [<br>            {<br>                &quot;role&quot;: &quot;user&quot;,<br>                &quot;content&quot;: [<br>                    {<br>                        &quot;type&quot;: &quot;text&quot;,<br>                        &quot;text&quot;: query<br>                    }<br>                ]<br>            }<br>        ],<br>        &quot;tools&quot;: [<br>            {<br>                &quot;tool_spec&quot;: {<br>                    &quot;type&quot;: &quot;cortex_analyst_text_to_sql&quot;,<br>                    &quot;name&quot;: &quot;analyst1&quot;<br>                }<br>            },<br>            {<br>                &quot;tool_spec&quot;: {<br>                    &quot;type&quot;: &quot;cortex_search&quot;,<br>                    &quot;name&quot;: &quot;search1&quot;<br>                }<br>            }<br>        ],<br>        &quot;tool_resources&quot;: {<br>            &quot;analyst1&quot;: {&quot;semantic_model_file&quot;: SEMANTIC_MODELS},<br>            &quot;search1&quot;: {<br>                &quot;name&quot;: CORTEX_SEARCH_SERVICES,<br>                &quot;max_results&quot;: limit<br>            }<br>        }<br>    }<br>    <br>    resp = requests.post(<br>            url=f&quot;https://{HOST}&quot;+AGENT_API_ENDPOINT,<br>            json=payload,<br>            headers={<br>                &quot;Authorization&quot;: f&#39;Snowflake Token=&quot;{st.session_state.CONN.rest.token}&quot;&#39;,<br>                &quot;Content-Type&quot;: &quot;application/json&quot;,<br>            }<br>        )<br><br><br>    if resp.status_code &lt; 400: <br>        client = sseclient.SSEClient(resp)<br><br>        for event in client.events():<br>            try: <br>                parsed = json.loads(event.data)<br><br>                try: <br>                    if parsed[&#39;delta&#39;][&#39;content&#39;][0][&#39;type&#39;] == &#39;text&#39;: <br>                        text = parsed[&#39;delta&#39;][&#39;content&#39;][0][&#39;text&#39;]<br>                        yield text<br>     <br>                    elif parsed[&#39;delta&#39;][&#39;content&#39;][0][&#39;type&#39;] == &#39;tool_use&#39;: <br>                        text = parsed[&#39;delta&#39;][&#39;content&#39;][1][&#39;tool_results&#39;][&#39;content&#39;][0][&#39;json&#39;][&#39;text&#39;]<br>                        sql = parsed[&#39;delta&#39;][&#39;content&#39;][1][&#39;tool_results&#39;][&#39;content&#39;][0][&#39;json&#39;][&#39;sql&#39;]<br>                        yield text<br>                        yield &quot;\n\n `&quot; + sql + &quot;`&quot; <br><br>                    else: <br>                        text = parsed<br>                        yield text<br><br><br>                except:<br>                    continue<br>            except:<br>                continue<br><br>def main():<br><br>    with st.sidebar:<br>        if st.button(&quot;Reset Conversation&quot;, key=&quot;new_chat&quot;):<br>            st.session_state.messages = []<br>            st.rerun()<br><br>    st.title(&quot;Intelligent Sales Assistant&quot;)<br><br>    # connection<br>    if &#39;CONN&#39; not in st.session_state or st.session_state.CONN is None:<br><br>        try: <br>            st.session_state.CONN = snowflake.connector.connect(<br>                user=USER,<br>                password=PASSWORD,<br>                account=ACCOUNT,<br>                host=HOST,<br>                port=443,<br>                role=ROLE,<br>                warehouse=WAREHOUSE<br>            )  <br>            st.info(&#39;Snowflake Connection established!&#39;, icon=&quot;💡&quot;)    <br>        except:<br>            st.error(&#39;Connection not established. Check that you have correctly entered your Snowflake credentials!&#39;, icon=&quot;🚨&quot;)    <br><br><br><br>    #try: <br>    #  Initialize session state<br>    if &#39;messages&#39; not in st.session_state:<br>        st.session_state.messages = []<br><br>    for message in st.session_state.messages:<br>        with st.chat_message(message[&#39;role&#39;]):<br>            st.markdown(message[&#39;content&#39;].replace(&quot;•&quot;, &quot;\n\n-&quot;))<br><br>    if user_input := st.chat_input(&quot;What is your question?&quot;):<br><br>            # Add user message to chat       <br>            with st.chat_message(&quot;user&quot;):<br>                st.markdown(user_input)<br>                st.session_state.messages.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: user_input})<br><br>            # Get response from API<br>            with st.spinner(&quot;Processing your request...&quot;):<br>                <br>                response = agent_api_call(user_input, 1)<br>                text = st.write(response)<br><br>                # Add assistant response to chat<br>                if text:<br>                    st.session_state.messages.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: text})<br><br>      <br>if __name__ == &quot;__main__&quot;:<br>    main()</pre><p>If you’d like to try it out for yourself, here’s the GitHub repo:</p><p><a href="https://github.com/annafil/cortex-agent-api-demo/">GitHub - annafil/cortex-agent-api-demo</a></p><h3>Conclusion</h3><p>Snowflake Cortex Agents represent a fundamental shift in how enterprises interact with their data, transforming complex analytics from a technical barrier into natural conversations that any business user can navigate. By combining powerful AI capabilities with enterprise-grade security, these agents don’t just democratize data access — they turn your entire organization’s knowledge into a competitive advantage.</p><h3><strong>Dive Deeper with these Essential Resources</strong></h3><p>Ready to get your hands dirty and explore more? These resources are your next stop for understanding and implementing Snowflake Cortex Agents:</p><p>YouTube video:</p><ul><li><a href="https://www.youtube.com/watch?v=SDqyB-yWaAE">Getting started with Cortex Agents</a></li></ul><p><strong>Docs and Articles:</strong></p><ul><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents">Snowflake Cortex Agents Documentation</a></li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api">Snowflake Cortex Agents REST API Documentation</a></li><li><a href="https://medium.com/snowflake/the-future-of-data-science-how-ai-agents-are-revolutionizing-ml-development-ea402ca582b3">The Future of Data Science: How AI Agents are Revolutionizing ML Development (Medium)</a></li></ul><p><strong>GitHub Repos and Quickstarts Tutorials:</strong></p><ul><li><a href="https://github.com/annafil/cortex-agent-api-demo/">Cortex Agent API Demo (GitHub)</a></li><li><a href="https://quickstarts.snowflake.com/guide/getting_started_with_cortex_agents/index.html?index=../..index#0">Getting Started with Cortex Agents (Snowflake Quickstart)</a></li><li><a href="https://quickstarts.snowflake.com/guide/getting_started_with_snowflake_agents_api_and_react/index.html?index=../..index#0">Getting Started with Snowflake Agents API and React (Snowflake Quickstart)</a></li><li><a href="https://quickstarts.snowflake.com/guide/integrate_snowflake_cortex_agents_with_slack/index.html#0">Integrate Snowflake Cortex Agents with Slack (Snowflake Quickstart)</a></li><li><a href="https://quickstarts.snowflake.com/guide/integrate_snowflake_cortex_agents_with_microsoft_teams/index.html?index=..%2F..index#0">Integrate Snowflake Cortex Agents with Microsoft Teams (Snowflake Quickstart)</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=46b52ea4aceb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/snowflake/developers-guide-to-snowflake-cortex-agent-46b52ea4aceb">Developer’s Guide to Snowflake Cortex Agent</a> was originally published in <a href="https://medium.com/snowflake">Snowflake Builders Blog: Data Engineers, App Developers, AI, &amp; Data Science</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started with Snowflake Semantic View]]></title>
            <link>https://medium.com/snowflake/getting-started-with-snowflake-semantic-view-7eced29abe6f?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/7eced29abe6f</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[semantic-view]]></category>
            <category><![CDATA[snowflake]]></category>
            <category><![CDATA[semantic-model]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Wed, 11 Jun 2025 04:15:49 GMT</pubDate>
            <atom:updated>2025-07-10T20:48:12.809Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P5D7-4Lj9gryZ7jmR9qhzQ.png" /></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FV6RshK2twis%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DV6RshK2twis&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FV6RshK2twis%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1f2f1e7df6de41db2744ffb0d7b1978/href">https://medium.com/media/f1f2f1e7df6de41db2744ffb0d7b1978/href</a></iframe><h3>Overview</h3><p>AI-powered Business Intelligence (BI) and conversational analytics hold immense promise for data-driven decision-making. However, directly applying these technologies to complex enterprise schemas often leads to inaccurate or inconsistent results, commonly referred to as “hallucinations.” This challenge arises because AI and BI systems may struggle to interpret raw data without a clear understanding of the organizational context and definitions.</p><p>Snowflake addresses these challenges by introducing Semantic Views, a new schema-level object that stores all semantic model information natively within the database. Semantic views capture and store semantic model information directly within the database, including business-relevant concepts such as metrics (<em>e.g.,</em> total sales), dimensions (<em>e.g.,</em> product category), and facts.</p><h4>What You’ll Learn</h4><ul><li>How to setup a database and schema in Snowflake</li><li>How to create views from existing sample data</li><li>The process of defining a Snowflake semantic view with tables, relationships, dimensions, and metrics</li><li>How to query a semantic view</li><li>How semantic views enhance AI-powered analytics and consistency across BI tools</li></ul><h4>What You’ll Build</h4><p>You will build a foundational understanding and practical setup of a Snowflake semantic view, complete with data views and a defined semantic model, enabling simplified and consistent data querying for BI and AI applications using TPC-DS sample data.</p><h4>What You’ll Need</h4><ul><li>Access to a <a href="https://signup.snowflake.com/">Snowflake account</a></li><li>Basic knowledge of SQL and Python</li><li>Familiarity with data analysis concepts</li><li>Access to ACCOUNTADMIN role is required for creating semantic views)</li><li>Access to the SNOWFLAKE_SAMPLE_DATA database</li></ul><h3>Understand Semantic Views</h3><h4>What is a Semantic View?</h4><p>A semantic view acts as a translator between your raw data and how humans or AI interpret it. It defines key business concepts like “metrics” (<em>e.g.,</em> total sales) and “dimensions” (<em>e.g.,</em> customer location) by referencing your underlying tables and their relationships.</p><h4>Why Semantic Views Matter</h4><p>Semantic views are crucial for several reasons:</p><ul><li>Ensures AI and BI consistency: By embedding organizational context and definitions directly into the data layer, semantic views ensure that both AI and BI systems interpret information uniformly, leading to trustworthy answers.</li><li>Enables AI-powered analytics: They make data “AI-ready,” unlocking advanced use cases such as conversational analytics and significantly reducing the risk of AI hallucinations.</li><li>Maintains consistency across BI Tools: Semantic models are shifted from individual BI tool layers to the core data platform, guaranteeing that all tools utilize the same semantic concepts.</li><li>Unlocks rich analytical capabilities: Semantic views power diverse user interfaces, including AI-powered analytics, traditional BI clients, Streamlit applications, and custom applications.</li></ul><h4>Basic Elements of a Semantic View Definition</h4><p>Every semantic view definition requires essential elements:</p><ul><li>Physical model objects: These refer to your existing tables, views, or (in future releases) SQL queries that contain the raw data.</li><li>Relationships: These define how your physical objects connect to each other (<em>e.g.,</em> a CUSTOMER table linked to an ORDERS table).</li><li>Dimensions: These are business-friendly attributes used to group or filter your data (<em>e.g.,</em> customer’s birth year, product category).</li><li>Metrics: These are business-friendly calculations or aggregations, often representing Key Performance Indicators (KPIs) (<em>e.g.,</em> total sales price, total sales quantity).</li></ul><h3>Setup Environment</h3><h4>Download the Notebook</h4><p>Firstly, to follow along with this quickstart, you can click on <a href="https://github.com/Snowflake-Labs/snowflake-demo-notebooks/blob/main/Snowflake_Semantic_View/getting-started-with-snowflake-semantic-view.ipynb">getting-started-with-snowflake-semantic-view.ipynb</a> to download the Notebook from GitHub.</p><p>Snowflake Notebooks come pre-installed with common Python libraries for data science and machine learning, such as numpy, pandas, matplotlib, and more! If you are looking to use other packages, click on the Packages dropdown on the top right to add additional packages to your notebook.</p><h4>Setup your Database and Schema</h4><p>First, we’ll create a new database named SAMPLE_DATA and a schema named TPCDS_SF10TCL to organize our data. We will then set the context to use this new schema.</p><pre>-- Create a new test database named SAMPLE_DATA<br>CREATE DATABASE SAMPLE_DATA;<br><br>-- Use the newly created database<br>USE DATABASE SAMPLE_DATA;<br><br>-- Create a new schema named TPCDS_SF10TCL within SAMPLE_DATA<br>CREATE SCHEMA TPCDS_SF10TCL;<br><br>-- Set the context to use the new schema<br>USE SCHEMA TPCDS_SF10TCL;</pre><h3>Create Views from Sample Data</h3><p>Next, we’ll create views for the tables we want to analyze. These views will be based on the SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL dataset, allowing us to work with a subset of the data without modifying the original tables.</p><pre>-- Create or replace views for the tables from SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL<br>CREATE OR REPLACE VIEW CUSTOMER AS<br>SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.CUSTOMER;<br><br>CREATE OR REPLACE VIEW CUSTOMER_DEMOGRAPHICS AS<br>SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.CUSTOMER_DEMOGRAPHICS;<br><br>CREATE OR REPLACE VIEW DATE_DIM AS<br>SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.DATE_DIM;<br><br>CREATE OR REPLACE VIEW ITEM AS<br>SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.ITEM;<br><br>CREATE OR REPLACE VIEW STORE AS<br>SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.STORE;<br><br>CREATE OR REPLACE VIEW STORE_SALES AS<br>SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.STORE_SALES;</pre><h4>Verify your Environment Setup</h4><p>Before proceeding, let’s ensure our warehouse, database, and schema are correctly set, and then list the views we just created.</p><pre>-- Select the warehouse, database, and schema<br>USE WAREHOUSE COMPUTE_WH;<br>USE DATABASE SAMPLE_DATA;<br>USE SCHEMA TPCDS_SF10TCL;<br><br>-- Show all views in the current schema to verify creation<br>SHOW VIEWS;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*GxEQ3ap_xVW4igde.png" /></figure><p><em>Note:</em></p><ul><li>Ensure you have the ACCOUNTADMIN role to create semantic views</li><li>Verify that all views are created successfully before proceeding to the next step</li></ul><h3>Create the Semantic View</h3><h4>Define the Semantic View</h4><p>We’ll start by switching to the ACCOUNTADMIN role:</p><pre>-- Switch to ACCOUNTADMIN role to create the semantic view<br>USE ROLE ACCOUNTADMIN;</pre><p>Now, we’ll define our TPCDS_SEMANTIC_VIEW_SM semantic view. This view will establish relationships between our tables, define facts (measures), and dimensions (attributes), making it easier to query and analyze our data without complex joins.</p><pre>-- Create or replace the semantic view named TPCDS_SEMANTIC_VIEW_SM<br>CREATE OR REPLACE SEMANTIC VIEW TPCDS_SEMANTIC_VIEW_SM<br> tables (<br>  CUSTOMER primary key (C_CUSTOMER_SK),<br>  DATE as DATE_DIM primary key (D_DATE_SK),<br>  DEMO as CUSTOMER_DEMOGRAPHICS primary key (CD_DEMO_SK),<br>  ITEM primary key (I_ITEM_SK),<br>  STORE primary key (S_STORE_SK),<br>  STORESALES as STORE_SALES<br>        primary key (SS_SOLD_DATE_SK,SS_CDEMO_SK,SS_ITEM_SK,SS_STORE_SK,SS_CUSTOMER_SK)<br> )<br> relationships (<br>  SALESTOCUSTOMER as STORESALES(SS_CUSTOMER_SK) references CUSTOMER(C_CUSTOMER_SK),<br>  SALESTODATE as STORESALES(SS_SOLD_DATE_SK) references DATE(D_DATE_SK),<br>  SALESTODEMO as STORESALES(SS_CDEMO_SK) references DEMO(CD_DEMO_SK),<br>  SALESTOITEM as STORESALES(SS_ITEM_SK) references ITEM(I_ITEM_SK),<br>  SALETOSTORE as STORESALES(SS_STORE_SK) references STORE(S_STORE_SK)<br> )<br> facts (<br>  ITEM.COST as i_wholesale_cost,<br>  ITEM.PRICE as i_current_price,<br>  STORE.TAX_RATE as S_TAX_PRECENTAGE<br> )<br> dimensions (<br>  CUSTOMER.BIRTHYEAR as C_BIRTH_YEAR,<br>  CUSTOMER.COUNTRY as C_BIRTH_COUNTRY,<br>  CUSTOMER.C_CUSTOMER_SK as c_customer_sk,<br>  DATE.DATE as D_DATE,<br>  DATE.D_DATE_SK as d_date_sk,<br>  DATE.MONTH as D_MOY,<br>  DATE.WEEK as D_WEEK_SEQ,<br>  DATE.YEAR as D_YEAR,<br>  DEMO.CD_DEMO_SK as cd_demo_sk,<br>  DEMO.CREDIT_RATING as CD_CREDIT_RATING,<br>  DEMO.MARITAL_STATUS as CD_MARITAL_STATUS,<br>  ITEM.BRAND as I_BRAND,<br>  ITEM.CATEGORY as I_CATEGORY,<br>  ITEM.CLASS as I_CLASS,<br>  ITEM.I_ITEM_SK as i_item_sk,<br>  STORE.MARKET as S_MARKET_ID,<br>  STORE.SQUAREFOOTAGE as S_FLOOR_SPACE,<br>  STORE.STATE as S_STATE,<br>  STORE.STORECOUNTRY as S_COUNTRY,<br>  STORE.S_STORE_SK as s_store_sk,<br>  STORESALES.SS_CDEMO_SK as ss_cdemo_sk,<br>  STORESALES.SS_CUSTOMER_SK as ss_customer_sk,<br>  STORESALES.SS_ITEM_SK as ss_item_sk,<br>  STORESALES.SS_SOLD_DATE_SK as ss_sold_date_sk,<br>  STORESALES.SS_STORE_SK as ss_store_sk<br> )<br> metrics (<br>  STORESALES.TOTALCOST as SUM(item.cost),<br>  STORESALES.TOTALSALESPRICE as SUM(SS_SALES_PRICE),<br>  STORESALES.TOTALSALESQUANTITY as SUM(SS_QUANTITY)<br>            WITH SYNONYMS = ( &#39;total sales quantity&#39;, &#39;total sales amount&#39;)<br> )<br>;</pre><h4>Verify the Semantic View Creation</h4><p>Let’s confirm that our semantic view has been successfully created by listing all semantic views in the current database.</p><pre>-- Lists semantic views in the database that is currently in use<br>SHOW SEMANTIC VIEWS;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vRqcyAj6XO-rl3ex.png" /></figure><h3>Describe the Semantic View</h3><p>To understand the structure and components of our newly created semantic view, we can use the DESC SEMANTIC VIEW command. This will provide details about its tables, relationships, facts, and dimensions.</p><pre>-- Describes the semantic view named TPCDS_SEMANTIC_VIEW_SM, and as a special bonus uses our new flow operator to filter and project only the metric and dimension names<br>DESC SEMANTIC VIEW TPCDS_SEMANTIC_VIEW_SM<br>    -&gt;&gt; SELECT &quot;object_kind&quot;,&quot;property_value&quot; as &quot;parent_object&quot;,&quot;object_name&quot; FROM $1<br>        WHERE &quot;object_kind&quot; IN (&#39;METRIC&#39;,&#39;DIMENSION&#39;) AND &quot;property&quot; IN (&#39;TABLE&#39;)<br>;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*biCmmTiTMrTwZEXI.png" /></figure><h3>“Talk To” the Semantic View with Cortex Analyst</h3><h4>Natural Language Querying</h4><p>Snowflake’s Cortex Analyst allows you to interact with your semantic views using natural language. This powerful feature transforms how users can explore data without needing to know SQL syntax.</p><h4>Access Cortex Analyst</h4><p>You can access Cortex Analyst through the Snowflake interface.</p><p>Let’s dynamically generate a link to Cortex Analyst so that you can access the semantic view.</p><p>First, we’ll create a SQL cell named sql_step7:</p><pre>SELECT &#39;https://app.snowflake.com/&#39; || CURRENT_ORGANIZATION_NAME() || &#39;/&#39; || CURRENT_ACCOUNT_NAME() || &#39;/#/studio/analyst/databases/SAMPLE_DATA/schemas/TPCDS_SF10TCL/semanticView/TPCDS_SEMANTIC_VIEW_SM/edit&#39; AS RESULT;</pre><p>Next, we’ll call it from the following Python code cell that we called py_link:</p><pre>import streamlit as st<br><br>link = sql_step7.to_pandas()[&#39;RESULT&#39;].iloc[0]<br>st.link_button(&quot;Go to Cortex Analyst&quot;, link)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*PGaS86YoEgqiskuP.gif" /></figure><h4>Example Natural Language Query</h4><p>Once in Cortex Analyst, you can ask questions like:</p><p><em>Show me the top selling brands in by total sales quantity in the state ‘TX’ in the ‘Books’ category in the year 2003</em></p><p>Cortex Analyst will automatically translate this natural language question into the appropriate Semantic SQL query and return the results.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*gy_GP4IjLl4xO-bo.gif" /></figure><h3>Query Semantic Views</h3><h4>Basic Query Structure</h4><p>To query a semantic view, you’ll use this special query structure:</p><pre>SELECT * FROM SEMANTIC_VIEW (view_name<br>    METRICS metric1, metric2, ...<br>    DIMENSIONS dimension1, dimension2, ...<br>);</pre><p>Let’s break down each part:</p><ul><li>SELECT * FROM SEMANTIC_VIEW (view_name ...): This initiates your query, indicating that you want to retrieve data from a semantic view</li><li>METRICS metric1, metric2, ...: Within the parentheses, specify the metrics (calculated values or totals) you wish to retrieve</li><li>DIMENSIONS dimension1, dimension2, ...: Next, specify the dimensions (categories or attributes) you want to group or filter your data by</li></ul><h4>Add Filters and Sorting</h4><p>You can enhance your queries with standard SQL clauses:</p><ul><li>Filtering: Use WHERE clauses to filter your results</li><li>Sorting: Use ORDER BY to sort your results</li><li>Limiting: Use LIMIT to restrict the number of results</li></ul><h4>Example Query: Top Selling Brands</h4><p>Now that our semantic view is defined, we can easily query it to retrieve aggregated data. The following query demonstrates how to find the top-selling brands in a specific state and category for a given year and month:</p><pre>-- Query the semantic view to find top selling brands<br>SELECT * FROM SEMANTIC_VIEW<br>(<br> TPCDS_SEMANTIC_VIEW_SM<br>    DIMENSIONS<br>            Item.Brand,<br>            Item.Category,<br>            Date.Year,<br>            Date.Month,<br>            Store.State<br>    METRICS<br>        StoreSales.TotalSalesQuantity<br>)<br>WHERE Year = &#39;2002&#39; AND Month = &#39;12&#39; AND State =&#39;TX&#39; AND Category = &#39;Books&#39;<br>ORDER BY TotalSalesQuantity DESC LIMIT 10;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QCZ1DuW91Mcf5b26.png" /></figure><h3>Build an Interactive Data App</h3><p>In this step, we’ll build 2 simple interactive data apps:</p><ol><li>Interactive data visualization app</li><li>Simple interactive dashboard</li></ol><h4>Query data</h4><p>Firstly, we’ll modify the SQL query to show data for month 12.</p><pre>-- Query the semantic view for month 12<br>SELECT * FROM SEMANTIC_VIEW<br>( <br> TPCDS_SEMANTIC_VIEW_SM<br>    DIMENSIONS <br>            Item.Brand,<br>            Item.Category,            <br>            Date.Year,<br>            Date.Month,<br>            Store.State<br>    METRICS <br>        StoreSales.TotalSalesQuantity<br>    WHERE<br>        Date.Year = &#39;2002&#39; AND Date.Month = &#39;12&#39; AND Item.Category = &#39;Books&#39;<br>) <br>ORDER BY TotalSalesQuantity DESC;</pre><p>Next, in a Python cell named df, we&#39;ll convert the SQL table to a Pandas DataFrame:</p><pre>cell1.to_pandas()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*R4h5wVyJJq7mPcnt.png" /></figure><h4>App 1: Interactive data visualization app</h4><p>Here the user can interactively explore the sales data:</p><pre>import streamlit as st<br>import pandas as pd<br><br>st.title(&quot;📊 Sales Data Interactive Visualization&quot;)<br><br># Create selectbox for grouping option<br>group_by = st.selectbox(<br>    &quot;Select grouping option:&quot;,<br>    options=[&#39;BRAND&#39;, &#39;STATE&#39;],<br>    index=0<br>)<br><br># Group the data based on selection<br>if group_by == &#39;BRAND&#39;:<br>    grouped_data = df.groupby(&#39;BRAND&#39;)[&#39;TOTALSALESQUANTITY&#39;].sum().reset_index()<br>    grouped_data = grouped_data.set_index(&#39;BRAND&#39;)<br>    chart_title = &quot;Total Sales Quantity by Brand&quot;<br>else:  # group_by == &#39;STATE&#39;<br>    grouped_data = df.groupby(&#39;STATE&#39;)[&#39;TOTALSALESQUANTITY&#39;].sum().reset_index()<br>    grouped_data = grouped_data.set_index(&#39;STATE&#39;)<br>    chart_title = &quot;Total Sales Quantity by State&quot;<br><br># Display the chart<br>st.subheader(chart_title)<br>st.bar_chart(grouped_data[&#39;TOTALSALESQUANTITY&#39;])<br><br># Optional: Display the data table<br>if st.checkbox(&quot;Show data table&quot;):<br>    st.subheader(&quot;Grouped Data&quot;)<br>    st.dataframe(grouped_data)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*HaLfiZGXRf7dIPqA.gif" /></figure><h4>App 2: Simple interactive dashboard</h4><p>Here’s a simple dashboard we’re we’ve included a row of metrics:</p><pre><br>import streamlit as st<br>import pandas as pd<br><br>st.title(&quot;📊 Sales Data Dashboard&quot;)<br><br># Create selectbox for grouping option<br>group_by = st.selectbox(<br>    &quot;Select grouping option:&quot;,<br>    options=[&#39;BRAND&#39;, &#39;STATE&#39;],<br>    index=0<br>)<br><br># Group the data based on selection<br>if group_by == &#39;BRAND&#39;:<br>    grouped_data = df.groupby(&#39;BRAND&#39;)[&#39;TOTALSALESQUANTITY&#39;].sum().reset_index()<br>    grouped_data = grouped_data.set_index(&#39;BRAND&#39;)<br>    chart_title = &quot;Total Sales Quantity by Brand&quot;<br>else:  # group_by == &#39;STATE&#39;<br>    grouped_data = df.groupby(&#39;STATE&#39;)[&#39;TOTALSALESQUANTITY&#39;].sum().reset_index()<br>    grouped_data = grouped_data.set_index(&#39;STATE&#39;)<br>    chart_title = &quot;Total Sales Quantity by State&quot;<br><br># Calculate KPIs based on current grouping<br>total_sales = df[&#39;TOTALSALESQUANTITY&#39;].sum()<br>avg_sales = df[&#39;TOTALSALESQUANTITY&#39;].mean()<br>top_performer = grouped_data[&#39;TOTALSALESQUANTITY&#39;].max()<br>top_performer_name = grouped_data[&#39;TOTALSALESQUANTITY&#39;].idxmax()<br><br># Display KPI metrics in 3 columns<br>col1, col2, col3 = st.columns(3)<br><br>with col1:<br>    st.metric(<br>        label=&quot;Total Sales Quantity&quot;, <br>        value=f&quot;{total_sales:,.0f}&quot;,<br>        delta=None<br>    )<br><br>with col2:<br>    if group_by == &#39;BRAND&#39;:<br>        st.metric(<br>            label=&quot;Average Sales per Brand&quot;, <br>            value=f&quot;{avg_sales:,.0f}&quot;,<br>            delta=f&quot;{((avg_sales/total_sales)*100):.3f}% of total&quot;<br>        )<br>    else:<br>        st.metric(<br>            label=&quot;Average Sales per State&quot;, <br>            value=f&quot;{avg_sales:,.0f}&quot;,<br>            delta=f&quot;{len(df[&#39;STATE&#39;].unique())} state(s)&quot;<br>        )<br><br>with col3:<br>    st.metric(<br>        label=f&quot;Top {group_by.title()}&quot;, <br>        value=f&quot;{top_performer:,.0f}&quot;,<br>        delta=f&quot;{top_performer_name}&quot;<br>    )<br><br># Display the chart<br>st.subheader(chart_title)<br>st.bar_chart(grouped_data[&#39;TOTALSALESQUANTITY&#39;])<br><br># Optional: Display the data table<br>if st.checkbox(&quot;Show data table&quot;):<br>    st.subheader(&quot;Grouped Data&quot;)<br>    st.dataframe(grouped_data)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*w_8f17mb4gpMItXS.gif" /></figure><h3>Conclusion And Resources</h3><p>Congratulations! You’ve successfully created your first Snowflake semantic view. By implementing this semantic layer directly within Snowflake, you’ve established a foundation for consistent, AI-ready analytics that bridges the gap between raw data and meaningful business insights.</p><p>The semantic view you built not only simplifies complex data relationships but also enables natural language querying through Cortex Analyst, democratizing data access across your organization. As you continue to develop your semantic models, remember that this approach scales to support enterprise-wide analytics initiatives, ensuring that all stakeholders — from data analysts to business users — can trust and understand the data that they’re working with.</p><h4>What You Learned</h4><ul><li>How to create and configure Snowflake semantic views using the TPC-DS sample data</li><li>The importance of semantic views for AI-powered analytics and BI consistency</li><li>How to define relationships, dimensions, and metrics in a semantic view</li><li>How to query semantic views</li><li>How to leverage Cortex Analyst for natural language data exploration</li></ul><h4>Related Resources</h4><p>Articles:</p><ul><li><a href="https://docs.snowflake.com/user-guide/views-semantic/sql">Using SQL commands to create and manage semantic views</a></li><li><a href="https://docs.snowflake.com/en/user-guide/views-semantic/ui">Using the Cortex Analyst Semantic View Generator</a></li><li><a href="https://docs.snowflake.com/en/user-guide/sample-data-tpcds">Sample Data: TPC-DS</a></li><li><a href="https://www.tpc.org/tpcds/">TPC-DS Benchmark Overview</a> — Understanding the sample dataset used in this guide</li></ul><p>Documentation:</p><ul><li><a href="https://docs.snowflake.com/en/user-guide/views-semantic/overview">Overview of semantic views</a></li><li><a href="https://docs.snowflake.com/en/sql-reference/sql/create-semantic-view">CREATE SEMANTIC VIEW</a></li><li><a href="https://docs.snowflake.com/en/sql-reference/sql/drop-semantic-view">DROP SEMANTIC VIEW</a></li><li><a href="https://docs.snowflake.com/en/sql-reference/sql/show-semantic-views">SHOW SEMANTIC VIEWS</a></li><li><a href="https://docs.snowflake.com/en/sql-reference/sql/desc-semantic-view">DESCRIBE SEMANTIC VIEW</a></li></ul><p>Ready to start Snowflake? Start your 30-day free Snowflake trial which includes $400 worth of free usage <a href="https://signup.snowflake.com/?utm_source=&amp;utm_medium=social&amp;utm_campaign=--en-&amp;utm_content=-ss-medium-blog-v2">here</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7eced29abe6f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/snowflake/getting-started-with-snowflake-semantic-view-7eced29abe6f">Getting Started with Snowflake Semantic View</a> was originally published in <a href="https://medium.com/snowflake">Snowflake Builders Blog: Data Engineers, App Developers, AI, &amp; Data Science</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Towards Building a Customer Review Analytics Dashboard with Snowflake Cortex and Streamlit]]></title>
            <link>https://medium.com/snowflake/towards-building-a-customer-review-analytics-dashboard-with-snowflake-and-streamlit-3decdde91567?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/3decdde91567</guid>
            <category><![CDATA[streamlit]]></category>
            <category><![CDATA[dashboard]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[snowflake]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Tue, 29 Apr 2025 22:01:57 GMT</pubDate>
            <atom:updated>2025-05-13T04:16:17.530Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8kKFlMDe3KpDhXBJ9vj_4Q.png" /><figcaption>Image generated using flux-softserve-anime on Replicate by Author.</figcaption></figure><p>Have you ever wondered how to transform unstructured customer feedback into actionable business insights? Organizations often struggle to efficiently process and analyze large volumes of customer reviews stored in various document formats.</p><p>The solution lies in building an automated analytics pipeline that combines Snowflake’s powerful data processing capabilities with modern visualization tools.</p><p>In this blog, I will guide you through creating a complete analytics solution that processes customer review data using Snowflake Cortex and visualizes insights with Streamlit.</p><p>While we won’t be building a fully functional dashboard today, the techniques covered can be easily repurposed to create one.</p><p>Readers will learn:</p><ul><li>How to extract and process content from DOCX files using Snowflake</li><li>How to perform sentiment analysis using Snowflake Cortex</li><li>How to create interactive visualizations with Streamlit and Altair</li></ul><h3>Getting Started</h3><h4>Prerequisites</h4><p>Before proceeding, ensure you have:</p><ul><li>Access to a <a href="https://signup.snowflake.com/">Snowflake account</a></li><li>Basic knowledge of SQL and Python</li><li>Familiarity with data analysis concepts</li></ul><h4>New to data?</h4><p>Here are some introductory notes on</p><blockquote><strong><em>What is Snowflake?</em></strong><em> Snowflake is a cloud-based data platform that allows organizations to store, process, and analyze large amounts of data without managing complex infrastructure.</em></blockquote><blockquote><strong><em>What is Streamlit?</em></strong><em> Streamlit is an open-source Python library that makes it easy to create and share custom web apps for machine learning and data science projects without requiring front-end development experience.</em></blockquote><blockquote><strong><em>What is Snowflake Cortex?</em></strong><em> Snowflake Cortex is a built-in AI and machine learning feature in Snowflake that provides ready-to-use functions for tasks like sentiment analysis, translation, and document parsing without requiring expertise in AI/ML.</em></blockquote><h3>Setting Up the Database Environment</h3><p>Let’s break down the solution into manageable steps.</p><h4>Create the database and schema</h4><p>First, we’ll set up our environment and create the necessary database objects.</p><pre>CREATE DATABASE IF NOT EXISTS avalanche_db;<br>CREATE SCHEMA IF NOT EXISTS avalanche_schema;</pre><p>Here, we’re creating a database called avalanche_db and a schema called avalanche_schema within it. In Snowflake, a database is a container for data, and a schema is a way to organize objects within a database. The IF NOT EXISTS clause prevents errors if these objects already exist.</p><h4>Create the stage</h4><p>A stage in Snowflake is a location where data files are stored before being loaded into database tables.</p><p>Here, we’re creating a stage called customer_reviews with Snowflake-managed encryption and enabling directory listing functionality, which allows us to browse files in the stage.</p><pre>CREATE STAGE IF NOT EXISTS avalanche_db.avalanche_schema.customer_reviews<br>  ENCRYPTION = (TYPE = &#39;SNOWFLAKE_SSE&#39;)<br>  DIRECTORY = (ENABLE = true);</pre><p>You should see a confirmation message after a stage has been created succesfully:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y3HTW6YCR2csGyghVZOk5A.png" /></figure><h3>List contents of a stage</h3><p>Finally, we can verify that the files have been uploaded successfully to the stage by opening up a SQL worksheet, from the left menu sidebar go to Projects &gt; Worksheets &gt; + (Create SQL Worksheet)</p><p>Next, enter the following in a SQL worksheet:</p><pre>ls @avalanche_db.avalanche_schema.customer_reviews</pre><p>This should yield the following results output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sFLohBA6Gk4PvuMynieCpw.png" /></figure><h3>Data Extraction Process</h3><p>Now we’ll extract content from the DOCX files stored in our Snowflake stage.</p><pre>WITH files AS (<br>  SELECT <br>    REPLACE(REGEXP_SUBSTR(file_url, &#39;[^/]+$&#39;), &#39;%2e&#39;, &#39;.&#39;) as filename<br>  FROM DIRECTORY(&#39;@avalanche_db.avalanche_schema.customer_reviews&#39;)<br>  WHERE filename LIKE &#39;%.docx&#39;<br>)<br>SELECT <br>  filename,<br>  SNOWFLAKE.CORTEX.PARSE_DOCUMENT(<br>    @avalanche_db.avalanche_schema.customer_reviews,<br>    filename,<br>    {&#39;mode&#39;: &#39;layout&#39;}<br>  ):content AS layout<br>FROM files;</pre><p>Here’s a breakdown of the code:</p><ul><li>The WITH clause creates a temporary result set called files that contains the names of all DOCX files in our stage.</li><li>DIRECTORY() lists all files in the specified stage.</li><li>REGEXP_SUBSTR(file_url, &#39;[^/]+$&#39;) extracts just the filename from the full path.</li><li>REPLACE(..., &#39;%2e&#39;, &#39;.&#39;) converts URL-encoded periods back to actual periods.</li><li>SNOWFLAKE.CORTEX.PARSE_DOCUMENT() is a Cortex function that extracts text content from the DOCX files.</li><li>The :content part uses Snowflake&#39;s semi-structured data access notation to get just the content field from the returned JSON object.</li><li>{&#39;mode&#39;: &#39;layout&#39;} tells the parser to preserve the document&#39;s original layout.</li></ul><p>Running the above query should yield the following table output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D7tEnbkdpcqDMEEW6RHpMg.png" /></figure><h3>Data Reshaping</h3><p>Let’s transform the extracted content into a structured format and we’ll do this with regular expressions, which are patterns used to match character combinations in strings.</p><pre>SELECT <br>  filename,<br>  REGEXP_SUBSTR(layout, &#39;Product: (.*?) Date:&#39;, 1, 1, &#39;e&#39;) as product,<br>  REGEXP_SUBSTR(layout, &#39;Date: (202[0-9]-[0-9]{2}-[0-9]{2})&#39;, 1, 1, &#39;e&#39;) as date,<br>  REGEXP_SUBSTR(layout, &#39;## Customer Review\n([\\s\\S]*?)$&#39;, 1, 1, &#39;es&#39;) as customer_review<br>FROM previous_query_result;</pre><p>Here’s what the above query is doing:</p><ul><li>We’re using REGEXP_SUBSTR() to extract specific pieces of information from the document text.</li><li>The first expression extracts the product name from between &quot;Product:&quot; and &quot;Date:&quot;.</li><li>The second expression extracts a date in YYYY-MM-DD format.</li><li>The third expression extracts all content after the &quot;## Customer Review&quot; heading.</li><li>The parameters 1, 1, &#39;e&#39; mean: start at position 1, get the first occurrence, and extract the captured group.</li></ul><p>The resulting table output should look like the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ELYA9cgxKZSWtYpTwKJkvA.png" /></figure><h3>Analytics Processing</h3><p>We’ll apply Snowflake Cortex functions to translate and summarize text as well as computing the sentiment score.</p><pre>SELECT <br>    product,<br>    date,<br>    SNOWFLAKE.CORTEX.TRANSLATE(customer_review, &#39;&#39;, &#39;en&#39;) as translated_review,<br>    SNOWFLAKE.CORTEX.SUMMARIZE(translated_review) as summary,<br>    SNOWFLAKE.CORTEX.SENTIMENT(translated_review) as sentiment_score<br>FROM previous_query_result<br>ORDER BY date;</pre><p>Let’s see what the above query is doing:</p><ul><li>TRANSLATE(customer_review, &#39;&#39;, &#39;en&#39;) translates the review text to English if it&#39;s in another language. The empty string &#39;&#39; means to auto-detect the source language.</li><li>SUMMARIZE(translated_review) creates a concise summary of the review text.</li><li>SENTIMENT(translated_review) analyzes the emotional tone of the review and returns a score (typically between -1 and 1, where negative values indicate negative sentiment and positive values indicate positive sentiment).</li><li>ORDER BY date sorts the results chronologically.</li></ul><p>Results from the query is shown below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0D3Md9_OKBdXGQlrKoJa6A.png" /></figure><h3>Converting SQL Results to a Pandas DataFrame</h3><p>To prepare for visualization, we’ll convert the SQL results to a Pandas DataFrame:</p><pre>df = sql_result.to_pandas()</pre><p>This conversion allows us to use Python’s data visualization libraries to create interactive charts and graphs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0QUUayUEkg6LcQ8joDmCYg.png" /></figure><h3>Data Visualization</h3><p>Finally, we’ll create interactive visualizations using Streamlit and Altair.</p><h4>Calculate Daily Sentiment Scores</h4><p>First, let’s create a bar chart showing sentiment scores by date:</p><pre>import streamlit as st<br>import altair as alt<br>import pandas as pd<br><br># Ensure SENTIMENT_SCORE is numeric<br>df[&#39;SENTIMENT_SCORE&#39;] = pd.to_numeric(df[&#39;SENTIMENT_SCORE&#39;])<br><br># Create the base chart with bars<br>chart = alt.Chart(df).mark_bar(size=15).encode(<br>    x=alt.X(&#39;DATE:T&#39;,<br>            axis=alt.Axis(<br>                format=&#39;%Y-%m-%d&#39;,  # YYYY-MM-DD format<br>                labelAngle=90)  # Rotate labels 90 degrees<br>            ),<br>    y=alt.Y(&#39;SENTIMENT_SCORE:Q&#39;),<br>    color=alt.condition(<br>        alt.datum.SENTIMENT_SCORE &gt;= 0,<br>        alt.value(&#39;#2ecc71&#39;),  # green for positive<br>        alt.value(&#39;#e74c3c&#39;)   # red for negative<br>    ),<br>    tooltip=[&#39;PRODUCT:N&#39;, &#39;DATE:T&#39;] # Add tooltip<br>).properties(<br>    height=500<br>)<br><br># Display the chart<br>st.altair_chart(chart, use_container_width=True)</pre><p>Let’s take a glimpse at what the code is doing:</p><ol><li>We first import the necessary Python libraries: streamlitfor the web app, pandas for data visualization, and pandasfor data manipulation.</li><li>pd.to_numeric() converts the sentiment scores to numbers (they might be strings in the original data).</li><li>alt.Chart(df) creates a new chart using our data.</li><li>mark_bar(size=15) specifies we want a bar chart with bars 15 pixels wide.</li><li>The encode() function maps data fields to visual properties:</li></ol><ul><li>x=alt.X(&#39;DATE:T&#39;) puts dates on the x-axis (&#39;T&#39;means temporal/date data)</li><li>y=alt.Y(&#39;SENTIMENT_SCORE:Q&#39;) puts sentiment scores on the y-axis (&#39;Q&#39; means quantitative/numeric data)</li><li>color=alt.condition(...) colors positive scores green and negative scores red</li><li>tooltip=[...] shows product and date when hovering over a bar</li></ul><p>6. st.altair_chart() displays the chart in the Streamlit app.</p><p>This produces the following bar chart that conditionally colors the bars as green or red for positive and negative scores, respectively.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aXIEctg93qMAbQstvn_sjw.png" /></figure><h4>Calculate Product Sentiment Scores</h4><p>Next, let’s create a bar chart showing average sentiment scores by product:</p><pre>import streamlit as st<br>import altair as alt<br>import pandas as pd<br><br># Create the base chart with aggregation by PRODUCT<br>bars = alt.Chart(df).mark_bar(size=15).encode(<br>    y=alt.Y(&#39;PRODUCT:N&#39;, <br>            axis=alt.Axis(<br>                labelAngle=0,  # Horizontal labels<br>                labelOverlap=False,  # Prevent label overlap<br>                labelPadding=10  # Add some padding<br>            )<br>    ),<br>    x=alt.X(&#39;mean(SENTIMENT_SCORE):Q&#39;,  # Aggregate mean sentiment score<br>            title=&#39;MEAN SENTIMENT_SCORE&#39;),<br>    color=alt.condition(<br>        alt.datum.mean_SENTIMENT_SCORE &gt;= 0,<br>        alt.value(&#39;#2ecc71&#39;),  # green for positive<br>        alt.value(&#39;#e74c3c&#39;)   # red for negative<br>    ),<br>    tooltip=[&#39;PRODUCT:N&#39;, &#39;mean(SENTIMENT_SCORE):Q&#39;]<br>).properties(<br>    height=400<br>)<br><br># Display the chart<br>st.altair_chart(bars, use_container_width=True)</pre><p>This chart:</p><ul><li>Shows average sentiment scores for each product</li><li>Uses the same color scheme as the previous chart</li><li>Includes tooltips that show the product name and average sentiment score</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hAnwWnYakdy2EHJ6W8BYpQ.png" /></figure><h3>Add Download Button</h3><p>Finally, let’s add a download button so users can export the processed data:</p><pre># Download button for the CSV file<br>st.subheader(&#39;Processed Customer Reviews Data&#39;)<br>st.download_button(<br>    label=&quot;Download CSV&quot;,<br>    data=df[[&#39;PRODUCT&#39;, &#39;DATE&#39;, &#39;SUMMARY&#39;, &#39;SENTIMENT_SCORE&#39;]].to_csv(index=False).encode(&#39;utf-8&#39;),<br>    mime=&quot;text/csv&quot;<br>)</pre><p>This button allows users to download a CSV file containing the product name, date, summary, and sentiment score for each review.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vt6_xwLLXuY0dZe1g83BCQ.png" /></figure><h3>Conclusion</h3><p>In this blog, we built a comprehensive customer review analytics solution that transforms unstructured DOCX files into actionable insights. The solution combines Snowflake’s data processing capabilities with Cortex’s AI functions and Streamlit’s visualization tools to create an end-to-end analytics pipeline. You can adapt this framework for your own use cases by modifying the data source, analysis parameters, or visualization components to meet your specific business needs.</p><h3>What You’ve Learned</h3><ul><li>How to use Snowflake stages to store document files</li><li>How to extract text from DOCX files using Snowflake Cortex</li><li>How to structure unstructured data using regular expressions</li><li>How to apply AI functions for sentiment analysis and summarization</li><li>How to create interactive visualizations with Streamlit and Altair</li></ul><p>While we didn’t build a complete dashboard in this tutorial, the components we’ve developed can be easily combined into a comprehensive analytics dashboard. The Streamlit app we created serves as the foundation for more complex visualizations and interactive features.</p><h3>Resources</h3><p>Videos:</p><ul><li><a href="https://www.youtube.com/watch?v=6vnXaIuEwoA&amp;list=PLavJpcg8cl1Efw8x_fBKmfA2AMwjUaeBI">YouTube playlist on Snowflake Notebooks</a></li></ul><p>Documentation:</p><ul><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/parse-document">PARSE_DOCUMENT</a></li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions">Snowflake Cortex</a></li><li><a href="https://docs.snowflake.com/">Snowflake Documentation</a></li><li><a href="https://docs.streamlit.io/">Streamlit Documentation</a></li><li><a href="https://altair-viz.github.io/">Altair Documentation</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3decdde91567" width="1" height="1" alt=""><hr><p><a href="https://medium.com/snowflake/towards-building-a-customer-review-analytics-dashboard-with-snowflake-and-streamlit-3decdde91567">Towards Building a Customer Review Analytics Dashboard with Snowflake Cortex and Streamlit</a> was originally published in <a href="https://medium.com/snowflake">Snowflake Builders Blog: Data Engineers, App Developers, AI, &amp; Data Science</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to build a DeepSeek-R1 chatbot]]></title>
            <link>https://medium.com/snowflake/how-to-build-a-deepseek-r1-chatbot-1edbf6e5e9fe?source=rss-f94b47c3cfca------2</link>
            <guid isPermaLink="false">https://medium.com/p/1edbf6e5e9fe</guid>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[deepseek]]></category>
            <category><![CDATA[snowflake]]></category>
            <category><![CDATA[deepseek-r1]]></category>
            <dc:creator><![CDATA[Chanin Nantasenamat]]></dc:creator>
            <pubDate>Fri, 07 Feb 2025 19:53:50 GMT</pubDate>
            <atom:updated>2025-02-20T21:34:18.827Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n20vVG7AL4ZGe1sY8SYU7g.png" /><figcaption>Image generated using flux-softserve-anime on Replicate by Author.</figcaption></figure><p>The pace of advancements in the AI space is indeed proceeding at an unprecedented speed. In just over a week, the release of the DeepSeek-R1 LLM model has shaken the AI world with its impressive accuracy that is on par with established models and yet created at a steep fraction of the typical cost.</p><p>The DeepSeek team managed to distill the reasoning capabilities of their massive 671B parameter model as 6 small models based on Qwen (<em>DeepSeek-R1-Distill-Qwen-1.5B</em>, <em>7B</em>, <em>14B</em> and <em>32B</em>) and Llama (<em>DeepSeek-R1-Distill-Llama-8B</em> and <em>70B</em>). This essentially means that you can work with your own copy of the model — customizing it, making changes, running it locally, or hosting it on cloud platforms.</p><p>In this blog, we’re building a DeepSeek-R1 chatbot in Python. Briefly, Streamlit is used for the frontend, while on the backend the LLM model that is powering the app’s response is made possible through API calls to the DeepSeek-R1 model hosted in Snowflake.</p><p>By the end of this article, you’ll learn how to:</p><ol><li>Set up the development environment</li><li>Build the app</li><li>Deploy the app</li></ol><pre>🐳 Want to jump right in? Here&#39;s the <a href="https://github.com/Snowflake-Labs/snowflake-demo-streamlit/tree/main/DeepSeek-R1%20chatbot">GitHub repo</a>.</pre><h3>What is DeepSeek-R1?</h3><p>In a nutshell, DeepSeek-R1 is a reasoning model that leverages reinforcement learning to teach a base language model namely DeepSeek-V3 to reason without the need for human supervision.</p><p>Here are 5 key features of DeepSeek-R1:</p><ol><li><strong>State-of-the-Art Reasoning</strong>: DeepSeek-R1 could achieve 97.3% accuracy on advanced math tasks, outperforming earlier benchmarks. Similarly, it afforded scores of 79.8% on AIME 2024 and 49.2% on SWE-bench Verified, which also outperformed other models.</li><li><strong>Cost Efficiency</strong>: DeepSeek models were trained at significantly reduced costs compared to industry standards</li><li><strong>Versatile Applications</strong>: Demonstrates robust performance in creative writing, long-context comprehension, and factual question-answering.</li><li><strong>Scalability</strong>: Models are available in several distilled versions (1.5B to 70B parameters) thereby optimizing the balance between capability and resource usage.</li><li><strong>Accessibility</strong>: Open-source availability empowers developers and researchers to experiment with the model in efforts to implement advanced AI tools to real-world projects.</li></ol><p>In spite of its performance, there may still be concerns on security issues in relations to its usage. In light of this, since models were open-sourced the underlying code can be examined while the models itself could be self-deployed on the user’s own compute resources.</p><p>In this tutorial, we’ll use the <a href="https://www.snowflake.com/en/blog/deepseek-preview-snowflake-cortex-ai/">DeepSeek-R1</a> model that is hosted in the Snowflake platform.</p><h3>App overview</h3><p>Here is a high-level overview of the DeepSeek-R1 chatbot app:</p><ol><li>The user provides a prompt input (<em>i.e.</em> ask a question).</li><li>An LLM call is made via the use of SNOWFLAKE.CORTEX.COMPLETE(), where the prompt input is submitted and the resulting LLM-generated response is obtained and displayed in the app.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*705xD1IMpR1QeChxUF1qNg.jpeg" /></figure><h3>Chatbot in action</h3><p>Let’s see the chatbot in action, fire up the chatbot and enter a question into the chat input:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/1*f7DCRcOIdrJo9yaRNrgTWg.gif" /><figcaption>Screencast of DeepSeek-R1 chatbot in action.</figcaption></figure><p>As a reasoning model, the LLM first proceeds to the thinking phase:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2-X0hAxnPFVzBiog_GeOFQ.png" /></figure><p>After the thought process is complete, the final answer is revealed underneath:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dqaJ4gIAgGP2ufuFNfTgyg.png" /></figure><p>It should be noted that the depth of thought and answer is directly affected by the max tokens parameter. Here, we limit the max tokens to 800 for testing purposes, but you may increase this to 20,480.</p><h3>Build DeepSeek-R1 chatbot</h3><p>Let’s now proceed to build the DeepSeek-R1 chatbot on the Snowflake platform.</p><h4>Setup your development environment</h4><p>To have access to the necessary tools, ensure you have access to a <a href="https://signup.snowflake.com/">Snowflake account</a>.</p><p>Next, navigate to <a href="https://docs.snowflake.com/en/developer-guide/streamlit/about-streamlit">Streamlit in Snowflake</a> by heading over to Projects→ Streamlit and then click on + Streamlit App to create the app (you’ll then specify the app location and warehouse):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_Wwu4q-nsjPF3UjzA-9yng.png" /></figure><p>Next, you’ll see an example starter app to get you started:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8xzcBiKH61ZJWk2on09wcg.png" /></figure><p>This Streamlit in Snowflake interface resembles an online code editor where you can edit code on the left and see the rendered app on the right.</p><p>Go ahead and replace this with the app that we’ll be building today.</p><h4>Retrieve the code</h4><p>The DeepSeek-R1 chatbot app that we’ll build today is comprised of:</p><ul><li>environment.yml — environment dependencies of the app</li><li>streamlit_app.py — Streamlit app file</li></ul><p>Firstly, the content of the environment.yml file is displayed below:</p><pre>name: app_environment<br>channels:<br>  - snowflake<br>dependencies:<br>  - python=3.11.*<br>  - snowflake-ml-python<br>  - snowflake-snowpark-python<br>  - streamlit</pre><p>Secondly, the content for the sis_app.py file is shown below:</p><pre>import streamlit as st<br>from snowflake.snowpark.context import get_active_session<br>import pandas as pd<br>import json<br>import re<br><br># App configuration<br>st.set_page_config(page_title=&quot;🐳💬 DeepSeek R1 Chatbot&quot;, initial_sidebar_state=&quot;expanded&quot;)<br>session = get_active_session()<br><br># Helper functions<br>def clear_chat_history():<br>    st.session_state.messages = [{&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: &quot;How may I assist you today?&quot;}]<br><br>def escape_sql_string(s):<br>    return s.replace(&quot;&#39;&quot;, &quot;&#39;&#39;&quot;)<br><br>def extract_think_content(response):<br>    think_pattern = r&#39;&lt;think&gt;(.*?)&lt;/think&gt;&#39;<br>    think_match = re.search(think_pattern, response, re.DOTALL)<br>    <br>    if think_match:<br>        think_content = think_match.group(1).strip()<br>        main_response = re.sub(think_pattern, &#39;&#39;, response, flags=re.DOTALL).strip()<br>        return think_content, main_response<br>    return None, response<br><br>def generate_deepseek_response(prompt, **params):<br>    string_dialogue = &quot;&quot;.join(<br>        f&quot;{msg[&#39;content&#39;]}\n\n&quot; <br>        for msg in st.session_state.messages<br>    )<br>    <br>    cortex_prompt = f&quot;&#39;[INST] {string_dialogue}{prompt} [/INST]&#39;&quot;<br>    prompt_data = [{&#39;role&#39;: &#39;user&#39;, &#39;content&#39;: cortex_prompt}], params<br>    prompt_json = escape_sql_string(json.dumps(prompt_data))<br>    response = session.sql(<br>        &quot;select snowflake.cortex.complete(?, ?)&quot;, <br>        params=[&#39;deepseek-r1&#39;, prompt_json]<br>    ).collect()[0][0]<br>    <br>    return response<br><br># Model parameters configuration<br>MODEL_PARAMS = {<br>    &#39;temperature&#39;: {&#39;min&#39;: 0.01, &#39;max&#39;: 1.0, &#39;default&#39;: 0.7, &#39;step&#39;: 0.01},<br>    &#39;top_p&#39;: {&#39;min&#39;: 0.01, &#39;max&#39;: 1.0, &#39;default&#39;: 1.0, &#39;step&#39;: 0.01},<br>    &#39;max_tokens&#39;: {&#39;min&#39;: 10, &#39;max&#39;: 100, &#39;default&#39;: 20, &#39;step&#39;: 10},<br>    &#39;presence_penalty&#39;: {&#39;min&#39;: -1.0, &#39;max&#39;: 1.0, &#39;default&#39;: 0.0, &#39;step&#39;: 0.1},<br>    &#39;frequency_penalty&#39;: {&#39;min&#39;: -1.0, &#39;max&#39;: 1.0, &#39;default&#39;: 0.0, &#39;step&#39;: 0.1}<br>}<br><br># Sidebar UI<br>with st.sidebar:<br>    st.title(&#39;🐳💬 DeepSeek R1 Chatbot&#39;)<br>    st.write(&#39;This chatbot is created using the DeepSeek R1 LLM model via Snowflake Cortex.&#39;)<br>    <br>    st.subheader(&#39;⚙️ Model parameters&#39;)<br>    params = {<br>        param: st.sidebar.slider(<br>            param.replace(&#39;_&#39;, &#39; &#39;).title(),<br>            min_value=settings[&#39;min&#39;],<br>            max_value=settings[&#39;max&#39;],<br>            value=settings[&#39;default&#39;],<br>            step=settings[&#39;step&#39;]<br>        )<br>        for param, settings in MODEL_PARAMS.items()<br>    }<br>    <br>    st.button(&#39;Clear Chat History&#39;, on_click=clear_chat_history)<br><br># Initialize chat history<br>if &quot;messages&quot; not in st.session_state:<br>    st.session_state.messages = [{&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: &quot;How may I assist you today?&quot;}]<br><br># Display chat messages<br>for message in st.session_state.messages:<br>    with st.chat_message(message[&quot;role&quot;]):<br>        st.write(message[&quot;content&quot;])<br><br># Handle user input<br>if prompt := st.chat_input():<br>    with st.chat_message(&quot;user&quot;):<br>        st.write(prompt)<br>    st.session_state.messages.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: prompt})<br>    <br>    if st.session_state.messages[-1][&quot;role&quot;] != &quot;assistant&quot;:<br>        with st.chat_message(&quot;assistant&quot;):<br>            status_container = st.status(&quot;Thinking ...&quot;, expanded=True)<br>            <br>            with status_container:<br>                response = generate_deepseek_response(prompt, **params)<br>                think_content, main_response = extract_think_content(response)<br>                if think_content:<br>                    st.write(think_content)<br>            <br>            status_container.update(label=&quot;Thoughts&quot;, state=&quot;complete&quot;, expanded=False)<br>            st.markdown(main_response)<br>            st.session_state.messages.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: main_response})</pre><p>You can also download the necessary app files from this <a href="https://github.com/Snowflake-Labs/snowflake-demo-streamlit/tree/main/DeepSeek-R1%20chatbot">DeepSeek-R1 chatbot Github repository</a>.</p><h4>Run the app</h4><p>To run the app, copy-paste the aforementioned code and click on the Run button.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fcq4Pc1dT7yZW05JpkCePg.png" /></figure><p>You can position your mouse cursor on the divider of the code/app panels, then shift it to the left until the code panel disappears (see below). This will expand the app panel to full screen.</p><p>Go ahead and enter a prompt to begin your chatting session:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u0p1eFYKGmPKYICElKKG0A.png" /></figure><p>Also, see the <em>Chatbot in action</em> section above for an account of the LLM-generated thought process and answers.</p><h3>Code explanation</h3><p>Let’s explore what each code blocks are doing …</p><h4>Import libraries</h4><p>We’ll first start by importing the prerequisite libraries.</p><pre>import streamlit as st<br>from snowflake.snowpark.context import get_active_session<br>import pandas as pd<br>import json<br>import re</pre><h4>App configuration</h4><p>Next, we’re defining the app page and setup of their initial page parameter using st.set_page_config() and we’ll set the initial_sidebar_state=&quot;expanded&quot; so that they’ll do exactly as that, expanding the sidebar. Here, we also set the session variable, which we’ll use momentarily.</p><pre># App configuration<br>st.set_page_config(page_title=&quot;🐳💬 DeepSeek R1 Chatbot&quot;, initial_sidebar_state=&quot;expanded&quot;)<br>session = get_active_session()</pre><h4>Helper functions</h4><p>In this segment, we’re defining several of the helper functions that we’ll use in latter parts of the app:</p><ul><li>clear_chat_history() — this allows us to clear the chat history to the initial state</li><li>escape_sql_string() — replaces the SQL strings as we perform some text formatting</li><li>extract_think_content() — parse and separate content that’s wrapped in XML-style “think” tags (&lt;think&gt; and &lt;/think&gt;) from the final response.</li></ul><pre># Helper functions<br>def clear_chat_history():<br>    st.session_state.messages = [{&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: &quot;How may I assist you today?&quot;}]<br><br>def escape_sql_string(s):<br>    return s.replace(&quot;&#39;&quot;, &quot;&#39;&#39;&quot;)<br><br>def extract_think_content(response):<br>    think_pattern = r&#39;&lt;think&gt;(.*?)&lt;/think&gt;&#39;<br>    think_match = re.search(think_pattern, response, re.DOTALL)<br>    <br>    if think_match:<br>        think_content = think_match.group(1).strip()<br>        main_response = re.sub(think_pattern, &#39;&#39;, response, flags=re.DOTALL).strip()<br>        return think_content, main_response<br>    return None, response</pre><p>For example, say we have the following generated response:</p><pre>&lt;think&gt;Let me analyze this problem step by step...&lt;/think&gt;<br>Here&#39;s the solution you&#39;re looking for...</pre><p>It would parse and separate into:</p><ul><li>think_content: “Let me analyze this problem step by step…”</li><li>main_response: “Here’s the solution you’re looking for…”</li></ul><p>Let’s continue with our last helper function:</p><ul><li>generate_deepseek_response() — generate LLM responses using Snowflake’s Cortex service with the DeepSeek R1 model</li></ul><pre>def generate_deepseek_response(prompt, **params):<br>    string_dialogue = &quot;&quot;.join(<br>        f&quot;{msg[&#39;content&#39;]}\n\n&quot; <br>        for msg in st.session_state.messages<br>    )<br>    <br>    cortex_prompt = f&quot;&#39;[INST] {string_dialogue}{prompt} [/INST]&#39;&quot;<br>    prompt_data = [{&#39;role&#39;: &#39;user&#39;, &#39;content&#39;: cortex_prompt}], params<br>    prompt_json = escape_sql_string(json.dumps(prompt_data))<br>    response = session.sql(<br>        &quot;select snowflake.cortex.complete(?, ?)&quot;, <br>        params=[&#39;deepseek-r1&#39;, prompt_json]<br>    ).collect()[0][0]<br>    <br>    return response</pre><h4>Sidebar UI</h4><p>We’ll start by defining the MODEL_PARAMS variable as a dictionary format with their model parameters and associated min, max, default and step size values.</p><p>Next, we’ll define the sidebar that starts with the title of the app along with the app description. Here, we also include several slider widgets that is iteratively created via the for loop. Finally, we have a Clear Chat History button that calls the clear_chat_history callback function to reset the history to its initial state.</p><pre># Model parameters configuration<br>MODEL_PARAMS = {<br>    &#39;temperature&#39;: {&#39;min&#39;: 0.01, &#39;max&#39;: 1.0, &#39;default&#39;: 0.7, &#39;step&#39;: 0.01},<br>    &#39;top_p&#39;: {&#39;min&#39;: 0.01, &#39;max&#39;: 1.0, &#39;default&#39;: 1.0, &#39;step&#39;: 0.01},<br>    &#39;max_tokens&#39;: {&#39;min&#39;: 10, &#39;max&#39;: 100, &#39;default&#39;: 20, &#39;step&#39;: 10},<br>    &#39;presence_penalty&#39;: {&#39;min&#39;: -1.0, &#39;max&#39;: 1.0, &#39;default&#39;: 0.0, &#39;step&#39;: 0.1},<br>    &#39;frequency_penalty&#39;: {&#39;min&#39;: -1.0, &#39;max&#39;: 1.0, &#39;default&#39;: 0.0, &#39;step&#39;: 0.1}<br>}<br><br># Sidebar UI<br>with st.sidebar:<br>    st.title(&#39;🐳💬 DeepSeek R1 Chatbot&#39;)<br>    st.write(&#39;This chatbot is created using the DeepSeek R1 LLM model via Snowflake Cortex.&#39;)<br>    <br>    st.subheader(&#39;⚙️ Model parameters&#39;)<br>    params = {<br>        param: st.sidebar.slider(<br>            param.replace(&#39;_&#39;, &#39; &#39;).title(),<br>            min_value=settings[&#39;min&#39;],<br>            max_value=settings[&#39;max&#39;],<br>            value=settings[&#39;default&#39;],<br>            step=settings[&#39;step&#39;]<br>        )<br>        for param, settings in MODEL_PARAMS.items()<br>    }<br>    <br>    st.button(&#39;Clear Chat History&#39;, on_click=clear_chat_history)</pre><h4>Chat elements</h4><p>In this final segment of the app, we’re initializing the session state variable for the chat history, iteratively display chat messages as they come in and finally define the conditional flow for handling the user/app chat logic. The latter part makes use of previously defined helper functions to process the LLM generated responses.</p><pre># Initialize chat history<br>if &quot;messages&quot; not in st.session_state:<br>    st.session_state.messages = [{&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: &quot;How may I assist you today?&quot;}]<br><br># Display chat messages<br>for message in st.session_state.messages:<br>    with st.chat_message(message[&quot;role&quot;]):<br>        st.write(message[&quot;content&quot;])<br><br># Handle user input<br>if prompt := st.chat_input():<br>    with st.chat_message(&quot;user&quot;):<br>        st.write(prompt)<br>    st.session_state.messages.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: prompt})<br>    <br>    if st.session_state.messages[-1][&quot;role&quot;] != &quot;assistant&quot;:<br>        with st.chat_message(&quot;assistant&quot;):<br>            status_container = st.status(&quot;Thinking ...&quot;, expanded=True)<br>            <br>            with status_container:<br>                response = generate_deepseek_response(prompt, **params)<br>                think_content, main_response = extract_think_content(response)<br>                if think_content:<br>                    st.write(think_content)<br>            <br>            status_container.update(label=&quot;Thoughts&quot;, state=&quot;complete&quot;, expanded=False)<br>            st.markdown(main_response)<br>            st.session_state.messages.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: main_response})</pre><p>Piecing these code blocks together gives us the DeepSeek-R1 chatbot!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/1*f7DCRcOIdrJo9yaRNrgTWg.gif" /><figcaption>Screencast of DeepSeek-R1 chatbot in action.</figcaption></figure><h3>Conclusion</h3><p>Congratulations on building your very own chatbot powered by the powerful DeepSeek-R1 model. This is impressively achieved in less than 100 lines of code. You’ll probably notice that big portion of the code pertains to the processing of the “think” tags and extensive in-line comments, which if removed could make the app significantly smaller. You can further adapt this chatbot to your own use case, and do share with us in the comment section, the amazing projects you’re building with this!</p><h3>Resources</h3><p>Here are some additional further reading:</p><ul><li><a href="https://github.com/Snowflake-Labs/snowflake-demo-streamlit/tree/main/DeepSeek-R1%20chatbot">DeepSeek-R1 chatbot code</a></li><li><a href="https://www.snowflake.com/en/blog/deepseek-preview-snowflake-cortex-ai/">Announcing DeepSeek-R1 in Preview on Snowflake Cortex AI</a></li><li><a href="https://github.com/deepseek-ai/DeepSeek-R1">DeepSeek-R1’s GitHub repo</a></li><li><a href="https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions">Snowflake Cortex LLM functions</a></li><li><a href="https://docs.streamlit.io/">Streamlit Documentation</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1edbf6e5e9fe" width="1" height="1" alt=""><hr><p><a href="https://medium.com/snowflake/how-to-build-a-deepseek-r1-chatbot-1edbf6e5e9fe">How to build a DeepSeek-R1 chatbot</a> was originally published in <a href="https://medium.com/snowflake">Snowflake Builders Blog: Data Engineers, App Developers, AI, &amp; Data Science</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>