promptly 0.1.7 → 0.1.17
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 -428
- 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/helper.rb +19 -0
- data/lib/promptly/railtie.rb +15 -0
- data/lib/promptly/renderer.rb +6 -0
- data/lib/promptly/tasks/ai_prompts.rake +123 -0
- data/lib/promptly/validator.rb +24 -0
- data/lib/promptly/version.rb +1 -1
- data/lib/promptly.rb +79 -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 +35 -5
- data/promptly.gemspec +0 -46
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
|
+
```
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
## Rails App Integration
|
|
2
|
+
|
|
3
|
+
### Service Object Pattern
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
# app/services/ai_prompt_service.rb
|
|
7
|
+
class AiPromptService
|
|
8
|
+
def self.generate_welcome_email(user, locale: I18n.locale)
|
|
9
|
+
prompt = Promptly.render(
|
|
10
|
+
"user_onboarding/welcome_email",
|
|
11
|
+
locale: locale,
|
|
12
|
+
locals: {
|
|
13
|
+
name: user.full_name,
|
|
14
|
+
app_name: Rails.application.class.module_parent_name,
|
|
15
|
+
user_role: user.role.humanize,
|
|
16
|
+
features: available_features_for(user),
|
|
17
|
+
days_since_signup: (Date.current - user.created_at.to_date).to_i
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Send to AI service and return generated content
|
|
22
|
+
openai_client.chat(
|
|
23
|
+
model: "gpt-4",
|
|
24
|
+
messages: [{role: "user", content: prompt}]
|
|
25
|
+
).dig("choices", 0, "message", "content")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def self.available_features_for(user)
|
|
31
|
+
# Return features based on user's plan, role, etc.
|
|
32
|
+
case user.plan
|
|
33
|
+
when "basic"
|
|
34
|
+
["Create projects", "Basic reporting"]
|
|
35
|
+
when "pro"
|
|
36
|
+
["Create projects", "Team collaboration", "Advanced analytics", "API access"]
|
|
37
|
+
else
|
|
38
|
+
["Create projects"]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.openai_client
|
|
43
|
+
@openai_client ||= OpenAI::Client.new(access_token: Rails.application.credentials.openai_api_key)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Mailer Integration
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
# app/mailers/user_mailer.rb
|
|
52
|
+
class UserMailer < ApplicationMailer
|
|
53
|
+
def welcome_email(user)
|
|
54
|
+
@user = user
|
|
55
|
+
@ai_content = AiPromptService.generate_welcome_email(user, locale: user.locale)
|
|
56
|
+
|
|
57
|
+
mail(
|
|
58
|
+
to: user.email,
|
|
59
|
+
subject: t('mailer.welcome.subject')
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Background Job Usage
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
# app/jobs/generate_ai_content_job.rb
|
|
69
|
+
class GenerateAiContentJob < ApplicationJob
|
|
70
|
+
def perform(user_id, prompt_identifier, locals = {})
|
|
71
|
+
user = User.find(user_id)
|
|
72
|
+
|
|
73
|
+
prompt = Promptly.render(
|
|
74
|
+
prompt_identifier,
|
|
75
|
+
locale: user.locale,
|
|
76
|
+
locals: locals.merge(
|
|
77
|
+
user_name: user.full_name,
|
|
78
|
+
user_role: user.role,
|
|
79
|
+
account_type: user.account_type
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Generate AI content
|
|
84
|
+
ai_response = openai_client.chat(
|
|
85
|
+
model: "gpt-4",
|
|
86
|
+
messages: [{role: "user", content: prompt}]
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
generated_content = ai_response.dig("choices", 0, "message", "content")
|
|
90
|
+
|
|
91
|
+
# Store or send the generated content
|
|
92
|
+
user.notifications.create!(
|
|
93
|
+
title: "AI Generated Content Ready",
|
|
94
|
+
content: generated_content,
|
|
95
|
+
notification_type: prompt_identifier.split('/').last
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def openai_client
|
|
102
|
+
@openai_client ||= OpenAI::Client.new(access_token: Rails.application.credentials.openai_api_key)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Usage
|
|
107
|
+
GenerateAiContentJob.perform_later(
|
|
108
|
+
user.id,
|
|
109
|
+
"coaching/goal_review",
|
|
110
|
+
{
|
|
111
|
+
current_goals: user.goals.active.pluck(:title),
|
|
112
|
+
progress_summary: "Made good progress on fitness goals",
|
|
113
|
+
challenges: ["Time management", "Consistency"]
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## Schema Validation
|
|
2
|
+
|
|
3
|
+
Ensure all locals passed to templates match a defined schema, so missing or mistyped variables fail fast before sending to AI.
|
|
4
|
+
|
|
5
|
+
### Schema File Next to Prompt
|
|
6
|
+
|
|
7
|
+
For each prompt, create a `schema.yml` (or `.json`) file alongside the template.
|
|
8
|
+
|
|
9
|
+
**Example:**
|
|
10
|
+
|
|
11
|
+
`app/prompts/user_onboarding/welcome_email.schema.yml`
|
|
12
|
+
|
|
13
|
+
```yml
|
|
14
|
+
name: string
|
|
15
|
+
app_name: string
|
|
16
|
+
user_role: string
|
|
17
|
+
features: array
|
|
18
|
+
days_since_signup: integer
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Validation Layer in Promptly
|
|
22
|
+
|
|
23
|
+
The validation is automatically triggered when you call `Promptly.render`. It will check for missing keys and (optionally) value types.
|
|
24
|
+
|
|
25
|
+
Supported types: `string`, `integer`, `array`.
|
|
26
|
+
|
|
27
|
+
If the validation fails, it will raise an `ArgumentError` for missing keys or a `TypeError` for mismatched types.
|
data/wiki/_Sidebar.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
- [Home](https://github.com/wilburhimself/promptly/wiki)
|
|
2
|
+
- [Quick Start](https://github.com/wilburhimself/promptly/wiki/Quick-Start)
|
|
3
|
+
- [Schema Validation](https://github.com/wilburhimself/promptly/wiki/Schema-Validation)
|
|
4
|
+
- [Helper: render_prompt](https://github.com/wilburhimself/promptly/wiki/Helper-render_prompt)
|
|
5
|
+
- [Rails App Integration](https://github.com/wilburhimself/promptly/wiki/Rails-App-Integration)
|
|
6
|
+
- [I18n Prompts Usage](https://github.com/wilburhimself/promptly/wiki/I18n-Prompts-Usage)
|
|
7
|
+
- [Liquid Templates](https://github.com/wilburhimself/promptly/wiki/Liquid-Templates)
|
|
8
|
+
- [Configuration](https://github.com/wilburhimself/promptly/wiki/Configuration)
|
|
9
|
+
- [Generators](https://github.com/wilburhimself/promptly/wiki/Generators)
|
|
10
|
+
- [Linting Templates](https://github.com/wilburhimself/promptly/wiki/Linting-Templates)
|
|
11
|
+
- [Functional Prompt Tests](https://github.com/wilburhimself/promptly/wiki/Functional-Prompt-Tests)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: promptly
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.17
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Wilbur Suero
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: actionview
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '7.2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: json_schemer
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.3'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.3'
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: rspec
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -83,7 +97,7 @@ dependencies:
|
|
|
83
97
|
description: Build maintainable, localized, and testable AI prompts using ERB or Liquid
|
|
84
98
|
templates with Rails conventions
|
|
85
99
|
email:
|
|
86
|
-
-
|
|
100
|
+
- suerowilbur@gmail.com
|
|
87
101
|
executables: []
|
|
88
102
|
extensions: []
|
|
89
103
|
extra_rdoc_files: []
|
|
@@ -94,15 +108,31 @@ files:
|
|
|
94
108
|
- LICENSE
|
|
95
109
|
- README.md
|
|
96
110
|
- Rakefile
|
|
111
|
+
- app/prompts/test/prompt.en.erb
|
|
112
|
+
- app/prompts/test/prompt_with_metadata.en.erb
|
|
97
113
|
- lib/generators/promptly/prompt_generator.rb
|
|
98
114
|
- lib/promptly.rb
|
|
99
115
|
- lib/promptly/cache.rb
|
|
116
|
+
- lib/promptly/helper.rb
|
|
100
117
|
- lib/promptly/locator.rb
|
|
101
118
|
- lib/promptly/railtie.rb
|
|
102
119
|
- lib/promptly/renderer.rb
|
|
103
120
|
- lib/promptly/tasks/ai_prompts.rake
|
|
121
|
+
- lib/promptly/validator.rb
|
|
104
122
|
- lib/promptly/version.rb
|
|
105
|
-
-
|
|
123
|
+
- wiki/Configuration.md
|
|
124
|
+
- wiki/Functional-Prompt-Tests.md
|
|
125
|
+
- wiki/Generators.md
|
|
126
|
+
- wiki/Helper-render_prompt.md
|
|
127
|
+
- wiki/Home.md
|
|
128
|
+
- wiki/I18n-Prompts-Usage.md
|
|
129
|
+
- wiki/Linting-Templates.md
|
|
130
|
+
- wiki/Liquid-Templates.md
|
|
131
|
+
- wiki/Prompt-Version-Metadata.md
|
|
132
|
+
- wiki/Quick-Start.md
|
|
133
|
+
- wiki/Rails-App-Integration.md
|
|
134
|
+
- wiki/Schema-Validation.md
|
|
135
|
+
- wiki/_Sidebar.md
|
|
106
136
|
homepage: https://github.com/wilburhimself/promptly
|
|
107
137
|
licenses:
|
|
108
138
|
- MIT
|
|
@@ -120,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
120
150
|
requirements:
|
|
121
151
|
- - ">="
|
|
122
152
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: '3.
|
|
153
|
+
version: '3.2'
|
|
124
154
|
- - "<"
|
|
125
155
|
- !ruby/object:Gem::Version
|
|
126
156
|
version: '3.4'
|
data/promptly.gemspec
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/promptly/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "promptly"
|
|
7
|
-
spec.version = Promptly::VERSION
|
|
8
|
-
spec.authors = ["Wilbur Suero"]
|
|
9
|
-
spec.email = ["wilbur@example.com"]
|
|
10
|
-
|
|
11
|
-
spec.summary = "Opinionated Rails integration for reusable AI prompt templates"
|
|
12
|
-
spec.description = "Build maintainable, localized, and testable AI prompts using ERB or Liquid templates with Rails conventions"
|
|
13
|
-
spec.homepage = "https://github.com/wilburhimself/promptly"
|
|
14
|
-
spec.license = "MIT"
|
|
15
|
-
spec.required_ruby_version = ">= 3.3", "< 3.4"
|
|
16
|
-
|
|
17
|
-
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
18
|
-
|
|
19
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
20
|
-
spec.metadata["source_code_uri"] = "https://github.com/wilburhimself/promptly"
|
|
21
|
-
spec.metadata["changelog_uri"] = "https://github.com/wilburhimself/promptly/blob/main/CHANGELOG.md"
|
|
22
|
-
spec.metadata["documentation_uri"] = "https://github.com/wilburhimself/promptly/blob/main/README.md"
|
|
23
|
-
|
|
24
|
-
# Specify which files should be added to the gem when it is released.
|
|
25
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
26
|
-
gemfiles = Dir.chdir(__dir__) do
|
|
27
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
28
|
-
(File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
spec.files = gemfiles
|
|
32
|
-
|
|
33
|
-
spec.bindir = "exe"
|
|
34
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
35
|
-
spec.require_paths = ["lib"]
|
|
36
|
-
|
|
37
|
-
# Runtime dependencies (single target: Rails 7.2.x)
|
|
38
|
-
spec.add_dependency "actionview", "~> 7.2"
|
|
39
|
-
|
|
40
|
-
# Development dependencies
|
|
41
|
-
spec.add_development_dependency "rspec", "~> 3.12"
|
|
42
|
-
spec.add_development_dependency "standard", "~> 1.37"
|
|
43
|
-
spec.add_development_dependency "liquid", "~> 5.5"
|
|
44
|
-
# Development dependencies
|
|
45
|
-
spec.add_development_dependency "railties", "~> 7.2"
|
|
46
|
-
end
|