promptly 0.1.13 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +24 -493
- data/Rakefile +1 -0
- data/app/prompts/test/prompt.en.erb +1 -0
- data/app/prompts/test/prompt_with_metadata.en.erb +6 -0
- data/lib/promptly/tasks/ai_prompts.rake +9 -4
- data/lib/promptly/validator.rb +24 -0
- data/lib/promptly/version.rb +1 -1
- data/lib/promptly.rb +78 -2
- data/wiki/Configuration.md +63 -0
- data/wiki/Functional-Prompt-Tests.md +36 -0
- data/wiki/Generators.md +32 -0
- data/wiki/Helper-render_prompt.md +25 -0
- data/wiki/Home.md +29 -0
- data/wiki/I18n-Prompts-Usage.md +60 -0
- data/wiki/Linting-Templates.md +38 -0
- data/wiki/Liquid-Templates.md +49 -0
- data/wiki/Prompt-Version-Metadata.md +34 -0
- data/wiki/Quick-Start.md +116 -0
- data/wiki/Rails-App-Integration.md +116 -0
- data/wiki/Schema-Validation.md +27 -0
- data/wiki/_Sidebar.md +11 -0
- metadata +49 -7
data/lib/promptly.rb
CHANGED
|
@@ -5,14 +5,68 @@ require_relative "promptly/renderer"
|
|
|
5
5
|
require_relative "promptly/locator"
|
|
6
6
|
require_relative "promptly/cache"
|
|
7
7
|
require_relative "promptly/helper"
|
|
8
|
+
require_relative "promptly/validator"
|
|
9
|
+
require "yaml"
|
|
8
10
|
|
|
9
11
|
module Promptly
|
|
10
12
|
class Error < StandardError; end
|
|
13
|
+
class ValidationError < Error; end
|
|
14
|
+
|
|
15
|
+
class Prompt
|
|
16
|
+
attr_reader :content, :version, :author, :change_notes
|
|
17
|
+
|
|
18
|
+
def initialize(content:, version: nil, author: nil, change_notes: nil)
|
|
19
|
+
@content = content
|
|
20
|
+
@version = version
|
|
21
|
+
@author = author
|
|
22
|
+
@change_notes = change_notes
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s
|
|
26
|
+
content
|
|
27
|
+
end
|
|
28
|
+
end
|
|
11
29
|
|
|
12
30
|
def self.render_template(template, locals: {}, engine: :erb)
|
|
13
31
|
Renderer.render(template, locals: locals, engine: engine)
|
|
14
32
|
end
|
|
15
33
|
|
|
34
|
+
def self.response_format(identifier, strict: true)
|
|
35
|
+
schema_path = File.join(prompts_path, "#{identifier}.response.json")
|
|
36
|
+
raise Error, "Schema file not found for '#{identifier}' at #{schema_path}" unless File.exist?(schema_path)
|
|
37
|
+
|
|
38
|
+
require "json"
|
|
39
|
+
schema_content = JSON.parse(File.read(schema_path))
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
type: "json_schema",
|
|
43
|
+
json_schema: {
|
|
44
|
+
name: identifier.gsub(/[^a-zA-Z0-9_-]/, "_"),
|
|
45
|
+
strict: strict,
|
|
46
|
+
schema: schema_content
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.validate_response!(identifier, json_string)
|
|
52
|
+
schema_path = File.join(prompts_path, "#{identifier}.response.json")
|
|
53
|
+
raise Error, "Schema file not found for '#{identifier}' at #{schema_path}" unless File.exist?(schema_path)
|
|
54
|
+
|
|
55
|
+
require "json"
|
|
56
|
+
require "json_schemer"
|
|
57
|
+
|
|
58
|
+
schema_content = JSON.parse(File.read(schema_path))
|
|
59
|
+
parsed_json = JSON.parse(json_string)
|
|
60
|
+
|
|
61
|
+
schemer = JSONSchemer.schema(schema_content)
|
|
62
|
+
unless schemer.valid?(parsed_json)
|
|
63
|
+
errors = schemer.validate(parsed_json).to_a
|
|
64
|
+
raise ValidationError, "Response does not match schema: #{errors.inspect}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
parsed_json
|
|
68
|
+
end
|
|
69
|
+
|
|
16
70
|
# Configurable prompts root (defaults to Rails.root/app/prompts when Rails is present)
|
|
17
71
|
def self.prompts_path
|
|
18
72
|
@prompts_path || default_prompts_path
|
|
@@ -43,12 +97,34 @@ module Promptly
|
|
|
43
97
|
end
|
|
44
98
|
|
|
45
99
|
private_class_method def self.render_without_cache(identifier, locale: nil, locals: {})
|
|
100
|
+
schema_path = File.join(prompts_path, "#{identifier}.schema.yml")
|
|
101
|
+
Validator.validate!(locals, schema_path)
|
|
102
|
+
|
|
46
103
|
path = Locator.resolve(identifier, locale: locale)
|
|
47
104
|
raise Error, "Template not found for '#{identifier}' (locale: #{locale.inspect}) under #{prompts_path}" unless path
|
|
48
105
|
|
|
49
106
|
engine = Locator.engine_for(path)
|
|
50
|
-
|
|
51
|
-
|
|
107
|
+
file_content = File.read(path)
|
|
108
|
+
|
|
109
|
+
# Extract YAML front matter
|
|
110
|
+
match = file_content.match(/\A---\n(.*)
|
|
111
|
+
---\s*\n/m)
|
|
112
|
+
if match
|
|
113
|
+
metadata = YAML.safe_load(match[1])
|
|
114
|
+
template = match.post_match
|
|
115
|
+
else
|
|
116
|
+
metadata = {}
|
|
117
|
+
template = file_content
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
content = Renderer.render(template, locals: locals, engine: engine)
|
|
121
|
+
|
|
122
|
+
Prompt.new(
|
|
123
|
+
content: content,
|
|
124
|
+
version: metadata["version"],
|
|
125
|
+
author: metadata["author"],
|
|
126
|
+
change_notes: metadata["change_notes"]
|
|
127
|
+
)
|
|
52
128
|
end
|
|
53
129
|
|
|
54
130
|
def self.default_prompts_path
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
## Configuration
|
|
2
|
+
|
|
3
|
+
### Custom Prompts Path
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
# config/initializers/rails_ai_prompts.rb
|
|
7
|
+
Promptly.prompts_path = Rails.root.join("lib", "ai_prompts")
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
### Caching
|
|
11
|
+
|
|
12
|
+
Promptly supports optional caching for rendered prompts.
|
|
13
|
+
|
|
14
|
+
- Default: enabled, TTL = 3600 seconds (1 hour).
|
|
15
|
+
- In Rails, the Railtie auto-uses `Rails.cache` if present.
|
|
16
|
+
|
|
17
|
+
Configure globally:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
# config/initializers/promptly.rb
|
|
21
|
+
Promptly::Cache.configure do |c|
|
|
22
|
+
c.store = Rails.cache # or any ActiveSupport::Cache store
|
|
23
|
+
c.ttl = 3600 # default TTL in seconds
|
|
24
|
+
c.enabled = true # globally enable/disable caching
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Per-call options:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
# Bypass cache for this render only
|
|
32
|
+
Promptly.render("user_onboarding/welcome_email", locals: {...}, cache: false)
|
|
33
|
+
|
|
34
|
+
# Custom TTL for this render only
|
|
35
|
+
Promptly.render("user_onboarding/welcome_email", locals: {...}, ttl: 5.minutes)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Invalidation:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# Clear entire cache store (if supported by the store)
|
|
42
|
+
Promptly::Cache.clear
|
|
43
|
+
|
|
44
|
+
# Delete a specific cached entry
|
|
45
|
+
Promptly::Cache.delete(
|
|
46
|
+
identifier: "user_onboarding/welcome_email",
|
|
47
|
+
locale: :en,
|
|
48
|
+
locals: {name: "John"},
|
|
49
|
+
prompts_path: Promptly.prompts_path
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Direct Template Rendering
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# Render ERB directly (without file lookup)
|
|
57
|
+
template = "Hello <%= name %>, welcome to <%= app %>!"
|
|
58
|
+
output = Promptly.render_template(template, locals: {name: "John", app: "MyApp"})
|
|
59
|
+
|
|
60
|
+
# Render Liquid directly
|
|
61
|
+
template = "Hello {{ name }}, welcome to {{ app }}!"
|
|
62
|
+
output = Promptly.render_template(template, locals: {name: "John", app: "MyApp"}, engine: :liquid)
|
|
63
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## Functional Prompt Tests
|
|
2
|
+
|
|
3
|
+
Promptly provides an RSpec helper to write functional tests for your prompts. This allows you to verify the rendered output of your prompts, ensuring that they are correctly formatted and that all variables are properly interpolated.
|
|
4
|
+
|
|
5
|
+
### RSpec Helper
|
|
6
|
+
|
|
7
|
+
The `expect_prompt_render` helper is available in your RSpec tests. It takes the prompt identifier and a hash of locals as arguments.
|
|
8
|
+
|
|
9
|
+
**Example:**
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
# spec/prompts/user_onboarding/welcome_email_spec.rb
|
|
13
|
+
require "spec_helper"
|
|
14
|
+
|
|
15
|
+
RSpec.describe "user_onboarding/welcome_email" do
|
|
16
|
+
it "renders the welcome email correctly" do
|
|
17
|
+
locals = {
|
|
18
|
+
name: "John Doe",
|
|
19
|
+
app_name: "My App",
|
|
20
|
+
user_role: "Admin",
|
|
21
|
+
features: ["Feature 1", "Feature 2"],
|
|
22
|
+
days_since_signup: 5
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
expect(Promptly.render("user_onboarding/welcome_email", locals: locals)).to include("Hello John Doe")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Rake Task
|
|
31
|
+
|
|
32
|
+
You can run all your prompt tests using the `ai_prompts:test_prompts` Rake task.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
rake ai_prompts:test_prompts
|
|
36
|
+
```
|
data/wiki/Generators.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
## Generators
|
|
2
|
+
|
|
3
|
+
Create prompt templates following conventions.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# ERB with multiple locales
|
|
7
|
+
rails g promptly:prompt user_onboarding/welcome_email --locales en es --engine erb
|
|
8
|
+
|
|
9
|
+
# Liquid with a single locale
|
|
10
|
+
rails g promptly:prompt ai_coaching/goal_review --locales en --engine liquid
|
|
11
|
+
|
|
12
|
+
# Fallback-only (no locale suffix)
|
|
13
|
+
rails g promptly:prompt content_generation/outline --no-locale
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
|
|
18
|
+
- `--engine` erb|liquid (default: erb)
|
|
19
|
+
- `--locales` space-separated list (default: I18n.available_locales if available, else `en`)
|
|
20
|
+
- `--no-locale` create only fallback file (e.g., `welcome_email.erb`)
|
|
21
|
+
- `--force` overwrite existing files
|
|
22
|
+
|
|
23
|
+
Generated files are placed under `app/prompts/` and directories are created as needed.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
|
|
27
|
+
- `app/prompts/user_onboarding/welcome_email.en.erb`
|
|
28
|
+
- `app/prompts/user_onboarding/welcome_email.es.erb`
|
|
29
|
+
- `app/prompts/ai_coaching/goal_review.en.liquid`
|
|
30
|
+
- `app/prompts/content_generation/outline.erb` (fallback-only)
|
|
31
|
+
|
|
32
|
+
The generator seeds a minimal, intention-revealing scaffold you can edit immediately.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## Helper: render_prompt
|
|
2
|
+
|
|
3
|
+
Use a concise helper anywhere in Rails to render prompts with locals that are also exposed as instance variables inside ERB templates.
|
|
4
|
+
|
|
5
|
+
* **Auto-included**: Controllers, Mailers, and Jobs via Railtie.
|
|
6
|
+
* **Services/Plain Ruby**: `include Promptly::Helper`.
|
|
7
|
+
|
|
8
|
+
Example template and usage:
|
|
9
|
+
|
|
10
|
+
```erb
|
|
11
|
+
# app/prompts/welcome_email.erb
|
|
12
|
+
Hello <%= @user.name %>, welcome to our service!
|
|
13
|
+
We're excited to have you join.
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
# In a mailer, job, controller, or a service that includes Promptly::Helper
|
|
18
|
+
rendered = render_prompt("welcome_email", user: @user)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Notes:
|
|
22
|
+
|
|
23
|
+
- **Locals become @instance variables** in ERB. Passing `user: @user` makes `@user` available in the template.
|
|
24
|
+
- **Localization**: `render_prompt("welcome_email", locale: :es, user: user)` resolves `welcome_email.es.erb` with fallback per `Promptly::Locator`.
|
|
25
|
+
- **Caching**: Controlled per call (`cache:`, `ttl:`) and globally via `Promptly::Cache`.
|
data/wiki/Home.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Welcome to the Promptly Wiki!
|
|
2
|
+
|
|
3
|
+
Promptly is an opinionated Rails integration for reusable AI prompt templates. It helps you build maintainable, localized, and testable AI prompts using ERB or Liquid templates with Rails conventions.
|
|
4
|
+
|
|
5
|
+
This wiki provides detailed documentation for Promptly. If you are new to Promptly, we recommend starting with the [Quick Start](https://github.com/wilburhimself/promptly/wiki/Quick-Start) guide.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Template rendering**: ERB (via ActionView) and optional Liquid support
|
|
10
|
+
- **I18n integration**: Automatic locale fallback (`welcome.es.erb` → `welcome.en.erb` → `welcome.erb`)
|
|
11
|
+
- **Rails conventions**: Store prompts in `app/prompts/` with organized subdirectories
|
|
12
|
+
- **Render & CLI**: Test prompts in Rails console or via rake tasks
|
|
13
|
+
- **Minimal setup**: Auto-loads via Railtie, zero configuration required
|
|
14
|
+
- **Prompt caching**: Configurable cache store, TTL, and cache-bypass options
|
|
15
|
+
- **Schema Validation**: Ensure all locals passed to templates match a defined schema.
|
|
16
|
+
- **Functional Prompt Tests**: Write functional tests for your prompts using RSpec.
|
|
17
|
+
|
|
18
|
+
## Documentation
|
|
19
|
+
|
|
20
|
+
- [Quick Start](https://github.com/wilburhimself/promptly/wiki/Quick-Start)
|
|
21
|
+
- [Schema Validation](https://github.com/wilburhimself/promptly/wiki/Schema-Validation)
|
|
22
|
+
- [Helper: render_prompt](https://github.com/wilburhimself/promptly/wiki/Helper-render_prompt)
|
|
23
|
+
- [Rails App Integration](https://github.com/wilburhimself/promptly/wiki/Rails-App-Integration)
|
|
24
|
+
- [I18n Prompts Usage](https://github.com/wilburhimself/promptly/wiki/I18n-Prompts-Usage)
|
|
25
|
+
- [Liquid Templates](https://github.com/wilburhimself/promptly/wiki/Liquid-Templates)
|
|
26
|
+
- [Configuration](https://github.com/wilburhimself/promptly/wiki/Configuration)
|
|
27
|
+
- [Generators](https://github.com/wilburhimself/promptly/wiki/Generators)
|
|
28
|
+
- [Linting Templates](https://github.com/wilburhimself/promptly/wiki/Linting-Templates)
|
|
29
|
+
- [Functional Prompt Tests](https://github.com/wilburhimself/promptly/wiki/Functional-Prompt-Tests)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
## I18n Prompts Usage
|
|
2
|
+
|
|
3
|
+
### Directory Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
app/prompts/
|
|
7
|
+
├── user_onboarding/
|
|
8
|
+
│ ├── welcome_email.en.erb # English AI prompt
|
|
9
|
+
│ ├── welcome_email.es.erb # Spanish AI prompt
|
|
10
|
+
│ └── onboarding_checklist.erb # Fallback (any locale)
|
|
11
|
+
├── content_generation/
|
|
12
|
+
│ ├── blog_post_outline.en.erb
|
|
13
|
+
│ ├── social_media_post.es.erb
|
|
14
|
+
│ └── product_description.erb
|
|
15
|
+
└── ai_coaching/
|
|
16
|
+
├── goal_review.en.liquid # Liquid AI prompt
|
|
17
|
+
└── goal_review.es.liquid
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Locale Resolution
|
|
21
|
+
|
|
22
|
+
Promptly follows this resolution order:
|
|
23
|
+
|
|
24
|
+
1. **Requested locale**: `welcome.es.erb` (if `locale: :es` specified)
|
|
25
|
+
2. **Default locale**: `welcome.en.erb` (if `I18n.default_locale == :en`)
|
|
26
|
+
3. **Fallback**: `welcome.erb` (no locale suffix)
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
# Configure I18n in your Rails app
|
|
30
|
+
# config/application.rb
|
|
31
|
+
config.i18n.default_locale = :en
|
|
32
|
+
config.i18n.available_locales = [:en, :es, :fr]
|
|
33
|
+
|
|
34
|
+
# Usage examples
|
|
35
|
+
I18n.locale = :es
|
|
36
|
+
I18n.default_locale = :en
|
|
37
|
+
|
|
38
|
+
# Will try: welcome_email.es.erb → welcome_email.en.erb → welcome_email.erb
|
|
39
|
+
prompt = Promptly.render(
|
|
40
|
+
"user_onboarding/welcome_email",
|
|
41
|
+
locals: {
|
|
42
|
+
name: "María García",
|
|
43
|
+
app_name: "ProjectHub",
|
|
44
|
+
user_role: "Manager",
|
|
45
|
+
features: ["Team management", "Analytics", "Reporting"],
|
|
46
|
+
days_since_signup: 1
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Force specific locale for AI prompt generation
|
|
51
|
+
prompt = Promptly.render(
|
|
52
|
+
"content_generation/blog_post_outline",
|
|
53
|
+
locale: :fr,
|
|
54
|
+
locals: {
|
|
55
|
+
topic: "Intelligence Artificielle",
|
|
56
|
+
target_audience: "Développeurs",
|
|
57
|
+
word_count: 1500
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
## Linting Templates
|
|
2
|
+
|
|
3
|
+
Validate your prompt templates from the CLI.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Lint all templates under the prompts path
|
|
7
|
+
rake ai_prompts:lint
|
|
8
|
+
|
|
9
|
+
# Lint a specific identifier (path without locale/ext)
|
|
10
|
+
rake ai_prompts:lint[user_onboarding/welcome_email]
|
|
11
|
+
|
|
12
|
+
# Specify locales to check for coverage
|
|
13
|
+
LOCALES=en,es rake ai_prompts:lint
|
|
14
|
+
|
|
15
|
+
# Require placeholders to exist in templates
|
|
16
|
+
REQUIRED=name,app_name rake ai_prompts:lint[user_onboarding/welcome_email]
|
|
17
|
+
|
|
18
|
+
# Point to a custom prompts directory
|
|
19
|
+
PROMPTS_PATH=lib/ai_prompts rake ai_prompts:lint
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
What it checks:
|
|
23
|
+
|
|
24
|
+
- **Syntax errors**
|
|
25
|
+
- ERB: compiles with `ERB.new` (no execution)
|
|
26
|
+
- Liquid: parses with `Liquid::Template.parse` (if `liquid` gem present)
|
|
27
|
+
- **Missing locale files**
|
|
28
|
+
- For each identifier, warns when required locales are missing
|
|
29
|
+
- Locales source: `LOCALES` env or `I18n.available_locales`
|
|
30
|
+
- **Required placeholders**
|
|
31
|
+
- Best-effort scan for required keys from `REQUIRED` env
|
|
32
|
+
- ERB: looks for `<%= ... @key ... %>` or `<%= ... key ... %>` usage
|
|
33
|
+
- Liquid: looks for `{{ key }}` usage
|
|
34
|
+
|
|
35
|
+
Exit codes:
|
|
36
|
+
|
|
37
|
+
- `0` when all checks pass
|
|
38
|
+
- `1` when errors are found (syntax or missing required placeholders)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
### Liquid Templates
|
|
2
|
+
|
|
3
|
+
For more complex templating needs, use Liquid:
|
|
4
|
+
|
|
5
|
+
```liquid
|
|
6
|
+
<!-- app/prompts/ai_coaching/goal_review.en.liquid -->
|
|
7
|
+
You are an experienced life coach conducting a goal review session.
|
|
8
|
+
|
|
9
|
+
Context:
|
|
10
|
+
- Client name: {{ user_name }}
|
|
11
|
+
- Goals being reviewed: {% for goal in current_goals %}{{ goal }}{% unless forloop.last %}, {% endunless %}{% endfor %}
|
|
12
|
+
- Recent progress: {{ progress_summary }}
|
|
13
|
+
- Current challenges: {% for challenge in challenges %}{{ challenge }}{% unless forloop.last %}, {% endunless %}{% endfor %}
|
|
14
|
+
- Review period: {{ review_period | default: "monthly" }}
|
|
15
|
+
|
|
16
|
+
Task: Provide a personalized goal review that:
|
|
17
|
+
1. Acknowledges their progress and celebrates wins
|
|
18
|
+
2. Addresses each challenge with specific, actionable advice
|
|
19
|
+
3. Suggests 2-3 concrete next steps for the coming {{ review_period }}
|
|
20
|
+
4. Asks 1-2 thoughtful questions to help them reflect
|
|
21
|
+
5. Maintains an encouraging but realistic tone
|
|
22
|
+
|
|
23
|
+
{% if current_goals.size > 5 %}
|
|
24
|
+
Note: The client has many goals. Help them prioritize the most important ones.
|
|
25
|
+
{% endif %}
|
|
26
|
+
|
|
27
|
+
Format your response as a conversational coaching session, not a formal report.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
# Generate AI coaching content with Liquid template
|
|
32
|
+
prompt = Promptly.render(
|
|
33
|
+
"ai_coaching/goal_review",
|
|
34
|
+
locale: :en,
|
|
35
|
+
locals: {
|
|
36
|
+
user_name: "Alex",
|
|
37
|
+
current_goals: ["Run 5K under 25min", "Gym 3x/week", "Read 12 books/year"],
|
|
38
|
+
progress_summary: "Consistent with gym, behind on running pace, ahead on reading",
|
|
39
|
+
challenges: ["Time management", "Motivation on rainy days"],
|
|
40
|
+
review_period: "monthly"
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Send to AI service for personalized coaching
|
|
45
|
+
ai_coaching_session = openai_client.chat(
|
|
46
|
+
model: "gpt-4",
|
|
47
|
+
messages: [{role: "user", content: prompt}]
|
|
48
|
+
).dig("choices", 0, "message", "content")
|
|
49
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
## Prompt Version Metadata
|
|
2
|
+
|
|
3
|
+
Promptly allows you to add optional metadata fields to your prompt templates, such as `version`, `author`, and `change_notes`. This metadata can be useful for tracking changes to your prompts and for documentation purposes.
|
|
4
|
+
|
|
5
|
+
### Adding Metadata to Prompts
|
|
6
|
+
|
|
7
|
+
To add metadata to a prompt, include a YAML front matter block at the beginning of your template file. The front matter block must start and end with `---`.
|
|
8
|
+
|
|
9
|
+
**Example:**
|
|
10
|
+
|
|
11
|
+
```erb
|
|
12
|
+
---
|
|
13
|
+
version: 1.0
|
|
14
|
+
author: John Doe
|
|
15
|
+
change_notes: Initial version of the welcome email.
|
|
16
|
+
---
|
|
17
|
+
You are a friendly customer success manager writing a personalized welcome email.
|
|
18
|
+
...
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Accessing Metadata
|
|
22
|
+
|
|
23
|
+
When you render a prompt, the `Promptly.render` method returns a `Prompt` object. This object contains the rendered content of the prompt, as well as the metadata fields.
|
|
24
|
+
|
|
25
|
+
**Example:**
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
prompt = Promptly.render("user_onboarding/welcome_email")
|
|
29
|
+
|
|
30
|
+
puts prompt.content # The rendered content of the email
|
|
31
|
+
puts prompt.version # 1.0
|
|
32
|
+
puts prompt.author # John Doe
|
|
33
|
+
puts prompt.change_notes # Initial version of the welcome email.
|
|
34
|
+
```
|
data/wiki/Quick-Start.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
## Quick Start
|
|
2
|
+
|
|
3
|
+
### 1. Create prompt templates
|
|
4
|
+
|
|
5
|
+
Create `app/prompts/user_onboarding/welcome_email.en.erb`:
|
|
6
|
+
|
|
7
|
+
```erb
|
|
8
|
+
You are a friendly customer success manager writing a personalized welcome email.
|
|
9
|
+
|
|
10
|
+
Context:
|
|
11
|
+
- User name: <%= name %>
|
|
12
|
+
- App name: <%= app_name %>
|
|
13
|
+
- User's role: <%= user_role %>
|
|
14
|
+
- Available features for this user: <%= features.join(", ") %>
|
|
15
|
+
- User signed up <%= days_since_signup %> days ago
|
|
16
|
+
|
|
17
|
+
Task: Write a warm, personalized welcome email that:
|
|
18
|
+
1. Addresses the user by name
|
|
19
|
+
2. Explains the key benefits specific to their role
|
|
20
|
+
3. Highlights 2-3 most relevant features they should try first
|
|
21
|
+
4. Includes a clear call-to-action to get started
|
|
22
|
+
5. Maintains a professional but friendly tone
|
|
23
|
+
|
|
24
|
+
Keep the email concise (under 200 words) and actionable.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Create `app/prompts/user_onboarding/welcome_email.es.erb`:
|
|
28
|
+
|
|
29
|
+
```erb
|
|
30
|
+
Eres un gerente de éxito del cliente amigable escribiendo un email de bienvenida personalizado.
|
|
31
|
+
|
|
32
|
+
Contexto:
|
|
33
|
+
- Nombre del usuario: <%= name %>
|
|
34
|
+
- Nombre de la app: <%= app_name %>
|
|
35
|
+
- Rol del usuario: <%= user_role %>
|
|
36
|
+
- Funciones disponibles para este usuario: <%= features.join(", ") %>
|
|
37
|
+
- El usuario se registró hace <%= days_since_signup %> días
|
|
38
|
+
|
|
39
|
+
Tarea: Escribe un email de bienvenida cálido y personalizado que:
|
|
40
|
+
1. Se dirija al usuario por su nombre
|
|
41
|
+
2. Explique los beneficios clave específicos para su rol
|
|
42
|
+
3. Destaque 2-3 funciones más relevantes que debería probar primero
|
|
43
|
+
4. Incluya una llamada a la acción clara para comenzar
|
|
44
|
+
5. Mantenga un tono profesional pero amigable
|
|
45
|
+
|
|
46
|
+
Mantén el email conciso (menos de 200 palabras) y orientado a la acción.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Render in your Rails app
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
# In a controller, service, or anywhere in Rails
|
|
53
|
+
prompt = Promptly.render(
|
|
54
|
+
"user_onboarding/welcome_email",
|
|
55
|
+
locale: :es,
|
|
56
|
+
locals: {
|
|
57
|
+
name: "María García",
|
|
58
|
+
app_name: "ProjectHub",
|
|
59
|
+
user_role: "Team Lead",
|
|
60
|
+
features: ["Create projects", "Invite team members", "Track progress", "Generate reports"],
|
|
61
|
+
days_since_signup: 2
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Send to your AI service (OpenAI, Anthropic, etc.)
|
|
66
|
+
ai_response = openai_client.completions(
|
|
67
|
+
model: "gpt-4",
|
|
68
|
+
messages: [{role: "user", content: prompt}]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
puts ai_response.dig("choices", 0, "message", "content")
|
|
72
|
+
# => AI-generated personalized welcome email in Spanish
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Test via Rails console
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
rails console
|
|
79
|
+
|
|
80
|
+
# Render the prompt before sending to AI
|
|
81
|
+
prompt = Promptly.render(
|
|
82
|
+
"user_onboarding/welcome_email",
|
|
83
|
+
locale: :en,
|
|
84
|
+
locals: {
|
|
85
|
+
name: "John Smith",
|
|
86
|
+
app_name: "ProjectHub",
|
|
87
|
+
user_role: "Developer",
|
|
88
|
+
features: ["API access", "Code reviews", "Deployment tools"],
|
|
89
|
+
days_since_signup: 1
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
puts prompt
|
|
93
|
+
|
|
94
|
+
# Uses I18n.locale by default
|
|
95
|
+
I18n.locale = :es
|
|
96
|
+
prompt = Promptly.render(
|
|
97
|
+
"user_onboarding/welcome_email",
|
|
98
|
+
locals: {
|
|
99
|
+
name: "María García",
|
|
100
|
+
app_name: "ProjectHub",
|
|
101
|
+
user_role: "Team Lead",
|
|
102
|
+
features: ["Crear proyectos", "Invitar miembros", "Seguimiento"],
|
|
103
|
+
days_since_signup: 3
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 4. CLI rendering
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Render specific locale (shows the prompt, not AI output)
|
|
112
|
+
rails ai_prompts:render[user_onboarding/welcome_email,es]
|
|
113
|
+
|
|
114
|
+
# Uses default locale
|
|
115
|
+
rails ai_prompts:render[user_onboarding/welcome_email]
|
|
116
|
+
```
|