Skip to main content

A modern alternative to Gradio with stunning UI

Project description

olapp

A modern alternative to Gradio. Build ML demos and web apps with Python.

PyPI Python License Tests


Olapp UI Screenshot

Table of Contents


Why Olapp?

  • Clean, professional UI — not generic AI styling. Looks like a real product.
  • Simple APIInterface for quick demos, Blocks for complex layouts
  • 25 components — Textbox, Slider, Image, Chatbot, Code, Gallery, and more
  • Real-time streaming — SSE-based live updates
  • Dark/light themes — built-in, no config needed
  • HuggingFace Spaces compatible — drop in app.py and go
  • Mobile responsive — works on any screen size
  • Production ready — 114 tests, proper error handling

Install

pip install olapp

Requirements: Python 3.8+, aiohttp


Quick Start

import olapp

def greet(name, excitement):
    return f"Hello, {name}{'!' * int(excitement)}"

app = olapp.Interface(
    fn=greet,
    inputs=[
        olapp.Textbox(label="Name", placeholder="Enter your name"),
        olapp.Slider(minimum=1, maximum=10, value=3, label="Excitement"),
    ],
    outputs=olapp.Textbox(label="Greeting"),
    title="Greeter",
)
app.launch()

Open http://127.0.0.1:7860 and you have a working UI.


Tutorial: Build a Text Classifier UI

This tutorial shows how to wrap any NLP model (sentiment analysis, spam detection, etc.) in a web UI.

Step 1: Your Model Function

import olapp

# Replace this with your actual model
def classify_text(text):
    """Classify text sentiment."""
    # Example: simple keyword-based (replace with your ML model)
    positive_words = ["good", "great", "awesome", "love", "excellent"]
    negative_words = ["bad", "terrible", "hate", "awful", "horrible"]

    text_lower = text.lower()
    pos_count = sum(1 for w in positive_words if w in text_lower)
    neg_count = sum(1 for w in negative_words if w in text_lower)

    if pos_count > neg_count:
        return {"Positive": 0.85, "Neutral": 0.10, "Negative": 0.05}
    elif neg_count > pos_count:
        return {"Negative": 0.80, "Neutral": 0.15, "Positive": 0.05}
    else:
        return {"Neutral": 0.60, "Positive": 0.20, "Negative": 0.20}

Step 2: Create the Interface

app = olapp.Interface(
    fn=classify_text,
    inputs=olapp.Textbox(
        label="Input Text",
        placeholder="Type something to classify...",
        lines=3,
    ),
    outputs=olapp.Label(label="Prediction", num_top_classes=3),
    title="Text Classifier",
    description="Classify text sentiment using ML",
)

Step 3: Launch

app.launch()  # Opens at http://127.0.0.1:7860

Full Example with Real Model (Transformers)

import olapp
from transformers import pipeline

# Load model once at startup
classifier = pipeline("sentiment-analysis")

def predict(text):
    result = classifier(text)[0]
    return {result["label"]: result["score"]}

app = olapp.Interface(
    fn=predict,
    inputs=olapp.Textbox(label="Text", lines=4, placeholder="Enter text..."),
    outputs=olapp.Label(label="Sentiment"),
    title="Sentiment Analysis",
    description="Powered by HuggingFace Transformers",
)
app.launch()

Tutorial: Build an Image Generator UI

Wrap any image generation model (Stable Diffusion, DALL-E, etc.) in a web UI.

Step 1: Define Your Function

import olapp
from PIL import Image
import numpy as np

def generate_image(prompt, style, seed):
    """Generate an image. Replace with your actual model."""
    # Example: create a gradient image (replace with your model)
    np.random.seed(int(seed))
    width, height = 512, 512
    img = np.random.randint(0, 255, (height, width, 3), dtype=np.uint8)
    return Image.fromarray(img)

Step 2: Build the UI with Blocks

with olapp.Blocks(title="Image Generator") as app:
    olapp.Markdown(value="# Image Generator\nEnter a prompt and generate images.")

    with olapp.Row():
        with olapp.Column():
            prompt = olapp.Textbox(label="Prompt", placeholder="A beautiful sunset...", lines=3)
            style = olapp.Dropdown(
                label="Style",
                choices=["Realistic", "Anime", "Oil Painting", "Watercolor", "Pixel Art"],
                value="Realistic",
            )
            seed = olapp.Number(label="Seed", value=42, minimum=0, maximum=999999)
            btn = olapp.Button("Generate", variant="primary")

        with olapp.Column():
            output = olapp.Image(label="Generated Image")

    btn.click(fn=generate_image, inputs=[prompt, style, seed], outputs=output)

Step 3: Launch

app.launch()

Full Example with Stable Diffusion

import olapp
from diffusers import StableDiffusionPipeline
import torch

pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16,
).to("cuda")

def generate(prompt, steps, guidance):
    image = pipe(
        prompt,
        num_inference_steps=int(steps),
        guidance_scale=guidance,
    ).images[0]
    return image

with olapp.Blocks(title="Stable Diffusion") as app:
    with olapp.Row():
        with olapp.Column():
            prompt = olapp.Textbox(label="Prompt", lines=3)
            steps = olapp.Slider(label="Steps", minimum=1, maximum=100, value=30)
            guidance = olapp.Slider(label="Guidance Scale", minimum=1, maximum=20, value=7.5)
            btn = olapp.Button("Generate")
        with olapp.Column():
            img = olapp.Image(label="Output")

    btn.click(fn=generate, inputs=[prompt, steps, guidance], outputs=img)

app.launch(server_name="0.0.0.0", server_port=7860)

Tutorial: Build a Chatbot UI

Create a conversational AI interface.

Step 1: Define Chat Function

import olapp

def chat(message, history):
    """Process a chat message. Replace with your LLM."""
    # Simple echo bot (replace with your model)
    response = f"You said: {message}"
    history = history + [[message, response]]
    return history

Step 2: Build the UI

with olapp.Blocks(title="Chatbot") as app:
    olapp.Markdown(value="# AI Chatbot\nAsk me anything!")

    chatbot = olapp.Chatbot(label="Conversation", height=400)
    msg = olapp.Textbox(label="Your Message", placeholder="Type here...")

    with olapp.Row():
        send = olapp.Button("Send", variant="primary")
        clear = olapp.Button("Clear", variant="secondary")

    def send_message(message, history):
        if not message:
            return "", history
        response = chat(message, history)
        return "", response

    send.click(fn=send_message, inputs=[msg, chatbot], outputs=[msg, chatbot])
    msg.submit(fn=send_message, inputs=[msg, chatbot], outputs=[msg, chatbot])
    clear.click(fn=lambda: ("", []), outputs=[msg, chatbot])

app.launch()

Full Example with OpenAI

import olapp
from openai import OpenAI

client = OpenAI()

def chat(message, history):
    messages = [{"role": "system", "content": "You are a helpful assistant."}]
    for user_msg, bot_msg in history:
        messages.append({"role": "user", "content": user_msg})
        if bot_msg:
            messages.append({"role": "assistant", "content": bot_msg})
    messages.append({"role": "user", "content": message})

    response = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
    )
    reply = response.choices[0].message.content
    return history + [[message, reply]]

with olapp.Blocks(title="AI Chat") as app:
    chatbot = olapp.Chatbot(label="Chat", height=500)
    msg = olapp.Textbox(label="Message", placeholder="Ask anything...")

    with olapp.Row():
        send = olapp.Button("Send", variant="primary")
        clear = olapp.Button("Clear")

    send.click(fn=chat, inputs=[msg, chatbot], outputs=chatbot)
    msg.submit(fn=chat, inputs=[msg, chatbot], outputs=chatbot)
    clear.click(fn=lambda: [], outputs=chatbot)

app.launch()

Tutorial: Build a Data Dashboard

Create interactive data exploration tools.

import olapp
import pandas as pd

def analyze_data(file, filter_col, filter_val):
    """Analyze uploaded CSV data."""
    if file is None:
        return None, "No file uploaded"

    df = pd.read_csv(file)

    if filter_col and filter_val:
        df = df[df[filter_col].astype(str).str.contains(filter_val)]

    summary = df.describe().to_html()
    return {"headers": list(df.columns), "data": df.head(20).values.tolist()}, summary

with olapp.Blocks(title="Data Explorer") as app:
    olapp.Markdown(value="# Data Explorer\nUpload a CSV and explore your data.")

    with olapp.Row():
        with olapp.Column():
            file = olapp.File(label="Upload CSV", file_types=[".csv"])
            col = olapp.Textbox(label="Filter Column", placeholder="column_name")
            val = olapp.Textbox(label="Filter Value", placeholder="search term")
            btn = olapp.Button("Analyze", variant="primary")

        with olapp.Column():
            table = olapp.Dataframe(label="Data Preview")
            stats = olapp.HTML(label="Statistics")

    btn.click(fn=analyze_data, inputs=[file, col, val], outputs=[table, stats])

app.launch()

HuggingFace Spaces Deployment

Deploy your olapp app to HuggingFace Spaces in 3 steps.

Step 1: Create Your App

Create app.py:

import olapp

def predict(text):
    """Your model function."""
    return text[::-1]  # Example: reverse text

app = olapp.Interface(
    fn=predict,
    inputs=olapp.Textbox(label="Input", placeholder="Enter text..."),
    outputs=olapp.Textbox(label="Output"),
    title="Text Reverser",
    description="A simple text reverser built with olapp",
)

app.launch(server_name="0.0.0.0", server_port=7860)

Step 2: Create requirements.txt

olapp

Add any other dependencies your model needs:

olapp
transformers
torch

Step 3: Create README.md for Spaces

Add this YAML frontmatter to your Spaces README.md:

---
title: My Olapp Demo
emoji: 🚀
colorFrom: indigo
colorTo: purple
sdk: docker
pinned: false
---

Step 4: Push to HuggingFace

# Install huggingface_hub
pip install huggingface_hub

# Login
huggingface-cli login

# Create space
huggingface-cli space create my-olapp-demo --sdk docker

# Push your files
git add app.py requirements.txt README.md
git commit -m "Initial olapp demo"
git push

Dockerfile for Spaces

Create a Dockerfile:

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 7860
CMD ["python", "app.py"]

Example: Deploy a Sentiment Model to Spaces

# app.py
import olapp
from transformers import pipeline

classifier = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")

def predict(text):
    result = classifier(text)[0]
    return {result["label"]: round(result["score"], 4)}

app = olapp.Interface(
    fn=predict,
    inputs=olapp.Textbox(label="Text", lines=3, placeholder="Enter text to analyze..."),
    outputs=olapp.Label(label="Sentiment", num_top_classes=2),
    title="Sentiment Analysis",
    description="Powered by DistilBERT + olapp",
)

app.launch(server_name="0.0.0.0", server_port=7860)

Interface API

The simplest way to create a UI. Just define a function, inputs, and outputs.

import olapp

def my_function(input1, input2):
    return output

app = olapp.Interface(
    fn=my_function,
    inputs=[component1, component2],
    outputs=[component3],
    title="My App",
    description="What this app does",
)
app.launch()

Parameters

Parameter Type Default Description
fn Callable required The function to wrap
inputs Component/str/list [] Input components
outputs Component/str/list [] Output components
title str "Olapp" App title
description str "" App description
theme str "default" Theme name
live bool False Update on every input change

String Shorthand

# These are equivalent:
olapp.Interface(fn=f, inputs="textbox", outputs="textbox")
olapp.Interface(fn=f, inputs=olapp.Textbox(), outputs=olapp.Textbox())

Blocks API

For complex layouts with rows, columns, tabs, and events.

import olapp

with olapp.Blocks(title="My App") as app:
    # Add components
    text = olapp.Textbox(label="Input")
    output = olapp.Textbox(label="Output")
    btn = olapp.Button("Run")

    # Wire events
    btn.click(fn=lambda x: x.upper(), inputs=text, outputs=output)

app.launch()

Context Managers

with olapp.Blocks() as app:
    with olapp.Row():
        with olapp.Column():
            left = olapp.Textbox(label="Left")
        with olapp.Column():
            right = olapp.Textbox(label="Right")

    with olapp.Group():
        btn = olapp.Button("Submit")

    with olapp.Tabs():
        with olapp.Tab("Tab 1"):
            olapp.Markdown(value="Content 1")
        with olapp.Tab("Tab 2"):
            olapp.Markdown(value="Content 2")

All 25 Components

Input Components

Component Key Args Description
Textbox label, placeholder, lines, value Single/multi-line text
Number label, value, minimum, maximum, step Numeric input
Slider label, minimum, maximum, value, step Range slider
Checkbox label, value Boolean toggle
Dropdown label, choices, value, multiselect Selection dropdown
Radio label, choices, value Radio buttons
Button label, variant (primary/secondary) Click button
Image label, value Image upload/display
Audio label, value Audio upload/playback
Video label, value Video upload/playback
File label, file_types File upload
ColorPicker label, value Color picker
DateTime label, include_time Date/time picker
Code label, language, lines Code editor

Output Components

Component Key Args Description
Textbox (same as input) Text display
Image (same as input) Image display
Dataframe label, headers, value Table display
Markdown value Markdown renderer
HTML value Raw HTML
Chatbot label, value, height Chat interface
Label label, num_top_classes Classification labels
HighlightedText label, value Text with highlights
JSON label, value JSON viewer
Gallery label, columns, value Image grid
Progress label, value Progress bar

Utility Components

Component Description
State Hidden state between interactions

Color Theme

Olapp uses a clean, professional palette:

Token Light Dark Usage
Primary #6366f1 #818cf8 Buttons, links, accents
Success #059669 #059669 Success states
Warning #d97706 #d97706 Warning states
Error #dc2626 #dc2626 Error states
Background #ffffff #030712 Page background
Surface #ffffff #111827 Card backgrounds
Border #e5e7eb #1f2937 Borders and dividers
Text #111827 #f9fafb Primary text
Text Secondary #4b5563 #9ca3af Secondary text

Layout System

Row

Side-by-side layout:

with olapp.Row():
    left = olapp.Textbox(label="Left")
    right = olapp.Textbox(label="Right")

Column

Vertical layout with scaling:

with olapp.Column(scale=2):  # Takes 2x space
    big = olapp.Textbox(label="Big")
with olapp.Column(scale=1):  # Takes 1x space
    small = olapp.Textbox(label="Small")

Group

Bordered container:

with olapp.Group():
    olapp.Textbox(label="Inside group")
    olapp.Button("Also inside")

Tabs

Tabbed interface:

with olapp.Tabs():
    with olapp.Tab("Tab 1"):
        olapp.Markdown(value="Content 1")
    with olapp.Tab("Tab 2"):
        olapp.Markdown(value="Content 2")

Accordion

Collapsible sections:

with olapp.Accordion(label="Advanced Settings", open=False):
    olapp.Slider(label="Threshold", minimum=0, maximum=1, value=0.5)
    olapp.Checkbox(label="Enable caching")

Events & Interactivity

Click

Trigger on button click:

btn.click(fn=my_function, inputs=[input1, input2], outputs=output)

Change

Trigger on value change:

slider.change(fn=update_preview, inputs=slider, outputs=preview)

Submit

Trigger on form submit (Enter key):

textbox.submit(fn=process, inputs=textbox, outputs=result)

Chaining Events

with olapp.Blocks() as app:
    inp = olapp.Textbox(label="Input")
    step1 = olapp.Textbox(label="Step 1")
    step2 = olapp.Textbox(label="Step 2")
    out = olapp.Textbox(label="Output")

    inp.submit(fn=preprocess, inputs=inp, outputs=step1)
    step1.submit(fn=transform, inputs=step1, outputs=step2)
    step2.submit(fn=postprocess, inputs=step2, outputs=out)

Streaming & Real-time

For long-running operations, use streaming:

import olapp
import time

def slow_function(text):
    """Simulate a slow process."""
    result = ""
    for char in text:
        result += char
        time.sleep(0.1)
    return result

app = olapp.Interface(
    fn=slow_function,
    inputs=olapp.Textbox(label="Input"),
    outputs=olapp.Textbox(label="Output"),
    title="Streaming Demo",
)
app.launch()

Advanced Usage

Custom CSS

app = olapp.Interface(
    fn=my_fn,
    inputs="textbox",
    outputs="textbox",
    css="""
    .olapp-card { border-radius: 16px; }
    .olapp-btn-primary { background: #10b981; }
    """,
)

Pre/Post Processing

Components can preprocess inputs and postprocess outputs:

class MyTextbox(olapp.Textbox):
    def preprocess(self, x):
        return x.strip().lower()  # Clean input

    def postprocess(self, y):
        return y.upper()  # Format output

Multiple Outputs

def analyze(text):
    return text.upper(), len(text), text.split()

app = olapp.Interface(
    fn=analyze,
    inputs=olapp.Textbox(label="Input"),
    outputs=[
        olapp.Textbox(label="Uppercase"),
        olapp.Number(label="Length"),
        olapp.JSON(label="Words"),
    ],
)

Launch Options

app.launch(
    server_name="0.0.0.0",  # Listen on all interfaces
    server_port=8080,        # Custom port
    prevent_thread_lock=True, # Non-blocking (for notebooks)
)

API Reference

Endpoints

Every olapp app exposes these HTTP endpoints:

Method Path Description
GET / Web UI
GET /api/config App configuration
POST /api/predict Run prediction
GET /api/health Health check
GET /api/queue/join SSE stream

Predict API

curl -X POST http://localhost:7860/api/predict \
  -H "Content-Type: application/json" \
  -d '{"data": ["Hello", 5]}'

Response:

{"data": ["Hello!!!!!"]}

Development

git clone https://github.com/Atum246/olapp.git
cd olapp
pip install -e ".[dev]"
python -m pytest tests/ -v

Project Structure

olapp/
├── olapp/
│   ├── __init__.py       # Package exports
│   ├── components.py     # 25 UI components
│   ├── interface.py      # Simple Interface API
│   ├── blocks.py         # Flexible Blocks API
│   ├── server.py         # aiohttp web server
│   ├── routes.py         # API route handlers
│   ├── utils.py          # Utilities
│   ├── static/
│   │   ├── olapp.css     # Styles
│   │   └── olapp.js      # Frontend logic
│   └── templates/
│       └── index.html    # HTML template
├── tests/                # 114 tests
├── examples/             # Example apps
├── app.py                # HuggingFace Spaces demo
└── pyproject.toml        # Package config

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

olapp-0.2.2.tar.gz (48.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

olapp-0.2.2-py3-none-any.whl (38.7 kB view details)

Uploaded Python 3

File details

Details for the file olapp-0.2.2.tar.gz.

File metadata

  • Download URL: olapp-0.2.2.tar.gz
  • Upload date:
  • Size: 48.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for olapp-0.2.2.tar.gz
Algorithm Hash digest
SHA256 5cdd113184267dac550f0b2fd8ea8c17e5b41a5e2a49612e13441dab8973b0b8
MD5 53f83af38950ab77a59943bfac1a2e10
BLAKE2b-256 cf5c4eb90fef71522378a184bf815891bc33a9a134e7ffc81acfc9b4021dfa6e

See more details on using hashes here.

File details

Details for the file olapp-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: olapp-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 38.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for olapp-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 395d4916c49cbcf3d1dcdd541a5cb86e0c2aef40c4fef13f549eeacdab330ddb
MD5 c1d1f81a4e811bfbcac03d0ebe4ec2d3
BLAKE2b-256 bbf4234da080dec70a38c86bc9a26162e2658939da4a25ba67801043b2f54b60

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page