Simple AI Engineering Pipeline (Python)

A beginner-friendly clone of an AI pipeline using Flask and SQLite

Welcome to another official UVF IT build guide! In this tutorial we’ll craft a tiny AI engineering pipeline inspired by the massive open‑source curriculum you referenced. The goal is a runnable Flask service that stores prompts, runs a placeholder "model" (just reverses text), and returns results—all with free, local tools.

You’ll finish in ~45 minutes, end up with a local web UI, and have a solid foundation to expand into real vector stores, LLM calls, or orchestration later.

Before you start

Minimal Pipeline Architecture
LOCAL RESOURCES store/retrieve prompts process prompt Flask App API + UI SQLite DB Placeholder Model reverse text
1

Phase 1: Scaffold the project

First we create an isolated Python environment so our dependencies don’t clash with other projects. Then we install Flask, the only web framework we need, and lay out a simple folder hierarchy that will hold the app code, the database schema, and static assets.

The folder layout mirrors typical Flask projects: a top‑level app package for Python modules, a templates folder for HTML UI, and a pipeline folder for the SQLite schema and future utilities. This scaffold gives us a clean starting point for incremental development.

python -m venv venv
# Activate the environment
# Windows:
venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate
pip install --upgrade pip
pip install Flask
# Create folder structure
mkdir -p app/templates pipeline
touch app/__init__.py app/routes.py pipeline/schema.sql
2

Phase 2: Define the data model

Our pipeline needs to persist the original prompt and the model’s output. SQLite is perfect for a lightweight, file‑based store and requires no external server. We’ll create a single table called interactions with columns for an auto‑incrementing ID, the prompt text, the result text, and a timestamp.

The schema lives in pipeline/schema.sql so it can be reapplied easily during development or testing. Later phases will load this file and execute it against the SQLite database file pipeline/data.db.

pipeline/schema.sql

CREATE TABLE IF NOT EXISTS interactions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    prompt TEXT NOT NULL,
    result TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
3

Phase 3: Implement the placeholder model

In this step we create a tiny “model” that pretends to be an AI engine. The function simply reverses whatever text you give it – that’s enough to prove the pipeline works end‑to‑end. Keeping the logic isolated in its own file makes it easy to swap for a real LLM later without touching the Flask code.

pipeline/model.py

import sqlite3
import os

DB_PATH = os.path.join(os.path.dirname(__file__), 'pipeline.db')

def _init_db():
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()
    cur.execute('''CREATE TABLE IF NOT EXISTS logs (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        prompt TEXT NOT NULL,
        response TEXT NOT NULL,
        ts DATETIME DEFAULT CURRENT_TIMESTAMP
    )''')
    conn.commit()
    conn.close()

# Ensure the DB exists before any calls
_init_db()

def run_model(prompt: str) -> str:
    """Placeholder model – returns the reversed prompt string.
    Also stores the prompt/response pair in SQLite for later inspection.
    """
    response = prompt[::-1]
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()
    cur.execute('INSERT INTO logs (prompt, response) VALUES (?, ?)', (prompt, response))
    conn.commit()
    conn.close()
    return response
4

Phase 4: Build the Flask API & UI

Now we wire a tiny Flask server to expose three endpoints: the home page, a JSON API to submit a prompt, and a view that lists all past interactions. The UI is a single HTML template that posts a prompt and shows the growing history table. All routes use the run_model function from the previous phase, so the reversed text appears instantly.

We keep the Flask app minimal – no blueprints, no extensions – to stay beginner‑friendly. The SQLite file lives next to the model, and we read it directly when rendering the history list.

pipeline/app.py

from flask import Flask, request, jsonify, render_template_string, redirect, url_for
from model import run_model
import sqlite3, os

app = Flask(__name__)
DB_PATH = os.path.join(os.path.dirname(__file__), 'pipeline.db')

HTML = """
<!doctype html>
<title>Simple AI Pipeline</title>
<h1>Enter a prompt</h1>
<form action="/submit" method="post">
  <input name="prompt" placeholder="type something" required>
  <button type="submit">Run</button>
</form>
<h2>History</h2>
<table border=1>
  <tr><th>Prompt</th><th>Response</th></tr>
  {% for row in logs %}
    <tr><td>{{row[0]}}</td><td>{{row[1]}}</td></tr>
  {% endfor %}
</table>
"""

def get_logs():
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()
    cur.execute('SELECT prompt, response FROM logs ORDER BY id DESC')
    rows = cur.fetchall()
    conn.close()
    return rows

@app.route('/')
def index():
    return render_template_string(HTML, logs=get_logs())

@app.route('/submit', methods=['POST'])
def submit():
    prompt = request.form.get('prompt', '')
    if prompt:
        run_model(prompt)
    return redirect(url_for('index'))

@app.route('/api/run', methods=['POST'])
def api_run():
    data = request.get_json(silent=True) or {}
    prompt = data.get('prompt', '')
    response = run_model(prompt) if prompt else ''
    return jsonify({'prompt': prompt, 'response': response})

if __name__ == '__main__':
    app.run(debug=True)
5

Phase 5: Run and verify locally

With the code in place, start the Flask server using the provided Bash command. The app will listen on http://127.0.0.1:5000/ – open that URL in a browser, type a phrase, and watch the reversed result appear in the history table. Finally, you can peek into the SQLite database to confirm the prompt/response pair was persisted.

# From the repository root, install Flask if needed and launch the app
python -m pip install flask --quiet
python pipeline/app.py

Verifying the Stack

CheckCommand / Why it matters
Server starts without errorYou see "Running on http://127.0.0.1:5000/" in the terminal
Submitting a prompt shows reversed text in the listEnter "hello" in the browser UI; the page displays "olleh" under the prompt
SQLite file contains a rowRun sqlite3 pipeline/pipeline.db "SELECT prompt,response FROM logs;" and see the stored values

What’s next?

You now have a functional skeleton. Swap run_model for an actual LLM (OpenAI, HuggingFace, etc.), add vector‑store persistence, or expand the UI. Happy hacking!