jekyll-chatgpt-translate 0.0.1 → 0.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 903d9dcdc683aff4816e02d7e49b699d3b8393a64716b162c5b46509efa77a7a
4
- data.tar.gz: a202b7a057a6294046ba081ab8432ee6ef2a3c398a93805bf95b87c8fde76731
3
+ metadata.gz: d4406bec62ad6c32b1dcff60e2b87e49b7aa886d483efd11d141aa55a5dcea4f
4
+ data.tar.gz: d12af607c08b438cbb14d660a6347070b4c4b5bced4fbda805709b27544f20de
5
5
  SHA512:
6
- metadata.gz: 1e5ae442015d83a9b7f9a5408826dc1c0ed808abb1bf3b9b7339f87d40d7ba6b0e6518547d9bc707a00b7a98c30bc1d2e3fcf41ed576b175e215f764ed8dcf7d
7
- data.tar.gz: 19e9825b50ecd0b72bf9acde8f330d47f1a00964516570e967d3dbe0e3d1077069dddcb6daac7eb1851bd8fcc2d52be0044a060320c83621fff3dac5a36a9da0
6
+ metadata.gz: 65f1e5fc709dbf5750435dc205b70c5d1b30c51e44e6ae53b4d9c1d2d670f64b38546e033e3f9f87cd7f374d4d244f8b6f3226e4be4622a47832c84ed86f719f
7
+ data.tar.gz: 1484f30b17ef150720e7cb68ac5ce136e56135e1f16706a43b7a38735922b7fdde639f5acb154edf68c66dc78ae92183232e5f1ee82dc67c946cd263c8b50afb
data/.rubocop.yml CHANGED
@@ -18,11 +18,11 @@ Layout/MultilineMethodCallIndentation:
18
18
  Metrics/AbcSize:
19
19
  Enabled: false
20
20
  Metrics/BlockLength:
21
- Max: 30
21
+ Max: 50
22
22
  Metrics/CyclomaticComplexity:
23
- Max: 10
23
+ Max: 15
24
24
  Metrics/PerceivedComplexity:
25
- Max: 10
25
+ Max: 15
26
26
  Layout/EmptyLineAfterGuardClause:
27
27
  Enabled: false
28
28
  Naming/FileName:
data/Gemfile CHANGED
@@ -26,7 +26,7 @@ source 'https://rubygems.org'
26
26
  gemspec
27
27
 
28
28
  gem 'cucumber', '8.0.0', require: false
29
- gem 'jekyll', '3.9.2', require: false
29
+ gem 'jekyll', '3.9.3', require: false
30
30
  gem 'kramdown-parser-gfm', '1.1.0', require: false
31
31
  gem 'minitest', '5.19.0', require: false
32
32
  gem 'rake', '13.0.6', require: false
data/README.md CHANGED
@@ -11,6 +11,7 @@ Then, add this to `_config.yml`:
11
11
 
12
12
  ```yaml
13
13
  chatgpt-translate:
14
+ model: gpt-3.5-turbo
14
15
  source: en
15
16
  layout: translated
16
17
  targets:
@@ -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.1'
31
+ s.version = '0.0.2'
32
32
  s.license = 'MIT'
33
33
  s.summary = 'Translate Jekyll Pages Through ChatGPT'
34
34
  s.description = [
@@ -42,9 +42,11 @@ Gem::Specification.new do |s|
42
42
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
43
43
  s.rdoc_options = ['--charset=UTF-8']
44
44
  s.extra_rdoc_files = %w[README.md LICENSE.txt]
45
- s.add_runtime_dependency 'iso-639', '~> 0.3.6'
46
- s.add_runtime_dependency 'jekyll', '~> 3.9.2'
47
- s.add_runtime_dependency 'redcarpet', '~> 3.6.0'
48
- s.add_runtime_dependency 'ruby-openai', '~> 5.0.0'
45
+ s.add_runtime_dependency 'iri', '~> 0.6'
46
+ s.add_runtime_dependency 'iso-639', '~> 0.3'
47
+ s.add_runtime_dependency 'jekyll', '~> 3.9'
48
+ s.add_runtime_dependency 'liquid', '~> 4.0'
49
+ s.add_runtime_dependency 'redcarpet', '~> 3.6'
50
+ s.add_runtime_dependency 'ruby-openai', '~> 5.0'
49
51
  s.metadata['rubygems_mfa_required'] = 'true'
50
52
  end
@@ -38,40 +38,40 @@ class GptTranslate::ChatGPT
38
38
  # +key+ OpenAI API Key, which can't be nil, but can be empty string, which means dry mode (no calls to OpenAI)
39
39
  # +source+ The language to translate from
40
40
  # +target+ The language to translate into
41
- def initialize(key, source, target)
41
+ def initialize(key, model, source, target)
42
42
  raise 'OpenAI key cannot be nil' if key.nil?
43
43
  @key = key
44
+ @model = model
44
45
  @source = source
45
46
  @target = target
46
47
  end
47
48
 
48
49
  def translate(text)
49
- model = 'gpt-3.5-turbo'
50
50
  text.split("\n\n").compact.map do |par|
51
51
  if par.length <= 32
52
52
  Jekyll.logger.debug("Not translating this, b/c too short: \"#{par}\"")
53
53
  par
54
- elsif par !~ /^[А-Я]/
54
+ elsif par !~ /^[a-zA-Zа-яА-Я]/
55
55
  Jekyll.logger.debug("Not translating this, b/c it's not a plain text: \"#{par}\"")
56
56
  par
57
57
  elsif @key.empty?
58
58
  par
59
59
  else
60
- translate_par(par, model)
60
+ translate_par(par)
61
61
  end
62
62
  end.join("\n\n")
63
63
  end
64
64
 
65
65
  private
66
66
 
67
- def translate_par(par, model)
67
+ def translate_par(par)
68
68
  Time.now
69
69
  t = nil
70
70
  attempt = 0
71
71
  begin
72
72
  response = OpenAI::Client.new(access_token: @key).chat(
73
73
  parameters: {
74
- model: model,
74
+ model: @model,
75
75
  messages: [{
76
76
  role: 'user',
77
77
  content: "#{prompt}:\n\n#{par}"
@@ -91,7 +91,7 @@ class GptTranslate::ChatGPT
91
91
  else
92
92
  Jekyll.logger.debug("Translated #{par.split.count} #{@source.upcase} words
93
93
  to #{t.split.count} #{@target.upcase} words
94
- through #{model} in #{(Time.now - pstart).round(2)}s")
94
+ through #{@model} in #{(Time.now - pstart).round(2)}s")
95
95
  t
96
96
  end
97
97
  end
@@ -24,7 +24,9 @@
24
24
 
25
25
  require 'jekyll'
26
26
  require_relative 'chatgpt'
27
+ require_relative 'ping'
27
28
  require_relative 'plain'
29
+ require_relative 'version'
28
30
 
29
31
  # The module we are in.
30
32
  module GptTranslate; end
@@ -57,9 +59,17 @@ but pages will be generated')
57
59
  site.posts.docs.each do |doc|
58
60
  plain = GptTranslate::Plain.new(doc.content).to_s
59
61
  config['targets'].each do |target|
62
+ link = permalink(doc, target['permalink'])
63
+ next if GptTranslate::Ping.new(site, link).exists?
60
64
  lang = target['language']
61
65
  raise 'Language must be defined for each target' if target.nil?
62
- gpt = GptTranslate::ChatGPT.new(key, config['source'] || 'en', lang)
66
+ model = config['model'] || 'gpt-3.5-turbo'
67
+ gpt = GptTranslate::ChatGPT.new(
68
+ key,
69
+ model,
70
+ config['source'] || 'en',
71
+ lang
72
+ )
63
73
  translated = gpt.translate(plain)
64
74
  path = "_chatgpt-translated/#{doc.basename}"
65
75
  FileUtils.mkdir_p(File.dirname(path))
@@ -69,17 +79,19 @@ but pages will be generated')
69
79
  '---',
70
80
  "layout: #{target['layout'] || layout}",
71
81
  "title: #{doc.data['title']}",
72
- "permalink: #{permalink(doc, target['permalink'])}",
82
+ "permalink: #{link}",
73
83
  '---',
74
84
  '',
75
- translated
85
+ translated,
86
+ '',
87
+ "Translated by ChatGPT #{model}/#{GptTranslate::VERSION}\n{: .jekyll-chatgpt-translate}"
76
88
  ].join("\n")
77
89
  )
78
90
  site.pages << Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path))
79
91
  total += 1
80
92
  end
81
93
  end
82
- puts "#{total} pages generated in #{(Time.now - start).round(2)}s"
94
+ Jekyll.logger.info("#{total} pages generated in #{(Time.now - start).round(2)}s")
83
95
  end
84
96
 
85
97
  private
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (The MIT License)
4
+ #
5
+ # Copyright (c) 2023 Yegor Bugayenko
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the 'Software'), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ require 'iri'
26
+ require 'net/http'
27
+ require 'uri'
28
+ require_relative 'version'
29
+
30
+ # see https://stackoverflow.com/a/6048451/187141
31
+ require 'openssl'
32
+ OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
33
+
34
+ # The module we are in.
35
+ module GptTranslate; end
36
+
37
+ # Ping one page of a site.
38
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
39
+ # Copyright:: Copyright (c) 2023 Yegor Bugayenko
40
+ # License:: MIT
41
+ class GptTranslate::Ping
42
+ # Ctor.
43
+ def initialize(site, link)
44
+ @site = site
45
+ @link = link
46
+ end
47
+
48
+ def exists?
49
+ home = @site.config['url']
50
+ return false if home.nil?
51
+ uri = Iri.new(home).path(@link)
52
+ before = Net::HTTP.get_response(URI(uri.to_s))
53
+ if before.is_a?(Net::HTTPSuccess) && before.body.include?("/#{GptTranslate::VERSION}")
54
+ Jekyll.logger.info("No need to translate, page exists at #{uri} (#{before.body.split.count} words)")
55
+ return true
56
+ end
57
+ Jekyll.logger.debug("GET #{uri}: #{before.code}")
58
+ false
59
+ end
60
+ end
@@ -23,6 +23,7 @@
23
23
  # SOFTWARE.
24
24
 
25
25
  require 'redcarpet'
26
+ require 'liquid'
26
27
 
27
28
  # The module we are in.
28
29
  module GptTranslate; end
@@ -42,12 +43,23 @@ class GptTranslate::Plain
42
43
  par.gsub!("\n", ' ')
43
44
  par.gsub!(/\s{2,}/, ' ')
44
45
  par.strip!
45
- next if par.start_with?('<')
46
- next if par.start_with?('{%')
46
+ liquid = Liquid::Template.parse(par)
47
+ par = liquid.render({}, drop: NullDrop.new, registers: { removed: true })
47
48
  Redcarpet::Markdown.new(Strip).render(par)
48
49
  end.join("\n\n").gsub(/\n{2,}/, "\n\n").strip
49
50
  end
50
51
 
52
+ # To ignore/remove Liquid tags.
53
+ class NullDrop < Liquid::Drop
54
+ def method_missing(*)
55
+ nil
56
+ end
57
+
58
+ def respond_to_missing?(*)
59
+ true
60
+ end
61
+ end
62
+
51
63
  # Markdown to pain text.
52
64
  class Strip < Redcarpet::Render::Base
53
65
  %i[
@@ -65,6 +77,10 @@ class GptTranslate::Plain
65
77
  end
66
78
  end
67
79
 
80
+ def raw_html(_content)
81
+ 'HTML'
82
+ end
83
+
68
84
  def list(content, _type)
69
85
  content
70
86
  end
@@ -22,6 +22,6 @@
22
22
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
23
  # SOFTWARE.
24
24
 
25
- module Jekyll::Translate
25
+ module GptTranslate
26
26
  VERSION = '0.0.1'
27
27
  end
data/test/test_chatgpt.rb CHANGED
@@ -31,17 +31,17 @@ require_relative '../lib/jekyll-chatgpt-translate/chatgpt'
31
31
  # License:: MIT
32
32
  class GptTranslate::ChatGPTTest < Minitest::Test
33
33
  def test_short_text
34
- chat = GptTranslate::ChatGPT.new('fake-key', 'en', 'ru')
34
+ chat = GptTranslate::ChatGPT.new('fake-key', 'gpt-3.5-turbo', 'en', 'ru')
35
35
  assert_equal('Hello, world!', chat.translate('Hello, world!'))
36
36
  end
37
37
 
38
38
  def test_dry_mode
39
- chat = GptTranslate::ChatGPT.new('', 'en', 'ru')
39
+ chat = GptTranslate::ChatGPT.new('', 'gpt-3.5-turbo', 'en', 'ru')
40
40
  assert_equal(38, chat.translate('This text should not be sent to OpenAI').length)
41
41
  end
42
42
 
43
43
  def test_markup
44
- chat = GptTranslate::ChatGPT.new('fake-key', 'en', 'ru')
44
+ chat = GptTranslate::ChatGPT.new('fake-key', 'gpt-3.5-turbo', 'en', 'ru')
45
45
  assert_equal('<img src="a"/>', chat.translate('<img src="a"/>'))
46
46
  end
47
47
  end
data/test/test_ping.rb ADDED
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (The MIT License)
4
+ #
5
+ # Copyright (c) 2023 Yegor Bugayenko
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the 'Software'), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ require 'minitest/autorun'
26
+ require 'jekyll'
27
+ require_relative '../lib/jekyll-chatgpt-translate/ping'
28
+
29
+ # Ping test.
30
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
+ # Copyright:: Copyright (c) 2023 Yegor Bugayenko
32
+ # License:: MIT
33
+ class GptTranslate::PingTest < Minitest::Test
34
+ class FakeSite
35
+ attr_reader :config
36
+
37
+ def initialize(config)
38
+ @config = config
39
+ end
40
+ end
41
+
42
+ def test_when_exists
43
+ site = FakeSite.new({ 'url' => 'https://www.yegor256.com/' })
44
+ ping = GptTranslate::Ping.new(site, '/about-me.html')
45
+ assert(!ping.exists?)
46
+ end
47
+ end
data/test/test_plain.rb CHANGED
@@ -53,4 +53,33 @@ class GptTranslate::PlainTest < Minitest::Test
53
53
  GptTranslate::Plain.new('Hello, [dude](https://www.google.com)!').to_s
54
54
  )
55
55
  end
56
+
57
+ def test_code
58
+ assert_equal(
59
+ 'Hello, Java!',
60
+ GptTranslate::Plain.new('Hello, `Java`!').to_s
61
+ )
62
+ end
63
+
64
+ def test_code_block
65
+ assert_equal(
66
+ "Hello:\n\nJava",
67
+ GptTranslate::Plain.new("Hello:\n\n```\nJava\n```\n").to_s
68
+ )
69
+ end
70
+
71
+ def test_html
72
+ assert_equal(
73
+ 'This is picture: HTML!',
74
+ GptTranslate::Plain.new('This is picture: <img src="a"/>!').to_s
75
+ )
76
+ assert_equal('HTML', GptTranslate::Plain.new('<img src="a"/>').to_s)
77
+ end
78
+
79
+ def test_liquid_tags
80
+ assert_equal(
81
+ 'Hello, !',
82
+ GptTranslate::Plain.new('Hello, {{ Java }}!').to_s
83
+ )
84
+ end
56
85
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-chatgpt-translate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -10,62 +10,90 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2023-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: iri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.6'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: iso-639
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: 0.3.6
33
+ version: '0.3'
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: 0.3.6
40
+ version: '0.3'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: jekyll
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: 3.9.2
47
+ version: '3.9'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: liquid
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
34
62
  type: :runtime
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: 3.9.2
68
+ version: '4.0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: redcarpet
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
73
  - - "~>"
46
74
  - !ruby/object:Gem::Version
47
- version: 3.6.0
75
+ version: '3.6'
48
76
  type: :runtime
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
- version: 3.6.0
82
+ version: '3.6'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: ruby-openai
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
87
  - - "~>"
60
88
  - !ruby/object:Gem::Version
61
- version: 5.0.0
89
+ version: '5.0'
62
90
  type: :runtime
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: 5.0.0
96
+ version: '5.0'
69
97
  description: Add this plugin to your Jekyll site and all posts will be automatically
70
98
  translated to the languages of your choice through ChatGPT
71
99
  email: yegor256@gmail.com
@@ -93,12 +121,14 @@ files:
93
121
  - lib/jekyll-chatgpt-translate.rb
94
122
  - lib/jekyll-chatgpt-translate/chatgpt.rb
95
123
  - lib/jekyll-chatgpt-translate/generator.rb
124
+ - lib/jekyll-chatgpt-translate/ping.rb
96
125
  - lib/jekyll-chatgpt-translate/plain.rb
97
126
  - lib/jekyll-chatgpt-translate/version.rb
98
127
  - renovate.json
99
128
  - test/test__helper.rb
100
129
  - test/test_chatgpt.rb
101
130
  - test/test_generator.rb
131
+ - test/test_ping.rb
102
132
  - test/test_plain.rb
103
133
  homepage: https://github.com/yegor256/jekyll-chatgpt-translate
104
134
  licenses: