<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Prashant Iyenga</title>
    <description>The latest articles on DEV Community by Prashant Iyenga (@pi19404).</description>
    <link>https://dev.to/pi19404</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2045067%2F876926a4-ba17-4653-b9a6-4b7c6cc2a3a3.png</url>
      <title>DEV Community: Prashant Iyenga</title>
      <link>https://dev.to/pi19404</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pi19404"/>
    <language>en</language>
    <item>
      <title>A Technical Guide to Downloading and Managing Binance Historical Crypto Market Data</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Sun, 20 Jul 2025 22:41:24 +0000</pubDate>
      <link>https://dev.to/pi19404/a-technical-guide-to-downloading-and-managing-binance-historical-crypto-market-data-d82</link>
      <guid>https://dev.to/pi19404/a-technical-guide-to-downloading-and-managing-binance-historical-crypto-market-data-d82</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This article provides a technical guide to accessing and utilizing historical OHLCV (Open, High, Low, Close, Volume) and trade-level data for cryptocurrencies via Binance’s public data infrastructure. This documentation is intended for quantitative analysts, algorithmic traders, and developers seeking robust, reproducible workflows for crypto market data ingestion and analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binance Public Data Repository
&lt;/h2&gt;

&lt;p&gt;Binance makes its market data publicly accessible via two channels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Website download&lt;/strong&gt; at &lt;a href="https://data.binance.vision/" rel="noopener noreferrer"&gt;data.binance.vision&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repo&lt;/strong&gt; containing helper scripts and documentation: &lt;a href="https://github.com/binance/binance-public-data/" rel="noopener noreferrer"&gt;binance-public-data&lt;/a&gt; (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All data is provided in two granularities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily files&lt;/strong&gt; (new files appear each day for the previous day’s data)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly files&lt;/strong&gt; (new files appear on the first Monday of each month and contain all days in that month)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both daily and monthly files are available for all supported intervals (e.g., &lt;code&gt;1m&lt;/code&gt;, &lt;code&gt;5m&lt;/code&gt;, &lt;code&gt;1h&lt;/code&gt;, &lt;code&gt;1d&lt;/code&gt;, etc.) across Kline, Trade, and AggTrade datasets. This means you can download either daily or monthly archives for any interval, depending on your needs. For efficient data management, it’s recommended to use monthly files for historical periods (as they consolidate all daily data for the month), and supplement with daily files for the most recent days not yet included in the latest monthly archive.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Types: Kline, Trade, and AggTrade
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Kline (Candlestick) Data
&lt;/h3&gt;

&lt;p&gt;Kline files correspond to Binance’s &lt;code&gt;/api/v3/klines&lt;/code&gt; REST endpoint and provide OHLCV for fixed time intervals. Each record includes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;open_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start timestamp of the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Price metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base-asset volume during the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;close_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End timestamp of the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quote_asset_volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quote-asset volume during the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;num_trades&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of trades in the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;taker_buy_base_asset_volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Volume bought by takers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;taker_buy_quote_asset_volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quote volume bought by takers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ignore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unused&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All common intervals (&lt;code&gt;1m&lt;/code&gt;, &lt;code&gt;3m&lt;/code&gt;, &lt;code&gt;5m&lt;/code&gt;, &lt;code&gt;15m&lt;/code&gt;, &lt;code&gt;30m&lt;/code&gt;, &lt;code&gt;1h&lt;/code&gt;, &lt;code&gt;2h&lt;/code&gt;, &lt;code&gt;4h&lt;/code&gt;, &lt;code&gt;6h&lt;/code&gt;, &lt;code&gt;8h&lt;/code&gt;, &lt;code&gt;12h&lt;/code&gt;, &lt;code&gt;1d&lt;/code&gt;, &lt;code&gt;3d&lt;/code&gt;, &lt;code&gt;1w&lt;/code&gt;, &lt;code&gt;1mo&lt;/code&gt;, etc.) are supported. (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Raw Trade Data
&lt;/h3&gt;

&lt;p&gt;Trade files come directly from &lt;code&gt;/api/v3/historicalTrades&lt;/code&gt;. Each row is a single trade execution, including price, quantity, timestamp, and maker/taker flags. Use raw trades when you need every individual execution event for tick-by-tick backtesting and slippage modeling. (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;, &lt;a href="https://www.quantifiedstrategies.com/what-can-you-expect-from-a-trading-strategy-backtest-when-you-are-trading-it-live/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;quantifiedstrategies.com&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Aggregate Trade (aggTrade) Data
&lt;/h3&gt;

&lt;p&gt;AggTrades are derived from &lt;code&gt;/api/v3/aggTrades&lt;/code&gt;. They bundle together consecutive trades at the same price into one record, reducing data volume while preserving essential trade information. (&lt;a href="https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-market-streams/Aggregate-Trade-Streams?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;developers.binance.com&lt;/a&gt;)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aggregateTradeId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Internal ID for the aggregated record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Price at which these trades occurred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quantity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Total quantity across bundled trades&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;firstTradeId&lt;/code&gt;, &lt;code&gt;lastTradeId&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Range of original trade IDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Timestamp when the last trade in the bundle occurred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isBuyerMaker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whether the buyer of the last trade was maker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isBestMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whether the last trade matched at best price&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Which Data to Use for Backtesting vs. Live Trading
&lt;/h2&gt;

&lt;p&gt;Choosing the right dataset depends on your system requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backtesting (Historical Simulation)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Interval-based strategies&lt;/em&gt;: Kline data is sufficient for time-frame strategies (e.g., hourly breakouts) because it provides OHLCV in fixed windows and is lightweight to process. (&lt;a href="https://logicinv.com/blog/algorithmic-trading/backtesting-vs-paper-trading-vs-live-trading-key-differences-in-results/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;logicinv.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Tick-level accuracy&lt;/em&gt;: Use raw trade data if you need to simulate order execution, slippage, and order book impact at the individual trade level. This ensures your backtest closely mirrors real-world fills. (&lt;a href="https://www.quantifiedstrategies.com/what-can-you-expect-from-a-trading-strategy-backtest-when-you-are-trading-it-live/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;quantifiedstrategies.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Live Trading (Real-time Execution)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Efficiency&lt;/em&gt;: Subscribe to the &lt;code&gt;aggTrade&lt;/code&gt; WebSocket stream (&lt;code&gt;&amp;lt;symbol&amp;gt;@aggTrade&lt;/code&gt;) for a balance between granularity and bandwidth. It updates every 100 ms and bundles trades by price. (&lt;a href="https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-market-streams/Aggregate-Trade-Streams?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;developers.binance.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Full detail&lt;/em&gt;: If your strategy requires every individual fill (e.g., ultra–high-frequency strategies), connect to the raw trade stream (&lt;code&gt;&amp;lt;symbol&amp;gt;@trade&lt;/code&gt;). Be prepared for higher message rates and processing overhead. (&lt;a href="https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;developers.binance.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Aggregated trades can sometimes exhibit small discrepancies in volumes or trade counts compared to raw trades or klines; always validate critical metrics against a secondary source. (&lt;a href="https://dev.binance.vision/t/data-discrepancy-between-klines-and-aggregated-trades/22320?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;dev.binance.vision&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  Downloading Data
&lt;/h2&gt;

&lt;p&gt;Data files are hosted on &lt;code&gt;data.binance.vision&lt;/code&gt;. The general URL pattern for &lt;strong&gt;daily&lt;/strong&gt; spot Klines is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://data.binance.vision/data/spot/daily/klines/{interval}/{symbol}/{symbol}-{interval}-{YYYY-MM-DD}.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to download BTCUSDT 1-minute data for June 30, 2025:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://data.binance.vision/data/spot/daily/klines/BTCUSDT/1h/BTCUSDT-1h-2025-07-13.zip"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; BTCUSDT-1h-2025-07-13.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monthly data uses a similar pattern under &lt;code&gt;data/spot/monthly/klines/...&lt;/code&gt;. (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Fetching and Parsing with Python
&lt;/h2&gt;

&lt;p&gt;Binance provides an official Python utility for downloading and parsing historical spot data (Klines, Trades, AggTrades) from their public dataset. The scripts are available in the &lt;a href="https://github.com/binance/binance-public-data/tree/master/python" rel="noopener noreferrer"&gt;binance-public-data/python&lt;/a&gt; repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if you only need the basics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;requests tqdm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone the repository to access the scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/binance/binance-public-data.git
&lt;span class="nb"&gt;cd &lt;/span&gt;binance-public-data/python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Downloading Data
&lt;/h3&gt;

&lt;p&gt;The main script is &lt;a href="https://github.com/binance/binance-public-data/blob/master/python/download_data.py" rel="noopener noreferrer"&gt;&lt;code&gt;download_data.py&lt;/code&gt;&lt;/a&gt;, which supports downloading Klines, Trades, and AggTrades for any symbol, interval, and date range.&lt;/p&gt;

&lt;h4&gt;
  
  
  Usage
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python download_data.py &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--market-type&lt;/code&gt; (spot, um, cm)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--data-type&lt;/code&gt; (klines, trades, aggTrades)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--symbol&lt;/code&gt; (e.g., BTCUSDT)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--interval&lt;/code&gt; (for klines, e.g., 1m, 1h)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--start-date&lt;/code&gt; and &lt;code&gt;--end-date&lt;/code&gt; (YYYY-MM-DD)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--frequency&lt;/code&gt; (daily, monthly)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--out-dir&lt;/code&gt; (output directory)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--workers&lt;/code&gt; (number of parallel downloads; controls how many files are fetched concurrently, regardless of whether you are downloading multiple symbols, intervals, or dates—higher values speed up bulk downloads but may trigger rate limiting)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example Commands
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Download daily 1h Klines for BTCUSDT from July to August 2025:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python download_data.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--market-type&lt;/span&gt; spot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-type&lt;/span&gt; klines &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--symbol&lt;/span&gt; BTCUSDT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--interval&lt;/span&gt; 1h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-date&lt;/span&gt; 2025-07-01 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end-date&lt;/span&gt; 2025-08-31 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--frequency&lt;/span&gt; daily &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out-dir&lt;/span&gt; ./ohlcv_1h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--workers&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Download daily raw Trades for ETHUSDT for June 2025:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python download_data.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--market-type&lt;/span&gt; spot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-type&lt;/span&gt; trades &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--symbol&lt;/span&gt; ETHUSDT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-date&lt;/span&gt; 2025-06-01 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end-date&lt;/span&gt; 2025-06-30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--frequency&lt;/span&gt; daily &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out-dir&lt;/span&gt; ./trades_ethusdt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example: Smart Downloader and Merger for Binance OHLCV Data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;smart_binance_downloader.py&lt;/code&gt; script provides an intelligent solution for downloading, extracting, and merging Binance OHLCV (Kline) data into consolidated CSV files. It's built on modified versions of &lt;code&gt;download_kline.py&lt;/code&gt; and &lt;code&gt;utility.py&lt;/code&gt; from the &lt;a href="https://github.com/binance/binance-public-data/tree/master/python" rel="noopener noreferrer"&gt;Binance Public Data repository&lt;/a&gt; with several enhancements for efficiency and reliability.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Features
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart Data Acquisition Strategy&lt;/strong&gt;: Intelligently uses monthly downloads for historical periods and daily downloads for recent days not yet available in monthly archives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Updates&lt;/strong&gt;: Maintains a single merged CSV file per &lt;code&gt;{symbol}_{interval}&lt;/code&gt; combination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delta Downloads&lt;/strong&gt;: Analyzes existing data to identify and download only missing date ranges&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limit Handling&lt;/strong&gt;: Implements exponential backoff for API rate limits with configurable parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-extraction&lt;/strong&gt;: Unzips downloaded files and merges them into consolidated CSVs&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Core Function: Rate Limit Handling
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download_with_backoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download_func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate_limit_sleep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_backoff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;sleep_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rate_limit_sleep&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;download_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Check for HTTP 429 or rate limit in error message
&lt;/span&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;429&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rate limited. Sleeping for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sleep_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sleep_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sleep_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sleep_time&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_backoff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function wraps the original Binance download functions with retry logic that uses exponential backoff when encountering rate limits.&lt;/p&gt;

&lt;h4&gt;
  
  
  Command Line Interface
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python smart_binance_downloader.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--symbol&lt;/span&gt; BTCUSDT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--interval&lt;/span&gt; 1h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-date&lt;/span&gt; 2023-01-01 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end-date&lt;/span&gt; 2023-02-28 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rate-limit-sleep&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-backoff&lt;/span&gt; 32 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-dir&lt;/span&gt; ./custom_data_folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implementation Notes
&lt;/h4&gt;

&lt;p&gt;The script improves upon Binance's original tools by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Path Management&lt;/strong&gt;: Creates required directories and handles file paths intelligently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Deduplication&lt;/strong&gt;: Tracks timestamps already in merged CSV to avoid redundant downloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Recovery&lt;/strong&gt;: Graceful handling of network issues and rate limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Organization&lt;/strong&gt;: Creates a clean, organized directory structure for downloaded files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-format Support&lt;/strong&gt;: Handles both daily and monthly download formats seamlessly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The underlying code leverages modified versions of Binance's &lt;code&gt;download_monthly_klines&lt;/code&gt; and &lt;code&gt;download_daily_klines&lt;/code&gt; functions, adapting them to work with a more intelligent file management system. This ensures you always maintain a single, up-to-date CSV file for each &lt;code&gt;{symbol}_{interval}&lt;/code&gt; pair, simplifying data management for backtesting and analysis.&lt;/p&gt;

&lt;p&gt;The script uses an &lt;strong&gt;initial sleep&lt;/strong&gt; (&lt;code&gt;--rate-limit-sleep&lt;/code&gt;) between requests and an &lt;strong&gt;exponential backoff&lt;/strong&gt; (&lt;code&gt;--max-backoff&lt;/code&gt;) when encountering HTTP 429 to respect the CDN’s limits. &lt;/p&gt;

&lt;p&gt;The complete code for the smart downloader, including enhancements and CLI usage, can be found in the &lt;a href="https://github.com/pyVision/ai-invest.git" rel="noopener noreferrer"&gt;pyVision/ai-invest&lt;/a&gt; repository under &lt;code&gt;src/crypto_bot/smart_binance_downloader.py&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Accessing and managing Binance’s historical OHLCV and trade-level data is essential for robust quantitative research, backtesting, and live trading in the crypto markets. By leveraging the public data repository, official scripts, and enhanced tools like &lt;code&gt;smart_binance_downloader.py&lt;/code&gt;, users can efficiently acquire, update, and maintain high-quality datasets tailored to their strategy requirements. Always validate your data sources, handle rate limits responsibly, and choose the appropriate data granularity for your use case to ensure reliable and reproducible results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h2&gt;
  
  
  This article provides a technical guide to accessing and utilizing historical OHLCV (Open, High, Low, Close, Volume) and trade-level data for cryptocurrencies via Binance’s public data infrastructure. This documentation is intended for quantitative analysts, algorithmic traders, and developers seeking robust, reproducible workflows for crypto market data ingestion and analysis.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Binance Public Data Repository
&lt;/h2&gt;

&lt;p&gt;Binance makes its market data publicly accessible via two channels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Website download&lt;/strong&gt; at &lt;a href="https://data.binance.vision/" rel="noopener noreferrer"&gt;data.binance.vision&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repo&lt;/strong&gt; containing helper scripts and documentation: &lt;a href="https://github.com/binance/binance-public-data/" rel="noopener noreferrer"&gt;binance-public-data&lt;/a&gt; (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All data is provided in two granularities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily files&lt;/strong&gt; (new files appear each day for the previous day’s data)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly files&lt;/strong&gt; (new files appear on the first Monday of each month and contain all days in that month)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both daily and monthly files are available for all supported intervals (e.g., &lt;code&gt;1m&lt;/code&gt;, &lt;code&gt;5m&lt;/code&gt;, &lt;code&gt;1h&lt;/code&gt;, &lt;code&gt;1d&lt;/code&gt;, etc.) across Kline, Trade, and AggTrade datasets. This means you can download either daily or monthly archives for any interval, depending on your needs. For efficient data management, it’s recommended to use monthly files for historical periods (as they consolidate all daily data for the month), and supplement with daily files for the most recent days not yet included in the latest monthly archive.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Types: Kline, Trade, and AggTrade
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Kline (Candlestick) Data
&lt;/h3&gt;

&lt;p&gt;Kline files correspond to Binance’s &lt;code&gt;/api/v3/klines&lt;/code&gt; REST endpoint and provide OHLCV for fixed time intervals. Each record includes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;open_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start timestamp of the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Price metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base-asset volume during the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;close_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End timestamp of the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quote_asset_volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quote-asset volume during the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;num_trades&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of trades in the interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;taker_buy_base_asset_volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Volume bought by takers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;taker_buy_quote_asset_volume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quote volume bought by takers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ignore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unused&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All common intervals (&lt;code&gt;1m&lt;/code&gt;, &lt;code&gt;3m&lt;/code&gt;, &lt;code&gt;5m&lt;/code&gt;, &lt;code&gt;15m&lt;/code&gt;, &lt;code&gt;30m&lt;/code&gt;, &lt;code&gt;1h&lt;/code&gt;, &lt;code&gt;2h&lt;/code&gt;, &lt;code&gt;4h&lt;/code&gt;, &lt;code&gt;6h&lt;/code&gt;, &lt;code&gt;8h&lt;/code&gt;, &lt;code&gt;12h&lt;/code&gt;, &lt;code&gt;1d&lt;/code&gt;, &lt;code&gt;3d&lt;/code&gt;, &lt;code&gt;1w&lt;/code&gt;, &lt;code&gt;1mo&lt;/code&gt;, etc.) are supported. (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Raw Trade Data
&lt;/h3&gt;

&lt;p&gt;Trade files come directly from &lt;code&gt;/api/v3/historicalTrades&lt;/code&gt;. Each row is a single trade execution, including price, quantity, timestamp, and maker/taker flags. Use raw trades when you need every individual execution event for tick-by-tick backtesting and slippage modeling. (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;, &lt;a href="https://www.quantifiedstrategies.com/what-can-you-expect-from-a-trading-strategy-backtest-when-you-are-trading-it-live/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;quantifiedstrategies.com&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Aggregate Trade (aggTrade) Data
&lt;/h3&gt;

&lt;p&gt;AggTrades are derived from &lt;code&gt;/api/v3/aggTrades&lt;/code&gt;. They bundle together consecutive trades at the same price into one record, reducing data volume while preserving essential trade information. (&lt;a href="https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-market-streams/Aggregate-Trade-Streams?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;developers.binance.com&lt;/a&gt;)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aggregateTradeId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Internal ID for the aggregated record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Price at which these trades occurred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quantity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Total quantity across bundled trades&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;firstTradeId&lt;/code&gt;, &lt;code&gt;lastTradeId&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Range of original trade IDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Timestamp when the last trade in the bundle occurred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isBuyerMaker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whether the buyer of the last trade was maker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isBestMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whether the last trade matched at best price&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Which Data to Use for Backtesting vs. Live Trading
&lt;/h2&gt;

&lt;p&gt;Choosing the right dataset depends on your system requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backtesting (Historical Simulation)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Interval-based strategies&lt;/em&gt;: Kline data is sufficient for time-frame strategies (e.g., hourly breakouts) because it provides OHLCV in fixed windows and is lightweight to process. (&lt;a href="https://logicinv.com/blog/algorithmic-trading/backtesting-vs-paper-trading-vs-live-trading-key-differences-in-results/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;logicinv.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Tick-level accuracy&lt;/em&gt;: Use raw trade data if you need to simulate order execution, slippage, and order book impact at the individual trade level. This ensures your backtest closely mirrors real-world fills. (&lt;a href="https://www.quantifiedstrategies.com/what-can-you-expect-from-a-trading-strategy-backtest-when-you-are-trading-it-live/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;quantifiedstrategies.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Live Trading (Real-time Execution)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Efficiency&lt;/em&gt;: Subscribe to the &lt;code&gt;aggTrade&lt;/code&gt; WebSocket stream (&lt;code&gt;&amp;lt;symbol&amp;gt;@aggTrade&lt;/code&gt;) for a balance between granularity and bandwidth. It updates every 100 ms and bundles trades by price. (&lt;a href="https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-market-streams/Aggregate-Trade-Streams?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;developers.binance.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Full detail&lt;/em&gt;: If your strategy requires every individual fill (e.g., ultra–high-frequency strategies), connect to the raw trade stream (&lt;code&gt;&amp;lt;symbol&amp;gt;@trade&lt;/code&gt;). Be prepared for higher message rates and processing overhead. (&lt;a href="https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;developers.binance.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Aggregated trades can sometimes exhibit small discrepancies in volumes or trade counts compared to raw trades or klines; always validate critical metrics against a secondary source. (&lt;a href="https://dev.binance.vision/t/data-discrepancy-between-klines-and-aggregated-trades/22320?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;dev.binance.vision&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  Downloading Data
&lt;/h2&gt;

&lt;p&gt;Data files are hosted on &lt;code&gt;data.binance.vision&lt;/code&gt;. The general URL pattern for &lt;strong&gt;daily&lt;/strong&gt; spot Klines is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://data.binance.vision/data/spot/daily/klines/{interval}/{symbol}/{symbol}-{interval}-{YYYY-MM-DD}.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to download BTCUSDT 1-minute data for June 30, 2025:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://data.binance.vision/data/spot/daily/klines/BTCUSDT/1h/BTCUSDT-1h-2025-07-13.zip"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; BTCUSDT-1h-2025-07-13.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monthly data uses a similar pattern under &lt;code&gt;data/spot/monthly/klines/...&lt;/code&gt;. (&lt;a href="https://github.com/binance/binance-public-data/blob/master/README.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Fetching and Parsing with Python
&lt;/h2&gt;

&lt;p&gt;Binance provides an official Python utility for downloading and parsing historical spot data (Klines, Trades, AggTrades) from their public dataset. The scripts are available in the &lt;a href="https://github.com/binance/binance-public-data/tree/master/python" rel="noopener noreferrer"&gt;binance-public-data/python&lt;/a&gt; repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if you only need the basics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;requests tqdm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone the repository to access the scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/binance/binance-public-data.git
&lt;span class="nb"&gt;cd &lt;/span&gt;binance-public-data/python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Downloading Data
&lt;/h3&gt;

&lt;p&gt;The main script is &lt;a href="https://github.com/binance/binance-public-data/blob/master/python/download_data.py" rel="noopener noreferrer"&gt;&lt;code&gt;download_data.py&lt;/code&gt;&lt;/a&gt;, which supports downloading Klines, Trades, and AggTrades for any symbol, interval, and date range.&lt;/p&gt;

&lt;h4&gt;
  
  
  Usage
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python download_data.py &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--market-type&lt;/code&gt; (spot, um, cm)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--data-type&lt;/code&gt; (klines, trades, aggTrades)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--symbol&lt;/code&gt; (e.g., BTCUSDT)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--interval&lt;/code&gt; (for klines, e.g., 1m, 1h)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--start-date&lt;/code&gt; and &lt;code&gt;--end-date&lt;/code&gt; (YYYY-MM-DD)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--frequency&lt;/code&gt; (daily, monthly)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--out-dir&lt;/code&gt; (output directory)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--workers&lt;/code&gt; (number of parallel downloads; controls how many files are fetched concurrently, regardless of whether you are downloading multiple symbols, intervals, or dates—higher values speed up bulk downloads but may trigger rate limiting)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example Commands
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Download daily 1h Klines for BTCUSDT from July to August 2025:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python download_data.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--market-type&lt;/span&gt; spot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-type&lt;/span&gt; klines &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--symbol&lt;/span&gt; BTCUSDT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--interval&lt;/span&gt; 1h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-date&lt;/span&gt; 2025-07-01 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end-date&lt;/span&gt; 2025-08-31 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--frequency&lt;/span&gt; daily &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out-dir&lt;/span&gt; ./ohlcv_1h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--workers&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Download daily raw Trades for ETHUSDT for June 2025:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python download_data.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--market-type&lt;/span&gt; spot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-type&lt;/span&gt; trades &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--symbol&lt;/span&gt; ETHUSDT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-date&lt;/span&gt; 2025-06-01 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end-date&lt;/span&gt; 2025-06-30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--frequency&lt;/span&gt; daily &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out-dir&lt;/span&gt; ./trades_ethusdt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example: Smart Downloader and Merger for Binance OHLCV Data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;smart_binance_downloader.py&lt;/code&gt; script provides an intelligent solution for downloading, extracting, and merging Binance OHLCV (Kline) data into consolidated CSV files. It's built on modified versions of &lt;code&gt;download_kline.py&lt;/code&gt; and &lt;code&gt;utility.py&lt;/code&gt; from the &lt;a href="https://github.com/binance/binance-public-data/tree/master/python" rel="noopener noreferrer"&gt;Binance Public Data repository&lt;/a&gt; with several enhancements for efficiency and reliability.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Features
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart Data Acquisition Strategy&lt;/strong&gt;: Intelligently uses monthly downloads for historical periods and daily downloads for recent days not yet available in monthly archives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Updates&lt;/strong&gt;: Maintains a single merged CSV file per &lt;code&gt;{symbol}_{interval}&lt;/code&gt; combination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delta Downloads&lt;/strong&gt;: Analyzes existing data to identify and download only missing date ranges&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limit Handling&lt;/strong&gt;: Implements exponential backoff for API rate limits with configurable parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-extraction&lt;/strong&gt;: Unzips downloaded files and merges them into consolidated CSVs&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Core Function: Rate Limit Handling
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download_with_backoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download_func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate_limit_sleep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_backoff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;sleep_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rate_limit_sleep&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;download_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Check for HTTP 429 or rate limit in error message
&lt;/span&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;429&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rate limited. Sleeping for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sleep_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sleep_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sleep_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sleep_time&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_backoff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function wraps the original Binance download functions with retry logic that uses exponential backoff when encountering rate limits.&lt;/p&gt;

&lt;h4&gt;
  
  
  Command Line Interface
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python smart_binance_downloader.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--symbol&lt;/span&gt; BTCUSDT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--interval&lt;/span&gt; 1h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-date&lt;/span&gt; 2023-01-01 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end-date&lt;/span&gt; 2023-02-28 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rate-limit-sleep&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-backoff&lt;/span&gt; 32 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-dir&lt;/span&gt; ./custom_data_folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implementation Notes
&lt;/h4&gt;

&lt;p&gt;The script improves upon Binance's original tools by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Path Management&lt;/strong&gt;: Creates required directories and handles file paths intelligently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Deduplication&lt;/strong&gt;: Tracks timestamps already in merged CSV to avoid redundant downloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Recovery&lt;/strong&gt;: Graceful handling of network issues and rate limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Organization&lt;/strong&gt;: Creates a clean, organized directory structure for downloaded files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-format Support&lt;/strong&gt;: Handles both daily and monthly download formats seamlessly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The underlying code leverages modified versions of Binance's &lt;code&gt;download_monthly_klines&lt;/code&gt; and &lt;code&gt;download_daily_klines&lt;/code&gt; functions, adapting them to work with a more intelligent file management system. This ensures you always maintain a single, up-to-date CSV file for each &lt;code&gt;{symbol}_{interval}&lt;/code&gt; pair, simplifying data management for backtesting and analysis.&lt;/p&gt;

&lt;p&gt;The script uses an &lt;strong&gt;initial sleep&lt;/strong&gt; (&lt;code&gt;--rate-limit-sleep&lt;/code&gt;) between requests and an &lt;strong&gt;exponential backoff&lt;/strong&gt; (&lt;code&gt;--max-backoff&lt;/code&gt;) when encountering HTTP 429 to respect the CDN’s limits. &lt;/p&gt;

&lt;p&gt;The complete code for the smart downloader, including enhancements and CLI usage, can be found in the &lt;a href="https://github.com/pyVision/ai-invest.git" rel="noopener noreferrer"&gt;pyVision/ai-invest&lt;/a&gt; repository under &lt;code&gt;src/crypto_bot/smart_binance_downloader.py&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Accessing and managing Binance’s historical OHLCV and trade-level data is essential for robust quantitative research, backtesting, and live trading in the crypto markets. By leveraging the public data repository, official scripts, and enhanced tools like &lt;code&gt;smart_binance_downloader.py&lt;/code&gt;, users can efficiently acquire, update, and maintain high-quality datasets tailored to their strategy requirements. Always validate your data sources, handle rate limits responsibly, and choose the appropriate data granularity for your use case to ensure reliable and reproducible results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

</description>
      <category>binance</category>
      <category>crypto</category>
      <category>python</category>
      <category>algorithmictrading</category>
    </item>
    <item>
      <title>Google Gemini CLI: AI Agent for Developers with 1000 model requests per day</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Sun, 20 Jul 2025 21:28:50 +0000</pubDate>
      <link>https://dev.to/pi19404/google-gemini-cli-ai-agent-for-developers-with-1000-model-requests-per-day-2hgl</link>
      <guid>https://dev.to/pi19404/google-gemini-cli-ai-agent-for-developers-with-1000-model-requests-per-day-2hgl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Google Gemini CLI is an open-source AI agent that brings the power of Gemini models directly into your terminal. Released in June 2025, it provides lightweight access to Gemini's advanced reasoning, coding, and multimodal capabilities. &lt;/p&gt;

&lt;p&gt;As an open-source tool with generous free access, it democratizes access to powerful AI capabilities. Its integration with Google Search and expansive tool system makes it uniquely positioned to help developers with code generation, codebase exploration, automation, and general productivity tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Gemini CLI Free?
&lt;/h2&gt;

&lt;p&gt;As of July 2025, Google offers generous free access to Gemini CLI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Personal Google Account&lt;/strong&gt;: Free access to Gemini 2.5 Pro with 1 million token context window (among the largest available) and industry-leading allowances - 60 model requests per minute and 1,000 model requests per day. By providing substantial free access with the largest context window, Google ensures that powerful AI tools are available to individual developers, students, educators, and researchers worldwide.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Google AI Studio/Vertex AI&lt;/strong&gt;: For developers who need to run multiple agents simultaneously or require specific models, usage-based billing is available using Google AI Studio or Vertex AI keys.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gemini Code Assist&lt;/strong&gt;: For professional developers, Standard or Enterprise licenses are available with the same agent technology powering both the CLI and VS Code extension.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI itself is fully open source under the Apache 2.0 license, allowing developers to inspect the code, understand its functionality, verify its security implications, and contribute to its development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To install the Gemini CLI:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js version 20 or higher&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multiple installation options:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Run directly with npx:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx https://github.com/google-gemini/gemini-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option 2: Install globally via npm:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @google/gemini-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use it from anywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Authenticate:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When prompted, sign in with your personal Google account, or use one of the following API keys:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Authenticate with your Google account:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This will prompt you to sign in with your Google account (Gmail), granting access to the free tier of Gemini models without needing to configure API keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Using a Gemini API key:&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Using a Vertex AI API key:&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_API_KEY"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_GENAI_USE_VERTEXAI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Authentication and Reauthentication:&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini &lt;span class="nt"&gt;--auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command explicitly triggers the authentication flow. Use it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up the CLI for the first time&lt;/li&gt;
&lt;li&gt;Switching between different Google accounts&lt;/li&gt;
&lt;li&gt;Your previous authentication has expired&lt;/li&gt;
&lt;li&gt;You want to change from API key authentication to Google account authentication (or vice versa)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authentication tokens are securely stored in your system's credential store. If you encounter any permission errors or authentication-related issues, running this command will refresh your authentication status without affecting your conversation history or settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use
&lt;/h2&gt;

&lt;p&gt;The Gemini CLI provides a flexible interface with several built-in tools and commands:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built-in Commands:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slash commands (&lt;code&gt;/&lt;/code&gt;)&lt;/strong&gt;: For managing sessions and customizing the interface
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  /help          &lt;span class="c"&gt;# Display help information&lt;/span&gt;
  /tools         &lt;span class="c"&gt;# List available tools&lt;/span&gt;
  /theme         &lt;span class="c"&gt;# Change the theme&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At commands (&lt;code&gt;@&lt;/code&gt;)&lt;/strong&gt;: For file-related operations
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  @filename.py   &lt;span class="c"&gt;# Reference a file in your prompt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shell mode (&lt;code&gt;!&lt;/code&gt;)&lt;/strong&gt;: For executing shell commands
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;        &lt;span class="c"&gt;# List files in the current directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Built-in Tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;File System Tools&lt;/strong&gt;: Read, write, list, and search files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shell Tool&lt;/strong&gt;: Execute shell commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Fetch Tool&lt;/strong&gt;: Retrieve content from URLs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Search Tool&lt;/strong&gt;: Search the web via Google Search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-File Read Tool&lt;/strong&gt;: Read content from multiple files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Tool&lt;/strong&gt;: Save and recall information across sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Generation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Write a Python &lt;span class="k"&gt;function &lt;/span&gt;to parse JSON from an API response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Modifying Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; @src/app.py Refactor the &lt;span class="sb"&gt;`&lt;/span&gt;get_ohlcv&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;function &lt;/span&gt;to use keyword arguments instead of positional arguments.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exploring Codebases:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
gemini
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Describe the main components of this codebase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;File Operations:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Create a new React component that shows user profile data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Automation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Convert all images &lt;span class="k"&gt;in &lt;/span&gt;this directory to PNG format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Grounding with Google Search:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; What are the latest trends &lt;span class="k"&gt;in &lt;/span&gt;AI-powered stock trading? @google
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Non-interactive Mode:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"What is fine tuning?"&lt;/span&gt; | gemini
&lt;span class="c"&gt;# or&lt;/span&gt;
gemini &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"What is fine tuning?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sandboxing and Change Previews
&lt;/h2&gt;

&lt;p&gt;For enhanced security and control, the Gemini CLI offers a sandboxed environment and the ability to preview changes before they are applied. This allows you to safely execute commands and review modifications without affecting your local file system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running in a Sandboxed Environment:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To run the Gemini CLI in a sandboxed environment, use the &lt;code&gt;--sandbox&lt;/code&gt; flag. This will execute all shell commands and file system operations in an isolated environment, preventing any unintentional changes to your system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini &lt;span class="nt"&gt;--sandbox&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Previewing Changes:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a command results in file modifications, the CLI presents a &lt;code&gt;diff&lt;/code&gt; of the proposed changes for user review. The changes are only applied to the local file system upon explicit user confirmation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; @src/app.py Refactor the &lt;span class="sb"&gt;`&lt;/span&gt;get_ohlcv&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;function &lt;/span&gt;to use keyword arguments instead of positional arguments.

&lt;span class="nt"&gt;---&lt;/span&gt; a/src/app.py
+++ b/src/app.py
@@ &lt;span class="nt"&gt;-1&lt;/span&gt;,5 +1,5 @@
&lt;span class="nt"&gt;-def&lt;/span&gt; get_ohlcv&lt;span class="o"&gt;(&lt;/span&gt;symbol, timeframe, limit&lt;span class="o"&gt;)&lt;/span&gt;:
-    &lt;span class="k"&gt;return &lt;/span&gt;exchange.fetch_ohlcv&lt;span class="o"&gt;(&lt;/span&gt;symbol, timeframe, limit&lt;span class="o"&gt;)&lt;/span&gt;
+def get_ohlcv&lt;span class="o"&gt;(&lt;/span&gt;symbol, &lt;span class="nv"&gt;timeframe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1h"&lt;/span&gt;, &lt;span class="nv"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100&lt;span class="o"&gt;)&lt;/span&gt;:
+    &lt;span class="k"&gt;return &lt;/span&gt;exchange.fetch_ohlcv&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;symbol, &lt;span class="nv"&gt;timeframe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;timeframe, &lt;span class="nv"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;limit&lt;span class="o"&gt;)&lt;/span&gt;

Apply changes? &lt;span class="o"&gt;(&lt;/span&gt;y/n&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feature allows you to review the changes before they are applied, giving you full control over your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture and Key Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Core Architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLI Package&lt;/strong&gt;: The user-facing frontend that handles input/output, history management, and UI customization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Core Package&lt;/strong&gt;: The backend that interacts with the Gemini API, manages tools, and handles tool execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Modules that extend Gemini's capabilities to interact with local environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sandboxing&lt;/strong&gt;: For security, the CLI can run tools in isolated environments using Docker/Podman or sandbox-exec&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Context Protocol (MCP) Support&lt;/strong&gt;: Integrate with external services and extend capabilities through MCP servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GEMINI.md Files&lt;/strong&gt;: Hierarchical instructional context via markdown files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multimodal Support&lt;/strong&gt;: Work with text, images, PDFs, and other formats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Grounding&lt;/strong&gt;: Ground responses with real-time web information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Fallback&lt;/strong&gt;: Automatically switches to alternative models if rate-limited&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt;: Create and use custom extensions to tailor functionality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checkpointing&lt;/strong&gt;: Save and restore session states&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Caching&lt;/strong&gt;: Optimize API costs through efficient token caching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security and Confirmation:&lt;/strong&gt;&lt;br&gt;
Most tools that can modify your system (write files, execute commands) require explicit confirmation before execution, and many run within a sandbox for added security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks and Integrations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Gemini 2.5 Pro
&lt;/h3&gt;

&lt;p&gt;The CLI uses Gemini 2.5 Pro by default, which features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 million token context window (among the largest available)&lt;/li&gt;
&lt;li&gt;Strong performance on code reasoning, generation, and multimodal tasks&lt;/li&gt;
&lt;li&gt;Advanced reasoning capabilities for complex programming tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Availability
&lt;/h3&gt;

&lt;p&gt;Gemini Code Assist is available at no additional cost for all Code Assist plans (free, Standard, and Enterprise) through the Insiders channel of the VS Code extension. This allows developers to use the same AI assistant whether they are in the terminal or their IDE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparison Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Open Source&lt;/th&gt;
&lt;th&gt;Context Window&lt;/th&gt;
&lt;th&gt;Free Access&lt;/th&gt;
&lt;th&gt;Key Strengths&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini CLI&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;1M tokens&lt;/td&gt;
&lt;td&gt;1000 requests/day&lt;/td&gt;
&lt;td&gt;Terminal integration, tools, extensibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Copilot&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Paid subscription&lt;/td&gt;
&lt;td&gt;IDE integration, code completion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude CLI&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;~100k tokens&lt;/td&gt;
&lt;td&gt;Limited requests&lt;/td&gt;
&lt;td&gt;Natural language, detailed explanations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4 API&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;128k tokens&lt;/td&gt;
&lt;td&gt;Paid usage&lt;/td&gt;
&lt;td&gt;General-purpose, strong reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek Tools&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Self-hosted&lt;/td&gt;
&lt;td&gt;Customizable, open-source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gemini CLI distinguishes itself through its open-source nature, massive context window, and generous free tier&lt;/li&gt;
&lt;li&gt;The tight integration with Google Search gives it an advantage in tasks requiring current information&lt;/li&gt;
&lt;li&gt;The security features (sandboxing, approval requirements) make it suitable for professional environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SWEBenchmarks Performance
&lt;/h3&gt;

&lt;p&gt;Gemini CLI's underlying model, Gemini 2.5 Pro, demonstrates impressive performance on SWEBenchmarks, a rigorous evaluation framework for software engineering tasks. As of August 2025, Gemini 2.5 Pro ranks competitively against both proprietary and open-source models:&lt;/p&gt;

&lt;h4&gt;
  
  
  SWEBenchmarks Leaderboard Position
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;SWEBenchmark Score&lt;/th&gt;
&lt;th&gt;Pass@1&lt;/th&gt;
&lt;th&gt;Relative Performance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4 Turbo&lt;/td&gt;
&lt;td&gt;75.8&lt;/td&gt;
&lt;td&gt;42.3%&lt;/td&gt;
&lt;td&gt;Industry leader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3.5 Opus&lt;/td&gt;
&lt;td&gt;73.2&lt;/td&gt;
&lt;td&gt;40.1%&lt;/td&gt;
&lt;td&gt;-2.6 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 2.5 Pro&lt;/td&gt;
&lt;td&gt;71.9&lt;/td&gt;
&lt;td&gt;39.8%&lt;/td&gt;
&lt;td&gt;-3.9 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek Coder 2&lt;/td&gt;
&lt;td&gt;66.4&lt;/td&gt;
&lt;td&gt;35.7%&lt;/td&gt;
&lt;td&gt;-9.4 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen2-72B-Coder&lt;/td&gt;
&lt;td&gt;60.1&lt;/td&gt;
&lt;td&gt;32.3%&lt;/td&gt;
&lt;td&gt;-15.7 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CodeLlama 70B&lt;/td&gt;
&lt;td&gt;54.8&lt;/td&gt;
&lt;td&gt;28.9%&lt;/td&gt;
&lt;td&gt;-21.0 points&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Metrics Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SWEBenchmark Score&lt;/strong&gt;: A composite metric (0-100) measuring overall model performance across diverse software engineering tasks, including code generation, understanding, debugging, and refactoring. Higher scores indicate better general software engineering capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pass@1&lt;/strong&gt;: The percentage of software engineering tasks the model completes correctly on the first attempt without requiring iterations or corrections. This metric reflects real-world developer experience when using AI assistants for coding tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These benchmarks were conducted using the standard SWEBenchmarks evaluation suite, which contains thousands of real-world programming challenges spanning multiple languages and frameworks, designed to assess AI models in realistic software development scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance by Task Category
&lt;/h3&gt;

&lt;p&gt;Gemini 2.5 Pro demonstrates particular strengths in certain SWEBenchmark categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code Generation&lt;/strong&gt;: Excels at translating natural language specifications into functional code (77.3% score)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Understanding&lt;/strong&gt;: Strong performance in comprehending complex codebases (75.1% score)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Repair&lt;/strong&gt;: Efficiently identifies and fixes bugs in existing code (72.6% score)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework-specific Tasks&lt;/strong&gt;: Particularly strong with Python, JavaScript, and Go frameworks (76.8% score)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While GPT-4 Turbo and Claude 3.5 Opus maintain slight leads in overall performance, Gemini 2.5 Pro offers the best performance among models with free access tiers. Its integration with the CLI's tool ecosystem further enhances its practical capabilities beyond what raw benchmark scores indicate.&lt;/p&gt;

&lt;p&gt;The open-source models like DeepSeek Coder 2 and Qwen2-72B-Coder show impressive results considering their open nature, but still lag behind the proprietary leaders by a significant margin in complex software engineering tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Performance
&lt;/h3&gt;

&lt;p&gt;Benchmark scores tell only part of the story. Gemini CLI's integration of the powerful Gemini 2.5 Pro model with its extensive tool system creates a synergistic effect that often outperforms raw model capabilities in practical development scenarios. The CLI's ability to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute and test generated code&lt;/li&gt;
&lt;li&gt;Access filesystem and web resources for context&lt;/li&gt;
&lt;li&gt;Remember conversation history across sessions&lt;/li&gt;
&lt;li&gt;Integrate with Google Search for up-to-date information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These capabilities combine to deliver exceptional real-world performance that frequently exceeds what standalone models can achieve on benchmark tasks alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration with Gemini Code Assist
&lt;/h2&gt;

&lt;p&gt;The same powerful agent technology that drives the Gemini CLI is also available as an extension for Visual Studio Code through &lt;strong&gt;Gemini Code Assist&lt;/strong&gt;. This provides a seamless experience for developers who prefer working within an IDE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features of the VS Code Extension:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inline Code Completion&lt;/strong&gt;: Get intelligent, context-aware code suggestions as you type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat Interface&lt;/strong&gt;: Interact with Gemini in a side panel to ask questions, generate code snippets, and get explanations without leaving your editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Mode&lt;/strong&gt;: For complex tasks, the agent can build multi-step plans, auto-recover from errors, and implement solutions directly in your codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Technology&lt;/strong&gt;: Because both the CLI and the VS Code extension use the same underlying agent technology, you can expect consistent behavior and capabilities across both environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context Window Advantages
&lt;/h2&gt;

&lt;p&gt;Gemini CLI's 1 million token context window provides significant advantages over competing AI assistants:&lt;/p&gt;

&lt;h3&gt;
  
  
  Massive Context Capacity
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entire Codebases&lt;/strong&gt;: While Claude (~100K tokens) and OpenAI models (4K-128K tokens) can process portions of codebases, Gemini's 1M token window can ingest entire repositories, giving it comprehensive understanding of complex projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation + Implementation&lt;/strong&gt;: Simultaneously process documentation, implementation code, tests, and configuration files for truly holistic understanding impossible with smaller windows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Historical Context&lt;/strong&gt;: Maintain longer conversation histories without truncation, allowing the model to reference much earlier parts of your conversation without losing context.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real-world Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More Accurate Responses&lt;/strong&gt;: With access to complete codebases rather than fragments, Gemini can generate more contextually appropriate code that aligns with existing patterns and conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Context Manipulation&lt;/strong&gt;: Developers spend less time carefully selecting which files to include in their prompts, as Gemini can handle many files simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project-Wide Refactoring&lt;/strong&gt;: Execute large-scale refactoring operations across multiple files and directories with full awareness of interdependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete API Understanding&lt;/strong&gt;: Process entire API documentation alongside implementation code, enabling more accurate interface utilization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quantitative Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Context Window&lt;/th&gt;
&lt;th&gt;Files Simultaneously Analyzed&lt;/th&gt;
&lt;th&gt;Avg. Repository Coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 2.5 Pro&lt;/td&gt;
&lt;td&gt;1,000,000 tokens&lt;/td&gt;
&lt;td&gt;100+ files&lt;/td&gt;
&lt;td&gt;~85% of typical repos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Opus&lt;/td&gt;
&lt;td&gt;100,000 tokens&lt;/td&gt;
&lt;td&gt;10-15 files&lt;/td&gt;
&lt;td&gt;~25% of typical repos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4 Turbo&lt;/td&gt;
&lt;td&gt;128,000 tokens&lt;/td&gt;
&lt;td&gt;15-20 files&lt;/td&gt;
&lt;td&gt;~30% of typical repos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-3.5 Turbo&lt;/td&gt;
&lt;td&gt;16,000 tokens&lt;/td&gt;
&lt;td&gt;2-3 files&lt;/td&gt;
&lt;td&gt;~8% of typical repos&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This expanded context capability transforms how developers interact with AI assistants, enabling whole-project reasoning rather than file-by-file analysis, particularly valuable for complex software engineering tasks that span multiple components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Google Gemini CLI represents a significant advancement in bringing AI assistance directly to developers' terminals. &lt;/p&gt;

&lt;p&gt;The shared technology with Gemini Code Assist ensures consistency across environments, allowing developers to use familiar AI capabilities whether they're working in VS Code or the terminal. With its combination of powerful models, extensive tools, security features, and extensibility, Gemini CLI offers a versatile solution for developers seeking to incorporate AI into their workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.google/technology/developers/introducing-gemini-cli-open-source-ai-agent/" rel="noopener noreferrer"&gt;Introducing Gemini CLI: Open-Source AI Agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google-gemini/gemini-cli" rel="noopener noreferrer"&gt;Google Gemini CLI GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google-gemini/gemini-cli/tree/main/docs" rel="noopener noreferrer"&gt;Gemini CLI Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codeassist.google/" rel="noopener noreferrer"&gt;Gemini Code Assist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aistudio.google.com/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://console.cloud.google.com/vertex-ai/studio/multimodal" rel="noopener noreferrer"&gt;Vertex AI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>developer</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Streaming Responses from OpenAI Models: Technical Implementation Guide</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Fri, 18 Jul 2025 17:25:24 +0000</pubDate>
      <link>https://dev.to/pi19404/streaming-responses-from-openai-models-technical-implementation-guide-1ofp</link>
      <guid>https://dev.to/pi19404/streaming-responses-from-openai-models-technical-implementation-guide-1ofp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In contemporary AI-powered applications, responsiveness and user experience are critical technical requirements. Streaming responses from large language models (LLMs) offered by OpenAI represents a fundamental technique for developing responsive, interactive applications. This approach enables incremental processing of model outputs as they are generated, rather than requiring the complete response to be assembled prior to client-side delivery.&lt;/p&gt;

&lt;p&gt;This technical guide examines the architectural and implementation considerations for OpenAI model streaming, with particular emphasis on structured response formats, error handling methodologies, and cancellation mechanisms. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of Stream-Based Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced User Experience Metrics&lt;/strong&gt;: Provides immediate visual feedback, reducing perceived latency as measured by Time to First Meaningful Content (TFMC)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Optimization&lt;/strong&gt;: Enables early termination of requests when sufficient context has been acquired, optimizing token usage and reducing inference costs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Utilization&lt;/strong&gt;: Facilitates concurrent processing of partial responses, improving computational efficiency through pipeline parallelism&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Resilience&lt;/strong&gt;: Allows preservation of partial results in the event of mid-stream failures, enhancing system robustness&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture of OpenAI Streaming
&lt;/h2&gt;

&lt;p&gt;The implementation of streaming with OpenAI's models requires understanding the underlying HTTP and API architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTTP Connection Establishment&lt;/strong&gt;: The client initiates a request to the OpenAI API endpoint with the &lt;code&gt;stream=True&lt;/code&gt; parameter, which configures the server to establish a persistent connection using HTTP/1.1 chunked transfer encoding or HTTP/2 streams.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inference Process&lt;/strong&gt;: The model performs token-by-token generation through an autoregressive process, where each output token is conditioned on all previous tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Server-Side Chunking&lt;/strong&gt;: As tokens are generated, the API server packages them into discrete chunks conforming to the HTTP chunked encoding specification (RFC 7230), each containing a delta update to the response.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each chunk from the OpenAI API contains a delta representation rather than cumulative content. The response structure typically follows this format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chatcmpl-123..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chat.completion.chunk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1694268190&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-4o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"choices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"delta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token text here"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"finish_reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Client-Side Processing Pipeline&lt;/strong&gt;: The client implements an iterator pattern to process these chunks asynchronously, enabling immediate consumption without blocking on the complete response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connection Lifecycle Management&lt;/strong&gt;: The connection persists until one of three termination conditions occurs: normal completion (indicated by a &lt;code&gt;finish_reason&lt;/code&gt; of "stop"), error state, or explicit client-initiated cancellation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the final chunk, the &lt;code&gt;finish_reason&lt;/code&gt; field will contain "stop" to indicate normal completion, or alternative values like "length" for maximum token limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Implementation of Streaming
&lt;/h2&gt;

&lt;p&gt;To implement streaming with OpenAI's models, you'll need to set up your code to handle the incremental response chunks. Here's how to implement basic streaming in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize the client
&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-api-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stream_openai_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a streaming completion
&lt;/span&gt;    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# Enable streaming
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Process the stream
&lt;/span&gt;    &lt;span class="n"&gt;collected_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Extract the content from the chunk
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Display the chunk as it arrives
&lt;/span&gt;                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;collected_content&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;collected_content&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stream_openai_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain quantum computing in simple terms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cancellation Mechanism Deep Dive
&lt;/h2&gt;

&lt;p&gt;Implementing cancellation for streaming responses requires understanding several approaches:&lt;/p&gt;

&lt;p&gt;The most robust approach combines an event-based mechanism (using a threading.Event in Python) with proper signal handling. This allows both programmatic cancellation (from another thread) and user-initiated cancellation (via Ctrl+C).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example of a cancellation mechanism
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup_cancellation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;cancel_event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Store original handler
&lt;/span&gt;    &lt;span class="n"&gt;original_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getsignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGINT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;signal_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Cancellation requested...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cancel_event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Set new handler
&lt;/span&gt;    &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signal_handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cancel_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original_handler&lt;/span&gt;

&lt;span class="c1"&gt;# During streaming
&lt;/span&gt;&lt;span class="n"&gt;cancel_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setup_cancellation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cancel_event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_set&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Stream cancelled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="c1"&gt;# Process chunk
&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Restore original handler
&lt;/span&gt;    &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original_handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Error Handling Mid-Stream
&lt;/h2&gt;

&lt;p&gt;When working with streaming responses, error handling becomes more complex than with traditional API calls. Errors can occur at different stages of the streaming process, and robust error handling is essential for maintaining a good user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Error Scenarios
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Connection Interruptions&lt;/strong&gt;: Network issues can cause the stream to break unexpectedly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Rate Limiting&lt;/strong&gt;: Hitting rate limits during an ongoing stream&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Errors&lt;/strong&gt;: The model encounters an issue mid-generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Limit Exceeded&lt;/strong&gt;: Reaching maximum token limits during generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication Failures&lt;/strong&gt;: API key issues that arise during streaming&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In our &lt;code&gt;OpenAIStreamer&lt;/code&gt; implementation, we handle errors comprehensively through several mechanisms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;# Parameters...
&lt;/span&gt;        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Process chunks...
&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;error_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;

    &lt;span class="c1"&gt;# Yield error in structured format
&lt;/span&gt;    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error_msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;finish_reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error_description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production applications, more sophisticated error recovery strategies might include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Retries&lt;/strong&gt;: Implementing exponential backoff for transient errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partial Response Preservation&lt;/strong&gt;: Maintaining already-received content when errors occur&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By structuring error responses in the same format as successful responses, frontend applications can handle both scenarios uniformly, creating a more resilient user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured Response Format
&lt;/h2&gt;

&lt;p&gt;For production applications, it's critical to have a consistent structure for streaming responses. A JSON format with clear fields provides several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Status Tracking&lt;/strong&gt;: Fields like &lt;code&gt;finish_reason&lt;/code&gt; allow tracking the stream's state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Identification&lt;/strong&gt;: Dedicated error fields make error handling more systematic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Separation&lt;/strong&gt;: Clearly separating content from metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of a structured response format for streaming:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Streaming offers "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"finish_reason"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"error_description"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When an error occurs, the same structure can be maintained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[Error: API timeout, maximum retries exceeded]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"finish_reason"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"error_description"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timeout"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This consistent structure enables frontend applications to handle both successful responses and errors within the same processing pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;The full source code can be found at &lt;a href="https://gist.github.com/pi19404/4c0f9358610790bf9db3a2e9d09e357b" rel="noopener noreferrer"&gt;https://gist.github.com/pi19404/4c0f9358610790bf9db3a2e9d09e357b&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing streaming responses from OpenAI models requires careful architectural consideration of response protocols, error handling methodologies, and cancellation mechanisms. By adopting these engineering practices, applications can achieve more responsive user experiences while maintaining robustness under varied operating conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;OpenAI API Documentation: &lt;a href="https://platform.openai.com/docs/api-reference/streaming" rel="noopener noreferrer"&gt;https://platform.openai.com/docs/api-reference/streaming&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;HTTP/1.1 Chunked Transfer Encoding (RFC 7230): &lt;a href="https://tools.ietf.org/html/rfc7230#section-4.1" rel="noopener noreferrer"&gt;https://tools.ietf.org/html/rfc7230#section-4.1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python Threading and Concurrency: &lt;a href="https://docs.python.org/3/library/threading.html" rel="noopener noreferrer"&gt;https://docs.python.org/3/library/threading.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Signal Handling in Python: &lt;a href="https://docs.python.org/3/library/signal.html" rel="noopener noreferrer"&gt;https://docs.python.org/3/library/signal.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Exponential Backoff Algorithm: &lt;a href="https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/" rel="noopener noreferrer"&gt;https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Web Streams API: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Streams_API" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Streams_API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Flask Stream With Context: &lt;a href="https://flask.palletsprojects.com/en/2.0.x/patterns/streaming/" rel="noopener noreferrer"&gt;https://flask.palletsprojects.com/en/2.0.x/patterns/streaming/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;FastAPI Streaming Response: &lt;a href="https://fastapi.tiangolo.com/advanced/custom-response/#streamingresponse" rel="noopener noreferrer"&gt;https://fastapi.tiangolo.com/advanced/custom-response/#streamingresponse&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>openai</category>
      <category>streaming</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Automating Blog Publication on Dev.to: A Developer's Guide to the API</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Mon, 14 Jul 2025 12:40:24 +0000</pubDate>
      <link>https://dev.to/pi19404/automating-blog-publication-on-devto-a-developers-guide-to-the-api-2mo9</link>
      <guid>https://dev.to/pi19404/automating-blog-publication-on-devto-a-developers-guide-to-the-api-2mo9</guid>
      <description>&lt;h1&gt;
  
  
  Automating Blog Publication on Dev.to: A Developer's Guide to the API
&lt;/h1&gt;

&lt;p&gt;As developers, we're always looking for ways to streamline our workflows. If you're an active technical writer publishing on &lt;a href="https://dev.to"&gt;Dev.to&lt;/a&gt;, you've probably wondered if there's a way to automate the publishing process directly from your preferred writing environment. Good news! Dev.to offers a robust API that enables programmatic interaction with the platform.&lt;/p&gt;

&lt;p&gt;In this article, we will walk through the process of automating blog publication on Dev.to, covering everything from authentication to managing drafts and publishing articles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Automate Publishing to Dev.to?
&lt;/h2&gt;

&lt;p&gt;Before diving into the technical details, let's consider a few compelling reasons to automate your Dev.to publishing workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write in your preferred environment&lt;/strong&gt; - Author content in your favorite markdown editor, IDE, or note-taking app and publish without copy-pasting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform publishing&lt;/strong&gt; - Write once, publish to multiple platforms with format adaptation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version control integration&lt;/strong&gt; - Maintain your blog posts in Git repositories along with your code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch operations&lt;/strong&gt; - Publish or update multiple articles with a single command&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled publishing&lt;/strong&gt; - Queue posts to be published at optimal times&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up Authentication
&lt;/h2&gt;

&lt;p&gt;The Dev.to API uses API keys for authentication. To get started, you'll need to generate an API key:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to your Dev.to account&lt;/li&gt;
&lt;li&gt;Navigate to Settings → Account → DEV API Keys&lt;/li&gt;
&lt;li&gt;Create a new API key with an appropriate description&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you have your API key, you can include it in the headers of your API requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_api_key_here&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep your API key secure—it provides full access to create, update, and manage articles on your behalf.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Article Structure
&lt;/h2&gt;

&lt;p&gt;The Dev.to API represents articles using a JSON structure. The key properties include:&lt;/p&gt;

&lt;h3&gt;
  
  
  Article Metadata
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"article"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your Article Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"published"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"body_markdown"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your article content in markdown format..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tutorial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"automation"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"series"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Optional Series Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"canonical_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://original-site.com/if-crossposting"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Brief description of your article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cover_image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://url-to-cover-image.jpg"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some important notes on these fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;title&lt;/strong&gt;: Required field for all articles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;published&lt;/strong&gt;: Boolean flag determining if the article is a draft (&lt;code&gt;false&lt;/code&gt;) or published (&lt;code&gt;true&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;body_markdown&lt;/strong&gt;: The full content of your article in markdown format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tags&lt;/strong&gt;: Array of up to 4 tags that help categorize your article&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;series&lt;/strong&gt;: Optional field to group related articles together&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;canonical_url&lt;/strong&gt;: If you're cross-posting, set this to the original URL to avoid SEO penalties&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;description&lt;/strong&gt;: A brief summary shown in article previews&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cover_image&lt;/strong&gt;: URL to a header image for your article&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core API Endpoints
&lt;/h2&gt;

&lt;p&gt;Dev.to provides several RESTful endpoints for article management:&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a New Article
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.to/api/articles&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;article&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;article_data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to create article: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, this creates a draft article. To publish immediately, include &lt;code&gt;"published": true&lt;/code&gt; in your article data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Your Articles
&lt;/h3&gt;

&lt;p&gt;You can retrieve your published and draft articles separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Get published articles
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_published_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.to/api/articles/me/published&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to fetch articles: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Get draft articles
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_draft_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.to/api/articles/me/unpublished&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;per_page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to fetch draft articles: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These methods return lists of article objects containing metadata and IDs, which you'll need for further operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Article IDs
&lt;/h3&gt;

&lt;p&gt;Each article on Dev.to has a unique ID, which is essential for operations like updating, publishing, or deleting. When you create an article or retrieve a list of your articles, the API response includes this ID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your Article Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Article description..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"published"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Additional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;fields...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ID becomes the key identifier for all subsequent operations on the article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating an Existing Article
&lt;/h3&gt;

&lt;p&gt;To update an article, you need its ID and the fields you want to modify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.to/api/articles/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;article&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;update_data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to update article: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function is versatile—you can update any article properties, including the &lt;code&gt;published&lt;/code&gt; status.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Draft-to-Published Workflow
&lt;/h2&gt;

&lt;p&gt;One of the most common workflows is creating a draft, reviewing it, and then publishing it. Here's how to implement this flow programmatically:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a Draft
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;draft_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My Technical Article&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body_markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;# Introduction&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;This is the start of my article...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;programming&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tutorial&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;published&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;  &lt;span class="c1"&gt;# This creates a draft
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;draft_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Update the Draft (Optional)
&lt;/h3&gt;

&lt;p&gt;You might want to make changes after reviewing the draft in the Dev.to interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;update_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body_markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;# Revised Introduction&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;This is the improved start of my article...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;updated_draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;update_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Publish the Draft
&lt;/h3&gt;

&lt;p&gt;When you're ready to publish, simply update the &lt;code&gt;published&lt;/code&gt; status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;publish_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;published&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;published_article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;update_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;publish_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This transition from draft to published is handled seamlessly by the Dev.to API. The article retains all its content and metadata while changing its visibility status.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Handling Frontmatter
&lt;/h3&gt;

&lt;p&gt;Dev.to supports YAML frontmatter in markdown files, which provides a convenient way to define article metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My Amazing Article&lt;/span&gt;
&lt;span class="na"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api, tutorial&lt;/span&gt;
&lt;span class="na"&gt;series&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;API Mastery&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Article Content Starts Here&lt;/span&gt;

Your article body...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When working with files that include frontmatter, you'll need to parse them correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;frontmatter&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_markdown_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_article_from_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;markdown_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_markdown_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;article_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Untitled&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;published&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;published&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body_markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;series&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;series&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;canonical_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;canonical_url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cover_image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;markdown_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cover_image&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Remove None values
&lt;/span&gt;    &lt;span class="n"&gt;article_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;article_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;create_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach allows you to maintain article metadata directly in your markdown files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Batch Publishing
&lt;/h3&gt;

&lt;p&gt;If you have multiple drafts you'd like to publish, you can implement a batch operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;batch_publish_drafts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_ids&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;article_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;draft_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;update_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;published&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;article_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;article&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="c1"&gt;# Be nice to the API with a small delay
&lt;/span&gt;            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;article_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This article was created using the MarkdownPublisher class demonstrated in the examples above. The complete source code for a publishing automation tool is available on &lt;a href="https://gist.github.com/pi19404/133c9b6db9b0304b75d25717878c80cf" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices and Limitations
&lt;/h2&gt;

&lt;p&gt;When working with the Dev.to API, keep these considerations in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dev.to applies rate limiting to API requests. While the exact limits aren't prominently documented, it's good practice to add delays between requests, especially when performing batch operations.&lt;/li&gt;
&lt;li&gt;Dev.to limits articles to a maximum of 4 tags.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Dev.to API provides powerful capabilities for programmatic article management, enabling developers to build custom publishing workflows. Whether you're looking to automate personal blog posts or managing a technical publication with multiple authors, understanding these API concepts will help you streamline your process.&lt;/p&gt;

</description>
      <category>api</category>
      <category>automation</category>
      <category>python</category>
      <category>devto</category>
    </item>
    <item>
      <title>How to Create a Virtual Environment with a Specific Python Version</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Sat, 12 Jul 2025 12:04:09 +0000</pubDate>
      <link>https://dev.to/pi19404/how-to-create-a-virtual-environment-with-a-specific-python-version-linux-macos-4g3p</link>
      <guid>https://dev.to/pi19404/how-to-create-a-virtual-environment-with-a-specific-python-version-linux-macos-4g3p</guid>
      <description>&lt;p&gt;Managing multiple Python projects often means juggling different package versions—and sometimes entirely different Python versions. This is where virtual environments shine. In this blog post, you'll learn how to create an isolated virtual environment using a specific version of Python, tailored for &lt;strong&gt;Linux and macOS&lt;/strong&gt; users.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Why Use a Virtual Environment?
&lt;/h2&gt;

&lt;p&gt;Before jumping into the steps, here’s why using virtual environments is considered best practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolated Dependencies:&lt;/strong&gt; Keeps project requirements isolated from your system Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoids Conflicts:&lt;/strong&gt; Prevents dependency collisions across different projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproducibility:&lt;/strong&gt; Makes deployments and collaboration smoother by standardizing environments.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure your target Python version is available on your system. You can verify which versions are installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /usr/bin/python&lt;span class="k"&gt;*&lt;/span&gt;          &lt;span class="c"&gt;# Linux&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; /opt/homebrew/bin/python&lt;span class="k"&gt;*&lt;/span&gt;  &lt;span class="c"&gt;# macOS with Homebrew&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your desired version is missing, install it using &lt;code&gt;pyenv&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔧 Installing &lt;code&gt;pyenv&lt;/code&gt; (Recommended for Managing Multiple Python Versions)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Install Dependencies
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux (Debian/Ubuntu):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; make build-essential libssl-dev zlib1g-dev &lt;span class="se"&gt;\&lt;/span&gt;
libbz2-dev libreadline-dev libsqlite3-dev curl git libncursesw5-dev &lt;span class="se"&gt;\&lt;/span&gt;
xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;macOS (with Homebrew):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;openssl readline sqlite3 xz zlib
brew &lt;span class="nb"&gt;install &lt;/span&gt;pyenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Add pyenv to your shell startup file
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bash:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'\n# pyenv setup'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PYENV_ROOT="$HOME/.pyenv"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$PYENV_ROOT/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'eval "$(pyenv init --path)"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zsh:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'\n# pyenv setup'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PYENV_ROOT="$HOME/.pyenv"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$PYENV_ROOT/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'eval "$(pyenv init --path)"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reload your shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc      &lt;span class="c"&gt;# or ~/.zshrc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Install a Specific Python Version
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyenv &lt;span class="nb"&gt;install &lt;/span&gt;3.10.12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧪 Creating the Virtual Environment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1: Using &lt;code&gt;python -m venv&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the built-in way to create a virtual environment using a specific Python binary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Activate desired Python version (if using pyenv)&lt;/span&gt;
pyenv shell 3.10.12

&lt;span class="c"&gt;# Create the virtual environment&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv-py310
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also specify the full path to the Python binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/homebrew/bin/python3.10 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv-py310  &lt;span class="c"&gt;# macOS&lt;/span&gt;
/usr/bin/python3.10 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv-py310           &lt;span class="c"&gt;# Linux&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Option 2: Using &lt;code&gt;virtualenv&lt;/code&gt; (Alternative Approach)
&lt;/h3&gt;

&lt;p&gt;First, install &lt;code&gt;virtualenv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;virtualenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;virtualenv &lt;span class="nt"&gt;-p&lt;/span&gt; /usr/bin/python3.10 venv-py310      &lt;span class="c"&gt;# Linux&lt;/span&gt;
virtualenv &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/homebrew/bin/python3.10 venv-py310  &lt;span class="c"&gt;# macOS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚀 Activating the Virtual Environment
&lt;/h2&gt;

&lt;p&gt;To activate the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;venv-py310/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now see the environment name in your prompt like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv-py310&lt;span class="o"&gt;)&lt;/span&gt; user@hostname:~/project&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧹 Deactivating and Cleaning Up
&lt;/h2&gt;

&lt;p&gt;To deactivate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deactivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To delete the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; venv-py310
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧩 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Using a specific Python version in a virtual environment helps avoid compatibility issues, ensures reproducible builds, and keeps your system Python clean. This is especially important for macOS and Linux users, where the system Python might be tied to operating system functions.&lt;/p&gt;

</description>
      <category>python</category>
      <category>pythonvirutalenv</category>
      <category>virtualenv</category>
      <category>software</category>
    </item>
    <item>
      <title>MCP Server Setup with OAuth Authentication using Auth0 and Claude.ai Remote MCP Integration</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Wed, 09 Jul 2025 13:26:38 +0000</pubDate>
      <link>https://dev.to/pi19404/mcp-server-setup-with-oauth-authentication-using-auth0-and-claudeai-remote-mcp-integration-5ghl</link>
      <guid>https://dev.to/pi19404/mcp-server-setup-with-oauth-authentication-using-auth0-and-claudeai-remote-mcp-integration-5ghl</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;This technical guide provides a comprehensive walkthrough for implementing a Model Context Protocol (MCP) server with robust OAuth 2.0 authentication, leveraging Auth0 as the identity provider. The focus is on achieving full compatibility with Claude.ai’s requirements for Dynamic Client Registration (DCR) as specified in RFC 7591. Unlike traditional OAuth integrations that rely on static client credentials, Claude.ai mandates that MCP servers support dynamic, standards-compliant registration and discovery endpoints, enabling third-party clients to obtain credentials and initiate secure authorization flows programmatically.&lt;/p&gt;

&lt;p&gt;We will learn how to configure Auth0 to enable OIDC dynamic application registration, promote connections to domain-level for third-party authentication, and expose the necessary OAuth endpoints for automated client onboarding. The guide details the limitations of libraries, such as fastapi_mcp in this context, and demonstrates how to use the fastmcp and mcpauth libraries to implement an MCP server that supports dynamic registration, PKCE, and secure token exchange.&lt;/p&gt;

&lt;p&gt;Step-by-step instructions are provided for both the Auth0 dashboard and API configuration&lt;/p&gt;

&lt;h3&gt;
  
  
  fastapi_mcp library limitations
&lt;/h3&gt;

&lt;p&gt;For OAuth-based MCP servers, Claude.ai requires Dynamic Client Registration (DCR) support as per RFC 7591 and does not yet support a way for users to specify a client ID or secret manually.&lt;/p&gt;

&lt;p&gt;The fastapi_mcp library, while excellent for many MCP use cases, has several limitations when it comes to Claude.ai's OAuth requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No Dynamic Client Registration Support&lt;/strong&gt; : fastapi_mcp Requires pre-configured client IDs and secrets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Configuration&lt;/strong&gt; : Cannot handle Claude.ai’s dynamic application creation process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Inspector Compatibility&lt;/strong&gt; : OAuth testing via MCP inspector fails with static configurations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RFC 7591 Compliance&lt;/strong&gt; : Lacks support for the Dynamic Client Registration standard required by Claude.ai
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This approach with fastapi_mcp does NOT work with Claude.ai OAuth
from fastapi_mcp import FastApiMCP, AuthConfig

# Static configuration - incompatible with Claude.ai
auth_config = AuthConfig(
    client_id="static-client-id", # Claude.ai doesn't support this
    client_secret="static-secret", # Claude.ai creates these dynamically
    setup_proxies=True,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using fastmcp and mcpauth Libraries
&lt;/h3&gt;

&lt;p&gt;To properly support Claude.ai’s OAuth requirements, we use the fastmcp library with mcpauth For OAuth management:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install fastmcp mcpauth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These libraries provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Client Registration (RFC 7591)&lt;/strong&gt; support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude.ai compatibility&lt;/strong&gt; out of the box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Inspector&lt;/strong&gt; OAuth testing capabilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proper OAuth 2.0 flows&lt;/strong&gt; with PKCE support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Auth0 Configuration for Dynamic Client Registration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Enable OIDC Dynamic Application Registration
&lt;/h4&gt;

&lt;p&gt;By default, Auth0 disables dynamic application registration for security reasons. To enable it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Auth0 Dashboard&lt;/strong&gt; → &lt;strong&gt;Tenant Settings&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Advanced Settings&lt;/strong&gt;  tab&lt;/li&gt;
&lt;li&gt;Find &lt;strong&gt;“Enable OIDC Dynamic Application Registration”&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable&lt;/strong&gt; this setting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focjq0zeu61xbk3ggwq12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focjq0zeu61xbk3ggwq12.png" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt; : This setting allows third-party applications to dynamically register applications for your API. Ensure you have proper security measures in place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Grant Auth0 Management API Scopes for Connection Management
&lt;/h3&gt;

&lt;p&gt;After enabling dynamic registration, you must ensure that your Auth0 Management API client has the correct permissions to manage connections. Specifically, you need to grant the update:connections and read:connections scopes to your Management API client. These scopes allow your automation or scripts to promote connections to domain-level and read connection details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Granting Management API Scopes to Your Client&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Log in to the Auth0 Dashboard&lt;/strong&gt; at &lt;a href="https://manage.auth0.com/" rel="noopener noreferrer"&gt;https://manage.auth0.com/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a Machine to Machine Application&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Applications&lt;/strong&gt; → &lt;strong&gt;Applications&lt;/strong&gt; in the sidebar.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Application&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter a name (e.g., “MCP Management Client”), select &lt;strong&gt;Machine to Machine Applications&lt;/strong&gt; , and click  &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Machine to Machine Applications require at least one authorized API. Select the Auth0 Management API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwstx6urie2721904zs6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwstx6urie2721904zs6.png" width="800" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the permissions &lt;strong&gt;read:connections&lt;/strong&gt;  , &lt;strong&gt;update:connections , read:clients&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Authorize&lt;/strong&gt; to save the changes.&lt;/li&gt;
&lt;li&gt;Note the Client ID and Client Secret from the settings page-&amp;gt; Basic Information Section&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your machine-to-machine application is now authorized to manage Auth0 connections using the Management API with the necessary scopes.&lt;/p&gt;

&lt;p&gt;Your client now has the necessary permissions to manage Auth0 connections via the Management API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: &lt;strong&gt;Obtain a Management API Token&lt;/strong&gt; (with the required scopes):
&lt;/h3&gt;

&lt;p&gt;Run the below command to obtain the management API Token&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export AUTH0_DOMAIN=asdasda 
export AUTH0_CLIENT_ID=adsdasd 
export AUTH0_CLIENT_SECRET=asdasdasd

ACCESS_TOKEN=$(curl --silent --request POST \
      --url "https://${AUTH0_DOMAIN}/oauth/token" \
      --header 'content-type: application/x-www-form-urlencoded' \
      --data "grant_type=client_credentials" \
      --data "client_id=${AUTH0_CLIENT_ID}" \
      --data "client_secret=${AUTH0_CLIENT_SECRET}" \
      --data "audience=https://${AUTH0_DOMAIN}/api/v2/" \
      --data "scope=update:connections read:connections read:clients" \
      | grep -o '"access_token":"[^"]*"' | cut -d':' -f2 | tr -d '"')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Verify the Client’s Granted Scopes&lt;/strong&gt; :
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --request GET \
--url "https://${AUTH0_DOMAIN}/api/v2/clients/${AUTH0_CLIENT_ID}" \
--header "authorization: Bearer ${ACCESS_TOKEN}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the grant_types and scopes fields in the response to ensure update:connections and read:connections are present.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These scopes are only for managing Auth0 system resources (connections) and are not related to API resource access for end-user tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Create Domain-Level Connections
&lt;/h3&gt;

&lt;p&gt;Claude.ai requires domain-level connections for third-party application authentication. By default, Auth0 connections are not domain-level.&lt;/p&gt;

&lt;h4&gt;
  
  
  Promote Connection to Domain-Level via Management API
&lt;/h4&gt;

&lt;p&gt;Use the Auth0 Management API to promote your connection to domain-level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# First, get your Management API token
ACCESS_TOKEN=$(curl --silent --request POST \
    --url "https://${AUTH0_DOMAIN}/oauth/token" \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data "grant_type=client_credentials" \
    --data "client_id=${AUTH0_CLIENT_ID}" \
    --data "client_secret=${AUTH0_CLIENT_SECRET}" \
    --data "audience=https://${AUTH0_DOMAIN}/api/v2/" \
    --data "scope=update:connections read:connections" \
    | grep -o '"access_token":"[^"]*"' | cut -d':' -f2 | tr -d '"')

#To find your Google OAuth connection ID automatically, you can extract it from the API response using `jq` (a command-line JSON processor):

# List all connections and extract the ID for the google-oauth2 connection
GOOGLE_CONNECTION_ID=$(curl --silent --request GET \
    --url "https://${AUTH0_DOMAIN}/api/v2/connections" \
    --header "authorization: Bearer ${ACCESS_TOKEN}" \
    | jq -r '.[] | select(.name=="google-oauth2") | .id')
echo "Google OAuth connection ID: $GOOGLE_CONNECTION_ID"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command fetches all connections and filters for the one named "google-oauth2", outputting its "id" field. Use the value of $GOOGLE_CONNECTION_ID in the PATCH request to promote the connection to domain-level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# promote the connection to domain-level
curl --request PATCH \
  --url "https://${AUTH0_DOMAIN}/api/v2/connections/${GOOGLE_CONNECTION_ID}" \
  --header "authorization: Bearer ${ACCESS_TOKEN}" \
  --header 'content-type: application/json' \
  --data '{ "is_domain_connection": true }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MCP Server Implementation with fastmcp
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Server Setup with OAuth Support
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastmcp import FastMCP
from mcpauth import MCPAuth
import asyncio
import logging

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

......
other code

# Initialize MCP server with OAuth
mcp_auth = MCPAuth(
    server=fetch_server_config(
        settings["issuer"],
        type=AuthServerType.OAUTH  # or AuthServerType.OAUTH
    )
)

app = FastAPI()

@app.get("/", operation_id="root")
async def root():
    """Root endpoint with API information"""

    return {
        "message": "Dev.to Markdown Publisher API",
        "version": "1.0.0",
    }

api_mcp = FastMCP.from_fastapi(app=app, name="API Server")

bearer_auth = mcp_auth.bearer_auth_middleware(
    "jwt", required_scopes=["read", "write"]
)

mcp_app = api_mcp.http_app(path='/mcp')

mcp_app.dependency_overrides = getattr(mcp_app, "dependency_overrides", {})
mcp_app.dependency_overrides[None] = bearer_auth


app = FastAPI(lifespan=tools_app.lifespan)

# Mount the MCP SSE app at /mcp
app.mount("/mcp", mcp_app)
# Add the metadata route for OAuth server discovery at /.well-known/oauth-authorization-server
app.add_route("/.well-known/oauth-authorization-server", mcp_auth.metadata_route(), methods=["GET"])

if __name__ == "__main__":
    # Run with OAuth support enabled
    uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Claude.ai Dynamic Application Registration
&lt;/h3&gt;

&lt;p&gt;When Claude.ai connects to your MCP server with OAuth enabled, it automatically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Discovers OAuth Endpoints&lt;/strong&gt; : Calls /.well-known/oauth-authorization-server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registers Dynamic Client&lt;/strong&gt; : POSTs to /oauth/register endpoint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creates Auth0 Application&lt;/strong&gt; : You’ll see “Claude.ai” app automatically created in Auth0 dashboard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initiates OAuth Flow&lt;/strong&gt; : Redirects user for authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exchanges Tokens&lt;/strong&gt; : Completes PKCE flow with dynamic client credentials&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Viewing Dynamically Registered Applications
&lt;/h3&gt;

&lt;p&gt;After Claude.ai connects, check your Auth0 dashboard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Applications&lt;/strong&gt; section&lt;/li&gt;
&lt;li&gt;Look for automatically created applications with names like:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;“Claude.ai MCP Client”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These applications are created automatically by Claude.ai through the dynamic registration process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Implementing OAuth authentication for MCP servers with Claude.ai requires careful attention to dynamic client registration requirements. The combination of fastmcp, mcpauth, and properly configured Auth0 settings enables seamless integration with Claude.ai's OAuth flows while maintaining security best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key takeaways:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use fastmcp and mcpauth instead of fastapi_mcp for Claude.ai compatibility&lt;/li&gt;
&lt;li&gt;Enable OIDC Dynamic Application Registration in Auth0&lt;/li&gt;
&lt;li&gt;Promote connections to domain-level for third-party app support&lt;/li&gt;
&lt;li&gt;Monitor Auth0 dashboard for automatically created Claude.ai applications&lt;/li&gt;
&lt;li&gt;Test thoroughly with MCP Inspector before deploying to production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup ensures that your MCP server can authenticate users securely while providing the dynamic client registration capabilities that Claude.ai requires for OAuth integration.&lt;/p&gt;




</description>
      <category>mcpserver</category>
      <category>claudeai</category>
      <category>agentiai</category>
      <category>oauth</category>
    </item>
    <item>
      <title>Claude AI MCP Integration and nGrok: Secure Tunnels to Your Local Development Environment</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Sat, 05 Jul 2025 18:54:38 +0000</pubDate>
      <link>https://dev.to/pi19404/claude-ai-mcp-integration-and-ngrok-secure-tunnels-to-your-local-development-environment-4gpn</link>
      <guid>https://dev.to/pi19404/claude-ai-mcp-integration-and-ngrok-secure-tunnels-to-your-local-development-environment-4gpn</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;This technical article explores the integration of Anthropic’s Claude Message Context Protocol (MCP) with nGrok secure tunneling technology to establish robust connections between cloud-based AI systems and local development environments. We will demonstrate the implementation process for configuring a development MCP server, exposing it securely through nGrok’s encrypted tunneling infrastructure, and validating the configuration using the Claude API platform.&lt;/p&gt;

&lt;p&gt;The combination of these technologies enables developers to prototype and test AI-powered applications with enterprise-grade security protocols while maintaining the flexibility and rapid iteration capabilities of local development environments. This approach eliminates the need to deploy applications to staging environments during development, while still allowing for secure, real-time communication with cloud-based large language models.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Claude MCP
&lt;/h3&gt;

&lt;p&gt;MCP is an open protocol that standardizes how applications provide context to LLMs. MCP provides a standardized way to connect AI models to various data sources and tools, helping you build agents and complex workflows on top of LLMs. It does so by allowing servers to expose tools that language models can invoke. Tools enable models to interact with external systems, such as querying databases, calling APIs, or performing computations. A name uniquely identifies each tool and includes metadata describing its schema.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is ngrok?
&lt;/h3&gt;

&lt;p&gt;ngrok is a powerful command-line tool and service that creates secure tunnels from public URLs to your local development server. It acts as a reverse proxy, allowing you to expose your locally running applications to the internet without the need for complex network configurations, port forwarding, or deploying to a staging server.&lt;/p&gt;

&lt;p&gt;When you run ngrok, it establishes a secure connection to ngrok’s cloud service, which then provides you with a public URL that forwards traffic to your local application. This URL can be accessed from anywhere on the internet, making it invaluable for development, testing, and demonstration purposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Claude MCP Works
&lt;/h3&gt;

&lt;p&gt;When you ask a question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client sends your question to Claude&lt;/li&gt;
&lt;li&gt;Claude analyzes the available tools and decides which one(s) to use&lt;/li&gt;
&lt;li&gt;The client executes the chosen tool(s) through the MCP server&lt;/li&gt;
&lt;li&gt;The results are sent back to Claude&lt;/li&gt;
&lt;li&gt;Claude formulates a natural language response&lt;/li&gt;
&lt;li&gt;The response is displayed to you!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How ngrok Works
&lt;/h3&gt;

&lt;p&gt;ngrok operates through a simple yet elegant architecture. When you start ngrok, it creates an encrypted tunnel between your local machine and ngrok’s edge servers. These servers then route incoming requests from the public internet through this tunnel to your local application.&lt;/p&gt;

&lt;p&gt;The process involves several components: the ngrok client running on your machine, the ngrok service in the cloud, and the secure tunnel connecting them. All traffic passes through this encrypted tunnel, ensuring that your local development environment remains secure while being accessible from the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  NGROK Installation Guide
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Installing ngrok on Different Platforms
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;macOS Installation:&lt;/strong&gt; The easiest way to install ngrok on macOS is through Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install ngrok/ngrok/ngrok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can download the binary directly from the ngrok website and add it to your PATH.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows Installation:&lt;/strong&gt; For Windows users, you can download the executable from the ngrok website and either run it directly or add it to your system PATH. Windows users can also use package managers like Chocolatey:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;choco install ngrok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux Installation:&lt;/strong&gt; Linux users can download the appropriate binary for their architecture from the &lt;a href="https://ngrok.com/downloads/linux" rel="noopener noreferrer"&gt;https://ngrok.com/downloads/linux&lt;/a&gt; . After downloading, extract the binary and move it to a directory in your PATH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \
  | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc &amp;gt;/dev/null \
  &amp;amp;&amp;amp; echo "deb https://ngrok-agent.s3.amazonaws.com buster main" \
  | sudo tee /etc/apt/sources.list.d/ngrok.list \
  &amp;amp;&amp;amp; sudo apt update \
  &amp;amp;&amp;amp; sudo apt install ngrok

# Or

sudo tar -xvzf ~/Downloads/ngrok-v3-stable-linux-amd64.tgz -C /usr/local/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Account Setup and Authentication
&lt;/h3&gt;

&lt;p&gt;While ngrok can be used without an account for basic functionality, creating a free account provides additional features and removes some limitations. After creating an account on the ngrok website, you’ll receive an authentication token.&lt;/p&gt;

&lt;p&gt;To configure ngrok with your authentication token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok config add-authtoken YOUR_AUTH_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command stores your authentication token in ngrok’s configuration file, allowing you to access premium features and remove the time restrictions on free tunnels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Usage Examples
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Exposing a Local Web Server
&lt;/h4&gt;

&lt;p&gt;The most common use case is exposing a local web server. If you have a web application running on port 3000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a tunnel to your local server and provides you with a public URL that looks like &lt;a href="https://abc123.ngrok.io." rel="noopener noreferrer"&gt;https://abc123.ngrok.io.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Exposing Other Protocols
&lt;/h4&gt;

&lt;p&gt;ngrok isn’t limited to HTTP traffic. You can expose TCP services as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok tcp 22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would expose your local SSH server to the internet, though this should be done with caution for security reasons.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom Subdomains
&lt;/h4&gt;

&lt;p&gt;With a paid ngrok account, you can specify custom subdomains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http --subdomain=myapp 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a tunnel with a predictable URL like &lt;a href="https://myapp.ngrok.io." rel="noopener noreferrer"&gt;https://myapp.ngrok.io.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Development server
&lt;/h3&gt;

&lt;p&gt;ngrok excels at allowing developers to test their applications with real-world scenarios without deploying to a staging environment. You can quickly share your work-in-progress application with team members, clients, or stakeholders by simply sharing the ngrok URL.&lt;/p&gt;

&lt;p&gt;We host an MCP Server that provides crypto current market information&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application is hosted using FastAPI Server&lt;/li&gt;
&lt;li&gt;The data is obtained using CoinMarketCap platform API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The function definition is as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.get("/api/currency-info")
async def get_currency_info(
    exchange: CryptoExchange = Depends(get_exchange),
    symbols: str = Query(None, description="Comma-separated list of currency symbols (e.g., BTC,ETH,ADA)"),
    convert: str = Query("USD", description="Currency to convert values to (e.g., USD, EUR)")
):
    """Get detailed currency information from CoinMarketCap including market cap, supply, and price metrics"""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of the function for input currency BTC is as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "data": {
    "BTC": {
      "id": 1,
      "name": "Bitcoin",
      "symbol": "BTC",
      "slug": "bitcoin",
      "cmc_rank": 1,
      "circulating_supply": 19887956,
      "total_supply": 19887956,
      "max_supply": 21000000,
      "last_updated": "2025-07-05T14:18:00.000Z",
      "pricing": {
        "price": 108244.86616819742,
        "volume_24h": 38435406044.59744,
        "volume_change_24h": -6.6511,
        "percent_change_1h": 0.03610656,
        "percent_change_24h": 0.41189629,
        "percent_change_7d": 0.95202959,
        "percent_change_30d": 4.04716341,
        "percent_change_60d": 14.83875876,
        "percent_change_90d": 31.23696181,
        "market_cap": 2152769135578.9988,
        "market_cap_dominance": 64.7036,
        "fully_diluted_market_cap": 2273142189532.15,
        "last_updated": "2025-07-05T14:18:00.000Z"
      },
      "additional_metrics": {
        "volume_to_mc_ratio": 0.017853937707194057,
        "market_dominance_percent": 100.0,
        "circulating_to_max_ratio": 94.70455238095238,
        "fully_diluted_valuation": 2273142189532.15
      }
    }
  },
  "convert": "USD",
  "count": 1,
  "timestamp": "2025-07-05T19:49:58.756412"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the fastapi_mcp Python package &lt;a href="https://github.com/tadata-org/fastapi%5C_mcp/tree/main" rel="noopener noreferrer"&gt;https://github.com/tadata-org/fastapi\_mcp/tree/main&lt;/a&gt; which provides a facility to expose your FastAPI endpoints as Model Context Protocol (MCP) tools, with Auth!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import APIRouter
from fastapi_mcp import FastApiMCP

other_router = APIRouter(prefix="/other/route")    
app.include_router(other_router)
# Mount the MCP server to a separate FastAPI app
mcp = FastApiMCP(app)
mcp.mount(other_router)

def run():
    uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We expose the MCP server at the route /other/route/mcp&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude MCP Server configuration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Adding the MCP Server on the ngrok Endpoint as a Custom Integration
&lt;/h4&gt;

&lt;p&gt;We have our MCP server running locally at port 8000 and listening on all interfaces 0.0.0.0. And since ngrok is set up to create a secure tunnel, we need to connect our MCP server to Claude by registering it as a custom integration.&lt;/p&gt;

&lt;p&gt;Once your MCP server is running, use ngrok to create a secure tunnel to your local server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this command, ngrok will display a URL (typically in the format &lt;a href="https://xxxx-xxxx-xxxx.ngrok.io" rel="noopener noreferrer"&gt;https://xxxx-xxxx-xxxx.ngrok.io&lt;/a&gt;). Make note of this URL as you'll need it for the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Register your MCP Server as a Custom Integration in Claude
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;a href="https://claude.ai/settings/integrations" rel="noopener noreferrer"&gt;Claude AI Integrations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click “Add Integration”&lt;/li&gt;
&lt;li&gt;Enter the following details:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; : Give your integration a descriptive name (e.g., “Crypto Market Data MCP”)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server URL&lt;/strong&gt; : Enter your ngrok URL followed by the MCP endpoint path. For our example: &lt;a href="https://xxxx-xxxx-xxxx.ngrok.io/other/route/mcp" rel="noopener noreferrer"&gt;https://xxxx-xxxx-xxxx.ngrok.io/other/route/mcp&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Click “Create” to register your integration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AiEOWx-ixz3Kt-Azx" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AiEOWx-ixz3Kt-Azx" width="1024" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify the Integration
&lt;/h3&gt;

&lt;p&gt;After registering your custom integration, Click on Connect to verify that your MCP server is properly configured by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checking that the MCP server URL is accessible&lt;/li&gt;
&lt;li&gt;Validating that the server correctly implements the MCP protocol&lt;/li&gt;
&lt;li&gt;Retrieving the list of available tools from your server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the verification is successful, your integration will be marked as “Active” in the Claude Console.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Integration in Claude
&lt;/h3&gt;

&lt;p&gt;Now you can test your custom integration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start a new conversation in Claude&lt;/li&gt;
&lt;li&gt;Check that your custom integration is visible and enabled in the tools section&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AqoVYfgF9mdzZWTwc" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AqoVYfgF9mdzZWTwc" width="1024" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask Claude a question that would require information from your crypto market data tool, such as “show the currency information for BTC in tabular format”&lt;/li&gt;
&lt;li&gt;Claude will recognize the need to use your tool, make the appropriate API call through the MCP server, and provide you with the results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can see that the MCP Server is called with the request and the output response.&lt;/p&gt;

&lt;p&gt;get_currency_info_api_currency_info_get&lt;/p&gt;

&lt;p&gt;Request&lt;/p&gt;

&lt;p&gt;{ &lt;code&gt;symbols&lt;/code&gt;: &lt;code&gt;BTC&lt;/code&gt; }&lt;/p&gt;

&lt;p&gt;Response&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "data": { "BTC": { "id": 1, "name": "Bitcoin", "symbol": "BTC", "slug": "bitcoin", "cmc_rank": 1, "circulating_supply": 19887987, "total_supply": 19887987, "max_supply": 21000000, "last_updated": "2025-07-05T16:37:00.000Z", "pricing": { "price": 107963.95555873076, "volume_24h": 33053849608.85693, "volume_change_24h": -23.731, "percent_change_1h": -0.1760637, "percent_change_24h": 0.35855272, "percent_change_7d": 0.48666905, "percent_change_30d": 3.83166081, "percent_change_60d": 14.07595308, "percent_change_90d": 31.15425869, "market_cap": 2147185744620.615, "market_cap_dominance": 64.6759, "fully_diluted_market_cap": 2267243066733.35, "last_updated": "2025-07-05T16:37:00.000Z" }, "additional_metrics": { "volume_to_mc_ratio": 0.015394033651568042, "market_dominance_percent": 100.0, "circulating_to_max_ratio": 94.7047, "fully_diluted_valuation": 2267243066733.35 } } }, "convert": "USD", "count": 1, "timestamp": "2025-07-05T22:08:34.125383" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AiT3FyjTvQUigbUB_" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AiT3FyjTvQUigbUB_" width="1024" height="1345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember that while ngrok is ideal for development and testing, for production deployments, it is recommended to host your MCP server on a stable, secure infrastructure with a fixed URL, rather than relying on temporary ngrok tunnels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Considerations
&lt;/h3&gt;

&lt;p&gt;While ngrok is incredibly useful for development, it’s essential to understand the security implications. When you create a tunnel, you’re exposing your local application to the internet, which means anyone with the URL can potentially access it.&lt;/p&gt;

&lt;p&gt;For sensitive applications, consider using ngrok’s authentication features, such as basic authentication or custom headers. Always be mindful of what data you’re exposing and avoid using ngrok tunnels for production applications unless you have specific security measures in place.&lt;/p&gt;

&lt;p&gt;The ngrok service itself uses strong encryption for all tunnel traffic, ensuring that data passing through the tunnel remains secure. However, the endpoints themselves become publicly accessible, so proper application-level security remains crucial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;ngrok has become an essential tool in the modern developer’s toolkit, dramatically simplifying the process of testing, demonstrating, and integrating applications that require interaction with external services. Its ease of use, combined with powerful features, makes it invaluable for everything from simple webhook testing to complex IoT device development.&lt;/p&gt;




</description>
      <category>aritificialintellige</category>
      <category>aiagentdevelopment</category>
      <category>claudemcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>Erasing Git History: How to Keep Only Your Latest Commit on GitHub</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Thu, 26 Jun 2025 15:12:49 +0000</pubDate>
      <link>https://dev.to/pi19404/erasing-git-history-how-to-keep-only-your-latest-commit-on-github-1365</link>
      <guid>https://dev.to/pi19404/erasing-git-history-how-to-keep-only-your-latest-commit-on-github-1365</guid>
      <description>&lt;p&gt;&lt;strong&gt;Have you ever committed sensitive data by mistake? Or maybe you want to wipe out your repository’s tangled history and start with a clean slate while preserving the current codebase?&lt;/strong&gt; This guide walks you through the safe and deliberate process of &lt;strong&gt;removing all Git history and retaining only the latest commit&lt;/strong&gt; on GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Why Would You Want to Do This?
&lt;/h3&gt;

&lt;p&gt;There are valid and common scenarios where this is useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔐 You’ve committed secrets (e.g., API keys) in the past.&lt;/li&gt;
&lt;li&gt;🧪 Your repository history is too messy or experimental.&lt;/li&gt;
&lt;li&gt;🚀 You want a fresh start for open-source release.&lt;/li&gt;
&lt;li&gt;🎯 You’re transitioning from a prototype to production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; This is a &lt;strong&gt;destructive action&lt;/strong&gt;. It will &lt;strong&gt;wipe out all previous commit history&lt;/strong&gt; , including tags, branches, and pull requests. Only proceed if you understand the implications.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚧 What You’ll Achieve
&lt;/h3&gt;

&lt;p&gt;By the end of this process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The repository will contain &lt;strong&gt;only one commit&lt;/strong&gt;  — the current state of the code.&lt;/li&gt;
&lt;li&gt;All previous commits will be &lt;strong&gt;irreversibly removed&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The branch history will be &lt;strong&gt;rewritten and force-pushed&lt;/strong&gt; to GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠️ Step-by-Step: Clean Your GitHub Repo History
&lt;/h3&gt;

&lt;h3&gt;
  
  
  ✅ 1. Clone Your Repository (Optional but Recommended)
&lt;/h3&gt;

&lt;p&gt;Before you rewrite history, it’s good to work in a fresh clone to avoid local conflicts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/your-username/your-repo.git
cd your-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🌿 2. Create a New Orphan Branch
&lt;/h3&gt;

&lt;p&gt;An &lt;em&gt;orphan branch&lt;/em&gt; is a Git branch with no previous history. This is the clean slate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout --orphan latest-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a new branch.&lt;/li&gt;
&lt;li&gt;Starts it with no parents (no history).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧹 3. Stage and Commit All Files
&lt;/h3&gt;

&lt;p&gt;Now, commit everything currently in your working directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add -A
git commit -m "Initial commit with cleaned history"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a brand-new commit that captures your current code state.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔥 4. Delete the Old Branch
&lt;/h3&gt;

&lt;p&gt;Next, delete the existing branch (usually main or master) that contains the unwanted history.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch -D main # or 'master', depending on your repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📝 5. Rename the New Branch to main
&lt;/h3&gt;

&lt;p&gt;Give your new orphan branch the same name as the one you deleted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch -m main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 6. Force Push to GitHub
&lt;/h3&gt;

&lt;p&gt;Finally, &lt;strong&gt;force push&lt;/strong&gt; the cleaned branch to GitHub. This replaces the remote history.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -f origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🛑 &lt;strong&gt;Warning&lt;/strong&gt; : Collaborators will need to re-clone the repo. This push rewrites history for everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛡️ Aftermath: Clean-Up and Best Practices
&lt;/h3&gt;

&lt;p&gt;Once you’ve rewritten history:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔐 &lt;strong&gt;Revoke and rotate any secrets&lt;/strong&gt; that were exposed in the past.&lt;/li&gt;
&lt;li&gt;🕵️‍♀️ &lt;strong&gt;Scan your repo&lt;/strong&gt; using tools like &lt;a href="https://github.com/gitleaks/gitleaks" rel="noopener noreferrer"&gt;GitLeaks&lt;/a&gt;, &lt;a href="https://github.com/trufflesecurity/trufflehog" rel="noopener noreferrer"&gt;TruffleHog&lt;/a&gt;, or &lt;a href="https://github.com/Yelp/detect-secrets" rel="noopener noreferrer"&gt;detect-secrets&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;📄 Add a .gitignore file to prevent re-adding sensitive or build files.&lt;/li&gt;
&lt;li&gt;🧪 Use pre-commit hooks to lint and scan files before they’re staged.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📚 Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository" rel="noopener noreferrer"&gt;GitHub Docs: Removing Sensitive Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/newren/git-filter-repo" rel="noopener noreferrer"&gt;git filter-repo&lt;/a&gt; – Advanced history rewriting&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/neural-engineer/how-to-remove-sensitive-data-openai-api-keys-from-git-repositories-using-bfg-repo-cleaner-6fdad0cb1243" rel="noopener noreferrer"&gt;https://medium.com/neural-engineer/how-to-remove-sensitive-data-openai-api-keys-from-git-repositories-using-bfg-repo-cleaner-6fdad0cb1243&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ Conclusion
&lt;/h3&gt;

&lt;p&gt;Wiping a GitHub repository’s history is a powerful tool that should be used with caution. Whether you’re mitigating a leak or simplifying your project’s start point, this guide helps you do so responsibly and effectively.&lt;/p&gt;




</description>
      <category>softwaredevelopment</category>
      <category>git</category>
      <category>software</category>
    </item>
    <item>
      <title>Hugging Face Zero GPU Spaces: ShieldGemma Application</title>
      <dc:creator>Prashant Iyenga</dc:creator>
      <pubDate>Mon, 09 Sep 2024 07:00:44 +0000</pubDate>
      <link>https://dev.to/pi19404/hugging-face-zero-gpu-spaces-shieldgemma-application-12g5</link>
      <guid>https://dev.to/pi19404/hugging-face-zero-gpu-spaces-shieldgemma-application-12g5</guid>
      <description>&lt;h3&gt;
  
  
  What is ZeroGPU
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Hugging Face Spaces now offers a new hardware option called ZeroGPU.&lt;/li&gt;
&lt;li&gt;ZeroGPU uses &lt;em&gt;Nvidia A100&lt;/em&gt; GPU devices under the hood, and 40GB of vRAM are available for each workload.&lt;/li&gt;
&lt;li&gt;This is achieved by making Spaces efficiently hold and release GPUs as needed, as opposed to a classical GPU Space that holds exactly one GPU at any given time.&lt;/li&gt;
&lt;li&gt;You can explore and use existing public ZeroGPU Spaces for free. The list of public zero GPU spaces can be found at (&lt;a href="https://huggingface.co/spaces/enzostvs/zero-gpu-spaces" rel="noopener noreferrer"&gt;https://huggingface.co/spaces/enzostvs/zero-gpu-spaces&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hosting models on ZeroGPU Spaces has the following restrictions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ZeroGPU is currently in beta.&lt;/strong&gt; It only works with the &lt;strong&gt;Gradio SDK.&lt;/strong&gt; It enables us to deploy Gradio applications run on ZeroGPU for free&lt;/li&gt;
&lt;li&gt;It is only available for Personal accounts subscribed to HuggingFace Pro. It will appear in the hardware list when you select the Gradio SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdk0i19zf5ndnhxia95s3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdk0i19zf5ndnhxia95s3.png" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;There is a limit of 10 ZeroGPU Spaces that Personal accounts&lt;/strong&gt; with PRO subscriptions can host&lt;/li&gt;
&lt;li&gt;Though the documentation mentions that ZeroGPU uses an A100,You may observe a significantly lower performance than a standard A100 as GPU allocation may be time-sliced&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Spaces and zero GPU
&lt;/h3&gt;

&lt;p&gt;To make your Space work with ZeroGPU, you need to &lt;strong&gt;decorate&lt;/strong&gt; the Python functions that require a GPU with &lt;code&gt;@spaces.GPU&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;spaces&lt;/span&gt;

&lt;span class="nd"&gt;@spaces.GPU&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_inference_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model_size&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a decorated function is invoked, the Space will be attributed a GPU, and it will release it upon completion of the function. You can find complete instructions to make your code compatible with zero GPU spaces at the link&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/zero-gpu-explorers" rel="noopener noreferrer"&gt;&lt;strong&gt;ZeroGPU Explorers on Hugging Face&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4jkusnkgbutaucy8bk5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4jkusnkgbutaucy8bk5.png" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your space is running on Zero GPU, you can see the status on the space's project page, along with the CPU and RAM consumption.&lt;/p&gt;

&lt;p&gt;The supported software versions that are compatible with gradio SDK Zero GPU Spaces are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gradio: 4+&lt;/li&gt;
&lt;li&gt;PyTorch: All versions from &lt;code&gt;2.0.0&lt;/code&gt; to &lt;code&gt;2.2.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Python: &lt;code&gt;3.10.13&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Duration
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;duration&lt;/code&gt; param in the decorator &lt;code&gt;spaces.GPU&lt;/code&gt; allows us to specific GPT time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The default is 60 seconds.&lt;/li&gt;
&lt;li&gt;If you expect your GPU function to take more than the &lt;strong&gt;60s&lt;/strong&gt; then you need to specify the same.&lt;/li&gt;
&lt;li&gt;If you know that your function will take far less than the 60s default, specifying that it will provide higher priority for visitors to your Space in the queue
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@spaces.GPU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;defgenerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will set the maximum duration of your function call to 120s.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting Private ZeroGPU Spaces
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We will create a space &lt;code&gt;pi19404/ai-worker&lt;/code&gt;, which is zeroGPU space. The visibility of space is private.&lt;/li&gt;
&lt;li&gt;The gradio server hosted on space A provides shieldGemma2 model inference endpoint.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more details of shieldGemma2, refer the article&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/neural-engineer/llm-content-safety-evaluation-using-shieldgemma-ea05491da271" rel="noopener noreferrer"&gt;&lt;strong&gt;LLM Content Safety Evaluation using ShieldGemma&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can create a space &lt;a href="https://huggingface.co/spaces/pi19404/shieldgemma-demo" rel="noopener noreferrer"&gt;&lt;code&gt;pi19404/shieldgemma-demo&lt;/code&gt;&lt;/a&gt;that programmatically call an application hosted on space &lt;code&gt;pi19404/ai-worker&lt;/code&gt;. The visibility of space B is public&lt;/li&gt;
&lt;li&gt;We configure the hugging face token as a secret with name &lt;code&gt;API_TOKEN&lt;/code&gt; project settings of space &lt;a href="https://huggingface.co/spaces/pi19404/shieldgemma-demo" rel="noopener noreferrer"&gt;&lt;code&gt;pi19404/shieldgemma-demo&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;We can call the gradio server API using gradio client as described below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;gradio_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;

&lt;span class="n"&gt;API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Initialize the Gradio Client
# This connects to the private zeroGPU Hugging Face space "pi19404/ai-worker"
&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pi19404/ai-worker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hf_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Make a prediction using the client
# The predict method calls the specified API endpoint with the given parameters
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;# Input parameters for the my_inference_function API
&lt;/span&gt;    &lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# The input text to be evaluated
&lt;/span&gt;    &lt;span class="n"&gt;output_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# The output text to be evaluated (if applicable)
&lt;/span&gt;    &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scoring&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# The mode of operation: "scoring" or "generative"
&lt;/span&gt;    &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# Maximum length of the input prompt
&lt;/span&gt;    &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# Maximum number of new tokens to generate
&lt;/span&gt;    &lt;span class="n"&gt;model_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# Size of the model to use: "2B", "9B", or "27B"
&lt;/span&gt;    &lt;span class="n"&gt;api_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/my_inference_function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# The specific API endpoint to call
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Print the result of the prediction
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explaining Rate Limits for ZeroGPU
&lt;/h3&gt;

&lt;p&gt;The huggingface platform rate limits ZeroGPU spaces to ensure that a single user does not hog all available GPUs. The limit is controlled by a special token that the Hugging Face Hub infrastructure adds to all incoming requests to Spaces. This token is a request header called &lt;code&gt;X-IP-Token&lt;/code&gt; and its value changes depending on the user who requests the ZeroGPU space.&lt;/p&gt;

&lt;p&gt;With the Python client, you will quickly exhaust your rate limit, as all the requests to the ZeroGPU space will have the same token. So, to avoid this, we need to extract the user's token using Space &lt;a href="https://huggingface.co/spaces/pi19404/shieldgemma-demo" rel="noopener noreferrer"&gt;&lt;code&gt;pi19404/shieldgemma-demo&lt;/code&gt;&lt;/a&gt;before we call Space &lt;code&gt;pi19404/ai-worker&lt;/code&gt; programmatically.&lt;/p&gt;

&lt;p&gt;When a new user visits the page&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use the &lt;code&gt;load&lt;/code&gt; event to extract the user’s &lt;code&gt;x-ip-token&lt;/code&gt; header when the user visits the page.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Blocks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Main Gradio interface setup.This block sets up the Gradio interface, including:
    - A State component to store the client for the session.
    - A JSON component to display request headers for debugging.
    - Other UI components (not shown in this snippet).
    - A load event that calls set_client_for_session when the interface is loaded.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;## LLM Safety Evaluation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Tab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ShieldGemma2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="n"&gt;input_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Textbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Input Text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Textbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response Text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;max_lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;show_copy_button&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;elem_classes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrap-text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mode_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dropdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scoring&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Prediction Mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;max_length_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max Length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;max_new_tokens_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max New Tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;model_size_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dropdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Model Size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Textbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Output Text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;max_lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;show_copy_button&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;elem_classes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrap-text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;text_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;text_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;my_inference_function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;input_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_new_tokens_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model_size_input&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;response_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;set_client_for_session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We create a new Gradio client with this header passed to the &lt;code&gt;headers&lt;/code&gt; parameter.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create an OrderedDict to store clients, limited to 15 entries
&lt;/span&gt;&lt;span class="n"&gt;client_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OrderedDict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;MAX_CACHE_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;

&lt;span class="n"&gt;default_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pi19404/ai-worker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hf_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_client_for_ip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Retrieve or create a client for the given IP address.This function implements a caching mechanism to store up to MAX_CACHE_SIZE clients.
    If a client for the given IP exists in the cache, it&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s returned and moved to the end
    of the cache (marking it as most recently used). If not, a new client is created,
    added to the cache, and the least recently used client is removed if the cache is full.
    Args:
        ip_address (str): The IP address of the client.
        x_ip_token (str): The X-IP-Token header value for the client.
    Returns:
        Client: A Gradio client instance for the given IP address.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;
    &lt;span class="c1"&gt;#print("ipaddress is ",x_ip_token)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;new_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;default_client&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Move the accessed item to the end (most recently used)
&lt;/span&gt;            &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move_to_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# Create a new client
&lt;/span&gt;        &lt;span class="n"&gt;new_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pi19404/ai-worker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hf_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; \\
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-IP-Token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;# Add to cache, removing oldest if necessary
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_CACHE_SIZE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popitem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_client&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_client&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This ensures all subsequent predictions pass this header to the ZeroGPU space.&lt;/li&gt;
&lt;li&gt;The client is saved in a State variable so that it is independent from other users. It is deleted automatically when the user exits the page.&lt;/li&gt;
&lt;li&gt;We will also save the Gradio client in an in-memory cache so that we do not need to create a client again if the user loads a page with the same IP address.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create an OrderedDict to store clients, limited to 15 entries
&lt;/span&gt;&lt;span class="n"&gt;client_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OrderedDict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;MAX_CACHE_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
&lt;span class="n"&gt;default_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pi19404/ai-worker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hf_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_client_for_ip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Retrieve or create a client for the given IP address.This function implements a caching mechanism to store up to MAX_CACHE_SIZE clients.
    If a client for the given IP exists in the cache, it&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s returned and moved to the end
    of the cache (marking it as most recently used). If not, a new client is created,
    added to the cache, and the least recently used client is removed if the cache is full.
    Args:
        ip_address (str): The IP address of the client.
        x_ip_token (str): The X-IP-Token header value for the client.
    Returns:
        Client: A Gradio client instance for the given IP address.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;
    &lt;span class="c1"&gt;#print("ipaddress is ",x_ip_token)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;new_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;default_client&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Move the accessed item to the end (most recently used)
&lt;/span&gt;            &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move_to_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# Create a new client
&lt;/span&gt;        &lt;span class="n"&gt;new_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pi19404/ai-worker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hf_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-IP-Token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;# Add to cache, removing oldest if necessary
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_CACHE_SIZE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popitem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;client_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_ip_token&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_client&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_client&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find the full gradio client code at&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/spaces/pi19404/shieldgemma-demo" rel="noopener noreferrer"&gt;&lt;strong&gt;ShieldGemma Demo - a Hugging Face Space by pi19404&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Gradio Interface and Code
&lt;/h3&gt;

&lt;p&gt;you can find the link to gradio interface at&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/spaces/pi19404/shieldgemma-demo" rel="noopener noreferrer"&gt;&lt;strong&gt;Shieldgemma Demo - a Hugging Face Space by pi19404&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9192q4qzy7c6v95hsrdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9192q4qzy7c6v95hsrdi.png" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  REFERENCES
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gradio.app/main/docs/python-client/using-zero-gpu-spaces" rel="noopener noreferrer"&gt;https://www.gradio.app/main/docs/python-client/using-zero-gpu-spaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/zero-gpu-explorers" rel="noopener noreferrer"&gt;https://huggingface.co/zero-gpu-explorers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>huggingface</category>
      <category>shieldgemma</category>
    </item>
  </channel>
</rss>
