Build a Full Stack Storybooks Application with Low-Code: Rowy x BravoStudio
Tags: googlecloud, tutorial, beginners, codenewbie
Published: 2023-06-15 21:40:49

<p>Imagine generating captivating storybooks from simple one-line prompts! 🤯 With our <strong>full-stack</strong>, <strong>low-code</strong>, Story Books template, effortlessly <strong>create storybooks featuring auto-generated titles</strong>, <strong>subtitles</strong>, <strong>multiple pages</strong>, and <strong>vibrant illustrations</strong>. </p>
<p>And that's not all! </p>
<p>We enhance the experience by <strong>generating an audio file</strong> for each story page, enabling users to listen to the stories instead of reading them.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FDXTiPw8DBo5EZ7GaYeG7-storybooks-1.png?alt=media&token=7f41e8c5-4b96-4410-aa66-a337101a3999" alt="storybooks-rowy-bravo-1" /></p>
<p>Let’s dive deeper and explore a powerful combination of tools that can bring your bedtime storybook app to life! 💪</p>
<h2 id="thestorybooksapplication">The Story Books Application 📖</h2>
<p>The Story Books application is designed to <strong>create engaging bedtime stories for children</strong>. It harnesses the power of the <strong>GPT-4 API</strong> to <strong>convert simple one-line prompts into entire storybooks</strong> filled with captivating tales. The app takes it a step further by leveraging the Stability AI API to generate beautiful illustrations for every page of the story.</p>
<p>We wanted to make the reading experience even more immersive and interactive, so we incorporated the <strong>PlayHT API</strong>. This means you can <strong>listen to the stories</strong> instead of reading them! It's a fantastic way to make the app more <strong>accessible</strong> and engaging for all users.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FxUiWb0CYnbjdmq6SAdGM-storybooks-2.png?alt=media&token=ca17d900-dd19-4de4-b1b5-d824f3ef02a6" alt="storybooks-rowy-bravo-2" /></p>
<p>To get started, you can create your own Story Books app using our <a href="https://rowy.app/workspaces">cloneable AI templates</a> that combines <a href="https://www.rowy.io/">Rowy</a> as the spreadsheet UI backend and CMS, and <a href="https://www.bravostudio.app/">Bravo Studio</a> as the front-end no-code app builder. Thus you can easily manage the content of your stories using low-code app development. </p>
<h2 id="whatisbravostudio">What is Bravo Studio?</h2>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FKatTW1lw7kwi8V3eh4QB-storybooks-3.png?alt=media&token=36ae87bb-22aa-4829-aaf8-83d2e90262b7" alt="storybooks-rowy-bravo-3" /></p>
<p>Bravo Studio is a <strong>code-free app builder</strong> that transforms your <strong>Figma</strong> or <strong>AdobeXD</strong> prototypes into native iOS and Android apps instantly. It also let’s you c<strong>onnect to external APIs</strong> and use the <strong>Data Library</strong> to give you the ability to connect your data with real data from an external source.</p>
<p>Bravo Studio utilizes <strong>Bravo Tags</strong>, which are merely native mobile components to make your apps Android and iOS compatible. These Bravo Tags enable Bravo to identify the native behavior in your apps such as slide menu, splash screens, and even Lottie Animations, to make real components and converting them to an original app in Bravo Studios.</p>
<p>With Bravo Studio, you can effortlessly turn your storybook content into a visually stunning and interactive mobile app, all without the need to write a single line of code.</p>
<h2 id="settingupthestorybooksapplication">Setting up the Story Books Application ✨</h2>
<p>Let us give you a quick walk-through on how you can set up your Story Books application with Rowy and Bravo Studio!</p>
<h3 id="1cloningthetemplateonrowy">1. Cloning the template on Rowy 🤩</h3>
<p>The first step is to visit www.rowy.io and click on the "Sign In" button. Once you have created your Workspace and set up your Project, you need to select the Story Books template from the "Create a Table" section located at the top of the page.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FoUblBkEbU6FipGJNIIfH-storybooks-4.png?alt=media&token=dd3a6069-155a-429a-ad9b-80d01058ed30" alt="storybooks-rowy-bravo-4" /></p>
<p>You'll be guided by the template setup wizard to easily configure your table, include your confidential keys, and deploy your cloud functions, all in a single seamless process!</p>
<h3 id="2settingupyoursecrets">2. Setting up your Secrets 🤫</h3>
<p>To begin the template setup, you will be asked to provide three secret keys: your <strong>OpenAI API Key</strong>, <strong>PlayHT Secret Key</strong>, and <strong>Stability AI API Key.</strong></p>
<p>Here are the steps to obtain these secret keys for your project:</p>
<h4 id="21retrievingtheopenaiapikey">2.1 Retrieving the OpenAI API Key ✅</h4>
<ul>
<li>Go to the <a href="https://platform.openai.com/account/api-keys">OpenAI Account Dashboard</a> and create an account if you haven’t already.</li>
<li>Click on <strong>Create a new secret key</strong>.
<img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2Ft7ecwW5pR3o2BjdSL6zf-storybooks-5.png?alt=media&token=22fbae06-68b3-4cb0-a48d-5f261143668a" alt="storybooks-rowy-bravo-4" /></li>
<li>Add a name for your secret key. Let's use "<strong>Story Book</strong>" as an example. Finally, click "<strong>Create</strong>" to save your new secret key.</li>
<li>Great! You've generated your OpenAI API Key. 🎉 Make sure to copy and store it in a safe and accessible location, since you'll be needing it later.</li>
</ul>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FdFAMUDyl2Qxm2uIpyWaE-storybooks-6.png?alt=media&token=028f55fb-e038-4446-b94e-ac219ddc6cc2" alt="storybooks-rowy-bravo-5" /></p>
<p>In the Template Setup Wizard, when prompted to add your OpenAI API Key, click on the "<strong>Add a key in Secret Manager</strong>" button. This will redirect you to the <a href="https://console.cloud.google.com/security/secret-manager">GCP Secret Manager</a>. Add your OpenAI API Key as shown below and click "<strong>Create a Secret</strong>".</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2Fwu0lI3I6VLCxbcn9CxYw-storybooks-7.png?alt=media&token=c64af9fc-798a-44a4-b68c-f10edfeb148f" alt="storybooks-rowy-bravo-6" /></p>
<p>Now, you can go back to the setup process. Simply click on the Secret dropdown and select your newly generated API Key. If you can't see it, try clicking the “<strong>Refresh</strong>” button.</p>
<h4 id="22retrievingtheplayhtsecretkey">2.2 Retrieving the PlayHT Secret Key ✅</h4>
<ul>
<li>Navigate to the <a href="https://play.ht/app/api-access">PlayHT Developer Dashboard</a>. Create an account, if you haven’t already and copy the <strong>User ID</strong> and <strong>Secret Key</strong>.
<img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FTi4Oy4LoK6AMBnkoLZmX-storybooks-8.png?alt=media&token=249c9e22-c302-49b1-86b6-1a64a8c80b08" alt="storybooks-rowy-bravo-7" /></li>
</ul>
<p>That’s it! Now, you’ve generated your User ID and Secret Key! 🎉 In the Template Setup Wizard, when prompted to add your PlayHT Secret Key, click on the "<strong>Add a key in Secret Manager</strong>" button. This will redirect you to the <a href="https://console.cloud.google.com/security/secret-manager">GCP Secret Manager</a>. Add your PlayHT Key as shown below and click <strong>Create a Secret</strong>.</p>
<pre><code class="js language-js">{
    "userId": "PASTE YOUR USER ID HERE",
    "secretKey": "PASTE YOUR SECRET KEY HERE"
}
</code></pre>
<p>After generating the <strong>PlayHT Secret Key</strong>, you can return to the setup process and select your newly generated API key from the Secret dropdown.</p>
<h4 id="23retrievingthestabilityaiapikey">2.3 Retrieving the Stability AI API Key ✅</h4>
<ul>
<li>Go to the <a href="https://beta.dreamstudio.ai/account">DreamStudio Dashboard</a> by <strong>Stability AI</strong>, and create an account via a simple step-by-step guided process.</li>
<li>Click on “<strong>Get API Key</strong>” button to generate your API Key.
<img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2F8DzX5Od8i6QIQe8IuPH9-storybooks-9.png?alt=media&token=7d1f959a-468e-4d0e-99a8-885f1583025b" alt="storybooks-rowy-bravo-8" /></li>
</ul>
<p>Your Stability AI API Key is now generated! 🎉</p>
<p>In the Template Setup Wizard, when prompted to add your <strong>Stability AI Secret Key</strong>, click on the <strong>Add a key in Secret Manager</strong> button. This will redirect you to the <a href="https://console.cloud.google.com/security/secret-manager">GCP Secret Manager</a>. Add your Stability AI Key as shown below and click <strong>Create a Secret</strong>.</p>
<pre><code class="js language-js">"PASTE YOUR API KEY HERE"
</code></pre>
<p>After generating the <strong>Stability AI Secret Key</strong>, you can go back to the setup process, click <strong>Refresh</strong> and select the generated API key from the Secret dropdown.</p>
<h2 id="understandingandcustomisinglogicandfunctionalityofstorybooks">Understanding and Customising Logic and Functionality of Story Books 💭</h2>
<p>When you click on the "<strong>Add Row</strong>" button to create a new entry, you have the option to select the <strong>Writing Style</strong> from a dropdown menu. The available styles are <strong>inspired by renowned authors and illustrators</strong> in the field of children's literature. If you prefer, you can customize the list by adding or removing the names of authors of your choice through the "<strong>Column Config</strong>" settings.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2F0mT95mJPSjtnlMSwFMql-storybooks-10.png?alt=media&token=8fd16c2c-3be2-4f3f-9112-9663ccd1769d" alt="storybooks-rowy-bravo-9" /></p>
<p>The story is generated based on the content in the "<strong>Prompt</strong>" field. You can input any idea that comes to mind and the system will generate a story around it. For instance, you could enter <code>A curious squirrel's exciting forest treasure hunt teaches the value of friendship</code>.</p>
<p>The "<strong>Response</strong>" column is a Derivative Field that utilizes the power of OpenAI's GPT-4 API to generate story content in the form of a JSON object.</p>
<p>To access and modify the underlying logic responsible for generating the stories, simply go to the "<strong>Column Config</strong>" menu for the "<strong>Response</strong>" field.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2F9YnUiND5Hr8VLMrJFC4Y-storybooks-11.png?alt=media&token=1fb19ab4-b427-470d-a7b2-5be61b3eb81f" alt="storybooks-rowy-bravo-10" /></p>
<h2 id="storybooksresponseinsidethescript">Story Books Response - Inside the Script 📜</h2>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FoKzJHS1vNwyA0U9b2Qrg-storybooks-12.png?alt=media&token=fd11fc60-a24f-430e-ac0e-b989c33f5c9c" alt="storybooks-rowy-bravo-11" /></p>
<p>The <code>systemPrompt</code> variable is responsible for conveying the story prompt to the AI. We have set the <code>response</code> column to return the generated story book data in the form of a Structured JSON response, which would help us to parse through the data easily.</p>
<pre><code class="js language-js">{
  "cover":{
      "title":string,
    "subtitle":string,
        "illustration":string
   },
   "pages":[
     {
            index:number,
      "illustration":string,
          "text":string
     }
   ]  
}
</code></pre>
<p>Via this derivative field’s JSON contents, we’ll be extracting the various components of our Story Books Application, such as the <strong>Story Title, Subtitle, the illustration prompt</strong> for generating the cover image, and the <strong>story pages with respective illustrations</strong>.</p>
<blockquote>
  <p>We can also add additional instructions and rules for the storybook content, such as they must be meaningful, have a good moral, be safe for children to hear, and must not contain explicit content.</p>
</blockquote>
<p>In the API call to OpenAI, we specify the model, which is <code>gpt-4</code>, and the temperature. The Temperature always lies in the range of 0 to 1. The Temperature is particularly useful when we want the API to complete something, where there is only one answer and vice versa. If you want to generate ideas or complete a story, higher temperature will bring us more variety.</p>
<pre><code class="js language-js">const response = await openai.createChatCompletion({
      model: "gpt-4",
      temperature: 0.7,
      messages: [
        { role: "system", content: systemPrompt },
        //...chatHistory,
        {
          role: "user",
          content: row.prompt,
        }
      ]
    })
</code></pre>
<p>When the temperature is set to <code>0</code>, the responses become quite straightforward and lack creativity, almost being deterministic. On the other hand, when the temperature is set to <code>1</code>, the responses exhibit a wide range of creativity and can vary significantly.</p>
<h2 id="generatingcoverimages">Generating Cover Images 🖼️</h2>
<p>The prompt for generating the cover image of the story is stored in the "<strong>Cover Illustration</strong>" field, which is <strong>obtained from OpenAI's response</strong>. To generate the cover image, you can choose from a <strong>variety of style presets</strong> available in the "<strong>Style Preset</strong>" dropdown menu.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FkDNLYQRTXpMNpOxFnKFV-storybooks-13.png?alt=media&token=011d2470-2448-4654-af56-1aab9f96d001" alt="storybooks-rowy-bravo-12" /></p>
<p>The "<strong>Style Preset</strong>" field can be customized through the Column Config menu. You have the option to add or remove style presets or change the default preset.</p>
<p>Both the "<strong>Cover Illustration</strong>" and "<strong>Style Presets</strong>" fields serve as listeners for image generation. Any modifications made to these fields will trigger the regeneration of the cover image.</p>
<p>If you are not satisfied with the appearance of your cover image, you have the flexibility to directly modify the prompt in the table or select a different style preset of your preference.</p>
<h2 id="selectingvoiceforthegeneratedstory">Selecting Voice for the Generated Story 🎧</h2>
<p>The “<strong>Voice</strong>” column is a Connector field type which calls an external API, in our case it calls the PlayHT <code>getVoices</code> end-point. This allows us to fetch the list of voices we can generate our audio story in.</p>
<p>This ensures our app stays up-to-date as it would get all the updated voice options without having to manually add them in the dropdown menu.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FPNPBOZBR945y9SzxNbQl-storybooks-14.png?alt=media&token=eb73d203-48f0-4139-a81d-ea842fafc471" alt="storybooks-rowy-bravo-13" /></p>
<h2 id="extractingpagestoasubtable">Extracting Pages to a Sub-table 📑</h2>
<p>Once we get our generated response via OpenAI, we can see that our response consists of two parts:</p>
<ul>
<li><code>cover</code> which contains the illustration, subtitle, and title for our story.</li>
<li><code>pages</code> which contains illustration, index, and the story text for every page.</li>
</ul>
<p>Now, to be able to convert this response into separate pages, we have a <strong>Sync Pages</strong> extension deployed which automates creating a document in a sub-collection for each page in the story. The extension is triggered by the <code>responsePages</code> , <code>stylePreset</code> , and <code>voiceId</code> fields, which means any changes in these columns will trigger a re-evaluation of the <strong>Sync Pages</strong> extension.</p>
<p>The <strong>Sync Pages</strong> extension body automates going through all the pages in the response and adds a document for each page of the story in the sub-table.</p>
<pre><code class="js language-js">await Promise.all(row.response.pages.map(async(page,i)=&gt;{
   console.log(`p-${i}`)
    await ref.collection('pages').doc(`p-${i}`).set({...page,stylePreset,voiceId},{merge:true})
  }))
</code></pre>
<h2 id="bravointegration">Bravo Integration 🚀</h2>
<p>We will be <strong>utilizing Rowy Webhooks to set up the connection and access data</strong> in our Rowy table via the Bravo Studio frontend.</p>
<h3 id="createastorywebhook">“Create a Story” Webhook 🕸️</h3>
<p>We have the option to enable verification via a Firebase Authorization token, which needs to be passed as a Header as <code>Authorization: Bear ACCESS_TOKEN</code>. This allows you to assert a restriction to who can access which stories. <strong>This verification is entirely optional</strong>.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/website-a1s39m.appspot.com/o/blog%2F6HEbFhFrwOjGlZ60A9hi%2FcontentImages%2FS6oamqRhmtM991tohg9S-storybooks-15.png?alt=media&token=6bd6a878-4c9e-4480-800c-1b0625d71937" alt="storybooks-rowy-bravo-14" /></p>
<p>The Parser function takes the request inside the body, and creates a new document for the incoming prompt to generate a new story. We can also add the <strong>Writing Style</strong>, <strong>Preset Style</strong>, and the <strong>Voice</strong>.</p>
<pre><code class="js language-js">// send a post requst with body containing 'prompt' key with prompt of the story 
  const { body } = req;
    return { ...body}
</code></pre>
<h3 id="getstorieswebhook">“Get Stories” Webhook 🕸️</h3>
<p>This is the Webhook responsible for getting the stories. The parser queries the collection to get the stories table. The parser maps through the query documents to create the stories objects and sends it back to the client.</p>
<h2 id="rowyxbravostudioapowerfulcombinationforyourbedtimestorybookapp">Rowy X Bravo Studio: A Powerful Combination for Your Bedtime Storybook App 💪✨</h2>
<p>The Rowy X Bravo Studio combination offers a <strong>highly reusable and extensible</strong> app-building solution that <strong>opens up a world of possibilities for no-code and low-code users</strong>. With the Story Books template, you can effortlessly create captivating storybooks by simply providing one-line prompts, making it ideal for users to reuse the template logic and enhance it to their liking.</p>
<p>With its user-friendly interface and the ability to manage and organize content using Rowy as the backend CMS, the possibilities for creating interactive mobile apps extend beyond storybooks. From educational apps and interactive catalogs, to guided tours and immersive experiences, the Rowy X Bravo Studio duo empowers users to transform their creative visions into reality, all without the need for coding expertise.</p>
<p>Experience the boundless potential of <strong>Rowy X Bravo Studio</strong>and unlock your imagination to craft captivating, interactive applications that leave a lasting impression on your audience.</p>
<p>If you enjoyed our content, please give us a&nbsp;<a href="https://twitter.com/rowyio">follow on Twitter</a>&nbsp;or&nbsp;<a href="https://rowy.io/discord">join our Discord</a>&nbsp;in case of any questions. We look forward to hearing from you! 💜</p>