prompt_manager 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c96927dad3be1d7e793e3edd5d3df3e3a12999fcec57ad01d3d773d9b40e674
4
- data.tar.gz: 4aa47ce704540fa933dbdf30d3afddbb3704bd541b4dab1f7a751e0e461f3c1e
3
+ metadata.gz: 6785a25ba5b2c7e8bacf3bdba572eced1c95bdab2f83144a4ec32f0ae359eeb1
4
+ data.tar.gz: fd21f559d660899ec94765b7ef3f3fd6a4579ac625a44af428ab7771ba934713
5
5
  SHA512:
6
- metadata.gz: '0857d6d0532c0c1293799e760933e5bf2ee1a82f8cfdce6dd649b187f724e31935bf959b04c8058a90877525751cf99deaa4fd51a9cc64d0259a3d4b1e40de38'
7
- data.tar.gz: 59d2e1cabed3a87766092f56eae6ed7e7d30a2c0d0b3e3dc2efd93fe9ce79d97ce7ee5af3d1beae6896aed3a1754649dc7a7f3bbdec1e0566015640d8f7f2128
6
+ metadata.gz: 4373edc2de2e838a606ab748a81a73bc15242f9bac45343ce5d89fa2cd13fd57b228bf1f34e1a870e31640ff7f957382d44b65bcf0fa7360d004b95854965dae
7
+ data.tar.gz: e1b04a1643de8de6a24618d5e2737241b17580922436bf6f3fa73e9caf394f9122426721eb3a44b37f227bd2eba21b0e20fad150a2b98265d707be033a7c4887
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] = 2023-11-28
4
+
5
+ - **Breaking change** The value of the parameters Hash for a keyword is now an Array instead of a single value. The last value in the Array is always the most recent value used for the given keyword. This was done to support the use of a Readline::History object editing in the [aia](https://github.com/MadBomber/aia) CLI tool
6
+
3
7
  ## [0.2.0] - 2023-11-21
4
8
 
5
9
  - **Breaking change to FileSystemAdapter config process**
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  Manage the parameterized prompts (text) used in generative AI (aka chatGPT, OpenAI, _et.al._) using storage adapters such as FileSystemAdapter, SqliteAdapter and ActiveRecordAdapter.
4
4
 
5
- **Breaking Change** in version 0.2.0 for `FileSystemAdapter` configuration. See [Configuration](#configuration) to see how the new `config` block works.
5
+ **Breaking Change** in version 0.3.0 - The value of the parameters Hash for a keyword is now an Array instead of a single value. The last value in the Array is always the most recent value used for the given keyword. This was done to support the use of a Readline::History object editing in the [aia](https://github.com/MadBomber/aia) CLI tool
6
+
6
7
 
7
8
  <!-- Tocer[start]: Auto-generated, don't remove. -->
8
9
 
@@ -19,6 +20,8 @@ Manage the parameterized prompts (text) used in generative AI (aka chatGPT, Open
19
20
  - [prompts_dir](#prompts_dir)
20
21
  - [search_proc](#search_proc)
21
22
  - [File Extensions](#file-extensions)
23
+ - [Example Prompt Text File](#example-prompt-text-file)
24
+ - [Example Prompt Parameters JSON File](#example-prompt-parameters-json-file)
22
25
  - [Extra Functionality](#extra-functionality)
23
26
  - [SqliteAdapter](#sqliteadapter)
24
27
  - [ActiveRecordAdapter](#activerecordadapter)
@@ -118,6 +121,36 @@ Currently the `FileSystemAdapter` only supports a JSON serializer for its parame
118
121
 
119
122
  They exist so that there is a platform on to which other storage adapters can be built or serializers added. This is not currently on the roadmap.
120
123
 
124
+ ##### Example Prompt Text File
125
+
126
+ ```text
127
+ # ~/.prompts/joke.txt
128
+ # Desc: Tell some jokes
129
+
130
+ Tell me a few [KIND] jokes about [SUBJECT]
131
+ ```
132
+
133
+ Note the command lines at the top. This is a convention I use. It is not part of the software. I find it helpful in documenting the prompt.
134
+
135
+ ##### Example Prompt Parameters JSON File
136
+
137
+ ```json
138
+ {
139
+ "[KIND]": [
140
+ "pun",
141
+ "family friendly"
142
+ ],
143
+ "[SUBJECT]": [
144
+ "parrot",
145
+ "garbage man",
146
+ "snowman",
147
+ "weather girl"
148
+ ]
149
+ }
150
+ ```
151
+
152
+ The last value in the keyword's Array is the most recent value used for that keyword. This is a functionality established since v0.3.0. Its purpose is to provide a history of values from which a user can select to repeat a previous value or to select ta previous value and edit it into something new.
153
+
121
154
  ##### Extra Functionality
122
155
 
123
156
  The `FileSystemAdapter` adds two new methods for use by the `Prompt` class:
@@ -108,7 +108,7 @@ class PromptManager::Prompt
108
108
  def build
109
109
  @prompt = text.gsub(PARAMETER_REGEX) do |match|
110
110
  param_name = match
111
- parameters[param_name] || match
111
+ parameters[param_name].last || match
112
112
  end
113
113
 
114
114
  remove_comments
@@ -120,7 +120,7 @@ class PromptManager::Prompt
120
120
  def update_keywords
121
121
  @keywords = @text.scan(PARAMETER_REGEX).flatten.uniq
122
122
  keywords.each do |kw|
123
- @parameters[kw] = "" unless @parameters.has_key?(kw)
123
+ @parameters[kw] = [] unless @parameters.has_key?(kw)
124
124
  end
125
125
  end
126
126
 
@@ -63,4 +63,99 @@ class PromptManager::Storage::ActiveRecordAdapter
63
63
  def find_prompt(prompt_id)
64
64
  model_class.find_by(id: prompt_id) || raise('Prompt not found')
65
65
  end
66
- end
66
+ end
67
+
68
+
69
+ __END__
70
+
71
+ # prompt_manager/lib/prompt_manager/storage/active_record_adapter.rb
72
+
73
+ require 'active_record'
74
+
75
+ module PromptManager
76
+ module Storage
77
+ class ActiveRecordAdapter
78
+
79
+ # Define models for ActiveRecord
80
+ class Prompt < ActiveRecord::Base
81
+ validates :unique_id, presence: true
82
+ validates :text, presence: true
83
+ end
84
+
85
+ class PromptParameter < ActiveRecord::Base
86
+ belongs_to :prompt
87
+ validates :key, presence: true
88
+ serialize :value
89
+ end
90
+
91
+ def initialize
92
+ unless ActiveRecord::Base.connected?
93
+ raise ArgumentError, "ActiveRecord is not connected"
94
+ end
95
+ end
96
+
97
+ def get(id:)
98
+ prompt = Prompt.find_by(unique_id: id)
99
+ return nil unless prompt
100
+
101
+ parameters = prompt.prompt_parameters.index_by(&:key)
102
+
103
+ {
104
+ id: prompt.unique_id,
105
+ text: prompt.text,
106
+ parameters: parameters.transform_values(&:value)
107
+ }
108
+ end
109
+
110
+ def save(id:, text: "", parameters: {})
111
+ prompt = Prompt.find_or_initialize_by(unique_id: id)
112
+ prompt.text = text
113
+ prompt.save!
114
+
115
+ parameters.each do |key, value|
116
+ parameter = PromptParameter.find_or_initialize_by(prompt: prompt, key: key)
117
+ parameter.value = value
118
+ parameter.save!
119
+ end
120
+ end
121
+
122
+ def delete(id:)
123
+ prompt = Prompt.find_by(unique_id: id)
124
+ return unless prompt
125
+
126
+ prompt.prompt_parameters.destroy_all
127
+ prompt.destroy
128
+ end
129
+
130
+ def search(for_what)
131
+ query = '%' + for_what.downcase + '%'
132
+ Prompt.where('LOWER(text) LIKE ?', query).pluck(:unique_id)
133
+ end
134
+
135
+ def list(*)
136
+ Prompt.pluck(:unique_id)
137
+ end
138
+
139
+ private
140
+
141
+ # This is an example of how the database connection setup could look like,
142
+ # but it should be handled externally in the actual application setup.
143
+ def self.setup_database_connection
144
+ ActiveRecord::Base.establish_connection(
145
+ adapter: 'sqlite3',
146
+ database: 'prompts.db'
147
+ )
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ # After this, you would need to create a database migration to generate the required tables.
154
+ # Additionally, you have to establish an ActiveRecord connection before using this adapter,
155
+ # typically in the environment setup of your application.
156
+
157
+ # Keep in mind you need to create migrations for both the Prompt and PromptParameter models,
158
+ # and manage the database schema using ActiveRecord migrations. This adapter assumes that the
159
+ # database structure is already in place and follows the schema inferred by the models in the adapter.
160
+
161
+
@@ -61,5 +61,96 @@ class PromptManager::Storage::SqliteAdapter
61
61
  end
62
62
 
63
63
 
64
+ __END__
65
+
66
+
67
+ require 'sequel'
68
+ require 'pathname'
69
+ require 'json'
70
+
71
+ module PromptManager
72
+ module Storage
73
+ class SqliteAdapter
74
+ DEFAULT_DB_FILE = 'prompts.sqlite3'.freeze
75
+
76
+ class << self
77
+ attr_accessor :db_file, :db
78
+
79
+ def config
80
+ if block_given?
81
+ yield self
82
+ else
83
+ raise ArgumentError, 'No block given to config'
84
+ end
85
+
86
+ self.db = Sequel.sqlite(db_file || DEFAULT_DB_FILE) # Use provided db_file or default
87
+ create_tables unless db.table_exists?(:prompts)
88
+ end
89
+
90
+ # Define the necessary tables within the SQLite database if they don't exist
91
+ def create_tables
92
+ db.create_table :prompts do
93
+ primary_key :id
94
+ String :prompt_id, unique: true, null: false
95
+ Text :text
96
+ Json :parameters
97
+
98
+ index :prompt_id
99
+ end
100
+ end
101
+ end
102
+
103
+ def initialize
104
+ @db = self.class.db
105
+ end
106
+
107
+ def get(id:)
108
+ validate_id(id)
109
+ result = @db[:prompts].where(prompt_id: id).first
110
+ raise ArgumentError, 'Prompt not found' unless result
111
+
112
+ {
113
+ id: result[:prompt_id],
114
+ text: result[:text],
115
+ parameters: result[:parameters]
116
+ }
117
+ end
118
+
119
+ def save(id:, text: '', parameters: {})
120
+ validate_id(id)
121
+ rec = @db[:prompts].where(prompt_id: id).first
122
+ if rec
123
+ @db[:prompts].where(prompt_id: id).update(text: text, parameters: Sequel.pg_json(parameters))
124
+ else
125
+ @db[:prompts].insert(prompt_id: id, text: text, parameters: Sequel.pg_json(parameters))
126
+ end
127
+ end
128
+
129
+ def delete(id:)
130
+ validate_id(id)
131
+ @db[:prompts].where(prompt_id: id).delete
132
+ end
133
+
134
+ # Return an Array of prompt IDs
135
+ def list()
136
+ @db[:prompts].select_map(:prompt_id)
137
+ end
138
+
139
+ def search(for_what)
140
+ search_term = for_what.downcase
141
+ @db[:prompts].where(Sequel.ilike(:text, "%#{search_term}%")).select_map(:prompt_id)
142
+ end
143
+
144
+ private
145
+
146
+ # Validate that the ID contains good characters.
147
+ def validate_id(id)
148
+ raise ArgumentError, "Invalid ID format id: #{id}" unless id =~ /^[a-zA-Z0-9\-\/_]+$/
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+
64
155
 
65
156
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PromptManager
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prompt_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-23 00:00:00.000000000 Z
11
+ date: 2023-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: amazing_print