slidict 0.4.0 → 0.4.2
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/.github/release-drafter.yml +1 -1
- data/lib/slidict/cli/app.rb +18 -1
- data/lib/slidict/cli/lint.rb +19 -2
- data/lib/slidict/config.rb +2 -2
- data/lib/slidict/lint/linter.rb +2 -2
- data/lib/slidict/llm/client.rb +23 -9
- data/lib/slidict/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 829a5806efaa7c29d773818f0683fa3c0525bebfe883bd32261ba29f5a649a5e
|
|
4
|
+
data.tar.gz: e45e42541ba0940a883f470f7d03941df71b5825c0c9b93471fe3b1c991b0de5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff04a4475b51083d1c8ed884ad10f924000bb6c47adb0947d6c365fa3dd81d83eb09b94b280794bed9d2ef1001b559589c9241d92b0ccc005a7969065a814eb1
|
|
7
|
+
data.tar.gz: a0385b86027802eb018c4c9bda5fc26ee8030df9eee449879bd5dc299faa32382df90e5b8c707b528c846018d1fa8f28b3861ce299ed8d58f7d5ad125bc29b15
|
data/.github/release-drafter.yml
CHANGED
data/lib/slidict/cli/app.rb
CHANGED
|
@@ -28,6 +28,8 @@ module Slidict
|
|
|
28
28
|
return lint(options[:args]) if options[:command] == "lint"
|
|
29
29
|
|
|
30
30
|
config = build_config(options)
|
|
31
|
+
return print_available_models(config) if config.llm_enabled? && config.model.nil?
|
|
32
|
+
|
|
31
33
|
client = llm_client_for(config)
|
|
32
34
|
return 1 if client && !verify_connection(client)
|
|
33
35
|
|
|
@@ -155,6 +157,21 @@ module Slidict
|
|
|
155
157
|
)
|
|
156
158
|
end
|
|
157
159
|
|
|
160
|
+
def print_available_models(config)
|
|
161
|
+
client = Llm::Client.new(base_url: config.base_url, api_key: config.api_key, model: nil)
|
|
162
|
+
models = client.list_models
|
|
163
|
+
if models.empty?
|
|
164
|
+
@output.puts "No models available at #{config.base_url}"
|
|
165
|
+
else
|
|
166
|
+
@output.puts "Available models (specify one with --llm-model NAME or SLIDICT_LLM_MODEL=NAME):"
|
|
167
|
+
models.each { |m| @output.puts " #{m}" }
|
|
168
|
+
end
|
|
169
|
+
0
|
|
170
|
+
rescue Llm::Client::Error => e
|
|
171
|
+
@output.puts "Error: LLM request failed (#{e.message})"
|
|
172
|
+
1
|
|
173
|
+
end
|
|
174
|
+
|
|
158
175
|
def llm_client_for(config)
|
|
159
176
|
return nil unless config.llm_enabled?
|
|
160
177
|
|
|
@@ -284,7 +301,7 @@ module Slidict
|
|
|
284
301
|
--llm-base-url URL OpenAI Compatible API base URL (env: SLIDICT_LLM_BASE_URL).
|
|
285
302
|
When omitted, the built-in slide template is used instead.
|
|
286
303
|
--llm-api-key KEY API key for the LLM endpoint (env: SLIDICT_LLM_API_KEY)
|
|
287
|
-
--llm-model NAME Model name to request (env: SLIDICT_LLM_MODEL
|
|
304
|
+
--llm-model NAME Model name to request (env: SLIDICT_LLM_MODEL); omit to list available models
|
|
288
305
|
--no-llm Skip the LLM call and use the built-in slide template
|
|
289
306
|
--publish Publish the generated slides to slidict.io as a draft
|
|
290
307
|
(requires `slidict auth`; creates a new slide, or edits
|
data/lib/slidict/cli/lint.rb
CHANGED
|
@@ -31,12 +31,13 @@ module Slidict
|
|
|
31
31
|
def run_lint(options)
|
|
32
32
|
config = build_config(options)
|
|
33
33
|
return llm_required unless config.llm_enabled?
|
|
34
|
+
return print_available_models(config) if config.model.nil?
|
|
34
35
|
|
|
35
36
|
print_findings(lint(options, config))
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
def lint(options, config)
|
|
39
|
-
@linter_factory.call(config).lint(File.read(options[:path]), format: format_for(options))
|
|
40
|
+
@linter_factory.call(config).lint(File.read(options[:path]), format: format_for(options), translate: options[:translate])
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
def print_usage_error(error)
|
|
@@ -70,6 +71,7 @@ module Slidict
|
|
|
70
71
|
when "--llm-base-url" then options[:llm_base_url] = fetch_value!(args, arg)
|
|
71
72
|
when "--llm-api-key" then options[:llm_api_key] = fetch_value!(args, arg)
|
|
72
73
|
when "--llm-model" then options[:llm_model] = fetch_value!(args, arg)
|
|
74
|
+
when "--translate" then options[:translate] = fetch_value!(args, arg)
|
|
73
75
|
else raise ArgumentError, "unknown option #{arg}"
|
|
74
76
|
end
|
|
75
77
|
end
|
|
@@ -111,6 +113,20 @@ module Slidict
|
|
|
111
113
|
1
|
|
112
114
|
end
|
|
113
115
|
|
|
116
|
+
def print_available_models(config)
|
|
117
|
+
client = Llm::Client.new(base_url: config.base_url, api_key: config.api_key, model: nil)
|
|
118
|
+
models = client.list_models
|
|
119
|
+
if models.empty?
|
|
120
|
+
@output.puts "No models available at #{config.base_url}"
|
|
121
|
+
else
|
|
122
|
+
@output.puts "Available models (specify one with --llm-model NAME or SLIDICT_LLM_MODEL=NAME):"
|
|
123
|
+
models.each { |m| @output.puts " #{m}" }
|
|
124
|
+
end
|
|
125
|
+
0
|
|
126
|
+
rescue Llm::Client::Error => e
|
|
127
|
+
print_error(e)
|
|
128
|
+
end
|
|
129
|
+
|
|
114
130
|
def llm_required
|
|
115
131
|
@output.puts "Error: lint requires an LLM endpoint (--llm-base-url or SLIDICT_LLM_BASE_URL)"
|
|
116
132
|
1
|
|
@@ -123,7 +139,8 @@ module Slidict
|
|
|
123
139
|
--format FORMAT markdown or asciidoc (default: auto-detected from extension)
|
|
124
140
|
--llm-base-url URL OpenAI Compatible API base URL (env: SLIDICT_LLM_BASE_URL)
|
|
125
141
|
--llm-api-key KEY API key for the LLM endpoint (env: SLIDICT_LLM_API_KEY)
|
|
126
|
-
--llm-model NAME Model name to request (env: SLIDICT_LLM_MODEL
|
|
142
|
+
--llm-model NAME Model name to request (env: SLIDICT_LLM_MODEL); omit to list available models
|
|
143
|
+
--translate LANG Translate findings into the given language (e.g. Japanese)
|
|
127
144
|
-h, --help Show this help
|
|
128
145
|
HELP
|
|
129
146
|
0
|
data/lib/slidict/config.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Slidict
|
|
|
6
6
|
|
|
7
7
|
attr_reader :base_url, :api_key, :model
|
|
8
8
|
|
|
9
|
-
def initialize(base_url: nil, api_key: nil, model:
|
|
9
|
+
def initialize(base_url: nil, api_key: nil, model: nil, enabled: true)
|
|
10
10
|
@base_url = base_url
|
|
11
11
|
@api_key = api_key
|
|
12
12
|
@model = model
|
|
@@ -17,7 +17,7 @@ module Slidict
|
|
|
17
17
|
new(
|
|
18
18
|
base_url: env["SLIDICT_LLM_BASE_URL"],
|
|
19
19
|
api_key: env["SLIDICT_LLM_API_KEY"],
|
|
20
|
-
model: env["SLIDICT_LLM_MODEL"]
|
|
20
|
+
model: env["SLIDICT_LLM_MODEL"]
|
|
21
21
|
)
|
|
22
22
|
end
|
|
23
23
|
|
data/lib/slidict/lint/linter.rb
CHANGED
|
@@ -11,11 +11,11 @@ module Slidict
|
|
|
11
11
|
@client = client
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def lint(content, format: "markdown")
|
|
14
|
+
def lint(content, format: "markdown", translate: nil)
|
|
15
15
|
slides = SlideParser.parse(content, format: format)
|
|
16
16
|
raise Error, "no slides found in the given file" if slides.empty?
|
|
17
17
|
|
|
18
|
-
@client.lint_slides(slides)
|
|
18
|
+
@client.lint_slides(slides, translate: translate)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
end
|
data/lib/slidict/llm/client.rb
CHANGED
|
@@ -21,12 +21,18 @@ module Slidict
|
|
|
21
21
|
# Checks that the endpoint is reachable before the (slower, more
|
|
22
22
|
# expensive) chat completion request is made. Raises Error on failure.
|
|
23
23
|
def verify_connection!
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
response = perform_request(uri, request)
|
|
24
|
+
response = get_models_response
|
|
25
|
+
raise Error, "#{response.code} #{response.message}" unless response.is_a?(Net::HTTPSuccess)
|
|
26
|
+
end
|
|
28
27
|
|
|
28
|
+
# Returns a sorted array of model IDs available at the endpoint.
|
|
29
|
+
def list_models
|
|
30
|
+
response = get_models_response
|
|
29
31
|
raise Error, "#{response.code} #{response.message}" unless response.is_a?(Net::HTTPSuccess)
|
|
32
|
+
|
|
33
|
+
Array(JSON.parse(response.body)["data"]).map { |m| m["id"] }.sort
|
|
34
|
+
rescue JSON::ParserError => e
|
|
35
|
+
raise Error, "could not parse models response: #{e.message}"
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
def generate_slides(deck)
|
|
@@ -37,13 +43,20 @@ module Slidict
|
|
|
37
43
|
# slide_texts is an array of slide bodies (1-indexed by position) as
|
|
38
44
|
# produced by Slidict::Lint::SlideParser. Returns an array of
|
|
39
45
|
# Slidict::Lint::Finding.
|
|
40
|
-
def lint_slides(slide_texts)
|
|
41
|
-
content = chat_completion(lint_prompt_for(slide_texts))
|
|
46
|
+
def lint_slides(slide_texts, translate: nil)
|
|
47
|
+
content = chat_completion(lint_prompt_for(slide_texts, translate: translate))
|
|
42
48
|
findings_from(content)
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
private
|
|
46
52
|
|
|
53
|
+
def get_models_response
|
|
54
|
+
uri = endpoint_uri("models")
|
|
55
|
+
request = Net::HTTP::Get.new(uri)
|
|
56
|
+
request["Authorization"] = "Bearer #{@api_key}"
|
|
57
|
+
perform_request(uri, request)
|
|
58
|
+
end
|
|
59
|
+
|
|
47
60
|
def prompt_for(deck)
|
|
48
61
|
<<~PROMPT
|
|
49
62
|
You are an assistant that designs presentation slide outlines.
|
|
@@ -93,9 +106,10 @@ module Slidict
|
|
|
93
106
|
JSON array. Return an empty array [] if you find no issues.
|
|
94
107
|
PROMPT
|
|
95
108
|
|
|
96
|
-
def lint_prompt_for(slide_texts)
|
|
109
|
+
def lint_prompt_for(slide_texts, translate: nil)
|
|
97
110
|
numbered = slide_texts.each_with_index.map { |text, i| "--- Slide #{i + 1} ---\n#{text}" }.join("\n\n")
|
|
98
|
-
format(LINT_PROMPT_TEMPLATE, numbered: numbered)
|
|
111
|
+
prompt = format(LINT_PROMPT_TEMPLATE, numbered: numbered)
|
|
112
|
+
translate ? "#{prompt}\nWrite each message field in #{translate}." : prompt
|
|
99
113
|
end
|
|
100
114
|
|
|
101
115
|
def findings_from(content)
|
|
@@ -190,7 +204,7 @@ module Slidict
|
|
|
190
204
|
return candidate if candidate
|
|
191
205
|
end
|
|
192
206
|
|
|
193
|
-
raise Error, "no JSON array found in model response"
|
|
207
|
+
raise Error, "no JSON array found in model response\nThe model may be too small to follow the required output format. Try using a larger model."
|
|
194
208
|
end
|
|
195
209
|
|
|
196
210
|
def json_array_from(content, start)
|
data/lib/slidict/version.rb
CHANGED