# Create app to read and display data from Excel file  import pandas as pd  from taipy import Gui    # ---- READ EXCEL ----  df = pd.read_excel(      io="data/supermarkt_sales.xlsx",      engine="openpyxl",      sheet_name="Sales",      skiprows=3,      usecols="B:R",      nrows=1000,  )  # Add 'hour' column to dataframe  df["hour"] = pd.to_datetime(df["Time"], format="%H:%M:%S").dt.hour      # initialization of variables  cities = list(df["City"].unique())  types = list(df["Customer_type"].unique())  genders = list(df["Gender"].unique())  city = cities  customer_type = types  gender = genders    layout = {"margin": {"l": 220}}    # Markdown for the entire page  ## NOTE: {: .orange} references a color from main.css use to style my text  ## <text|  ## |text>  ## "text" here is just a name given to my part/my section  ## it has no meaning in the code  page = """<|toggle|theme|>    <|layout|columns=20 80|gap=30px|  <sidebar|  ## Please **filter**{: .orange} here:    <|{city}|selector|lov={cities}|multiple|label=Select the City|dropdown|on_change=on_filter|width=100%|>    <|{customer_type}|selector|lov={types}|multiple|label=Select the Customer Type|dropdown|on_change=on_filter|width=100%|>    <|{gender}|selector|lov={genders}|multiple|label=Select the Gender|dropdown|on_change=on_filter|width=100%|>  |sidebar>    <main_page|  # 📊 **Sales**{: .orange} Dashboard    <|layout|columns=1 1 1|  <total_sales|  ## **Total**{: .orange} sales:  ### US $ <|{int(df_selection["Total"].sum())}|>  |total_sales>    <average_rating|  ## **Average**{: .orange} Rating:  ### <|{round(df_selection["Rating"].mean(), 1)}|> <|{"⭐" * int(round(round(df_selection["Rating"].mean(), 1), 0))}|>  |average_rating>    <average_sale|  ## Average Sales Per **Transaction**{: .orange}:  ### US $ <|{round(df_selection["Total"].mean(), 2)}|>  |average_sale>  |>    <br/>    Display df_selection in an expandable  <|Sales Table|expandable|expanded=False|  <|{df_selection}|table|width=100%|page_size=5|rebuild|class_name=table|>  |>    <charts|  <|{sales_by_hour}|chart|x=Hour|y=Total|type=bar|title=Sales by Hour|color=#ff462b|>    <|{sales_by_product_line}|chart|x=Total|y=Product|type=bar|orientation=h|title=Sales by Product|layout={layout}|color=#ff462b|>  |charts>  |main_page>  |>    Code from [Coding is Fun](https://github.com/Sven-Bo)    Get the Taipy Code [here](https://github.com/Avaiga/demo-sales-dashboard) and the original code [here](https://github.com/Sven-Bo/streamlit-sales-dashboard)  """      def filter(city, customer_type, gender):      df_selection = df[          df["City"].isin(city)          & df["Customer_type"].isin(customer_type)          & df["Gender"].isin(gender)      ]        # SALES BY PRODUCT LINE [BAR CHART]      sales_by_product_line = (          df_selection[["Product line", "Total"]]          .groupby(by=["Product line"])          .sum()[["Total"]]          .sort_values(by="Total")      )      sales_by_product_line["Product"] = sales_by_product_line.index        # SALES BY HOUR [BAR CHART]      sales_by_hour = (          df_selection[["hour", "Total"]].groupby(by=["hour"]).sum()[["Total"]]      )      sales_by_hour["Hour"] = sales_by_hour.index      return df_selection, sales_by_product_line, sales_by_hour      def on_filter(state):      state.df_selection, state.sales_by_product_line, state.sales_by_hour = filter(          state.city, state.customer_type, state.gender      )      if __name__ == "__main__":      # initialize dataframes      df_selection, sales_by_product_line, sales_by_hour = filter(          city, customer_type, gender      )        # run the app      Gui(page).run()


# Create an app with slider and chart  from taipy.gui import Gui  from math import cos, exp    value = 10    page = """  Markdown  # Taipy *Demo*    Value: <|{value}|text|>    <|{value}|slider|on_change=on_slider|>    <|{data}|chart|>  """    def compute_data(decay:int)->list:      return [cos(i/6) * exp(-i*decay/600) for i in range(100)]    def on_slider(state):      state.data = compute_data(state.value)    data = compute_data(value)    Gui(page).run(use_reloader=True, port=5002)


# Create app to predict covid in the world  from taipy.gui import Gui  import taipy as tp    from pages.country.country import country_md  from pages.world.world import world_md  from pages.map.map import map_md  from pages.predictions.predictions import predictions_md, selected_scenario  from pages.root import root, selected_country, selector_country    from config.config import Config    pages = {      '/':root,      "Country":country_md,      "World":world_md,      "Map":map_md,      "Predictions":predictions_md  }      gui_multi_pages = Gui(pages=pages)    if __name__ == '__main__':      tp.Core().run()            gui_multi_pages.run(title="Covid Dashboard")


# Create app for finance data analysis  import yfinance as yf  from taipy.gui import Gui  from taipy.gui.data.decimator import MinMaxDecimator, RDP, LTTB      df_AAPL = yf.Ticker("AAPL").history(interval="1d", period="100Y")  df_AAPL["DATE"] = df_AAPL.index.astype("int64").astype(float)    n_out = 500  decimator_instance = MinMaxDecimator(n_out=n_out)    decimate_data_count = len(df_AAPL)    page = """  # Decimator    From a data length of <|{len(df_AAPL)}|> to <|{n_out}|>    ## Without decimator    <|{df_AAPL}|chart|x=DATE|y=Open|>    ## With decimator    <|{df_AAPL}|chart|x=DATE|y=Open|decimator=decimator_instance|>  """    gui = Gui(page)  gui.run(port=5026)


# Create an app to upload a csv and display it in a table  from taipy.gui import Gui  import pandas as pd    data = []  data_path = ""      def data_upload(state):      state.data = pd.read_csv(state.data_path)      page = """  <|{data_path}|file_selector|on_action=data_upload|>  <|{data}|table|>  """    Gui(page).run()


# Create an app to visualize sin and amp with slider and chart  from taipy.gui import Gui  from math import cos, exp    state = {"amp": 1, "data":[]}    def update(state):    x = [i/10 for i in range(100)]    y = [math.sin(i)*state.amp for i in x]      state.data = [{"data": y}]    page = """  Amplitude: <|{amp}|slider|>  <|Data|chart|data={data}|>   """    Gui(page).run(state=state)


# Create an app to visualize sin, cos with slider and chart  from taipy.gui import Gui  from math import sin, cos, pi    state = {    "frequency": 1,    "decay": 0.01,    "data": []    }    page = """  # Sine and Cosine Functions    Frequency: <|{frequency}|slider|min=0|max=10|step=0.1|on_change=update|>   Decay: <|{decay}|slider|min=0|max=1|step=0.01|on_change=update|>    <|Data|chart|data={data}|>  """    def update(state):    x = [i/10 for i in range(100)]        y1 = [sin(i*state.frequency*2*pi) * exp(-i*state.decay) for i in x]    y2 = [cos(i*state.frequency*2*pi) * exp(-i*state.decay) for i in x]        state.data = [      {"name": "Sine", "data": y1},      {"name": "Cosine", "data": y2}    ]    Gui(page).run(use_reloader=True, state=state)


# Create app to visualize country population  import numpy as np  import pandas as pd    from taipy.gui import Markdown    from data.data import data    selected_country = 'France'  data_country_date = None    representation_selector = ['Cumulative', 'Density']  selected_representation = representation_selector[0]    layout = {'barmode':'stack', "hovermode":"x"}  options = {"unselected":{"marker":{"opacity":0.5}}}      def initialize_case_evolution(data, selected_country='France'):      # Aggregation of the dataframe to erase the regions that will not be used here      data_country_date = data.groupby(["Country/Region",'Date'])\                              .sum()\                              .reset_index()            # a country is selected, here France by default      data_country_date = data_country_date.loc[data_country_date['Country/Region']==selected_country]      return data_country_date    data_country_date = initialize_case_evolution(data)  pie_chart = pd.DataFrame({"labels": ["Deaths", "Recovered", "Confirmed"],"values": [data_country_date.iloc[-1, 6], data_country_date.iloc[-1, 5], data_country_date.iloc[-1, 4]]})        def convert_density(state):      if state.selected_representation == 'Density':          df_temp = state.data_country_date.copy()          df_temp['Deaths'] = df_temp['Deaths'].diff().fillna(0)          df_temp['Recovered'] = df_temp['Recovered'].diff().fillna(0)          df_temp['Confirmed'] = df_temp['Confirmed'].diff().fillna(0)          state.data_country_date = df_temp      else:          state.data_country_date = initialize_case_evolution(data, state.selected_country)    def on_change_country(state):      # state contains all the Gui variables and this is through this state variable that we can update the Gui      # state.selected_country, state.data_country_date, ...      # update data_country_date with the right country (use initialize_case_evolution)      print("Chosen country: ", state.selected_country)      state.data_country_date = initialize_case_evolution(data, state.selected_country)      state.pie_chart = pd.DataFrame({"labels": ["Deaths", "Recovered", "Confirmed"],                                      "values": [state.data_country_date.iloc[-1, 6], state.data_country_date.iloc[-1, 5], state.data_country_date.iloc[-1, 4]]})            convert_density(state)      page ="""    # **Country**{: .color-primary} Statistics    <|layout|columns=1 1 1|  <|{selected_country}|selector|lov={selector_country}|on_change=on_change_country|dropdown|label=Country|>    <|{selected_representation}|toggle|lov={representation_selector}|on_change=convert_density|>  |>
    <|layout|columns=1 1 1 1|gap=50px|  <|card|  **Deaths**{: .color-primary}  <|{'{:,}'.format(int(data_country_date.iloc[-1]['Deaths'])).replace(',', ' ')}|text|class_name=h2|>  |>    <|card|  **Recovered**{: .color-primary}  <|{'{:,}'.format(int(data_country_date.iloc[-1]['Recovered'])).replace(',', ' ')}|text|class_name=h2|>  |>    <|card|  **Confirmed**{: .color-primary}  <|{'{:,}'.format(int(data_country_date.iloc[-1]['Confirmed'])).replace(',', ' ')}|text|class_name=h2|>  |>  |>
    <|layout|columns=2 1|  <|{data_country_date}|chart|type=bar|x=Date|y[3]=Deaths|y[2]=Recovered|y[1]=Confirmed|layout={layout}|options={options}|title=Covid Evolution|>    <|{pie_chart}|chart|type=pie|values=values|labels=labels|title=Distribution between cases|>  |>    """    Gui(page).run(use_reloader=True, state=state)


# Create Taipy app to generate mandelbrot fractals    from taipy import Gui    import numpy as np  from PIL import Image  import matplotlib.pyplot as plt    WINDOW_SIZE = 500    cm = plt.cm.get_cmap("viridis")      def generate_mandelbrot(      center: int = WINDOW_SIZE / 2,      dx_range: int = 1000,      dx_start: float = -0.12,      dy_range: float = 1000,      dy_start: float = -0.82,      iterations: int = 50,      max_value: int = 200,      i: int = 0,  ) -> str:      mat = np.zeros((WINDOW_SIZE, WINDOW_SIZE))      for y in range(WINDOW_SIZE):          for x in range(WINDOW_SIZE):              dx = (x - center) / dx_range + dx_start              dy = (y - center) / dy_range + dy_start              a = dx              b = dy              for t in range(iterations):                  d = (a * a) - (b * b) + dx                  b = 2 * (a * b) + dy                  a = d                  h = d > max_value                  if h is True:                      mat[x, y] = t        colored_mat = cm(mat / mat.max())      im = Image.fromarray((colored_mat * 255).astype(np.uint8))      path = f"mandelbrot_{i}.png"      im.save(path)        return path      def generate(state):      state.i = state.i + 1      state.path = generate_mandelbrot(          dx_start=-state.dx_start / 100,          dy_start=(state.dy_start - 100) / 100,          iterations=state.iterations,          i=state.i,      )      i = 0  dx_start = 11  dy_start = 17  iterations = 50    path = generate_mandelbrot(      dx_start=-dx_start / 100,      dy_start=(dy_start - 100) / 100,  )    page = """  # Mandelbrot Generator    <|layout|columns=35 65|  Display image from path  <|{path}|image|width=500px|height=500px|class_name=img|>    Iterations:
  Create a slider to select iterations  <|{iterations}|slider|min=10|max=50|continuous=False|on_change=generate|>
  X Position:
  <|{dy_start}|slider|min=0|max=100|continuous=False|on_change=generate|>
  Y Position:
    Slider dx_start  <|{dx_start}|slider|min=0|max=100|continuous=False|on_change=generate|>
  |>  """    Gui(page).run(title="Mandelbrot Generator")


# Create app to auto generate Tweeter status  import logging  import random  import re    # Import from 3rd party libraries  from taipy.gui import Gui, notify, state  import taipy    # Import modules  import oai    # Configure logger  logging.basicConfig(format="\n%(asctime)s\n%(message)s", level=logging.INFO, force=True)      def error_prompt_flagged(state, prompt):      """Notify user that a prompt has been flagged."""      notify(state, "error", "Prompt flagged as inappropriate.")      logging.info(f"Prompt flagged as inappropriate: {prompt}")      def error_too_many_requests(state):      """Notify user that too many requests have been made."""      notify(          state,          "error",          "Too many requests. Please wait a few seconds before generating another text or image.",      )      logging.info(f"Session request limit reached: {state.n_requests}")      state.n_requests = 1      # Define functions  def generate_text(state):      """Generate Tweet text."""      state.tweet = ""      state.image = None        # Check the number of requests done by the user      if state.n_requests >= 5:          error_too_many_requests(state)          return        # Check if the user has put a topic      if state.topic == "":          notify(state, "error", "Please enter a topic")          return        # Create the prompt and add a style or not      if state.style == "":          state.prompt = (              f"Write a {state.mood}Tweet about {state.topic} in less than 120 characters "              f"and with the style of {state.style}:\n\n\n\n"          )      else:          state.prompt = f"Write a {state.mood}Tweet about {state.topic} in less than 120 characters:\n\n"        # openai configured and check if text is flagged      openai = oai.Openai()      flagged = openai.moderate(state.prompt)        if flagged:          error_prompt_flagged(state, f"Prompt: {state.prompt}\n")          return      else:          # Generate the tweet          state.n_requests += 1          state.tweet = openai.complete(state.prompt).strip().replace('"', "")            # Notify the user in console and in the GUI          logging.info(              f"Topic: {state.prompt}{state.mood}{state.style}\n" f"Tweet: {state.tweet}"          )          notify(state, "success", "Tweet created!")      def generate_image(state):      """Generate Tweet image."""      notify(state, "info", "Generating image...")        # Check the number of requests done by the user      if state.n_requests >= 5:          error_too_many_requests(state)          return        state.image = None        # Creates the prompt      prompt_wo_hashtags = re.sub("#[A-Za-z0-9_]+", "", state.prompt)      processing_prompt = (          "Create a detailed but brief description of an image that captures "          f"the essence of the following text:\n{prompt_wo_hashtags}\n\n"      )        # Openai configured and check if text is flagged      openai = oai.Openai()      flagged = openai.moderate(processing_prompt)        if flagged:          error_prompt_flagged(state, processing_prompt)          return      else:          state.n_requests += 1          # Generate the prompt that will create the image          processed_prompt = (              openai.complete(prompt=processing_prompt, temperature=0.5, max_tokens=40)              .strip()              .replace('"', "")              .split(".")[0]              + "."          )            # Generate the image          state.image = openai.image(processed_prompt)            # Notify the user in console and in the GUI          logging.info(f"Tweet: {state.prompt}\nImage prompt: {processed_prompt}")          notify(state, "success", f"Image created!")      def feeling_lucky(state):      """Generate a feeling-lucky tweet."""      with open("moods.txt") as f:          sample_moods = f.read().splitlines()      state.topic = "an interesting topic"      state.mood = random.choice(sample_moods)      state.style = ""      generate_text(state)      # Variables  tweet = ""  prompt = ""  n_requests = 0    topic = "AI"  mood = "inspirational"  style = "elonmusk"    image = None      # Called whever there is a problem  def on_exception(state, function_name: str, ex: Exception):      logging.error(f"Problem {ex} \nin {function_name}")      notify(state, "error", f"Problem {ex} \nin {function_name}")      def update_documents(state: taipy.gui.state, docs: list[dict]) -> None:      """      Updates a partial with a list of documents        Args:          state: The state of the GUI          docs: A list of documents      """      updated_part = ""      for doc in docs:          title = doc["title"]          summary = doc["summary"]          link = doc["link"]          updated_part += f"""
{title}

{summary}

          """      state.p.update_content(state, updated_part)      # Markdown for the entire page  ## <text|  ## |text>  ## "text" here is just a name given to my part/my section  ## it has no meaning in the code  page = """  <|container|  # **Generate**{: .color-primary} Tweets    This mini-app generates Tweets using OpenAI's GPT-3 based [Davinci model](https://beta.openai.com/docs/models/overview) for texts and [DALL·E](https://beta.openai.com/docs/guides/images) for images. You can find the code on [GitHub](https://github.com/Avaiga/demo-tweet-generation) and the original author on [Twitter](https://twitter.com/kinosal).

{sqdqs}

{qfqffqs}

    <|layout|columns=1 1 1|gap=30px|class_name=card|  <topic|  ## **Topic**{: .color-primary} (or hashtag)    <|{topic}|input|label=Topic (or hashtag)|>  |topic>    <mood|  ## **Mood**{: .color-primary}    <|{mood}|input|label=Mood (e.g. inspirational, funny, serious) (optional)|>  |mood>


# Create app for py2jsonl3.py py2jsonl3.py
import os
import json

EXCLUDED_FILES = ["CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "INSTALLATION.md", "README.md"]

def find_files(directory, extensions):
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(extensions) and file not in EXCLUDED_FILES:
                yield os.path.join(root, file)

def extract_content(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        return file.read()

def write_to_jsonl(output_file, data):
    with open(output_file, 'a', encoding='utf-8') as file:
        json_record = json.dumps(data)
        file.write(json_record + '\n')

def main(directory, output_file):
    for file_path in find_files(directory, ('.py', '.md')):
        file_content = extract_content(file_path)
        file_comment = f"# Create app for {os.path.basename(file_path)}"
        data = {"text": file_comment + '\n' + file_content}
        write_to_jsonl(output_file, data)

directory = 'taipy_repos3'  # Replace with the path to your directory
output_file = 'output.jsonl'  # Name of the output JSONL file

main(directory, output_file)


# Create app for demo-remove-background main.py
from taipy.gui import Gui, notify
from rembg import remove
from PIL import Image
from io import BytesIO

path_upload = ""
path_download = "fixed_img.png"
original_image = None
fixed_image = None
fixed = False

page = """<|toggle|theme|>

<page|layout|columns=300px 1fr|
<|sidebar|
### Removing **Background**{: .color-primary} from your image

Upload and download
<|{path_upload}|file_selector|on_action=fix_image|extensions=.png,.jpg|label=Upload original image|>

Download it here
<|{path_download}|file_download|label=Download fixed image|active={fixed}|>
|>

<|container|
# Image Background **Eliminator**{: .color-primary}

🐶 Give it a try by uploading an image to witness the seamless removal of the background. You can download images in full quality from the sidebar.
This code is open source and accessible on [GitHub](https://github.com/Avaiga/demo-remove-background).

<images|layout|columns=1 1|
<col1|card text-center|part|render={fixed}|
### Original Image 📷
<|{original_image}|image|>
|col1>

<col2|card text-center|part|render={fixed}|
### Fixed Image 🔧
<|{fixed_image}|image|>
|col2>
|images>

|>
|page>
"""

def convert_image(img):
    buf = BytesIO()
    img.save(buf, format="PNG")
    byte_im = buf.getvalue()
    return byte_im

def fix_image(state):
    notify(state, 'info', 'Uploading original image...')
    image = Image.open(state.path_upload)

    notify(state, 'info', 'Removing the background...')
    fixed_image = remove(image)
    fixed_image.save("fixed_img.png")

    notify(state, 'success', 'Background removed successfully!')
    state.original_image = convert_image(image)
    state.fixed_image = convert_image(fixed_image)
    state.fixed = True

if __name__ == "__main__":
    Gui(page=page).run(margin="0px", title='Background Remover')


# Create app for demo-tweet-generation oai.py
"""OpenAI API connector."""

# Import from standard library
import os
import logging

# Import from 3rd party libraries
import openai

import os

# Assign credentials from environment variable or streamlit secrets dict
openai.api_key = "Enter your token here"

# Suppress openai request/response logging
# Handle by manually changing the respective APIRequestor methods in the openai package
# Does not work hosted on Streamlit since all packages are re-installed by Poetry
# Alternatively (affects all messages from this logger):
logging.getLogger("openai").setLevel(logging.WARNING)

class Openai:
    """OpenAI Connector."""

    @staticmethod
    def moderate(prompt: str) -> bool:
        """Call OpenAI GPT Moderation with text prompt.
        Args:
            prompt: text prompt
        Return: boolean if flagged
        """
        try:
            response = openai.Moderation.create(prompt)
            return response["results"][0]["flagged"]

        except Exception as e:
            logging.error(f"OpenAI API error: {e}")

    @staticmethod
    def complete(prompt: str, temperature: float = 0.9, max_tokens: int = 50) -> str:
        """Call OpenAI GPT Completion with text prompt.
        Args:
            prompt: text prompt
        Return: predicted response text
        """
        kwargs = {
            "engine": "text-davinci-003",
            "prompt": prompt,
            "temperature": temperature,
            "max_tokens": max_tokens,
            "top_p": 1,  # default
            "frequency_penalty": 0,  # default,
            "presence_penalty": 0,  # default
        }
        try:
            response = openai.Completion.create(**kwargs)
            return response["choices"][0]["text"]

        except Exception as e:
            logging.error(f"OpenAI API error: {e}")

    @staticmethod
    def image(prompt: str) -> str:
        """Call OpenAI Image Create with text prompt.
        Args:
            prompt: text prompt
        Return: image url
        """
        try:
            response = openai.Image.create(
                prompt=prompt,
                n=1,
                size="512x512",
                response_format="url",
            )
            return response["data"][0]["url"]

        except Exception as e:
            logging.error(f"OpenAI API error: {e}")


# Create app for demo-tweet-generation main.py
# Import from standard library
import logging
import random
import re

# Import from 3rd party libraries
from taipy.gui import Gui, notify

# Import modules
import oai

# Configure logger
logging.basicConfig(format="\n%(asctime)s\n%(message)s", level=logging.INFO, force=True)

def error_prompt_flagged(state, prompt):
    """Notify user that a prompt has been flagged."""
    notify(state, "error", "Prompt flagged as inappropriate.")
    logging.info(f"Prompt flagged as inappropriate: {prompt}")

def error_too_many_requests(state):
    """Notify user that too many requests have been made."""
    notify(state, "error", "Too many requests. Please wait a few seconds before generating another text or image.")
    logging.info(f"Session request limit reached: {state.n_requests}")
    state.n_requests = 1

# Define functions
def generate_text(state):
    """Generate Tweet text."""
    state.tweet = ""
    state.image = None

    # Check the number of requests done by the user
    if state.n_requests >= 5:
        error_too_many_requests(state)
        return

    # Check if the user has put a topic
    if state.topic == "":
        notify(state, "error", "Please enter a topic")
        return

    # Create the prompt and add a style or not
    if state.style == "":
        state.prompt = (
            f"Write a {state.mood}Tweet about {state.topic} in less than 120 characters "
            f"and with the style of {state.style}:\n\n\n\n"
        )
    else:
        state.prompt = f"Write a {state.mood}Tweet about {state.topic} in less than 120 characters:\n\n"

    # openai configured and check if text is flagged
    openai = oai.Openai()
    flagged = openai.moderate(state.prompt)

    if flagged:
        error_prompt_flagged(state, f"Prompt: {state.prompt}\n")
        return
    else:
        # Generate the tweet
        state.n_requests += 1
        state.tweet = (
            openai.complete(state.prompt).strip().replace('"', "")
        )

        # Notify the user in console and in the GUI
        logging.info(
            f"Topic: {state.prompt}{state.mood}{state.style}\n"
            f"Tweet: {state.tweet}"
        )
        notify(state, "success", "Tweet created!")

def generate_image(state):
    """Generate Tweet image."""
    notify(state, "info", "Generating image...")

    # Check the number of requests done by the user
    if state.n_requests >= 5:
        error_too_many_requests(state)
        return

    state.image = None

    # Creates the prompt
    prompt_wo_hashtags = re.sub("#[A-Za-z0-9_]+", "", state.prompt)
    processing_prompt = (
        "Create a detailed but brief description of an image that captures "
        f"the essence of the following text:\n{prompt_wo_hashtags}\n\n"
    )

    # Openai configured and check if text is flagged
    openai = oai.Openai()
    flagged = openai.moderate(processing_prompt)

    if flagged:
        error_prompt_flagged(state, processing_prompt)
        return
    else:
        state.n_requests += 1
        # Generate the prompt that will create the image
        processed_prompt = (
            openai.complete(
                prompt=processing_prompt, temperature=0.5, max_tokens=40
            )
            .strip()
            .replace('"', "")
            .split(".")[0]
            + "."
        )

        # Generate the image
        state.image = openai.image(processed_prompt)

        # Notify the user in console and in the GUI
        logging.info(f"Tweet: {state.prompt}\nImage prompt: {processed_prompt}")
        notify(state, "success", f"Image created!")

# Variables
tweet = ""
prompt = ""
n_requests = 0

topic = "AI"
mood = "inspirational"
style = "elonmusk"

image = None

# Called whever there is a problem
def on_exception(state, function_name: str, ex: Exception):
    logging.error(f"Problem {ex} \nin {function_name}")
    notify(state, 'error', f"Problem {ex} \nin {function_name}")

# Markdown for the entire page
## <text|
## |text>
## "text" here is just a name given to my part/my section
## it has no meaning in the code
page = """
<|container|
# **Generate**{: .color-primary} Tweets

This mini-app generates Tweets using OpenAI's GPT-3 based [Davinci model](https://beta.openai.com/docs/models/overview) for texts and [DALL·E](https://beta.openai.com/docs/guides/images) for images. You can find the code on [GitHub](https://github.com/Avaiga/demo-tweet-generation) and the original author on [Twitter](https://twitter.com/kinosal).

<|layout|columns=1 1 1|gap=30px|class_name=card|
<topic|
## **Topic**{: .color-primary} (or hashtag)

<|{topic}|input|label=Topic (or hashtag)|>
|topic>

<mood|
## **Mood**{: .color-primary}

<|{mood}|input|label=Mood (e.g. inspirational, funny, serious) (optional)|>
|mood>


# Create app for demo-realtime-pollution sender.py
# echo-client.py

import math
import time
import socket
import pickle
import numpy as np

HOST = "127.0.0.1"
PORT = 65432

init_lat = 49.247
init_long = 1.377

factory_lat = 49.246
factory_long = 1.369

diff_lat = abs(init_lat - factory_lat) * 15
diff_long = abs(init_long - factory_long) * 15

lats_unique = np.arange(init_lat - diff_lat, init_lat + diff_lat, 0.001)
longs_unique = np.arange(init_long - diff_long, init_long + diff_long, 0.001)

countdown = 20

def pollution(lat: float, long: float):
    """
    Return pollution level in percentage
    Pollution should be centered around the factory
    Pollution should decrease with distance to factory
    Pollution should have an added random component

    Args:
        - lat: latitude
        - long: longitude

    Returns:
        - pollution level
    """
    global countdown
    return 80 * (0.5 + 0.5 * math.sin(countdown / 20)) * math.exp(
        -(0.8 * (lat - factory_lat) ** 2 + 0.2 * (long - factory_long) ** 2) / 0.00005
    ) + np.random.randint(0, 50)

lats = []
longs = []
pollutions = []

for lat in lats_unique:
    for long in longs_unique:
        lats.append(lat)
        longs.append(long)
        pollutions.append(pollution(lat, long))

def update():
    """
    Update the pollution levels
    """
    for i, _ in enumerate(lats):
        pollutions[i] = pollution(lats[i], longs[i])
    return pollutions

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    while True:
        data = pickle.dumps(pollutions)
        s.sendall(data)
        print(f"Sent Data: {pollutions[:5]}")
        pollutions = update()
        countdown += 5
        time.sleep(5)


# Create app for demo-realtime-pollution receiver.py
import socket
import pickle
import math
from threading import Thread
from taipy.gui import Gui, State, invoke_callback, get_state_id
import numpy as np
import pandas as pd

init_lat = 49.247
init_long = 1.377

factory_lat = 49.246
factory_long = 1.369

diff_lat = abs(init_lat - factory_lat) * 15
diff_long = abs(init_long - factory_long) * 15

lats_unique = np.arange(init_lat - diff_lat, init_lat + diff_lat, 0.001)
longs_unique = np.arange(init_long - diff_long, init_long + diff_long, 0.001)

countdown = 20
periods = 0
line_data = pd.DataFrame({"Time": [], "Max AQI": []})

drone_data = pd.DataFrame(
    {
        "Drone ID": [43, 234, 32, 23, 5, 323, 12, 238, 21, 84],
        "Battery Level": [
            "86%",
            "56%",
            "45%",
            "12%",
            "85%",
            "67%",
            "34%",
            "78%",
            "90%",
            "100%",
        ],
        "AQI": [40, 34, 24, 22, 33, 45, 23, 34, 23, 34],
        "Status": [
            "Moving",
            "Measuring",
            "Measuring",
            "Stopped",
            "Measuring",
            "Moving",
            "Moving",
            "Measuring",
            "Measuring",
            "Measuring",
        ],
    }
)

HOST = "127.0.0.1"
PORT = 65432

layout_map = {
    "mapbox": {
        "style": "open-street-map",
        "center": {"lat": init_lat, "lon": init_long},
        "zoom": 13,
    },
    "dragmode": "false",
    "margin": {"l": 0, "r": 0, "b": 0, "t": 0},
}

layout_line = {
    "title": "Max Measured AQI over Time",
    "yaxis": {"range": [0, 150]},
}

options = {
    "opacity": 0.8,
    "colorscale": "Bluered",
    "zmin": 0,
    "zmax": 140,
    "colorbar": {"title": "AQI"},
    "hoverinfo": "none",
}

config = {"scrollZoom": False, "displayModeBar": False}

def pollution(lat: float, long: float):
    """
    Return pollution level in percentage
    Pollution should be centered around the factory
    Pollution should decrease with distance to factory
    Pollution should have an added random component

    Args:
        - lat: latitude
        - long: longitude

    Returns:
        - pollution level
    """
    global countdown
    return 80 * (0.5 + 0.5 * math.sin(countdown / 20)) * math.exp(
        -(0.8 * (lat - factory_lat) ** 2 + 0.2 * (long - factory_long) ** 2) / 0.00005
    ) + np.random.randint(0, 50)

lats = []
longs = []
pollutions = []
times = []
max_pollutions = []

for lat in lats_unique:
    for long in longs_unique:
        lats.append(lat)
        longs.append(long)
        pollutions.append(pollution(lat, long))

data_province_displayed = pd.DataFrame(
    {
        "Latitude": lats,
        "Longitude": longs,
        "Pollution": pollutions,
    }
)

max_pollution = data_province_displayed["Pollution"].max()

# Socket handler
def client_handler(gui: Gui, state_id_list: list):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen()
    conn, _ = s.accept()
    while True:
        if data := conn.recv(1024 * 1024):
            pollutions = pickle.loads(data)
            print(f"Data received: {pollutions[:5]}")
            if hasattr(gui, "_server") and state_id_list:
                invoke_callback(
                    gui,
                    state_id_list[0],
                    update_pollutions,
                    [pollutions],
                )
        else:
            print("Connection closed")
            break

# Gui declaration
state_id_list = []

Gui.add_shared_variable("pollutions")

def on_init(state: State):
    state_id = get_state_id(state)
    if (state_id := get_state_id(state)) is not None and state_id != "":
        state_id_list.append(state_id)
    update_pollutions(state, pollutions)

def update_pollutions(state: State, val):
    state.pollutions = val
    state.data_province_displayed = pd.DataFrame(
        {
            "Latitude": lats,
            "Longitude": longs,
            "Pollution": state.pollutions,
        }
    )
    # Add an hour to the time
    state.periods = state.periods + 1
    state.max_pollutions = state.max_pollutions + [max(state.pollutions)]
    state.times = pd.date_range(
        "2020-11-04", periods=len(state.max_pollutions), freq="H"
    )
    state.line_data = pd.DataFrame(
        {
            "Time": state.times,
            "Max AQI": state.max_pollutions,
        }
    )

page = """
<|{data_province_displayed}|chart|type=densitymapbox|plot_config={config}|options={options}|lat=Latitude|lon=Longitude|layout={layout_map}|z=Pollution|mode=markers|class_name=map|height=40vh|>
<|layout|columns=1 2 2|
<|part|class_name=card|
**Max Measured AQI:**

<|{int(data_province_displayed["Pollution"].max())}|indicator|value={int(data_province_displayed["Pollution"].max())}|min=140|max=0|>

**Average Measured AQI:**

<|{int(data_province_displayed["Pollution"].mean())}|indicator|value={int(data_province_displayed["Pollution"].mean())}|min=140|max=0|>
|>

<|part|class_name=card|
<|{drone_data}|table|show_all=True|>
|>

<|part|class_name=card|
<|{line_data[-30:]}|chart|type=lines|x=Time|y=Max AQI|layout={layout_line}|height=40vh|>
|>
|>
"""
gui = Gui(page=page)

t = Thread(
    target=client_handler,
    args=(
        gui,
        state_id_list,
    ),
)
t.start()
gui.run(run_browser=False)


# Create app for demo-pyspark-penguin-app config.py
### app/config.py
import datetime as dt
import os
import subprocess
import sys
from pathlib import Path

import pandas as pd
import taipy as tp
from taipy import Config

SCRIPT_DIR = Path(__file__).parent
SPARK_APP_PATH = SCRIPT_DIR / "penguin_spark_app.py"

input_csv_path = str(SCRIPT_DIR / "penguins.csv")

# -------------------- Data Nodes --------------------

input_csv_path_cfg = Config.configure_data_node(id="input_csv_path", default_data=input_csv_path)
# Path to save the csv output of the spark app
output_csv_path_cfg = Config.configure_data_node(id="output_csv_path")

processed_penguin_df_cfg = Config.configure_parquet_data_node(
    id="processed_penguin_df", validity_period=dt.timedelta(days=1)
)

species_cfg = Config.configure_data_node(id="species")  # "Adelie", "Chinstrap", "Gentoo"
island_cfg = Config.configure_data_node(id="island")  # "Biscoe", "Dream", "Torgersen"
sex_cfg = Config.configure_data_node(id="sex")  # "male", "female"

output_cfg = Config.configure_json_data_node(
    id="output",
)

# -------------------- Tasks --------------------

def spark_process(input_csv_path: str, output_csv_path: str) -> pd.DataFrame:
    proc = subprocess.Popen(
        [
            str(Path(sys.executable).with_name("spark-submit")),
            str(SPARK_APP_PATH),
            "--input-csv-path",
            input_csv_path,
            "--output-csv-path",
            output_csv_path,
        ],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )

    try:
        outs, errs = proc.communicate(timeout=15)
    except subprocess.TimeoutExpired:
        proc.kill()
        outs, errs = proc.communicate()

    if proc.returncode != os.EX_OK:
        raise Exception("Spark training failed")

    df = pd.read_csv(output_csv_path)

    return df

def filter(penguin_df: pd.DataFrame, species: str, island: str, sex: str) -> dict:
    df = penguin_df[(penguin_df.species == species) & (penguin_df.island == island) & (penguin_df.sex == sex)]
    output = df[["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]].to_dict(orient="records")
    return output[0] if output else dict()

spark_process_task_cfg = Config.configure_task(
    id="spark_process",
    function=spark_process,
    skippable=True,
    input=[input_csv_path_cfg, output_csv_path_cfg],
    output=processed_penguin_df_cfg,
)

filter_task_cfg = Config.configure_task(
    id="filter",
    function=filter,
    skippable=True,
    input=[processed_penguin_df_cfg, species_cfg, island_cfg, sex_cfg],
    output=output_cfg,
)

scenario_cfg = Config.configure_scenario(
    id="scenario", task_configs=[spark_process_task_cfg, filter_task_cfg]
)


# Create app for demo-pyspark-penguin-app main.py
### app/main.py
from pathlib import Path
from typing import Optional

import taipy as tp
from config import scenario_cfg
from taipy.gui import Gui, notify

valid_features: dict[str, list[str]] = {
    "species": ["Adelie", "Chinstrap", "Gentoo"],
    "island": ["Torgersen", "Biscoe", "Dream"],
    "sex": ["Male", "Female"],
}

selected_species = valid_features["species"][0]
selected_island = valid_features["island"][0]
selected_sex = valid_features["sex"][0]

selected_scenario: Optional[tp.Scenario] = None

data_dir = Path(__file__).with_name("data")
data_dir.mkdir(exist_ok=True)

def scenario_on_creation(state, id, payload):
    _ = payload["config"]
    date = payload["date"]
    label = payload["label"]
    properties = payload["properties"]

    # Create scenario with selected configuration
    scenario = tp.create_scenario(scenario_cfg, creation_date=date, name=label)
    scenario.properties.update(properties)

    # Write the selected GUI values to the scenario
    scenario.species.write(state.selected_species)
    scenario.island.write(state.selected_island)
    scenario.sex.write(state.selected_sex.lower())
    output_csv_file = data_dir / f"{scenario.id}.csv"
    scenario.output_csv_path.write(str(output_csv_file))

    notify(state, "S", f"Created {scenario.id}")

    return scenario

def scenario_on_submission_change(state, submittable, details):
    """When the selected_scenario's submission status changes, reassign selected_scenario to force a GUI refresh."""

    state.selected_scenario = submittable

selected_data_node = None

main_md = """
<|layout|columns=1 4|gap=1.5rem|

<lhs|part|
# Spark with **Taipy**{: .color-primary}

## Scenario

<|{selected_scenario}|scenario_selector|on_creation=scenario_on_creation|>

----------

## Scenario info

<|{selected_scenario}|scenario|on_submission_change=scenario_on_submission_change|>

|lhs>

<rhs|part|render={selected_scenario}|

## Selections

<selections|layout|columns=1 1 1 2|gap=1.5rem|

<|{selected_species}|selector|lov={valid_features["species"]}|dropdown|label=Species|>

<|{selected_island}|selector|lov={valid_features["island"]}|dropdown|label=Island|>

<|{selected_sex}|selector|lov={valid_features["sex"]}|dropdown|label=Sex|>

|selections>

----------

## Output

**<|{str(selected_scenario.output.read()) if selected_scenario and selected_scenario.output.is_ready_for_reading else 'Submit the scenario using the left panel.'}|text|raw|class_name=color-primary|>**

## Data node inspector

<|{selected_data_node}|data_node_selector|display_cycles=False|>

**Data node value:**

<|{str(selected_data_node.read()) if selected_data_node and selected_data_node.is_ready_for_reading else None}|>

<br/>

----------

## DAG

<|Scenario DAG|expandable|
<|{selected_scenario}|scenario_dag|>
|>

|rhs>

|>
"""

def on_change(state, var_name: str, var_value):
    if var_name == "selected_species":
        state.selected_scenario.species.write(var_value)
    elif var_name == "selected_island":
        state.selected_scenario.island.write(var_value)
    elif var_name == "selected_sex":
        state.selected_scenario.sex.write(var_value.lower())

if __name__ == "__main__":
    tp.Core().run()

    gui = Gui(main_md)
    gui.run(title="Spark with Taipy")


# Create app for demo-pyspark-penguin-app penguin_spark_app.py
### app/penguin_spark_app.py
import argparse
import os
import sys

parser = argparse.ArgumentParser()
parser.add_argument("--input-csv-path", required=True, help="Path to the input penguin CSV file.")
parser.add_argument("--output-csv-path", required=True, help="Path to save the output CSV file.")
args = parser.parse_args()

import pyspark.pandas as ps
from pyspark.sql import SparkSession

def read_penguin_df(csv_path: str):
    penguin_df = ps.read_csv(csv_path)
    return penguin_df

def clean(df: ps.DataFrame) -> ps.DataFrame:
    return df[df.sex.isin(["male", "female"])].dropna()

def process(df: ps.DataFrame) -> ps.DataFrame:
    """The mean of measured penguin values, grouped by island and sex."""

    mean_df = df.groupby(by=["species", "island", "sex"]).agg("mean").drop(columns="year").reset_index()
    return mean_df

if __name__ == "__main__":
    spark = SparkSession.builder.appName("Mean Penguin").getOrCreate()

    penguin_df = read_penguin_df(args.input_csv_path)
    cleaned_penguin_df = clean(penguin_df)
    processed_penguin_df = process(cleaned_penguin_df)
    processed_penguin_df.to_pandas().to_csv(args.output_csv_path, index=False)

    sys.exit(os.EX_OK)


# Create app for demo-dask-customer-analysis config.py
from taipy import Config

from algos.algo import (
    preprocess_and_score,
    featurization_and_segmentation,
    segment_analysis,
    high_value_cust_summary_statistics,
)

# -------------------- Data Nodes --------------------

path_to_data_cfg = Config.configure_data_node(id="path_to_data", default_data="data/customers_data.csv")

scored_df_cfg = Config.configure_data_node(id="scored_df")

payment_threshold_cfg = Config.configure_data_node(id="payment_threshold", default_data=1000)

score_threshold_cfg = Config.configure_data_node(id="score_threshold", default_data=1.5)

segmented_customer_df_cfg = Config.configure_data_node(id="segmented_customer_df")

metric_cfg = Config.configure_data_node(id="metric", default_data="mean")

segment_result_cfg = Config.configure_data_node(id="segment_result")

summary_statistic_type_cfg = Config.configure_data_node(id="summary_statistic_type", default_data="median")

high_value_summary_df_cfg = Config.configure_data_node(id="high_value_summary_df")

# -------------------- Tasks --------------------

preprocess_and_score_task_cfg = Config.configure_task(
    id="preprocess_and_score",
    function=preprocess_and_score,
    skippable=True,
    input=[path_to_data_cfg],
    output=[scored_df_cfg],
)

featurization_and_segmentation_task_cfg = Config.configure_task(
    id="featurization_and_segmentation",
    function=featurization_and_segmentation,
    skippable=True,
    input=[scored_df_cfg, payment_threshold_cfg, score_threshold_cfg],
    output=[segmented_customer_df_cfg],
)

segment_analysis_task_cfg = Config.configure_task(
    id="segment_analysis",
    function=segment_analysis,
    skippable=True,
    input=[segmented_customer_df_cfg, metric_cfg],
    output=[segment_result_cfg],
)

high_value_cust_summary_statistics_task_cfg = Config.configure_task(
    id="high_value_cust_summary_statistics",
    function=high_value_cust_summary_statistics,
    skippable=True,
    input=[segment_result_cfg, segmented_customer_df_cfg, summary_statistic_type_cfg],
    output=[high_value_summary_df_cfg],
)

scenario_cfg = Config.configure_scenario(
    id="scenario_1",
    task_configs=[
        preprocess_and_score_task_cfg,
        featurization_and_segmentation_task_cfg,
        segment_analysis_task_cfg,
        high_value_cust_summary_statistics_task_cfg,
    ],
)


# Create app for demo-dask-customer-analysis algo.py
import time

import dask.dataframe as dd
import pandas as pd

def preprocess_and_score(path_to_original_data: str):
    print("__________________________________________________________")
    print("1. TASK 1: DATA PREPROCESSING AND CUSTOMER SCORING ...")
    start_time = time.perf_counter()  # Start the timer

    # Step 1: Read data using Dask
    df = dd.read_csv(path_to_original_data)

    # Step 2: Simplify the customer scoring formula
    df["CUSTOMER_SCORE"] = (
        0.5 * df["TotalPurchaseAmount"] / 1000 + 0.3 * df["NumberOfPurchases"] / 10 + 0.2 * df["AverageReviewScore"]
    )

    # Save all customers to a new CSV file
    scored_df = df[["CUSTOMER_SCORE", "TotalPurchaseAmount", "NumberOfPurchases", "TotalPurchaseTime"]]

    pd_df = scored_df.compute()

    end_time = time.perf_counter()  # Stop the timer
    execution_time = (end_time - start_time) * 1000  # Calculate the time in milliseconds
    print(f"Time of Execution: {execution_time:.4f} ms")

    return pd_df

def featurization_and_segmentation(scored_df, payment_threshold, score_threshold):
    print("__________________________________________________________")
    print("2. TASK 2: FEATURE ENGINEERING AND SEGMENTATION ...")

    # payment_threshold, score_threshold = float(payment_threshold), float(score_threshold)
    start_time = time.perf_counter()  # Start the timer

    df = scored_df

    # Feature: Indicator if customer's total purchase is above the payment threshold
    df["HighSpender"] = (df["TotalPurchaseAmount"] > payment_threshold).astype(int)

    # Feature: Average time between purchases
    df["AverageTimeBetweenPurchases"] = df["TotalPurchaseTime"] / df["NumberOfPurchases"]

    # Additional computationally intensive features
    df["Interaction1"] = df["TotalPurchaseAmount"] * df["NumberOfPurchases"]
    df["Interaction2"] = df["TotalPurchaseTime"] * df["CUSTOMER_SCORE"]
    df["PolynomialFeature"] = df["TotalPurchaseAmount"] ** 2

    # Segment customers based on the score_threshold
    df["ValueSegment"] = ["High Value" if score > score_threshold else "Low Value" for score in df["CUSTOMER_SCORE"]]

    end_time = time.perf_counter()  # Stop the timer
    execution_time = (end_time - start_time) * 1000  # Calculate the time in milliseconds
    print(f"Time of Execution: {execution_time:.4f} ms")

    return df

def segment_analysis(df: pd.DataFrame, metric):
    print("__________________________________________________________")
    print("3. TASK 3: SEGMENT ANALYSIS ...")
    start_time = time.perf_counter()  # Start the timer

    # Detailed analysis for each segment: mean/median of various metrics
    segment_analysis = (
        df.groupby("ValueSegment")
        .agg(
            {
                "CUSTOMER_SCORE": metric,
                "TotalPurchaseAmount": metric,
                "NumberOfPurchases": metric,
                "TotalPurchaseTime": metric,
                "HighSpender": "sum",  # Total number of high spenders in each segment
                "AverageTimeBetweenPurchases": metric,
            }
        )
        .reset_index()
    )

    end_time = time.perf_counter()  # Stop the timer
    execution_time = (end_time - start_time) * 1000  # Calculate the time in milliseconds
    print(f"Time of Execution: {execution_time:.4f} ms")

    return segment_analysis

def high_value_cust_summary_statistics(df: pd.DataFrame, segment_analysis: pd.DataFrame, summary_statistic_type: str):
    print("__________________________________________________________")
    print("4. TASK 4: ADDITIONAL ANALYSIS BASED ON SEGMENT ANALYSIS ...")
    start_time = time.perf_counter()  # Start the timer

    # Filter out the High Value customers
    high_value_customers = df[df["ValueSegment"] == "High Value"]

    # Use summary_statistic_type to calculate different types of summary statistics
    if summary_statistic_type == "mean":
        average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].mean()
    elif summary_statistic_type == "median":
        average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].median()
    elif summary_statistic_type == "max":
        average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].max()
    elif summary_statistic_type == "min":
        average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].min()

    median_score_high_value = high_value_customers["CUSTOMER_SCORE"].median()

    # Fetch the summary statistic for 'TotalPurchaseAmount' for High Value customers from segment_analysis
    segment_statistic_high_value = segment_analysis.loc[
        segment_analysis["ValueSegment"] == "High Value", "TotalPurchaseAmount"
    ].values[0]

    # Create a DataFrame to hold the results
    result_df = pd.DataFrame(
        {
            "SummaryStatisticType": [summary_statistic_type],
            "AveragePurchaseHighValue": [average_purchase_high_value],
            "MedianScoreHighValue": [median_score_high_value],
            "SegmentAnalysisHighValue": [segment_statistic_high_value],
        }
    )

    end_time = time.perf_counter()  # Stop the timer
    execution_time = (end_time - start_time) * 1000  # Calculate the time in milliseconds
    print(f"Time of Execution: {execution_time:.4f} ms")

    return result_df

if __name__ == "__main__":
    t1 = preprocess_and_score("data/customers_data.csv")

    t2 = featurization_and_segmentation(t1, 1500, 1.5)

    t3 = segment_analysis(t2, "mean")

    t4 = high_value_cust_summary_statistics(t2, t3, "mean")

    print(t4)


# Create app for demo-taipy-gui-starter-1 main.py
from taipy.gui import Gui
from math import cos, exp

page = """
#This is *Taipy* GUI

A value: <|{decay}|>.

A slider: <br/>
<|{decay}|slider|>

My chart:
<|{data}|chart|>
"""

def compute_data(decay):
    return [cos(i/16) * exp(-i*decay/6000) for i in range(720)]

def on_change(state, var_name, var_value):
    if var_name == 'decay':
        state.data = compute_data(var_value)

decay = 10
data = compute_data(decay)

Gui(page=page).run(title='Taipy Demo GUI 1',
    		       dark_mode=False)


# Create app for demo-churn-classification main.py
import pandas as pd
import taipy as tp
from taipy.gui import Gui, Icon, navigate
from config.config import scenario_cfg
from taipy.config import Config
from pages.main_dialog import *

import warnings
with warnings.catch_warnings():
    warnings.simplefilter(action='ignore', category=FutureWarning)

# Load configuration
Config.load('config/config.toml')
scenario_cfg = Config.scenarios['churn_classification']

# Execute the scenario
tp.Core().run()

def create_first_scenario(scenario_cfg):
    """Create and submit the first scenario."""
    scenario = tp.create_scenario(scenario_cfg)
    tp.submit(scenario)
    return scenario

scenario = create_first_scenario(scenario_cfg)

# Read datasets
train_dataset = scenario.train_dataset.read()
test_dataset = scenario.test_dataset.read()
roc_dataset = scenario.roc_data_ml.read()

# Process test dataset columns
test_dataset.columns = [str(column).upper() for column in test_dataset.columns]

# Prepare data for visualization
select_x = test_dataset.drop('EXITED',axis=1).columns.tolist()
x_selected = select_x[0]
select_y = select_x
y_selected = select_y[1]

# Read results and create charts
values = scenario.results_ml.read()
forecast_series = values['Forecast']
scatter_dataset_pred = creation_scatter_dataset_pred(test_dataset, forecast_series)
histo_full_pred = creation_histo_full_pred(test_dataset, forecast_series)
histo_full = creation_histo_full(test_dataset)
scatter_dataset = creation_scatter_dataset(test_dataset)
features_table = scenario.feature_importance_ml.read()
accuracy_graph, f1_score_graph, score_auc_graph = compare_models_baseline(scenario, ['ml', 'baseline'])

def create_charts(model_type):
    """Create pie charts and metrics for the given model type."""
    metrics = c_update_metrics(scenario, model_type)
    (number_of_predictions, accuracy, f1_score, score_auc,
     number_of_good_predictions, number_of_false_predictions,
     fp_, tp_, fn_, tn_) = metrics

    pie_plotly = pd.DataFrame({
        "values": [number_of_good_predictions, number_of_false_predictions],
        "labels": ["Correct predictions", "False predictions"]
    })

    distrib_class = pd.DataFrame({
        "values": [len(values[values["Historical"]==0]), len(values[values["Historical"]==1])],
        "labels": ["Stayed", "Exited"]
    })

    score_table = pd.DataFrame({
        "Score": ["Predicted stayed", "Predicted exited"],
        "Stayed": [tn_, fp_],
        "Exited": [fn_, tp_]
    })

    pie_confusion_matrix = pd.DataFrame({
        "values": [tp_, tn_, fp_, fn_],
        "labels": ["True Positive", "True Negative", "False Positive", "False Negative"]
    })

    return (number_of_predictions, number_of_false_predictions, number_of_good_predictions,
            accuracy, f1_score, score_auc, pie_plotly, distrib_class, score_table, pie_confusion_matrix)

# Initialize charts
chart_metrics = create_charts('ml')
(number_of_predictions, number_of_false_predictions, number_of_good_predictions,
 accuracy, f1_score, score_auc, pie_plotly, distrib_class, score_table, pie_confusion_matrix) = chart_metrics

def on_change(state, var_name, var_value):
    """Handle variable changes in the GUI."""
    if var_name in ['x_selected', 'y_selected']:
        update_histogram_and_scatter(state)
    elif var_name == 'mm_algorithm_selected':
        update_variables(state, var_value.lower())
    elif var_name in ['mm_algorithm_selected', 'db_table_selected']:
        handle_temp_csv_path(state)

# GUI initialization
menu_lov = [
    ("Data Visualization", Icon('images/histogram_menu.svg', 'Data Visualization')),
    ("Model Manager", Icon('images/model.svg', 'Model Manager')),
    ("Compare Models", Icon('images/compare.svg', 'Compare Models')),
    ('Databases', Icon('images/Datanode.svg', 'Databases'))
]

root_md = """
<|toggle|theme|>
<|menu|label=Menu|lov={menu_lov}|on_action=menu_fct|>
"""

page = "Data Visualization"

def menu_fct(state, var_name, var_value):
    """Function that is called when there is a change in the menu control."""
    state.page = var_value['args'][0]
    navigate(state, state.page.replace(" ", "-"))

def update_variables(state, model_type):
    """Update the different variables and dataframes used in the application."""
    global scenario
    state.values = scenario.data_nodes[f'results_{model_type}'].read()
    state.forecast_series = state.values['Forecast']

    metrics = c_update_metrics(scenario, model_type)
    (state.number_of_predictions, state.accuracy, state.f1_score, state.score_auc,
     number_of_good_predictions, number_of_false_predictions, fp_, tp_, fn_, tn_) = metrics

    update_charts(state, model_type, number_of_good_predictions, number_of_false_predictions, fp_, tp_, fn_, tn_)

def update_charts(state, model_type, number_of_good_predictions, number_of_false_predictions, fp_, tp_, fn_, tn_):
    """This function updates all the charts of the GUI.

    Args:
        state: object containing all the variables used in the GUI
        model_type (str): the name of the model_type shown
        number_of_good_predictions (int): number of good predictions
        number_of_false_predictions (int): number of false predictions
        fp_ (float): false positive rate
        tp_ (float): true positive rate
        fn_ (float): false negative rate
        tn_ (float): true negative rate
    """
    state.roc_dataset = scenario.data_nodes[f'roc_data_{model_type}'].read()
    state.features_table = scenario.data_nodes[f'feature_importance_{model_type}'].read()

    state.score_table = pd.DataFrame({"Score":["Predicted stayed", "Predicted exited"],
                                      "Stayed": [tn_, fp_],
                                      "Exited" : [fn_, tp_]})

    state.pie_confusion_matrix = pd.DataFrame({"values": [tp_, tn_, fp_, fn_],
                                               "labels" : ["True Positive", "True Negative", "False Positive", "False Negative"]})

    state.scatter_dataset_pred = creation_scatter_dataset_pred(test_dataset, state.forecast_series)
    state.histo_full_pred = creation_histo_full_pred(test_dataset, state.forecast_series)

    # pie charts
    state.pie_plotly = pd.DataFrame({"values": [number_of_good_predictions, number_of_false_predictions],
                                     "labels": ["Correct predictions", "False predictions"]})

    state.distrib_class = pd.DataFrame({"values": [len(state.values[state.values["Historical"]==0]),
                                                   len(state.values[state.values["Historical"]==1])],
                                        "labels" : ["Stayed", "Exited"]})

def on_init(state):
    update_histogram_and_scatter(state)

# Define pages
pages = {
    "/": root_md + dialog_md,
    "Data-Visualization": dv_data_visualization_md,
    "Model-Manager": mm_model_manager_md,
    "Compare-Models": cm_compare_models_md,
    "Databases": db_databases_md,
}

# Run the GUI
if __name__ == '__main__':
    gui = Gui(pages=pages)
    gui.run(title="Churn classification", dark_mode=False, port=8494)


# Create app for demo-churn-classification config.py
from algos.algos import *
from taipy import Config, Scope
##############################################################################################################################
# Creation of the datanodes
##############################################################################################################################
# How to connect to the database
path_to_csv = 'data/churn.csv'

# path for csv and file_path for pickle
initial_dataset_cfg = Config.configure_data_node(id="initial_dataset",
                                             path=path_to_csv,
                                             storage_type="csv",
                                             has_header=True)

date_cfg = Config.configure_data_node(id="date", default_data="None")

preprocessed_dataset_cfg = Config.configure_data_node(id="preprocessed_dataset")

# the final datanode that contains the processed data
train_dataset_cfg = Config.configure_data_node(id="train_dataset")

# the final datanode that contains the processed data
trained_model_ml_cfg = Config.configure_data_node(id="trained_model_ml")
trained_model_baseline_cfg= Config.configure_data_node(id="trained_model_baseline")

# the final datanode that contains the processed data
test_dataset_cfg = Config.configure_data_node(id="test_dataset")

forecast_dataset_ml_cfg = Config.configure_data_node(id="forecast_dataset_ml")
forecast_dataset_baseline_cfg = Config.configure_data_node(id="forecast_dataset_baseline")

roc_data_ml_cfg = Config.configure_data_node(id="roc_data_ml")
roc_data_baseline_cfg = Config.configure_data_node(id="roc_data_baseline")

score_auc_ml_cfg = Config.configure_data_node(id="score_auc_ml")
score_auc_baseline_cfg = Config.configure_data_node(id="score_auc_baseline")

metrics_ml_cfg = Config.configure_data_node(id="metrics_ml")
metrics_baseline_cfg = Config.configure_data_node(id="metrics_baseline")

feature_importance_ml_cfg = Config.configure_data_node(id="feature_importance_ml")
feature_importance_baseline_cfg = Config.configure_data_node(id="feature_importance_baseline")

results_ml_cfg = Config.configure_data_node(id="results_ml")
results_baseline_cfg = Config.configure_data_node(id="results_baseline")

##############################################################################################################################
# Creation of the tasks
##############################################################################################################################

# the task will make the link between the input data node
# and the output data node while executing the function

# initial_dataset --> preprocess dataset --> preprocessed_dataset
task_preprocess_dataset_cfg = Config.configure_task(id="preprocess_dataset",
                                                    input=[initial_dataset_cfg,date_cfg],
                                                    function=preprocess_dataset,
                                                    output=preprocessed_dataset_cfg)

# preprocessed_dataset --> create train data --> train_dataset, test_dataset
task_create_train_test_cfg = Config.configure_task(id="create_train_and_test_data",
                                                   input=preprocessed_dataset_cfg,
                                                   function=create_train_test_data,
                                                   output=[train_dataset_cfg, test_dataset_cfg])

# train_dataset --> create train_model data --> trained_model
task_train_model_baseline_cfg = Config.configure_task(id="train_model_baseline",
                                                      input=train_dataset_cfg,
                                                      function=train_model_baseline,
                                                      output=[trained_model_baseline_cfg,feature_importance_baseline_cfg])

# train_dataset --> create train_model data --> trained_model
task_train_model_ml_cfg = Config.configure_task(id="train_model_ml",
                                                input=train_dataset_cfg,
                                                function=train_model_ml,
                                                output=[trained_model_ml_cfg,feature_importance_ml_cfg])

# test_dataset --> forecast --> forecast_dataset
task_forecast_baseline_cfg = Config.configure_task(id="predict_the_test_data_baseline",
                                                   input=[test_dataset_cfg, trained_model_baseline_cfg],
                                                   function=forecast,
                                                   output=forecast_dataset_baseline_cfg)
# test_dataset --> forecast --> forecast_dataset
task_forecast_ml_cfg = Config.configure_task(id="predict_the_test_data_ml",
                                             input=[test_dataset_cfg, trained_model_ml_cfg],
                                             function=forecast,
                                             output=forecast_dataset_ml_cfg)

task_roc_ml_cfg = Config.configure_task(id="task_roc_ml",
                                        input=[forecast_dataset_ml_cfg, test_dataset_cfg],
                                        function=roc_from_scratch,
                                        output=[roc_data_ml_cfg,score_auc_ml_cfg])

task_roc_baseline_cfg = Config.configure_task(id="task_roc_baseline",
                                              input=[forecast_dataset_baseline_cfg, test_dataset_cfg],
                                              function=roc_from_scratch,
                                              output=[roc_data_baseline_cfg,score_auc_baseline_cfg])

task_create_metrics_baseline_cfg = Config.configure_task(id="task_create_metrics_baseline",
                                                         input=[forecast_dataset_baseline_cfg,test_dataset_cfg],
                                                         function=create_metrics,
                                                         output=metrics_baseline_cfg)

task_create_metrics_ml_cfg = Config.configure_task(id="task_create_metrics",
                                                   input=[forecast_dataset_ml_cfg,test_dataset_cfg],
                                                   function=create_metrics,
                                                   output=metrics_ml_cfg)

task_create_results_baseline_cfg = Config.configure_task(id="task_create_results_baseline",
                                                         input=[forecast_dataset_baseline_cfg,test_dataset_cfg],
                                                         function=create_results,
                                                         output=results_baseline_cfg)

task_create_results_ml_cfg = Config.configure_task(id="task_create_results_ml",
                                                   input=[forecast_dataset_ml_cfg,test_dataset_cfg],
                                                   function=create_results,
                                                   output=results_ml_cfg)

##############################################################################################################################
# Creation of the scenario
##############################################################################################################################

scenario_cfg = Config.configure_scenario(id="churn_classification",
                                         task_configs=[task_create_metrics_baseline_cfg,
                                                       task_create_metrics_ml_cfg,
                                                       task_create_results_baseline_cfg,
                                                       task_create_results_ml_cfg,
                                                       task_forecast_baseline_cfg,
                                                       task_forecast_ml_cfg,
                                                       task_roc_ml_cfg,
                                                       task_roc_baseline_cfg,
                                                       task_train_model_baseline_cfg,
                                                       task_train_model_ml_cfg,
                                                       task_preprocess_dataset_cfg,
                                                       task_create_train_test_cfg])

Config.export('config/config.toml')


# Create app for demo-churn-classification algos.py
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

import datetime as dt

import pandas as pd
import numpy as np

##############################################################################################################################
# Function used in the tasks
##############################################################################################################################

def preprocess_dataset(initial_dataset: pd.DataFrame, date: dt.datetime="None"):
    """This function preprocess the dataset to be used in the model

    Args:
        initial_dataset (pd.DataFrame): the raw format when we first read the data

    Returns:
        pd.DataFrame: the preprocessed dataset for classification
    """
    print("\n     Preprocessing the dataset...")

    #We filter the dataframe on the date
    if date != "None":
        initial_dataset['Date'] = pd.to_datetime(initial_dataset['Date'])
        processed_dataset = initial_dataset[initial_dataset['Date'] <= date]
        print(len(processed_dataset))
    else:
        processed_dataset = initial_dataset

    processed_dataset = processed_dataset[['CreditScore','Geography','Gender','Age','Tenure','Balance','NumOfProducts','HasCrCard','IsActiveMember','EstimatedSalary','Exited']]

    processed_dataset = pd.get_dummies(processed_dataset)

    if 'Gender_Female' in processed_dataset.columns:
        processed_dataset.drop('Gender_Female',axis=1,inplace=True)

    processed_dataset = processed_dataset.apply(pd.to_numeric)

    columns_to_select = ['CreditScore', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'HasCrCard',
                         'IsActiveMember', 'EstimatedSalary',  'Geography_France', 'Geography_Germany',
                         'Geography_Spain',  'Gender_Male','Exited']

    processed_dataset = processed_dataset[[col for col in columns_to_select if col in processed_dataset.columns]]

    print("     Preprocessing done!\n")
    return processed_dataset

def create_train_test_data(preprocessed_dataset: pd.DataFrame):
    """This function will create the train data by segmenting the dataset

    Args:
        preprocessed_dataset (pd.DataFrame): the preprocessed dataset

    Returns:
        pd.DataFrame: the training dataset
    """
    print("\n     Creating the training and testing dataset...")

    X_train, X_test, y_train, y_test = train_test_split(preprocessed_dataset.iloc[:,:-1],preprocessed_dataset.iloc[:,-1],test_size=0.2,random_state=42)

    train_data = pd.concat([X_train,y_train],axis=1)
    test_data = pd.concat([X_test,y_test],axis=1)
    print("     Creating done!")
    return train_data, test_data

def train_model_baseline(train_dataset: pd.DataFrame):
    """Function to train the Logistic Regression model

    Args:
        train_dataset (pd.DataFrame): the training dataset

    Returns:
        model (LogisticRegression): the fitted model
    """
    print("     Training the model...\n")
    X,y = train_dataset.iloc[:,:-1],train_dataset.iloc[:,-1]
    model_fitted = LogisticRegression().fit(X,y)
    print("\n    ",model_fitted," is trained!")

    importance_dict = {'Features' : X.columns, 'Importance':model_fitted.coef_[0]}
    importance = pd.DataFrame(importance_dict).sort_values(by='Importance',ascending=True)
    return model_fitted, importance

def train_model_ml(train_dataset: pd.DataFrame):
    """Function to train the Logistic Regression model

    Args:
        train_dataset (pd.DataFrame): the training dataset

    Returns:
        model (RandomForest): the fitted model
    """
    print("     Training the model...\n")
    X,y = train_dataset.iloc[:,:-1],train_dataset.iloc[:,-1]
    model_fitted = RandomForestClassifier().fit(X,y)
    print("\n    ",model_fitted," is trained!")

    importance_dict = {'Features' : X.columns, 'Importance':model_fitted.feature_importances_}
    importance = pd.DataFrame(importance_dict).sort_values(by='Importance',ascending=True)
    return model_fitted, importance

def forecast(test_dataset: pd.DataFrame, trained_model: RandomForestClassifier):
    """Function to forecast the test dataset

    Args:
        test_dataset (pd.DataFrame): the test dataset
        trained_model (LogisticRegression): the fitted model

    Returns:
        forecast (pd.DataFrame): the forecasted dataset
    """
    print("     Forecasting the test dataset...")
    X,y = test_dataset.iloc[:,:-1],test_dataset.iloc[:,-1]
    #predictions = trained_model.predict(X)
    predictions = trained_model.predict_proba(X)[:, 1]
    print("     Forecasting done!")
    return predictions

def roc_from_scratch(probabilities, test_dataset, partitions=100):
    print("     Calculation of the ROC curve...")
    y_test = test_dataset.iloc[:,-1]

    roc = np.array([])
    for i in range(partitions + 1):
        threshold_vector = np.greater_equal(probabilities, i / partitions).astype(int)
        tpr, fpr = true_false_positive(threshold_vector, y_test)
        roc = np.append(roc, [fpr, tpr])

    roc_np = roc.reshape(-1, 2)
    roc_data = pd.DataFrame({"False positive rate": roc_np[:, 0], "True positive rate": roc_np[:, 1]})
    print("     Calculation done")
    print("     Scoring...")

    score_auc = roc_auc_score(y_test, probabilities)
    print("     Scoring done\n")

    return roc_data, score_auc

def true_false_positive(threshold_vector:np.array, y_test:np.array):
    """Function to calculate the true positive rate and the false positive rate

    Args:
        threshold_vector (np.array): the test dataset
        y_test (np.array): the fitted model

    Returns:
        tpr (pd.DataFrame): the forecasted dataset
        fpr (pd.DataFrame): the forecasted dataset
    """

    true_positive = np.equal(threshold_vector, 1) & np.equal(y_test, 1)
    true_negative = np.equal(threshold_vector, 0) & np.equal(y_test, 0)
    false_positive = np.equal(threshold_vector, 1) & np.equal(y_test, 0)
    false_negative = np.equal(threshold_vector, 0) & np.equal(y_test, 1)

    tpr = true_positive.sum() / (true_positive.sum() + false_negative.sum())
    fpr = false_positive.sum() / (false_positive.sum() + true_negative.sum())

    return tpr, fpr

def create_metrics(predictions:np.array, test_dataset:np.array):
    print("     Creating the metrics...")
    threshold = 0.5
    threshold_vector = np.greater_equal(predictions, threshold).astype(int)

    y_test = test_dataset.iloc[:,-1]

    true_positive = (np.equal(threshold_vector, 1) & np.equal(y_test, 1)).sum()
    true_negative = (np.equal(threshold_vector, 0) & np.equal(y_test, 0)).sum()
    false_positive = (np.equal(threshold_vector, 1) & np.equal(y_test, 0)).sum()
    false_negative = (np.equal(threshold_vector, 0) & np.equal(y_test, 1)).sum()

    f1_score = np.around(2*true_positive/(2*true_positive+false_positive+false_negative), decimals=2)
    accuracy = np.around((true_positive+true_negative)/(true_positive+true_negative+false_positive+false_negative), decimals=2)
    dict_ftpn = {"tp": true_positive, "tn": true_negative, "fp": false_positive, "fn": false_negative}

    number_of_good_predictions = true_positive + true_negative
    number_of_false_predictions = false_positive + false_negative

    metrics = {"f1_score": f1_score,
               "accuracy": accuracy,
               "dict_ftpn": dict_ftpn,
               'number_of_predictions': len(predictions),
               'number_of_good_predictions':number_of_good_predictions,
               'number_of_false_predictions':number_of_false_predictions}

    return metrics

def create_results(forecast_values,test_dataset):
    forecast_series_proba = pd.Series(np.around(forecast_values,decimals=2), index=test_dataset.index, name='Probability')
    forecast_series = pd.Series((forecast_values>0.5).astype(int), index=test_dataset.index, name='Forecast')
    true_series = pd.Series(test_dataset.iloc[:,-1], name="Historical",index=test_dataset.index)
    index_series = pd.Series(range(len(true_series)), index=test_dataset.index, name="Id")

    results = pd.concat([index_series, forecast_series_proba, forecast_series, true_series], axis=1)
    return results


# Create app for demo-churn-classification main_dialog.py
from pages.compare_models_md import *
from pages.data_visualization_md import *
from pages.databases_md import *
from pages.model_manager_md import *

dr_show_roc = False

dialog_md = """
<|dialog|open={dr_show_roc}|title=ROC Curve|on_action={lambda s: s.assign("dr_show_roc", False)}|labels=Close|width=1000px|
<|{roc_dataset}|chart|x=False positive rate|y[1]=True positive rate|label[1]=True positive rate|height=500px|width=900px|type=scatter|>
|>
"""


# Create app for demo-churn-classification databases_md.py
import pathlib

# This path is used to create a temporary CSV file download the table
tempdir = pathlib.Path(".tmp")
tempdir.mkdir(exist_ok=True)
PATH_TO_TABLE = str(tempdir / "table.csv")

# Selector to select the table to show
db_table_selector = ['Training Dataset', 'Test Dataset', 'Forecast Dataset', 'Confusion Matrix']
db_table_selected = db_table_selector[0]

def handle_temp_csv_path(state):
    """This function checks if the temporary csv file exists. If it does, it is deleted. Then, the temporary csv file
    is created for the right table

    Args:
        state: object containing all the variables used in the GUI
    """
    if state.db_table_selected == 'Test Dataset':
        state.test_dataset.to_csv(PATH_TO_TABLE, sep=';')
    if state.db_table_selected == 'Confusion Matrix':
        state.score_table.to_csv(PATH_TO_TABLE, sep=';')
    if state.db_table_selected == "Training Dataset":
        state.train_dataset.to_csv(PATH_TO_TABLE, sep=';')
    if state.db_table_selected == "Forecast Dataset":
        state.values.to_csv(PATH_TO_TABLE, sep=';')

# Aggregation of the strings to create the complete page
db_databases_md = """
# Data**bases**{: .color-primary}

<|layout|columns=2 2 1|
<|{mm_algorithm_selected}|selector|lov={mm_algorithm_selector}|dropdown|label=Algorithm|active=False|>

<|{db_table_selected}|selector|lov={db_table_selector}|dropdown|label=Table|>

<|{PATH_TO_TABLE}|file_download|name=table.csv|label=Download table|>
|>

<Confusion|part|render={db_table_selected=='Confusion Matrix'}|
<|{score_table}|table|width=fit-content|show_all|class_name=ml-auto mr-auto|>
|Confusion>

<Training|part|render={db_table_selected=='Training Dataset'}|
<|{train_dataset}|table|>
|Training>

<Forecast|part|render={db_table_selected=='Forecast Dataset'}|
<|{values}|table|width=fit-content|style={lambda s,i,r: 'red_color' if r['Historical']!=r['Forecast'] else 'green_color'}|class_name=ml-auto mr-auto|>
|Forecast>

<test_dataset|part|render={db_table_selected=='Test Dataset'}|
<|{test_dataset}|table|>
|test_dataset>
"""


# Create app for demo-churn-classification data_visualization_md.py
import pandas as pd
import numpy as np

dv_graph_selector = ['Histogram','Scatter']
dv_graph_selected = dv_graph_selector[0]

# Histograms dialog
properties_histo_full = {}
properties_scatter_dataset = {}

def creation_scatter_dataset(test_dataset:pd.DataFrame):
    """This function creates the dataset for the scatter plot.  For every column (except Exited), scatter_dataset will have a positive and negative version.
    The positive column will have NaN when the Exited is zero and the negative column will have NaN when the Exited is one.

    Args:
        test_dataset (pd.DataFrame): the test dataset

    Returns:
        pd.DataFrame: the datafram
    """
    scatter_dataset = test_dataset.copy()

    for column in scatter_dataset.columns:
        if column != 'EXITED' :
            column_neg = str(column)+'_neg'
            column_pos = str(column)+'_pos'

            scatter_dataset[column_neg] = scatter_dataset[column]
            scatter_dataset[column_pos] = scatter_dataset[column]

            scatter_dataset.loc[(scatter_dataset['EXITED'] == 1),column_neg] = np.NaN
            scatter_dataset.loc[(scatter_dataset['EXITED'] == 0),column_pos] = np.NaN

    return scatter_dataset

def creation_histo_full(test_dataset:pd.DataFrame):
    """This function creates the dataset for the histogram plot.  For every column (except Exited), histo_full will have a positive and negative version.
    The positive column will have NaN when the Exited is zero and the negative column will have NaN when the Exited is one.

    Args:
        test_dataset (pd.DataFrame): the test dataset

    Returns:
        pd.DataFrame: the Dataframe used to display the Histogram
    """
    histo_full = test_dataset.copy()

    for column in histo_full.columns:
        column_neg = str(column)+'_neg'
        histo_full[column_neg] = histo_full[column]
        histo_full.loc[(histo_full['EXITED'] == 1),column_neg] = np.NaN
        histo_full.loc[(histo_full['EXITED'] == 0),column] = np.NaN

    return histo_full

def update_histogram_and_scatter(state):
    global x_selected, y_selected
    x_selected = state.x_selected
    y_selected = state.y_selected
    state.properties_scatter_dataset =  {"x":x_selected,
                                         "y[1]":y_selected+'_pos',
                                         "y[2]":y_selected+'_neg'}
    state.scatter_dataset = state.scatter_dataset
    state.scatter_dataset_pred = state.scatter_dataset_pred

    state.properties_histo_full =  {"x[1]":x_selected,
                                    "x[2]":x_selected+'_neg'}
    state.histo_full = state.histo_full
    state.histo_full_pred = state.histo_full_pred

dv_data_visualization_md = """
# Data **Visualization**{: .color-primary}
<|{dv_graph_selected}|toggle|lov={dv_graph_selector}|>

--------------------------------------------------------------------

<|part|render={dv_graph_selected == 'Histogram'}|
### Histogram
<|{x_selected}|selector|lov={select_x}|dropdown=True|label=Select x|>

<|{histo_full}|chart|type=histogram|properties={properties_histo_full}|rebuild|y=EXITED|label=EXITED|color[1]=red|color[2]=green|name[1]=Exited|name[2]=Stayed|height=600px|>
|>

<|part|render={dv_graph_selected == 'Scatter'}|
### Scatter
<|layout|columns= 1 2|
<|{x_selected}|selector|lov={select_x}|dropdown|label=Select x|>

<|{y_selected}|selector|lov={select_y}|dropdown|label=Select y|>
|>

<|{scatter_dataset}|chart|properties={properties_scatter_dataset}|rebuild|color[1]=red|color[2]=green|name[1]=Exited|name[2]=Stayed|mode=markers|type=scatter|height=600px|>
|>

"""


# Create app for demo-churn-classification compare_models_md.py
import numpy as np

from sklearn.metrics import f1_score

import pandas as pd
import numpy as np

cm_height_histo = "100%"
cm_dict_barmode = {"barmode": "stack","margin":{"t":30}}
cm_options_md = "height={cm_height_histo}|width={cm_height_histo}|layout={cm_dict_barmode}"

cm_compare_models_md = """
# Model comparison

----

<|layout|columns=   1 1 1|columns[mobile]=1|
<|{accuracy_graph}|chart|type=bar|x=Model Type|y[1]=Accuracy Model|y[2]=Accuracy Baseline|title=Accuracy|""" + cm_options_md + """|>

<|{f1_score_graph}|chart|type=bar|x=Model Type|y[1]=F1 Score Model|y[2]=F1 Score Baseline|title=F1 Score|""" + cm_options_md + """|>

<|{score_auc_graph}|chart|type=bar|x=Model Type|y[1]=AUC Score Model|y[2]=AUC Score Baseline|title=AUC Score|""" + cm_options_md + """|>

|>
"""

def compare_charts(accuracies, f1_scores, scores_auc, names):
    """This funcion creates the pandas Dataframes (charts) used in the model comparison page

    Args:
        accuracies (list): list of accuracies
        f1_scores (list): list of f1 scores
        scores_auc (list): list of auc scores
        names (list): list of scenario names

    Returns:
        pd.DataFrame: the resulting three pd.DataFrame
    """
    accuracy_graph = pd.DataFrame(create_metric_dict(accuracies, "Accuracy", names))
    f1_score_graph = pd.DataFrame(create_metric_dict(f1_scores, "F1 Score", names))
    score_auc_graph = pd.DataFrame(create_metric_dict(scores_auc, "AUC Score", names))

    return accuracy_graph, f1_score_graph, score_auc_graph

def compare_models_baseline(scenario,model_types):
    """This function creates the objects for the model comparison

    Args:
        scenario (scenario): the selected scenario
        model_types (str): the name of the selected model type

    Returns:
        pd.DataFrame: the resulting three pd.DataFrame
    """
    accuracies = []
    f1_scores = []
    scores_auc = []
    names = []
    for model_type in model_types:
        (_,accuracy,f1_score,score_auc,_,_,_,_,_,_) = c_update_metrics(scenario, model_type)

        accuracies.append(accuracy)
        f1_scores.append(f1_score)
        scores_auc.append(score_auc)
        names.append('Model' if model_type != "baseline" else "Baseline")

    accuracy_graph,f1_score_graph, score_auc_graph = compare_charts(accuracies, f1_scores, scores_auc, names)
    return accuracy_graph, f1_score_graph, score_auc_graph

def create_metric_dict(metric, metric_name, names):
    """This function creates a dictionary of metrics for multiple models that will be used in a Dataframe shown on the Gui

    Args:
        metric (list): the value of the metric
        metric_name (str): the name of the metric
        names (list): list of scenario names

    Returns:
        dict: dicitonary used for a pandas Dataframe
    """
    metric_dict = {}
    initial_list = [0]*len(names)

    metric_dict["Model Type"] = names
    for i in range(len(names)):
        current_list = initial_list.copy()

        current_list[i] = metric[i]
        metric_dict[metric_name +" "+ names[i].capitalize()] = current_list

    return metric_dict

def c_update_metrics(scenario, model_type):
    """This function updates the metrics of a scenario using a model

    Args:
        scenario (scenario): the selected scenario
        model_type (str): the name of the selected model_type

    Returns:
        obj: a number of values, lists that represent the metrics
    """
    metrics = scenario.data_nodes[f'metrics_{model_type}'].read()

    number_of_predictions = metrics['number_of_predictions']
    number_of_good_predictions = metrics['number_of_good_predictions']
    number_of_false_predictions = metrics['number_of_false_predictions']

    accuracy = np.around(metrics['accuracy'], decimals=2)
    f1_score = np.around(metrics['f1_score'], decimals=2)
    score_auc = np.around(scenario.data_nodes[f'score_auc_{model_type}'].read(), decimals=2)

    dict_ftpn = metrics['dict_ftpn']

    fp_ = dict_ftpn['fp']
    tp_ = dict_ftpn['tp']
    fn_ = dict_ftpn['fn']
    tn_ = dict_ftpn['tn']
    return number_of_predictions, accuracy, f1_score, score_auc, number_of_good_predictions, number_of_false_predictions, fp_, tp_, fn_, tn_


# Create app for demo-churn-classification model_manager_md.py
import pandas as pd
import numpy as np

mm_graph_selector_scenario = ['Metrics', 'Features', 'Histogram','Scatter']
mm_graph_selected_scenario = mm_graph_selector_scenario[0]

mm_algorithm_selector = ['Baseline', 'ML']
mm_algorithm_selected = 'ML'

mm_pie_color_dict_2 = {"piecolorway":["#00D08A","#FE913C"]}
mm_pie_color_dict_4 = {"piecolorway":["#00D08A","#81F1A0","#F3C178","#FE913C"]}

mm_margin_features = {'margin': {'l': 150}}

def creation_scatter_dataset_pred(test_dataset:pd.DataFrame, forecast_series:pd.Series):
    """This function creates the dataset for the scatter plot for the predictions.  For every column (except EXITED) will have a positive and negative version.
    EXITED is here a binary indicating if the prediction is good or bad.
    The positive column will have NaN when the Exited is zero and the negative column will have NaN when the Exited is one.

    Args:
        test_dataset (pd.DataFrame): the test dataset
        forecast_series (pd.DataFrame): the forecast dataset

    Returns:
        pd.DataFrame: the Dataframe used to display the Histogram
    """

    scatter_dataset = test_dataset.copy()
    scatter_dataset['EXITED'] =  (scatter_dataset['EXITED']!=forecast_series.to_numpy()).astype(int)

    for column in scatter_dataset.columns:
        if column != 'EXITED' :
            column_neg = str(column)+'_neg'
            column_pos = str(column)+'_pos'

            scatter_dataset[column_neg] = scatter_dataset[column]
            scatter_dataset[column_pos] = scatter_dataset[column]

            scatter_dataset.loc[(scatter_dataset['EXITED'] == 1),column_neg] = np.NaN
            scatter_dataset.loc[(scatter_dataset['EXITED'] == 0),column_pos] = np.NaN

    return scatter_dataset

def creation_histo_full_pred(test_dataset:pd.DataFrame,forecast_series:pd.Series):
    """This function creates the dataset for the histogram plot for the predictions.  For every column (except PREDICTION) will have a positive and negative version.
    PREDICTION is a binary indicating if the prediction is good or bad.
    The positive column will have NaN when the PREDICTION is zero and the negative column will have NaN when the PREDICTION is one.

    Args:
        test_dataset (pd.DataFrame): the test dataset
        forecast_series (pd.DataFrame): the forecast dataset

    Returns:
        pd.DataFrame: the Dataframe used to display the Histogram
    """
    histo_full = test_dataset.copy()
    histo_full['EXITED'] =  (histo_full['EXITED']!=forecast_series.to_numpy()).astype(int)
    histo_full.columns = histo_full.columns.str.replace('EXITED', 'PREDICTION')

    for column in histo_full.columns:
        column_neg = str(column)+'_neg'
        histo_full[column_neg] = histo_full[column]
        histo_full.loc[(histo_full['PREDICTION'] == 1),column_neg] = np.NaN
        histo_full.loc[(histo_full['PREDICTION'] == 0),column] = np.NaN

    return histo_full

mm_model_manager_md = """
# **Model**{: .color-primary} Manager

<|layout|columns=3 2 2 2|
<|{mm_graph_selected_scenario}|toggle|lov={mm_graph_selector_scenario}|>

<|{mm_algorithm_selected}|selector|lov={mm_algorithm_selector}|dropdown|label=Algorithm|>

<|show roc|button|on_action={lambda s: s.assign("dr_show_roc", True)}|>

<br/> **Number of predictions:** <|{number_of_predictions}|>
|>

-----------------------------------------------------------------

<Metrics|part|render={mm_graph_selected_scenario == 'Metrics'}|
### Metrics

<|layout|columns=1 1 1|columns[mobile]=1|
<accuracy|
<|{accuracy}|indicator|value={accuracy}|min=0|max=1|>

**Model accuracy**
{: .text-center}

<|{pie_plotly}|chart|title=Accuracy of predictions model|values=values|labels=labels|type=pie|layout={mm_pie_color_dict_2}|>
|accuracy>

<score_auc|
<|{score_auc}|indicator|value={score_auc}|min=0|max=1|>

**Model AUC**
{: .text-center}

<|{pie_confusion_matrix}|chart|title=Confusion Matrix|values=values|labels=labels|type=pie|layout={mm_pie_color_dict_4}|>
|score_auc>

<f1_score|
<|{f1_score}|indicator|value={f1_score}|min=0|max=1|>

**Model F1-score**
{: .text-center}

<|{distrib_class}|chart|title=Distribution between Exited and Stayed|values=values|labels=labels|type=pie|layout={mm_pie_color_dict_2}|>
|f1_score>
|>
|Metrics>

<Features|part|render={mm_graph_selected_scenario == 'Features'}|
### Features
<|{features_table}|chart|type=bar|y=Features|x=Importance|orientation=h|layout={mm_margin_features}|>
|Features>

<Histogram|part|render={mm_graph_selected_scenario == 'Histogram'}|
### Histogram
<|{x_selected}|selector|lov={select_x}|dropdown|label=Select x|>

<|{histo_full_pred}|chart|type=histogram|properties={properties_histo_full}|rebuild|y=PREDICTION|label=PREDICTION|color[1]=red|color[2]=green|name[1]=Good Predictions|name[2]=Bad Predictions|height=600px|>
|Histogram>

<Scatter|part|render={mm_graph_selected_scenario == 'Scatter'}|
### Scatter
<|layout|columns=1 2|
<|{x_selected}|selector|lov={select_x}|dropdown|label=Select x|>

<|{y_selected}|selector|lov={select_y}|dropdown=True|label=Select y|>
|>

<|{scatter_dataset_pred}|chart|properties={properties_scatter_dataset}|rebuild|color[1]=red|color[2]=green|name[1]=Bad prediction|name[2]=Good prediction|mode=markers|type=scatter|height=600px|>
|Scatter>
"""


# Create app for demo-stock-visualization main.py
from taipy.gui import Gui, notify
from datetime import date
import yfinance as yf
from prophet import Prophet
import pandas as pd

# Parameters for retrieving the stock data
start_date = "2015-01-01"
end_date = date.today().strftime("%Y-%m-%d")
selected_stock = 'AAPL'
n_years = 1

def get_stock_data(ticker, start, end):
    ticker_data = yf.download(ticker, start, end)  # downloading the stock data from START to TODAY
    ticker_data.reset_index(inplace=True)  # put date in the first column
    ticker_data['Date'] = pd.to_datetime(ticker_data['Date']).dt.tz_localize(None)
    return ticker_data

def get_data_from_range(state):
    print("GENERATING HIST DATA")
    start_date = state.start_date if type(state.start_date)==str else state.start_date.strftime("%Y-%m-%d")
    end_date = state.end_date if type(state.end_date)==str else state.end_date.strftime("%Y-%m-%d")

    state.data = get_stock_data(state.selected_stock, start_date, end_date)
    if len(state.data) == 0:
        notify(state, "error", f"Not able to download data {state.selected_stock} from {start_date} to {end_date}")
        return
    notify(state, 's', 'Historical data has been updated!')
    notify(state, 'w', 'Deleting previous predictions...')
    state.forecast = pd.DataFrame(columns=['Date', 'Lower', 'Upper'])

def generate_forecast_data(data, n_years):
    # FORECASTING
    df_train = data[['Date', 'Close']]
    df_train = df_train.rename(columns={"Date": "ds", "Close": "y"})  # This is the format that Prophet accepts

    m = Prophet()
    m.fit(df_train)
    future = m.make_future_dataframe(periods=n_years * 365)
    fc = m.predict(future)[['ds', 'yhat_lower', 'yhat_upper']].rename(columns={"ds": "Date", "yhat_lower": "Lower", "yhat_upper": "Upper"})
    print("Process Completed!")
    return fc

def forecast_display(state):
    notify(state, 'i', 'Predicting...')
    state.forecast = generate_forecast_data(state.data, state.n_years)
    notify(state, 's', 'Prediction done! Forecast data has been updated!')

#### Getting the data, make initial forcast and build a front end web-app with Taipy GUI
data = get_stock_data(selected_stock, start_date, end_date)
forecast = generate_forecast_data(data, n_years)

show_dialog = False

partial_md = "<|{forecast}|table|>"
dialog_md = "<|{show_dialog}|dialog|partial={partial}|title=Forecast Data|on_action={lambda state: state.assign('show_dialog', False)}|>"

page = dialog_md + """<|toggle|theme|>
<|container|
# Stock Price **Analysis**{: .color-primary} Dashboard

<|layout|columns=1 2 1|gap=40px|class_name=card p2|

<dates|
#### Selected **Period**{: .color-primary}

From:
<|{start_date}|date|on_change=get_data_from_range|>

To:
<|{end_date}|date|on_change=get_data_from_range|>
|dates>

<ticker|
#### Selected **Ticker**{: .color-primary}

Please enter a valid ticker:
<|{selected_stock}|input|label=Stock|on_action=get_data_from_range|>

or choose a popular one

<|{selected_stock}|toggle|lov=MSFT;GOOG;AAPL; AMZN; META; COIN; AMC; PYPL|on_change=get_data_from_range|>
|ticker>

<years|
#### Prediction **years**{: .color-primary}
Select number of prediction years: <|{n_years}|>
<|{n_years}|slider|min=1|max=5|>

<|PREDICT|button|on_action=forecast_display|class_name={'plain' if len(forecast)==0 else ''}|>
|years>

|>

<|Historical Data|expandable|expanded=False|
<|layout|columns=1 1|
<|
### Historical **closing**{: .color-primary} price
<|{data}|chart|mode=line|x=Date|y[1]=Open|y[2]=Close|>
|>

<|
### Historical **daily**{: .color-primary} trading volume
<|{data}|chart|mode=line|x=Date|y=Volume|>
|>
|>

### **Whole**{: .color-primary} historical data: <|{selected_stock}|text|raw|>
<|{data}|table|>

|>

### **Forecast**{: .color-primary} Data
<|{forecast}|chart|mode=line|x=Date|y[1]=Lower|y[2]=Upper|>

<|More info|button|on_action={lambda s: s.assign("show_dialog", True)}|>
{: .text-center}
|>

"""

# Run Taipy GUI
gui = Gui(page)
partial = gui.add_partial(partial_md)
gui.run(dark_mode=False, title="Stock Visualization")


# Create app for demo-movie-genre main.py
import taipy as tp
import pandas as pd
from taipy import Config, Scope, Gui

# Create a Taipy App that will output the 7 best movies for a genre

# Taipy Core - backend definition

# Filter function for Task
def filtering_genre(initial_dataset: pd.DataFrame, selected_genre):
    filtered_dataset = initial_dataset[initial_dataset['genres'].str.contains(selected_genre)]
    filtered_data = filtered_dataset.nlargest(7, 'Popularity %')
    return filtered_data

# Input Data Nodes configuration
initial_dataset_cfg = Config.configure_data_node(id="initial_dataset",
                                                 storage_type="csv",
                                                 path="data.csv",
                                                 scope=Scope.GLOBAL)

selected_genre_cfg = Config.configure_data_node(id="selected_genre_node",
                                                 default_data="ACTION",
                                                 scope=Scope.GLOBAL)

# Output Data Node configuration
filtered_data_cfg = Config.configure_data_node(id="filtered_data",
                                                 scope=Scope.GLOBAL)

# Task configuration
filter_task_cfg = Config.configure_task(id="filter_genre",
                                            function=filtering_genre,
                                            input=[initial_dataset_cfg, selected_genre_cfg],
                                            output=filtered_data_cfg,
                                            skippable=True)

# Pipeline configuration
pipeline_cfg = Config.configure_pipeline(id="pipeline",
                                         task_configs=[filter_task_cfg])
# Scenario configuration
scenario_cfg = Config.configure_scenario(id="scenario", pipeline_configs=[pipeline_cfg])

# Run of the Taipy Core service
tp.Core().run()

# Creation of my scenario
scenario = tp.create_scenario(scenario_cfg)

# Taipy GUI- front end definition

# Callback definition
def modify_df(state):
    scenario.selected_genre_node.write(state.selected_genre)
    tp.submit(scenario)
    state.df = scenario.filtered_data.read()

# Get list of genres
list_genres = ['Action', 'Adventure', 'Animation', 'Children', 'Comedy', 'Fantasy', 'IMAX', 'Romance',
               'Sci-FI', 'Western', 'Crime', 'Mystery', 'Drama', 'Horror', 'Thriller', 'Film-Noir',
               'War', 'Musical', 'Documentary']

# Initialization of variables
df = pd.DataFrame(columns=['Title', 'Popularity %'])
selected_genre = None

# movie_genre_app
movie_genre_app = """
# Film recommendation

## Choose your favorite genre
<|{selected_genre}|selector|lov={list_genres}|on_change=modify_df|dropdown|>

## Here are the top 7 picks
<|{df}|chart|x=Title|y=Popularity %|type=bar|title=Film Popularity|>
"""
# run the app
Gui(page=movie_genre_app).run()


# Create app for demo-job-monitoring __init__.py


# Create app for demo-job-monitoring runtime.py
from taipy import run

class App:
    """A singleton class that provides the Taipy runtime objects."""

    def __new__(cls):
        if not hasattr(cls, "instance"):
            cls.instance = super(App, cls).__new__(cls)
        return cls.instance

    @property
    def gui(self):
        return self.__gui

    @property
    def core(self):
        return self.__core

    @gui.setter
    def gui(self, gui):
        self.__gui = gui

    @core.setter
    def core(self, core):
        self.__core = core

    def start(self, **kwargs):
        # Starts the app by calling `taipy.run` on the core and gui objects:
        run(self.__gui, self.__core, **kwargs)


# Create app for demo-job-monitoring main.py
from runtime import App
from pages import root, monitoring
import taipy
from taipy.config.config import Config
from taipy.gui import Gui
import os

# Variables for bindings
all_jobs = [['','','','']]
show_dialog_run_pipeline = False
selected_pipeline = None
show_details_pane = False
selected_job = None

if __name__ == "__main__":
    # Initialize Taipy objects
    Config.configure_job_executions(mode="standalone", nb_of_workers=4)
    Config.load("app.config.toml")
    App().core = taipy.Core()
    App().gui = Gui(pages={"/": root.page, "monitoring": monitoring.page})

    # Start the app
    App().start(
        title="Job Monitoring Demo",
        port=os.environ.get("PORT", "8080"),
        dark_mode=False,
        css_file="app",
    )