<?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: Nuvem Dev</title>
    <description>The latest articles on DEV Community by Nuvem Dev (@nuvemdev).</description>
    <link>https://dev.to/nuvemdev</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4199270%2F91dc8b9f-e13b-4b68-86aa-55cc6eb3b7ce.png</url>
      <title>DEV Community: Nuvem Dev</title>
      <link>https://dev.to/nuvemdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nuvemdev"/>
    <language>en</language>
    <item>
      <title>Python: checar preço de produto passando por proxy residencial (e calcular o custo por página)</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Sun, 01 Nov 2026 12:10:53 +0000</pubDate>
      <link>https://dev.to/nuvemdev/python-checar-preco-de-produto-passando-por-proxy-residencial-e-calcular-o-custo-por-pagina-3d9d</link>
      <guid>https://dev.to/nuvemdev/python-checar-preco-de-produto-passando-por-proxy-residencial-e-calcular-o-custo-por-pagina-3d9d</guid>
      <description>&lt;p&gt;Quando o scraping começa a tomar bloqueio, o culpado costuma ser o IP do seu servidor. Aqui vai um script curto que passa a requisição por um proxy (se você tiver um) e já estima quanto aquela página custou em tráfego. Eu rodei esse script de verdade contra um servidor local, sem proxy, só pra validar o código. Não testei com um proxy pago nesta edição.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjkm3zqab3s6gf79zmjf9.gif" alt="vídeo curto" width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Instala
&lt;/h2&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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. O script
&lt;/h2&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;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# PROXY_URL no formato http://usuario:senha@host:porta (vem do painel do provedor)
&lt;/span&gt;&lt;span class="n"&gt;proxy&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;PROXY_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;proxies&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;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;proxy&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;proxy&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pega&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;r&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;proxies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;proxies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&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;User-Agent&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;Mozilla/5.0 (compatible; checa-preco/0.1)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&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;r&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__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;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pega&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;kb&lt;/span&gt; &lt;span class="o"&gt;=&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;r&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="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&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;status=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tamanho=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kb&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; KB via_proxy=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;)&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="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;custo estimado a US$ 5,51/GB: US$ &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mf"&gt;5.51&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="n"&gt;f&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;h2&gt;
  
  
  3. Rodando
&lt;/h2&gt;

&lt;p&gt;Sem proxy (testei assim, com uma página local):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python checa_preco.py http://localhost:8765/index.html
&lt;span class="c"&gt;# status=200 tamanho=0.0 KB via_proxy=False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com proxy, é só exportar a variável antes:&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;export &lt;/span&gt;&lt;span class="nv"&gt;PROXY_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://usuario:senha@host:porta"&lt;/span&gt;
python checa_preco.py https://exemplo.com.br/produto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Por que o custo por página importa
&lt;/h2&gt;

&lt;p&gt;Proxy residencial é cobrado por giga de tráfego. Na página oficial do IPRoyal (01/11/2026) o preço vai de US$ 7,35/GB no pacote de 1 GB a US$ 5,51/GB no de 10 GB, e o tráfego não expira. Uma página de 200 KB custa na casa de US$ 0,001. O que pesa mesmo é imagem e JavaScript: se der pra pedir só o HTML, o custo cai bastante.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boas práticas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Leia os termos do site e o robots.txt antes de coletar.&lt;/li&gt;
&lt;li&gt;Se existir API oficial, use a API.&lt;/li&gt;
&lt;li&gt;Coloque um sleep entre requisições. Rotacionar IP não justifica martelar o servidor dos outros.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preços e planos do IPRoyal: &lt;a href="https://go.nowto.link/iproyal" rel="noopener noreferrer"&gt;https://go.nowto.link/iproyal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se curtiu, a versão newsletter com os números dos pacotes está na Substack: &lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com&lt;/a&gt;. E o tutorial anterior (isolamento de perfil com Playwright) está no meu perfil: &lt;a href="https://dev.to/nuvemdev"&gt;https://dev.to/nuvemdev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Divulgação: alguns links são de afiliado. Se você comprar, eu posso ganhar uma comissão, sem custo extra pra você.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>tutorial</category>
      <category>braziliandev</category>
    </item>
    <item>
      <title>Isolando sessões de navegador com Playwright em Python (a ideia por trás dos perfis antidetect)</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Sat, 31 Oct 2026 12:32:28 +0000</pubDate>
      <link>https://dev.to/nuvemdev/isolando-sessoes-de-navegador-com-playwright-em-python-a-ideia-por-tras-dos-perfis-antidetect-46l4</link>
      <guid>https://dev.to/nuvemdev/isolando-sessoes-de-navegador-com-playwright-em-python-a-ideia-por-tras-dos-perfis-antidetect-46l4</guid>
      <description>&lt;p&gt;Quem vende online acaba com várias contas abertas: loja, anúncios, marketplace. No mesmo Chrome, cookie e login se misturam. Navegador antidetect resolve isso com perfis isolados. Dá pra entender a ideia em 20 linhas de Python.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nuvemdev.substack.com/p/varias-contas-de-loja-online-sem" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyhlqqyqbs6yeix25mg2h.gif" alt="Isolamento de perfis" width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  O que vamos fazer
&lt;/h2&gt;

&lt;p&gt;Abrir dois "perfis" com Playwright, cada um com cookies, idioma, fuso, user agent e tela próprios, e confirmar que um não enxerga o outro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalação
&lt;/h2&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;playwright
playwright &lt;span class="nb"&gt;install &lt;/span&gt;chromium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O código
&lt;/h2&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;playwright.sync_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sync_playwright&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;sync_playwright&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;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chromium&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;user_agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124 Safari/537.36&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt-BR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;America/Sao_Paulo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;viewport&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;width&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1366&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;height&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;user_agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/124 Safari/537.36&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en-US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;America/New_York&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;viewport&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;width&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;height&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&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;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&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;B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;pg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_cookies&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&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;conta&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;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;http://localhost:8765&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt;
        &lt;span class="n"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8765&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[navigator.language, Intl.DateTimeFormat().resolvedOptions().timeZone, screen.width]&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;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&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;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Antes, suba um servidor local qualquer: &lt;code&gt;python3 -m http.server 8765&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saída que eu obtive aqui
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A ['pt-BR', 'America/Sao_Paulo', 1366] ['A']
B ['en-US', 'America/New_York', 1440] ['B']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada contexto tem seu cookie e sua identidade. Nenhum enxerga o do outro.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que isso NÃO faz
&lt;/h2&gt;

&lt;p&gt;Isso é só isolamento básico. Um navegador antidetect de verdade cuida de dezenas de sinais (canvas, WebGL, fontes), guarda cada perfil, e deixa você abrir pela interface sem código. E nenhuma ferramenta te autoriza a violar regra de plataforma: muita loja proíbe conta duplicada, então leia os termos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Se não quiser programar
&lt;/h2&gt;

&lt;p&gt;O GoLogin tem plano grátis com 3 perfis e 7 dias de teste completo (conferi na página de preços em 31/10; o Professional, 10 perfis, é US$ 9/mês): &lt;a href="https://go.nowto.link/gologin" rel="noopener noreferrer"&gt;https://go.nowto.link/gologin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mais conteúdo em português na newsletter: &lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alguns links são de afiliado: se você comprar, eu posso ganhar uma comissão, sem custo extra pra você.&lt;/p&gt;

</description>
      <category>python</category>
      <category>playwright</category>
      <category>ecommerce</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Script em Python pra registrar suas músicas de IA e saber quais você pode monetizar</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Fri, 30 Oct 2026 12:37:17 +0000</pubDate>
      <link>https://dev.to/nuvemdev/script-em-python-pra-registrar-suas-musicas-de-ia-e-saber-quais-voce-pode-monetizar-1207</link>
      <guid>https://dev.to/nuvemdev/script-em-python-pra-registrar-suas-musicas-de-ia-e-saber-quais-voce-pode-monetizar-1207</guid>
      <description>&lt;p&gt;&lt;a href="https://nuvemdev.substack.com/p/musica-com-ia-pro-seu-video-o-plano" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuu1hxliq44agum9opa72.jpg" alt="Vídeo: música com IA" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usar música gerada por IA em vídeo é ótimo até você esquecer em qual plano gerou cada faixa. Em ferramentas como o Suno, a página de preços mostra que o plano Free não tem direitos comerciais, e o Pro (US$ 8/mês) e o Premier (US$ 24/mês) têm. Então vale ter um registro simples de cada música. Vamos fazer isso com um script Python sem dependências.&lt;/p&gt;

&lt;h2&gt;
  
  
  O script
&lt;/h2&gt;

&lt;p&gt;Salve como &lt;code&gt;musicas.py&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;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;
&lt;span class="n"&gt;ARQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;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;musicas.json&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;carregar&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;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&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;ARQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&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;def&lt;/span&gt; &lt;span class="nf"&gt;registrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;titulo&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;plano&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;dados&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;carregar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;dados&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;titulo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;titulo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plano&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;plano&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comercial&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;plano&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="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pro&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;premier&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;ARQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dados&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&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;indent&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;relatorio&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;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;carregar&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OK&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;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comercial&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NAO USAR EM VIDEO MONETIZADO&lt;/span&gt;&lt;span class="sh"&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;titulo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | plano &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plano&lt;/span&gt;&lt;span class="sh"&gt;"&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__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;__main__&lt;/span&gt;&lt;span class="sh"&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;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;add&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;registrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&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;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&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="nf"&gt;relatorio&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usando
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 musicas.py add &lt;span class="s2"&gt;"Lofi chuva"&lt;/span&gt; &lt;span class="s2"&gt;"lofi calmo com chuva"&lt;/span&gt; free
python3 musicas.py add &lt;span class="s2"&gt;"Trilha intro"&lt;/span&gt; &lt;span class="s2"&gt;"synth leve otimista"&lt;/span&gt; Pro
python3 musicas.py rel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Saída que eu rodei aqui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2026-10-30 | Lofi chuva | plano free | NAO USAR EM VIDEO MONETIZADO
2026-10-30 | Trilha intro | plano Pro | OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Por que isso ajuda
&lt;/h2&gt;

&lt;p&gt;Se um cliente ou a plataforma perguntar de onde veio a trilha, você tem prompt, data e plano na mão. É só um JSON, mas evita dor de cabeça. Importante: os termos de uso do serviço podem ter outras limitações, então leia antes de publicar.&lt;/p&gt;

&lt;p&gt;Quer a versão em vídeo e os planos explicados? Está na newsletter: &lt;a href="https://nuvemdev.substack.com/p/musica-com-ia-pro-seu-video-o-plano" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com/p/musica-com-ia-pro-seu-video-o-plano&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se quiser testar o Suno: &lt;a href="https://go.nowto.link/suno" rel="noopener noreferrer"&gt;https://go.nowto.link/suno&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outro post prático meu: &lt;a href="https://dev.to/nuvemdev/script-em-python-pra-validar-margem-antes-de-abrir-sua-loja-online-4cc"&gt;https://dev.to/nuvemdev/script-em-python-pra-validar-margem-antes-de-abrir-sua-loja-online-4cc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Aviso: o link do Suno é de afiliado; a Nuvem Dev pode receber comissão sem custo extra pra você.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ia</category>
      <category>tutorial</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Script em Python pra validar margem antes de abrir sua loja online</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Thu, 29 Oct 2026 12:06:33 +0000</pubDate>
      <link>https://dev.to/nuvemdev/script-em-python-pra-validar-margem-antes-de-abrir-sua-loja-online-4cc</link>
      <guid>https://dev.to/nuvemdev/script-em-python-pra-validar-margem-antes-de-abrir-sua-loja-online-4cc</guid>
      <description>&lt;p&gt;Antes de pagar qualquer plataforma de loja (Shopify, Nuvemshop, tanto faz), eu faria uma conta: sobra quanto por venda? Segue um script curto que eu rodei aqui.&lt;/p&gt;

&lt;h2&gt;
  
  
  O script
&lt;/h2&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;margem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;custo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taxa_pct&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0499&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taxa_fixa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imposto_pct&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.06&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;taxas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;taxa_pct&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;taxa_fixa&lt;/span&gt;
    &lt;span class="n"&gt;imposto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;imposto_pct&lt;/span&gt;
    &lt;span class="n"&gt;lucro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;custo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;frete&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;taxas&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;imposto&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lucro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lucro&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&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;if&lt;/span&gt; &lt;span class="n"&gt;__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;__main__&lt;/span&gt;&lt;span class="sh"&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;preco&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;79.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;99.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;129.9&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="n"&gt;preco&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;margem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;custo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Saída real
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;79.9 (17.52, 21.9)
99.9 (35.32, 35.4)
129.9 (62.02, 47.7)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com custo de R$ 35 e frete de R$ 18, vender a R$ 79,90 deixa só 21,9% de margem. A R$ 99,90 já vai pra 35%. As taxas (4,99% + R$ 0,60) e o imposto (6%) são valores de exemplo: troque pelos do seu gateway e do seu regime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Próximo passo
&lt;/h2&gt;

&lt;p&gt;Se a margem fechou, aí sim vale testar uma plataforma. A Shopify tem teste de 3 dias grátis e depois US$ 1/mês por 3 meses (confira na página oficial, promoção muda), e o Shopify Magic, que escreve descrição de produto, é gratuito segundo a central de ajuda deles. Link do teste: &lt;a href="https://go.nowto.link/shopify" rel="noopener noreferrer"&gt;https://go.nowto.link/shopify&lt;/a&gt;&lt;br&gt;
Contei a versão em newsletter, com vídeo curto, aqui: &lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com&lt;/a&gt;. E sobre IA e privacidade, escrevi sobre VPN: &lt;a href="https://nuvemdev.substack.com/p/vpn-protege-o-que-voce-digita-na" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com/p/vpn-protege-o-que-voce-digita-na&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Aviso: este post contém link de afiliado. Se você assinar pelo link, a Nuvem Dev pode receber uma comissão, sem custo extra pra você.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ecommerce</category>
      <category>shopify</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>VPN e IA: o que muda no tráfego, testado com curl (e o que não muda)</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Wed, 28 Oct 2026 12:08:32 +0000</pubDate>
      <link>https://dev.to/nuvemdev/vpn-e-ia-o-que-muda-no-trafego-testado-com-curl-e-o-que-nao-muda-5d71</link>
      <guid>https://dev.to/nuvemdev/vpn-e-ia-o-que-muda-no-trafego-testado-com-curl-e-o-que-nao-muda-5d71</guid>
      <description>&lt;p&gt;Muita gente acha que VPN deixa o uso de IA "privado". Dá pra testar isso em 2 minutos no terminal. Os comandos abaixo eu rodei de verdade; o IP que apareceu foi o de saída da máquina onde rodei.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F78xcwfyvv989pfntenzp.gif" alt="vídeo curto" width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Qual IP o servidor enxerga?
&lt;/h2&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; https://api.ipify.org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Saída no meu teste: &lt;code&gt;52.26.208.45&lt;/code&gt;. Com uma VPN conectada, esse número passa a ser o IP do servidor da VPN, não o seu.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. O que chega no servidor quando você chama uma API de IA?
&lt;/h2&gt;

&lt;p&gt;Vou usar o httpbin.org como "servidor de mentira" que devolve tudo que recebe:&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="nt"&gt;-X&lt;/span&gt; POST https://httpbin.org/post &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"model":"exemplo","messages":[{"role":"user","content":"meu prompt secreto"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trecho da resposta real:&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;"data"&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="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;model&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;exemplo&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:[{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;meu prompt secreto&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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;"origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"52.26.208.45"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"json"&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;"messages"&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;"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;"meu prompt secreto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user"&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;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;Duas coisas aparecem: &lt;code&gt;origin&lt;/code&gt; (o IP, que a VPN troca) e &lt;code&gt;data&lt;/code&gt; (o seu prompt, que a VPN &lt;strong&gt;não&lt;/strong&gt; troca). O texto vai criptografado por HTTPS até o destino, mas o destino lê tudo.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Conclusão prática
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;VPN protege o caminho: Wi-Fi público, provedor de internet, IP de casa.&lt;/li&gt;
&lt;li&gt;VPN não protege o conteúdo diante de quem recebe: a empresa da IA vê o prompt e a conta logada.&lt;/li&gt;
&lt;li&gt;Se o requisito é "o texto não sai da minha infraestrutura", rode o modelo localmente ou numa VPS sua. Exemplo com Ollama:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
ollama run llama3.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eu detalhei VPS vs GPU por hora aqui: &lt;a href="https://dev.to/nuvemdev/rodando-llm-em-gpu-alugada-por-hora-checklist-e-comandos-runpod-38if"&gt;https://dev.to/nuvemdev/rodando-llm-em-gpu-alugada-por-hora-checklist-e-comandos-runpod-38if&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quando a VPN ainda vale a pena
&lt;/h2&gt;

&lt;p&gt;Rede pública, esconder navegação do provedor, separar o IP de casa. Conferi em 28/10/2026 a página da NordVPN em português: plano Básico de 2 anos a US$ 3,49/mês e Completo a US$ 3,99/mês (renovação maior: US$ 139,08 e US$ 219,48 por ano), garantia de 30 dias e 10 dispositivos. Link: &lt;a href="https://go.nowto.link/nord" rel="noopener noreferrer"&gt;https://go.nowto.link/nord&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quer receber os próximos testes por e-mail? Assine a newsletter: &lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Divulgação: o link da NordVPN é de afiliado. Se você assinar por ele, posso ganhar uma comissão, sem custo extra pra você.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vpn</category>
      <category>privacy</category>
      <category>ai</category>
      <category>linux</category>
    </item>
    <item>
      <title>Rodando LLM em GPU alugada por hora: checklist e comandos (RunPod)</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Tue, 27 Oct 2026 12:13:09 +0000</pubDate>
      <link>https://dev.to/nuvemdev/rodando-llm-em-gpu-alugada-por-hora-checklist-e-comandos-runpod-38if</link>
      <guid>https://dev.to/nuvemdev/rodando-llm-em-gpu-alugada-por-hora-checklist-e-comandos-runpod-38if</guid>
      <description>&lt;p&gt;Você não precisa de uma GPU em casa pra testar um modelo grande. Dá pra alugar por hora, rodar o que precisa e desligar. Aqui vai um checklist direto, sem enrolação. (Os preços vêm da página oficial da RunPod, conferidos em 27/10/2026, e mudam.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgmbds87ew81cnwzniphc.jpg" alt="Nuvem Dev: GPU por hora" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Escolha a GPU pelo tamanho do modelo
&lt;/h2&gt;

&lt;p&gt;A regra prática é olhar a VRAM. Na tabela de pods da RunPod:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;th&gt;VRAM&lt;/th&gt;
&lt;th&gt;Preço/hora&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RTX 3090&lt;/td&gt;
&lt;td&gt;24 GB&lt;/td&gt;
&lt;td&gt;US$ 0,50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTX 4090&lt;/td&gt;
&lt;td&gt;24 GB&lt;/td&gt;
&lt;td&gt;US$ 0,89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A100&lt;/td&gt;
&lt;td&gt;80 GB&lt;/td&gt;
&lt;td&gt;US$ 1,79&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H100 PCIe&lt;/td&gt;
&lt;td&gt;80 GB&lt;/td&gt;
&lt;td&gt;US$ 2,89&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Modelos de 7B a 13B quantizados cabem em 24 GB. Modelos de 70B quantizados precisam de mais, tipo 80 GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Confira a GPU assim que o pod subir
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;Se aparecer o nome da placa e a VRAM livre, tá tudo certo.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Rode um modelo com Ollama
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
ollama pull llama3.1:8b
ollama run llama3.1:8b &lt;span class="s2"&gt;"Explique o que é VRAM em duas frases"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em outro terminal, veja a placa trabalhando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watch &lt;span class="nt"&gt;-n&lt;/span&gt; 1 nvidia-smi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Ou suba uma API compatível com OpenAI (vLLM)
&lt;/h2&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;vllm
vllm serve Qwen/Qwen2.5-7B-Instruct &lt;span class="nt"&gt;--port&lt;/span&gt; 8000
curl http://localhost:8000/v1/models
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Desligue tudo no final
&lt;/h2&gt;

&lt;p&gt;Pod ligado é dinheiro saindo. Parou de usar, pare o pod. Lembre também que disco (volume) tem cobrança própria, mesmo com o pod parado: na tabela, volume ocioso custa US$ 0,20/GB/mês.&lt;/p&gt;

&lt;h2&gt;
  
  
  GPU por hora ou VPS?
&lt;/h2&gt;

&lt;p&gt;IA no ar o dia inteiro (chatbot, automação): uma VPS sai mais previsível, mas sem GPU roda só modelo pequeno. Teste, treino e modelo grande por poucas horas: GPU por hora. Montei o passo a passo da versão VPS neste outro post: &lt;a href="https://dev.to/nuvemdev"&gt;https://dev.to/nuvemdev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Links (afiliado):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RunPod: &lt;a href="https://go.nowto.link/runpod" rel="noopener noreferrer"&gt;https://go.nowto.link/runpod&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hostinger VPS: &lt;a href="https://go.nowto.link/hostinger" rel="noopener noreferrer"&gt;https://go.nowto.link/hostinger&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recebo a newsletter com os comparativos e vídeos curtos aqui: &lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Aviso: alguns links são de afiliado. Se você comprar por eles, posso receber uma comissão, sem custo adicional pra você.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gpu</category>
      <category>llm</category>
      <category>linux</category>
    </item>
    <item>
      <title>Ollama + Open WebUI numa VPS: seu ChatGPT privado em 10 minutos</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Mon, 26 Oct 2026 23:38:32 +0000</pubDate>
      <link>https://dev.to/nuvemdev/ollama-open-webui-numa-vps-seu-chatgpt-privado-em-10-minutos-36ff</link>
      <guid>https://dev.to/nuvemdev/ollama-open-webui-numa-vps-seu-chatgpt-privado-em-10-minutos-36ff</guid>
      <description>&lt;p&gt;Vamos direto ao que interessa. Você tem uma VPS Ubuntu com pelo menos 8 GB de RAM e quer rodar um modelo de IA aberto com interface web. São quatro passos.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Instalar o Ollama
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
ollama &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Baixar um modelo pequeno
&lt;/h2&gt;

&lt;p&gt;Sem GPU, comece com modelos de 3B a 8B parâmetros. Em 8 GB de RAM, o 3B é o mais confortável:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull llama3.2:3b
ollama run llama3.2:3b &lt;span class="s2"&gt;"Explique o que é uma VPS em duas frases"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Instalar o Docker e subir o Open WebUI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.docker.com | sh
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--add-host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host.docker.internal:host-gateway &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; open-webui:/app/backend/open-webui &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; open-webui &lt;span class="nt"&gt;--restart&lt;/span&gt; always &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/open-webui/open-webui:main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Abra &lt;code&gt;http://IP_DA_VPS:3000&lt;/code&gt;, crie o usuário admin (o primeiro cadastro vira admin) e ele detecta o Ollama.&lt;/p&gt;

&lt;p&gt;Se não detectar, ajuste o Ollama pra escutar fora do localhost: &lt;code&gt;sudo systemctl edit ollama&lt;/code&gt;, adicione &lt;code&gt;Environment="OLLAMA_HOST=0.0.0.0"&lt;/code&gt; e rode &lt;code&gt;sudo systemctl restart ollama&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Fechar o acesso
&lt;/h2&gt;

&lt;p&gt;Não deixe a porta 3000 aberta pro mundo:&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;sudo &lt;/span&gt;ufw allow OpenSSH
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow from SEU_IP to any port 3000
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Limites
&lt;/h2&gt;

&lt;p&gt;CPU puro é lento: espere respostas bem mais devagar que no ChatGPT. Pra modelos grandes, aluguel de GPU por hora faz mais sentido.&lt;/p&gt;

&lt;p&gt;Plano de referência: Hostinger (KVM 2: 2 vCPU, 8 GB RAM, R$ 42,99/mês na promo atual, preço verificado em 26/10): &lt;a href="https://go.nowto.link/hostinger" rel="noopener noreferrer"&gt;https://go.nowto.link/hostinger&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vídeo e newsletter: &lt;a href="https://nuvemdev.substack.com" rel="noopener noreferrer"&gt;https://nuvemdev.substack.com&lt;/a&gt; . Também escrevi sobre voz de IA em português: &lt;a href="https://dev.to/nuvemdev/narracao-em-portugues-com-ia-de-graca-no-linux-piper-tts-ffmpeg-575h"&gt;https://dev.to/nuvemdev/narracao-em-portugues-com-ia-de-graca-no-linux-piper-tts-ffmpeg-575h&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alguns links são de afiliado: se você comprar, eu ganho uma comissão e você não paga nada a mais.&lt;/p&gt;

</description>
      <category>ollama</category>
      <category>docker</category>
      <category>ai</category>
      <category>linux</category>
    </item>
    <item>
      <title>Narração em português com IA, de graça, no Linux (Piper TTS + ffmpeg)</title>
      <dc:creator>Nuvem Dev</dc:creator>
      <pubDate>Fri, 23 Oct 2026 23:09:43 +0000</pubDate>
      <link>https://dev.to/nuvemdev/narracao-em-portugues-com-ia-de-graca-no-linux-piper-tts-ffmpeg-575h</link>
      <guid>https://dev.to/nuvemdev/narracao-em-portugues-com-ia-de-graca-no-linux-piper-tts-ffmpeg-575h</guid>
      <description>&lt;p&gt;&lt;a href="https://nuvemdev.substack.com/p/voz-de-ia-em-portugues-por-us-1-e" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fewkywwe6r8dhnhcvrw40.jpg" alt="Short de 32 s narrado com Piper" width="720" height="1280"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Esse short de 32 segundos foi narrado inteiro com o que tá nesse tutorial. Clica pra ver (ele roda na newsletter).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Eu precisava de narração em português pros meus vídeos curtos e não queria depender de API paga logo de cara. A saída foi o &lt;a href="https://github.com/OHF-Voice/piper1-gpl" rel="noopener noreferrer"&gt;Piper&lt;/a&gt;: um TTS open source (GPL-3.0) que roda offline, na CPU, e tem voz pt-BR.&lt;/p&gt;

&lt;p&gt;Aqui vai o caminho que eu usei, do zero até um mp4 vertical. Rodei tudo isso num Debian, com Python 3.12, em outubro de 2026, com o &lt;code&gt;piper-tts&lt;/code&gt; 1.8.0.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Instalar
&lt;/h2&gt;

&lt;p&gt;Cria uma venv pra não bagunçar o Python do sistema:&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;mkdir &lt;/span&gt;narracao &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;narracao
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install &lt;/span&gt;piper-tts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não precisa de GPU. O pacote já vem com o que ele usa pra fonemas (espeak-ng embutido).&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Baixar a voz pt-BR
&lt;/h2&gt;

&lt;p&gt;A voz brasileira que eu uso é a &lt;code&gt;faber&lt;/code&gt;, qualidade medium (dataset CC0, segundo o model card):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; piper.download_voices pt_BR-faber-medium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso baixa dois arquivos na pasta atual: &lt;code&gt;pt_BR-faber-medium.onnx&lt;/code&gt; (uns 63 MB) e o &lt;code&gt;.onnx.json&lt;/code&gt; de config. Os dois precisam ficar juntos.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Primeiro áudio
&lt;/h2&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;"Fala, pessoal! Essa narração foi gerada de graça, rodando no meu servidor."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; roteiro.txt
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; piper &lt;span class="nt"&gt;-m&lt;/span&gt; pt_BR-faber-medium.onnx &lt;span class="nt"&gt;-i&lt;/span&gt; roteiro.txt &lt;span class="nt"&gt;-f&lt;/span&gt; narracao.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui levou menos de 2 segundos pra gerar uns 4 segundos de áudio, na CPU. Confere o arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="nt"&gt;-show_entries&lt;/span&gt; &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;duration:stream&lt;span class="o"&gt;=&lt;/span&gt;sample_rate,channels &lt;span class="nt"&gt;-of&lt;/span&gt; &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;nw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 narracao.wav
&lt;span class="c"&gt;# sample_rate=22050&lt;/span&gt;
&lt;span class="c"&gt;# channels=1&lt;/span&gt;
&lt;span class="c"&gt;# duration=4.179592&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flags que valem conhecer (&lt;code&gt;python3 -m piper --help&lt;/code&gt; mostra todas):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--length-scale 1.1&lt;/code&gt; deixa a fala mais lenta; &lt;code&gt;0.9&lt;/code&gt; acelera&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--sentence-silence 0.3&lt;/code&gt; coloca pausa entre frases&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--volume 1.2&lt;/code&gt; aumenta o volume&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Em lote, com Python
&lt;/h2&gt;

&lt;p&gt;Pra vídeo eu gosto de gerar um arquivo por cena, porque fica fácil sincronizar legenda e imagem depois. Uma linha do roteiro = uma cena:&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;# narrar.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wave&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;piper&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PiperVoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SynthesisConfig&lt;/span&gt;

&lt;span class="n"&gt;voz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PiperVoice&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt_BR-faber-medium.onnx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SynthesisConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length_scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt; 1 = fala mais rápido
&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;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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="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="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;blocos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&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;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocos&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;with&lt;/span&gt; &lt;span class="n"&gt;wave&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&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;parte_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.wav&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;wb&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="n"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;voz&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;synthesize_wav&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syn_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cfg&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;parte_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.wav  &amp;lt;- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;]&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"Primeira frase do roteiro.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Segunda frase, um pouco mais longa, pra testar o ritmo.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; roteiro2.txt
python3 narrar.py roteiro2.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dica de quem apanhou: nome de marca em inglês ele lê do jeito dele. Eu mantenho duas versões do texto, uma pra legenda ("ElevenLabs") e outra pra voz, escrita do jeito que eu quero ouvir ("Íleven Labs").&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Juntar e normalizar o volume
&lt;/h2&gt;

&lt;p&gt;Plataforma de vídeo curto costuma trabalhar perto de -14 LUFS. O &lt;code&gt;loudnorm&lt;/code&gt; do ffmpeg resolve:&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="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in &lt;/span&gt;parte_&lt;span class="k"&gt;*&lt;/span&gt;.wav&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"file '&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; lista.txt
ffmpeg &lt;span class="nt"&gt;-f&lt;/span&gt; concat &lt;span class="nt"&gt;-safe&lt;/span&gt; 0 &lt;span class="nt"&gt;-i&lt;/span&gt; lista.txt &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="nv"&gt;loudnorm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-14&lt;/span&gt;:TP&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-1&lt;/span&gt;.5:LRA&lt;span class="o"&gt;=&lt;/span&gt;11 &lt;span class="nt"&gt;-ar&lt;/span&gt; 44100 narracao_final.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pra conferir quanto deu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; narracao_final.wav &lt;span class="nt"&gt;-af&lt;/span&gt; ebur128 &lt;span class="nt"&gt;-f&lt;/span&gt; null - 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A1&lt;/span&gt; Integrated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Num clipe curto o loudnorm de uma passada fica um pouco abaixo do alvo (aqui deu -14,9). Pra short isso tá ok; se quiser cravar, faz o loudnorm em duas passadas.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Virar vídeo vertical
&lt;/h2&gt;

&lt;p&gt;O mínimo: uma imagem 1080x1920 + a narração.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-loop&lt;/span&gt; 1 &lt;span class="nt"&gt;-i&lt;/span&gt; capa.png &lt;span class="nt"&gt;-i&lt;/span&gt; narracao_final.wav &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=1080:1920,format=yuv420p"&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; 30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-tune&lt;/span&gt; stillimage &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="nt"&gt;-b&lt;/span&gt;:a 160k &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-shortest&lt;/span&gt; video.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="nt"&gt;-show_entries&lt;/span&gt; &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;codec_name,width,height,r_frame_rate &lt;span class="nt"&gt;-of&lt;/span&gt; compact video.mp4
&lt;span class="c"&gt;# stream|codec_name=h264|width=1080|height=1920|r_frame_rate=30/1&lt;/span&gt;
&lt;span class="c"&gt;# stream|codec_name=aac|r_frame_rate=0/0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No meu pipeline eu vou além disso (uma cena por imagem com zoom lento via &lt;code&gt;zoompan&lt;/code&gt;, legenda em &lt;code&gt;.ass&lt;/code&gt; queimada com o filtro &lt;code&gt;ass=&lt;/code&gt;), mas o esqueleto é esse aí.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limites, sendo sincero
&lt;/h2&gt;

&lt;p&gt;A voz é boa pra tutorial e pra testar formato. Mas a entonação é mais reta que a dos serviços pagos e às vezes escorrega numa palavra. Se o projeto pede voz bem natural, ou clonar a sua, aí vale olhar ElevenLabs ou Murf. Eu comparei preço por minuto das duas (e da Fish Audio, que hoje não lista português no TTS) &lt;a href="https://nuvemdev.substack.com/p/voz-de-ia-em-portugues-por-us-1-e" rel="noopener noreferrer"&gt;nessa edição da newsletter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se travar em algum passo, comenta aqui com o erro que eu tento ajudar.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Alguns links da newsletter são de afiliado: se você comprar, eu ganho uma comissão e você não paga nada a mais.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
