In Morph, you build the backend using Python. You can freely add Python packages to build data processing and AI workflows.

Development Flow

The steps for backend development in Morph are as follows.

1

Add Python Packages

Since Morph follows the common Python project format, you can freely add Python packages. Add the necessary packages to requirements.txt or pyproject.toml.

2

Define Python Functions and Add Morph Decorators

By adding Morph decorators to regular Python function definitions, you can set aliases. This allows you to reference the results of these functions from other Python, SQL, or Markdown files.

import pandas as pd
import morph
from morph import MorphGlobalContext

# Add Morph decorators
@morph.func(name="example_dataframe")
@morph.load_data("example_data")
def example_dataframe(context: MorphGlobalContext):
    df = context.data["example_data"]
    return df
3

Test Python Functions

Use the morph run command to execute functions for unit testing.

morph run example_dataframe
4

Start the Development Server

By starting the development server, you can check the web application locally.

morph serve

Return Values of Python Functions

Python functions defined in a Morph project should have the following return values.

DataFrame

A DataFrame object representing the result of data processing. SQL execution results are also handled as DataFrames. Use this when you want to use the result of data processing in other Python files or display it in Markdown files.

The corresponding Markdown component is <DataFrame>.

import morph
from morph import MorphGlobalContext

@morph.func(name="example_dataframe")
@morph.load_data("example_data")
def example_dataframe(context: MorphGlobalContext):
    df = context.data["example_data"]
    return df

HTML String

An HTML string for rendering the results of data visualization. Use this when you want to display graphs drawn using visualization libraries like Plotly or Bokeh.

The corresponding Markdown component is <Embed>.

import plotly.express as px
import morph
from morph import MorphGlobalContext
from morph_lib.types import HtmlResponse

@morph.func(name="example_dataframe")
@morph.load_data("example_data")
def example_dataframe(context: MorphGlobalContext):
    df = context.data["example_data"]
    fig = px.bar(df, x='date', y='amount')
    return HtmlResponse(fig.to_html())

Streaming

Use this when using streaming APIs such as LLM API. Execute value streaming using the yeild instead of return.

The corresponding Markdown component is <Chat>.

import morph
from morph import MorphGlobalContext
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

@morph.func
def langchain_chat(context: MorphGlobalContext):
    llm = ChatOpenAI(model="gpt-4o")
    messages are [HumanMessage(context.vars["prompt"])]
    for token in llm.stream(messages):
        yield token.content