Metadata-Version: 2.4
Name: python-prompt-manager
Version: 0.2.0
Summary: Centralized prompt management for LLM applications
Home-page: https://github.com/yourusername/python-prompt-manager
Author: Your Name
Author-email: Andrew OHarney <noemail@enodomain.com>
License: MIT
Project-URL: Homepage, https://github.com/yourusername/python-prompt-manager
Project-URL: Documentation, https://python-prompt-manager.readthedocs.io
Project-URL: Repository, https://github.com/yourusername/python-prompt-manager
Project-URL: Issues, https://github.com/yourusername/python-prompt-manager/issues
Keywords: prompt,prompt-management,llm,openai,ai
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Framework :: Django
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == "openai"
Provides-Extra: yaml
Requires-Dist: pyyaml>=5.4; extra == "yaml"
Provides-Extra: django
Requires-Dist: django>=3.2; extra == "django"
Provides-Extra: pydantic
Requires-Dist: pydantic>=2.0; extra == "pydantic"
Provides-Extra: all
Requires-Dist: openai>=1.0.0; extra == "all"
Requires-Dist: pyyaml>=5.4; extra == "all"
Requires-Dist: pydantic>=2.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: pytest-django>=4.5; extra == "dev"
Requires-Dist: pytest-env>=0.8; extra == "dev"
Requires-Dist: black>=23.0; extra == "dev"
Requires-Dist: flake8>=6.0; extra == "dev"
Requires-Dist: mypy>=1.0; extra == "dev"
Requires-Dist: tox>=4.0; extra == "dev"
Requires-Dist: sphinx>=5.0; extra == "dev"
Requires-Dist: sphinx-rtd-theme>=1.0; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# Python Prompt Manager

A lightweight, extensible prompt management system for LLM applications. Centralize and version your prompts while keeping your codebase clean.

[![PyPI version](https://badge.fury.io/py/python-prompt-manager.svg)](https://badge.fury.io/py/python-prompt-manager)
[![Python Support](https://img.shields.io/pypi/pyversions/python-prompt-manager.svg)](https://pypi.org/project/python-prompt-manager/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Why Use This?

Managing prompts for LLM applications can quickly become messy. Hardcoded strings, scattered prompt files / urls, and unclear versioning make maintenance difficult. This package solves these problems by providing a clean, centralized way to manage your prompts.

## Features

- **Multiple Storage Backends**: Store prompts in OpenAI's system, local files, or create your own storage extension
- **Environment-Based Configuration**: No hardcoded secrets or paths in your code
- **Flexible Caching**: Reduce API calls with configurable caching
- **Framework Agnostic**: Use with any Python framework or standalone scripts
- **Type Safe**: Full type hints for better development experience
- **Extensible**: Easy to add new storage backends

## Installation

```bash
# Basic installation
pip install python-prompt-manager

# With OpenAI support
pip install python-prompt-manager[openai]

# With all optional dependencies
pip install python-prompt-manager[all]
```

## Quick Start

### Basic Usage

```python
from prompt_manager import get_prompt

# Get a prompt (reads from configured source)
prompt = get_prompt("welcome_message")
print(prompt)
```

### With Variables

```python
# Use template variables in your prompts
prompt = get_prompt(
    "greeting", 
    variables={"name": "Alice", "day": "Monday"}
)
# "Hello Alice! Happy Monday!"
```

## Configuration

Configure your prompts using a simple Python dictionary:

```python
PROMPT_CONFIG = {
    "prompts": {
        "welcome": {
            "source": "openai",
            "id": "pmpt_1234567890",
            "version": "1.0"
        },
        "greeting": {
            "source": "local",
            "path": "greeting.txt"
        },
        "analysis": {
            "source": "openai",
            "id": "pmpt_0987654321",
            "cache_ttl": 300  # 5 minutes
        }
    },
    "sources": {
        "openai": {
            "api_key": os.getenv("OPENAI_API_KEY"),  # Keep secrets in env vars
            "timeout": 30,
            "max_retries": 3
        },
        "local": {
            "base_dir": "./prompts"
        }
    }
}

# Initialize with your config
from prompt_manager import PromptManager
pm = PromptManager(PROMPT_CONFIG)
```

### Django Configuration

In your Django settings:

```python
# settings.py
PROMPT_MANAGER = {
    "prompts": {
        "welcome": {"source": "openai", "id": "pmpt_123"},
        "email_template": {"source": "local", "path": "emails/welcome.txt"}
    },
    "sources": {
        "openai": {
            "api_key": env("OPENAI_API_KEY")
        }
    }
}
```

## Usage Examples

### Simple Example

```python
from prompt_manager import PromptManager

# Initialize with config
pm = PromptManager({
    "prompts": {
        "welcome": {"source": "openai", "id": "pmpt_123"},
        "goodbye": {"source": "local", "path": "goodbye.txt"}
    }
})

# Get prompts
welcome = pm.get("welcome")
goodbye = pm.get("goodbye")
```

### With Default Fallback

```python
# Provide a default if prompt is not found
prompt = pm.get("optional_prompt", default="This is a fallback prompt")
```

### Dynamic Configuration

```python
# Load config from a file
import json

with open("prompts.json") as f:
    config = json.load(f)

pm = PromptManager(config)
```

### Template Variables

```python
# Configure a prompt with variables
config = {
    "prompts": {
        "greeting": {"source": "local", "path": "greeting.txt"}
    }
}

pm = PromptManager(config)

# Apply variables when retrieving
prompt = pm.get(
    "greeting",
    variables={"name": "Alice", "app_name": "AwesomeApp"}
)
# "Hello Alice! Welcome to AwesomeApp."
```

## Django Integration

Add your prompt configuration to settings:

```python
# settings.py
PROMPT_MANAGER = {
    "prompts": {
        "welcome_email": {"source": "openai", "id": "pmpt_email_123"},
        "user_greeting": {"source": "local", "path": "templates/greeting.txt"},
        "error_message": {"source": "openai", "id": "pmpt_error_456"}
    },
    "sources": {
        "openai": {"api_key": env("OPENAI_API_KEY")}
    }
}

# Optional: Add the Django app for additional features
INSTALLED_APPS = [
    ...
    'prompt_manager.integrations.django',  # Optional
]
```

Use in your views:

```python
# views.py
from django.conf import settings
from prompt_manager import PromptManager

# Initialize once
pm = PromptManager(settings.PROMPT_MANAGER)

def my_view(request):
    prompt = pm.get("welcome_email", variables={"user": request.user.name})
    # Use prompt with your LLM
    ...
```

## Validation

By default, prompts are validated when first accessed. To validate all prompts on startup:

```python
config = {
    "prompts": {...},
    "validate_on_startup": True  # Validate all prompts exist
}

pm = PromptManager(config)
```

## Advanced Usage

### Error Handling

```python
from prompt_manager import PromptManager, PromptNotFoundError

pm = PromptManager(config)

try:
    prompt = pm.get("my_prompt")
except PromptNotFoundError:
    # Handle missing prompt
    logger.error("Prompt not found")
except Exception as e:
    # Handle other errors
    logger.error(f"Error loading prompt: {e}")
```

### Caching

```python
# Configure cache TTL per prompt
config = {
    "prompts": {
        "static_prompt": {"source": "local", "path": "static.txt"},  # Uses default cache
        "dynamic_prompt": {"source": "openai", "id": "pmpt_123", "cache_ttl": 0}  # No cache
    },
    "cache_ttl": 3600  # Default 1 hour
}

# Clear cache manually
pm.clear_cache()
```

### Custom Sources

Extend the base class to add new sources:

```python
from prompt_manager.sources.base import BasePromptSource

class DatabaseSource(BasePromptSource):
    def fetch(self, config):
        # Your implementation
        return prompt_content
```

## Best Practices

1. **Keep Secrets in Environment Variables**: API keys should never be in code
2. **Use Clear Naming**: Choose descriptive names for your prompts
3. **Set Appropriate Cache TTLs**: Static prompts can cache longer than dynamic ones
4. **Handle Errors Gracefully**: Always provide fallbacks for critical prompts
5. **Version Your Prompts**: Use the version field to track prompt iterations

## Development

```bash
# Clone the repository
git clone https://github.com/yourusername/python-prompt-manager.git
cd python-prompt-manager

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest

# Run linting
black src tests
flake8 src tests
mypy src
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Acknowledgments

- Built for the modern LLM application stack
- Designed with production use in mind
