Class: Boxcars::Conversation
- Inherits:
-
Object
- Object
- Boxcars::Conversation
- Defined in:
- lib/boxcars/conversation.rb
Overview
used to keep track of the conversation
Constant Summary collapse
- PEOPLE =
%i[system user assistant history].freeze
Instance Attribute Summary collapse
-
#lines ⇒ Object
readonly
Returns the value of attribute lines.
Instance Method Summary collapse
-
#add_assistant(text) ⇒ Object
add assistant text to the conversation at the end.
-
#add_conversation(conversation) ⇒ Object
add a conversation to the conversation.
-
#add_history(conversation) ⇒ Object
insert converation above history line if it is present.
-
#add_lines(lines) ⇒ Object
add multiple lines to the conversation.
-
#add_system(text) ⇒ Object
add system text to the conversation at the end.
-
#add_user(text) ⇒ Object
add user text to the conversation at the end.
-
#as_messages(inputs = nil) ⇒ Hash
compute the prompt parameters with input substitutions (used for chatGPT).
-
#as_prompt(inputs: nil, prefixes: default_prefixes, show_roles: false) ⇒ Hash
compute the prompt parameters with input substitutions.
-
#cformat(*args) ⇒ Object
special format that replaces lone percent signs with double percent signs.
-
#check_lines(lines) ⇒ Object
check the lines.
- #default_prefixes ⇒ Object
-
#initialize(lines: []) ⇒ Conversation
constructor
A new instance of Conversation.
-
#message_text ⇒ Object
return just the messages for the conversation.
- #no_history ⇒ Object
- #process_content(content, inputs) ⇒ Object
-
#to_a ⇒ Array
The result as a convesation array.
-
#to_s ⇒ String
A conversation string.
Constructor Details
#initialize(lines: []) ⇒ Conversation
Returns a new instance of Conversation.
10 11 12 13 |
# File 'lib/boxcars/conversation.rb', line 10 def initialize(lines: []) @lines = lines check_lines(@lines) end |
Instance Attribute Details
#lines ⇒ Object (readonly)
Returns the value of attribute lines.
6 7 8 |
# File 'lib/boxcars/conversation.rb', line 6 def lines @lines end |
Instance Method Details
#add_assistant(text) ⇒ Object
add assistant text to the conversation at the end
38 39 40 |
# File 'lib/boxcars/conversation.rb', line 38 def add_assistant(text) @lines << [:assistant, text] end |
#add_conversation(conversation) ⇒ Object
add a conversation to the conversation
61 62 63 |
# File 'lib/boxcars/conversation.rb', line 61 def add_conversation(conversation) @lines += conversation.lines end |
#add_history(conversation) ⇒ Object
insert converation above history line if it is present
67 68 69 70 71 72 73 74 75 76 |
# File 'lib/boxcars/conversation.rb', line 67 def add_history(conversation) # find the history line hi = lines.rindex { |ln| ln[0] == :history } return unless hi @lines = @lines.dup # insert the conversation above the history line @lines.insert(hi, *conversation.lines) end |
#add_lines(lines) ⇒ Object
add multiple lines to the conversation
55 56 57 58 |
# File 'lib/boxcars/conversation.rb', line 55 def add_lines(lines) check_lines(lines) @lines += lines end |
#add_system(text) ⇒ Object
add system text to the conversation at the end
50 51 52 |
# File 'lib/boxcars/conversation.rb', line 50 def add_system(text) @lines << [:system, text] end |
#add_user(text) ⇒ Object
add user text to the conversation at the end
44 45 46 |
# File 'lib/boxcars/conversation.rb', line 44 def add_user(text) @lines << [:user, text] end |
#as_messages(inputs = nil) ⇒ Hash
compute the prompt parameters with input substitutions (used for chatGPT)
90 91 92 93 94 95 96 |
# File 'lib/boxcars/conversation.rb', line 90 def (inputs = nil) { messages: no_history.map { |ln| { role: ln.first, content: cformat(ln.last, inputs) } } } rescue ::KeyError => e first_line = e..to_s.split("\n").first Boxcars.error "Missing prompt input key: #{first_line}" raise KeyError, "Prompt format error: #{first_line}" end |
#as_prompt(inputs: nil, prefixes: default_prefixes, show_roles: false) ⇒ Hash
compute the prompt parameters with input substitutions
101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/boxcars/conversation.rb', line 101 def as_prompt(inputs: nil, prefixes: default_prefixes, show_roles: false) if show_roles lines = no_history.map { |ln| [prefixes[ln[0]], ln[1]] } lines.map { |ln| cformat("#{ln.first}#{ln.last}", inputs) }.compact.join("\n\n") else no_history.map { |ln| cformat(ln.last, inputs) }.compact.join("\n\n") end rescue ::KeyError => e first_line = e..to_s.split("\n").first Boxcars.error "Missing prompt input key: #{first_line}" raise KeyError, "Prompt format error: #{first_line}" end |
#cformat(*args) ⇒ Object
special format that replaces lone percent signs with double percent signs
133 134 135 136 |
# File 'lib/boxcars/conversation.rb', line 133 def cformat(*args) args[0] = args[0].dup.gsub(/%(?!<)/, '%%') if args.length > 1 format(*args) end |
#check_lines(lines) ⇒ Object
check the lines
16 17 18 19 20 21 22 23 24 |
# File 'lib/boxcars/conversation.rb', line 16 def check_lines(lines) raise ArgumentError, "Lines must be an array" unless lines.is_a?(Array) lines.each do |ln| raise ArgumentError, "Conversation item must be a array" unless ln.is_a?(Array) raise ArgumentError, "Conversation item must have 2 items, role and text" unless ln.size == 2 raise ArgumentError, "Conversation item must have a role #{ln} in (#{PEOPLE})" unless PEOPLE.include? ln[0] end end |
#default_prefixes ⇒ Object
138 139 140 |
# File 'lib/boxcars/conversation.rb', line 138 def default_prefixes { system: 'System: ', user: 'User: ', assistant: 'Assistant: ', history: :history } end |
#message_text ⇒ Object
return just the messages for the conversation
83 84 85 |
# File 'lib/boxcars/conversation.rb', line 83 def lines.map(&:last).join("\n") end |
#no_history ⇒ Object
78 79 80 |
# File 'lib/boxcars/conversation.rb', line 78 def no_history @lines.reject { |ln| ln[0] == :history } end |
#process_content(content, inputs) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/boxcars/conversation.rb', line 114 def process_content(content, inputs) # If content is a string, treat it as text if content.is_a?(String) [{ type: "text", text: cformat(content, inputs) }] # If content is an array, assume it's already in the new format elsif content.is_a?(Array) content.map do |item| if item[:type] == "text" { type: "text", text: cformat(item[:text], inputs) } else item # Pass through non-text items (like images) without modification end end else raise ArgumentError, "Invalid content type: #{content.class}" end end |
#to_a ⇒ Array
Returns The result as a convesation array.
27 28 29 |
# File 'lib/boxcars/conversation.rb', line 27 def to_a lines end |
#to_s ⇒ String
Returns A conversation string.
32 33 34 |
# File 'lib/boxcars/conversation.rb', line 32 def to_s lines.map { |ln| "#{ln[0]}: #{ln[1]}" }.join("\n") end |