jekyll-chatgpt-translate 0.0.21 → 0.0.22
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/features/cli.feature +35 -0
- data/jekyll-chatgpt-translate.gemspec +1 -1
- data/lib/jekyll-chatgpt-translate/generator.rb +7 -3
- data/lib/jekyll-chatgpt-translate/ping.rb +20 -5
- data/lib/jekyll-chatgpt-translate/version.rb +1 -1
- data/test/test__helper.rb +104 -0
- data/test/test_generator.rb +2 -89
- data/test/test_ping.rb +10 -21
- 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: daa42e099235943fc1a5473a83796abe90b7949d1365c9d9b7349c7c86be7406
|
4
|
+
data.tar.gz: 6c7559aea364339a8b2ac5eac397e314491166b77cfff92565218f6cdd04499b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e651bfae3d35ddf473555eb168cf3301ba6dacda8352fd00a610613c9a2dc8821a1188064089f701ae94c4e4b2277f41b5d635842ae4132f92e9242828ecc0ac
|
7
|
+
data.tar.gz: a18e7007a9f40cfdba340285c8ef665c8c47d8e829ac6f76d304b77cec89b14ce9e9c1d56ddfd72f010429d4620f712ee773ed7011942d771c49993799bcef23
|
data/features/cli.feature
CHANGED
@@ -31,6 +31,11 @@ Feature: Simple site building
|
|
31
31
|
Chinese: {{ content }}
|
32
32
|
The original: {{ page.translated-original-url }}
|
33
33
|
"""
|
34
|
+
And I have a "_layouts/translated.html" file with content:
|
35
|
+
"""
|
36
|
+
French: {{ content }}
|
37
|
+
The original: {{ page.translated-original-url }}
|
38
|
+
"""
|
34
39
|
And I have a "_posts/2023-01-01-hello.md" file with content:
|
35
40
|
"""
|
36
41
|
---
|
@@ -50,3 +55,33 @@ Feature: Simple site building
|
|
50
55
|
And File "_site/2023-01-01-hello-chinese.html" contains "The original: /2023/01/01/hello.html"
|
51
56
|
And File "_site/2023/hello-french.html" exists
|
52
57
|
|
58
|
+
Scenario: Simple download of existing page
|
59
|
+
Given I have a "_config.yml" file with content:
|
60
|
+
"""
|
61
|
+
url: https://www.yegor256.com
|
62
|
+
markdown: kramdown
|
63
|
+
plugins:
|
64
|
+
- jekyll-chatgpt-translate
|
65
|
+
chatgpt-translate:
|
66
|
+
source: en
|
67
|
+
version: ""
|
68
|
+
api_key: "it-is-not-used, because EN to EN translation"
|
69
|
+
layout: should-not-be-used
|
70
|
+
targets:
|
71
|
+
-
|
72
|
+
language: en
|
73
|
+
permalink: about-me.html
|
74
|
+
"""
|
75
|
+
And I have a "_posts/2023-01-01-hello.md" file with content:
|
76
|
+
"""
|
77
|
+
---
|
78
|
+
title: foo
|
79
|
+
---
|
80
|
+
foo
|
81
|
+
"""
|
82
|
+
Then I build Jekyll site
|
83
|
+
And Exit code is zero
|
84
|
+
And Stdout contains "No need to translate, the page exists"
|
85
|
+
And File "_site/2023/01/01/hello.html" exists
|
86
|
+
And File "_site/about-me.html" exists
|
87
|
+
And File "_site/about-me.html" contains "Yegor Bugayenko"
|
@@ -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.22'
|
32
32
|
s.license = 'MIT'
|
33
33
|
s.summary = 'Translate Jekyll Pages Through ChatGPT'
|
34
34
|
s.description = [
|
@@ -81,9 +81,8 @@ class GptTranslate::Generator < Jekyll::Generator
|
|
81
81
|
'---'
|
82
82
|
].join("\n")
|
83
83
|
)
|
84
|
-
url = Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path)).url
|
85
84
|
ping = GptTranslate::Ping.new(site, link)
|
86
|
-
if config['no_download'].nil? && ping.found?(
|
85
|
+
if config['no_download'].nil? && ping.found?(version.empty? ? '' : marker)
|
87
86
|
copied += 1
|
88
87
|
elsif translated >= threshold
|
89
88
|
next
|
@@ -113,7 +112,8 @@ class GptTranslate::Generator < Jekyll::Generator
|
|
113
112
|
doc.data['chatgpt-model'] = model
|
114
113
|
end
|
115
114
|
end
|
116
|
-
Jekyll.logger.info("
|
115
|
+
Jekyll.logger.info("jekyll-chatgpt-translate #{GptTranslate::VERSION}: \
|
116
|
+
#{translated} pages translated and #{copied} pages copied in #{(Time.now - start).round(2)}s")
|
117
117
|
end
|
118
118
|
|
119
119
|
private
|
@@ -134,6 +134,10 @@ class GptTranslate::Generator < Jekyll::Generator
|
|
134
134
|
Jekyll.logger.info("The file with the OpenAI API key is not found: #{file.inspect}")
|
135
135
|
nil
|
136
136
|
end
|
137
|
+
if key.nil? && config['api_key']
|
138
|
+
Jekyll.logger.info("The OpenAI API key is found in 'api_key' of _config.yml")
|
139
|
+
key = config['api_key']
|
140
|
+
end
|
137
141
|
if key.nil? && Jekyll.env == 'development'
|
138
142
|
Jekyll.logger.info("OPENAI_API_KEY environment variable is not set, \
|
139
143
|
the `api_key_file` option is not specified in the _config.yml, and \
|
@@ -25,6 +25,7 @@
|
|
25
25
|
require 'iri'
|
26
26
|
require 'net/http'
|
27
27
|
require 'uri'
|
28
|
+
require 'jekyll'
|
28
29
|
require 'fileutils'
|
29
30
|
require_relative 'version'
|
30
31
|
|
@@ -47,7 +48,7 @@ class GptTranslate::Ping
|
|
47
48
|
@path = path
|
48
49
|
end
|
49
50
|
|
50
|
-
def found?(
|
51
|
+
def found?(marker)
|
51
52
|
home = @site.config['url']
|
52
53
|
return false if home.nil?
|
53
54
|
uri = Iri.new(home).path(@path).to_s
|
@@ -57,9 +58,8 @@ class GptTranslate::Ping
|
|
57
58
|
html = before.body
|
58
59
|
if html.include?(marker)
|
59
60
|
Jekyll.logger.info("No need to translate, the page exists at \
|
60
|
-
#{uri.inspect} (#{html.split.count} words)
|
61
|
-
|
62
|
-
File.write(file, html)
|
61
|
+
#{uri.inspect} (#{html.split.count} words)")
|
62
|
+
@site.static_files << DownloadedFile.new(@site, @path, html)
|
63
63
|
return true
|
64
64
|
end
|
65
65
|
Jekyll.logger.info("Re-translation required for #{uri.inspect}")
|
@@ -67,10 +67,25 @@ class GptTranslate::Ping
|
|
67
67
|
Jekyll.logger.info("The page is absent, will translate #{uri.inspect} (#{before.code})")
|
68
68
|
end
|
69
69
|
Jekyll.logger.debug("GET #{uri.inspect}: #{before.code}")
|
70
|
-
rescue
|
70
|
+
rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL => e
|
71
71
|
Jekyll.logger.debug("Failed to ping #{uri.inspect}: #{e.message}")
|
72
72
|
Jekyll.logger.info("The page is absent (#{e.class.name}): #{uri.inspect}")
|
73
73
|
end
|
74
74
|
false
|
75
75
|
end
|
76
|
+
|
77
|
+
# The file we just downloaded.
|
78
|
+
class DownloadedFile < Jekyll::StaticFile
|
79
|
+
def initialize(site, path, html)
|
80
|
+
super(site, site.dest, '', path)
|
81
|
+
@html = html
|
82
|
+
end
|
83
|
+
|
84
|
+
def write(_dest)
|
85
|
+
FileUtils.mkdir_p(File.dirname(path))
|
86
|
+
File.write(path, @html)
|
87
|
+
Jekyll.logger.info("Saved #{@html.split.count} words to #{path.inspect}")
|
88
|
+
true
|
89
|
+
end
|
90
|
+
end
|
76
91
|
end
|
data/test/test__helper.rb
CHANGED
@@ -27,3 +27,107 @@ SimpleCov.start
|
|
27
27
|
|
28
28
|
require 'jekyll'
|
29
29
|
Jekyll.logger.adjust_verbosity(verbose: true)
|
30
|
+
|
31
|
+
# The module we are in.
|
32
|
+
module GptTranslate; end
|
33
|
+
|
34
|
+
# Fake.
|
35
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
36
|
+
# Copyright:: Copyright (c) 2023 Yegor Bugayenko
|
37
|
+
# License:: MIT
|
38
|
+
class GptTranslate::FakeSite
|
39
|
+
attr_reader :config, :pages, :static_files
|
40
|
+
|
41
|
+
def initialize(config, docs = [])
|
42
|
+
@config = config
|
43
|
+
@docs = docs
|
44
|
+
@pages = []
|
45
|
+
@static_files = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def posts
|
49
|
+
GptTranslate::FakePosts.new(@docs)
|
50
|
+
end
|
51
|
+
|
52
|
+
def permalink_style
|
53
|
+
''
|
54
|
+
end
|
55
|
+
|
56
|
+
def frontmatter_defaults
|
57
|
+
Jekyll::FrontmatterDefaults.new(self)
|
58
|
+
end
|
59
|
+
|
60
|
+
def converters
|
61
|
+
[Jekyll::Converters::Markdown.new({ 'markdown_ext' => 'md' })]
|
62
|
+
end
|
63
|
+
|
64
|
+
def source
|
65
|
+
''
|
66
|
+
end
|
67
|
+
|
68
|
+
def dest
|
69
|
+
return '' if @docs.empty?
|
70
|
+
File.dirname(@docs[0])
|
71
|
+
end
|
72
|
+
|
73
|
+
def in_theme_dir(base, _foo = nil, _bar = nil)
|
74
|
+
base
|
75
|
+
end
|
76
|
+
|
77
|
+
def in_dest_dir(*paths)
|
78
|
+
paths[0].dup
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Fake.
|
83
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
84
|
+
# Copyright:: Copyright (c) 2023 Yegor Bugayenko
|
85
|
+
# License:: MIT
|
86
|
+
class GptTranslate::FakeDocument
|
87
|
+
attr_reader :data
|
88
|
+
|
89
|
+
def initialize(path)
|
90
|
+
@path = path
|
91
|
+
@data = { 'date' => Time.now, 'title' => 'Hello!' }
|
92
|
+
end
|
93
|
+
|
94
|
+
def content
|
95
|
+
'Hello, world!'
|
96
|
+
end
|
97
|
+
|
98
|
+
def []=(key, value)
|
99
|
+
@data[key] = value
|
100
|
+
end
|
101
|
+
|
102
|
+
def [](key)
|
103
|
+
@data[key] || ''
|
104
|
+
end
|
105
|
+
|
106
|
+
def relative_path
|
107
|
+
@path
|
108
|
+
end
|
109
|
+
|
110
|
+
def url
|
111
|
+
'2023-01-01-hello.html'
|
112
|
+
end
|
113
|
+
|
114
|
+
def basename
|
115
|
+
'2023-01-01-hello.md'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Fake.
|
120
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
121
|
+
# Copyright:: Copyright (c) 2023 Yegor Bugayenko
|
122
|
+
# License:: MIT
|
123
|
+
class GptTranslate::FakePosts
|
124
|
+
attr_reader :config
|
125
|
+
|
126
|
+
def initialize(docs)
|
127
|
+
@docs = docs
|
128
|
+
end
|
129
|
+
|
130
|
+
def docs
|
131
|
+
@docs.map { |d| GptTranslate::FakeDocument.new(d) }
|
132
|
+
end
|
133
|
+
end
|
data/test/test_generator.rb
CHANGED
@@ -33,98 +33,11 @@ require_relative '../lib/jekyll-chatgpt-translate/generator'
|
|
33
33
|
# Copyright:: Copyright (c) 2023 Yegor Bugayenko
|
34
34
|
# License:: MIT
|
35
35
|
class GptTranslate::GeneratorTest < Minitest::Test
|
36
|
-
class FakeSite
|
37
|
-
attr_reader :config, :pages
|
38
|
-
|
39
|
-
def initialize(config, docs)
|
40
|
-
@config = config
|
41
|
-
@docs = docs
|
42
|
-
@pages = []
|
43
|
-
end
|
44
|
-
|
45
|
-
def posts
|
46
|
-
FakePosts.new(@docs)
|
47
|
-
end
|
48
|
-
|
49
|
-
def permalink_style
|
50
|
-
''
|
51
|
-
end
|
52
|
-
|
53
|
-
def frontmatter_defaults
|
54
|
-
Jekyll::FrontmatterDefaults.new(self)
|
55
|
-
end
|
56
|
-
|
57
|
-
def converters
|
58
|
-
[Jekyll::Converters::Markdown.new({ 'markdown_ext' => 'md' })]
|
59
|
-
end
|
60
|
-
|
61
|
-
def source
|
62
|
-
''
|
63
|
-
end
|
64
|
-
|
65
|
-
def dest
|
66
|
-
File.dirname(@docs[0])
|
67
|
-
end
|
68
|
-
|
69
|
-
def in_theme_dir(base, _foo = nil, _bar = nil)
|
70
|
-
base
|
71
|
-
end
|
72
|
-
|
73
|
-
def in_dest_dir(*paths)
|
74
|
-
paths[0].dup
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class FakeDocument
|
79
|
-
attr_reader :data
|
80
|
-
|
81
|
-
def initialize(path)
|
82
|
-
@path = path
|
83
|
-
@data = { 'date' => Time.now, 'title' => 'Hello!' }
|
84
|
-
end
|
85
|
-
|
86
|
-
def content
|
87
|
-
'Hello, world!'
|
88
|
-
end
|
89
|
-
|
90
|
-
def []=(key, value)
|
91
|
-
@data[key] = value
|
92
|
-
end
|
93
|
-
|
94
|
-
def [](key)
|
95
|
-
@data[key] || ''
|
96
|
-
end
|
97
|
-
|
98
|
-
def relative_path
|
99
|
-
@path
|
100
|
-
end
|
101
|
-
|
102
|
-
def url
|
103
|
-
'2023-01-01-hello.html'
|
104
|
-
end
|
105
|
-
|
106
|
-
def basename
|
107
|
-
'2023-01-01-hello.md'
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
class FakePosts
|
112
|
-
attr_reader :config
|
113
|
-
|
114
|
-
def initialize(docs)
|
115
|
-
@docs = docs
|
116
|
-
end
|
117
|
-
|
118
|
-
def docs
|
119
|
-
@docs.map { |d| FakeDocument.new(d) }
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
36
|
def test_simple_scenario
|
124
37
|
Dir.mktmpdir do |home|
|
125
38
|
post = File.join(home, '2023-01-01-hello.md')
|
126
39
|
File.write(post, "---\ntitle: Hello\n---\n\nHello, world!")
|
127
|
-
site = FakeSite.new(
|
40
|
+
site = GptTranslate::FakeSite.new(
|
128
41
|
{
|
129
42
|
'url' => 'https://www.yegor256.com/',
|
130
43
|
'chatgpt-translate' => {
|
@@ -150,7 +63,7 @@ class GptTranslate::GeneratorTest < Minitest::Test
|
|
150
63
|
Dir.mktmpdir do |home|
|
151
64
|
post = File.join(home, '2023-01-01-hello.md')
|
152
65
|
File.write(post, "---\ntitle: Hello\n---\n\nHello, world!")
|
153
|
-
site = FakeSite.new(
|
66
|
+
site = GptTranslate::FakeSite.new(
|
154
67
|
{
|
155
68
|
'chatgpt-translate' => {
|
156
69
|
'threshold' => 1,
|
data/test/test_ping.rb
CHANGED
@@ -34,39 +34,28 @@ require_relative '../lib/jekyll-chatgpt-translate/ping'
|
|
34
34
|
# Copyright:: Copyright (c) 2023 Yegor Bugayenko
|
35
35
|
# License:: MIT
|
36
36
|
class GptTranslate::PingTest < Minitest::Test
|
37
|
-
class FakeSite
|
38
|
-
attr_reader :config
|
39
|
-
|
40
|
-
def initialize(config)
|
41
|
-
@config = config
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
37
|
def test_when_exists
|
46
|
-
stub_request(:any, 'https://www.yegor256.com/about-me.html')
|
47
|
-
site = FakeSite.new({ 'url' => 'https://www.yegor256.com/' })
|
38
|
+
stub_request(:any, 'https://www.yegor256.com/about-me.html').to_return(body: 'Hello!')
|
39
|
+
site = GptTranslate::FakeSite.new({ 'url' => 'https://www.yegor256.com/' })
|
48
40
|
ping = GptTranslate::Ping.new(site, '/about-me.html')
|
49
|
-
|
50
|
-
|
51
|
-
end
|
41
|
+
assert(ping.found?(''))
|
42
|
+
assert_equal(1, site.static_files.size)
|
52
43
|
end
|
53
44
|
|
54
45
|
def test_when_not_exists
|
55
46
|
stub_request(:any, 'https://www.yegor256.com/absent.html').to_return(status: 404)
|
56
|
-
site = FakeSite.new({ 'url' => 'https://www.yegor256.com/' })
|
47
|
+
site = GptTranslate::FakeSite.new({ 'url' => 'https://www.yegor256.com/' })
|
57
48
|
ping = GptTranslate::Ping.new(site, '/absent.html')
|
58
|
-
|
59
|
-
|
60
|
-
end
|
49
|
+
assert(!ping.found?(''))
|
50
|
+
assert_equal(0, site.static_files.size)
|
61
51
|
end
|
62
52
|
|
63
53
|
def test_wrong_address
|
64
54
|
WebMock.allow_net_connect!
|
65
|
-
site = FakeSite.new({ 'url' => 'https://localhost:1/' })
|
55
|
+
site = GptTranslate::FakeSite.new({ 'url' => 'https://localhost:1/' })
|
66
56
|
ping = GptTranslate::Ping.new(site, '/boom.html')
|
67
|
-
|
68
|
-
|
69
|
-
end
|
57
|
+
assert(!ping.found?(''))
|
58
|
+
assert_equal(0, site.static_files.size)
|
70
59
|
end
|
71
60
|
|
72
61
|
def test_relative_path
|