Abe EstradaAbe Estradahttps://feed.abeestrada.com/allSun, 17 Mar 2024 21:07:18 -0600Sun, 17 Mar 2024 21:07:18 -0600Feeds sin actualizarhttps://abeestrada.com/post/feeds-sin-actualizar/Wed, 13 Mar 2024 12:00:00 -0600https://abeestrada.com/post/feeds-sin-actualizar/<p>Una de las cosas que extraño cuando empecé a utilizar <a href="https://newsboat.org/" target="_blank" rel="noopener">Newsboat</a> (no es queja), es que no puedo revisar de una forma fácil como en <a href="https://feedbin.com/blog/2024/01/15/fixable-feeds/" target="_blank" rel="noopener">Feedbin</a> . Tengo una lista donde feeds no han sido actualizados desde hace tiempo, o feeds con problemas, ya sea por que cambiaron de dominio o están rotos, etc.</p> <p>Por lo anterior, tengo que crear mis propias herramientas. Para esto he creado un pequeño programa en Go, para evaluar cada feed.</p> <p>Lo que hago, es leer de una archivo <code>urls.txt</code> todas las urls, luego una por una si es un feed válido, busco la última vez que fueron actualizados, y muestro los feeds que tienen más de 6 meses sin actualizar y de paso los que tienen algún error, ya sea para quitarlo o notificar al dueño.</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">package</span> <span style="color:#e06c75">main</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">import</span> ( </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;bufio&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;context&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;fmt&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;os&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;regexp&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;sync&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;time&#34;</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;github.com/mmcdole/gofeed&#34;</span> </span></span><span style="display:flex;"><span>) </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">func</span> <span style="color:#61afef;font-weight:bold">getFeed</span>(<span style="color:#e06c75">url</span> <span style="color:#e5c07b">string</span>) { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">today</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">time</span>.<span style="color:#61afef;font-weight:bold">Now</span>().<span style="color:#61afef;font-weight:bold">Local</span>() </span></span><span style="display:flex;"><span> <span style="color:#7f848e">// Timeout: 60 seconds </span></span></span><span style="display:flex;"><span><span style="color:#7f848e"></span> <span style="color:#e06c75">ctx</span>, <span style="color:#e06c75">cancel</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">context</span>.<span style="color:#61afef;font-weight:bold">WithTimeout</span>(<span style="color:#e06c75">context</span>.<span style="color:#61afef;font-weight:bold">Background</span>(), <span style="color:#d19a66">60</span><span style="color:#56b6c2">*</span><span style="color:#e06c75">time</span>.<span style="color:#e06c75">Second</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">defer</span> <span style="color:#61afef;font-weight:bold">cancel</span>() </span></span><span style="display:flex;"><span> <span style="color:#e06c75">fp</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">gofeed</span>.<span style="color:#61afef;font-weight:bold">NewParser</span>() </span></span><span style="display:flex;"><span> <span style="color:#e06c75">feed</span>, <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">fp</span>.<span style="color:#61afef;font-weight:bold">ParseURLWithContext</span>(<span style="color:#e06c75">url</span>, <span style="color:#e06c75">ctx</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Println</span>(<span style="color:#98c379">&#34;&gt;&gt;&#34;</span>, <span style="color:#e06c75">url</span>, <span style="color:#e06c75">err</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">updated</span> <span style="color:#56b6c2">*</span><span style="color:#e06c75">time</span>.<span style="color:#e06c75">Time</span> </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">UpdatedParsed</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">updated</span> = <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">UpdatedParsed</span> </span></span><span style="display:flex;"><span> } <span style="color:#c678dd">else</span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">PublishedParsed</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">updated</span> = <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">PublishedParsed</span> </span></span><span style="display:flex;"><span> } <span style="color:#c678dd">else</span> <span style="color:#c678dd">if</span> <span style="color:#e5c07b">len</span>(<span style="color:#e06c75">feed</span>.<span style="color:#e06c75">Items</span>) &gt; <span style="color:#d19a66">0</span> <span style="color:#56b6c2">&amp;&amp;</span> <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">Items</span>[<span style="color:#d19a66">0</span>].<span style="color:#e06c75">UpdatedParsed</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">updated</span> = <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">Items</span>[<span style="color:#d19a66">0</span>].<span style="color:#e06c75">UpdatedParsed</span> </span></span><span style="display:flex;"><span> } <span style="color:#c678dd">else</span> <span style="color:#c678dd">if</span> <span style="color:#e5c07b">len</span>(<span style="color:#e06c75">feed</span>.<span style="color:#e06c75">Items</span>) &gt; <span style="color:#d19a66">0</span> <span style="color:#56b6c2">&amp;&amp;</span> <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">Items</span>[<span style="color:#d19a66">0</span>].<span style="color:#e06c75">PublishedParsed</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">updated</span> = <span style="color:#e06c75">feed</span>.<span style="color:#e06c75">Items</span>[<span style="color:#d19a66">0</span>].<span style="color:#e06c75">PublishedParsed</span> </span></span><span style="display:flex;"><span> } <span style="color:#c678dd">else</span> { </span></span><span style="display:flex;"><span> <span style="color:#7f848e">// Couldn&#39;t find the last update </span></span></span><span style="display:flex;"><span><span style="color:#7f848e"></span> <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Println</span>(<span style="color:#98c379">&#34;&gt;&#34;</span>, <span style="color:#e06c75">url</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#e06c75">duration</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">today</span>.<span style="color:#61afef;font-weight:bold">Sub</span>(<span style="color:#56b6c2">*</span><span style="color:#e06c75">updated</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">days</span> <span style="color:#56b6c2">:=</span> <span style="color:#e5c07b">int</span>(<span style="color:#e06c75">duration</span>.<span style="color:#61afef;font-weight:bold">Hours</span>() <span style="color:#56b6c2">/</span> <span style="color:#d19a66">24</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">days</span> &gt; <span style="color:#d19a66">180</span> { <span style="color:#7f848e">// Older: 6 months </span></span></span><span style="display:flex;"><span><span style="color:#7f848e"></span> <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Println</span>(<span style="color:#e06c75">days</span>, <span style="color:#e06c75">url</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span>} </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">func</span> <span style="color:#61afef;font-weight:bold">main</span>() { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">file</span>, <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">os</span>.<span style="color:#61afef;font-weight:bold">Open</span>(<span style="color:#98c379">&#34;urls.txt&#34;</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Println</span>(<span style="color:#98c379">&#34;Error:&#34;</span>, <span style="color:#e06c75">err</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#c678dd">defer</span> <span style="color:#e06c75">file</span>.<span style="color:#61afef;font-weight:bold">Close</span>() </span></span><span style="display:flex;"><span> <span style="color:#e06c75">scanner</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">bufio</span>.<span style="color:#61afef;font-weight:bold">NewScanner</span>(<span style="color:#e06c75">file</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">urls</span> <span style="color:#56b6c2">:=</span> []<span style="color:#e5c07b">string</span>{} </span></span><span style="display:flex;"><span> <span style="color:#e06c75">pattern</span> <span style="color:#56b6c2">:=</span> <span style="color:#98c379">`\bhttps?:\/\/[-A-Za-z0-9+&amp;@#\/%?=~_|!:,.;]*[-A-Za-z0-9+&amp;@#\/%=~_|]`</span> </span></span><span style="display:flex;"><span> <span style="color:#e06c75">regex</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">regexp</span>.<span style="color:#61afef;font-weight:bold">MustCompile</span>(<span style="color:#e06c75">pattern</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">for</span> <span style="color:#e06c75">scanner</span>.<span style="color:#61afef;font-weight:bold">Scan</span>() { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">line</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">scanner</span>.<span style="color:#61afef;font-weight:bold">Text</span>() </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">line</span> <span style="color:#56b6c2">!=</span> <span style="color:#98c379">&#34;&#34;</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">matches</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">regex</span>.<span style="color:#61afef;font-weight:bold">FindAllString</span>(<span style="color:#e06c75">line</span>, <span style="color:#56b6c2">-</span><span style="color:#d19a66">1</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">for</span> <span style="color:#e06c75">_</span>, <span style="color:#e06c75">url</span> <span style="color:#56b6c2">:=</span> <span style="color:#c678dd">range</span> <span style="color:#e06c75">matches</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">urls</span> = <span style="color:#e5c07b">append</span>(<span style="color:#e06c75">urls</span>, <span style="color:#e06c75">url</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">scanner</span>.<span style="color:#61afef;font-weight:bold">Err</span>(); <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Println</span>(<span style="color:#98c379">&#34;Error:&#34;</span>, <span style="color:#e06c75">err</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">wg</span> <span style="color:#e06c75">sync</span>.<span style="color:#e06c75">WaitGroup</span> </span></span><span style="display:flex;"><span> <span style="color:#e06c75">wg</span>.<span style="color:#61afef;font-weight:bold">Add</span>(<span style="color:#e5c07b">len</span>(<span style="color:#e06c75">urls</span>)) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">for</span> <span style="color:#e06c75">_</span>, <span style="color:#e06c75">url</span> <span style="color:#56b6c2">:=</span> <span style="color:#c678dd">range</span> <span style="color:#e06c75">urls</span> { </span></span><span style="display:flex;"><span> <span style="color:#c678dd">go</span> <span style="color:#c678dd">func</span>(<span style="color:#e06c75">url</span> <span style="color:#e5c07b">string</span>) { </span></span><span style="display:flex;"><span> <span style="color:#c678dd">defer</span> <span style="color:#e06c75">wg</span>.<span style="color:#61afef;font-weight:bold">Done</span>() </span></span><span style="display:flex;"><span> <span style="color:#61afef;font-weight:bold">getFeed</span>(<span style="color:#e06c75">url</span>) </span></span><span style="display:flex;"><span> }(<span style="color:#e06c75">url</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#e06c75">wg</span>.<span style="color:#61afef;font-weight:bold">Wait</span>() </span></span><span style="display:flex;"><span>} </span></span></code></pre></div>Resúmenes de texto con Gemma (Google) + MLXhttps://abeestrada.com/post/resumenes-gemma-mlx/Wed, 28 Feb 2024 11:30:00 -0700https://abeestrada.com/post/resumenes-gemma-mlx/<p>Este es un ejemplo de como crear resúmenes de documentos (txt y pdf) en Español utilizando el modelo gratuito de Google: <a href="https://ai.google.dev/gemma" target="_blank" rel="noopener">Gemma</a> en sus dos variantes 2B y 7B en dispositivos con Apple Silicon utilizando Python y <a href="https://github.com/ml-explore/mlx" target="_blank" rel="noopener">MLX</a> .</p> <h5 id="dependencias">Dependencias</h5> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>pip install mlx_lm torch langchain langchain_community pypdf tqdm </span></span></code></pre></div><h5 id="código">Código</h5> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#c678dd">from</span> <span style="color:#e06c75">mlx_lm</span> <span style="color:#c678dd">import</span> <span style="color:#e06c75">load</span>, <span style="color:#e06c75">generate</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">from</span> <span style="color:#e06c75">jinja2</span> <span style="color:#c678dd">import</span> <span style="color:#e06c75">Template</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">from</span> <span style="color:#e06c75">tqdm</span> <span style="color:#c678dd">import</span> <span style="color:#e06c75">tqdm</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">from</span> <span style="color:#e06c75">langchain_community.document_loaders</span> <span style="color:#c678dd">import</span> <span style="color:#e06c75">PyPDFLoader</span>, <span style="color:#e06c75">TextLoader</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">from</span> <span style="color:#e06c75">langchain.text_splitter</span> <span style="color:#c678dd">import</span> <span style="color:#e06c75">RecursiveCharacterTextSplitter</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#7f848e"># model_id = &#34;mlx-community/quantized-gemma-7b-it&#34;</span> </span></span><span style="display:flex;"><span><span style="color:#e06c75">model_id</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">&#34;mlx-community/quantized-gemma-2b-it&#34;</span> </span></span><span style="display:flex;"><span><span style="color:#e06c75">model</span>, <span style="color:#e06c75">tokenizer</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">load</span>(<span style="color:#e06c75">model_id</span>) </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#e06c75">loaders</span> <span style="color:#56b6c2">=</span> {<span style="color:#98c379">&#34;pdf&#34;</span>: <span style="color:#e06c75">PyPDFLoader</span>, <span style="color:#98c379">&#34;txt&#34;</span>: <span style="color:#e06c75">TextLoader</span>} </span></span><span style="display:flex;"><span><span style="color:#e06c75">text_splitter</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">RecursiveCharacterTextSplitter</span>( </span></span><span style="display:flex;"><span> <span style="color:#e06c75">chunk_size</span><span style="color:#56b6c2">=</span><span style="color:#d19a66">5000</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">chunk_overlap</span><span style="color:#56b6c2">=</span><span style="color:#d19a66">20</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">length_function</span><span style="color:#56b6c2">=</span><span style="color:#e5c07b">len</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">is_separator_regex</span><span style="color:#56b6c2">=</span><span style="color:#e5c07b">False</span>, </span></span><span style="display:flex;"><span>) </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#7f848e"># https://storage.googleapis.com/deepmind-media/gemma/gemma-report.pdf</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">def</span> <span style="color:#61afef;font-weight:bold">prompt_template</span>(<span style="color:#e06c75">messages</span>, <span style="color:#e06c75">add_generation</span><span style="color:#56b6c2">=</span><span style="color:#e5c07b">True</span>): </span></span><span style="display:flex;"><span> <span style="color:#e06c75">template_str</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">&#34;&#34;&#34; </span></span></span><span style="display:flex;"><span><span style="color:#98c379"> {</span><span style="color:#98c379">% f</span><span style="color:#98c379">or item in messages %} </span></span></span><span style="display:flex;"><span><span style="color:#98c379"> &lt;start_of_turn&gt;{{ item.role }}</span><span style="color:#98c379">\n</span><span style="color:#98c379">{{ item.content }}&lt;end_of_turn&gt;</span><span style="color:#98c379">\n</span><span style="color:#98c379"> </span></span></span><span style="display:flex;"><span><span style="color:#98c379"> {</span><span style="color:#98c379">% i</span><span style="color:#98c379">f loop.last %}{</span><span style="color:#98c379">% i</span><span style="color:#98c379">f add_generation %}&lt;start_of_turn&gt;model</span><span style="color:#98c379">\n</span><span style="color:#98c379">{</span><span style="color:#98c379">% e</span><span style="color:#98c379">ndif %}{</span><span style="color:#98c379">% e</span><span style="color:#98c379">ndif %} </span></span></span><span style="display:flex;"><span><span style="color:#98c379"> {</span><span style="color:#98c379">% e</span><span style="color:#98c379">ndfor %} </span></span></span><span style="display:flex;"><span><span style="color:#98c379"> &#34;&#34;&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#e06c75">template</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">Template</span>(<span style="color:#e06c75">template_str</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">result</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">template</span><span style="color:#56b6c2">.</span><span style="color:#e06c75">render</span>(<span style="color:#e06c75">messages</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">messages</span>, <span style="color:#e06c75">add_generation</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">add_generation</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> <span style="color:#e06c75">result</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#7f848e"># https://python.langchain.com/docs/modules/data_connection/document_loaders/</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">def</span> <span style="color:#61afef;font-weight:bold">load_file</span>(<span style="color:#e06c75">file_name</span>, <span style="color:#e06c75">file_type</span>): </span></span><span style="display:flex;"><span> <span style="color:#e06c75">path</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">f</span><span style="color:#98c379">&#34;./assets/</span><span style="color:#98c379">{</span><span style="color:#e06c75">file_name</span><span style="color:#98c379">}</span><span style="color:#98c379">.</span><span style="color:#98c379">{</span><span style="color:#e06c75">file_type</span><span style="color:#98c379">}</span><span style="color:#98c379">&#34;</span> </span></span><span style="display:flex;"><span> <span style="color:#e06c75">LoaderClass</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">loaders</span><span style="color:#56b6c2">.</span><span style="color:#e06c75">get</span>(<span style="color:#e06c75">file_type</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">LoaderClass</span> <span style="color:#56b6c2">is</span> <span style="color:#e5c07b">None</span>: </span></span><span style="display:flex;"><span> <span style="color:#c678dd">raise</span> <span style="color:#e06c75">ValueError</span>(<span style="color:#98c379">f</span><span style="color:#98c379">&#34;Unknown file type: </span><span style="color:#98c379">{</span><span style="color:#e06c75">file_type</span><span style="color:#98c379">}</span><span style="color:#98c379">&#34;</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">loader</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">LoaderClass</span>(<span style="color:#e06c75">path</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> <span style="color:#e06c75">loader</span><span style="color:#56b6c2">.</span><span style="color:#e06c75">load_and_split</span>(<span style="color:#e06c75">text_splitter</span>) </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">def</span> <span style="color:#61afef;font-weight:bold">main</span>(): </span></span><span style="display:flex;"><span> <span style="color:#7f848e"># https://normas-apa.org/wp-content/uploads/Guia-Normas-APA-7ma-edicion.pdf</span> </span></span><span style="display:flex;"><span> <span style="color:#7f848e"># document = load_file(&#34;Guia-Normas-APA-7ma-edicion&#34;, &#34;pdf&#34;)</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> <span style="color:#7f848e"># https://www.gutenberg.org/ebooks/2000</span> </span></span><span style="display:flex;"><span> <span style="color:#e06c75">document</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">load_file</span>(<span style="color:#98c379">&#34;pg2000&#34;</span>, <span style="color:#98c379">&#34;txt&#34;</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">prompt</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">&#34;Crea un resumen del siguiente documento:&#34;</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> <span style="color:#e06c75">summaries</span> <span style="color:#56b6c2">=</span> [] </span></span><span style="display:flex;"><span> <span style="color:#c678dd">for</span> <span style="color:#e06c75">doc</span> <span style="color:#56b6c2">in</span> <span style="color:#e06c75">tqdm</span>(<span style="color:#e06c75">document</span>[:<span style="color:#d19a66">48</span>]): </span></span><span style="display:flex;"><span> <span style="color:#e06c75">summaries</span><span style="color:#56b6c2">.</span><span style="color:#e06c75">append</span>( </span></span><span style="display:flex;"><span> <span style="color:#e06c75">generate</span>( </span></span><span style="display:flex;"><span> <span style="color:#e06c75">model</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">tokenizer</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">tokenizer</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">prompt</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">prompt_template</span>( </span></span><span style="display:flex;"><span> [{ </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;content&#34;</span>: <span style="color:#e06c75">prompt</span> <span style="color:#56b6c2">+</span> <span style="color:#98c379">f</span><span style="color:#98c379">&#34;&#39;</span><span style="color:#98c379">{</span><span style="color:#e06c75">doc</span><span style="color:#56b6c2">.</span><span style="color:#e06c75">page_content</span><span style="color:#98c379">}</span><span style="color:#98c379">&#39;&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;role&#34;</span>: <span style="color:#98c379">&#34;user&#34;</span> </span></span><span style="display:flex;"><span> }]), </span></span><span style="display:flex;"><span> <span style="color:#e06c75">temp</span><span style="color:#56b6c2">=</span><span style="color:#d19a66">0.2</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">max_tokens</span><span style="color:#56b6c2">=</span><span style="color:#d19a66">512</span>, </span></span><span style="display:flex;"><span> )) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">summaries_text</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">&#34;</span><span style="color:#98c379">\n</span><span style="color:#98c379">&#34;</span><span style="color:#56b6c2">.</span><span style="color:#e06c75">join</span>(<span style="color:#e06c75">summaries</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">prompt_summary</span> <span style="color:#56b6c2">=</span> { </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;content&#34;</span>: <span style="color:#98c379">f</span><span style="color:#98c379">&#34;Crea un resumen del siguiente documento: &#39;</span><span style="color:#98c379">{</span><span style="color:#e06c75">summaries_text</span><span style="color:#98c379">}</span><span style="color:#98c379">&#39;&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#98c379">&#34;role&#34;</span>: <span style="color:#98c379">&#34;user&#34;</span> </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#e06c75">result</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">generate</span>( </span></span><span style="display:flex;"><span> <span style="color:#e06c75">model</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">tokenizer</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">tokenizer</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">prompt</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">prompt_template</span>([<span style="color:#e06c75">prompt_summary</span>]), </span></span><span style="display:flex;"><span> <span style="color:#e06c75">temp</span><span style="color:#56b6c2">=</span><span style="color:#d19a66">0.2</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">max_tokens</span><span style="color:#56b6c2">=</span><span style="color:#d19a66">1024</span> </span></span><span style="display:flex;"><span> ) </span></span><span style="display:flex;"><span> <span style="color:#e5c07b">print</span>(<span style="color:#e06c75">result</span>) </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">if</span> <span style="color:#e06c75">__name__</span> <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#39;__main__&#39;</span>: </span></span><span style="display:flex;"><span> <span style="color:#e06c75">main</span>() </span></span></code></pre></div><p>Lo que hace el código anterior es cargar un archivo, partirlo en fragmentos y crear pequeños resúmenes, para luego en base a esos resúmenes crear un resumen general. Se pueden modificar las variables para extraer información más puntual, empezando con <code>prompt_summary</code> para buscar nombres por ejemplo, cambiar la temperatura para obtener diferentes resultados y el tamaño del texto de los fragmentos (<code>max_tokens</code>) del documento para un resultado más amplio, en caso de los resúmenes es de esperarse que alguna información se pierda.</p> <p>Si el tamaño del documento es muy grande para la capacidad de procesamiento, se puede partir el documento para agilizarlo y no acabarnos la memoria, por ejemplo <code>for doc in tqdm(document[:48]):</code> solo obtenemos el primer 10% del documento en caso de que el total sea 481 en el caso del documento <code>pg2000.txt</code>. El tamaño ideal puede variar entre capacidades de cómputo y el tamaño del documento.</p> <h4 id="comparativa-de-los-modelos-con-el-2-del-documento">Comparativa de los modelos con el 2% del documento</h4> <h5 id="gemma-2b">Gemma 2B</h5> <blockquote> <p>El documento es un resumen del libro &ldquo;El ingenioso hidalgo de la Mancha&rdquo; de Miguel de Cervantes Saavedra. Describe la historia de un caballero llamado Don Quijote, incluyendo su vida y las muchas aventuras que lo han marcado.</p> </blockquote> <h5 id="gemma-7b">Gemma 7B</h5> <blockquote> <p>El documento es un resumen del libro &ldquo;Don Quijote&rdquo; de Miguel de Cervantes Saavedra. Describe la historia del ingenioso hidalgo don Quijote de la Mancha, desde su infancia hasta su muerte. Se cuenta cómo Don Quijote tuvo una serie de aventuras y experiencias, incluyendo una aventura con los cuadrilleros, una aventura con el Caballero del Bosque, una aventura con el pastor enamorado y una aventura con el rebuño y el titlerero. También se cuenta cómo Don Quijote tuvo varias relaciones amorosas y cómo finalmente llegó al casamiento que quería con Dulcinea del Toboso.</p> </blockquote> <figure class="w-1/2" > <img src="https://files.abeestrada.com/images/2024/02/mlx-gemma-2b-7b.png" loading="lazy"> </figure> <hr> <h4 id="enlaces">Enlaces</h4> <ul> <li><a href="https://storage.googleapis.com/deepmind-media/gemma/gemma-report.pdf" target="_blank" rel="noopener">Gemma: Open Models Based on Gemini Research and Technology</a> </li> </ul>Qwen1.5https://abeestrada.com/post/qwen1.5/Mon, 05 Feb 2024 18:50:00 -0700https://abeestrada.com/post/qwen1.5/<p>El modelo <a href="https://github.com/QwenLM/Qwen" target="_blank" rel="noopener">Qwen</a> de Alibaba ha sido <a href="https://qwenlm.github.io/blog/qwen1.5/" target="_blank" rel="noopener">actualizado</a> y ya se puede ejecutar con <a href="https://github.com/ml-explore/mlx" target="_blank" rel="noopener">MLX</a> :</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>pip install -U mlx-lm </span></span><span style="display:flex;"><span>python -m mlx_lm.generate<span style="color:#98c379">\ </span></span></span><span style="display:flex;"><span><span style="color:#98c379"></span> --model <span style="color:#98c379">&#34;mlx-community/Qwen1.5-7B-Chat-4bit-mlx&#34;</span><span style="color:#98c379">\ </span></span></span><span style="display:flex;"><span><span style="color:#98c379"></span> --eos-token <span style="color:#98c379">&#34;&lt;|im_end|&gt;&#34;</span><span style="color:#98c379">\ </span></span></span><span style="display:flex;"><span><span style="color:#98c379"></span> --max-tokens 500<span style="color:#98c379">\ </span></span></span><span style="display:flex;"><span><span style="color:#98c379"></span> --prompt <span style="color:#98c379">&#34;write a quick sort in python&#34;</span> </span></span></code></pre></div> <div class="container-md p-0 p-md-3"> <video class="mw-100" preload="auto" controls muted loop playsinline> <source src="https://files.abeestrada.com/images/2024/01/qwen1.5-7b-chat-4bit-mlx.mp4" type="video/mp4" /> </video> </div>SwiftData Previewshttps://abeestrada.com/post/swiftdata-previews/Fri, 02 Feb 2024 19:00:00 -0700https://abeestrada.com/post/swiftdata-previews/<p>Algo que me entretuvo bastante tiempo, es la forma en que podemos agregar un <code>#Preview</code> con contenido de algún modelo utilizando SwiftData a una vista anidada, que no sea la principal o típica <code>ContentView</code> en <em>SwiftUI</em>.</p> <p>El ejemplo que encontré por todos lados es el siguiente:</p> <p>Tenemos el modelo y agregamos una extensión llamada <code>preview</code> que podemos utilizar en la vista base.</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#c678dd">import</span> <span style="color:#e5c07b">Foundation</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">import</span> <span style="color:#e5c07b">SwiftData</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>@<span style="color:#e06c75">Model</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">class</span> <span style="color:#e5c07b">Item</span>: <span style="color:#e06c75">Identifiable</span>{ </span></span><span style="display:flex;"><span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">name</span>: <span style="color:#e5c07b">String</span> </span></span><span style="display:flex;"><span> <span style="color:#c678dd">init</span>(<span style="color:#e06c75">name</span>: <span style="color:#e5c07b">String</span>){ </span></span><span style="display:flex;"><span> <span style="color:#e5c07b">self</span>.<span style="color:#e06c75">name</span> = <span style="color:#e06c75">name</span> </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span>} </span></span><span style="display:flex;"><span><span style="color:#c678dd">extension</span> <span style="color:#e5c07b">Item</span> { </span></span><span style="display:flex;"><span> @<span style="color:#e06c75">MainActor</span> </span></span><span style="display:flex;"><span> <span style="color:#c678dd">static</span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">preview</span>: <span style="color:#e06c75">ModelContainer</span> { </span></span><span style="display:flex;"><span> <span style="color:#c678dd">let</span> <span style="color:#e06c75">container</span> = <span style="color:#c678dd">try</span>! <span style="color:#e06c75">ModelContainer</span>(<span style="color:#c678dd">for</span>: <span style="color:#e06c75">Item</span>.<span style="color:#e5c07b">self</span>, </span></span><span style="display:flex;"><span> <span style="color:#e06c75">configurations</span>: <span style="color:#e06c75">ModelConfiguration</span>(<span style="color:#e06c75">isStoredInMemoryOnly</span>: <span style="color:#e5c07b">true</span>)) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">let</span> <span style="color:#e06c75">items</span> = [ </span></span><span style="display:flex;"><span> <span style="color:#e06c75">Item</span>(<span style="color:#e06c75">name</span>: <span style="color:#98c379">&#34;Ejemplo 1&#34;</span>), </span></span><span style="display:flex;"><span> <span style="color:#e06c75">Item</span>(<span style="color:#e06c75">name</span>: <span style="color:#98c379">&#34;Ejemplo 2&#34;</span>) </span></span><span style="display:flex;"><span> ] </span></span><span style="display:flex;"><span> <span style="color:#c678dd">for</span> <span style="color:#e06c75">item</span> <span style="color:#c678dd">in</span> <span style="color:#e06c75">items</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">container</span>.<span style="color:#e06c75">mainContext</span>.<span style="color:#e06c75">insert</span>(<span style="color:#e06c75">item</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> <span style="color:#e06c75">container</span> </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p>El cual podemos utilizar de la siguiente forma:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span>#<span style="color:#e06c75">Preview</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">ContentView</span>() </span></span><span style="display:flex;"><span> .<span style="color:#e06c75">modelContainer</span>(<span style="color:#e06c75">Item</span>.<span style="color:#e06c75">preview</span>) </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p>El problema surge cuando queremos accesar al <code>modelContainer</code> en otra vista, ya que este fue solo declarado dentro de la <code>*App.Swift</code> para <code>ContentView</code>.</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#c678dd">import</span> <span style="color:#e5c07b">SwiftUI</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>@<span style="color:#e06c75">main</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">struct</span> <span style="color:#e5c07b">MyApp</span>: <span style="color:#e06c75">App</span> { </span></span><span style="display:flex;"><span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">body</span>: <span style="color:#e06c75">some</span> <span style="color:#e06c75">Scene</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">WindowGroup</span>() { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">ContentView</span>() </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> .<span style="color:#e06c75">modelContainer</span>(<span style="color:#c678dd">for</span>: <span style="color:#e06c75">Item</span>.<span style="color:#e5c07b">self</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p>Para esto, debemos declarar primero el <code>mainContext</code> y con esto podemos agregar objetos:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span>#<span style="color:#e06c75">Preview</span> { </span></span><span style="display:flex;"><span> <span style="color:#c678dd">let</span> <span style="color:#e06c75">context</span> = <span style="color:#e06c75">Item</span>.<span style="color:#e06c75">preview</span>.<span style="color:#e06c75">mainContext</span> </span></span><span style="display:flex;"><span> <span style="color:#c678dd">let</span> <span style="color:#e06c75">item</span> = <span style="color:#e06c75">Item</span>(<span style="color:#e06c75">name</span>: <span style="color:#98c379">&#34;Ejemplo 3&#34;</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">context</span>.<span style="color:#e06c75">insert</span>(<span style="color:#e06c75">item</span>) </span></span><span style="display:flex;"><span> <span style="color:#c678dd">return</span> <span style="color:#e06c75">NavigationStack</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">AnotherView</span>(<span style="color:#e06c75">item</span>: <span style="color:#e06c75">item</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p>Fuente: <a href="https://www.hackingwithswift.com/forums/swiftui/swiftdata-child-views-not-updating-on-insertions-but-updating-fine-on-deletions/25407" target="_blank" rel="noopener">Hacking with Swift forums</a> </p>SwiftUI UserInterfaceSizeClasshttps://abeestrada.com/post/swiftui-userinterfacesizeclass/Mon, 29 Jan 2024 17:00:00 -0700https://abeestrada.com/post/swiftui-userinterfacesizeclass/<p>Hasta ahora, todos los ejemplos para utilizar <a href="https://developer.apple.com/documentation/swiftui/userinterfacesizeclass" target="_blank" rel="noopener">UserInterfaceSizeClass</a> son así:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#c678dd">struct</span> <span style="color:#e5c07b">MyView</span>: <span style="color:#e06c75">View</span> { </span></span><span style="display:flex;"><span> @<span style="color:#e06c75">Environment</span>(\.<span style="color:#e06c75">horizontalSizeClass</span>) <span style="color:#c678dd">private</span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">horizontalSizeClass</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">body</span>: <span style="color:#e06c75">some</span> <span style="color:#e06c75">View</span> { </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">horizontalSizeClass</span> == .<span style="color:#e06c75">compact</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">Text</span>(<span style="color:#98c379">&#34;Portrait&#34;</span>) </span></span><span style="display:flex;"><span> } <span style="color:#c678dd">else</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">Text</span>(<span style="color:#98c379">&#34;Landscape&#34;</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p>Pero al momento de ejecutar el código, no funciona, ya que al parecer <code>horizontalSizeClass</code> no es suficiente para determinar si un dispositivo a cambiado de orientación.</p> <p>Y este ejemplo, es el único que me ha funcionado:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#c678dd">struct</span> <span style="color:#e5c07b">MyView</span>: <span style="color:#e06c75">View</span> { </span></span><span style="display:flex;"><span> @<span style="color:#e06c75">Environment</span>(\.<span style="color:#e06c75">verticalSizeClass</span>) <span style="color:#c678dd">private</span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">verticalSizeClass</span> </span></span><span style="display:flex;"><span> @<span style="color:#e06c75">Environment</span>(\.<span style="color:#e06c75">horizontalSizeClass</span>) <span style="color:#c678dd">private</span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">horizontalSizeClass</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> <span style="color:#c678dd">var</span> <span style="color:#e06c75">body</span>: <span style="color:#e06c75">some</span> <span style="color:#e06c75">View</span> { </span></span><span style="display:flex;"><span> <span style="color:#c678dd">if</span> (<span style="color:#e06c75">horizontalSizeClass</span> == .<span style="color:#e06c75">regular</span> <span style="color:#56b6c2">&amp;&amp;</span> <span style="color:#e06c75">verticalSizeClass</span> == .<span style="color:#e06c75">compact</span>) <span style="color:#56b6c2">||</span> </span></span><span style="display:flex;"><span> (<span style="color:#e06c75">horizontalSizeClass</span> == .<span style="color:#e06c75">compact</span> <span style="color:#56b6c2">&amp;&amp;</span> <span style="color:#e06c75">verticalSizeClass</span> == .<span style="color:#e06c75">compact</span>) { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">Text</span>(<span style="color:#98c379">&#34;Landscape (iPhone)&#34;</span>) </span></span><span style="display:flex;"><span> } <span style="color:#c678dd">else</span> <span style="color:#c678dd">if</span> <span style="color:#e06c75">horizontalSizeClass</span> == .<span style="color:#e06c75">compact</span> <span style="color:#56b6c2">&amp;&amp;</span> <span style="color:#e06c75">verticalSizeClass</span> == .<span style="color:#e06c75">regular</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">Text</span>(<span style="color:#98c379">&#34;Portrait (iPhone)&#34;</span>) </span></span><span style="display:flex;"><span> } <span style="color:#c678dd">else</span> { </span></span><span style="display:flex;"><span> <span style="color:#e06c75">Text</span>(<span style="color:#98c379">&#34;iPad&#34;</span>) </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span> } </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p>Fuente: <a href="https://note.com/taatn0te/n/nc87bcd599f30" target="_blank" rel="noopener">SwiftUIでサイズクラスに応じてレイアウトを変える</a> </p>WordPress Playgroundhttps://abeestrada.com/post/wordpress-playground/Thu, 25 Jan 2024 16:30:00 -0700https://abeestrada.com/post/wordpress-playground/<p>Siendo uno de mis primeros lenguajes que aprendí, tengo más de 10 años sin escribir código en <a href="https://www.php.net" target="_blank" rel="noopener">PHP</a> .</p> <p>Y el día de hoy aprendí algo que me voló la cabeza 🤯 y es que ya se puede ejecutar PHP por medio de <a href="https://nodejs.org" target="_blank" rel="noopener">Node.js</a> sin instalar nada extra, gracias a <a href="https://webassembly.org" target="_blank" rel="noopener">WebAssembly</a> (Wasm). Esto se debe a que lograron compilar todo el código de PHP, escrito en un 75% de C a Wasm el cual es interpretado por JavaScript.</p> <p>Tan sencillo como:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ npx @php-wasm/cli -v </span></span><span style="display:flex;"><span>PHP 8.3.0-dev <span style="color:#56b6c2">(</span>cli<span style="color:#56b6c2">)</span> <span style="color:#56b6c2">(</span>built: Jan <span style="color:#d19a66">17</span> <span style="color:#d19a66">2024</span> 23:41:46<span style="color:#56b6c2">)</span> <span style="color:#56b6c2">(</span>NTS<span style="color:#56b6c2">)</span> </span></span><span style="display:flex;"><span>Copyright <span style="color:#56b6c2">(</span>c<span style="color:#56b6c2">)</span> The PHP Group </span></span><span style="display:flex;"><span>Zend Engine v4.3.0-dev, Copyright <span style="color:#56b6c2">(</span>c<span style="color:#56b6c2">)</span> Zend Technologies </span></span></code></pre></div><p>Además de también poder cambiar la versión:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ <span style="color:#e06c75">PHP</span><span style="color:#56b6c2">=</span>7.4 npx @php-wasm/cli -v </span></span><span style="display:flex;"><span>PHP 7.4.31-dev <span style="color:#56b6c2">(</span>cli<span style="color:#56b6c2">)</span> <span style="color:#56b6c2">(</span>built: Jan <span style="color:#d19a66">17</span> <span style="color:#d19a66">2024</span> 23:43:33<span style="color:#56b6c2">)</span> <span style="color:#56b6c2">(</span> NTS <span style="color:#56b6c2">)</span> </span></span><span style="display:flex;"><span>Copyright <span style="color:#56b6c2">(</span>c<span style="color:#56b6c2">)</span> The PHP Group </span></span><span style="display:flex;"><span>Zend Engine v3.4.0, Copyright <span style="color:#56b6c2">(</span>c<span style="color:#56b6c2">)</span> Zend Technologies </span></span></code></pre></div><p>Las <a href="https://github.com/WordPress/wordpress-playground/blob/trunk/packages/php-wasm/universal/src/lib/supported-php-versions.ts" target="_blank" rel="noopener">versiones disponibles</a> por el momento, son:</p> <ul> <li>8.3</li> <li>8.2</li> <li>8.1</li> <li>8.0</li> <li>7.4</li> <li>7.3</li> <li>7.2</li> <li>7.1</li> <li>7.0</li> </ul> <p>Incluso se puede ejecutar el servidor web que incluye PHP:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>npx @php-wasm/cli -S localhost:8000 </span></span></code></pre></div><p>Y es así como después de más de 10 años, pude escribir PHP de nuevo:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#56b6c2">&lt;?</span><span style="color:#e06c75">php</span> <span style="color:#e06c75">phpinfo</span>(); </span></span></code></pre></div><p>El proyecto es creado y mantenido por <a href="https://developer.wordpress.org/playground/" target="_blank" rel="noopener">WordPress</a> /<a href="https://github.com/WordPress/wordpress-playground" target="_blank" rel="noopener">wordpress-playground</a> .</p>Tools I usehttps://abeestrada.com/uses/Tue, 23 Jan 2024 14:00:00 -0700https://abeestrada.com/uses/<p>Based on <a href="https://uses.tech" target="_blank" rel="noopener">https://uses.tech</a> </p> <details class="group mx-3"> <summary class="text-2xl hover:text-violet-700 hover:dark:text-purple-400 group-open:text-violet-700 dark:group-open:text-purple-400 cursor-pointer pb-2">2024</summary> <h3 id="hardware">Hardware</h3> <ul> <li>16-inch 2023 MacBook Pro <ul> <li>Apple M2 Max</li> <li>32 GB RAM</li> </ul> </li> <li>Magic Keyboard</li> <li>Magic Trackpad</li> <li>iPhone X</li> <li><a href="https://steelseries.com/gaming-headsets/arctis-nova-7x?color=black" target="_blank" rel="noopener">Arctis Nova 7X Wireless</a> </li> </ul> <h3 id="software">Software</h3> <h4 id="macos-14-sonoma">macOS 14 Sonoma</h4> <ul> <li><a href="https://adblockplus.org" target="_blank" rel="noopener">Adblock Plus</a> </li> <li><a href="https://freemacsoft.net/appcleaner/" target="_blank" rel="noopener">AppCleaner</a> </li> <li><a href="https://www.arqbackup.com" target="_blank" rel="noopener">Arq</a> </li> <li><a href="https://www.mozilla.org/en-US/firefox/" target="_blank" rel="noopener">Firefox</a> </li> <li><a href="https://overcast.fm/forecast" target="_blank" rel="noopener">Forecast</a> </li> <li><a href="https://www.google.com/chrome/" target="_blank" rel="noopener">Google Chrome</a> </li> <li><a href="https://imageoptim.com/mac" target="_blank" rel="noopener">ImageOptim</a> </li> <li><a href="https://www.apple.com/logic-pro/" target="_blank" rel="noopener">Logic Pro</a> </li> <li><a href="https://www.pixelmator.com/pro/" target="_blank" rel="noopener">Pixelmator Pro</a> </li> <li><a href="https://rssdiscovery.app" target="_blank" rel="noopener">RSS Button</a> </li> <li><a href="https://underpassapp.com/StopTheMadness/" target="_blank" rel="noopener">StopTheMadness Pro</a> </li> <li><a href="https://www.sublimemerge.com" target="_blank" rel="noopener">Sublime Merge</a> </li> <li><a href="https://www.sublimetext.com" target="_blank" rel="noopener">Sublime Text</a> </li> <li><a href="https://tailscale.com" target="_blank" rel="noopener">Tailscale</a> </li> <li><a href="https://www.videolan.org" target="_blank" rel="noopener">VLC</a> </li> <li><a href="https://wezfurlong.org/wezterm/" target="_blank" rel="noopener">WezTerm</a> </li> <li><a href="https://www.wireguard.com" target="_blank" rel="noopener">WireGuard</a> </li> </ul> <h4 id="zsh">ZSH</h4> <ul> <li><a href="https://aria2.github.io" target="_blank" rel="noopener">aria2</a> : Download utility</li> <li><a href="https://github.com/sharkdp/bat" target="_blank" rel="noopener">bat</a> A cat(1) clone with wings</li> <li><a href="https://clementtsang.github.io/bottom" target="_blank" rel="noopener">bottom</a> : Process/system monitor</li> <li><a href="https://github.com/Wilfred/difftastic" target="_blank" rel="noopener">difftastic</a> : A structural diff that understands syntax</li> <li><a href="https://github.com/bootandy/dust" target="_blank" rel="noopener">dust</a> A more intuitive version of du in rust</li> <li><a href="https://helix-editor.com" target="_blank" rel="noopener">helix</a> A post-modern text editor</li> <li><a href="https://github.com/eza-community/eza" target="_blank" rel="noopener">eza</a> A modern, maintained replacement for ls</li> <li><a href="https://github.com/Schniz/fnm" target="_blank" rel="noopener">fnm</a> : Fast and simple node.js version manager, built in rust</li> <li><a href="https://github.com/swsnr/mdcat" target="_blank" rel="noopener">mdcat</a> Show markdown documents on text terminals</li> <li><a href="https://newsboat.org" target="_blank" rel="noopener">newsboat</a> : RSS/Atom feed reader</li> <li><a href="https://ohmyz.sh" target="_blank" rel="noopener">oh my zsh</a> <ul> <li><a href="https://github.com/Aloxaf/fzf-tab" target="_blank" rel="noopener">fzf-tab</a> </li> <li><a href="https://github.com/zsh-users/zsh-history-substring-search" target="_blank" rel="noopener">history-substring-search</a> </li> <li><a href="https://github.com/zsh-users/zsh-autosuggestions" target="_blank" rel="noopener">zsh-autosuggestions</a> </li> <li><a href="https://github.com/lukechilds/zsh-better-npm-completion" target="_blank" rel="noopener">zsh-better-npm-completion</a> </li> <li><a href="https://github.com/zsh-users/zsh-syntax-highlighting" target="_blank" rel="noopener">zsh-syntax-highlighting</a> </li> </ul> </li> <li><a href="https://github.com/mrusme/reader" target="_blank" rel="noopener">reader</a> : A lightweight tool offering better readability of web pages on the cli</li> <li><a href="https://starship.rs" target="_blank" rel="noopener">starship</a> : The minimal, blazing-fast, and infinitely customizable prompt for any shell!</li> <li><a href="https://toot.readthedocs.io/en/latest/index.html" target="_blank" rel="noopener">toot</a> : toot is a cli and tui tool for interacting with mastodon instances</li> <li><a href="https://github.com/sxyazi/yazi" target="_blank" rel="noopener">yazi</a> Blazing fast terminal file manager written in Rust, based on async I/O</li> <li><a href="https://github.com/ajeetdsouza/zoxide" target="_blank" rel="noopener">zoxide</a> : A smarter cd command</li> </ul> <h4 id="ios">iOS</h4> <ul> <li><a href="https://apps.apple.com/us/app/adblock-plus-for-safari-abp/id1028871868" target="_blank" rel="noopener">Adblock Plus</a> </li> <li><a href="https://apps.apple.com/us/app/duckduckgo-private-browser/id663592361" target="_blank" rel="noopener">DuckDuckGo</a> </li> <li><a href="https://apps.apple.com/us/app/logsit/id776811015" target="_blank" rel="noopener">Logsit</a> </li> <li><a href="https://apps.apple.com/us/app/simple-call-blocker/id1409872025" target="_blank" rel="noopener">Simple Call Blocker</a> </li> <li><a href="https://apps.apple.com/us/app/stopthemadness-pro/id6471380298" target="_blank" rel="noopener">StopTheMadness Pro</a> </li> <li><a href="https://apps.apple.com/us/app/tailscale/id1470499037" target="_blank" rel="noopener">Tailscale</a> </li> <li><a href="https://apps.apple.com/us/app/viewexif/id945320815" target="_blank" rel="noopener">ViewExif</a> </li> <li><a href="https://apps.apple.com/us/app/wireguard/id1441195209" target="_blank" rel="noopener">WireGuard</a> </li> </ul> </details> <details class="group mx-3"> <summary class="text-2xl hover:text-violet-700 hover:dark:text-purple-400 group-open:text-violet-700 dark:group-open:text-purple-400 cursor-pointer pb-2">2023</summary> <h3 id="hardware">Hardware</h3> <ul> <li>16-inch 2023 MacBook Pro <ul> <li>Apple M2 Max</li> <li>32 GB RAM</li> </ul> </li> <li>Magic Keyboard</li> <li>Magic Trackpad</li> <li>iPhone X</li> <li><a href="https://steelseries.com/gaming-headsets/arctis-nova-7x?color=black" target="_blank" rel="noopener">Arctis Nova 7X Wireless</a> </li> </ul> <h3 id="software">Software</h3> <h4 id="macos-14-sonoma">macOS 14 Sonoma</h4> <ul> <li><a href="https://1blocker.com" target="_blank" rel="noopener">1Blocker</a> </li> <li><a href="https://freemacsoft.net/appcleaner/" target="_blank" rel="noopener">AppCleaner</a> </li> <li><a href="https://www.arqbackup.com" target="_blank" rel="noopener">Arq</a> </li> <li><a href="https://www.mozilla.org/en-US/firefox/" target="_blank" rel="noopener">Firefox</a> </li> <li><a href="https://overcast.fm/forecast" target="_blank" rel="noopener">Forecast</a> </li> <li><a href="https://www.google.com/chrome/" target="_blank" rel="noopener">Google Chrome</a> </li> <li><a href="https://imageoptim.com/mac" target="_blank" rel="noopener">ImageOptim</a> </li> <li><a href="https://kaleidoscope.app" target="_blank" rel="noopener">Kaleidoscope</a> </li> <li><a href="https://www.apple.com/logic-pro/" target="_blank" rel="noopener">Logic Pro</a> </li> <li><a href="https://www.pixelmator.com/pro/" target="_blank" rel="noopener">Pixelmator Pro</a> </li> <li><a href="https://underpassapp.com/StopTheMadness/" target="_blank" rel="noopener">StopTheMadness</a> </li> <li><a href="https://www.sublimemerge.com" target="_blank" rel="noopener">Sublime Merge</a> </li> <li><a href="https://www.sublimetext.com" target="_blank" rel="noopener">Sublime Text</a> </li> <li><a href="https://www.videolan.org" target="_blank" rel="noopener">VLC</a> </li> <li><a href="https://wezfurlong.org/wezterm/" target="_blank" rel="noopener">WezTerm</a> </li> <li><a href="https://www.wireguard.com" target="_blank" rel="noopener">WireGuard</a> </li> </ul> <h4 id="zsh">ZSH</h4> <ul> <li><a href="https://aria2.github.io" target="_blank" rel="noopener">aria2</a> : download utility</li> <li><a href="https://clementtsang.github.io/bottom" target="_blank" rel="noopener">bottom</a> : process/system monitor</li> <li><a href="https://github.com/Wilfred/difftastic" target="_blank" rel="noopener">difftastic</a> : a structural diff that understands syntax</li> <li><a href="https://github.com/Schniz/fnm" target="_blank" rel="noopener">fnm</a> : fast and simple node.js version manager, built in rust</li> <li><a href="https://newsboat.org" target="_blank" rel="noopener">newsboat</a> : rss/atom feed reader</li> <li><a href="https://ohmyz.sh" target="_blank" rel="noopener">oh my zsh</a> </li> <li><a href="https://github.com/mrusme/reader" target="_blank" rel="noopener">reader</a> : a lightweight tool offering better readability of web pages on the cli</li> <li><a href="https://starship.rs" target="_blank" rel="noopener">starship</a> : the minimal, blazing-fast, and infinitely customizable prompt for any shell!</li> <li><a href="https://toot.readthedocs.io/en/latest/index.html" target="_blank" rel="noopener">toot</a> : toot is a cli and tui tool for interacting with mastodon instances</li> <li><a href="https://github.com/ajeetdsouza/zoxide" target="_blank" rel="noopener">zoxide</a> : a smarter cd command. supports all major shells</li> </ul> </details> <details class="group mx-3"> <summary class="text-2xl hover:text-violet-700 hover:dark:text-purple-400 group-open:text-violet-700 dark:group-open:text-purple-400 cursor-pointer pb-2">2022</summary> <h3 id="hardware">Hardware</h3> <ul> <li>15&quot; MacBook Pro (2016)</li> <li>Magic Keyboard</li> <li>Magic Trackpad</li> <li>iPhone X</li> <li><a href="https://www.bose.com/en_us/products/headphones/earbuds/sport-open-earbuds.html" target="_blank" rel="noopener">Bose Sport Open Earbuds</a> </li> </ul> <h3 id="software">Software</h3> <h4 id="macos">macOS</h4> <ul> <li><a href="https://1blocker.com" target="_blank" rel="noopener">1Blocker</a> </li> <li><a href="https://freemacsoft.net/appcleaner/" target="_blank" rel="noopener">AppCleaner</a> </li> <li><a href="https://www.arqbackup.com" target="_blank" rel="noopener">Arq</a> </li> <li><a href="https://auphonic.com/leveler" target="_blank" rel="noopener">Auphonic Leveler</a> </li> <li><a href="https://www.apple.com/final-cut-pro/" target="_blank" rel="noopener">Final Cut Pro</a> </li> <li><a href="https://www.mozilla.org/en-US/firefox/" target="_blank" rel="noopener">Firefox</a> </li> <li><a href="https://overcast.fm/forecast" target="_blank" rel="noopener">Forecast</a> </li> <li><a href="https://www.google.com/chrome/" target="_blank" rel="noopener">Google Chrome</a> </li> <li><a href="https://imageoptim.com/mac" target="_blank" rel="noopener">ImageOptim</a> </li> <li><a href="https://www.izotope.com/en/products/rx.html" target="_blank" rel="noopener">iZotope RX 10</a> </li> <li><a href="https://kaleidoscope.app" target="_blank" rel="noopener">Kaleidoscope</a> </li> <li><a href="https://www.apple.com/logic-pro/" target="_blank" rel="noopener">Logic Pro</a> </li> <li><a href="https://www.pixelmator.com/pro/" target="_blank" rel="noopener">Pixelmator Pro</a> </li> <li><a href="https://underpassapp.com/StopTheMadness/" target="_blank" rel="noopener">StopTheMadness</a> </li> <li><a href="https://www.sublimemerge.com" target="_blank" rel="noopener">Sublime Merge</a> </li> <li><a href="https://www.sublimetext.com" target="_blank" rel="noopener">Sublime Text</a> </li> <li><a href="https://panic.com/transmit/" target="_blank" rel="noopener">Transmit</a> </li> <li><a href="https://www.videolan.org" target="_blank" rel="noopener">VLC</a> </li> <li><a href="https://www.wireguard.com" target="_blank" rel="noopener">WireGuard</a> </li> </ul> <h4 id="terminal">Terminal</h4> <ul> <li><a href="https://aerc-mail.org" target="_blank" rel="noopener">aerc</a> : email client</li> <li><a href="https://aria2.github.io" target="_blank" rel="noopener">aria2</a> : download utility</li> <li><a href="https://clementtsang.github.io/bottom" target="_blank" rel="noopener">bottom</a> : process/system monitor</li> <li><a href="https://isync.sourceforge.io" target="_blank" rel="noopener">isync</a> : mailbox synchronization</li> <li><a href="https://newsboat.org" target="_blank" rel="noopener">newsboat</a> : rss/atom feed reader</li> <li><a href="https://toot.readthedocs.io/en/latest/index.html" target="_blank" rel="noopener">toot</a> : toot is a cli and tui tool for interacting with mastodon instances from the command line</li> <li><a href="https://tut.anv.nu" target="_blank" rel="noopener">tut</a> : tut is a tui for mastodon with vim inspired keys</li> </ul> </details>OpenVINO Noise Suppressionhttps://abeestrada.com/post/openvino-noise-suppression/Thu, 04 Jan 2024 21:00:00 -0700https://abeestrada.com/post/openvino-noise-suppression/<p>Me acabo de enterar que <a href="https://www.audacityteam.org/blog/openvino-ai-effects/" target="_blank" rel="noopener">Intel ha creado</a> un conjunto de herramientas (plugins) de IA (que en realidad es Machine Learning) para Audacity, útiles tanto para audio solo con voz como para música. Estas funciones se ejecutan de forma 100% local.</p> <p>Para los contenidos de solo voz, el plugin de supresión de ruido es procesado utilizando OpenVINO.</p> <p>Por el momento el plugin solo esta disponible para Windows (precompilado) y para Linux si lo compilas desde cero.</p> <p>En mi casolo, solo quiero probar el Noise Suppression en macOS.</p> <p>Primero hay que crear un <a href="https://docs.python.org/3/library/venv.html" target="_blank" rel="noopener">ambiente virtual de Python</a> para este proyecto.</p> <p>Empezamos con instalar OpenVINO.</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>pip install openvino </span></span></code></pre></div><p>Y verificamos que funcione:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>python -c <span style="color:#98c379">&#34;from openvino.runtime import Core; print(Core().available_devices)&#34;</span> </span></span></code></pre></div><p>Luego tenemos que conseguir los modelos, para lo cual tenemos dos opciones:</p> <ol> <li>De la página de plugins, descargamos <a href="https://github.com/intel/openvino-plugins-ai-audacity/releases/download/v3.4.2-R1/openvino-models.zip" target="_blank" rel="noopener"><code>openvino-models.zip</code></a> y extraemos los archivos:</li> </ol> <ul> <li><code>noise-suppression-denseunet-ll-0001.bin</code></li> <li><code>noise-suppression-denseunet-ll-0001.xml</code></li> </ul> <ol start="2"> <li>En el repositorio de <code>open_model_zoo</code> podemos ver los enlaces de descarga directa: <a href="https://github.com/openvinotoolkit/open_model_zoo/blob/master/models/intel/noise-suppression-poconetlike-0001/model.yml" target="_blank" rel="noopener">https://github.com/openvinotoolkit/open_model_zoo/blob/master/models/intel/noise-suppression-poconetlike-0001/model.yml</a> y podemos obtener:</li> </ol> <ul> <li><code>noise-suppression-poconetlike-0001.bin</code></li> <li><code>noise-suppression-poconetlike-0001.xml</code></li> </ul> <p>Cualquiera de los dos modelos funciona.</p> <p>Luego tenemos que convertir el archivo de audio con ruido que queremos procesar a 16kHz:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ffmpeg -i noisy.flac -ar <span style="color:#d19a66">16000</span> noisy.wav </span></span></code></pre></div><p>Y obtenemos el archivo de ejemplo:</p> <p><a href="https://github.com/openvinotoolkit/open_model_zoo/blob/master/demos/noise_suppression_demo/python/noise_suppression_demo.py" target="_blank" rel="noopener">https://github.com/openvinotoolkit/open_model_zoo/blob/master/demos/noise_suppression_demo/python/noise_suppression_demo.py</a> </p> <p>Luego lo ejecutamos de la siguiente forma:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>python noise_suppression_demo.py <span style="color:#98c379">\ </span></span></span><span style="display:flex;"><span><span style="color:#98c379"></span>--model<span style="color:#56b6c2">=</span>models/noise-suppression-denseunet-ll-0001.xml <span style="color:#98c379">\ </span></span></span><span style="display:flex;"><span><span style="color:#98c379"></span>--input<span style="color:#56b6c2">=</span>noisy.wav <span style="color:#98c379">\ </span></span></span><span style="display:flex;"><span><span style="color:#98c379"></span>--output<span style="color:#56b6c2">=</span>cleaned.wav </span></span></code></pre></div><p>De esta forma podemos procesar el audio en macOS sin tener que esperar al plugin para Audacity.</p>Mixtral 8x7Bhttps://abeestrada.com/post/mixtral-8x7b/Thu, 14 Dec 2023 13:00:00 -0700https://abeestrada.com/post/mixtral-8x7b/<p>Siguiendo con mis experimentos con <a href="https://github.com/ml-explore/mlx/" target="_blank" rel="noopener">MLX</a> , me puse a intentar correr el nuevo modelo de Mistral: <a href="https://mistral.ai/news/mixtral-of-experts/" target="_blank" rel="noopener">Mixtral 8x7B</a> .</p> <p>Para esto, necesitamos los directorios donde vamos a trabajar:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>mkdir mixtral-8x7b </span></span><span style="display:flex;"><span><span style="color:#e5c07b">cd</span> mixtral-8x7b </span></span></code></pre></div><p>Descargamos el modelo de aproximadamente 86GB por medio de un torrent que fue <a href="https://twitter.com/MistralAI/status/1733150512395038967" target="_blank" rel="noopener">tuiteado</a> directamente de la cuenta de <a href="https://twitter.com/MistralAI/" target="_blank" rel="noopener">@MistralAI</a> . En mi caso utilizo <a href="https://aria2.github.io" target="_blank" rel="noopener">aria2</a> , pero cualquier cliente que acepte enlaces <code>magnet</code> va a funcionar. El modelo se va a encontrar dentro de <code>mixtral-8x7b-32kseqlen/</code>.</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>aria2c <span style="color:#98c379">&#39;magnet:?xt=urn:btih:5546272da9065eddeb6fcd7ffddeef5b75be79a7&amp;dn=mixtral-8x7b-32kseqlen&amp;tr=udp%3A%2F%http://2Fopentracker.i2p.rocks%3A6969%2Fannounce&amp;tr=http%3A%2F%http://2Ftracker.openbittorrent.com%3A80%2Fannounce&#39;</span> </span></span></code></pre></div><p>Instalamos las dependencias requeridas:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>pip install mlx sentencepiece torch numpy </span></span></code></pre></div><p>Del <a href="https://github.com/ml-explore/mlx-examples/tree/main/mixtral" target="_blank" rel="noopener">repositorio de ejemplos</a> , descargamos los siguientes archivos:</p> <ul> <li><a href="https://github.com/ml-explore/mlx-examples/blob/main/mixtral/convert.py" target="_blank" rel="noopener">convert.py</a> </li> <li><a href="https://github.com/ml-explore/mlx-examples/blob/main/mixtral/mixtral.py" target="_blank" rel="noopener">mixtral.py</a> </li> </ul> <p>Convertimos el modelo:</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>python convert.py --model_path mixtral-8x7b-32kseqlen/ </span></span></code></pre></div><p>Y ejecutamos:</p> <pre tabindex="0"><code>python mixtral.py --model_path mixtral-8x7b-32kseqlen/ </code></pre><p>Y si tenemos más de 100GB de RAM debe funcionar.</p> <p>Desgraciadamente me dí cuenta hasta que la ejecución el script de Python estaba siendo terminada por falta de RAM 😔.</p> <p>Después de mi intento fallido, y esperar dos días, Mozilla ha lanzado el modelo en formato de <code>llamafile</code>, que es un ejecutable multiplataforma, optmizado, y que para este modelo viene en dos versiones:</p> <ul> <li><code>mixtral-8x7b-instruct-v0.1.Q3</code></li> <li><code>mixtral-8x7b-instruct-v0.1.Q6</code></li> </ul> <p>Que a su vez tienen dos versiones cada uno, linea de comand o server.</p> <p>Para mis especificaciones, descargué <a href="https://huggingface.co/jartine/Mixtral-8x7B-v0.1.llamafile/tree/main" target="_blank" rel="noopener"><code>mixtral-8x7b-instruct-v0.1.Q3_K_M-server.llamafile</code></a> .</p> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>chmod +x mixtral-8x7b-instruct-v0.1.Q3_K_M-server.llamafile </span></span><span style="display:flex;"><span>./mixtral-8x7b-instruct-v0.1.Q3_K_M-server.llamafile </span></span></code></pre></div><p>Esta versión tan solo requiere 30GB de RAM para ejecutarse.</p> <figure > <img src="https://files.abeestrada.com/images/2023/12/mixtral-llamafile-ram.png" loading="lazy"> </figure>MLX + Whisperhttps://abeestrada.com/post/mlx--whisper/Wed, 13 Dec 2023 18:00:00 -0700https://abeestrada.com/post/mlx--whisper/<p>Llevo tiempo siguiendo el avance que tiene <a href="https://github.com/openai/whisper" target="_blank" rel="noopener">Whisper</a> para la transcripción de texto. Hasta ahora había sido muy lento, tomando aproximadamente el doble de tiempo del audio para trasncribir el texto, por lo cual hacía no factible su uso en una computadora personal, todos los demas ejemplos se ejecutaban en servidores con tarjeta gráficas más potentes.</p> <p>Hace unos días, Apple lanzó <a href="https://github.com/ml-explore/mlx" target="_blank" rel="noopener">MLX</a> , un framework que viene a más o menos reemplazar PyTorch para proyectos que tengan que ver con redes neurales, con la ventaja de que esta 100% optimizada para utilizar todos los recursos que ofrecen los procesadores M, en este caso el &ldquo;Neural Engine&rdquo; integrado. Entre los cuales se encuentra Whisper.</p> <p>En el repositorio existen <a href="https://github.com/ml-explore/mlx-examples/" target="_blank" rel="noopener">varios ejemplos</a> , utilizando el ejemplo de <a href="https://github.com/ml-explore/mlx-examples/tree/main/whisper" target="_blank" rel="noopener">mlx-examples/whisper</a> :</p> <h3 id="mainpy"><code>main.py</code></h3> <div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#c678dd">from</span> <span style="color:#e06c75">pprint</span> <span style="color:#c678dd">import</span> <span style="color:#e06c75">pprint</span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">from</span> <span style="color:#e06c75">whisper</span> <span style="color:#c678dd">import</span> <span style="color:#e06c75">transcribe</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#e06c75">MODEL</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">&#39;large-v3&#39;</span> <span style="color:#7f848e"># ~/.cache/whisper</span> </span></span><span style="display:flex;"><span><span style="color:#e06c75">AUDIO</span> <span style="color:#56b6c2">=</span> <span style="color:#98c379">&#39;./whisper/assets/&lt;AUDIO&gt;.wav&#39;</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">def</span> <span style="color:#61afef;font-weight:bold">main</span>(): </span></span><span style="display:flex;"><span> <span style="color:#e06c75">x</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">transcribe</span>(<span style="color:#e06c75">audio</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">AUDIO</span>, <span style="color:#e06c75">model</span><span style="color:#56b6c2">=</span><span style="color:#e06c75">MODEL</span>, <span style="color:#e06c75">verbose</span><span style="color:#56b6c2">=</span><span style="color:#e5c07b">False</span>) </span></span><span style="display:flex;"><span> <span style="color:#e06c75">pprint</span>(<span style="color:#e06c75">x</span>) </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#c678dd">if</span> <span style="color:#e06c75">__name__</span> <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#39;__main__&#39;</span>: </span></span><span style="display:flex;"><span> <span style="color:#e06c75">main</span>() </span></span></code></pre></div><figure class="w-full" > <img src="https://files.abeestrada.com/images/2023/12/mlx-whisper2.png" loading="lazy"> </figure> <p>Y utilizando al 100% el Neural Engine del procesador M, obtenemos las transcripciones en un 10% del tiempo de la duración del audio original.</p> <figure > <img src="https://files.abeestrada.com/images/2023/12/mlx-whisper.png" loading="lazy"> </figure> <p>Fuente:</p> <ul> <li><a href="https://github.com/ml-explore/mlx-examples/tree/main/whisper" target="_blank" rel="noopener">mlx-examples/whisper</a> </li> </ul>