jekyll-chatgpt-translate 0.0.24 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/README.md +9 -4
- data/jekyll-chatgpt-translate.gemspec +1 -1
- data/lib/jekyll-chatgpt-translate/chatgpt.rb +18 -3
- data/lib/jekyll-chatgpt-translate/plain.rb +2 -2
- data/lib/jekyll-chatgpt-translate/version.rb +1 -1
- data/test/test_chatgpt.rb +14 -0
- data/test/test_plain.rb +7 -7
- 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: 9f480f74d9f096d1b24d516f05c1c24a27cefe7e87cc9db917d2fffe727646fe
|
4
|
+
data.tar.gz: 0dd088c831b8a3d9685bf4363ea7821d83d8602767fb933740b938552475d98e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c286215fa7b40fab206be74d7f03d02963f307009ba6d91c0f1ff7ce06795eb29be1588c022a994696755677e6640fb595aca7246474d8a1bc9072f38f5458a1
|
7
|
+
data.tar.gz: af831575ce9749aada2c42ad5c4d8798890490e5e0795cd87f70cce9a2d8b7bbaa3d7dfba9b95e9b5f81eaef2e9f9513ca1542341e1393bc4878c6ee257911af
|
data/.rubocop.yml
CHANGED
@@ -3,7 +3,7 @@ AllCops:
|
|
3
3
|
- 'bin/**/*'
|
4
4
|
- 'assets/**/*'
|
5
5
|
DisplayCopNames: true
|
6
|
-
TargetRubyVersion: 2.
|
6
|
+
TargetRubyVersion: 2.7
|
7
7
|
SuggestExtensions: false
|
8
8
|
NewCops: enable
|
9
9
|
|
@@ -35,3 +35,5 @@ Layout/EndAlignment:
|
|
35
35
|
Enabled: false
|
36
36
|
Metrics/ClassLength:
|
37
37
|
Max: 200
|
38
|
+
Style/ClassVars:
|
39
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -60,9 +60,14 @@ Full list of options available to specify in `_config.yml`:
|
|
60
60
|
* `api_key_file` (optional) — the file with OpenAI API key. If this option is not specified,
|
61
61
|
it is expected to have the key in the `OPENAI_API_KEY` environment variable.
|
62
62
|
|
63
|
-
* `
|
63
|
+
* `api_key` (optional) — the OpenAI API key itself. This is a very bad idea to
|
64
|
+
specify it right in the `_config.yml` file, but it's still possible.
|
64
65
|
|
65
|
-
* `
|
66
|
+
* `model` (optional) — specifies the model to use by ChatGPT,
|
67
|
+
[examples are here](https://github.com/alexrudall/ruby-openai#models).
|
68
|
+
|
69
|
+
* `source` (optional) — is the [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
|
70
|
+
code of the source language.
|
66
71
|
|
67
72
|
* `no_download` (optional) — if this attribute is present, the plugin won't try
|
68
73
|
to find HTML versions of translated pages in the Internet and won't try to
|
@@ -79,7 +84,7 @@ This layout will be specified for the pages generated by this plugin.
|
|
79
84
|
|
80
85
|
* `targets` (mandatory) — an array of target languages, each of which has the following attributes
|
81
86
|
|
82
|
-
* `language` (mandatory) — ISO-
|
87
|
+
* `language` (mandatory) — [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) code of the target language
|
83
88
|
|
84
89
|
* `permalink` (mandatory) — template to use for newly generated pages
|
85
90
|
|
@@ -93,7 +98,7 @@ This layout will be specified for the pages generated by this plugin.
|
|
93
98
|
* `version` (optional) — the version that will be attached to each generated page,
|
94
99
|
in order to avoid repetitive translations on one hand and enable re-translations
|
95
100
|
when the `version` is changed on another hand. By default, the version of
|
96
|
-
|
101
|
+
this plugin will be used, unless you set your own value.
|
97
102
|
|
98
103
|
## How to Contribute
|
99
104
|
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
29
29
|
s.required_ruby_version = '>= 2.6'
|
30
30
|
s.name = 'jekyll-chatgpt-translate'
|
31
|
-
s.version = '0.0.
|
31
|
+
s.version = '0.0.26'
|
32
32
|
s.license = 'MIT'
|
33
33
|
s.summary = 'Translate Jekyll Pages Through ChatGPT'
|
34
34
|
s.description = [
|
@@ -35,6 +35,9 @@ module GptTranslate; end
|
|
35
35
|
# Copyright:: Copyright (c) 2023 Yegor Bugayenko
|
36
36
|
# License:: MIT
|
37
37
|
class GptTranslate::ChatGPT
|
38
|
+
# Is TRUE if we already shown to the user the available models.
|
39
|
+
@@models_printed = false
|
40
|
+
|
38
41
|
# Ctor.
|
39
42
|
# +key+ OpenAI API Key, which can't be nil, but can be empty string, which means dry mode (no calls to OpenAI)
|
40
43
|
# +source+ The language to translate from
|
@@ -64,6 +67,10 @@ class GptTranslate::ChatGPT
|
|
64
67
|
par
|
65
68
|
elsif @key.empty?
|
66
69
|
par
|
70
|
+
elsif par.start_with?('* ')
|
71
|
+
"* #{translate_par(par[2..])}"
|
72
|
+
elsif par =~ /^[0-9]+\. /
|
73
|
+
"1. #{translate_par(par.split('.', 2)[1])}"
|
67
74
|
else
|
68
75
|
translate_par(par)
|
69
76
|
end
|
@@ -73,12 +80,17 @@ class GptTranslate::ChatGPT
|
|
73
80
|
private
|
74
81
|
|
75
82
|
def translate_par(par)
|
83
|
+
client = OpenAI::Client.new(access_token: @key)
|
84
|
+
if @@models_printed
|
85
|
+
Jekyll.logger.info("Available ChatGPT models: #{client.models.list['data'].map { |m| m['id'] }.join(', ')}")
|
86
|
+
@@models_printed = true
|
87
|
+
end
|
88
|
+
prompt = GptTranslate::Prompt.new(par, @source, @target).to_s
|
76
89
|
start = Time.now
|
77
90
|
answer = nil
|
78
91
|
attempt = 0
|
79
92
|
begin
|
80
|
-
|
81
|
-
response = OpenAI::Client.new(access_token: @key).chat(
|
93
|
+
response = client.chat(
|
82
94
|
parameters: {
|
83
95
|
model: @model,
|
84
96
|
messages: [{ role: 'user', content: prompt }],
|
@@ -86,7 +98,10 @@ class GptTranslate::ChatGPT
|
|
86
98
|
}
|
87
99
|
)
|
88
100
|
answer = response.dig('choices', 0, 'message', 'content')
|
89
|
-
|
101
|
+
if answer.nil?
|
102
|
+
Jekyll.logger.error("No content returned by ChatGPT: #{response}")
|
103
|
+
raise 'No content returned by ChatGPT'
|
104
|
+
end
|
90
105
|
Jekyll.logger.debug("ChatGPT prompt: #{prompt.inspect}, ChatGPT answer: #{answer.inspect}")
|
91
106
|
rescue StandardError => e
|
92
107
|
attempt += 1
|
data/test/test_chatgpt.rb
CHANGED
@@ -44,6 +44,20 @@ class GptTranslate::ChatGPTTest < Minitest::Test
|
|
44
44
|
assert_equal('done!', chat.translate('[OpenAI](https://openai.com) is the creator of ChatGPT', min: 10))
|
45
45
|
end
|
46
46
|
|
47
|
+
def test_unordered_list_item
|
48
|
+
stub_request(:any, 'https://api.openai.com/v1/chat/completions')
|
49
|
+
.to_return(body: '{"choices":[{"message":{"content": "done!"}}]}')
|
50
|
+
chat = GptTranslate::ChatGPT.new('fake-key', 'gpt-3.5-turbo', 'en', 'ru')
|
51
|
+
assert_equal("* done!\n\n* done!", chat.translate("* First\n\n* Second", min: 1))
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_ordered_list_item
|
55
|
+
stub_request(:any, 'https://api.openai.com/v1/chat/completions')
|
56
|
+
.to_return(body: '{"choices":[{"message":{"content": "done!"}}]}')
|
57
|
+
chat = GptTranslate::ChatGPT.new('fake-key', 'gpt-3.5-turbo', 'en', 'ru')
|
58
|
+
assert_equal("1. done!\n\n1. done!", chat.translate("1. First\n\n2. Second", min: 1))
|
59
|
+
end
|
60
|
+
|
47
61
|
def test_dry_mode
|
48
62
|
chat = GptTranslate::ChatGPT.new('', 'foo', 'xx', 'xx')
|
49
63
|
assert_equal(38, chat.translate('This text should not be sent to OpenAI', min: 100).length)
|
data/test/test_plain.rb
CHANGED
@@ -42,25 +42,25 @@ class GptTranslate::PlainTest < Minitest::Test
|
|
42
42
|
|
43
43
|
def test_lists
|
44
44
|
assert_equal(
|
45
|
-
"first\n\
|
45
|
+
"* first\n\n* second\n\n* third",
|
46
46
|
GptTranslate::Plain.new("* first\n\n* second\n\n* third").to_s
|
47
47
|
)
|
48
48
|
assert_equal(
|
49
|
-
'first',
|
49
|
+
'* first',
|
50
50
|
GptTranslate::Plain.new("* first\n\n\n\n").to_s
|
51
51
|
)
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_ordered_list
|
55
55
|
assert_equal(
|
56
|
-
"first\n\
|
56
|
+
"1. first\n\n1. second\n\n1. third",
|
57
57
|
GptTranslate::Plain.new("1. first\n\n2. second\n\n3. third").to_s
|
58
58
|
)
|
59
59
|
end
|
60
60
|
|
61
61
|
def test_compact_list
|
62
62
|
assert_equal(
|
63
|
-
"first\n\
|
63
|
+
"* first\n\n* second\n\n* third",
|
64
64
|
GptTranslate::Plain.new("* first\n* second\n* third").to_s
|
65
65
|
)
|
66
66
|
end
|
@@ -151,11 +151,11 @@ class GptTranslate::PlainTest < Minitest::Test
|
|
151
151
|
|
152
152
|
In this *lovely* letter I will explain how objects work in C++:
|
153
153
|
|
154
|
-
Declare a class
|
154
|
+
* Declare a class
|
155
155
|
|
156
|
-
Make an instance of it
|
156
|
+
* Make an instance of it
|
157
157
|
|
158
|
-
Delete the instance
|
158
|
+
* Delete the instance
|
159
159
|
|
160
160
|
## More details
|
161
161
|
|