<?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: Dominik Kundel</title>
    <description>The latest articles on DEV Community by Dominik Kundel (@dkundel).</description>
    <link>https://dev.to/dkundel</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%2F1749%2F583683bd-36df-4ef5-8502-1b230d5e83ae.jpg</url>
      <title>DEV Community: Dominik Kundel</title>
      <link>https://dev.to/dkundel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dkundel"/>
    <language>en</language>
    <item>
      <title>Five ways to use Generative AI in JavaScript</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Sun, 28 Jul 2024 19:09:11 +0000</pubDate>
      <link>https://dev.to/dkundel/five-ways-to-use-generative-ai-in-javascript-11pf</link>
      <guid>https://dev.to/dkundel/five-ways-to-use-generative-ai-in-javascript-11pf</guid>
      <description>&lt;p&gt;Machine Learning and AI development is traditionally dominated by Python and because of that the ecosystem of tutorials, libraries, and examples is primarily dominated by Python. However, with the rise of the &lt;a href="https://www.latent.space/p/ai-engineer" rel="noopener noreferrer"&gt;AI Engineer&lt;/a&gt; concept, we are seeing more full-stack web developers begin to work on AI, and with it the demand for JavaScript/Typescript compatible tooling rises. In fact in February 2024, &lt;a href="https://x.com/jaredpalmer" rel="noopener noreferrer"&gt;Jared Palmer&lt;/a&gt; from Vercel even claimed that "The AI engineer of the future is a TypeScript engineer". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fn55krsk33i0nzuzfzrpn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fn55krsk33i0nzuzfzrpn.jpg" alt="Jared Palmer standing in front of a black slide with white text reading "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this blog post, we'll go through five ways how you as a JavaScript developer can use different generative AI tools without brushing up on your Python skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud APIs
&lt;/h2&gt;

&lt;p&gt;If you are just getting started and especially if you are planning to use a Large Language Model (LLM) like &lt;a href="https://platform.openai.com/docs/models" rel="noopener noreferrer"&gt;OpenAI's GPT models&lt;/a&gt; or &lt;a href="https://docs.anthropic.com/en/docs/about-claude/models" rel="noopener noreferrer"&gt;Anthropic's Claude models&lt;/a&gt; using their APIs directly can be an excellent start.&lt;/p&gt;

&lt;p&gt;Interacting with the model is just one &lt;code&gt;fetch&lt;/code&gt; call away.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.openai.com/v1/chat/completions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;model&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a helpful assistant.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Who won the world series in 2020?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Los Angeles Dodgers won the World Series in 2020.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Where was it played?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
 &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In fact, OpenAI's "Chat Completions" API has become the de-facto standard for a lot of other model providers. Providers like &lt;a href="https://console.groq.com/docs/openai" rel="noopener noreferrer"&gt;Groq&lt;/a&gt; or &lt;a href="https://docs.together.ai/docs/openai-api-compatibility" rel="noopener noreferrer"&gt;Together.ai&lt;/a&gt; provide OpenAI compatibility meaning you just need to change the URL to switch to a different provider to choose a different model.&lt;/p&gt;

&lt;p&gt;If you are looking to use other models there are also providers like &lt;a href="https://replicate.com" rel="noopener noreferrer"&gt;Replicate&lt;/a&gt; that specialize in hosting open-source models with a &lt;a href="https://replicate.com/docs/reference/http#predictions.create" rel="noopener noreferrer"&gt;consistent REST API&lt;/a&gt; and even &lt;a href="https://dev.to/blog/fine-tuning-sdxl"&gt;expose APIs to fine-tune some models on their platform&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;

&lt;p&gt;While Cloud APIs are great to get started, sometimes you don't want to rely on a cloud-hosted provider for your use case. For example, maybe you want to explicitly run a model like &lt;a href="https://huggingface.co/meta-llama/Meta-Llama-3-8B" rel="noopener noreferrer"&gt;Llama 3 8B&lt;/a&gt; directly on your local machine or you want to use an open-source library like &lt;a href="https://github.com/Unstructured-IO" rel="noopener noreferrer"&gt;Unstructured.io&lt;/a&gt; that's written in Python and use it within your JavaScript project without paying for the hosted API.&lt;/p&gt;

&lt;p&gt;Some projects provide for that reason &lt;a href="https://www.docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; container that will expose an HTTP API when run. For example, you can start the &lt;a href="https://github.com/Unstructured-IO/unstructured-api" rel="noopener noreferrer"&gt;Unstructured API&lt;/a&gt; Docker container by running:&lt;/p&gt;

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

docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; unstructured-api downloads.unstructured.io/unstructured-io/unstructured-api:latest 
&lt;span class="nt"&gt;--port&lt;/span&gt; 8000 &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0


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

&lt;/div&gt;

&lt;p&gt;Once the container is running you now have a localhost version of the Unstructured API that you can use to chunk documents to later store in your vector database.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;// e.g. `fs.readFileSync('./fileLocation');&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8000/general/v0/general&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
 &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;multipart/form-data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="s2"&gt;```

Similarly, you could use [`&lt;/span&gt;&lt;span class="nx"&gt;llama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cpp&lt;/span&gt;&lt;span class="s2"&gt;` docker container](https://github.com/ggerganov/llama.cpp/blob/master/docs/docker.md) or [Ollama](https://ollama.com) to run local APIs for your LLM models such as Llama 3.

If you are working with an ML team that trained their own model or you want to host any model off [Huggingface](https://huggingface.co) and use the same Docker container approach, you can also check out [`&lt;/span&gt;&lt;span class="nx"&gt;cog&lt;/span&gt;&lt;span class="s2"&gt;` by Replicate](https://github.com/replicate/cog). It wraps Docker and is specifically designed for creating Docker containers for ML models.

All of this works great if you have a relatively small surface area of tasks you want to perform and the composability is limited. 

## JavaScript-native libraries

Now this one might be the most obvious option but the best option remains picking a library or tool that was natively written in JavaScript or TypeScript and fortunately, this ecosystem continues to grow.

Most cloud API model providers offer a JavaScript native SDK incl. [OpenAI](https://www.npmjs.com/package/openai), [Anthropic](https://npm.im/@anthropic-ai/sdk), and [Google](https://npm.im/@google/generative-ai).

Additionally, two of the most popular open-source LLM frameworks [Langchain](https://www.langchain.com) and [LlamaIndex](https://www.llamaindex.ai) provide TypeScript versions of their frameworks. Vercel also offers the [`&lt;/span&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="s2"&gt;` SDK](https://sdk.vercel.ai) that is built from the ground up with a stronger focus on bringing together LLMs and the front-end experiences they power. Even though the documentation is heavily focused on Vercel's own Next.js framework, the SDK also works with other frameworks.

```&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ai-sdk/openai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generateText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Write a vegetarian lasagna recipe for 4 people.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="s2"&gt;```

However, since most of these ultimately wrap other tools and frameworks as integrations, you are still often left with more limited functionality than their Python counterparts. For example, the Python version of Langchain has 18 different document transformer integrations while the JavaScript one has 5. 

## Native LLM APIs

Now this one is still more forward-looking. Google Chrome recently released an [experimental set of APIs](https://developer.chrome.com/docs/ai/built-in) into the [Chrome Dev](https://www.google.com/chrome/dev/?extra=devchannel) and [Chrome Canary](https://www.google.com/chrome/canary/) channels that expose access to a locally run [Gemini Nano model](https://blog.google/technology/ai/google-gemini-ai).

```&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTextSession&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Translate the following to German: Hello how are you?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// " Hallo, wie gehts"&lt;/span&gt;
&lt;span class="s2"&gt;```

Since the model is so small compared to state-of-the-art models including smaller ones like [GPT-4o mini](https://openai.com/index/gpt-4o-mini-advancing-cost-efficient-intelligence/) or [Llama 3.1 8B](https://ai.meta.com/blog/meta-llama-3-1/), you will likely have a harder time prompting this reliably though. With the pace of model development, this will likely change quickly though.

While this API is still experimental and only spearheaded by Chrome, the trend of local LLMs might change this quickly as more companies get interested. Mozilla, for example, recently announced that they are focused on moving "local AI" forward incl. creating a new [dedicated accelerator program](https://blog.mozilla.org/en/mozilla/mozilla-builders-accelerator/) and Apple is already using local models for their new Apple Intelligence feature.

If you want to give the `&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="s2"&gt;` API a shot, check out [Google's explainer repository](https://github.com/explainers-by-googlers/prompt-api) as well as the [`&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="s2"&gt;` package for Vercel's `&lt;/span&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="s2"&gt;` SDK](https://github.com/jeasonstudio/chrome-ai) to get started.

## Pythonia

One interesting approach to using Python tools in JavaScript is [`&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;`](https://www.npmjs.com/package/pythonia). It's one half of the [`&lt;/span&gt;&lt;span class="nx"&gt;JSPyBridge&lt;/span&gt;&lt;span class="s2"&gt;` project](https://github.com/extremeheat/JSPyBridge) that creates an interface to call JavaScript from Python and Python from JavaScript by facilitating the interprocess communication so that you can write code in the language of your choice. 

It uses inter-process communication (IPC) and [JavaScript Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to enable you to almost use identical code when calling a Python library in JavaScript than in Python and then actually executing it in Python.

For example, here's a code snippet taken from the [getting started guide of the Python library `&lt;/span&gt;&lt;span class="nx"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="s2"&gt;`](https://haystack.deepset.ai/overview/quick-start):

```&lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;haystack&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PredefinedPipeline&lt;/span&gt;

&lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PredefinedPipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CHAT_WITH_WEBSITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetcher&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://haystack.deepset.ai/overview/quick-start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Which components do I need for a RAG pipeline?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;replies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="s2"&gt;```

By using the `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` npm package we can write the same equivalent code:

```&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;python&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pythonia&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;haystack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;python&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;haystack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PredefinedPipeline&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nc"&gt;PredefinedPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chat_with_website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;fetcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://haystack.deepset.ai/overview/quick-start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Which components do I need for a RAG pipeline?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueOf&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="s2"&gt;```

You might notice that this code is slightly longer and heavily uses `&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="s2"&gt;`. That's because of the IPC communication. `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` does a lot of optimizations behind the scenes to effectively communicate between the channels. For example, the actual data is not being sent back from Python to Node.js unless you call `&lt;/span&gt;&lt;span class="nf"&gt;valueOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;`. However, outside of that the code is very similar and is using native Python libraries.

### Performance of `&lt;/span&gt;&lt;span class="nx"&gt;pythoia&lt;/span&gt;&lt;span class="s2"&gt;`

One concern for you might be performance and while it would be slower than entirely running in Python, the actual performance might surprise you. If you want to use a Python library, like [RAGatoille](https://github.com/bclavie/RAGatouille), but the rest of your system is written in JavaScript, really the only alternative to `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` is exposing the library through an HTTP API and using `&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="s2"&gt;` to bridge the systems. 

If we run a benchmark where we use the `&lt;/span&gt;&lt;span class="nx"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="s2"&gt;` code snippet from above and run it both using `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` and expose it using [FastAPI](https://fastapi.tiangolo.com), both requests are slow because of their calls to OpenAI but `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` actually slightly wins the race.

&amp;lt;figure&amp;gt;
![Benchmark screenshot where pythonia is 13% faster across 10 runs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24iqajuncyl2zbsh382z.png)
&amp;lt;figcaption&amp;gt;Using `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` results in an average of 13% faster results but both take longer than 1.2s per run&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;


Overall while there is a performance hit of using `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` over using only native Python, given the long-running nature of most generative AI calls, the overhead becomes relatively negligible especially when compared to making local HTTP requests.

## Conclusion

While more and more JavaScript developers are getting into the Generative AI space, we still have ways to go to catch up to an ecosystem that has the breadth of the Python space. Cloud APIs, running local Docker containers, and bridging projects such as `&lt;/span&gt;&lt;span class="nx"&gt;pythonia&lt;/span&gt;&lt;span class="s2"&gt;` are great options to tap into this space without moving all of your logic into Python. Ultimately it's up to us though to either grow the space of available AI JavaScript tools by contributing to existing open-source projects or even starting new ones if you want to maintain a project. In the meantime, AI tools such as [GitHub Copilot](https://github.com/features/copilot), [Cursor](https://www.cursor.com), or [Codeium](https://codeium.com) can help you with writing some Python code.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>machinelearning</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating your own image generation model using JavaScript</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Fri, 23 Feb 2024 08:00:00 +0000</pubDate>
      <link>https://dev.to/dkundel/creating-your-own-image-generation-model-using-javascript-3oph</link>
      <guid>https://dev.to/dkundel/creating-your-own-image-generation-model-using-javascript-3oph</guid>
      <description>&lt;p&gt;Similar to a lot of other developers I've been experimenting in the last year a lot with different generative AI solutions. But I'm not a machine learning engineer, and I'm not even a Python developer. I'm a web developer who loves writing JavaScript &amp;amp; TypeScript from front-end over back-end to &lt;a href="https://dkundel.com/blog/how-we-hacked-our-coffee-machine-with-javascript/"&gt;coffee machines&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;So even just using open-source models like &lt;a href="https://github.com/Stability-AI/generative-models"&gt;Stability AI's Stable Diffusion XL (SDXL)&lt;/a&gt; has  been intimidating to me, let alone figuring out how to "fine-tune" such a model for my own needs. Just looking at the model's &lt;a href="https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/"&gt;Hugging Face page&lt;/a&gt; — you can think of Hugging Face like the GitHub of sharing machine learning models — brings up all sorts of questions. What's CUDA? What does &lt;code&gt;torch&lt;/code&gt; do? And most importantly: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;how do I make it generate images of my corgi?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this blog post we'll explore how you can create your own image generation model on top of SDXL without needing any specific hardware and just using JavaScript and APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to create your own image generation model
&lt;/h3&gt;

&lt;p&gt;Creating an image generation model is extremely hard and requires a lot of data and the results can be mixed. For that reason various companies are working on their proprietary models like &lt;a href="https://www.adobe.com/products/firefly.html"&gt;Adobe's Firefly&lt;/a&gt; or &lt;a href="https://openai.com/dall-e-3"&gt;OpenAI's DALL·E 3&lt;/a&gt;. The problem with these models is that they are more of the "you get what you get" variety, meaning while you might be able to influence them with some example images they are largely static. &lt;/p&gt;

&lt;p&gt;That's where open-source models come into play as base models for our project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Choosing a base model
&lt;/h4&gt;

&lt;p&gt;There are a multitude of open-source text-to-image generation models. Stability AI's Stable Diffusion XL (SDXL) is probably the most popular one among them though. It's both versatile, produces high quality output and is licensed in a way that you can use it for commercial use cases, unlike some alternative models.&lt;/p&gt;

&lt;p&gt;The other reason why we want to use SDXL is that it not only allows for fine-tuning but it allows fine-tuning through a technique called LoRA.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is fine-tuning? What does LoRA mean?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftf2qoqz0igr8wrg3y7us.png" class="article-body-image-wrapper"&gt;&lt;img alt="picture of my corgi in a lab coat" src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftf2qoqz0igr8wrg3y7us.png" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;
Prompt: "A film still of a TOK dog, big smile, dressed in a lab coat in front of a blackboard, warm color grading, 70mm, bokeh, cinematic, anamorphic, beautiful" — &lt;a href="https://replicate.com/p/53q3qtlbwozyvsyqpef5ey5miu" rel="noopener noreferrer"&gt;View generation details&lt;/a&gt;



&lt;p&gt;The core part of a model are its weights. The weights are essentially the brain of the model and so if we want to teach a model something new we need to update those weights. This updating of the weights is done through a process called fine-tuning.&lt;/p&gt;

&lt;p&gt;The problem is that the weights are a massive matrix though and updating all the relevant weights can be intensive work and therefore costly. That's where LoRA comes into place. LoRA stands for Low-Rank Adaptation. &lt;/p&gt;

&lt;p&gt;With LoRA rather than changing the whole matrix of weights, an "adapter" gets created that is essentially a smaller matrix that sits on top of the original model and manipulates the relevant weights. The output of this process is also significantly smaller since it sits on top of the original weights rather than representing the whole set of weights. This means you could have more easily a multitude of fine-tuned models on top of the same base model without wasting storage.&lt;/p&gt;

&lt;p&gt;So now we know what LoRA is but how do we apply it? A quick Google you'll find lots of Python based tutorials that are often heavy in machine learning terms and on top of that require you to have NVIDIA hardware that's compatible with NVIDIA's CUDA tooling. So what if you don't have that or don't have time to learn all the Python concepts?&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing Replicate
&lt;/h3&gt;

&lt;p&gt;That's where &lt;a href="https://replicate.com"&gt;Replicate&lt;/a&gt; comes in. They're goal is "making machine learning accessible to every software developer." There are some other offerings that provide ways for you to fine-tune your model but for this blog post we'll use Replicate.&lt;/p&gt;

&lt;p&gt;If you don't have a Replicate account yet, &lt;a href="https://replicate.com/signin"&gt;start by signing up for a Replicate account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you signed up, create an API key and &lt;a href="https://www.twilio.com/en-us/blog/how-to-set-environment-variables-html"&gt;add it as an environment variable&lt;/a&gt; named &lt;code&gt;REPLICATE_API_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you have an existing Node.js project already you can install the Replicate Node.js library using:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Alternatively, we'll create a new project using the &lt;code&gt;create-replicate&lt;/code&gt; CLI tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-replicate sdxl-fine-tune &lt;span class="nt"&gt;--model&lt;/span&gt; stability-ai/sdxl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will both create a new project and also run an example image generation of SDXL and your output should look similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbaajtiutngm89z5htpo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbaajtiutngm89z5htpo.png" alt="astronaut in space on a unicorn" width="768" height="768"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://replicate.com/p/dzsqmb3bg4lqpjkz2iptjqgccm"&gt;View generation details&lt;/a&gt;



&lt;p&gt;And you'll find the code that generated this image in &lt;code&gt;sdxl-fine-tune/index.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you are creating your own project you can replicate the same generation using this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Replicate&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;replicate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Replicate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPLICATE_API_TOKEN&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An astronaut riding a rainbow unicorn, cinematic, dramatic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;refine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expert_ensemble_refiner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;K_EULER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lora_scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;num_outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;guidance_scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;7.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apply_watermark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;high_noise_frac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;negative_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;prompt_strength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;num_inference_steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Running...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Done!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we were able to generate our first image using SDXL, it's time to create our own model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gathering your data
&lt;/h3&gt;

&lt;p&gt;Before we can start the process of fine-tuning we'll need some data, or rather some images, that we can train the model on using LoRA. &lt;/p&gt;

&lt;p&gt;For my project I used 21 images of various sizes but with my subject being very clear in the picture and captured from different angles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0f9osfvzdm6cwu1w2iid.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0f9osfvzdm6cwu1w2iid.png" alt="screenshot of a folder full of pictures of a corgi" width="800" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have collected all the images of what you want to train the model on(20-30 is a good amount to have for a pet for example), put them in a folder and ZIP up the folder so we can start our fine-tuning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting your fine-tuning
&lt;/h3&gt;

&lt;p&gt;Now that you have your files together let's do the fine-tuning! With Replicate there are two ways we can do this. &lt;/p&gt;

&lt;h4&gt;
  
  
  Using the website
&lt;/h4&gt;

&lt;p&gt;The first option and maybe the easiest to try things out is &lt;a href="https://replicate.com/stability-ai/sdxl/train"&gt;using the website interface&lt;/a&gt;. You can upload the ZIP file you created directly there and generate your model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41spq31rntdwjc4iifnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41spq31rntdwjc4iifnx.png" alt="Screenshot of the Replicate website with the SDXL training UI" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Using the JavaScript
&lt;/h4&gt;

&lt;p&gt;The alternative way is using &lt;a href="https://replicate.com/docs/reference/http#trainings.create"&gt;Replicate's Trainings API&lt;/a&gt; for example through the Node.js client library. &lt;/p&gt;

&lt;p&gt;When using the API we first need to &lt;a href="https://replicate.com/create"&gt;create a new model&lt;/a&gt; that will act as our target for our training model. You can create both private and public models. I'll be creating a private one. Take note of your username and model name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspba03p3bte3n1901dph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspba03p3bte3n1901dph.png" alt="Screenshot of the Replicate website" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to kick off a training using the API you'll need to host your ZIP file somewhere publicly like an S3 bucket or any static file hosting. &lt;/p&gt;

&lt;p&gt;Once you have uploaded your ZIP file it's time to set up the code. Create a new file &lt;code&gt;fine-tune.js&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Replicate&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;replicate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Replicate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPLICATE_API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;training&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trainings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stability-ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sdxl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your-username&amp;gt;/&amp;lt;your-model-name&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;input_images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://&amp;lt;path-to-your-training-data&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;mask_target_prompts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;photo of a dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;training&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you replace &lt;code&gt;&amp;lt;your-username&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;your-model-name&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;path-to-your-training-data&amp;gt;&lt;/code&gt; according to your respective values. &lt;/p&gt;

&lt;p&gt;Since I'm fine-tuning the model for pictures of my dog, I added a parameter of &lt;code&gt;mask_target_prompts&lt;/code&gt; that essentially tells the training process to focus in my input pictures on the &lt;code&gt;photo of a dog&lt;/code&gt;. If you just train the model on a specific style of picture you can for example omit this parameter. There are a variety of parameters that you can pass into the training. &lt;a href="https://replicate.com/stability-ai/sdxl/train#training-inputs"&gt;Check the model for documentation on what parameters are available&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you are ready start your training by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node fine-tuning.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will include a link to your training process or alternatively you can find the training run within the &lt;a href="https://replicate.com/trainings"&gt;Trainings section of your Replicate dashboard&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;On this page you'll be able to watch the logs live as the training is going on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing your new model
&lt;/h3&gt;

&lt;p&gt;Once your training run is complete it's time to test our new model. Update your &lt;code&gt;index.js&lt;/code&gt; file to point to your own model. &lt;/p&gt;

&lt;p&gt;You'll need both your username and model as well as the version of your model that you can find either on the training page or in the &lt;code&gt;Versions&lt;/code&gt; tab of your model page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Replicate&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;replicate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Replicate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPLICATE_API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your-username&amp;gt;/&amp;lt;your-model-name&amp;gt;:&amp;lt;your-version&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A TOK dog sitting in a throne in the style of a renaissance painting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;refine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expert_ensemble_refiner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;K_EULER&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lora_scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;num_outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;guidance_scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;7.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;apply_watermark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;high_noise_frac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;negative_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;prompt_strength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;num_inference_steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When looking at the code you'll notice that the prompt says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A TOK dog sitting in a throne in the style of a renaissance painting&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But what is the &lt;code&gt;TOK&lt;/code&gt;? It's basically a special "keyword" or token that represents the concept that you fine-tuned into the model. So when we say &lt;code&gt;A TOK dog&lt;/code&gt; we are basically saying we want a dog that looks like the dog we trained the model on (in this case my corgi). The &lt;code&gt;dog&lt;/code&gt; in this promopt is not stricly required and the prompt could also be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A TOK sitting in a throne in the style of a renaissance painting&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But using &lt;code&gt;TOK dog&lt;/code&gt; or even &lt;code&gt;TOK corgi&lt;/code&gt; helps nudge the model into the right direction. &lt;/p&gt;

&lt;p&gt;If you really don't like &lt;code&gt;TOK&lt;/code&gt; you could pass during the training process the &lt;code&gt;token_string&lt;/code&gt; parameter in with a different token but &lt;code&gt;TOK&lt;/code&gt; seems to be the established way to do this.&lt;/p&gt;

&lt;p&gt;With that we have everything ready to generate some corgi images. Let's run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here we go! My corgi on a throne 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjj74vltc1czse0739po.png" class="article-body-image-wrapper"&gt;&lt;img alt="picture of my corgi swimming in a pool with sunglasses" src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjj74vltc1czse0739po.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
Prompt: "A TOK dog sitting in a throne in the style of a renaissance painting" — &lt;a href="https://replicate.com/p/wdy523lbibifz4sktqmuectf7u" rel="noopener noreferrer"&gt;View generation details&lt;/a&gt;



&lt;h3&gt;
  
  
  Getting ready for production
&lt;/h3&gt;

&lt;p&gt;As you start using your new model you might notice that it's taking a bit of time to execute and sometimes might even get queued for a while. That's because by default your model runs on shared infrastructure until you are ready to "Deploy" your model. &lt;/p&gt;

&lt;p&gt;When you are ready and happy with your model and want to use it in production, head over to the version of your model that you want to deploy and press the "Deploy" button. &lt;/p&gt;

&lt;p&gt;From here you can pick how many instances and what infrastructure you'll want it to run on. Here you are primarily trading off cost, scale and execution time. &lt;/p&gt;

&lt;p&gt;Once you deployed your model you have to update your code once more to point against your specific deployment by changing the call from &lt;code&gt;replicate.run&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;prediction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deployments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your-username&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your-deployment-name&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A TOK dog sitting in a throne in the style of a renaissance painting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;prediction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that you are ready to create all the pictures your heart desires.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running it locally
&lt;/h3&gt;

&lt;p&gt;If you have the right CUDA compatible NVIDIA hardware on your local computer you can also use Replicate's &lt;a href="https://github.com/replicate/cog"&gt;&lt;code&gt;cog&lt;/code&gt; tool&lt;/a&gt; to run the model you trained locally instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cog predict r8.im/&amp;lt;your-username&amp;gt;/&amp;lt;your-model-name&amp;gt;@sha256:&amp;lt;your-version&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'seed=1234'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'width=1024'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'height=1024'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'prompt="A TOK dog sitting in a throne in the style of a renaissance painting"'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'refine="expert_ensemble_refiner"'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'scheduler="K_EULER"'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'lora_scale=0.8'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'num_outputs=1'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'guidance_scale=7.5'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'apply_watermark=true'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'high_noise_frac=0.95'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'negative_prompt=""'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'prompt_strength=0.8'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'num_inference_steps=50'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood this will leverage Docker to set up the environment to run your predictions.&lt;/p&gt;

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

&lt;p&gt;Stability AI's SDXL model is an extremely powerful open-source text-to-image generation model and there is a variety of different guides and ways to fine-tune SDXL for your own purposes. But with Replicate we were able to train the model without having to understand how LoRA works in detail, deal with having the right infrastructure or having to understand how to use Python libraries like PyTorch.&lt;/p&gt;

&lt;p&gt;If you are hooked like me, Replicate offers a variety of other models to  fine-tune directly on their platform incl. &lt;a href="https://replicate.com/docs/guides/fine-tune-a-language-model"&gt;Llama 2 and Mistral models&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fouy0onmps6mlu4hn81f7.png" class="article-body-image-wrapper"&gt;&lt;img alt="picture of my corgi swimming in a pool with sunglasses" src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fouy0onmps6mlu4hn81f7.png" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;
Prompt: "A TOK corgi with sunglasses in a pool, cinematic, anamorphic, 70mm" — &lt;a href="https://replicate.com/p/62jkhg3bouucnysyo2u7cxophq" rel="noopener noreferrer"&gt;View generation details&lt;/a&gt;



</description>
      <category>javascript</category>
      <category>ai</category>
      <category>node</category>
      <category>api</category>
    </item>
    <item>
      <title>Compete For Glory In An IoT Tug-Of-War!</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Thu, 23 Jul 2020 12:13:46 +0000</pubDate>
      <link>https://dev.to/twilio/compete-for-glory-in-an-iot-tug-of-war-4gnh</link>
      <guid>https://dev.to/twilio/compete-for-glory-in-an-iot-tug-of-war-4gnh</guid>
      <description>&lt;p&gt;NomNom the Roomba was born in July 2020. A series 585 Roomba, NomNom never goes anywhere without its external microcontroller and &lt;a href="https://www.twilio.com/iot/supersim"&gt; Twilio Super SIM&lt;/a&gt;. Its favorite activities are wearing fancy hats and eating confetti.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq0vwcdjrhsizz6jqolef.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq0vwcdjrhsizz6jqolef.jpg" alt="nomnom" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compete for glory in an IoT tug-of-war! Direct NomNom the Roomba to vacuum up your team’s confetti first. The winning team goes down in history as NomNom’s Most Favorite CodeLanders.&lt;/p&gt;

&lt;p&gt;If you want to learn more about how we built this, check out the GitHub repository of the project.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dkundel"&gt;
        dkundel
      &lt;/a&gt; / &lt;a href="https://github.com/dkundel/remote-controlled-roomba"&gt;
        remote-controlled-roomba
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Code of the Break Activity at CodeLand 2020 that allowed participants to remote control a Roomba
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>codeland</category>
    </item>
    <item>
      <title>Join us live on Twitch this Thursday!</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Thu, 07 May 2020 02:17:49 +0000</pubDate>
      <link>https://dev.to/twilio/join-us-live-on-twitch-this-thursday-4g90</link>
      <guid>https://dev.to/twilio/join-us-live-on-twitch-this-thursday-4g90</guid>
      <description>&lt;p&gt;The Twilio Hackathon is over but the Twilio Office Hours on Twitch are not! &lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/devteam" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SsFI-Xwo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Forganization%252Fprofile_image%252F1%252Fd908a186-5651-4a5a-9f76-15200bc6801f.jpg" alt="The DEV Team" width="150" height="150"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OD5kLNtd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Fuser%252Fprofile_image%252F264%252F40d89fb9-4de0-414d-8a06-f52ddda0bc75.jpg" alt="" width="150" height="150"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/devteam/announcing-the-twilio-hackathon-winners-1lp4" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Announcing: The Twilio Hackathon Winners!&lt;/h2&gt;
      &lt;h3&gt;Jess Lee for The DEV Team ・ May 5 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#twiliohackathon&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#showdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;The only thing that changes is the name. Instead of joining us for Twilio Office Hours, we welcome you to join us for &lt;strong&gt;Remote Participants&lt;/strong&gt; every Thursday 4pm PST on &lt;a href="https://twitch.tv/twilio"&gt;Twitch&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  New Title Same Show
&lt;/h2&gt;

&lt;p&gt;The title change but the hosts will remain! &lt;a href="https://dev.to/philnash"&gt;Phil Nash&lt;/a&gt; and I are excited to hang out with you between for two hours answering your questions about Twilio, coding in general and jumping into the code editor to build fun things!&lt;/p&gt;

&lt;h2&gt;
  
  
  What's on this week?
&lt;/h2&gt;

&lt;p&gt;For this week we will look into the winners of the hackathon and also cover some of the fun hacks that were submitted but didn't make it into the top 14 submissions. &lt;/p&gt;

&lt;p&gt;We'll also dive into using &lt;a href="https://workers.cloudflare.com/"&gt;Cloudflare workers&lt;/a&gt; to host single page applications on &lt;a href="https://www.twilio.com/functions"&gt;Twilio Functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Other than that we welcome you to join us and help us decide what we talk about 😊 or maybe drop by and show us your awesome projects!&lt;/p&gt;

&lt;h2&gt;
  
  
  When is this happening?
&lt;/h2&gt;

&lt;p&gt;The next stream is on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thursday May 7, 2020 at 4pm PST&lt;/li&gt;
&lt;li&gt;Thursday May 7, 2020 at 7pm EST&lt;/li&gt;
&lt;li&gt;Friday May 8, 2020 at 9am AEST&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are all the same times but Phil is in Australia and therefore a day ahead 😊&lt;/p&gt;

&lt;p&gt;We can't wait for you to join us at &lt;a href="https://twitch.tv/twilio"&gt;twitch.tv/twilio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>twilio</category>
      <category>twiliohackathon</category>
    </item>
    <item>
      <title>Twilio Office Hours with Phil &amp; Dom</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Tue, 28 Apr 2020 20:27:10 +0000</pubDate>
      <link>https://dev.to/twilio/twilio-office-hours-with-phil-dom-1f4l</link>
      <guid>https://dev.to/twilio/twilio-office-hours-with-phil-dom-1f4l</guid>
      <description>&lt;p&gt;The #twiliohackathon with DEV is over in a few days and we hope your projects are going well. We can't wait to see all the awesome things you built this month.&lt;/p&gt;

&lt;p&gt;To wrap up the hackathon we'll host another edition of our weekly office hours on Twitch! Over there &lt;a href="https://dev.to/philnash"&gt;Phil&lt;/a&gt; and &lt;a href="https://dev.to/dkundel"&gt;I&lt;/a&gt; will be looking at some of the already submitted apps (no we won't judge them), answer any last questions and additionally we'll have a special guest with &lt;a href="https://dev.to/thorwebdev"&gt;Thor&lt;/a&gt; from Stripe showing us how he combined Twilio and Stripe to create a mobile payment experience.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Hackathon office hours will be hosted on the &lt;a href="https://twitch.tv/twilio"&gt;Twilio Twitch channel&lt;/a&gt;&lt;/em&gt; at:&lt;/p&gt;

&lt;p&gt;19:00 EDT Thursday 30th April&lt;br&gt;
16:00 PDT Thursday 30th April&lt;br&gt;
09:00 AEST Friday 1st May&lt;/p&gt;

&lt;p&gt;(They're all the same time, Phil is just a day ahead in Australia!)&lt;/p&gt;

&lt;p&gt;We'll see you on Twitch right here: &lt;a href="https://www.twitch.tv/twilio"&gt;https://www.twitch.tv/twilio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>twilio</category>
      <category>twiliohackathon</category>
    </item>
    <item>
      <title>Twilio Office Hours with Phil &amp; Dom</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Thu, 23 Apr 2020 21:58:35 +0000</pubDate>
      <link>https://dev.to/twilio/twilio-office-hours-with-phil-dom-63e</link>
      <guid>https://dev.to/twilio/twilio-office-hours-with-phil-dom-63e</guid>
      <description>&lt;p&gt;We hope your #twiliohackathon projects are going well but we also know that everyone hits a stumbling block at one point and we at Twilio want to make sure you have all the help you might need.&lt;/p&gt;

&lt;p&gt;One way you can seek our help every day is by reaching out to the &lt;a href="https://dev.to/thepracticaldev/twilio-hackathon-help-thread-1jno"&gt;Twilio Hackathon Help Thread&lt;/a&gt; or by requesting access to the DEV connect live chat. &lt;/p&gt;

&lt;p&gt;But if you prefer to see the faces of the people answering your questions, you can also jump onto our weekly office hours on Twitch! Over there &lt;a href="https://dev.to/philnash"&gt;Phil&lt;/a&gt; and &lt;a href="https://dev.to/dkundel"&gt;I&lt;/a&gt; will be chatting hackathons, answering your questions, bounding around ideas and checking out some of the projects people are working on. And if we have some time, we'll be jumping into some live coding ourselves.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Hackathon office hours will be hosted on the &lt;a href="https://twitch.tv/twilio"&gt;Twilio Twitch channel&lt;/a&gt;&lt;/em&gt; at:&lt;/p&gt;

&lt;p&gt;19:00 EDT Thursday 23th April&lt;br&gt;
16:00 PDT Thursday 23th April&lt;br&gt;
09:00 AEST Friday 24th April&lt;/p&gt;

&lt;p&gt;(They're all the same time, Phil is just a day ahead in Australia!)&lt;/p&gt;

&lt;p&gt;We'll see you on Twitch right here: &lt;a href="https://www.twitch.tv/twilio"&gt;https://www.twitch.tv/twilio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>twilio</category>
      <category>twiliohackathon</category>
    </item>
    <item>
      <title>Twilio Office Hours with Phil &amp; Dom</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Wed, 15 Apr 2020 17:47:59 +0000</pubDate>
      <link>https://dev.to/twilio/twilio-office-hours-with-phil-dom-9pk</link>
      <guid>https://dev.to/twilio/twilio-office-hours-with-phil-dom-9pk</guid>
      <description>&lt;p&gt;We hope your #twiliohackathon projects are going well but we also know that everyone hits a stumbling block at one point and we at Twilio want to make sure you have all the help you might need.&lt;/p&gt;

&lt;p&gt;One way you can seek our help every day is by reaching out to the &lt;a href="https://dev.to/thepracticaldev/twilio-hackathon-help-thread-1jno"&gt;Twilio Hackathon Help Thread&lt;/a&gt; or by requesting access to the DEV connect live chat. &lt;/p&gt;

&lt;p&gt;But if you prefer to see the faces of the people answering your questions, you can also jump onto our weekly office hours on Twitch! Over there &lt;a href="https://dev.to/philnash"&gt;Phil&lt;/a&gt; and &lt;a href="https://dev.to/dkundel"&gt;I&lt;/a&gt; will be chatting hackathons, answering your questions, bounding around ideas and checking out some of the projects people are working on. And if we have some time, we'll be jumping into some live coding ourselves.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Hackathon office hours will be hosted on the &lt;a href="https://twitch.tv/twilio"&gt;Twilio Twitch channel&lt;/a&gt;&lt;/em&gt; at:&lt;/p&gt;

&lt;p&gt;19:00 EDT Thursday 16th April&lt;br&gt;
16:00 PDT Thursday 16th April&lt;br&gt;
09:00 AEST Friday 17th April&lt;/p&gt;

&lt;p&gt;(They're all the same time, Phil is just a day ahead in Australia!)&lt;/p&gt;

&lt;p&gt;We'll see you on Twitch right here: &lt;a href="https://www.twitch.tv/twilio"&gt;https://www.twitch.tv/twilio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>twilio</category>
      <category>twiliohackathon</category>
    </item>
    <item>
      <title>Learn How to Contribute to Open Source</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Mon, 21 Oct 2019 16:52:41 +0000</pubDate>
      <link>https://dev.to/twilio/learn-how-to-contribute-to-open-source-57fh</link>
      <guid>https://dev.to/twilio/learn-how-to-contribute-to-open-source-57fh</guid>
      <description>&lt;p&gt;Contributing to an open-source project can often be intimidating. Especially if it is your first contribution. At one point we've all been there. But contributing to open source can also be fun and rewarding once you get through it. We decided to try and help you with your first steps into the world of open source and hopefully make it less intimidating and more fun!&lt;/p&gt;

&lt;p&gt;As a result we are launching today two new projects! The &lt;a href="https://open-pixel-art.com"&gt;Open Pixel Art&lt;/a&gt; project and a brand new &lt;a href="https://twil.io/hacktoberfest-quest"&gt;Twilio Quest mission&lt;/a&gt; focused on taking you step-by-step through your quest into the world of open source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Pixel Art - A Collaborative Art Project
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OBz2QwRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/v05w5m12klybtm4drhfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OBz2QwRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/v05w5m12klybtm4drhfw.png" alt="Open Pixel Art Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One problem doing your first contribution to open source is finding the right project to get started. While there are some great projects that welcome new contributors, we wanted to create something that makes it easy to identify what to contribute.&lt;/p&gt;

&lt;p&gt;We often talk at Twilio about how &lt;em&gt;Code is Creative&lt;/em&gt;. And we love pixel art. In fact at SIGNAL 2017 we created a giant wall of pixels for people to be creative and &lt;a href="https://www.twilio.com/blog/2017/06/drawing-pixel-art-text-messages-signal-video-wall.html"&gt;eventually hack&lt;/a&gt;. Inspired by our love for pixel art, we created the &lt;a href="https://open-pixel-art.com/"&gt;Open Pixel Art&lt;/a&gt; project with the aim to teach people how to contribute to open source while collaborating on an art project.&lt;/p&gt;

&lt;p&gt;The project is based on a few basic principles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every user on GitHub can contribute exactly one pixel with a color of their choice.&lt;/li&gt;
&lt;li&gt;Pixels can never be removed.&lt;/li&gt;
&lt;li&gt;Pixels can be layered. (Your pixel will live on in the project even if it might be layered on the canvas. Who knows, maybe we go 3D at one point?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To contribute a pixel to the project, you'll have to create a pull request where you add your pixel with its coordinates to the &lt;code&gt;_data/pixels.json&lt;/code&gt; file of the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  "data": [
    {"y": 1, "x": 3, "color": "#F22F46", "username": "twilio-labs"},
&lt;span class="gi"&gt;+    { "y": 1, "x": 4, "color": "#FFFF00", "username": "dkundel"},
&lt;/span&gt;    {"y": 2, "x": 9, "color": "#F22F46", "username": "twilio"},
    ...
  ]
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C2ptnkk3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/psnz1dmscttozmnf128h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C2ptnkk3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/psnz1dmscttozmnf128h.png" alt="Screenshot of merged pull request on GitHub for the Open Pixel Art project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you create your pull request for the &lt;a href="https://github.com/twilio-labs/open-pixel-art"&gt;project on GitHub&lt;/a&gt;, a few bots will kick off to validate your pull request. We wanted to make the experience of creating a pull request as gratifying for you as possible. That means if you only contributed a pixel change and all your checks passed, a bot will automatically merge your pull request.&lt;/p&gt;

&lt;p&gt;After your pull request has been merged by the Mergify bot, Netlify will automatically deploy the changes and you should be able to see your contributions a few minutes later on &lt;a href="https://open-pixel-art.com"&gt;open-pixel-art.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn more about the project and how to contribute, make sure to head over to the &lt;a href="https://github.com/twilio-labs/open-pixel-art"&gt;project on GitHub&lt;/a&gt; and check out the &lt;a href="https://github.com/twilio-labs/open-pixel-art/blob/master/CONTRIBUTING.md"&gt;contributing guide&lt;/a&gt;! But if you want to be guided step-by-step through your journey into open source, don't worry! We created a special &lt;a href="https://twil.io/hacktoberfest-quest"&gt;TwilioQuest&lt;/a&gt; mission just for you!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/5jT0jaNDsM6Ik7X9yq/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/5jT0jaNDsM6Ik7X9yq/giphy.gif" alt="gif of colorful confetti flying around"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Embark on Your Personal Open Source Quest
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4wv8oBnY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ph7nb75ln0jfz1hy28zu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4wv8oBnY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ph7nb75ln0jfz1hy28zu.png" alt="Screenshot of Open Source mission picker in TwilioQuest"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Open Pixel Art project might take away the burden of finding the right project to contribute to. But if you've never contributed to an open-source project or are new to things like &lt;a href="https://git-scm.com/"&gt;git&lt;/a&gt; and &lt;a href="https://www.github.com/"&gt;GitHub&lt;/a&gt;, it might still be intimidating to you.&lt;/p&gt;

&lt;p&gt;For that reason we created a special mission in &lt;a href="https://twil.io/hacktoberfest-quest"&gt;TwilioQuest&lt;/a&gt;, our game aiming to teach you various Twilio and coding related concepts in a fun and engaging way. The mission will guide you through contributing to the Open Pixel Art project from signing up to GitHub, over what a fork or pull request is, all the way to getting your pull request merged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h5LVFJ4z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bdlo2pwidx8yg8cx44qj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h5LVFJ4z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bdlo2pwidx8yg8cx44qj.png" alt="Screenshot of TwilioQuest inside the Open Source mission"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Throughout your quest, we'll make sure to help you to have your development environment set up, validate that your fork is working, award you experience points and you can equip your TwilioQuest character!&lt;/p&gt;

&lt;p&gt;And after your mission you'll hopefully be equipped to explore the wide world of open source and contribute to more projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  We Can't Wait to See What You Contribute!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/120jXUxrHF5QJ2/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/120jXUxrHF5QJ2/giphy.gif" alt="gif of two people high fiving"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whether this is your first or hundredth open-source contribution, we are excited to be part of your journey. And remember, a contribution doesn't always have to be about code, some of the most valuable contributions to a project are often not code related.&lt;/p&gt;

&lt;p&gt;If you have any questions about the Open Pixel Art project or as you embark on your open-source quest, feel free to create a &lt;a href="https://github.com/twilio-labs/open-pixel-art/issues"&gt;GitHub issue&lt;/a&gt; or reach out to me directly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/dkundel"&gt;@dkundel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="//mailto:dkundel@twilio.com"&gt;dkundel@twilio.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/dkundel"&gt;dkundel&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Open Source Tips from Maintainers for Maintainers</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Fri, 18 Oct 2019 19:36:48 +0000</pubDate>
      <link>https://dev.to/twilio/open-source-tips-from-maintainers-for-maintainers-3obb</link>
      <guid>https://dev.to/twilio/open-source-tips-from-maintainers-for-maintainers-3obb</guid>
      <description>&lt;p&gt;Over the last few years open source has become increasingly more popular. With initiatives such as Hacktoberfest or 24 Pull Requests there are plenty of initiatives to drive more contributions in open source. One thing that people often tend to forget though are the pains and challenges that maintainers often face, especially if your project is rapidly growing or you are new to maintaining a project. And when you search the internet, the resources for maintainers are often limited.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Maintainers for Maintainers
&lt;/h2&gt;

&lt;p&gt;This year for Hacktoberfest, Twilio decided to kick off a series of blog posts from various maintainers of large open-source projects and communities to share learnings and tips with the community and other maintainers. &lt;/p&gt;

&lt;p&gt;Throughout October, we are publishing one maintainer tip blog post every Wednesday. You can find them all by heading over to the &lt;a href="https://www.twilio.com/blog/tag/maintainer-tips"&gt;Twilio Blog&lt;/a&gt; but we wanted to give you a quick summary of each of these blog posts and we'll update this list as they are being published.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.twilio.com/blog/aligning-intention-open-source"&gt;Aligning with Intention in Open Source&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this blog post &lt;a href="https://twitter.com/outofambit"&gt;&lt;em&gt;Evelyn Masso&lt;/em&gt;&lt;/a&gt; is sharing one of her key learnings during her &lt;a href="https://processingfoundation.org/fellowships"&gt;Processing Foundation fellowship&lt;/a&gt; working on the &lt;a href="https://p5js.org/"&gt;p5.js&lt;/a&gt; project. Contributing is great but how do you make sure your contributions are in line with the project’s goals?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twilio.com/blog/aligning-intention-open-source"&gt;Read Evelyn's post on the Twilio blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.twilio.com/blog/10-lessons-learned-maintaining-open-source-community"&gt;10 lessons I learned from maintaining an open source community for 4 years&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Five years ago &lt;a href="https://twitter.com/lpnotes"&gt;&lt;em&gt;Linda Peng&lt;/em&gt;&lt;/a&gt; started the open source community &lt;a href="https://codebuddies.org/"&gt;CodeBuddies&lt;/a&gt; to &lt;em&gt;find remote running partners for code&lt;/em&gt;. In this blog post she's sharing 10 of her key lessons learned during the last years working on CodeBuddies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twilio.com/blog/10-lessons-learned-maintaining-open-source-community"&gt;Read Linda's post on the Twilio blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.twilio.com/blog/designing-enforcing-codes-of-conduct"&gt;Designing and Enforcing Code of Conducts&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Having a Code of Conduct in your open source project or community is becoming the de-facto standard with various projects providing easy to use templates. In this blog post, &lt;a href="https://twitter.com/maybekatz"&gt;&lt;em&gt;Kat Marchán&lt;/em&gt;&lt;/a&gt; shares learnings from their time founding communities like &lt;a href="https://lgbtq.technology"&gt;lgbtq.technology&lt;/a&gt; and &lt;a href="https://wealljs.org/"&gt;WeAllJS&lt;/a&gt; and maintaining various open-source projects. In this post, you’ll learn why having a clear enforcing process is key to great communities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twilio.com/blog/designing-enforcing-codes-of-conduct"&gt;Read Kat's post on the Twilio blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.twilio.com/blog/how-to-hacktoberfest-tips-and-tricks-for-maintaining-your-repo-and-your-mental-health"&gt;How to Hacktoberfest: Tips and Tricks for Maintaining your Repo and your Mental Health&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Hacktoberfest can be a wonderful and hectic time depending on how many contributions your projects gets during this time. In this blog post &lt;a href="https://github.com/Whatthefoxsays"&gt;Carly Vanderwert&lt;/a&gt; from the Twilio Developer Education team is sharing her top tips and tricks she learned from maintaining the &lt;a href="https://github.com/sendgrid/docs"&gt;SendGrid docs&lt;/a&gt; project. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twilio.com/blog/how-to-hacktoberfest-tips-and-tricks-for-maintaining-your-repo-and-your-mental-health"&gt;Read Carly's post on the Twilio blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More to Come
&lt;/h2&gt;

&lt;p&gt;We hope that this series of blog posts can be helpful for other maintainers but ultimately we want to hear from you what you would like to learn more about! So feel free to share your feedback below this post or by sending me an email to &lt;a href="//mailto:dkundel@twilio.com"&gt;dkundel@twilio.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Creating a virtual photo booth using Twilio, WhatsApp &amp; Cloudinary</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Fri, 06 Sep 2019 19:04:21 +0000</pubDate>
      <link>https://dev.to/twilio/creating-a-virtual-photo-booth-using-twilio-whatsapp-cloudinary-3o0m</link>
      <guid>https://dev.to/twilio/creating-a-virtual-photo-booth-using-twilio-whatsapp-cloudinary-3o0m</guid>
      <description>&lt;p&gt;If you've ever been to Berlin, chances are high that you've seen multiple photo booths in bars and on the street. Berlin and photo booths just belong together. This year for &lt;a href="https://2019.jsconf.eu/" rel="noopener noreferrer"&gt;JSConf EU&lt;/a&gt; we wanted to build our own virtual photo booth, powered by &lt;a href="https://www.twilio.com/whatsapp" rel="noopener noreferrer"&gt;Twilio for WhatsApp&lt;/a&gt;. In this post, we'll look at how we built the digital part of the photo booth using &lt;a href="https://www.twilio.com/" rel="noopener noreferrer"&gt;Twilio&lt;/a&gt; and &lt;a href="https://cloudinary.com/" rel="noopener noreferrer"&gt;Cloudinary&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's build a purely digital version of this photo booth where when a person sends in an image, we'll perform some manipulations on that picture and send it back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we get started, make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Twilio account (&lt;a href="https://www.twilio.com/try-twilio" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The WhatsApp Sandbox Channel installed (&lt;a href="https://www.twilio.com/docs/sms/whatsapp/api" rel="noopener noreferrer"&gt;learn how to activate your WhatsApp sandbox&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloudinary.com/signup" rel="noopener noreferrer"&gt;A free Cloudinary account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you prefer to view the next steps as a video to follow along, make sure to &lt;a href="https://www.youtube.com/watch?v=Rjh_b7MsB4Q" rel="noopener noreferrer"&gt;check out this video on YouTube&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Rjh_b7MsB4Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Your WhatsApp Number
&lt;/h2&gt;

&lt;p&gt;When a person sends a picture to our WhatsApp number (or Sandbox for that matter), Twilio will trigger a &lt;a href="https://www.youtube.com/watch?v=aLjSNfoJCYc" rel="noopener noreferrer"&gt;webhook request&lt;/a&gt; that we'll have to receive. We could use any HTTP server for this, but in our case we'll use a &lt;a href="https://www.twilio.com/functions" rel="noopener noreferrer"&gt;Twilio Function&lt;/a&gt;. This allows us to host a serverless HTTP endpoint using Node.js.&lt;/p&gt;

&lt;p&gt;Inside the &lt;a href="https://www.twilio.com/console/runtime/functions/manage" rel="noopener noreferrer"&gt;Twilio Console&lt;/a&gt;, head to the &lt;a href="https://www.twilio.com/console/runtime/functions/manage" rel="noopener noreferrer"&gt;Functions section&lt;/a&gt; and create a new Twilio Function with the "Hello SMS" template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Ff0R0eYtrR0gO9TzL_Zmur8UgLr3fQ7yFkWf31JfjF5nRc5.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Ff0R0eYtrR0gO9TzL_Zmur8UgLr3fQ7yFkWf31JfjF5nRc5.width-500.png" alt="screenshot of Twilio Functions "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you created your new Function, give it a name like "WhatsApp Photobooth" and a path such as &lt;code&gt;/photo&lt;/code&gt;. Make sure to save the changes and copy the path to your Twilio Function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FdQGLYaSbdPhMySFGWlrkj8fCxDAqPotzAM1ryebBtWdi5c.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FdQGLYaSbdPhMySFGWlrkj8fCxDAqPotzAM1ryebBtWdi5c.width-500.png" alt="Screenshot of the UI of a Function indicating to give the function a name and a path, save and copy the path"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a new tab, head over to the &lt;a href="https://www.twilio.com/console/sms/whatsapp/sandbox" rel="noopener noreferrer"&gt;WhatsApp sandbox configuration screen&lt;/a&gt; and set the URL for "When a message comes in" to the path of your Twilio Function. Scroll all the way to the bottom to save the changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F3Z8cjgqvwU0uM_FIZ5Lz6LCFw5wvgLpYs0ddBMJTsImCHk.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F3Z8cjgqvwU0uM_FIZ5Lz6LCFw5wvgLpYs0ddBMJTsImCHk.width-500.png" alt="Screenshot of the Twilio WhatsApp sandbox indicating to paste your Functions URL into the webhook field"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can test if everything is properly set up by texting any message to your WhatsApp sandbox. The response should always be "Hello World".&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiving the Picture
&lt;/h2&gt;

&lt;p&gt;Now that we have our Twilio Function wired up, let's see how we can retrieve an image when we sent one.&lt;/p&gt;

&lt;p&gt;When Twilio makes the HTTP request to your webhook, it will send a set of info around your message as part of that request. In Twilio Functions we can access these via the &lt;code&gt;event&lt;/code&gt; object that is passed to our Function.&lt;/p&gt;

&lt;p&gt;Specifically in our case the &lt;code&gt;event.MediaUrl0&lt;/code&gt; is of interest because it will contain the URL of our image if one has been sent with the message. We might also have &lt;code&gt;event.MediaUrl1&lt;/code&gt; to &lt;code&gt;event.MediaUrl9&lt;/code&gt; available if more images have been sent but in our case we'll focus on the first one.&lt;/p&gt;

&lt;p&gt;For now, we'll just log the URL, modify your Twilio Function accordingly and hit save:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MediaUrl0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Twilio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MessagingResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterwards, send in a picture to the sandbox and check the logs at the bottom of your Function. You should see a URL logged. Press the "copy" button to copy the URL and open it in another tab and you can see the image you've sent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FJVi-Id6B3LNazMWgGZWDIj6yuDvIKAhoCDf8JHiVKXlpnl.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FJVi-Id6B3LNazMWgGZWDIj6yuDvIKAhoCDf8JHiVKXlpnl.width-500.png" alt="Screenshot of the Function logs pointing at the URL of the image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we can access the sent image. Let's see how we can modify it using Cloudinary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manipulating the Picture
&lt;/h2&gt;

&lt;p&gt;Cloudinary is a platform for image management and manipulation. It's great for our use case because we'll want to do some image manipulation on our picture. We'll also need a URL that we can give Twilio to send the resulting image. Cloudinary combines both of these in one platform.&lt;/p&gt;

&lt;p&gt;Start by installing the &lt;a href="https://npm.im/cloudinary" rel="noopener noreferrer"&gt;&lt;code&gt;cloudinary&lt;/code&gt;&lt;/a&gt; SDK as a dependency and setting your Cloudinary credentials. Go to the &lt;em&gt;Configure&lt;/em&gt; page of your Twilio Functions and in the &lt;em&gt;Environment Variables&lt;/em&gt; section, add your &lt;code&gt;CLOUDINARY_URL&lt;/code&gt; from the &lt;a href="https://cloudinary.com/console" rel="noopener noreferrer"&gt;Cloudinary Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FNfrB7Cn78OL6SH3al86EtiB5royRgauMt95-zSHWo8ZD-Q.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FNfrB7Cn78OL6SH3al86EtiB5royRgauMt95-zSHWo8ZD-Q.width-500.png" alt="Screenshot of the Cloudinary dashboard highlighting the URL starting with cloudinary://"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FOL5hSEsHB9WepXT-mh7BqNABur8Sy6saapXqDlnGBK6Zj-.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FOL5hSEsHB9WepXT-mh7BqNABur8Sy6saapXqDlnGBK6Zj-.width-500.png" alt="Screenshot of the environment variables in Twilio Functions to indicate pasting your Cloudinary URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterwards, scroll to the &lt;em&gt;Dependencies&lt;/em&gt; section and add &lt;code&gt;cloudinary&lt;/code&gt; with the version &lt;code&gt;*&lt;/code&gt; to install the latest version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FDQYD0RK0NcfJg_39R4vLxZtD5LCf5LiZfllq70v5CVgKmV.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FDQYD0RK0NcfJg_39R4vLxZtD5LCf5LiZfllq70v5CVgKmV.width-500.png" alt="Screenshot of the Dependencies section of Twilio Functions with cloudinary installed with version *"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you are done with both, hit save to apply the changes.&lt;/p&gt;

&lt;p&gt;Now that we have the Cloudinary SDK all set-up, it's time to work on the image manipulation. In our case we'll want to do the following to the picture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the aspect ratio to a 3x4 picture.&lt;/li&gt;
&lt;li&gt;Adjust the height to 1600px&lt;/li&gt;
&lt;li&gt;Apply an overlay on top. In our case, it's going to be &lt;a href="https://i.imgur.com/cS1zGMO.png" rel="noopener noreferrer"&gt;this overlay&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FjZMCGeg4IrrPAV5Kl3PFMRsu9mlaKxRX1dLNDZmhfjyTNi.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FjZMCGeg4IrrPAV5Kl3PFMRsu9mlaKxRX1dLNDZmhfjyTNi.width-500.png" alt="Picture of the image overlay we'll use with a drop shadow to highlight the white parts of the picture better"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we can start with the image manipulation, you'll have to upload the overlay to your Cloudinary media library. You can either use your own in the size 1200px width by 1600px height or &lt;a href="https://i.imgur.com/cS1zGMO.png" rel="noopener noreferrer"&gt;download one here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Upload it to the Cloudinary Media library and give it a name of &lt;code&gt;overlay-photo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Fnt7PrcYmIRlz-v2F2JxqdbPsW7SUSQMp2TTPXqEMQ9wlh-.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Fnt7PrcYmIRlz-v2F2JxqdbPsW7SUSQMp2TTPXqEMQ9wlh-.width-500.png" alt="Screenshot of the Cloudinary Media Library to show where to rename the picture"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Cloudinary uses the concept of &lt;a href="https://cloudinary.com/documentation/image_transformations" rel="noopener noreferrer"&gt;transformations&lt;/a&gt; to manipulate an image and comes with a wide variety of options. It also supports &lt;em&gt;eager transforms&lt;/em&gt;. That means we can pass a set of transformations to it during image upload to tell it which transformations it should have readily cached. You can learn about the various &lt;a href="https://cloudinary.com/documentation/image_transformations" rel="noopener noreferrer"&gt;available transforms in the Cloudinary docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our situation the transformations convert to the following in JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cloudinaryTransforms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;transformation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;aspect_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;overlay-photo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;relative&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the Cloudinary API is callback based, we'll use the built-inbuilt in &lt;code&gt;promisify&lt;/code&gt; method to enable the use of async/await with this API.&lt;/p&gt;

&lt;p&gt;During the upload, we'll also have to assign the photo a public ID which acts as a name. We'll use the ID of your sent message (&lt;code&gt;MessageSid&lt;/code&gt;) for this one as it's a good unique identifier.&lt;/p&gt;

&lt;p&gt;As a result of the upload, we'll be able to retrieve the URL of the &lt;code&gt;eager&lt;/code&gt; transform. We can then use that to set the &lt;a href="https://www.twilio.com/docs/sms/twiml/message?code-sample=code-sending-of-an-message-with-media-mms-3&amp;amp;code-language=Node.js&amp;amp;code-sdk-version=3.x" rel="noopener noreferrer"&gt;&lt;code&gt;media&lt;/code&gt;&lt;/a&gt; on our response Messaging TwiML.&lt;/p&gt;

&lt;p&gt;Update your Twilio Function to contain the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cloudinary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloudinary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;util&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cloudinary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uploader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cloudinaryTransforms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;transformation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;aspect_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;overlay-photo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;relative&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Twilio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MessagingResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MediaUrl0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please send an image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;uploadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MediaUrl0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;public_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MessageSid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;eager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cloudinaryTransforms&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eager&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;secure_url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thanks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;media&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press &lt;em&gt;Save&lt;/em&gt; to deploy your changes.&lt;/p&gt;

&lt;p&gt;Now that you have the changes deployed, text a picture into your WhatsApp sandbox number and you should get as a response with the transformed picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FQb5UdYA7N3VHeku8Uyjx4AskrcwPb1VDrC81gjsrkdToSnS3yrQeZlOFJ_hzFdXCWGjHTWeE2v57g9" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FQb5UdYA7N3VHeku8Uyjx4AskrcwPb1VDrC81gjsrkdToSnS3yrQeZlOFJ_hzFdXCWGjHTWeE2v57g9" alt="animated GIF showing the response in WhatsApp and clicking on the image to enlarge it"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Congratulations, you've built your own digital photo booth powered by Twilio, WhatsApp, and Cloudinary. But your journey with Twilio doesn't have to be over. Why don't you check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/twilio/build-whatsapp-bots-with-twilio-autopilot-3b5o-temp-slug-5367350"&gt;Learn how you can use Twilio Autopilot to build WhatsApp bots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.twilio.com/blog/2018/08/build-npm-search-bot-whatsapp-twilio.html" rel="noopener noreferrer"&gt;How to build an npm search bot with Twilio and WhatsApp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.twilio.com/quest/" rel="noopener noreferrer"&gt;Jump into your own TwilioQuest adventure and learn in an interactive game how to use Twilio's APIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you have any questions or want to show me what you built, feel free to contact me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/dkundel?lang=en" rel="noopener noreferrer"&gt;@dkundel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="//mailto:dkundel@twilio.com"&gt;dkundel@twilio.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/dkundel" rel="noopener noreferrer"&gt;dkundel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dkundel.com/" rel="noopener noreferrer"&gt;dkundel.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>twilio</category>
    </item>
    <item>
      <title>SMS Forwarding and Responding Using Twilio and JavaScript</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Wed, 20 Mar 2019 20:07:21 +0000</pubDate>
      <link>https://dev.to/twilio/sms-forwarding-and-responding-using-twilio-and-javascript-2175</link>
      <guid>https://dev.to/twilio/sms-forwarding-and-responding-using-twilio-and-javascript-2175</guid>
      <description>&lt;p&gt;There are a variety of reasons why you sometimes don't want to give out your phone number to people but still want to receive SMS and be able to reply. Maybe you are trying to sell something on the internet, maybe you want to set up a way for people to report code of conduct violations at an event, or maybe you just don't trust the newly met person that asked for your number. In the past I showed how you can quickly &lt;a href="https://www.twilio.com/blog/2016/11/set-up-an-sms-forwarding-number-in-5-minutes-with-twilio.html" rel="noopener noreferrer"&gt;set up a message forwarding with practically no coding using TwiML Bins&lt;/a&gt;. However, it doesn't let you respond using that number. Let's take a look at how we can change that using Twilio Functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Twilio Function
&lt;/h2&gt;

&lt;p&gt;Before we get started, make sure you have a Twilio account. Sign up here for free: &lt;a href="http://www.twilio.com/try-twilio" rel="noopener noreferrer"&gt;www.twilio.com/try-twilio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you are logged in, head to the &lt;a href="https://www.twilio.com/console/runtime/functions/manage" rel="noopener noreferrer"&gt;Functions&lt;/a&gt;&lt;a href="https://www.twilio.com/console/runtime/functions/manage" rel="noopener noreferrer"&gt;section&lt;/a&gt; of the Runtime part of the &lt;a href="https://www.twilio.com/console/runtime/functions/manage" rel="noopener noreferrer"&gt;Twilio Console&lt;/a&gt;. Create a new Twilio Function and choose the "Hello SMS" template.&lt;/p&gt;

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

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

&lt;p&gt;Change the name of the Twilio Function to something that gives you a hint on what it does. I'll name mine "My SMS Forwarder" and give it the path &lt;code&gt;/forward-sms&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Right now our Function is just an auto-responder returning "Hello World". In order to actually forward SMS similar to our previous blog post, update the code the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_NUMBER_HERE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Twilio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MessagingResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;From&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to replace &lt;code&gt;YOUR_NUMBER_HERE&lt;/code&gt; with the phone number you want the incoming SMS forwarded to.&lt;/p&gt;

&lt;p&gt;In Twilio Functions we can access webhook data such as the &lt;code&gt;From&lt;/code&gt; number or the message &lt;code&gt;Body&lt;/code&gt; using &lt;code&gt;event.&lt;/code&gt;. The new &lt;code&gt;twiml.message&lt;/code&gt; line will now return the TwiML needed to forward an SMS to the specified number, containing the number of the person who sent it and the original message body.&lt;/p&gt;

&lt;p&gt;Save the code by clicking the "Save" button. Head to the &lt;a href="https://www.twilio.com/console/phone-numbers/incoming" rel="noopener noreferrer"&gt;Phone Numbers section in the Twilio Console&lt;/a&gt; and pick the number that you want to use for SMS forwarding or buy a new one.&lt;/p&gt;

&lt;p&gt;Once you are in the configuration screen, scroll to the bottom of the page, and under 'A message comes in' select the value "Function", and then the name of your Function. In my case that's "My SMS Forwarder". &lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbyhv7pslnv73hrjfe4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbyhv7pslnv73hrjfe4a.png" width="500" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterwards click "Save" and grab your phone to text any message to it. You should see a reply with your phone number and the message you sent:&lt;/p&gt;

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

&lt;p&gt;If you want to see if it properly works, ask a friend or colleague to text your Twilio number and you should see their message. Alternatively get a second Twilio number and use the &lt;a href="https://www.twilio.com/console/runtime/api-explorer/sms/messages/create" rel="noopener noreferrer"&gt;API Explorer's "Message Create" functionality&lt;/a&gt; to send an SMS to your forwarding number.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx44q0e6k1s8dk2yalko7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx44q0e6k1s8dk2yalko7.png" width="500" height="429"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ilgarudi8hmkpizbs5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ilgarudi8hmkpizbs5w.png" width="500" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Responding to Messages
&lt;/h3&gt;

&lt;p&gt;Now that we have the message forwarding solved, how do we reply to those messages? If you want to respond with your actual number, that's easy, copy the number from the SMS and write them from your phone. If you want to keep on using your masked number it's not quite that easy.&lt;/p&gt;

&lt;p&gt;Right now if you reply to any SMS it will trigger the same SMS webhook and basically just echo to you. We'll modify this behavior by adding the following logic to this:&lt;/p&gt;

&lt;p&gt;Check if the message came from our own number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Came from someone else -&amp;gt; Forward the SMS like we previously did&lt;/li&gt;
&lt;li&gt;Message is from us -&amp;gt; Parse message to receive intended recipient and forward the message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to find out the intended recipient, we'll establish a certain pattern that all of our responses have to follow. It will be the same way that we are currently forwarding messages:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RECIPIENT_NUMBER: MESSAGE_BODY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Update your Twilio Function code to apply this logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_NUMBER_HERE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Twilio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MessagingResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;From&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;separatorPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;separatorPosition&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You need to specify a recipient number and a ":" before the message.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recipientNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;separatorPosition&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messageBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;separatorPosition&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;recipientNumber&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;messageBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;From&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click save and wait until the updated Function is deployed (there will be a green box saying the deployment was successful).&lt;/p&gt;

&lt;p&gt;Grab your phone and try to send an SMS to a friend or your other Twilio number. The SMS has to be in the format &lt;code&gt;+RECEIPIENT_NUMBER: message&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;The other person should receive only the text you sent. If you sent it to another Twilio number, &lt;a href="https://www.twilio.com/console/sms/logs" rel="noopener noreferrer"&gt;check your messaging logs&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;You can also try sending a text that doesn't fit the format and you should receive a reply that the message is not appropriately formatted.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Congratulations!
&lt;/h3&gt;

&lt;p&gt;That's it. You are all set up with an SMS forwarding number that you can use whenever you don't want to give out your normal phone number. But this is really just the start. With &lt;a href="https://www.twilio.com/functions" rel="noopener noreferrer"&gt;Twilio Functions&lt;/a&gt; you have access to the npm ecosystem. So why not hook up a &lt;a href="https://www.twilio.com/blog/2017/03/google-spreadsheets-and-javascriptnode-js.html" rel="noopener noreferrer"&gt;Google Spreadsheet&lt;/a&gt; or the API of your preferred contacts host to look up names instead of having to write down the phone number to respond. Or create a list of blocked phone numbers. Or maybe you have a completely different idea, I would love to hear what you come up with.&lt;/p&gt;

&lt;p&gt;Feel free to reach out to me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email: &lt;a href="//mailto:dkundel@twilio.com"&gt;dkundel@twilio.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/dkundel?lang=en" rel="noopener noreferrer"&gt;@dkundel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/dkundel" rel="noopener noreferrer"&gt;dkundel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Web: &lt;a href="https://dkundel.com/" rel="noopener noreferrer"&gt;dkundel.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>twilio</category>
      <category>sms</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Building an Intelligent Coffee Order System with Twilio Autopilot</title>
      <dc:creator>Dominik Kundel</dc:creator>
      <pubDate>Mon, 18 Mar 2019 18:39:27 +0000</pubDate>
      <link>https://dev.to/twilio/building-an-intelligent-coffee-order-system-with-twilio-autopilot-7og</link>
      <guid>https://dev.to/twilio/building-an-intelligent-coffee-order-system-with-twilio-autopilot-7og</guid>
      <description>&lt;p&gt;Wouldn't it be great if you could save daily a few, maybe awkward, interactions with other humans and let bots take care of it instead? However, often these bots are not too intelligent when it comes to interacting with you. In this blog post we'll learn how we can build a smarter SMS bot in just a few minutes.&lt;/p&gt;

&lt;p&gt;In a previous blog post we talked about how we love to serve coffee at conferences and other events "Twilio-Style" by allowing attendees to order their coffee via SMS. If you haven't read the blog post, make sure to check out &lt;a href="https://www.twilio.com/blog/2018/03/serving-coffee-with-sms-and-react.html" rel="noopener noreferrer"&gt;Serving Coffee with Twilio Programmable SMS and React&lt;/a&gt;. Unfortunately we had a fairly rudimentary way of handling the orders. Until now.&lt;/p&gt;

&lt;p&gt;Let's see how we can upgrade this existing project using Twilio Autopilot to be truly intelligent.&lt;/p&gt;

&lt;p&gt;If you would prefer to see how this works by watching a video, here is our &lt;a href="https://www.youtube.com/watch?v=gOOrvhbJ9No" rel="noopener noreferrer"&gt;tutorial on YouTube&lt;/a&gt;:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gOOrvhbJ9No"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Before we get started, make sure you have your setup ready. If you've performed the steps in our previous blog post, you are all set. If you haven't, make sure to check out "&lt;a href="https://www.twilio.com/blog/2018/03/serving-coffee-with-sms-and-react.html" rel="noopener noreferrer"&gt;Serving Coffee with Twilio Programmable SMS and React&lt;/a&gt;". Alternatively follow the setup instructions in the &lt;code&gt;README&lt;/code&gt; of the &lt;a href="https://github.com/dkundel/barista-lite" rel="noopener noreferrer"&gt;Barista Lite GitHub project&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your Personal Coffee Assistant
&lt;/h2&gt;

&lt;p&gt;In order to get started with Twilio Autopilot, we'll have to create a new "Assistant". For this head to the &lt;a href="https://www.twilio.com/console/autopilot/list" rel="noopener noreferrer"&gt;Autopilot section of the Twilio Console&lt;/a&gt; and create a new Assistant. You can give the assistant any name. I'll name mine "CoffeeBot" for now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F49hWq7ZmrekGOB9Z8U4V5ZeWudwozNDPaG3U-t1yAErFNN.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F49hWq7ZmrekGOB9Z8U4V5ZeWudwozNDPaG3U-t1yAErFNN.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once created let's make sure we wire it up to our phone number to start testing the out-of-the-box experience. Click on "Channels" on the left side and choose "Programmable Messaging".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F9P5-R320tIvGzPkzz8F3P3ADZq49A3Nf0_ztI4uCgtUmpQ.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F9P5-R320tIvGzPkzz8F3P3ADZq49A3Nf0_ztI4uCgtUmpQ.width-500.png"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FUsACrs-1LdTAltmQjlpr2N2zWeefBKriL1dNc79lxAi00w.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FUsACrs-1LdTAltmQjlpr2N2zWeefBKriL1dNc79lxAi00w.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see a URL there. Copy it and go to your phone number in the &lt;a href="https://www.twilio.com/console/phone-numbers" rel="noopener noreferrer"&gt;Twilio Console Phone Numbers section&lt;/a&gt; and update the "When a message comes in" webhook to the URL you copied and make sure to press Save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FiI_1-681QCN7ieoc8nwQxVBxAOy9z2Vl1isemiMsYswQVW.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FiI_1-681QCN7ieoc8nwQxVBxAOy9z2Vl1isemiMsYswQVW.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once saved, take your phone and send any message to your number. You should see as a reply "This is your new Task".&lt;/p&gt;

&lt;p&gt;This message comes from the default task that has been created when you created your assistant. But what is a Task?&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Tasks, Samples, Fields, Models, ...???
&lt;/h2&gt;

&lt;p&gt;When you start working with Autopilot and you haven't worked with any Natural Language Processing before, there might be lots of new terms that might be confusing for you. So let's try to clear these up a bit more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tasks:&lt;/strong&gt; These are different units of work that you want to perform. Autopilot allows you to perform different "actions" inside a task. Those could be things like "say" to communicate a message to the user, "handoff" to forward the communication to a human, "redirect" to ping a webhook to decide what to do next, "collect" to gather a bunch of data, or many more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Samples:&lt;/strong&gt;   In order to let Autopilot understand when to trigger which task we need to provide it with sample statements and map these against the existing tasks. The more samples you have per task, the more intelligently your bot will be able to route your user to the right task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fields:&lt;/strong&gt; Sometimes your samples are not fully static. For example a sample like "I would like to have one espresso" has some important pieces of info that you want to extract that might vary from user to user. Say the quantity and the type of coffee are actually fields in this sample. We'll later look at how we can work with them and the different available Field Types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Models:&lt;/strong&gt;  Every time you modify these parts of your Autopilot assistant, you'll have to rebuild a new model. You can imagine a model as a giant "smart" decision tree that is the outcome of all the info you gave your assistant. The more info you give it, the more complex and smarter your model gets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating your First Task
&lt;/h2&gt;

&lt;p&gt;In order to see your existing tasks and create new ones, click on the &lt;a href="https://www.twilio.com/console/autopilot/CoffeeBot/tasks" rel="noopener noreferrer"&gt;"Task Builder" section&lt;/a&gt; of your assistant. You'll see one existing task there already called "hello_world". It also has some labels attached to it to signalize that it has been configured as the &lt;code&gt;Fallback&lt;/code&gt;, &lt;code&gt;Initiation&lt;/code&gt; and &lt;code&gt;OnFailure&lt;/code&gt; task. If you want to understand what these all mean or change one of them, click on the "Defaults" tab in the Tasks view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FbOy5avgMYP0lGYYvJilNyoz1GHQJA3shORznw1z2hbUhBF.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FbOy5avgMYP0lGYYvJilNyoz1GHQJA3shORznw1z2hbUhBF.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of creating a task from scratch, let's start by modifying this one. Click on the task and you'll see a code editor pop up that contains the following JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"say"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is your new Task"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside it you can see it shows the exact text we received earlier. Let's modify it to have a more friendly greeting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"say"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi there! Thanks for reaching out to your friendly Coffee Bot. Please let me know what you would like to order."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"listen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we changed the text behind the "say" key but also added a second action called "listen" to tell Autopilot that it should keep the session open. After modifying the JSON, hit save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FcJ5p8Phj__TGermuE-aBvY5V2e_Zh3Tk6FJgm3GDdUqAMJ.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FcJ5p8Phj__TGermuE-aBvY5V2e_Zh3Tk6FJgm3GDdUqAMJ.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next let's add some samples to trigger this task. Go to the &lt;a href="https://www.twilio.com/console/autopilot/CoffeeBot/router" rel="noopener noreferrer"&gt;"Natural Language Router" section&lt;/a&gt; and click on the expand button next to the text field. This way we can add multiple samples at once by adding them on different lines. Feel free to add whatever sample sentences you want or copy the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hey there
hi
what's up
hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the &lt;code&gt;hello_world&lt;/code&gt; task next to it and press the "+" button to add them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FFaf81oe0R0sCEeJXMYKozA1UL57RE_LdzZ_cI3_EmflWEz.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FFaf81oe0R0sCEeJXMYKozA1UL57RE_LdzZ_cI3_EmflWEz.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After doing all these changes we need to create a new model. Go to the &lt;a href="https://www.twilio.com/console/autopilot/CoffeeBot/router/model-builds" rel="noopener noreferrer"&gt;"Build Models" tab&lt;/a&gt; and create a new Model Build with a name like "v0.0.1".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Fhry2KwfbeZPRAtIzXb9DHzVx-ofPU-TNwJZkXasJdXBMIU.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Fhry2KwfbeZPRAtIzXb9DHzVx-ofPU-TNwJZkXasJdXBMIU.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your model's status changes to "Completed" your bot is ready to be tested.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FC-tFP-Quat8QSN9CVFNKXdGUZ8GNN8d3_lc1CQmyknzwmq.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FC-tFP-Quat8QSN9CVFNKXdGUZ8GNN8d3_lc1CQmyknzwmq.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this text anything you want to your number and you should see an updated message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FPhoto_20.02.19_18_38_20.width-500.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FPhoto_20.02.19_18_38_20.width-500.jpg" alt="Screenshot of Autopilot welcome message"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Dynamic Task
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FMs1HxAWtbxB7kM9bNbClZvK_p7n_S8-FM7qzbAQxPTn8ifIuAT-4v5xiMIOPuhOLSEyLx6jJZ8zm5a" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FMs1HxAWtbxB7kM9bNbClZvK_p7n_S8-FM7qzbAQxPTn8ifIuAT-4v5xiMIOPuhOLSEyLx6jJZ8zm5a"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alright, now that we have a static task let's bring in some more dynamic experiences using Fields. As previously mentioned, Fields allow you to add placeholders inside your samples that will later be automatically extracted by Autopilot so that we can work with them.&lt;/p&gt;

&lt;p&gt;Before we can work with the fields though we'll need to create a new task and something that will handle the field values later. For this let's first create a Twilio Function that will log the value of a field and return a &lt;code&gt;say&lt;/code&gt; action.&lt;/p&gt;

&lt;p&gt;Go to the &lt;a href="https://www.twilio.com/console/runtime/functions/manage" rel="noopener noreferrer"&gt;Functions section&lt;/a&gt; of &lt;a href="https://www.twilio.com/console/runtime/overview" rel="noopener noreferrer"&gt;Twilio Runtime&lt;/a&gt; and create a new "Blank" function. Give it a name like "Log Field Value" and add a path like &lt;code&gt;/log-value&lt;/code&gt;. Change the code of your Function to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Field_Quantity_Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;say&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thank you for your order.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterwards go back into your CoffeeBot Assistant and create a new task in &lt;a href="https://www.twilio.com/console/autopilot/CoffeeBot/tasks" rel="noopener noreferrer"&gt;Task Builder section&lt;/a&gt;. Give it a name like &lt;code&gt;new_order&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"redirect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;your_runtime&amp;gt;.twil.io/log-value"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FfYpklGZsM-qIrl0CT9rngsiE8X_Js0_43lcErVBg5Pr6GO.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FfYpklGZsM-qIrl0CT9rngsiE8X_Js0_43lcErVBg5Pr6GO.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to update the URL with the link to your Twilio Function. Afterwards click save to make sure your changes are not lost.&lt;/p&gt;

&lt;p&gt;Next we need to add Fields to this task. Click on the "Modify" link next to our task and in the dialog click the "View Fields" link. In there you'll be able to add new Fields. Create a new Field with the name &lt;code&gt;Quantity&lt;/code&gt;. Autopilot comes with a variety of predefined data types for Fields. In our case we care about the Quantity number. So go ahead and choose "Twilio.NUMBER" as the type of this field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Fy_w-gsw-R4vvZk0onIP9MSIi4GppSYQEkiOeM3rPkSzOQj.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2Fy_w-gsw-R4vvZk0onIP9MSIi4GppSYQEkiOeM3rPkSzOQj.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterwards close the dialog again and switch to &lt;em&gt;S&lt;/em&gt;&lt;em&gt;amples&lt;/em&gt; as we'll have to add new samples for our task. Expand the input field and place the following values into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I would like to have {Quantity} coffee please.
{Quantity} coffee.
Could you make me {Quantity} coffee please?
Can I have {Quantity} coffee?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{Quantity}&lt;/code&gt; tells Autopilot that this is a placeholder for the Field "Quantity". Associate the samples with the &lt;code&gt;new_order&lt;/code&gt; task and add them by hitting the "+" button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F-BU6Naz8LjEzWDvq0OT8qkIu_2CH7bI9XgkCWDFVG7VJQP.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F-BU6Naz8LjEzWDvq0OT8qkIu_2CH7bI9XgkCWDFVG7VJQP.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the samples, go to the &lt;code&gt;Build Models&lt;/code&gt; section again and trigger a new model build. Once that's finished, go back to your Twilio Function to see the logs in the bottom of the Function and take out your phone.&lt;/p&gt;

&lt;p&gt;Text it something like "Ten coffee please" and check the logs of your Function. You should see it log "10".&lt;/p&gt;

&lt;p&gt;That's because we are logging the parameter &lt;code&gt;Field_Quantity_Value&lt;/code&gt;. Autopilot will automatically pass every captured Field as &lt;code&gt;Field_&amp;lt;FIELD_NAME&amp;gt;_Value&lt;/code&gt; to the webhook. You can also see that it turned &lt;code&gt;Ten&lt;/code&gt; into &lt;code&gt;10&lt;/code&gt;. That's because we told Autopilot that this Field is of type number. It will now handle both numbers as digits or words. Try it by texting "Can I have 15 coffee?"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FH8UqFjqp_mdzWYcguT-LQY43lEoi_hp5hxkhkyJrUq1tY_.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FH8UqFjqp_mdzWYcguT-LQY43lEoi_hp5hxkhkyJrUq1tY_.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Custom Field Types
&lt;/h2&gt;

&lt;p&gt;While the built-in Field Types serve a variety of use cases, there will be the situation where you'll want to have your own Field Type. In our CoffeeBot case this would be, for example, the different types of coffee that we serve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FJYu4LjtQ3d9OOvdLkgAN0MeLvUTKI_Q7LVvxquUzrL_7Pyiex6UqoDXReMAA0BOdo9L_xYZmQBdcHp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FJYu4LjtQ3d9OOvdLkgAN0MeLvUTKI_Q7LVvxquUzrL_7Pyiex6UqoDXReMAA0BOdo9L_xYZmQBdcHp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To create a new Custom Field Type go into the Natural Language Router part of your bot and click on the &lt;a href="https://www.twilio.com/console/autopilot/CoffeeBot/router/field-types" rel="noopener noreferrer"&gt;Manage Fields&lt;/a&gt; tab. Press the "Create your first Field Type" button and give it a name like &lt;code&gt;coffee_type&lt;/code&gt;. Once created click on the name in the list of Field Types and press the Plus button to add new examples. This is where you'll want to add possible values for this type. In our case this would be any valid Coffee type. You can enter one value per line for ease of use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;espresso
americano
latte
mocha
tea
coffee
flat white
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F6XJxGn-YtMAIQHueJkmLVQg7shhrlxZ9VJ94O2GGI9_6l-.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F6XJxGn-YtMAIQHueJkmLVQg7shhrlxZ9VJ94O2GGI9_6l-.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the values that you provide here will not be the only valid ones. Autopilot will learn and try to match other words to this field type as well.&lt;/p&gt;

&lt;p&gt;After you created them, let's add &lt;code&gt;CoffeeType&lt;/code&gt; as a valid Field for our &lt;code&gt;new_order&lt;/code&gt; task. Go back into the &lt;a href="https://www.twilio.com/console/autopilot/CoffeeBot/tasks/tasks/new_order/fields" rel="noopener noreferrer"&gt;View Fields&lt;/a&gt; part of your &lt;code&gt;new_order&lt;/code&gt; Task and add a new Field of name &lt;code&gt;CoffeeType&lt;/code&gt; and data type &lt;code&gt;coffee_type&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FUW5CWm2oHG0Ye4yhEbGM2Gzt_g0sMqLnXLRjnAZyNhHyIp.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FUW5CWm2oHG0Ye4yhEbGM2Gzt_g0sMqLnXLRjnAZyNhHyIp.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now before we build our new model, we need to update our samples to use the new field. Go ahead and delete the old samples for the &lt;code&gt;new_order&lt;/code&gt; and instead create new samples using the following value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I would like to have {Quantity} {CoffeeType} please.
{Quantity} {CoffeeType}.
{CoffeeType}
Could you make me {Quantity} {CoffeeType} please?
Can I have {Quantity} {CoffeeType}?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once saved, go into &lt;a href="https://www.twilio.com/console/autopilot/CoffeeBot/router/model-builds" rel="noopener noreferrer"&gt;Model Builds&lt;/a&gt; and build a new Model by incrementing the version in your build name.&lt;/p&gt;

&lt;p&gt;Your model will now be able to understand both quantity and different coffee types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting our Ordering System
&lt;/h2&gt;

&lt;p&gt;To actually be able to create new orders we now need to change the action that we are triggering to our original Twilio Function URL and update our Twilio Function.&lt;/p&gt;

&lt;p&gt;Go to your "Barista Create Order" Twilio Function from the previous blog post and update it accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ORDER_LIST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SERVICE_SID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SYNC_SERVICE_SID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enter Sync Service Sid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Field_CoffeeType_Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderQuantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Field_Quantity_Value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderQuantity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;x &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// Create a sync list item for the order&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;twilioClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTwilioClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;twilioClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;services&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SERVICE_SID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;syncLists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ORDER_LIST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;syncListItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orderData&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;say&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Thank you for ordering &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will read the right fields as well as fall back to a quantity of one if no quantity could be detected. Additionally we are using the &lt;code&gt;event.UserIdentifier&lt;/code&gt; here to get the phone number since this will be the phone number for SMS and voice bots. Note that this won't work for Alexa or Google Home for example.&lt;/p&gt;

&lt;p&gt;Save your Function changes and copy the URL to your Function. Go back into your Autopilot Task and modify the &lt;code&gt;new_order&lt;/code&gt; task and update the URL for the redirect to your Function URL.&lt;/p&gt;

&lt;p&gt;Make sure you rebuild your model one more time to catch all changes.&lt;/p&gt;

&lt;p&gt;If you haven't yet opened your terminal do that now and start your React interface from the previous blog post by running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see in your browser the following screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F2JO_7mES5rGq68K36k1R3zzMbntaURgFOGIeAnE_7K7ST-.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F2JO_7mES5rGq68K36k1R3zzMbntaURgFOGIeAnE_7K7ST-.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's test if everything is working by texting something like "Can I have two latte please?". Note that we are spelling it lowercase and are altering our sentence from the example sentences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FdiU-_pCiOEGwVmo-TlPFQwCrQpwi1ql3JmPn5uzjR3KNAD.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FdiU-_pCiOEGwVmo-TlPFQwCrQpwi1ql3JmPn5uzjR3KNAD.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should get a confirmation of your order of "2x Latte" and it should appear in the browser UI. Click "Finish Order" or "Cancel Order" and you should receive the respective confirmation via SMS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FSg9I7t6-Syf7KyG7gsYgDAFNwE1E5iGz2oLSaas0RrUxkX.width-500.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FSg9I7t6-Syf7KyG7gsYgDAFNwE1E5iGz2oLSaas0RrUxkX.width-500.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FhuVgRNib8wjC1mQEyROrziT0FbnFep5FkPh6MVSkEGzql7ZpNjgqMXE_Ai78qxIH9bYfcbJeKhbggU" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FhuVgRNib8wjC1mQEyROrziT0FbnFep5FkPh6MVSkEGzql7ZpNjgqMXE_Ai78qxIH9bYfcbJeKhbggU"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FhyNQhFfiLX-90pf78CoPKD8NYdP78qRNR3NEuaB3ICj_hghwgkQ3XUpBbe9fqNrYv28vSa9RMbHGRU" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Foriginal_images%2FhyNQhFfiLX-90pf78CoPKD8NYdP78qRNR3NEuaB3ICj_hghwgkQ3XUpBbe9fqNrYv28vSa9RMbHGRU"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is just the beginning of what you can do with Twilio Autopilot. If you want to learn more, I suggest you check out the &lt;a href="https://www.twilio.com/docs/autopilot/actions/collect" rel="noopener noreferrer"&gt;Collect action&lt;/a&gt; that allows you to do form-filling with ease. You could use it for example to ask the customer for additional information like their name or if they want to have soy milk added to their coffee. Or check out how you can use the &lt;a href="https://www.twilio.com/docs/autopilot/actions/hand-off" rel="noopener noreferrer"&gt;Handoff&lt;/a&gt; functionality to connect either to a &lt;a href="https://www.twilio.com/flex" rel="noopener noreferrer"&gt;Twilio Flex&lt;/a&gt; agent or directly to the phone of your barista for any questions the bot can't answer.&lt;/p&gt;

&lt;p&gt;And if you want to import/export your bot to another account for example, you should check out the &lt;a href="https://github.com/twilio/autopilot-cli" rel="noopener noreferrer"&gt;autopilot-cli&lt;/a&gt; that will help you with building your bot.&lt;/p&gt;

&lt;p&gt;If you have any questions or if you want to show me what cool thing you built with Autopilot or just in general, feel free to reach out to me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="//mailto:dkundel@twilio.com"&gt;dkundel@twilio.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/dkundel" rel="noopener noreferrer"&gt;@dkundel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/dkundel" rel="noopener noreferrer"&gt;dkundel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dkundel.com/" rel="noopener noreferrer"&gt;dkundel.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>bots</category>
      <category>twilio</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
