1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
# frozen_string_literal: true
require 'openai'
require_relative './base'
require_relative '../crypto'
module NanoBot
module Components
module Providers
class OpenAI < Base
CHAT_SETTINGS = %i[
model stream temperature top_p n stop max_tokens
presence_penalty frequency_penalty logit_bias
].freeze
attr_reader :settings
def initialize(settings, environment: {})
@settings = settings
@environment = environment
@client = ::OpenAI::Client.new(
uri_base: "#{@settings[:credentials][:address].sub(%r{/$}, '')}/",
access_token: @settings[:credentials][:'access-token']
)
end
def stream(input)
provider = @settings.key?(:stream) ? @settings[:stream] : true
interface = input[:interface].key?(:stream) ? input[:interface][:stream] : true
provider && interface
end
def evaluate(input, &block)
messages = input[:history].map do |event|
{ role: event[:who] == 'user' ? 'user' : 'assistant',
content: event[:message] }
end
%i[instruction backdrop directive].each do |key|
next unless input[:behavior][key]
messages.prepend(
{ role: key == :directive ? 'system' : 'user',
content: input[:behavior][key] }
)
end
user = @settings[:credentials][:'user-identifier']
user_suffix = @environment && (
@environment['NANO_BOTS_USER_IDENTIFIER'] ||
@environment[:NANO_BOTS_USER_IDENTIFIER]
)
user = "#{user}/#{user_suffix}" if user_suffix && user_suffix != ''
payload = { model: @settings[:model], user: Crypto.encrypt(user, soft: true), messages: }
CHAT_SETTINGS.each do |key|
payload[key] = @settings[key] if @settings.key?(key)
end
payload.delete(:logit_bias) if payload.key?(:logit_bias) && payload[:logit_bias].nil?
if stream(input)
content = ''
payload[:stream] = proc do |chunk, _bytesize|
partial = chunk.dig('choices', 0, 'delta', 'content')
if partial
content += partial
block.call({ who: 'AI', message: partial }, false)
end
block.call({ who: 'AI', message: content }, true) if chunk.dig('choices', 0, 'finish_reason')
end
@client.chat(parameters: payload)
else
result = @client.chat(parameters: payload)
raise StandardError, result['error'] if result['error']
block.call({ who: 'AI', message: result.dig('choices', 0, 'message', 'content') }, true)
end
end
end
end
end
end
|