Skip to main content

A modern REST API service for managing and serving AI prompts

Project description

๐Ÿš€ Exemplar Prompt Hub

Python Version FastAPI License Code Style Test Coverage PostgreSQL Docker

A modern REST API service for managing and serving AI prompts. This service provides a centralized repository for storing, versioning, and retrieving prompts for various AI applications. It uses PostgreSQL as the database for robust and scalable data management.


๐Ÿ“‘ Table of Contents

โœจ Features

For a detailed checklist of implemented and planned features, see FEATURES.md.

  • RESTful API for prompt management
  • Version control for prompts
  • Tag-based prompt organization
  • Metadata support for prompts
  • Authentication and authorization
  • Search and filtering capabilities

๐Ÿ› ๏ธ Getting Started

Prerequisites

  • Python 3.8 or higher
  • pip (Python package manager)
  • Git
  • PostgreSQL (for database) (by default it uses sqlite as per .env.example)
  • Docker and Docker Compose (for containerized setup)

Installation

Using pip

You can install the package directly from PyPI:

๐Ÿ Python (pip, Virtual Environment)

python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install exemplar-prompt-hub
# Create a .env file and copy content from .env.example as per the github repo
cp .env.example .env
# Edit .env as needed
prompt-hub

Or install from the source:

# Clone the repository
git clone https://github.com/yourusername/exemplar-prompt-hub.git
cd exemplar-prompt-hub

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows, use `venv\Scripts\activate`

# Install the package
pip install -e .

# Copy .env.example to .env [copy .env.example from github repo branch]
cp .env.example .env

# Edit .env to configure your database and other settings

After installation, you can use the following command:

  • prompt-hub - Start the FastAPI server

Using Docker

The easiest way to get started is using Docker Compose:

  1. Clone the repository:

    git clone https://github.com/yourusername/exemplar-prompt-hub.git
    cd exemplar-prompt-hub
    
  2. Start the services:

    docker-compose up -d
    

    This will start:

  3. Access the services:

  4. Stop the services:

    docker-compose down
    

Manual Installation

If you prefer to run the services manually:

  1. Clone the repository:

    git clone https://github.com/yourusername/exemplar-prompt-hub.git
    cd exemplar-prompt-hub
    
  2. Create a virtual environment:

    python -m venv venv
    source venv/bin/activate  # On Windows, use `venv\\Scripts\\activate`
    
  3. Install dependencies:

    pip install -r requirements.txt
    
  4. Set up environment variables:

    • Copy .env.example to .env:
      cp .env.example .env
      
    • Edit .env to configure your database and other settings.
  5. Start the application:

    uvicorn app.main:app --reload
    

Running Tests

To run the tests, use:

pytest

For detailed test coverage, use:

pytest --cov=app --cov-report=term-missing

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For detailed contribution guidelines, please refer to the CONTRIBUTING.md file.

License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ“š API Documentation

Once the server is running, you can access the interactive API documentation at:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc

๐Ÿ”„ API Usage Examples

Here are some example curl commands to interact with the API:

Create a Prompt

curl -X POST "http://localhost:8000/api/v1/prompts/" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "example-prompt",
    "text": "This is an example prompt text",
    "description": "A sample prompt for demonstration",
    "meta": {
      "author": "test-user",
      "category": "example"
    },
    "tags": ["example", "test"]
  }'

Note: The version field is optional and handled automatically by the API. New prompts start with version 1, and subsequent updates will increment the version number automatically.

Get All Prompts

# Get all prompts
curl "http://localhost:8000/api/v1/prompts/"

# Get prompts with search
curl "http://localhost:8000/api/v1/prompts/?search=example"

# Get prompts with tag filter
curl "http://localhost:8000/api/v1/prompts/?tag=test"

# Get prompts with pagination
curl "http://localhost:8000/api/v1/prompts/?skip=0&limit=10"

Get a Specific Prompt

# Replace {prompt_id} with actual ID
curl "http://localhost:8000/api/v1/prompts/{prompt_id}"

Update a Prompt

curl -X PUT "http://localhost:8000/api/v1/prompts/{prompt_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Updated prompt text",
    "description": "Updated description",
    "meta": {
      "author": "test-user",
      "category": "updated"
    },
    "tags": ["updated", "test"]
  }'

Delete a Prompt

curl -X DELETE "http://localhost:8000/api/v1/prompts/{prompt_id}"

๐Ÿ“ Project Structure

exemplar-prompt-hub/
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ api/
โ”‚   โ”‚   โ””โ”€โ”€ endpoints/
โ”‚   โ”‚       โ””โ”€โ”€ prompts.py
โ”‚   โ”œโ”€โ”€ core/
โ”‚   โ”‚   โ””โ”€โ”€ config.py
โ”‚   โ”œโ”€โ”€ db/
โ”‚   โ”‚   โ”œโ”€โ”€ base_class.py
โ”‚   โ”‚   โ”œโ”€โ”€ models.py
โ”‚   โ”‚   โ””โ”€โ”€ session.py
โ”‚   โ”œโ”€โ”€ schemas/
โ”‚   โ”‚   โ””โ”€โ”€ prompt.py
โ”‚   โ””โ”€โ”€ main.py
โ”œโ”€โ”€ tests/
โ”‚   โ””โ”€โ”€ test_prompts.py
โ”œโ”€โ”€ alembic/
โ”‚   โ””โ”€โ”€ versions/
โ”œโ”€โ”€ .env.example
โ”œโ”€โ”€ .gitignore
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ LICENSE
โ”œโ”€โ”€ MANIFEST.in
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ requirements.txt
โ””โ”€โ”€ setup.py

๐Ÿ“Š Database Table Structure

Prompts Table

CREATE TABLE prompts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    text TEXT NOT NULL,
    description TEXT,
    version INTEGER NOT NULL,
    meta TEXT,  -- Store JSON as TEXT in SQLite
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP
);

Tags Table

CREATE TABLE tags (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE
);

Prompt Tags Table (Many-to-Many Relationship)

CREATE TABLE prompt_tags (
    prompt_id INTEGER,
    tag_id INTEGER,
    PRIMARY KEY (prompt_id, tag_id),
    FOREIGN KEY (prompt_id) REFERENCES prompts(id) ON DELETE CASCADE,
    FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);

Prompt Versions Table

CREATE TABLE prompt_versions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    prompt_id INTEGER,
    version INTEGER,
    text TEXT,
    description TEXT,
    meta TEXT,  -- Store JSON as TEXT in SQLite
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (prompt_id) REFERENCES prompts(id) ON DELETE CASCADE
);

Indexes

CREATE INDEX idx_prompts_name ON prompts(name);
CREATE INDEX idx_tags_name ON tags(name);
CREATE INDEX idx_prompt_versions_prompt_id ON prompt_versions(prompt_id);
CREATE INDEX idx_prompt_tags_prompt_id ON prompt_tags(prompt_id);
CREATE INDEX idx_prompt_tags_tag_id ON prompt_tags(tag_id);

Timestamp Trigger

CREATE TRIGGER update_prompt_timestamp 
AFTER UPDATE ON prompts
BEGIN
    UPDATE prompts SET updated_at = CURRENT_TIMESTAMP
    WHERE id = NEW.id;
END;

Key differences from PostgreSQL:

  1. Uses INTEGER PRIMARY KEY AUTOINCREMENT instead of SERIAL
  2. Uses TEXT instead of VARCHAR and JSONB
  3. Stores JSON as TEXT with manual serialization
  4. Requires explicit foreign key support with PRAGMA foreign_keys = ON
  5. Uses triggers for updated_at timestamp management

๐Ÿ”„ Updating Prompts with Versioning

The API supports versioning of prompts. When updating a prompt:

  1. The current version is incremented
  2. A new record is created with the updated content
  3. The old version is preserved for reference

To update a prompt, use the PUT endpoint with the prompt ID:

curl -X PUT "http://localhost:8000/api/v1/prompts/{prompt_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Updated prompt text",
    "description": "Updated description",
    "meta": {
      "author": "test-user",
      "category": "updated"
    },
    "tags": ["updated", "test"]
  }'

The API will automatically handle versioning and maintain the history of changes.

๐ŸŽจ Using Prompts with Jinja Templating

The API supports Jinja2 templating in prompts, allowing you to create dynamic prompts with variables. Here's how to use it:

1. Create a Template Prompt

# Create a basic greeting template
curl -X POST "http://localhost:8000/api/v1/prompts/" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "greeting-template",
    "text": "Hello {{ name }}! Welcome to {{ platform }}. Your role is {{ role }}.",
    "description": "A greeting template with dynamic variables",
    "meta": {
      "template_variables": ["name", "platform", "role"],
      "author": "test-user"
    },
    "tags": ["template", "greeting"]
  }'

# Response:
{
  "id": 1,
  "name": "greeting-template",
  "text": "Hello {{ name }}! Welcome to {{ platform }}. Your role is {{ role }}.",
  "description": "A greeting template with dynamic variables",
  "version": 1,
  "meta": {
    "template_variables": ["name", "platform", "role"],
    "author": "test-user"
  },
  "tags": [
    {"id": 1, "name": "template"},
    {"id": 2, "name": "greeting"}
  ],
  "created_at": "2024-03-20T10:00:00",
  "updated_at": null
}

See examples/jinja_open_ai.py for a complete Python implementation of how to use this template with Jinja2.

2. Fetch and Use Templates

# Fetch a template by ID
curl "http://localhost:8000/api/v1/prompts/1"

# Response:
{
  "id": 1,
  "name": "greeting-template",
  "text": "Hello {{ name }}! Welcome to {{ platform }}. Your role is {{ role }}.",
  "description": "A greeting template with dynamic variables",
  "version": 1,
  "meta": {
    "template_variables": ["name", "platform", "role"],
    "author": "test-user"
  },
  "tags": [
    {"id": 1, "name": "template"},
    {"id": 2, "name": "greeting"}
  ],
  "created_at": "2024-03-20T10:00:00",
  "updated_at": null
}

# Fetch a template by name
curl "http://localhost:8000/api/v1/prompts/?search=greeting-template"

# Response:
[
  {
    "id": 1,
    "name": "greeting-template",
    "text": "Hello {{ name }}! Welcome to {{ platform }}. Your role is {{ role }}.",
    "description": "A greeting template with dynamic variables",
    "version": 1,
    "meta": {
      "template_variables": ["name", "platform", "role"],
      "author": "test-user"
    },
    "tags": [
      {"id": 1, "name": "template"},
      {"id": 2, "name": "greeting"}
    ],
    "created_at": "2024-03-20T10:00:00",
    "updated_at": null
  }
]

3. Update a Template

# Update a template with new variables
curl -X PUT "http://localhost:8000/api/v1/prompts/1" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Hello {{ name }}! Welcome to {{ platform }}. Your role is {{ role }}. Your department is {{ department }}.",
    "description": "Updated greeting template with department",
    "meta": {
      "template_variables": ["name", "platform", "role", "department"],
      "author": "test-user",
      "updated": true
    },
    "tags": ["template", "greeting", "updated"]
  }'

# Response:
{
  "id": 1,
  "name": "greeting-template",
  "text": "Hello {{ name }}! Welcome to {{ platform }}. Your role is {{ role }}. Your department is {{ department }}.",
  "description": "Updated greeting template with department",
  "version": 2,
  "meta": {
    "template_variables": ["name", "platform", "role", "department"],
    "author": "test-user",
    "updated": true
  },
  "tags": [
    {"id": 1, "name": "template"},
    {"id": 2, "name": "greeting"},
    {"id": 5, "name": "updated"}
  ],
  "created_at": "2024-03-20T10:00:00",
  "updated_at": "2024-03-20T10:15:00"
}

4. Delete a Template

# Delete a template
curl -X DELETE "http://localhost:8000/api/v1/prompts/1"

# Response: 204 No Content

5. Using Templates in Python

See the complete examples in the examples/templating/python directory:

  1. Basic string template: examples/templating/python/string_template_example.py
  2. F-strings: examples/templating/python/f_strings_example.py
  3. Mako template engine: examples/templating/python/mako_example.py
  4. Control structures: examples/templating/python/control_structures_example.py
  5. Jinja2 macros: examples/templating/python/macro_example.py

Here's a simple example using Jinja2:

import requests
import jinja2
from jinja2 import Template

# Fetch the prompt template
response = requests.get("http://localhost:8000/api/v1/prompts/1")
prompt_data = response.json()

# Create a Jinja template
template = Template(prompt_data["text"])

# Render with variables
rendered_prompt = template.render(
    name="John",
    platform="Exemplar Prompt Hub",
    role="Developer",
    department="Engineering"
)

print(rendered_prompt)
# Output: Hello John! Welcome to Exemplar Prompt Hub. Your role is Developer. Your department is Engineering.

For more advanced examples including control structures, macros, and different template engines, refer to the example files mentioned above. Each example demonstrates different approaches to template rendering:

  • string_template_example.py: Uses Python's built-in string.Template for simple variable substitution
  • f_strings_example.py: Shows how to use Python's f-strings for template rendering
  • mako_example.py: Demonstrates the Mako template engine for high-performance templating
  • control_structures_example.py: Shows how to use if-else statements and loops in templates
  • macro_example.py: Demonstrates reusable template components using Jinja2 macros

6. Using Templates in JavaScript

See the complete examples in the examples/templating/javascript directory:

  1. Basic template literals: examples/templating/javascript/template_literals.js
  2. Handlebars.js: examples/templating/javascript/handlebars_example.js
  3. Mustache.js: examples/templating/javascript/mustache_example.js
  4. React component: examples/templating/javascript/react_example.jsx
  5. Control structures: examples/templating/javascript/control_structures_example.js
  6. Macros/Partials: examples/templating/javascript/macro_example.js

Here's a simple example using template literals:

// Fetch and render a template
async function renderPrompt(promptId, variables) {
    const response = await fetch(`http://localhost:8000/api/v1/prompts/${promptId}`);
    const promptData = await response.json();
    
    // Create template function
    const template = new Function('variables', `
        with(variables) {
            return \`${promptData.text}\`;
        }
    `);
    
    // Render with variables
    return template(variables);
}

// Usage
const renderedPrompt = await renderPrompt(1, {
    name: 'John',
    platform: 'Exemplar Prompt Hub',
    role: 'Developer',
    department: 'Engineering'
});

console.log(renderedPrompt);
// Output: Hello John! Welcome to Exemplar Prompt Hub. Your role is Developer. Your department is Engineering.

For more advanced examples including control structures, macros, and React integration, refer to the example files mentioned above.

Best Practices

  1. Document Variables: Always document template variables in the prompt's meta field
  2. Default Values: Consider providing default values in the template
  3. Error Handling: Use Jinja2's error handling features
  4. Security: Be careful with user input in templates
  5. Versioning: Use the API's versioning feature to track template changes

Example with Error Handling

from jinja2 import Template, TemplateError

try:
    template = Template(prompt_data["text"])
    rendered_prompt = template.render(
        name="John",
        platform="Exemplar Prompt Hub"
        # role is missing, will use default if defined
    )
except TemplateError as e:
    print(f"Template error: {e}")

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

exemplar_prompt_hub-0.2.1.tar.gz (20.7 kB view details)

Uploaded Source

Built Distribution

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

exemplar_prompt_hub-0.2.1-py3-none-any.whl (16.0 kB view details)

Uploaded Python 3

File details

Details for the file exemplar_prompt_hub-0.2.1.tar.gz.

File metadata

  • Download URL: exemplar_prompt_hub-0.2.1.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.7

File hashes

Hashes for exemplar_prompt_hub-0.2.1.tar.gz
Algorithm Hash digest
SHA256 fbbef37d7f9048eafd3b9bb92c655f8cb486b2060721b80ad5c8d71a34fd80b3
MD5 26216d52de9d93d66447204850e7002b
BLAKE2b-256 78819de6af32d7f240a34423b1792531fcd885a35da4cd92843acb07211b443f

See more details on using hashes here.

File details

Details for the file exemplar_prompt_hub-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for exemplar_prompt_hub-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 80ff755e87c3118aa88344daee2a8b5e6f6988ae983cc473d7ef899fc2714ee7
MD5 b8fc322faa303893a359f3ed53794b8d
BLAKE2b-256 5e7de57067d42276fe3979404c57b4e525d337fb4310d92989223d343e4f5169

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