jekyll-chatgpt-translate 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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: