Multi Page Streamlit Application - Code-A2Z/jarvis GitHub Wiki

📑 Multi Page Streamlit Application!

Jarvis - An AI-Powered application with streamlit interface is built using multi-page functionality to handle a wide range of tasks.

The different pages in streamlit interface are categorized on the basis of their functionality like,

  • There are 5 categories right now!

    • Account
    • Automations
    • Models
    • Programs
    • Admin Control
  • These categories consist some range of pages based on their functionality like,

    • API based programs
    • Image generator programs
    • Recommendation models
    • Health care models
    • Messenger automations
    • Coding automations, etc.

image


camelToReadable.py — Helper Module

Converts the name of the modules from camel case letters to readable format.

def camelToReadable(camelCaseName):
  readableName = ''.join([' ' + char if char.isupper() else char for char in camelCaseName]).strip()
  return readableName.title()

getFolder.py — Helper Module

Scans a parent directory and lists folders as pages.

import os
import streamlit as st
from src.helpers.camelToReadable import camelToReadable

def getFolders(MODULE_FOLDER_PATH):
  try:
    files = [f for f in os.listdir(MODULE_FOLDER_PATH) if os.path.isdir(os.path.join(MODULE_FOLDER_PATH, f)) and not f.startswith('__')]
  except FileNotFoundError:
    st.error("The specified directory does not exist.")
    return {}

  folders = {}
  for folder in files:
    readable_name = camelToReadable(folder)
    folders[readable_name] = folder
  return folders

getModules.py — Helper Module

Reads all .py files in a folder and maps them to user-readable module names.

import os
import streamlit as st
from src.helpers.camelToReadable import camelToReadable

def getModules(COMMON_MODULE_PATH):
  try:
    files = [f for f in os.listdir(COMMON_MODULE_PATH) if f.endswith('.py') and not f.startswith('__')]
  except FileNotFoundError:
    st.error("The specified directory does not exist.")
    return {}

  modules = {}
  for file in files:
    module_name = file[:-3]
    readable_name = camelToReadable(module_name)
    modules[readable_name] = module_name
  return modules

structPages.py — Build Pages Dynamically

Creates a Page object for each module under a category folder.

import streamlit as st
import importlib
import random
import re

from src.helpers.getModules import getModules
from src.helpers.getFolders import getFolders

icons = [
  .
  .
  ":material/smart_toy:",
  ":material/email:",
  ":material/web:",
  ":material/camera_alt:",
  ":material/assignment:",
  .
  .
]

def formatTitle(name):
  return re.sub(r'(?<!^)(?=[A-Z])', ' ', name)

def createPageModule(BASE_DIR, MAIN_DIR, MODULES):
  st.title(formatTitle(MAIN_DIR))
  choice = st.selectbox(f'Select a {BASE_DIR[:-1].lower()} to execute', [None] + list(MODULES.keys()), key=MAIN_DIR)
  st.divider()

  if choice in MODULES:
    module_name = MODULES[choice]
    try:
      module = importlib.import_module(f"src.apps.pages.{BASE_DIR}.{MAIN_DIR}.{module_name}")
      func = getattr(module, module_name)
      func()
    except ModuleNotFoundError as e:
      st.toast(f"Module '{module_name}.py' could not be found.", icon="🚫")
      st.error(f"An error occurred: {e}", icon="🚫")
    except AttributeError as e:
      st.toast(f"Function '{module_name}' could not be found in '{module_name}.py'.", icon="🚫")
      st.error(f"An error occurred: {e}", icon="🚫")
    except Exception as e:
      st.error(f"An error occurred: {e}", icon="🚫")
  else:
    st.info("Star this project on [GitHub](https://github.com/Code-A2Z/jarvis), if you like it!", icon='⭐')

def structPages(path):
  folders = getFolders(path)
  pages = []
  for name, folder in folders.items():
    COMMON_MODULE_PATH = f"{path}/{folder}"
    MODULES = getModules(COMMON_MODULE_PATH)
    if MODULES:
      pages.append(
        st.Page(
          lambda path=path.split('/')[-1], folder=folder, MODULES=MODULES: createPageModule(path, folder, MODULES),
          title=name,
          icon=random.choice(icons),
          url_path=folder
        )
      )
  return pages

Jarvis.py — Main Application Entrypoint

This script structures the app, adds categories/pages, and applies user authentication logic.

import streamlit as st

from src.helpers.structPages import structPages
from src.helpers.getFolders import getFolders

def application():
  pages = {
    "": [
      st.Page("src/apps/public/home.py", title="Home", icon=":material/home:"),
      st.Page("src/apps/public/youtubePlaylist.py", title="Jarvis Videos", icon=":material/ondemand_video:"),
    ],
    "Account": [
      st.Page("src/apps/auth/auth.py", title="Authentication", icon=":material/lock_open:"),
    ],
  }

  if st.user and st.user.is_logged_in:
    MAIN_DIR = "src/apps/pages"
    folders = getFolders(MAIN_DIR)
    if folders:
      for folder_name, folder_dir in folders.items():
        pages[folder_name.title()] = structPages(f"{MAIN_DIR}/{folder_dir}")

    if st.user.email == st.secrets["general"]["ADMIN_EMAIL"] and st.user.given_name == st.secrets["general"]["ADMIN_NAME"]:
      pages.update({
        "Admin": [
          st.Page("src/apps/auth/env.py", title="Environment Variables", icon=":material/security:"),
        ]
      })

  return st.navigation(pages)

application().run()

This modular setup allows for:

  • Easy extensibility by adding/removing modules
  • Role-based dynamic page access
  • Category-driven navigation structure
  • Clean user interface powered by st.Page and custom helper functions