<?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: Medcl</title>
    <description>The latest articles on DEV Community by Medcl (@medcl).</description>
    <link>https://dev.to/medcl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1130420%2F28ac58f8-801c-4fa5-adfc-4b057c9b399a.jpeg</url>
      <title>DEV Community: Medcl</title>
      <link>https://dev.to/medcl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/medcl"/>
    <language>en</language>
    <item>
      <title>Create Your Own AI Assistant, Coco AI v0.1.0 Released</title>
      <dc:creator>Medcl</dc:creator>
      <pubDate>Fri, 14 Feb 2025 09:12:03 +0000</pubDate>
      <link>https://dev.to/medcl/create-your-own-ai-assistant-coco-ai-v010-released-39id</link>
      <guid>https://dev.to/medcl/create-your-own-ai-assistant-coco-ai-v010-released-39id</guid>
      <description>&lt;h2&gt;
  
  
  Coco AI v0.1.0 Released
&lt;/h2&gt;

&lt;p&gt;We’re excited to announce the official release of Coco AI v0.1.0 – the first preview version of our powerful, open-source, cross-platform unified AI search and productivity tool!&lt;/p&gt;

&lt;p&gt;Coco AI allows you to seamlessly search through various data sources such as local applications, cloud storage (Google Drive, Notion, Youyan, Hugo), and enterprise knowledge bases. By leveraging advanced models like DeepSeek, Coco AI transforms personal knowledge management, enabling users to efficiently access information with enhanced privacy and security.&lt;/p&gt;

&lt;h2&gt;
  
  
  With Coco AI, users can:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Search multiple data sources in real-time, including both local and cloud data.&lt;/li&gt;
&lt;li&gt;Integrate AI-powered personal knowledge management for smarter information access.&lt;/li&gt;
&lt;li&gt;Chat with an AI assistant based on your personalized knowledge base, ensuring that information is always at your fingertips.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can now create your own personal AI Assistant with Coco AI now~&lt;/p&gt;

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

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

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

&lt;h2&gt;
  
  
  Key Features:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Unified Search &amp;amp; Productivity Tool: Connect and search across a wide range of data sources including desktop apps, cloud data, and internal knowledge bases.&lt;/li&gt;
&lt;li&gt;AI Assistant Mode: Chat with the AI assistant based on your knowledge base. The assistant understands your documents, personal data, and can offer intelligent summaries and responses.&lt;/li&gt;
&lt;li&gt;Privacy &amp;amp; Security: Coco AI allows for private deployment, ensuring your data stays secure, with all personal knowledge hosted locally or on your own server.&lt;/li&gt;
&lt;li&gt;Scalable &amp;amp; Open: Easily integrate your own data into Coco AI via APIs and extend functionality with custom data connectors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Download &amp;amp; Get Started
&lt;/h2&gt;

&lt;p&gt;Coco AI v0.1.0 is now available for MacOS 12 and above. You can start using it today by downloading from the following links:&lt;/p&gt;

&lt;p&gt;Download Coco AI: - &lt;a href="https://coco.rs/" rel="noopener noreferrer"&gt;https://coco.rs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coco AI App’s Github: &lt;a href="https://github.com/infinilabs/coco-app/" rel="noopener noreferrer"&gt;https://github.com/infinilabs/coco-app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coco AI Server’s Github: &lt;a href="https://github.com/infinilabs/coco-server" rel="noopener noreferrer"&gt;https://github.com/infinilabs/coco-server&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>search</category>
      <category>rag</category>
      <category>assistant</category>
    </item>
    <item>
      <title>Getting Started with INFINI Framework - Our homemade framework for building enterprise golang applications</title>
      <dc:creator>Medcl</dc:creator>
      <pubDate>Mon, 16 Dec 2024 10:25:46 +0000</pubDate>
      <link>https://dev.to/medcl/getting-started-with-infini-framework-our-homemade-framework-for-building-enterprise-golang-32mm</link>
      <guid>https://dev.to/medcl/getting-started-with-infini-framework-our-homemade-framework-for-building-enterprise-golang-32mm</guid>
      <description>&lt;p&gt;We recently open-sourced our homemade framework for building enterprise golang applications, called INFINI Framework.&lt;/p&gt;

&lt;p&gt;The github repo is &lt;a href="https://github.com/infinilabs/framework" rel="noopener noreferrer"&gt;https://github.com/infinilabs/framework&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I will show you how to get started with INFINI Framework.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create New Application
&lt;/h1&gt;

&lt;p&gt;Let's use the &lt;code&gt;NewAPP&lt;/code&gt; as the new project for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the project folder
&lt;/h2&gt;

&lt;p&gt;Use the name &lt;code&gt;new_app&lt;/code&gt; as the project id, and create the project folder as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/go/src/infini.sh/
&lt;span class="nb"&gt;mkdir &lt;/span&gt;new_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: Ensure that &lt;code&gt;new_app&lt;/code&gt; is located in the same directory as the &lt;code&gt;framework&lt;/code&gt; folder. This structure is required for the Makefile to function correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create the main file
&lt;/h2&gt;

&lt;p&gt;Create a empty &lt;code&gt;main.go&lt;/code&gt; file, and paste the code as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;package main

import &lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;"infini.sh/framework"&lt;/span&gt;
        &lt;span class="s2"&gt;"infini.sh/framework/core/module"&lt;/span&gt;
        &lt;span class="s2"&gt;"infini.sh/framework/core/util"&lt;/span&gt;
        &lt;span class="s2"&gt;"infini.sh/framework/modules/api"&lt;/span&gt;
        &lt;span class="s2"&gt;"infini.sh/new_app/config"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

func main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        terminalHeader :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"     __               _      ___  ___ &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;)&lt;/span&gt;
        terminalHeader +&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&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; &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;_____      __/_&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;/ _ &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;)&lt;/span&gt;
        terminalHeader +&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&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;/ / _ &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; /&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;  / /_)/ /_)/&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;)&lt;/span&gt;
        terminalHeader +&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&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;  /  __/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt; V  V /  _  &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;/ ___/ ___/ &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;)&lt;/span&gt;
        terminalHeader +&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&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;_&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;/ &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;_/&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;_/ &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;/   &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;/     &lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        terminalFooter :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Goodbye~"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        app :&lt;span class="o"&gt;=&lt;/span&gt; framework.NewApp&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"new_app"&lt;/span&gt;, &lt;span class="s2"&gt;"Make a golang application is such easy~."&lt;/span&gt;,
                util.TrimSpaces&lt;span class="o"&gt;(&lt;/span&gt;config.Version&lt;span class="o"&gt;)&lt;/span&gt;, util.TrimSpaces&lt;span class="o"&gt;(&lt;/span&gt;config.BuildNumber&lt;span class="o"&gt;)&lt;/span&gt;, util.TrimSpaces&lt;span class="o"&gt;(&lt;/span&gt;config.LastCommitLog&lt;span class="o"&gt;)&lt;/span&gt;, util.TrimSpaces&lt;span class="o"&gt;(&lt;/span&gt;config.BuildDate&lt;span class="o"&gt;)&lt;/span&gt;, util.TrimSpaces&lt;span class="o"&gt;(&lt;/span&gt;config.EOLDate&lt;span class="o"&gt;)&lt;/span&gt;, terminalHeader, terminalFooter&lt;span class="o"&gt;)&lt;/span&gt;
        app.IgnoreMainConfigMissing&lt;span class="o"&gt;()&lt;/span&gt;
        app.Init&lt;span class="o"&gt;(&lt;/span&gt;nil&lt;span class="o"&gt;)&lt;/span&gt;
        defer app.Shutdown&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;app.Setup&lt;span class="o"&gt;(&lt;/span&gt;func&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                module.RegisterSystemModule&lt;span class="o"&gt;(&lt;/span&gt;&amp;amp;api.APIModule&lt;span class="o"&gt;{})&lt;/span&gt;
                module.Start&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;, func&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;, nil&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                app.Run&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;We use this &lt;a href="http://patorjk.com/software/taag/#p=display&amp;amp;h=2&amp;amp;v=1&amp;amp;f=Ogre&amp;amp;t=NewAPP" rel="noopener noreferrer"&gt;online tool&lt;/a&gt; to generate a beauty ASCII based terminal header.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create the config file
&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;touch &lt;/span&gt;new_app.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the makefile
&lt;/h2&gt;

&lt;p&gt;create a empty &lt;code&gt;Makefile&lt;/code&gt;, and paste the code as below:&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="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/bash

&lt;span class="c"&gt;# APP info&lt;/span&gt;
APP_NAME :&lt;span class="o"&gt;=&lt;/span&gt; new_app
APP_VERSION :&lt;span class="o"&gt;=&lt;/span&gt; 1.0.0_SNAPSHOT
APP_CONFIG :&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;APP_NAME&lt;span class="si"&gt;)&lt;/span&gt;.yml
APP_EOLDate ?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2025-12-31T10:10:10Z"&lt;/span&gt;
APP_STATIC_FOLDER :&lt;span class="o"&gt;=&lt;/span&gt; .public
APP_STATIC_PACKAGE :&lt;span class="o"&gt;=&lt;/span&gt; public
APP_UI_FOLDER :&lt;span class="o"&gt;=&lt;/span&gt; ui
APP_PLUGIN_FOLDER :&lt;span class="o"&gt;=&lt;/span&gt; plugins
&lt;span class="nv"&gt;PREFER_MANAGED_VENDOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fase

include ../framework/Makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build the application
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  new_app &lt;span class="nv"&gt;OFFLINE_BUILD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true &lt;/span&gt;make build
building new_app 1.0.0_SNAPSHOT main
/Users/medcl/go/src/infini.sh/new_app
framework path:  /Users/medcl/go/src/infini.sh/framework
fatal: not a git repository &lt;span class="o"&gt;(&lt;/span&gt;or any of the parent directories&lt;span class="o"&gt;)&lt;/span&gt;: .git
update generated info
update configs
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../framework/  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make update-plugins&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="c"&gt;# build plugins in framework&lt;/span&gt;
&lt;span class="nv"&gt;GOPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/go:~/go/src/infini.sh/framework/../vendor/ &lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;GRPC_GO_REQUIRE_HANDSHAKE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;off  &lt;span class="nv"&gt;GO15VENDOREXPERIMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt; &lt;span class="nv"&gt;GO111MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;off go build &lt;span class="nt"&gt;-a&lt;/span&gt;  &lt;span class="nt"&gt;-gcflags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;all&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-l -B"&lt;/span&gt;  &lt;span class="nt"&gt;-ldflags&lt;/span&gt; &lt;span class="s1"&gt;'-static'&lt;/span&gt; &lt;span class="nt"&gt;-ldflags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'-s -w'&lt;/span&gt; &lt;span class="nt"&gt;-gcflags&lt;/span&gt; &lt;span class="s2"&gt;"-m"&lt;/span&gt;  &lt;span class="nt"&gt;--work&lt;/span&gt;  &lt;span class="nt"&gt;-o&lt;/span&gt; /Users/medcl/go/src/infini.sh/new_app/bin/new_app
&lt;span class="nv"&gt;WORK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/folders/j5/qd4qt3n55dz053d93q2mswfr0000gn/T/go-build435280758
&lt;span class="c"&gt;# infini.sh/new_app&lt;/span&gt;
./main.go:17:9: can inline main.deferwrap1
./main.go:21:12: can inline main.func2
./main.go:18:22: func literal does not escape
./main.go:19:45: &amp;amp;api.APIModule&lt;span class="o"&gt;{}&lt;/span&gt; escapes to heap
./main.go:21:12: func literal escapes to heap
restore generated info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the application
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  new_app git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; ✗ ./bin/new_app
     __               _      ___  ___
  /&lt;span class="se"&gt;\ \ \_&lt;/span&gt;____      __/_&lt;span class="se"&gt;\ &lt;/span&gt;   / _ &lt;span class="se"&gt;\/&lt;/span&gt; _ &lt;span class="se"&gt;\&lt;/span&gt;
 /  &lt;span class="se"&gt;\/&lt;/span&gt; / _ &lt;span class="se"&gt;\ \ &lt;/span&gt;/&lt;span class="se"&gt;\ &lt;/span&gt;/ //_&lt;span class="se"&gt;\\&lt;/span&gt;  / /_&lt;span class="o"&gt;)&lt;/span&gt;/ /_&lt;span class="o"&gt;)&lt;/span&gt;/
/ /&lt;span class="se"&gt;\ &lt;/span&gt; /  __/&lt;span class="se"&gt;\ &lt;/span&gt;V  V /  _  &lt;span class="se"&gt;\/&lt;/span&gt; ___/ ___/
&lt;span class="se"&gt;\_\ \/&lt;/span&gt; &lt;span class="se"&gt;\_&lt;/span&gt;__| &lt;span class="se"&gt;\_&lt;/span&gt;/&lt;span class="se"&gt;\_&lt;/span&gt;/&lt;span class="se"&gt;\_&lt;/span&gt;/ &lt;span class="se"&gt;\_&lt;/span&gt;/&lt;span class="se"&gt;\/&lt;/span&gt;   &lt;span class="se"&gt;\/&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;NEW_APP] Make a golang application is such easy~.
&lt;span class="o"&gt;[&lt;/span&gt;NEW_APP] 1.0.0_SNAPSHOT#001, 2024-12-16 06:15:10, 2025-12-31 10:10:10, HEAD
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;env.go:203] configuration auto reload enabled
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;env.go:209] watching config: /Users/medcl/go/src/infini.sh/new_app/config
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;app.go:311] initializing new_app, pid: 64426
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;app.go:312] using config: /Users/medcl/go/src/infini.sh/new_app/new_app.yml
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;api.go:214] &lt;span class="nb"&gt;local &lt;/span&gt;ips: 192.168.3.17
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;api.go:312] api server listen at: http://0.0.0.0:2900
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;module.go:159] started module: api
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;module.go:184] all modules are started
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;instance.go:101] workspace: /Users/medcl/go/src/infini.sh/new_app/data/new_app/nodes/ctfs8hbq50kevmkb3m6g
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:19] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;app.go:537] new_app is up and running now.
^C
&lt;span class="o"&gt;[&lt;/span&gt;NEW_APP] got signal: interrupt, start shutting down
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:23] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;module.go:213] all modules are stopped
&lt;span class="o"&gt;[&lt;/span&gt;12-16 14:15:23] &lt;span class="o"&gt;[&lt;/span&gt;INF] &lt;span class="o"&gt;[&lt;/span&gt;app.go:410] new_app now terminated.
&lt;span class="o"&gt;[&lt;/span&gt;NEW_APP] 1.0.0_SNAPSHOT, &lt;span class="nb"&gt;uptime&lt;/span&gt;: 4.13334s

Goodbye~
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The demo code can be found &lt;a href="https://github.com/infinilabs/new-app-example" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By leveraging the INFINI Framework, creating a Go application becomes significantly simpler and more efficient.&lt;br&gt;
The framework provides built-in commands and modules, streamlining the development process and enabling you to focus on building your application's core functionality.&lt;/p&gt;

&lt;p&gt;Follow us AT: &lt;a href="https://github.com/infinilabs" rel="noopener noreferrer"&gt;https://github.com/infinilabs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>go</category>
      <category>application</category>
    </item>
    <item>
      <title>How We Do Documentation Engineering</title>
      <dc:creator>Medcl</dc:creator>
      <pubDate>Mon, 16 Dec 2024 10:22:32 +0000</pubDate>
      <link>https://dev.to/medcl/how-we-do-documentation-engineering-27oc</link>
      <guid>https://dev.to/medcl/how-we-do-documentation-engineering-27oc</guid>
      <description>&lt;p&gt;At INFINI Labs, we see product documentation as an integral part of the product development process. Effective documentation ensures that users understand, adopt, and get the most out of our offerings.&lt;/p&gt;

&lt;p&gt;Take a look at our documentation site: &lt;a href="https://docs.infinilabs.com/" rel="noopener noreferrer"&gt;https://docs.infinilabs.com/&lt;/a&gt;. It hosts detailed documentation for each of our products.&lt;/p&gt;

&lt;p&gt;For each product, you can even switch between different versions effortlessly, like this:&lt;/p&gt;

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

&lt;p&gt;Managing comprehensive documentation might seem like an enormous task, especially since we don’t have a dedicated documentation team. However, with limited resources and many competing priorities, we’ve streamlined a practical and efficient approach to product documentation engineering.&lt;/p&gt;

&lt;p&gt;So, how do we do it?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tools We Use
&lt;/h2&gt;

&lt;p&gt;Our documentation workflow relies on the following tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;GitHub Pages&lt;/a&gt;&lt;/strong&gt;: For hosting our documentation website.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt;: To automate builds and deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://gohugo.io/" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt;&lt;/strong&gt;: A fast and flexible static site generator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.markdownguide.org/" rel="noopener noreferrer"&gt;Markdown&lt;/a&gt;&lt;/strong&gt;: To write clean and easily maintainable documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We love GitHub's ecosystem for its reliability and developer-friendly features. Using GitHub Pages, we can host our documentation effortlessly. Once our documentation is compiled into static files using Hugo, it’s lightweight, fast, and easy to serve to users.&lt;/p&gt;

&lt;p&gt;To enhance the user experience further, we integrate &lt;strong&gt;offline search functionality&lt;/strong&gt; powered by our own &lt;a href="https://github.com/infinilabs/pizza-searchbox/" rel="noopener noreferrer"&gt;pizza-searchbox&lt;/a&gt;. This ensures users can quickly find what they need, even without an internet connection.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It All Works Together
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Organizing Components Across Repositories
&lt;/h3&gt;

&lt;p&gt;We maintain separate repositories for each part of the documentation workflow. The final compiled version of all product documentation lives here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compiled docs: &lt;a href="https://github.com/infinilabs/docs" rel="noopener noreferrer"&gt;https://github.com/infinilabs/docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hugo theme for docs: &lt;a href="https://github.com/infinilabs/docs-theme" rel="noopener noreferrer"&gt;https://github.com/infinilabs/docs-theme&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Product with docs: &lt;a href="https://github.com/infinilabs/gateway" rel="noopener noreferrer"&gt;https://github.com/infinilabs/gateway&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By separating concerns, we make it easier to manage updates, streamline collaboration, and keep everything organized.&lt;/p&gt;

&lt;p&gt;As you can see the layout of compiled folder is looks like this:&lt;/p&gt;

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

&lt;p&gt;Each products have folder for each different version, and the &lt;code&gt;main&lt;/code&gt; is alwasy point to the latest version.&lt;/p&gt;

&lt;h3&gt;
  
  
  And how did these static docs coming from?
&lt;/h3&gt;

&lt;p&gt;Checkout this specify &lt;a href="https://github.com/infinilabs/gateway/tree/main/docs" rel="noopener noreferrer"&gt;product's&lt;/a&gt; repo for example:&lt;/p&gt;

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

&lt;p&gt;As you can see, in the product’s repository, there’s a folder named &lt;code&gt;docs&lt;/code&gt;, which contains all the documentation specific to that product.&lt;/p&gt;

&lt;p&gt;Alongside it, there’s a &lt;code&gt;config.yaml&lt;/code&gt; defines the basic configuration for the product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# VERSIONS=latest,v1.0 hugo    --minify --baseURL="/product/v1.0/"  -d public/product/v1.0&lt;/span&gt;

&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INFINI Gateway&lt;/span&gt;
&lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;book&lt;/span&gt;

&lt;span class="c1"&gt;# Book configuration&lt;/span&gt;
&lt;span class="na"&gt;disablePathToLower&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;enableGitInfo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="c1"&gt;# Needed for mermaid/katex shortcodes&lt;/span&gt;
&lt;span class="na"&gt;markup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;goldmark&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;renderer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;unsafe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;tableOfContents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;startLevel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="c1"&gt;# Multi-lingual mode config&lt;/span&gt;
&lt;span class="c1"&gt;# There are different options to translate files&lt;/span&gt;
&lt;span class="c1"&gt;# See https://gohugo.io/content-management/multilingual/#translation-by-filename&lt;/span&gt;
&lt;span class="c1"&gt;# And https://gohugo.io/content-management/multilingual/#translation-by-content-directory&lt;/span&gt;
&lt;span class="na"&gt;defaultContentLanguage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;en&lt;/span&gt;
&lt;span class="na"&gt;languages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;languageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;English&lt;/span&gt;
    &lt;span class="na"&gt;contentDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;content.en&lt;/span&gt;
    &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;


&lt;span class="na"&gt;menu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Github"&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://github.com/infinilabs/gateway"&lt;/span&gt;
      &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="s"&gt;EMITTED&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you changed the right github's repo address and the product name.&lt;/p&gt;

&lt;p&gt;And also there’s a &lt;code&gt;Makefile&lt;/code&gt; that defines how we build the docs:&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="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/bash

&lt;span class="c"&gt;# Basic info&lt;/span&gt;
PRODUCT?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;shell &lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;shell &lt;span class="nb"&gt;cd&lt;/span&gt; .. &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
BRANCH?&lt;span class="o"&gt;=&lt;/span&gt; main
VERSION?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;shell &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;BRANCH&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;BRANCH&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
CURRENT_VERSION?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;VERSION&lt;span class="si"&gt;)&lt;/span&gt;
VERSIONS?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt;
OUTPUT?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/tmp/docs"&lt;/span&gt;
THEME_FOLDER?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"themes/book"&lt;/span&gt;
THEME_REPO?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://github.com/infinilabs/docs-theme.git"&lt;/span&gt;
THEME_BRANCH?&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt;

.PHONY: docs-build

default: docs-build

docs-init:
    @if &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;THEME_FOLDER&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"theme does not exist"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;git clone &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;THEME_BRANCH&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;THEME_REPO&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;THEME_FOLDER&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;fi

&lt;/span&gt;docs-env:
    @echo &lt;span class="s2"&gt;"Debugging Variables:"&lt;/span&gt;
    @echo &lt;span class="s2"&gt;"PRODUCT: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;PRODUCT&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    @echo &lt;span class="s2"&gt;"BRANCH: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;BRANCH&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    @echo &lt;span class="s2"&gt;"VERSION: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;VERSION&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    @echo &lt;span class="s2"&gt;"CURRENT_VERSION: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;CURRENT_VERSION&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    @echo &lt;span class="s2"&gt;"VERSIONS: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;VERSIONS&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    @echo &lt;span class="s2"&gt;"OUTPUT: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;OUTPUT&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

docs-config: docs-init
    &lt;span class="nb"&gt;cp &lt;/span&gt;config.yaml config.bak
    &lt;span class="c"&gt;# Detect OS and apply the appropriate sed command&lt;/span&gt;
    @if &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;(uname)"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Darwin"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running on macOS"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s2"&gt;"s/BRANCH/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;VERSION&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/g"&lt;/span&gt; config.yaml&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running on Linux"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/BRANCH/$(VERSION)/g'&lt;/span&gt; config.yaml&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="k"&gt;fi

&lt;/span&gt;docs-build: docs-config
    hugo &lt;span class="nt"&gt;--minify&lt;/span&gt; &lt;span class="nt"&gt;--theme&lt;/span&gt; book &lt;span class="nt"&gt;--destination&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;OUTPUT&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;PRODUCT&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;VERSION&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--baseURL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;PRODUCT&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;VERSION&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    @&lt;span class="si"&gt;$(&lt;/span&gt;MAKE&lt;span class="si"&gt;)&lt;/span&gt; docs-restore-generated-file

docs-place-redirect:
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;!DOCTYPE html&amp;gt; &amp;lt;html&amp;gt; &amp;lt;head&amp;gt; &amp;lt;meta http-equiv=refresh content=0;url=main /&amp;gt; &amp;lt;/head&amp;gt; &amp;lt;body&amp;gt; &amp;lt;p&amp;gt;&amp;lt;a href=main /&amp;gt;REDIRECT TO THE LATEST_VERSION&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt; &amp;lt;/body&amp;gt; &amp;lt;/html&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;OUTPUT&lt;span class="si"&gt;)&lt;/span&gt;/&lt;span class="si"&gt;$(&lt;/span&gt;PRODUCT&lt;span class="si"&gt;)&lt;/span&gt;/index.html

docs-restore-generated-file:
    &lt;span class="nb"&gt;mv &lt;/span&gt;config.bak config.yaml

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

&lt;/div&gt;



&lt;p&gt;Usually, there’s no need to make any changes—simply copy these files to your new product, and everything will work seamlessly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Automation Makes Everything Easier
&lt;/h2&gt;

&lt;p&gt;And we use &lt;code&gt;.github/workflows/build-docs.yml&lt;/code&gt; to define how to build the documentation once someone pushed the code, or someone released a new version, take a look at the github actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Deploy Docs&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;v*'&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;v*'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-deploy-docs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout Product Repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set Variables Based on Ref&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vars&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;PRODUCT_NAME=$(basename $(pwd))  # Get the directory name as the product name&lt;/span&gt;
          &lt;span class="s"&gt;echo "PRODUCT_NAME=$PRODUCT_NAME" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
          &lt;span class="s"&gt;CURRENT_REF=${GITHUB_REF##*/}&lt;/span&gt;
          &lt;span class="s"&gt;IS_SEMVER=false&lt;/span&gt;
          &lt;span class="s"&gt;SEMVER_REGEX="^v([0-9]+)\.([0-9]+)\.([0-9]+)$"&lt;/span&gt;

          &lt;span class="s"&gt;if [[ "${GITHUB_REF_TYPE}" == "branch" ]]; then&lt;/span&gt;
            &lt;span class="s"&gt;if [[ "$CURRENT_REF" == "main" ]]; then&lt;/span&gt;
              &lt;span class="s"&gt;echo "VERSION=main" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
              &lt;span class="s"&gt;echo "BRANCH=main" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
            &lt;span class="s"&gt;elif [[ "$CURRENT_REF" =~ $SEMVER_REGEX ]]; then&lt;/span&gt;
              &lt;span class="s"&gt;IS_SEMVER=true&lt;/span&gt;
              &lt;span class="s"&gt;echo "VERSION=$CURRENT_REF" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
              &lt;span class="s"&gt;echo "BRANCH=$CURRENT_REF" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
            &lt;span class="s"&gt;else&lt;/span&gt;
              &lt;span class="s"&gt;echo "Branch '$CURRENT_REF' is not a valid semantic version. Skipping build."&lt;/span&gt;
              &lt;span class="s"&gt;exit 0&lt;/span&gt;
            &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="s"&gt;elif [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then&lt;/span&gt;
            &lt;span class="s"&gt;if [[ "$CURRENT_REF" =~ $SEMVER_REGEX ]]; then&lt;/span&gt;
              &lt;span class="s"&gt;IS_SEMVER=true&lt;/span&gt;
              &lt;span class="s"&gt;echo "VERSION=$CURRENT_REF" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
              &lt;span class="s"&gt;echo "BRANCH=main" &amp;gt;&amp;gt; $GITHUB_ENV  # Set BRANCH to 'main' for tags&lt;/span&gt;
            &lt;span class="s"&gt;else&lt;/span&gt;
              &lt;span class="s"&gt;echo "Tag '$CURRENT_REF' is not a valid semantic version. Skipping build."&lt;/span&gt;
              &lt;span class="s"&gt;exit 0&lt;/span&gt;
            &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;

          &lt;span class="s"&gt;# Gather branches and tags, filter for semantic versions, sort, remove duplicates&lt;/span&gt;
          &lt;span class="s"&gt;VERSIONS=$(git for-each-ref refs/remotes/origin refs/tags --format="%(refname:short)" | \&lt;/span&gt;
            &lt;span class="s"&gt;grep -E "^v[0-9]+\.[0-9]+\.[0-9]+$" | sort -Vr | uniq | tr '\n' ',' | sed 's/,$//')&lt;/span&gt;
          &lt;span class="s"&gt;echo "VERSIONS=main,$VERSIONS" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Hugo&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;wget https://github.com/gohugoio/hugo/releases/download/v0.79.1/hugo_extended_0.79.1_Linux-64bit.tar.gz&lt;/span&gt;
          &lt;span class="s"&gt;tar -xzvf hugo_extended_0.79.1_Linux-64bit.tar.gz&lt;/span&gt;
          &lt;span class="s"&gt;sudo mv hugo /usr/local/bin/&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout Docs Repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;infinilabs/docs&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docs-output&lt;/span&gt;
          &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DOCS_DEPLOYMENT_TOKEN }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Documentation&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;(cd docs &amp;amp;&amp;amp; OUTPUT=$(pwd)/../docs-output make docs-build docs-place-redirect)&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit and Push Changes to Docs Repo&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docs-output&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;git config user.name "GitHub Actions"&lt;/span&gt;
          &lt;span class="s"&gt;git config user.email "actions@github.com"&lt;/span&gt;

          &lt;span class="s"&gt;if [[ -n $(git status --porcelain) ]]; then&lt;/span&gt;
            &lt;span class="s"&gt;git add .&lt;/span&gt;
            &lt;span class="s"&gt;git commit -m "Rebuild $PRODUCT_NAME docs for version $VERSION"&lt;/span&gt;
            &lt;span class="s"&gt;git push origin main&lt;/span&gt;
          &lt;span class="s"&gt;else&lt;/span&gt;
            &lt;span class="s"&gt;echo "No changes to commit."&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Rebuild Docs for Latest Version (main), if not already on main&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;# Only rebuild the main branch docs if the current ref is not "main"&lt;/span&gt;
          &lt;span class="s"&gt;if [[ "$CURRENT_REF" != "main" ]]; then&lt;/span&gt;
            &lt;span class="s"&gt;echo "Switching to main branch and rebuilding docs for 'latest'"&lt;/span&gt;

            &lt;span class="s"&gt;# Checkout the main branch of the product repo to rebuild docs for "latest"&lt;/span&gt;
            &lt;span class="s"&gt;git checkout main&lt;/span&gt;

            &lt;span class="s"&gt;# Ensure the latest changes are pulled&lt;/span&gt;
            &lt;span class="s"&gt;git pull origin main&lt;/span&gt;

            &lt;span class="s"&gt;# Build Docs for Main Branch (latest)&lt;/span&gt;
            &lt;span class="s"&gt;(cd docs &amp;amp;&amp;amp; OUTPUT=$(pwd)/../docs-output VERSION="main" BRANCH="main" make docs-build docs-place-redirect)&lt;/span&gt;

            &lt;span class="s"&gt;# Commit and Push Latest Docs to Main&lt;/span&gt;
            &lt;span class="s"&gt;cd docs-output&lt;/span&gt;
            &lt;span class="s"&gt;git config user.name "GitHub Actions"&lt;/span&gt;
            &lt;span class="s"&gt;git config user.email "actions@github.com"&lt;/span&gt;

            &lt;span class="s"&gt;if [[ -n $(git status --porcelain) ]]; then&lt;/span&gt;
              &lt;span class="s"&gt;git add .&lt;/span&gt;
              &lt;span class="s"&gt;git commit -m "Rebuild $PRODUCT_NAME docs for main branch with latest version"&lt;/span&gt;
              &lt;span class="s"&gt;git push origin main&lt;/span&gt;
            &lt;span class="s"&gt;else&lt;/span&gt;
              &lt;span class="s"&gt;echo "No changes to commit for main."&lt;/span&gt;
            &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="s"&gt;else&lt;/span&gt;
            &lt;span class="s"&gt;echo "Current ref is 'main', skipping rebuild for 'latest'."&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;  &lt;span class="c1"&gt;# Working in the product repo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look closely at the GitHub Actions workflow, it simplifies the entire process by automating key tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitor Branches and Tags: Watches for branches or tags starting with v and validates them as semantic versioned branches or tags. Only valid versions trigger the documentation build process.&lt;/li&gt;
&lt;li&gt;Fetch Theme: Pulls the documentation theme from a separate repository to ensure a consistent look and feel across all products.&lt;/li&gt;
&lt;li&gt;Build and Deploy: Compiles the documentation into static files using Hugo, commits the changes with a clear and informative message, and pushes the updates to the docs repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Through GitHub Actions, the entire workflow becomes seamless:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile: Converts Markdown files into a polished static site using Hugo.&lt;/li&gt;
&lt;li&gt;Deploy: Publishes the site effortlessly to GitHub Pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This automation reduces manual effort, ensures consistency across documentation, and allows us to focus on delivering quality content to users.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Approach Works for Us
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt;: With automation, we can focus on content rather than operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: As our product offerings grow, this workflow scales effortlessly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Experience&lt;/strong&gt;: A fast, searchable, and offline-ready documentation site means better support for our users.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;Product documentation isn’t just a necessity—it’s a competitive advantage. By leveraging the right tools and automating where possible, we’ve built a process that delivers high-quality documentation without needing a dedicated team.&lt;/p&gt;

&lt;p&gt;Want to see it in action? Visit our documentation site here: &lt;a href="https://docs.infinilabs.com/" rel="noopener noreferrer"&gt;https://docs.infinilabs.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let us know what you think! Your feedback helps us improve not only our products but also the way we document and share them with the world.&lt;/p&gt;

&lt;p&gt;Follow us AT: &lt;a href="https://github.com/infinilabs" rel="noopener noreferrer"&gt;https://github.com/infinilabs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>engineering</category>
    </item>
    <item>
      <title>Introducing Coco AI in two minutes - an open-source alternative to Glean</title>
      <dc:creator>Medcl</dc:creator>
      <pubDate>Tue, 26 Nov 2024 16:21:21 +0000</pubDate>
      <link>https://dev.to/medcl/introducing-coco-ai-in-two-minutes-2ejp</link>
      <guid>https://dev.to/medcl/introducing-coco-ai-in-two-minutes-2ejp</guid>
      <description>&lt;p&gt;Introducing Coco AI in two minutes. Coco AI unifies all your enterprise applications and data—Google Workspace, Dropbox, GitHub, and more—into one powerful search and Gen-AI chat platform. Instantly access and interact with your team’s unique knowledges. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://coco.rs" rel="noopener noreferrer"&gt;http://coco.rs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/infinilabs/coco-app/" rel="noopener noreferrer"&gt;https://github.com/infinilabs/coco-app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1861590090985939294-771" src="https://platform.twitter.com/embed/Tweet.html?id=1861590090985939294"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1861590090985939294-771');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1861590090985939294&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/medcl/status/1861590090985939294" rel="noopener noreferrer"&gt;https://x.com/medcl/status/1861590090985939294&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>search</category>
      <category>opensource</category>
      <category>rust</category>
    </item>
    <item>
      <title>Benchmarking and Profiling Rust Applications on macOS: A Practical Guide</title>
      <dc:creator>Medcl</dc:creator>
      <pubDate>Mon, 23 Sep 2024 10:47:26 +0000</pubDate>
      <link>https://dev.to/medcl/benchmarking-and-profiling-rust-applications-on-macos-a-practical-guide-13pi</link>
      <guid>https://dev.to/medcl/benchmarking-and-profiling-rust-applications-on-macos-a-practical-guide-13pi</guid>
      <description>&lt;p&gt;Profiling Rust code has become part of my daily routine. As I primarily develop on macOS, I've noticed there aren't many tools that allow for easy and quick profiling of Rust applications. So, I’d like to share my daily profiling workflow, in case it helps others. If you have other approaches or tools that work well for you, feel free to share—I’d love to hear them!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Setting Up Micro-Benchmarks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use micro-benchmark tests to track the performance of critical functions in my Rust application. For this, I rely on &lt;code&gt;criterion&lt;/code&gt;, which is both powerful and easy to use. Here’s what my project setup looks like:&lt;/p&gt;

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

&lt;p&gt;As you noticed, i organized my benchmark tests per module, and so i can easily include or exclude specify tests in the &lt;code&gt;benches.rs&lt;/code&gt;, some times, they just take too much time, if i only want to profile specify tests, i can just comment out unrelated one. dirty but works.&lt;/p&gt;

&lt;p&gt;If you have many similar tests, you may group them by use a customized name, like this:&lt;/p&gt;

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

&lt;p&gt;Micro-benchmarking is a fundamental step that helps track performance changes when refactoring code or adding new features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Profiling The Micro-Benchmark&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if some tests are slow, a quick way to profiling is to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --bench benches   -o find-baseline.svg -- --bench
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run the benchmarks with a single command, but be sure to comment out any unrelated tests in &lt;code&gt;benches.rs&lt;/code&gt;. Just remember to revert those changes or avoid checking them in later. that's tedious, yes, i know :(&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Tracking Performance with Bencher&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that you have several micro-benchmark tests, how can you continuously monitor performance? I’m glad I discovered a free service provided by bencher.dev. It helps track performance over time, making it easier to identify any regressions or improvements.&lt;/p&gt;

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

&lt;p&gt;Here is my bencher command in my Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bencher-engine:
    if [ -z "${BENCHER_API_TOKEN:-}" ]; then \
        echo "Error: BENCHER_API_TOKEN environment variable is not set."; \
        exit 1; \
    fi

    bencher run \
        --project pizza-engine-bd8p44nc \
        --branch main \
        --testbed localhost \
        --adapter rust_criterion \
        "cd lib/engine &amp;amp;&amp;amp; cargo bench"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each time you run &lt;code&gt;make bencher-engine&lt;/code&gt;, it executes all your benchmarks and sends the results to their database. This service is free to use for open-source projects, making it a great resource for ongoing performance tracking.&lt;/p&gt;

&lt;p&gt;For example here is my &lt;a href="https://bencher.dev/console/projects/pizza-engine-bd8p44nc/plots" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt;:&lt;/p&gt;

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

&lt;p&gt;You can add a CI action to your GitHub repository to automatically track performance changes with each commit. If your code is hosted on GitHub, this setup will record performance variations for every commit, helping you maintain a history of your application's performance over time.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt; Profiling on MacOs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Profiling on macOS can be slightly less convenient than on Linux, where there are many robust tools available. Here’s what I do to make the most of the profiling process, I use &lt;code&gt;Dtrace&lt;/code&gt; along with two scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜ cat ~/start_profile.sh 
#!/bin/bash

# Check if PID argument is provided
if [ -z "$1" ]; then
  echo "Usage: $0 &amp;lt;pid&amp;gt;"
  exit 1
fi

pid=$1

# Run dtrace with the provided PID
sudo rm -rf target/out.user_stacks || true

sudo dtrace -x ustackframes=100 -n "profile-97 /pid == $pid/ { @[ustack()] = count(); } tick-60s { exit(0); }" -o target/out.user_stacks

➜ cat ~/end_profile.sh 
#!/bin/bash

# Clean up previous output files
rm -f target/stacks.folded target/flamegraph.svg

# Process the new profiling data
cat target/out.user_stacks | inferno-collapse-dtrace &amp;gt; target/stacks.folded
cat target/stacks.folded | inferno-flamegraph &amp;gt; target/flamegraph.svg

# Notify the user
echo "Flamegraph generated at target/flamegraph.svg"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then start your target Rust application, make sure you set &lt;code&gt;debug=true&lt;/code&gt; in &lt;code&gt;Cargo.toml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And then execute the start script, wait for a while and Ctrl+C to capture profiling data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  indexer git:(batch_indexing) ✗ ~/start_profile.sh 1494                                                      
dtrace: system integrity protection is on, some features will not be available

dtrace: description 'profile-97 ' matched 2 probes
^C%                                                                                                                                                                                                                                                                                      
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you can generate the flamegraph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  indexer git:(batch_indexing) ✗ ~/end_profile.sh 
Flamegraph generated at target/flamegraph.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open it with your web browser and figure out what's the bottlenect, and rock with it.&lt;/p&gt;

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

&lt;p&gt;That’s it! I hope this information helps you in your Rust development journey. If you have any questions or need further assistance, feel free to reach out!&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bheisler/criterion.rs" rel="noopener noreferrer"&gt;https://github.com/bheisler/criterion.rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bencher.dev/" rel="noopener noreferrer"&gt;https://bencher.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bencher.dev/console/projects/pizza-engine-bd8p44nc/plots" rel="noopener noreferrer"&gt;https://bencher.dev/console/projects/pizza-engine-bd8p44nc/plots&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow us AT: &lt;a href="https://github.com/infinilabs" rel="noopener noreferrer"&gt;https://github.com/infinilabs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>benchmark</category>
      <category>profiling</category>
      <category>macos</category>
    </item>
    <item>
      <title>Adding Search Functionality to a Hugo Static Site Based on INFINI Pizza for WebAssembly</title>
      <dc:creator>Medcl</dc:creator>
      <pubDate>Wed, 28 Aug 2024 13:21:42 +0000</pubDate>
      <link>https://dev.to/medcl/adding-search-functionality-to-a-hugo-static-site-based-on-infini-pizza-for-webassembly-4h5e</link>
      <guid>https://dev.to/medcl/adding-search-functionality-to-a-hugo-static-site-based-on-infini-pizza-for-webassembly-4h5e</guid>
      <description>&lt;p&gt;INFINI Pizza is an upcoming search engine developed by INFINI Labs, written in Rust (soon to be fully open-sourced). The basic search capabilities have already been completed, and based on the core engine of INFINI Pizza, a WASM version of the ultra-lightweight kernel is provided. This can be easily embedded into various application systems, such as websites, especially static sites or small blog systems.&lt;/p&gt;

&lt;p&gt;Currently, The website of INFINI Pizza have integrated INFINI Pizza for WebAssembly. The specific search results are shown in the image below:&lt;/p&gt;

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

&lt;p&gt;Visit the website (&lt;a href="http://pizza.rs" rel="noopener noreferrer"&gt;http://pizza.rs&lt;/a&gt;), and by pressing the shortcut key 's', you can bring up the search box and experience the search capabilities provided by INFINI Pizza. Notably, during the search process, all of your actions are executed locally in the browser. Unlike traditional search implementations, where each query requires an interaction with a backend search server, INFINI Pizza for WebAssembly operates entirely offline. Even if you're disconnected from the internet, you can still enjoy a seamless search experience.&lt;/p&gt;

&lt;p&gt;Without further ado, let's dive into how you can use INFINI Pizza for WebAssembly on your own site.&lt;/p&gt;

&lt;p&gt;First, INFINI Pizza for WebAssembly is open source. You can find the GitHub repository here: &lt;a href="https://github.com/infinilabs/pizza-wasm" rel="noopener noreferrer"&gt;https://github.com/infinilabs/pizza-wasm&lt;/a&gt;. The compiled WASM package is available for direct download here: &lt;a href="https://github.com/infinilabs/pizza-wasm/tree/main/pkg" rel="noopener noreferrer"&gt;https://github.com/infinilabs/pizza-wasm/tree/main/pkg&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  wasm git:(main) ✗ du -sh pkg/*
4.0K    pkg/README.md
4.0K    pkg/package.json
4.0K    pkg/pizza_wasm.d.ts
4.0K    pkg/pizza_wasm.js
 12K    pkg/pizza_wasm_bg.js
580K    pkg/pizza_wasm_bg.wasm
4.0K    pkg/pizza_wasm_bg.wasm.d.ts
256K    pkg/pizza_wasm_bg.wasm.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice that the WASM package is just over 500 KB, and after Gzip compression, it’s reduced to just over 200 KB, making it quite lightweight. You may have thinking there are some JavaScript based static search solution maybe more smaller, but please note they are not full featured search engine, and I will explain this when INFINI Pizza officially reveal sometime later.&lt;/p&gt;

&lt;p&gt;Pizza-WASM is a WebAssembly interface wrapper for the core engine of INFINI Pizza, exposing only a few simple access interfaces. These are sufficient for current frontend search applications. You can find a very basic example of how to call the WASM methods in the following directory: &lt;a href="https://github.com/infinilabs/pizza-wasm/tree/main/web" rel="noopener noreferrer"&gt;https://github.com/infinilabs/pizza-wasm/tree/main/web&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, just having the Pizza WASM isn't enough. If we want to add a search box to an existing static site, we also need to consider where the data comes from and how the results are displayed. To address this, we've wrapped up a project called Pizza-DocSearch, which further simplifies usage. This project is also open source, and you can find it on GitHub here: &lt;a href="https://github.com/infinilabs/pizza-docsearch" rel="noopener noreferrer"&gt;https://github.com/infinilabs/pizza-docsearch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since the example project has already uploaded the compiled code and samples, we can directly download the source code and preview the functionality locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  /tmp git clone https://github.com/infinilabs/pizza-docsearch.git
Cloning into 'pizza-docsearch'...
remote: Enumerating objects: 174, done.
remote: Counting objects: 100% (174/174), done.
remote: Compressing objects: 100% (112/112), done.
remote: Total 174 (delta 86), reused 147 (delta 59), pack-reused 0 (from 0)
Receiving objects: 100% (174/174), 941.94 KiB | 1.20 MiB/s, done.
Resolving deltas: 100% (86/86), done.
➜  /tmp cd pizza-docsearch/example/dist 
➜  dist git:(main) python3 -m http.server 8083    

Serving HTTP on :: port 8083 (http://[::]:8083/) ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser and visit: &lt;a href="http://localhost:8083" rel="noopener noreferrer"&gt;http://localhost:8083&lt;/a&gt;, as shown below:&lt;/p&gt;

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

&lt;p&gt;Observe the network requests in the browser, and you'll see that it loads the sample index.json data:&lt;/p&gt;

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

&lt;p&gt;In practice, if it's our own static website or blog, simply ensuring that this file (index.json) with the appropriate format exists in the root directory of the site is enough to quickly integrate the search functionality you see into your own website. OK, with the functionality verified, let's start integrating it into our site.&lt;/p&gt;

&lt;p&gt;The official website of Pizza/INFINI Labs is statically generated using Hugo, and the index.json file does not need to be manually created. First, we need to enable Hugo to generate content in JSON format, which is a built-in capability of Hugo. We'll need to modify the configuration of the Hugo project:&lt;/p&gt;

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

&lt;p&gt;Add a JSON output option to the outputs parameter, and then define the JSON output format template in the theme's template files:&lt;/p&gt;

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

&lt;p&gt;The text content is as follows for easy copying and pasting. Save the file with the name index.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{- $index := slice -}}
{{- range where .Site.RegularPages.ByDate.Reverse "Type" "not in" (slice "page" "json") -}}
    {{- $index = $index | append (dict "title" (.Title | plainify) "url" .Permalink "tags" .Params.tags "category" .Params.category "subcategory" .Params.subcategory "summary" (.Params.Summary | markdownify | plainify) "content" (.Content | markdownify | plainify)) -}}
{{- end -}}
{{- $index | jsonify -}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, next, we need to add the tags we’ve used above to the metadata of each article or blog post on the site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgefgm0fr8u6701thky46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgefgm0fr8u6701thky46.png" alt="Image description" width="800" height="587"&gt;&lt;/a&gt;&lt;br&gt;
OK, start the Hugo site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hugo server --forceSyncStatic   --minify --theme book


                   | EN   
-------------------+------
  Pages            | 181  
  Paginator pages  |   5  
  Non-page files   |   0  
  Static files     | 110  
  Processed images |   0  
  Aliases          |  52  
  Sitemaps         |   1  
  Cleaned          |   0  

Built in 323 ms
Watching for changes in /Users/medcl/Documents/rust/pizza/website/{assets,content.en,static,themes}
Watching for config changes in /Users/medcl/Documents/rust/pizza/website/config.yaml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at //localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the Hugo site address and try accessing &lt;a href="http://localhost:1313/index.json" rel="noopener noreferrer"&gt;http://localhost:1313/index.json&lt;/a&gt;. You should be able to access the JSON file:&lt;/p&gt;

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

&lt;p&gt;At this point, the data preparation is complete. Next, we'll integrate the frontend search widget.&lt;/p&gt;

&lt;p&gt;Do you remember the resource files we downloaded from Pizza-DocSearch earlier? We mainly use the three files in the assets folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/tmp/pizza-docsearch/example/dist
➜  dist git:(main) tree    
.
├── assets
  ├── index-C1z1vz3D.css
  ├── index-D_gOo737.js
  └── pizza_wasm_bg-BRCuviY_.wasm
├── index.html
└── index.json

1 directory, 5 files
➜  dist git:(main) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the index.html file, and you will see the following content:&lt;/p&gt;

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

&lt;p&gt;In order to integrate with the docsearch, we just need to add the three highlighted sections of code into our own static website.&lt;/p&gt;

&lt;p&gt;Copy the files from the assets directory to our Hugo site, in the following location:&lt;/p&gt;

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

&lt;p&gt;Then, modify the Hugo theme templates by adding a segment of code to the html-head.html file in the header template of all pages to load our CSS stylesheet:&lt;/p&gt;

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

&lt;p&gt;Next, continue modifying the Hugo theme template files by adding a segment of code to the footer template of all pages to load the JS script files:&lt;/p&gt;

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

&lt;p&gt;Next, insert a Docsearch tag in the appropriate place within the page template to place the search box, as shown in the image:&lt;/p&gt;

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

&lt;p&gt;With that, the task is complete!&lt;/p&gt;

&lt;p&gt;Open your browser to see the final result:&lt;/p&gt;

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

&lt;p&gt;Finally, to summarize, with the help of the 3 lines of code and copy 3 files from INFINI Pizza Docsearch, you can add a lightweight offline search functionality to your static site in just 5 minutes. Give it a try!&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pizza.rs" rel="noopener noreferrer"&gt;https://pizza.rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infinilabs/pizza-wasm" rel="noopener noreferrer"&gt;https://github.com/infinilabs/pizza-wasm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infinilabs/pizza-docsearch" rel="noopener noreferrer"&gt;https://github.com/infinilabs/pizza-docsearch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow us AT: &lt;a href="https://github.com/infinilabs" rel="noopener noreferrer"&gt;https://github.com/infinilabs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>hugo</category>
      <category>webassembly</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to leverage the state-of-the-art NLP models in Rust</title>
      <dc:creator>Medcl</dc:creator>
      <pubDate>Tue, 01 Aug 2023 02:59:25 +0000</pubDate>
      <link>https://dev.to/medcl/how-to-leverage-the-state-of-the-art-nlp-models-in-rust-59nf</link>
      <guid>https://dev.to/medcl/how-to-leverage-the-state-of-the-art-nlp-models-in-rust-59nf</guid>
      <description>&lt;p&gt;In this tutorial we will show you how to use &lt;code&gt;rust-bert&lt;/code&gt; library to utilize the state-of-the-art natural language processing models in Rust, and we are specifically tested on macOS environments.&lt;/p&gt;

&lt;p&gt;Rust crate &lt;a href="https://docs.rs/rust-bert/latest/rust_bert/bert/index.html" rel="noopener noreferrer"&gt;rust_bert&lt;/a&gt; implementation of the BERT language model (&lt;a href="https://arxiv.org/abs/1810.04805" rel="noopener noreferrer"&gt;https://arxiv.org/abs/1810.04805&lt;/a&gt; Devlin, Chang, Lee, Toutanova, 2018). The base model is implemented in the bert_model::BertModel struct. Several language model heads have also been implemented, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Masked language model: bert_model::BertForMaskedLM&lt;/li&gt;
&lt;li&gt;Multiple choices: bert_model:BertForMultipleChoice&lt;/li&gt;
&lt;li&gt;Question answering: bert_model::BertForQuestionAnswering&lt;/li&gt;
&lt;li&gt;Sequence classification: bert_model::BertForSequenceClassification&lt;/li&gt;
&lt;li&gt;Token classification (e.g. NER, POS tagging): bert_model::BertForTokenClassification&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Transformers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/docs/transformers/installation" rel="noopener noreferrer"&gt;Transformers&lt;/a&gt; is a State-of-the-art Machine Learning for Pytorch, TensorFlow, and JAX.&lt;/p&gt;

&lt;p&gt;Before installing the transformers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m venv .env
source .env/bin/activate

brew install cmake
brew install pkg-config
brew install sentencepiece

pip install sentencepiece
pip install transformers
pip install 'transformers[torch]'
pip install 'transformers[tf-cpu]'
pip install 'transformers[flax]'
pip install onnxruntime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(.env) ➜  transformers git:(main) python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('we love you'))"
No model was supplied, defaulted to distilbert-base-uncased-finetuned-sst-2-english and revision af0f99b (https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english).
Using a pipeline without specifying a model name and revision in production is not recommended.
Downloading (…)lve/main/config.json: 100%|████████████████████████████████████████████████████████████████████████████████████████████████| 629/629 [00:00&amp;lt;00:00, 1.13MB/s]
Downloading model.safetensors: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████| 268M/268M [00:26&amp;lt;00:00, 10.0MB/s]
Downloading (…)okenizer_config.json: 100%|███████████████████████████████████████████████████████████████████████████████████████████████| 48.0/48.0 [00:00&amp;lt;00:00, 158kB/s]
Downloading (…)solve/main/vocab.txt: 100%|███████████████████████████████████████████████████████████████████████████████████████████████| 232k/232k [00:00&amp;lt;00:00, 554kB/s]
Xformers is not installed correctly. If you want to use memory_efficient_attention to accelerate training use the following command to install Xformers
pip install xformers.
[{'label': 'POSITIVE', 'score': 0.9998704195022583}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the huggineface's transformers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/huggingface/transformers.git
cd transformers
pip install -e .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🤗 Transformers is tested on Python 3.6+, PyTorch 1.1.0+, TensorFlow 2.0+, and Flax. Follow the installation instructions below for the deep learning library you are using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PyTorch installation instructions.&lt;/li&gt;
&lt;li&gt;TensorFlow 2.0 installation instructions.&lt;/li&gt;
&lt;li&gt;Flax installation instructions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we will need to install these 3 dependend projects as follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install PyTorch
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip3 install torch torchvision torchaudio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install TensorFlow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# There is currently no official GPU support for MacOS.
python3 -m pip install tensorflow
# Verify install:
python3 -c "import tensorflow as tf; print(tf.reduce_sum(tf.random.normal([1000, 1000])))"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Flax
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://flax.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Flax&lt;/a&gt; delivers an end-to-end and flexible user experience for researchers who use &lt;a href="https://jax.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;JAX&lt;/a&gt; with neural networks. Flax exposes the full power of JAX. It is made up of loosely coupled libraries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jax.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;JAX&lt;/a&gt; is a project designed for High-Performance Array Computing,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.11 -m pip install --upgrade pip
pip install flax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Init Rust BERT
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install libtorch
brew link libtorch
brew ls --verbose libtorch | grep dylib
export LIBTORCH=$(brew --cellar pytorch)/$(brew info --json pytorch | jq -r '.[0].installed[0].version')
export LD_LIBRARY_PATH=${LIBTORCH}/lib:$LD_LIBRARY_PATH

git clone https://github.com/guillaume-be/rust-bert.git
cd rust-bert
ORT_STRATEGY=system cargo run --example sentence_embeddings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also better to add the following to bash/zsh environment in case you met exception like &lt;code&gt;"libtch/torch_api_generated.cpp" with args "c++" did not execute successfully (status code exit status: 1).&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export LIBTORCH=$(brew --cellar pytorch)/$(brew info --json pytorch | jq -r '.[0].installed[0].version')
export LD_LIBRARY_PATH=${LIBTORCH}/lib:$LD_LIBRARY_PATH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  In Rust's project
&lt;/h2&gt;

&lt;p&gt;Import the example code into Pizza's module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use log::*;
use rust_bert::pipelines::translation::{Language, TranslationModelBuilder};
pub(crate) fn translation() -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {
    info!("start translation:");
    let model = TranslationModelBuilder::new()
        .with_source_languages(vec![Language::English])
        .with_target_languages(vec![
            Language::Spanish,
            Language::French,
            Language::Italian,
        ])
        .create_model()
        .unwrap();

    let input_text = "Hello world!";
    let output = model
        .translate(&amp;amp;[input_text], None, Language::Spanish)
        .unwrap();

    for sentence in output {
        info!("Output: {}", sentence);
    }
    Ok(())
}

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

&lt;/div&gt;



&lt;p&gt;And we will get the result as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ___ _____  __________   _
  / _ \\_   \/ _  / _  /  /_\
 / /_)/ / /\/\// /\// /  //_\\
/ ___/\/ /_   / //\/ //\/  _  \
\/   \____/  /____/____/\_/ \_/

[PIZZA] The Next-Gen Real-Time Hybrid Search &amp;amp; AI-Native Innovation Engine.
[2023-06-03 19:00:32] [INFO] [pizza:96] PIZZA now starting.
[2023-06-03 19:00:32] [INFO] [pizza::modules::api:71] api listen at: http://0.0.0.0:2900
[2023-06-03 19:00:32] [INFO] [pizza::modules:37] started module [api]
[2023-06-03 19:00:32] [INFO] [pizza::modules::bert::translation:4] start translation:
[2023-06-03 19:00:32] [INFO] [actix_server::builder:200] starting 8 workers
[2023-06-03 19:00:32] [INFO] [actix_server::server:197] Tokio runtime found; starting in existing Tokio runtime
[2023-06-03 19:00:33] [INFO] [cached_path::cache:414] Cached version of https://huggingface.co/Helsinki-NLP/opus-mt-en-ROMANCE/resolve/main/vocab.json is up-to-date
[2023-06-03 19:00:33] [INFO] [cached_path::cache:414] Cached version of https://huggingface.co/Helsinki-NLP/opus-mt-en-ROMANCE/resolve/main/source.spm is up-to-date
[2023-06-03 19:00:34] [INFO] [cached_path::cache:414] Cached version of https://huggingface.co/Helsinki-NLP/opus-mt-en-ROMANCE/resolve/main/config.json is up-to-date
[2023-06-03 19:00:36] [INFO] [cached_path::cache:414] Cached version of https://huggingface.co/Helsinki-NLP/opus-mt-en-ROMANCE/resolve/main/rust_model.ot is up-to-date
[2023-06-03 19:00:36] [INFO] [pizza::modules::bert::translation:21] Output:  ¡Hola mundo!
[2023-06-03 19:00:36] [INFO] [pizza::modules:37] started module [bert]
[2023-06-03 19:00:36] [INFO] [pizza::modules:39] all modules are started
[2023-06-03 19:00:36] [INFO] [pizza:116] PIZZA is up and running now. PID: 37426
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow, &lt;code&gt;Hello World&lt;/code&gt; was successfully translated to &lt;code&gt;¡Hola mundo!&lt;/code&gt;, which is great!&lt;/p&gt;

&lt;p&gt;As you can see, creating a translation application is incredibly simple just in a few lines of code. And this is just the beginning! By harnessing the power of these pre-trained language models, we can accomplish so much more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/guillaume-be/rust-bert" rel="noopener noreferrer"&gt;https://github.com/guillaume-be/rust-bert&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/huggingface/transformers" rel="noopener noreferrer"&gt;https://github.com/huggingface/transformers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pytorch.org/get-started/locally/" rel="noopener noreferrer"&gt;https://pytorch.org/get-started/locally/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.tensorflow.org/install/pip#macos" rel="noopener noreferrer"&gt;https://www.tensorflow.org/install/pip#macos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flax.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;https://flax.readthedocs.io/en/latest/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>bert</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
