> ## Documentation Index
> Fetch the complete documentation index at: https://dev.writer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Social post generator

In this tutorial, you'll use the Writer Framework to build an AI-powered tool for generating social media posts and tags based on the input you provide!

The process will take only minutes using a drag-and-drop visual editor to build the user interface and Python for the back-end code.

Here's what the finished project will look like:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2ab.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=e38dd8f9a9fe0a6b6976706902b45761" alt="Finished social post generator project" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2ab.png" />

## Prerequisites

Before starting, ensure you have:

* **A Writer account:** You don't need an account to use Writer Framework, but you'll need one to use the AI module. [Sign up for a free account here](https://app.writer.com/register).
* **Python 3.9.2 or later**: Use the installer from [python.org](https://www.python.org/downloads/).
* **pip:** This command-line application comes with Python and is used for installing Python packages, including those from Writer.
* **A basic understanding of Python:** You should be familiar with the basics of the language.
* **Your favorite code editor (optional):** There's a code editor built into Writer for writing back-end code, but you can also use Visual Studio Code, Notepad++, Vim, Emacs, or any text editor made for programming if you prefer.

## Setting up your project

### Create a Writer app and get its API key

First, you'll need to create a new app within Writer.

<Steps>
  <Step title="Create the app in Writer">
    Log into Writer. From the Home screen, click on the **Build an app** button.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=8f7d36049df01e27d405a7f07401b8dc" alt="Writer home screen" width="3220" height="1900" data-path="framework/images/tutorial/social_post/sp_gen_2.png" />

    The **Start building** menu will appear, presenting options for the types of apps you can create.

    Select **Framework**, located under **Developer tools**. This will create a brand new app based on Writer Framework.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_3.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=8e8988274dfd797dde727d2070948200" alt="&#x22;Start building&#x22; menu" width="3220" height="1900" data-path="framework/images/tutorial/social_post/sp_gen_3.png" />
  </Step>

  <Step title="Copy your app's API key">
    On the next screen, titled **How to deploy an application**, you can get the API key for the app by clicking on the **Reveal key** button, located under the text **Authenticate with an API key**. Your complete API key will be displayed, and a "copy" button will appear. Click this button to copy the key; you'll use it in the next step.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2a.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=1ac1226cb669cb98048760f5d2dd1285" alt="&#x22;How to deploy an application&#x22; page" width="3203" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2a.png" />
  </Step>
</Steps>

### Set up your computer and create the app's project

The next step is to set up the Writer Framework environment on your computer. You'll do this by creating a directory for the project, installing dependencies, and creating the project for the application using a template.

<Steps>
  <Step title="Open your terminal application">
    Open your terminal application. On macOS and Linux, this application goes by the name *Terminal*; on Windows, you can use either *Windows PowerShell* (which is preferred) or *Command Prompt*.
  </Step>

  <Step title="Install the dependencies">
    <Note>If you already have the `writer` and `python-dotenv` packages installed on your computer, you can skip this step.</Note>

    Install the `writer` and `python-dotenv` packages by entering the following commands in your terminal application:

    ```
    pip install writer python-dotenv
    ```

    This command tells `pip`, the Python package installer, to install two packages:

    * `writer`, which provides some command-line commands and enables Python code to interact with Writer and the Writer Framework.
    * `python-dotenv`, which makes it easy to manage environment variables by loading them from a `.env` file. This one is optional for this exercise, but you might find it useful when working on larger projects.
  </Step>

  <Step title="Set the API key environment variable">
    To pass your API key to the Writer Framework, you need to set an environment variable called `WRITER_API_KEY`.

    Select your operating system and terminal application below, then copy and paste the command into your terminal application, replacing `[your_api_key]` with the API key you copied earlier:

    <CodeGroup>
      ```sh macOS/Linux (Terminal) theme={null}
      export WRITER_API_KEY=[your_api_key]
      ```

      ```sh On Windows (Windows PowerShell) theme={null}
      $env:WRITER_API_KEY=[your_api_key]
      ```

      ```sh On Windows (Command Prompt) theme={null}
      set WRITER_API_KEY=[your_api_key]
      ```
    </CodeGroup>

    The `WRITER_API_KEY` environment variable will remain defined as long your terminal session is open (that is, until you close your terminal application’s window).
  </Step>

  <Step title="Create the project">
    Create the project by entering this command into your terminal application:

    ```
    writer create social-post-generator --template=ai-starter
    ```

    This command sets up a new project called `social-post-generator` using a starter template called `ai-starter` so that you're not starting "from scratch."
  </Step>
</Steps>

## Build the UI

Now that you've created the project, it's time to define the UI. The Writer Framework's drag-and-drop capabilities make it easy — even if you haven't done much UI work before!

The project editor is a web application that runs on your computer and enables you to define and edit your app's user interface. Launch it by typing the following into your terminal application:

```
writer edit social-post-generator
```

You'll see a URL. Control-click it (command-click on macOS) to open it, or copy the URL and paste it into the address bar of a browser window.

The browser window will contain the project editor, which will look like this:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2b.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=d8e5d597c75f4303eb3f588e7ef5f7a8" alt="Project editor" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2b.png" />

You'll see the following:

* The **canvas** is in the center. It displays the app's user interface.
* The column on the left contains:
  * The **Core toolkit**, which contains all the UI components. You define the user interface by dragging components from the Toolkit and placing them on the canvas.
  * The **Component tree**, which shows the arrangement of the UI components on the canvas. It's also useful for selecting items on the canvas, especially when it has a lot of UI components.

It's time to build the UI!

<Steps>
  <Step title="Examine the header">
    Select the **Header** component by clicking it — it's the component at the top, containing the title **AI STARTER** and a gray area labeled **Empty Header**.

    When you click it, you'll see the **properties** panel appear on the right side of the page. This lets you view and edit the properties of the selected component.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2c.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=1ba5e3c03ec68463569c76c6e55baff2" alt="The selected header and its properties panel" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2c.png" />

    The first property you'll see in the panel is the **Text** property, which defines the text that appears as the header's title. It should contain the value `@{my_app.title}`. The `@{` and `}` indicate that `my_app.title` is a variable and that its contents should be the text displayed instead of the literal text "my\_app.title". You'll set the value of this variable soon.
  </Step>

  <Step title="Clear the Section's default title">
    Select the **Section** component by clicking it — it's just below the **Header** component and contains the title **Section Title** and a gray area labeled **Empty Section**.

    In the **properties** panel, clear out the value of the **Title** property. This will remove the *Section*'s default title.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2d.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=6d404fbbeea27b1ccd0214ac42622a2a" alt="The selected section and its properties panel" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2d.png" />
  </Step>

  <Step title="Add a Text Input component">
    The user will need a place to enter words or phrases that the app will use as the basis for generating posts and tags.

    Drag a **Text Input** component — and note, it's **Text *Input***, not **Text** —  from the **Core toolkit** panel on the left (it's under **Input**, and you may need to scroll down a little to find it) and into the **Section**. Sections can act as containers for other components.

    <Note>You can search for a specific component by using the search bar at the top of the **Core toolkit** panel.</Note>

    Select the **Text Input** component. In the **properties** panel:

    * Find the **Label** property and set its value to `Topic for social posts and tags`.
    * (Optional) Feel free to add some placeholder to the *Text Input* component by setting the value of the **Placeholder** property with something like `Enter words or phrases describing your topic`.

          <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2e.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=7922ce43b1b0dc522ce4fa3d7de4daae" alt="The text input component and its properties panel" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2e.png" />
  </Step>

  <Step title="Add a Button component">
    Drag a **Button** component from the **Core toolkit** panel (it's under **Other**, and you may need to scroll down a little to find it) into the **Section**, directly below the **Text Input**. The user will click this button to submit their prompt.

    Select the **Button**. In the **properties** panel:

    * Set the **Text** property's value to `Generate posts`.
    * Find the **Icon** property, and set its value to `arrow_forward`.

          <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2f.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=bf1cd3c45cf7aaa3089e45c1103285ff" alt="The button component and its properties panel" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2f.png" />
  </Step>

  <Step title="Add a Message component">
    The process of creating social media posts and tags takes a few moments. In order to reassure the user that the app is working and hasn't crashed, it will use a **Message** component to display something reassuring while it's generating.

    Drag a **Message** component from the **Core toolkit** panel into the **Section** positioning it immediately below the **Button**.

    Select the **Message** component. In the **properties** panel:

    * Scroll down to the **Style** section and look for the **Loading** property, which sets the color of the **Message** component when it's loading.
    * Click its **CSS** button, which will cause a text field to appear below it.
    * Enter this color value into the text field: `#D4FFF2`.

          <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2g.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=193337b7397365784f224687ae4ca8b3" alt="The message component and its properties panel" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2g.png" />
  </Step>

  <Step title="Add a new Section">
    The **Section** that you were working on is for user input. Let's add a new **Section** to hold the output — the social media posts and tags the app will generate.

    Drag a **Section** component from the **Toolbox** panel and place it *inside* the **Section** that's already there, just below the **Message** component.

    <Note>That's right — **Sections** can contain other **Sections**!</Note>

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2h.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=11dc51570178c77b7b1248f8b0d00110" alt="The new section inside the existing section" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2h.png" />

    Select the **Section** you just added. In the **properties** panel:

    * Find the **Title** property and clear it its value to remove the **Section**'s title.
    * Scroll down to the **Style** section and look for the **Container background** property, which sets the **Section**'s background color.
    * Click its **CSS** button, which will cause a text field to appear below it.
    * Enter this color value into the text field: `#F6EFFD`.

          <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2i.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=462524d0c44ea635930c7c8aeda22087" alt="The new section and its properties" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2i.png" />
  </Step>

  <Step title="Add a Tags component">
    Writer Framework has a number of useful components to make your apps more functional and beautiful. One of these is the **Tags** component, which can take a list of hashtags (or words, or short phrases) and display them inside colorful "bubbles" to make them stand out. This app will display the social media tags it generates in a **Tags** component.

    Drag a **Tags** component from the **Toolbox** panel and place it inside the new **Section**.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2j.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=54bac04c46c186245193ff0b18e1df9a" alt="The tags component" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2j.png" />
  </Step>

  <Step title="Add a Separator">
    Drag a **Separator** component from the **Toolbox** panel and place it inside the new **Section**, just below the **Tags** component. This will separate the tags from the posts.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2k.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=3f7e4b3524ce030c809588e275930e64" alt="The separator" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2k.png" />
  </Step>

  <Step title="Add a Text component">
    Finally, drag a **Text** component from the **Toolbox** panel and position it below the **Separator**. This will hold the generated social media posts.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2l.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=33db8853d9ac0c7cdebc2e54e856da7a" alt="The text component" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2l.png" />
  </Step>
</Steps>

## Add the back-end code

With the UI laid out, it's time to work on the logic behind it.

The logic behind the user interface is defined in a file named `main.py`, which is in your project's directory. This file was automatically generated; you'll update the code in it to define the behavior of your app.

The simplest way to edit `main.py` is within the project editor. Click on the "toggle code" button (beside the word **Code**) near the lower left corner of the project editor page.

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2m.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=23215946becf66a071916c4bfe27aabe" alt="Project editor with arrow pointing to toggle code button" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2m.png" />

A pane with the name **Code** will appear at the bottom half of the screen, displaying an editor for the the contents of `main.py`.

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2n.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=dcf19ac48e57128e2b3487fb23cb22d7" alt="Project editor with the code editor displayed" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2n.png" />

<Note>If you'd rather use a code editor instead of coding in the browser, use it to open the `main.py` file in your project's directory.</Note>

Now follow these steps:

<Steps>
  <Step title="Import libraries and load the Writer Framework API key">
    You should see the following at the start of the file:

    ```python theme={null}
    import writer as wf
    import writer.ai
    ```

    Replace that code with the following:

    ```python theme={null}
    import os
    import re
    import writer as wf
    import writer.ai

    # Set the API key
    wf.api_key = os.getenv("WRITER_API_KEY")
    ```

    This code imports the libraries that the application will need and then reads your Writer Framework API key in the `WRITER_API_KEY` environment variable.
  </Step>

  <Step title="Create a handler to respond to the user's input">
    When the user presses the app's **Button**, the app needs to call a function to generate and display the social media posts and tags. Find these comments in the code...

    ```python theme={null}
    # Welcome to Writer Framework! 
    # This template is a starting point for your AI apps.
    # More documentation is available at https://dev.writer.com/framework
    ```

    ...and replace them with the following function:

    ```python theme={null}
    def generate_and_display_posts_and_tags(state):
        print(f"Here's what the user entered: {state['topic']}")

        # Display message
        state["message"] = "% Generating social media posts and tags for you..."

        # Generate and display social posts
        prompt = f"You are a social media expert. Generate 5 engaging social media posts about {state['topic']}. Include emojis, and put a blank line between each post."
        state["posts"] = writer.ai.complete(prompt)
        print(f"Posts: {state['posts']}")

        # Generate and display hashtags
        prompt = f"You are a social media expert. Generate around 5 hashtags about {state['topic']}, delimited by spaces. For example, #dogs #cats #ducks #elephants #badgers"
        pattern = r"#\w+"
        hashtags = re.findall(pattern, writer.ai.complete(prompt))
        state["tags"] = {item: item for item in hashtags}
        print(f"Tags: {state['tags']}")

        # Hide message
        state["message"] = ""
    ```

    The `%` at the start of the string being assigned to `state["message"]` will be replaced by a “spinning circle” progress indicator graphic in the *Message* component.

    The `pattern` variable in the `# Generate and display hashtags` section defines a regular expression pattern to search for words that begin with the `#` character. The `r` in front of the opening quote specifies that the string is a *raw string*, which means that the `\` character should be treated as a literal backslash and not as the start of an escape character sequence.

    Note that `generate_and_display_posts_and_tags()` uses `print()` functions for debugging purposes, and you can use them to get a better idea of what's happening in the function. You'll see their output in both your terminal application and in the project editor's 'log' pane (which will be covered shortly) as you use the social post generator. This output will include:

    * The topic the user entered
    * The posts generated by the LLM
    * The hashtags generated by the LLM

    The `print()` functions don't affect the operation of the social post generator in any way, and you can remove them if you wish.
  </Step>

  <Step title="Initialize the application">
    The final step is to set the application's initial state. Find this code, which should be just after the `generate_and_display_posts_and_tags()` function...

    ```python theme={null}
    # Initialise the state
    wf.init_state({
        "my_app": {
            "title": "AI STARTER"
        },
    })
    ```

    ...and replace it with this:

    ```python theme={null}
    # Initialize the state
    wf.init_state({
        "topic": "writing",
        "message": "",
        "tags": {},
        "posts": "",
        "my_app": {
            "title": "SOCIAL POST GENERATOR"
        }
    })
    ```

    The Writer Framework's `init_state()` method sets the initial value of `state`, a dictionary containing values that define the state of the application. The key-value pairs in `state` are how you store values used by your app and how you pass data between the back-end code and the UI.

    The code above sets the initial value of `state` so that it has these key-value pairs:

    * `topic`: A string containing the topic that the application should generate social media posts and tags for. You'll bind its value to the *Text Input* component where the user will enter the topic.
    * `message`: A string containing text of the message that will be displayed to the user while the application is generating posts and tags. You'll bind its value to the **Message** component.
    * `tags`: A list containing the hashtags generated by the LLM. You'll bind its value to the **Tags** component.
    * `posts`: A string containing the social media posts generated by the LLM. You'll bind its value to the **Text** component.
    * `my_app`: A dictionary containing values that define the application's appearance. This dictionary has a single key-value pair, `title`, which defines the text that appears as the application's title.

    <Note>For more details about the `state` variable, see our [*Application state*](https://dev.writer.com/framework/application-state#application-state) page.</Note>
  </Step>

  <Step title="Save the updated code and hide the code editor">
    That’s all the code. If you edited the code in the browser, save it by clicking the “save” button near the top right corner of the code editor.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2o.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=d8da7e0bd7c4e66f1754e538246bf465" alt="Project editor and code editor, with arrow pointing to save button" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2o.png" />

    Click the "toggle code" button to hide the code editor.
  </Step>
</Steps>

## Bind the UI to the back-end code

You've built the UI and written the code behind it. Let's connect the two! Go back to the browser window with the project editor and do the following:

<Steps>
  <Step title="Observe that the heading at the top of the app is now 'SOCIAL POST GENERATOR'">
    Earlier, you saw that the **Header** component's **Text** property was set to `@{my_app.title}`, a value in the app's `state` variable. You changed this value when you update the call to the Writer Framework's `init_state()` method.
  </Step>

  <Step title="Bind the Text Input component to the 'state' variable's 'topic' key">
    Select the **Text Input** component. In the **properties** panel, scroll down to the **Binding** section and find the **State element** property. This is where you specify the `state` variable key whose value will be connected to the **Text Input** component. Set its value to `topic`.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2p.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=fc53611bc4959c8bad1b2d7af7e19cbb" alt="Updating the text input component's state element property" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2p.png" />
  </Step>

  <Step title="Connect the Button component to the 'generate_and_display_posts_and_tags()' function">
    Select the **Button** component. In the **properties** panel, scroll down to the **Events** section and find the **`wf-click`** property. This is where you specify the function to call when the user clicks the button — set its value to `generate_and_display_posts_and_tags`.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2q.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=c9c623a7061f1baa2ba98c606a1b8cd2" alt="Updating the button's wf-click property" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2q.png" />
  </Step>

  <Step title="Bind the Message component to the 'state' variable's 'message' key">
    Select the **Message** component. In the **properties** panel, find the **Message** property, which specifies the content of the **Message** component. Set its value to `@{message}`.

    <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2r.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=6ad60398867b52bd8a9843f725963a9d" alt="Updating the message's message property" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2r.png" />
  </Step>

  <Step title="Bind the Tags component to the 'state' variable's 'tags' key.">
    Select the **Tags** component. In the **properties** panel:

    * Find the **Tags** property, which specifies the source of the tags that the component will display.
    * Click its **JSON** button.
    * In the text field below the **JSON** button, set the **Tags** property's value to `@{tags}`.

          <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2s.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=58a4c76ca5d884b5248f9cf7d001e0d8" alt="Updating the tags component's tags property" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2s.png" />
  </Step>

  <Step title="Bind the Text component to the 'state' variable's 'posts' key">
    Select the **Text** component. In the **properties** panel:

    * Find the **Text** property, which specifies the content of the **Text** component. Set its value to `@{posts}`.
    * Set the **Use Markdown** property to **yes**.

          <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2t.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=c2b407d36da8a80322e9b59726a57e3d" alt="Updating the text component's properties" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2t.png" />
  </Step>

  <Step title="Set the visiblity of the Section component containing the Tags and Text components based on the 'state' variable's 'posts' key">
    Select the **Section** component containing the **Tags** and **Text** components. In the **properties** panel:

    * Scroll to the **Visibility** property at the bottom.
    * Click on the **Custom** button.
    * In the **Visibility value** field, set the value to `posts`. This will cause the **Section** to be visible only when the `state` variable's `posts` key has a non-empty value.

          <img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2u.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=66dd75bc9f809d79c0c176b02344ed3b" alt="Updating the inner section's visibility property" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2u.png" />
  </Step>
</Steps>

## Test the application

You've completed all the steps to make a working social post generator, and you can try using it right now, even while editing the user interface!

Enter a topic into the **Topic for social posts and tags** text field, then click the **Generate Posts** button\* *twice* — the first time will cause the **properties** panel to appear, and the second click will register as a click. You'll know that you've clicked the button when you see the **Message** component display the text “Generating social media posts and tags for you...”

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2v.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=447377026cf15c91a31ae023e09a8a40" alt="Waiting for the generator to finish while the message component displays its message" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2v.png" />

...and soon after that, you should see some results:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2w.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=8592349842ed1474717e26c14496c515" alt="The results" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2w.png" />

To get a better sense of what the experience will be like for the user, switch to the preview by changing the edit mode (located near the upper left corner of the page) from *UI* mode to *Preview* mode by selecting the **Preview** option:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2x.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=80d54c9686267c8e3b98c45478ecf7e9" alt="The project editor with an arrow pointing to the Preview button" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2x.png" />

Here’s what the app looks like in *Preview* mode:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2y.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=5a85e393eff468bcadf056e260e23b95" alt="The working social post generator, with the project editor in &#x22;Preview&#x22; mode" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2y.png" />

You can see the output of any `print()` functions and error messages by clicking on the **Log** button located near the upper right corner of the page:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2z.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=8d7cd482ba5658595eba7246578fbe28" alt="The social post generator with an arrow pointing to the Log button" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2z.png" />

Here’s what the app looks like when displaying the log:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2aa.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=c27dfb7ee4bed11a5c0908343a4bac3d" alt="The social post generator, with the log pane displayed" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2aa.png" />

It's very helpful to be able to test the application while editing it. As you continue to work with Writer Framework, you'll find yourself alternating between making changes to your application and testing those changes without having to leave the project editor.

## Run the application locally

Once you've tested the application, it's time to run it locally.

Switch back to your terminal application. Stop the editor with ctrl-c, then run the application by entering the following command:

```
writer run social-post-generator
```

Note that the command starts with `writer run` as opposed to `writer edit`. This launches the application as your users will see it, without any of the editing tools. Even though you can preview your applications in the project editor, it's still a good idea to test it by running it on your computer, outside the project editor, before deploying it.

You'll be able to access the application with your browser at the URL that appears on the command line. It should look like this:

<img src="https://mintcdn.com/writer/PCF7UWM79DSDrLoF/framework/images/tutorial/social_post/sp_gen_2ab.png?fit=max&auto=format&n=PCF7UWM79DSDrLoF&q=85&s=e38dd8f9a9fe0a6b6976706902b45761" alt="Finished social post generator project" width="3000" height="2000" data-path="framework/images/tutorial/social_post/sp_gen_2ab.png" />

<Note>The Writer editor, which you launched with `writer edit social-post-generator`, and your application, which you launched with `writer run social-post-generator`, run  on the same URL, but on different *ports* (specified by the number after the `:` character at the end of the URL).</Note>

## Conclusion

That's it — you've built a functional social post generator using the Writer Framework!

Feel free to modify this project! The Writer platform is flexible enough for you to customize, extend, and evolve your application into something completely different! To find out what else you can do, check out the documentation for [Writer Framework](https://dev.writer.com/framework/introduction) and the [Writer API](https://dev.writer.com/introduction).
