# Farcaster Frames with Model API

## **Video Tutorial**

{% embed url="<https://youtu.be/UWe_XoYEi5g>" %}

Welcome to this tutorial where we will walk you through the process of creating a Farcaster Frame and communicating with a FLock.io RAG API. This is a comprehensive guide that will give you the confidence to create, modify, and enhance your Farcaster Frames with FLock API.

What you will learn:

* How to create a Farcaster Frame
* Communicate with FLock RAG API.

## Technology Stack

* TypeScript
* Frog framework

## What is Frame?

A Frame is a tool for creating interactive, authenticated apps on Farcaster, allowing features like polls, live feeds, or galleries within Warpcast and other FC clients. Frames enhance the OpenGraph standard, transforming static embeds into interactive experiences.

## What is Frog framework?

Frog is a framework built on top of Hono for building Farcaster Frames.

The documentation: [Getting started](https://frog.fm/getting-started)

## How it Works

### Setup

* Install Frog Framework

```jsx
npm install frog hono

yarn add frog hono
```

* Create a Bot from the AI Co-Creation platform, where you can follow the guide.
* Install the API related package.

```jsx
# init frog framework
npm init frog

# install relavent packages
npm install axios dotenv @types/node
```

<figure><img src="/files/7fNtunqSO03L2qCNY7RY" alt=""><figcaption><p>Frog init</p></figcaption></figure>

* We will be using the `default` template, feel free to export other ones in the future.

### File structure

```jsx
📦flock-far-frog
 ┣ 📂public
 ┃ ┗ 📜icon.png
 ┣ 📂src
 ┃ ┣ 📂api
 ┃ ┃ ┗ 📜flock-api.ts
 ┃ ┗ 📜index.tsx
 ┣ 📜.env
 ┣ 📜.gitignore
 ┣ 📜README.md
 ┣ 📜package-lock.json
 ┣ 📜package.json
 ┗ 📜tsconfig.json
```

* Pages will stay in our router
* FLock API will stay in the utils

### Logic flow

We will have one page

* Default page - react on user’s input

This is a very simple and general approach of how we can use frame with FLock Chat Bot.

### API

Now create a folder under `src` called `api` within the `utils` folder create a file called `flock-api.ts` this is the place where your api will sit. And here is the code you can use directly.

```jsx
import axios from "axios";
import * as dotenv from "dotenv";

// Load environment variables from .env file
dotenv.config(); // Make sure the path is correct

async function chatFLockBot(prompt: string, modelId: string) {
  console.log("Prompt:", prompt);

  try {
    // Construct the request payload
    const payload = {
      question: prompt,
      chat_history: [],
      knowledge_source_id: modelId, // replace with your model id
    };

    // Set the headers
    const headers = {
      "x-api-key": process.env.FLOCK_BOT_API_KEY, // Ensure API key is set in .env
    };

    // Send POST request using axios
    const response = await axios.post(
      `${process.env.FLOCK_BOT_ENDPOINT}/chat/conversational_rag_chat`,
      payload,
      {
        headers,
      }
    );

    // Output the response data
    console.log(response.data);
    return response.data;
  } catch (error) {
    console.error("Error:", error);
  }
}

export default chatFLockBot;
```

Next create a `.env` file in the root directory of the project, and add following

```
FLOCK_BOT_API_KEY= "<your api key>"
FLOCK_BOT_ENDPOINT="<endpoint>"
FLOCK_BOT_ID="<your bot id>"
```

### Useful tools for OG image

> I personally think that the Vercel OG image playground is a convenient tool to quickly check up on your OG image. So, do utilise it!

[Vercel OG Image Playground](https://og-playground.vercel.app/)

### Page Structure

```jsx
app.frame('/', (c) => {
  const { buttonValue, inputText, status } = c
  const fruit = inputText || buttonValue
  return c.res({
    image: (
    
    ),
    intents: [
      
    ],
  })
})
```

Before diving in, let's first understand the structure of a ‘frame’. A frame consists of two components: the image and the intents.

* The **image** is where your visuals are displayed
* The **intents** handle interactions, including text input, button reactions, and the new transaction operations.

#### **Image**

```jsx
image: (
  <div
    style={{
      alignItems: 'center',
      background: 'black',
      backgroundSize: '100% 100%',
      display: 'flex',
      flexDirection: 'column',
      flexWrap: 'nowrap',
      height: '100%',
      justifyContent: 'center',
      textAlign: 'center',
      width: '100%',
    }}
  >
    <div
      style={{
        color: 'white',
        fontSize: 24,
        fontStyle: 'normal',
        letterSpacing: '-0.025em',
        lineHeight: 1.4,
        marginTop: 30,
        padding: '0 120px',
        whiteSpace: 'pre-wrap',
      }}
    >
      {status === 'response' && `Your question is: ${prompt}`}
    </div>
    <div
      style={{
        color: 'white',
        fontSize: status === 'response' ? 16 : 60,
        fontStyle: 'normal',
        letterSpacing: '-0.025em',
        lineHeight: 1.4,
        marginTop: 30,
        padding: '0 120px',
        whiteSpace: 'pre-wrap',
      }}
    >
      {status === 'response' ? response.answer : "Lets chat about FLock!"}
    </div>
</div>
)

```

Here we use status condition to show the content, if status is response, we will show the question and answer. Otherwise, the user will only see “Lets chat about FLock”

#### **Intent**

```jsx
intents: [
      <TextInput placeholder="Enter Prompt about FLock" />,
      <Button value={process.env.FLOCK_BOT_ID}>Lets Chat!</Button>,
      status === 'response' && <Button.Reset>Reset</Button.Reset>,
],
```

Here we have created three intents

* `TextInput` - for questions to be asked to the bot
* `Button` - for the interaction
* `Button` - for reset after receiving the response

#### Main logic flow

```tsx
import chatFLockBot from './api/flock-api'
 
app.frame('/', async (c) => {
  const { buttonValue, inputText, status } = c
  const prompt = inputText
  const modelId = buttonValue

  let response;

  if (prompt == undefined || modelId == undefined) {
    response = "Detail not satisfied, please insert prompt";
  } else {
    try {
      response = await chatFLockBot(prompt, modelId);

    } catch (e) {
      response = "There is somthing wrong with the process, please try again"
    }
  }

  return c.res({
    image: (
      ...
    ),
    intents: [
      ...
    ],
  })
})
```

In this section, we establish the logic to respond to both user input and an API call.

Initially, we extract values from the object **`c`** (representing context), which provides the current state or frame:

* **`buttonValue`** - the value assigned to a button,
* **`inputText`** - the text entered by the user,
* **`status`** - the status of the context within its lifecycle.

Next, we initialise two constants, **`prompt`** and **`modelId`**, using the extracted **`inputText`** and **`buttonValue`** respectively. This sets up the parameters we need for the subsequent API call.

We then employ an **`if`** statement to check whether either **`prompt`** or **`modelId`** is undefined. This validation is crucial as it ensures that we have the necessary data before proceeding.

Finally, we use a **`try-catch`** structure to manage the asynchronous function **`chatFlockBot`**. This function is called with **`prompt`** and **`modelId`** as arguments. The **`try`** block executes the function, and should any errors occur during the API call, the **`catch`** block captures these exceptions and sets an error message.

## Run the test

Now you have completed the setup of the frame. Let’s test it in the local environment.

```
# run this command in your terminal
npm run dev

# you will see followings
> dev
> frog dev

(!) Could not auto-determine entry point from rollupOptions or html files and there are no explicit optimizeDeps.include patterns. Skipping dependency pre-bundling.

  [running] frog@v0.9.0

  ➜  Local:   http://localhost:5173/
  ➜  Inspect: http://localhost:5173/dev
  ➜  Network: use --host to expose
```

Go to `http://localhost:5137/dev`

You will see the following page

<figure><img src="/files/78wMKcIMYWawoXzjQZTX" alt=""><figcaption></figcaption></figure>

1. The history of access
2. URL tab - similar to web browser URL tab
3. Metadata of current frame
4. Live frame interact
5. Request/Context/Metadata information
6. Request/Context/Metadata information

Now you can start typing the questions and chat with the frame!

## Deploy your frame

I recommend deploying your project using [Vercel](https://vercel.com/). You can easily deploy it by connecting your GitHub account and pushing your project to a repository.

Next, all you need to do is copy your deployed link and post it in any Farcaster Client.

Please tag us when you post the cast! “/flock-io”

**Lastly here is the GitHub Repository!**

<https://github.com/FLock-io/FLock-AI-Demo/tree/main/FLOCK-RAG-FRAME-React>

> *Reach out to us by Website:* [*https://flock.io/*](https://flock.io/) \
> *Twitter:* [*https://twitter.com/flock\_io*](https://twitter.com/flock_io) \
> *Telegram:* [*https://t.me/flock\_io\_community*](https://t.me/flock_io_community) \
> *Discord:* [*https://discord.gg/ay8MnJCg2W*](https://discord.gg/ay8MnJCg2W) \
> *Farcaster:* [*https://warpcast.com/\~/channel/flock-io*](https://warpcast.com/~/channel/flock-io)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flock.io/flock-products/ai-marketplace/quickstart/tutorials/farcaster-frames-with-model-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
