| """kwest.dev is a saas tool to craft stories for your ideas.""" | |
| import os | |
| from typing import Union | |
| import requests | |
| import streamlit as st | |
| API_URL = os.getenv("API_URL", None) | |
| AUTH_TOKEN = os.getenv("AUTH_TOKEN", None) | |
| RECIPES = ["sell", "motivate", "convince", "connect", "explain", "lead", "impress"] | |
| VALID_EMOJIS = {"yes": "β ", "no": "β"} | |
| if not API_URL or not AUTH_TOKEN: | |
| raise ValueError("API_URL and AUTH_TOKEN secrets must be set in the environment variables.") | |
| def check_if_input_is_valid(input_str: str) -> Union[dict[str, str], None]: | |
| """Check if the input string is valid for the API.""" | |
| response = requests.post( | |
| f"{API_URL}input-check", | |
| headers={"Authorization": f"{AUTH_TOKEN}", "Accept": "application/json"}, | |
| json={"input": input_str}, | |
| ) | |
| if response.status_code == 200: | |
| return response.json()["output"] | |
| else: | |
| return None | |
| def get_recipe_choices(input_str: str) -> Union[dict[str, str], None]: | |
| """Get the recipe choices for the input string.""" | |
| response = requests.post( | |
| f"{API_URL}recipe-choice", | |
| headers={"Authorization": f"{AUTH_TOKEN}", "Accept": "application/json"}, | |
| json={"input": input_str}, | |
| ) | |
| if response.status_code == 200: | |
| return response.json()["output"] | |
| else: | |
| return None | |
| def craft_story_from_recipe(input_str: str, recipe: str) -> None: | |
| """Craft a story from the input string and recipe.""" | |
| response = requests.post( | |
| f"{API_URL}craft-from-recipe", | |
| headers={"Authorization": f"{AUTH_TOKEN}", "Accept": "application/json"}, | |
| json={"input": input_str, "recipe": recipe}, | |
| ) | |
| if response.status_code == 200: | |
| st.session_state.story = response.json()["output"]["story"] | |
| else: | |
| raise ValueError("An error occurred while crafting the story.") | |
| st.markdown( | |
| """ | |
| <style> | |
| button { | |
| height: 100px !important; | |
| } | |
| </style> | |
| """, | |
| unsafe_allow_html=True, | |
| ) | |
| st.title("kwest.dev") | |
| st.subheader("Leverage the power of storytelling for any idea. π‘") | |
| with st.expander(label="How to present your idea to get the best story π", expanded=True): | |
| st.markdown( | |
| """ | |
| - π― Explain the **main objective** of your idea. What is the **main goal** you are trying to achieve? | |
| - π Give as much **context** as possible. For example, what is the problem you are trying to solve? If you have a good name for your idea, share it. | |
| - π€ What is the **audience** for your idea? Who are the people that should be interested in it? | |
| Once you have shared these details, you will have the opportunity to choose a recipe to craft your story. | |
| The different recipes available are: `sell`, `motivate`, `convince`, `connect`, `explain`, `lead`, `impress` | |
| You can choose the recipe that best fits your idea, but to help you decide we will mark the 1st and 2nd best recipes with π₯ and π₯ respectively. | |
| --- | |
| __Examples of good and bad inputs:__ | |
| β `I need a pitch for a new app that helps people find the best restaurants in town based on their previous feedback. I will present it to angel investors. The name of the app is "Foodie".` | |
| β `I want to present to my friends the idea of a collaborative group of people that help each other to achieve their goals. I want to motivate them to join the group to allow people to share knowledge together and grow skills using peer-to-peer learning.` | |
| β `I'm going to present a new way to manage projects to my team. I want to convince them that this new method will help us be more efficient, reduce stress, and deliver better results.` | |
| β `I need a pitch for a new app. It's cool.` | |
| """ | |
| ) | |
| input_col, btn_col = st.columns([3, 1], vertical_alignment="bottom") | |
| with input_col: | |
| input_str = st.text_area("Your idea that needs a story", "", placeholder="I need a pitch for ...") | |
| with btn_col: | |
| check_input = st.button(label="βΆοΈ", key="check_input", help="Check if the input is valid") | |
| if check_input and input_str != "": | |
| input_is_valid = check_if_input_is_valid(input_str) | |
| if input_is_valid is None: | |
| st.error("An error occurred while checking the input. Please try again.") | |
| st.stop() | |
| else: | |
| st.write( | |
| f"Objective: {VALID_EMOJIS[input_is_valid['objective']]} | " | |
| f"Context: {VALID_EMOJIS[input_is_valid['context']]} | " | |
| f"Audience: {VALID_EMOJIS[input_is_valid['audience']]}" | |
| ) | |
| if input_is_valid["objective"] == "yes" and input_is_valid["context"] == "yes" and input_is_valid["audience"] == "yes": | |
| recipe_choices = get_recipe_choices(input_str) | |
| st.write("Choose the recipe you want to use for your story.") | |
| recipe_choices_col = st.columns(7, vertical_alignment="bottom") | |
| for idx, recipe in enumerate(RECIPES): | |
| with recipe_choices_col[idx]: | |
| if recipe == recipe_choices["recipe"]: | |
| _recipe = f"π₯{recipe}" | |
| elif recipe == recipe_choices["second_recipe"]: | |
| _recipe = f"π₯{recipe}" | |
| else: | |
| _recipe = recipe | |
| st.button( | |
| _recipe, | |
| on_click=craft_story_from_recipe, | |
| kwargs={"input_str": input_str, "recipe": recipe}, | |
| use_container_width=True, | |
| ) | |
| if "story" in st.session_state: | |
| st.markdown(st.session_state.story) | |
| del st.session_state.story | |