smart_prompt 0.1.7 → 0.1.8
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/lib/smart_prompt/conversation.rb +52 -6
- data/lib/smart_prompt/engine.rb +9 -0
- data/lib/smart_prompt/ollama_adapter.rb +28 -13
- data/lib/smart_prompt/openai_adapter.rb +29 -17
- data/lib/smart_prompt/version.rb +1 -1
- data/lib/smart_prompt.rb +1 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab0d62158bbd98af9d2f57d9708426cceb95c2d3b2797abc0094de3caf96adf8
|
4
|
+
data.tar.gz: d2a50c4ede575eb70caeda1893b60412b04afdec665690b8fd2d4d0f3bdd410e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d61c7f8db100a715b16a8bd08ef27bf49f3e38127d68cb37a5fc55c3d5ee781e505d8c4acbc6ac98206bd2aeb22bcdd4dc6d749ed65293fecb5abbc361ffac9
|
7
|
+
data.tar.gz: 7f8ff17971d9979a95400bb1e4497737fab2c503d69a1c415a0003ff514400b55ade390d0f007a146e43569978b98e29f5e308091d74e25cd8b405689b73b136
|
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'retriable'
|
3
|
+
require "numo/narray"
|
2
4
|
|
3
5
|
module SmartPrompt
|
4
6
|
class Conversation
|
7
|
+
include APIHandler
|
5
8
|
attr_reader :messages, :last_response, :config_file
|
6
9
|
|
7
10
|
def initialize(engine)
|
@@ -26,12 +29,17 @@ module SmartPrompt
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def prompt(template_name, params = {})
|
29
|
-
template_name
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
if template_name.class == Symbol
|
33
|
+
template_name = template_name.to_s
|
34
|
+
SmartPrompt.logger.info "Use template #{template_name}"
|
35
|
+
raise "Template #{template_name} not found" unless @templates.key?(template_name)
|
36
|
+
content = @templates[template_name].render(params)
|
37
|
+
@messages << { role: 'user', content: content }
|
38
|
+
self
|
39
|
+
else
|
40
|
+
@messages << { role: 'user', content: template_name }
|
41
|
+
self
|
42
|
+
end
|
35
43
|
end
|
36
44
|
|
37
45
|
def sys_msg(message)
|
@@ -47,5 +55,43 @@ module SmartPrompt
|
|
47
55
|
@messages << { role: 'system', content: @sys_msg }
|
48
56
|
@last_response
|
49
57
|
end
|
58
|
+
|
59
|
+
def safe_send_msg
|
60
|
+
Retriable.retriable(RETRY_OPTIONS) do
|
61
|
+
raise ConfigurationError, "No LLM selected" if @current_llm.nil?
|
62
|
+
@last_response = @current_llm.send_request(@messages, @model_name)
|
63
|
+
@messages=[]
|
64
|
+
@messages << { role: 'system', content: @sys_msg }
|
65
|
+
@last_response
|
66
|
+
end
|
67
|
+
rescue => e
|
68
|
+
return "Failed to call LLM after #{MAX_RETRIES} attempts: #{e.message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def normalize(x, length)
|
72
|
+
if x.length > length
|
73
|
+
x = Numo::NArray.cast(x[0..length-1])
|
74
|
+
norm = Math.sqrt((x * x).sum)
|
75
|
+
return (x / norm).to_a
|
76
|
+
else
|
77
|
+
return x.concat([0] * (x.length - length))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def embeddings(length)
|
82
|
+
Retriable.retriable(RETRY_OPTIONS) do
|
83
|
+
raise ConfigurationError, "No LLM selected" if @current_llm.nil?
|
84
|
+
text = ""
|
85
|
+
@messages.each do |msg|
|
86
|
+
if msg[:role]=="user"
|
87
|
+
text = msg[:content]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
@last_response = @current_llm.embeddings(text, @model_name)
|
91
|
+
@messages=[]
|
92
|
+
@messages << { role: 'system', content: @sys_msg }
|
93
|
+
normalize(@last_response, length)
|
94
|
+
end
|
95
|
+
end
|
50
96
|
end
|
51
97
|
end
|
data/lib/smart_prompt/engine.rb
CHANGED
@@ -51,6 +51,15 @@ module SmartPrompt
|
|
51
51
|
require(file)
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
def check_worker(worker_name)
|
56
|
+
if SmartPrompt::Worker.workers[worker_name]
|
57
|
+
return true
|
58
|
+
else
|
59
|
+
SmartPrompt.logger.warn "Invalid worker: #{worker_name}"
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
end
|
54
63
|
|
55
64
|
def call_worker(worker_name, params = {})
|
56
65
|
SmartPrompt.logger.info "Calling worker: #{worker_name} with params: #{params}"
|
@@ -6,7 +6,7 @@ module SmartPrompt
|
|
6
6
|
super
|
7
7
|
begin
|
8
8
|
@client = Ollama.new(credentials: { address: @config['url'] })
|
9
|
-
rescue Ollama::
|
9
|
+
rescue Ollama::Errors => e
|
10
10
|
SmartPrompt.logger.error "Failed to initialize Ollama client: #{e.message}"
|
11
11
|
raise LLMAPIError, "Invalid Ollama configuration: #{e.message}"
|
12
12
|
rescue SocketError => e
|
@@ -36,18 +36,9 @@ module SmartPrompt
|
|
36
36
|
stream: false
|
37
37
|
}
|
38
38
|
)
|
39
|
-
rescue Ollama::
|
39
|
+
rescue Ollama::Errors => e
|
40
40
|
SmartPrompt.logger.error "Ollama API error: #{e.message}"
|
41
|
-
raise LLMAPIError, "Ollama API error: #{e.message}"
|
42
|
-
rescue Ollama::ConnectionError => e
|
43
|
-
SmartPrompt.logger.error "Connection error: Unable to reach Ollama API"
|
44
|
-
raise LLMAPIError, "Connection error: Unable to reach Ollama API"
|
45
|
-
rescue Ollama::TimeoutError => e
|
46
|
-
SmartPrompt.logger.error "Request to Ollama API timed out"
|
47
|
-
raise LLMAPIError, "Request to Ollama API timed out"
|
48
|
-
rescue Ollama::InvalidRequestError => e
|
49
|
-
SmartPrompt.logger.error "Invalid request to Ollama API: #{e.message}"
|
50
|
-
raise LLMAPIError, "Invalid request to Ollama API: #{e.message}"
|
41
|
+
raise LLMAPIError, "Ollama API error: #{e.message}"
|
51
42
|
rescue JSON::ParserError => e
|
52
43
|
SmartPrompt.logger.error "Failed to parse Ollama API response"
|
53
44
|
raise LLMAPIError, "Failed to parse Ollama API response"
|
@@ -58,7 +49,31 @@ module SmartPrompt
|
|
58
49
|
SmartPrompt.logger.info "Successful send a message"
|
59
50
|
end
|
60
51
|
SmartPrompt.logger.info "OllamaAdapter: Received response from Ollama"
|
61
|
-
return response
|
52
|
+
return response.dig(0,"response")
|
53
|
+
end
|
54
|
+
|
55
|
+
def embeddings(text, model)
|
56
|
+
SmartPrompt.logger.info "OllamaAdapter: get embeddings from Ollama"
|
57
|
+
if model
|
58
|
+
model_name = model
|
59
|
+
else
|
60
|
+
model_name = @config['model']
|
61
|
+
end
|
62
|
+
SmartPrompt.logger.info "OllamaAdapter: Using model #{model_name}"
|
63
|
+
begin
|
64
|
+
response = @client.embeddings(
|
65
|
+
{
|
66
|
+
model: model_name,
|
67
|
+
prompt: text.to_s
|
68
|
+
}
|
69
|
+
)
|
70
|
+
rescue => e
|
71
|
+
SmartPrompt.logger.error "Unexpected error during Ollama request: #{e.message}"
|
72
|
+
raise Error, "Unexpected error during Ollama request: #{e.message}"
|
73
|
+
ensure
|
74
|
+
SmartPrompt.logger.info "Successful send a message"
|
75
|
+
end
|
76
|
+
return response.dig(0,"embedding")
|
62
77
|
end
|
63
78
|
end
|
64
79
|
end
|
@@ -17,7 +17,7 @@ module SmartPrompt
|
|
17
17
|
rescue OpenAI::ConfigurationError => e
|
18
18
|
SmartPrompt.logger.error "Failed to initialize OpenAI client: #{e.message}"
|
19
19
|
raise LLMAPIError, "Invalid OpenAI configuration: #{e.message}"
|
20
|
-
rescue OpenAI::
|
20
|
+
rescue OpenAI::Error => e
|
21
21
|
SmartPrompt.logger.error "Failed to initialize OpenAI client: #{e.message}"
|
22
22
|
raise LLMAPIError, "OpenAI authentication failed: #{e.message}"
|
23
23
|
rescue SocketError => e
|
@@ -47,24 +47,12 @@ module SmartPrompt
|
|
47
47
|
temperature: @config['temperature'] || 0.7
|
48
48
|
}
|
49
49
|
)
|
50
|
-
rescue OpenAI::
|
50
|
+
rescue OpenAI::Error => e
|
51
51
|
SmartPrompt.logger.error "OpenAI API error: #{e.message}"
|
52
52
|
raise LLMAPIError, "OpenAI API error: #{e.message}"
|
53
|
-
rescue OpenAI::
|
54
|
-
SmartPrompt.logger.error "
|
55
|
-
raise LLMAPIError, "
|
56
|
-
rescue OpenAI::APITimeoutError => e
|
57
|
-
SmartPrompt.logger.error "Request to OpenAI API timed out"
|
58
|
-
raise LLMAPIError, "Request to OpenAI API timed out"
|
59
|
-
rescue OpenAI::InvalidRequestError => e
|
60
|
-
SmartPrompt.logger.error "Invalid request to OpenAI API: #{e.message}"
|
61
|
-
raise LLMAPIError, "Invalid request to OpenAI API: #{e.message}"
|
62
|
-
rescue OpenAI::AuthenticationError => e
|
63
|
-
SmartPrompt.logger.error "Authentication error with OpenAI API: #{e.message}"
|
64
|
-
raise LLMAPIError, "Authentication error with OpenAI API: #{e.message}"
|
65
|
-
rescue OpenAI::RateLimitError => e
|
66
|
-
SmartPrompt.logger.error "Rate limit exceeded for OpenAI API"
|
67
|
-
raise LLMAPIError, "Rate limit exceeded for OpenAI API"
|
53
|
+
rescue OpenAI::MiddlewareErrors => e
|
54
|
+
SmartPrompt.logger.error "OpenAI HTTP Error: #{e.message}"
|
55
|
+
raise LLMAPIError, "OpenAI HTTP Error"
|
68
56
|
rescue JSON::ParserError => e
|
69
57
|
SmartPrompt.logger.error "Failed to parse OpenAI API response"
|
70
58
|
raise LLMAPIError, "Failed to parse OpenAI API response"
|
@@ -77,5 +65,29 @@ module SmartPrompt
|
|
77
65
|
SmartPrompt.logger.info "OpenAIAdapter: Received response from OpenAI"
|
78
66
|
response.dig("choices", 0, "message", "content")
|
79
67
|
end
|
68
|
+
|
69
|
+
def embeddings(text, model)
|
70
|
+
SmartPrompt.logger.info "OpenAIAdapter: get embeddings from Ollama"
|
71
|
+
if model
|
72
|
+
model_name = model
|
73
|
+
else
|
74
|
+
model_name = @config['model']
|
75
|
+
end
|
76
|
+
SmartPrompt.logger.info "OpenAIAdapter: Using model #{model_name}"
|
77
|
+
begin
|
78
|
+
response = @client.embeddings(
|
79
|
+
parameters: {
|
80
|
+
model: model_name,
|
81
|
+
input: text.to_s
|
82
|
+
}
|
83
|
+
)
|
84
|
+
rescue => e
|
85
|
+
SmartPrompt.logger.error "Unexpected error during Ollama request: #{e.message}"
|
86
|
+
raise Error, "Unexpected error during Ollama request: #{e.message}"
|
87
|
+
ensure
|
88
|
+
SmartPrompt.logger.info "Successful send a message"
|
89
|
+
end
|
90
|
+
return response.dig("data", 0, "embedding")
|
91
|
+
end
|
80
92
|
end
|
81
93
|
end
|
data/lib/smart_prompt/version.rb
CHANGED
data/lib/smart_prompt.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.expand_path('../smart_prompt/version', __FILE__)
|
2
2
|
require File.expand_path('../smart_prompt/engine', __FILE__)
|
3
|
+
require File.expand_path('../smart_prompt/api_handler', __FILE__)
|
3
4
|
require File.expand_path('../smart_prompt/conversation', __FILE__)
|
4
5
|
require File.expand_path('../smart_prompt/llm_adapter', __FILE__)
|
5
6
|
require File.expand_path('../smart_prompt/openai_adapter', __FILE__)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_prompt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zhuang biaowei
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yaml
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.0.4
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: retriable
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 3.1.2
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 3.1.2
|
83
97
|
description: SmartPrompt provides a flexible DSL for managing prompts, interacting
|
84
98
|
with multiple LLMs, and creating composable task workers.
|
85
99
|
email:
|
@@ -125,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
139
|
- !ruby/object:Gem::Version
|
126
140
|
version: '0'
|
127
141
|
requirements: []
|
128
|
-
rubygems_version: 3.5.
|
142
|
+
rubygems_version: 3.5.23
|
129
143
|
signing_key:
|
130
144
|
specification_version: 4
|
131
145
|
summary: A smart prompt management and LLM interaction gem
|