jekyll-chatgpt-translate 0.1.0 → 0.3.0
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/.0pdd.yml +1 -1
- data/.github/workflows/actionlint.yml +2 -2
- data/.github/workflows/copyrights.yml +2 -2
- data/.github/workflows/markdown-lint.yml +3 -3
- data/.github/workflows/pdd.yml +2 -2
- data/.github/workflows/rake.yml +2 -2
- data/.github/workflows/reuse.yml +2 -2
- data/.github/workflows/typos.yml +19 -0
- data/.github/workflows/xcop.yml +2 -2
- data/.github/workflows/yamllint.yml +2 -2
- data/.gitignore +4 -4
- data/.rubocop.yml +2 -1
- data/.rultor.yml +1 -1
- data/Gemfile +7 -6
- data/LICENSE.txt +1 -1
- data/LICENSES/MIT.txt +1 -1
- data/README.md +25 -25
- data/REUSE.toml +7 -7
- data/Rakefile +1 -1
- data/features/cli.feature +1 -1
- data/features/gem_package.feature +1 -1
- data/features/step_definitions/steps.rb +1 -1
- data/features/support/env.rb +1 -1
- data/jekyll-chatgpt-translate.gemspec +12 -10
- data/lib/jekyll-chatgpt-translate/chatgpt.rb +33 -33
- data/lib/jekyll-chatgpt-translate/generator.rb +90 -88
- data/lib/jekyll-chatgpt-translate/pars.rb +2 -2
- data/lib/jekyll-chatgpt-translate/permalink.rb +2 -2
- data/lib/jekyll-chatgpt-translate/ping.rb +2 -2
- data/lib/jekyll-chatgpt-translate/plain.rb +2 -2
- data/lib/jekyll-chatgpt-translate/prompt.rb +2 -2
- data/lib/jekyll-chatgpt-translate/version.rb +2 -2
- data/lib/jekyll-chatgpt-translate.rb +1 -1
- data/test/test__helper.rb +5 -4
- data/test/test_chatgpt.rb +2 -2
- data/test/test_generator.rb +2 -2
- data/test/test_pars.rb +2 -2
- data/test/test_permalink.rb +2 -2
- data/test/test_ping.rb +2 -2
- data/test/test_plain.rb +2 -2
- data/test/test_prompt.rb +2 -2
- metadata +67 -32
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a33656cc2e5c82d51feb6cb2900c339cce6f210bbe9615dd19756f457ace47c7
|
|
4
|
+
data.tar.gz: 2867d144dfa9e867a6bbecce340a1d77eb908a54c9790fbef9f7985223861250
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 370cf4f063e237ab00af98e0212b738211d33f868e24c89547a4b378f867389ff46c6dfce39ac90553e25e448751490b8c465382d5a6ffdefb6aa8bca59b6826
|
|
7
|
+
data.tar.gz: beafec1d47ac6b1f731d9557de276c7ce4d9b9223a6a19e3791e7b9555cf2d3950501e99d77bc92c54501a0c8b8d4ba21710cb35102ad4a932430330c32b6795
|
data/.0pdd.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
timeout-minutes: 15
|
|
16
16
|
runs-on: ubuntu-24.04
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
19
|
- name: Download actionlint
|
|
20
20
|
id: get_actionlint
|
|
21
21
|
run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -15,5 +15,5 @@ jobs:
|
|
|
15
15
|
timeout-minutes: 15
|
|
16
16
|
runs-on: ubuntu-24.04
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
19
|
- uses: yegor256/copyrights-action@0.0.8
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -19,5 +19,5 @@ jobs:
|
|
|
19
19
|
timeout-minutes: 15
|
|
20
20
|
runs-on: ubuntu-24.04
|
|
21
21
|
steps:
|
|
22
|
-
- uses: actions/checkout@
|
|
23
|
-
- uses:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
- uses: DavidAnson/markdownlint-cli2-action@v20.0.0
|
data/.github/workflows/pdd.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -15,5 +15,5 @@ jobs:
|
|
|
15
15
|
timeout-minutes: 15
|
|
16
16
|
runs-on: ubuntu-24.04
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
19
|
- uses: volodya-lombrozo/pdd-action@master
|
data/.github/workflows/rake.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
ruby: [3.3]
|
|
19
19
|
runs-on: ${{ matrix.os }}
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
22
|
- uses: ruby/setup-ruby@v1
|
|
23
23
|
with:
|
|
24
24
|
ruby-version: ${{ matrix.ruby }}
|
data/.github/workflows/reuse.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -15,5 +15,5 @@ jobs:
|
|
|
15
15
|
timeout-minutes: 15
|
|
16
16
|
runs-on: ubuntu-24.04
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
19
|
- uses: fsfe/reuse-action@v5
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
---
|
|
4
|
+
# yamllint disable rule:line-length
|
|
5
|
+
name: typos
|
|
6
|
+
'on':
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- master
|
|
10
|
+
pull_request:
|
|
11
|
+
branches:
|
|
12
|
+
- master
|
|
13
|
+
jobs:
|
|
14
|
+
typos:
|
|
15
|
+
timeout-minutes: 15
|
|
16
|
+
runs-on: ubuntu-24.04
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
|
+
- uses: crate-ci/typos@v1.32.0
|
data/.github/workflows/xcop.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -15,5 +15,5 @@ jobs:
|
|
|
15
15
|
timeout-minutes: 15
|
|
16
16
|
runs-on: ubuntu-24.04
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
19
|
- uses: g4s8/xcop-action@master
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
# yamllint disable rule:line-length
|
|
@@ -15,5 +15,5 @@ jobs:
|
|
|
15
15
|
timeout-minutes: 15
|
|
16
16
|
runs-on: ubuntu-24.04
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
19
|
- uses: ibiqlik/action-yamllint@v3
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
---
|
|
4
4
|
AllCops:
|
|
@@ -48,3 +48,4 @@ Metrics/ClassLength:
|
|
|
48
48
|
Max: 200
|
|
49
49
|
Style/ClassVars:
|
|
50
50
|
Enabled: false
|
|
51
|
+
require: []
|
data/.rultor.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
source 'https://rubygems.org'
|
|
@@ -8,13 +8,14 @@ gemspec
|
|
|
8
8
|
|
|
9
9
|
gem 'cucumber', '~>9.2', require: false
|
|
10
10
|
gem 'kramdown-parser-gfm', '~>1.1', require: false
|
|
11
|
-
gem 'minitest', '~>
|
|
11
|
+
gem 'minitest', '~>6.0', require: false
|
|
12
12
|
gem 'minitest-reporters', '~>1.7', require: false
|
|
13
13
|
gem 'rake', '~>13.2', require: false
|
|
14
|
+
gem 'rdoc', '~>7.0', require: false
|
|
14
15
|
gem 'rubocop', '~>1.64', require: false
|
|
15
|
-
gem 'rubocop-minitest', '
|
|
16
|
-
gem 'rubocop-performance', '>
|
|
17
|
-
gem 'rubocop-rake', '
|
|
16
|
+
gem 'rubocop-minitest', '~>0.38', require: false
|
|
17
|
+
gem 'rubocop-performance', '>1.26', require: false
|
|
18
|
+
gem 'rubocop-rake', '~>0.7', require: false
|
|
18
19
|
gem 'simplecov', '~>0.22', require: false
|
|
19
|
-
gem 'simplecov-cobertura', '~>
|
|
20
|
+
gem 'simplecov-cobertura', '~>3.1', require: false
|
|
20
21
|
gem 'webmock', '~>3.24', require: false
|
data/LICENSE.txt
CHANGED
data/LICENSES/MIT.txt
CHANGED
data/README.md
CHANGED
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
[](https://badge.fury.io/rb/jekyll-chatgpt-translate)
|
|
7
7
|
|
|
8
8
|
If you have a [Jekyll](https://jekyllrb.com/) static site,
|
|
9
|
-
this plugin may help you automatically
|
|
10
|
-
translate its pages to another language, through
|
|
11
|
-
[ChatGPT](https://chat.openai.com/).
|
|
12
|
-
works for [my blog](https://github.com/yegor256/ru.yegor256.com),
|
|
13
|
-
for example [this page](https://ru.yegor256.com/2023-08-13-dictators.html)
|
|
14
|
-
is translated to
|
|
15
|
-
[English](https://www.yegor256.com/en/2023/08/13/dictators.html).
|
|
16
|
-
|
|
17
|
-
Install it first
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
this plugin may help you automatically
|
|
10
|
+
translate its pages to another language, through
|
|
11
|
+
[ChatGPT](https://chat.openai.com/).
|
|
12
|
+
See how it works for [my blog](https://github.com/yegor256/ru.yegor256.com),
|
|
13
|
+
for example [this page](https://ru.yegor256.com/2023-08-13-dictators.html)
|
|
14
|
+
is translated to
|
|
15
|
+
[English](https://www.yegor256.com/en/2023/08/13/dictators.html).
|
|
16
|
+
|
|
17
|
+
Install it first
|
|
18
|
+
(you need
|
|
19
|
+
[Ruby 3+](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/)
|
|
20
|
+
and [Jekyll 3+](https://jekyllrb.com/)):
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
23
|
gem install jekyll-chatgpt-translate
|
|
@@ -49,29 +50,28 @@ where the layout for Chinese is `_layout/chinese-translated.html` and for
|
|
|
49
50
|
French is `_layout/translated.html` (you must have these files).
|
|
50
51
|
|
|
51
52
|
OpenAI API KEY must be set in the `OPENAI_API_KEY` environment variable,
|
|
52
|
-
otherwise
|
|
53
|
-
|
|
54
|
-
You can get your key
|
|
55
|
-
[here][open-ai].
|
|
53
|
+
otherwise the plugin will not do any translation
|
|
54
|
+
and won't generate translated pages.
|
|
55
|
+
You can get your key go to [OpenAI][open-ai].
|
|
56
56
|
|
|
57
57
|
OpenAI API base URL can be customized by the `OPENAI_API_BASE`
|
|
58
|
-
environment variable.
|
|
58
|
+
environment variable.
|
|
59
59
|
If this variable is not set, the default value is `https://api.openai.com/`.
|
|
60
60
|
|
|
61
61
|
Inside the original page you can use `{{ page.chatgpt-translate.urls[XX] }}`
|
|
62
|
-
in order to render the URL
|
|
63
|
-
of the translated page, where `XX` is the [ISO-639-1][iso-639]
|
|
64
|
-
code of the target language.
|
|
62
|
+
in order to render the URL
|
|
63
|
+
of the translated page, where `XX` is the [ISO-639-1][iso-639]
|
|
64
|
+
code of the target language.
|
|
65
65
|
Inside the translated page you can use
|
|
66
|
-
`{{ page.chatgpt-translate.original-url }}` in order
|
|
67
|
-
to get the URL of the page that was translated.
|
|
66
|
+
`{{ page.chatgpt-translate.original-url }}` in order
|
|
67
|
+
to get the URL of the page that was translated.
|
|
68
68
|
|
|
69
69
|
You can also use `{{ page.chatgpt-translate.model }}`
|
|
70
|
-
inside both the original page and the translated one,
|
|
71
|
-
to refer to the model of ChatGPT.
|
|
70
|
+
inside both the original page and the translated one,
|
|
71
|
+
to refer to the model of ChatGPT.
|
|
72
72
|
The presence of `{{ page.chatgpt-translate }}` means that the
|
|
73
|
-
page was translated or the translated HTML was downloaded
|
|
74
|
-
and placed into the `_site` directory.
|
|
73
|
+
page was translated or the translated HTML was downloaded
|
|
74
|
+
and placed into the `_site` directory.
|
|
75
75
|
|
|
76
76
|
## Options
|
|
77
77
|
|
data/REUSE.toml
CHANGED
|
@@ -4,10 +4,17 @@
|
|
|
4
4
|
version = 1
|
|
5
5
|
[[annotations]]
|
|
6
6
|
path = [
|
|
7
|
+
".DS_Store",
|
|
8
|
+
".gitattributes",
|
|
9
|
+
".gitignore",
|
|
10
|
+
".pdd",
|
|
7
11
|
"**.json",
|
|
8
12
|
"**.md",
|
|
9
13
|
"**.png",
|
|
10
14
|
"**.txt",
|
|
15
|
+
"**/.DS_Store",
|
|
16
|
+
"**/.gitignore",
|
|
17
|
+
"**/.pdd",
|
|
11
18
|
"**/*.csv",
|
|
12
19
|
"**/*.jpg",
|
|
13
20
|
"**/*.json",
|
|
@@ -17,15 +24,8 @@ path = [
|
|
|
17
24
|
"**/*.svg",
|
|
18
25
|
"**/*.txt",
|
|
19
26
|
"**/*.vm",
|
|
20
|
-
"**/.DS_Store",
|
|
21
|
-
"**/.gitignore",
|
|
22
|
-
"**/.pdd",
|
|
23
27
|
"**/CNAME",
|
|
24
28
|
"**/Gemfile.lock",
|
|
25
|
-
".DS_Store",
|
|
26
|
-
".gitattributes",
|
|
27
|
-
".gitignore",
|
|
28
|
-
".pdd",
|
|
29
29
|
"Gemfile.lock",
|
|
30
30
|
"README.md",
|
|
31
31
|
"renovate.json",
|
data/Rakefile
CHANGED
data/features/cli.feature
CHANGED
data/features/support/env.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'English'
|
|
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
|
9
9
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
|
10
10
|
s.required_ruby_version = '>= 3.0'
|
|
11
11
|
s.name = 'jekyll-chatgpt-translate'
|
|
12
|
-
s.version = '0.
|
|
12
|
+
s.version = '0.3.0'
|
|
13
13
|
s.license = 'MIT'
|
|
14
14
|
s.summary = 'Translate Jekyll Pages Through ChatGPT'
|
|
15
15
|
s.description = [
|
|
@@ -23,13 +23,15 @@ Gem::Specification.new do |s|
|
|
|
23
23
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
24
24
|
s.rdoc_options = ['--charset=UTF-8']
|
|
25
25
|
s.extra_rdoc_files = %w[README.md LICENSE.txt]
|
|
26
|
-
s.add_dependency '
|
|
27
|
-
s.add_dependency '
|
|
28
|
-
s.add_dependency '
|
|
29
|
-
s.add_dependency '
|
|
30
|
-
s.add_dependency '
|
|
31
|
-
s.add_dependency '
|
|
32
|
-
s.add_dependency '
|
|
33
|
-
s.add_dependency '
|
|
26
|
+
s.add_dependency 'base64', '~>0.3'
|
|
27
|
+
s.add_dependency 'elapsed', '~>0.2'
|
|
28
|
+
s.add_dependency 'humanize', '~>3.1'
|
|
29
|
+
s.add_dependency 'iri', '~>0.11'
|
|
30
|
+
s.add_dependency 'iso-639', '~>0.3'
|
|
31
|
+
s.add_dependency 'jekyll', '>= 3.0', '< 5.0'
|
|
32
|
+
s.add_dependency 'json', '~>2.18'
|
|
33
|
+
s.add_dependency 'redcarpet', '~>3.6'
|
|
34
|
+
s.add_dependency 'ruby-openai', '~>8.3'
|
|
35
|
+
s.add_dependency 'tiktoken_ruby', '~>0.0'
|
|
34
36
|
s.metadata['rubygems_mfa_required'] = 'true'
|
|
35
37
|
end
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
+
require 'elapsed'
|
|
7
|
+
require 'iso-639'
|
|
6
8
|
require 'jekyll'
|
|
7
9
|
require 'json'
|
|
8
10
|
require 'openai'
|
|
9
|
-
require 'iso-639'
|
|
10
11
|
require 'tiktoken_ruby'
|
|
11
12
|
require_relative 'pars'
|
|
12
13
|
require_relative 'prompt'
|
|
@@ -16,7 +17,7 @@ module GptTranslate; end
|
|
|
16
17
|
|
|
17
18
|
# Abstraction of ChatGPT.
|
|
18
19
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
19
|
-
# Copyright:: Copyright (c) 2023-
|
|
20
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
20
21
|
# License:: MIT
|
|
21
22
|
class GptTranslate::ChatGPT
|
|
22
23
|
# Is TRUE if we already shown to the user the available models.
|
|
@@ -72,7 +73,7 @@ class GptTranslate::ChatGPT
|
|
|
72
73
|
ready[i] = "* #{translate_par(par[2..])}"
|
|
73
74
|
elsif /^[0-9]+\. /.match?(par)
|
|
74
75
|
ready[i] = "1. #{translate_par(par.split('.', 2)[1])}"
|
|
75
|
-
elsif /^[^\p{Alnum}
|
|
76
|
+
elsif /^[^\p{Alnum}*'"\[]/.match?(par)
|
|
76
77
|
Jekyll.logger.debug("Not translating this, b/c it's not a plain text: #{par.inspect}")
|
|
77
78
|
ready[i] = par
|
|
78
79
|
else
|
|
@@ -115,40 +116,39 @@ class GptTranslate::ChatGPT
|
|
|
115
116
|
@@models_printed = true
|
|
116
117
|
end
|
|
117
118
|
prompt = GptTranslate::Prompt.new(par, @source, @target).to_s
|
|
118
|
-
start = Time.now
|
|
119
119
|
answer = nil
|
|
120
120
|
attempt = 0
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
json = response.is_a?(Hash) ? response : JSON.parse(response)
|
|
130
|
-
answer = json.dig('choices', 0, 'message', 'content')
|
|
131
|
-
if answer.nil?
|
|
132
|
-
Jekyll.logger.error("No content returned by ChatGPT: #{response}")
|
|
133
|
-
raise 'No content returned by ChatGPT'
|
|
134
|
-
end
|
|
135
|
-
Jekyll.logger.debug("ChatGPT prompt: #{prompt.inspect}, ChatGPT answer: #{answer.inspect}")
|
|
136
|
-
rescue StandardError => e
|
|
137
|
-
attempt += 1
|
|
138
|
-
if attempt < 4
|
|
139
|
-
Jekyll.logger.error(
|
|
140
|
-
"ChatGPT failed to answer to #{prompt.inspect}" \
|
|
141
|
-
"(attempt no.#{attempt}): #{e.message.inspect}"
|
|
121
|
+
elapsed(Jekyll.logger) do
|
|
122
|
+
begin
|
|
123
|
+
response = @client.chat(
|
|
124
|
+
parameters: {
|
|
125
|
+
model: @model,
|
|
126
|
+
messages: [{ role: 'user', content: prompt }],
|
|
127
|
+
temperature: 0.7
|
|
128
|
+
}
|
|
142
129
|
)
|
|
143
|
-
|
|
130
|
+
json = response.is_a?(Hash) ? response : JSON.parse(response)
|
|
131
|
+
answer = json.dig('choices', 0, 'message', 'content')
|
|
132
|
+
if answer.nil?
|
|
133
|
+
Jekyll.logger.error("No content returned by ChatGPT: #{response}")
|
|
134
|
+
raise 'No content returned by ChatGPT'
|
|
135
|
+
end
|
|
136
|
+
Jekyll.logger.debug("ChatGPT prompt: #{prompt.inspect}, ChatGPT answer: #{answer.inspect}")
|
|
137
|
+
rescue StandardError => e
|
|
138
|
+
attempt += 1
|
|
139
|
+
if attempt < 4
|
|
140
|
+
Jekyll.logger.error(
|
|
141
|
+
"ChatGPT failed to answer to #{prompt.inspect}" \
|
|
142
|
+
"(attempt no.#{attempt}): #{e.message.inspect}"
|
|
143
|
+
)
|
|
144
|
+
retry
|
|
145
|
+
end
|
|
146
|
+
raise e
|
|
144
147
|
end
|
|
145
|
-
|
|
148
|
+
throw :"Translated #{par.split.count} #{@source.upcase} words \
|
|
149
|
+
to #{answer.split.count} #{@target.upcase} words \
|
|
150
|
+
through #{@model}: #{"#{par[0..24]}...".inspect}"
|
|
146
151
|
end
|
|
147
|
-
Jekyll.logger.info(
|
|
148
|
-
"Translated #{par.split.count} #{@source.upcase} words " \
|
|
149
|
-
"to #{answer.split.count} #{@target.upcase} words " \
|
|
150
|
-
"through #{@model} in #{(Time.now - start).round(2)}s: #{"#{par[0..24]}...".inspect}"
|
|
151
|
-
)
|
|
152
152
|
answer
|
|
153
153
|
end
|
|
154
154
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
require '
|
|
6
|
+
require 'elapsed'
|
|
7
7
|
require 'fileutils'
|
|
8
|
+
require 'jekyll'
|
|
8
9
|
require 'json'
|
|
9
10
|
require_relative 'chatgpt'
|
|
10
11
|
require_relative 'permalink'
|
|
@@ -17,7 +18,7 @@ module GptTranslate; end
|
|
|
17
18
|
|
|
18
19
|
# Pages generator.
|
|
19
20
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
20
|
-
# Copyright:: Copyright (c) 2023-
|
|
21
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
21
22
|
# License:: MIT
|
|
22
23
|
class GptTranslate::Generator < Jekyll::Generator
|
|
23
24
|
safe true
|
|
@@ -29,7 +30,7 @@ class GptTranslate::Generator < Jekyll::Generator
|
|
|
29
30
|
Jekyll.logger.info("jekyll-chatgpt-translate #{GptTranslate::VERSION} skipped, due to the --offline option")
|
|
30
31
|
return
|
|
31
32
|
end
|
|
32
|
-
Jekyll.logger.info("jekyll-chatgpt-translate #{GptTranslate::VERSION}
|
|
33
|
+
Jekyll.logger.info("jekyll-chatgpt-translate #{GptTranslate::VERSION} starts (no --offline option)...")
|
|
33
34
|
config ||= site.config['chatgpt-translate'] || {}
|
|
34
35
|
home = config['tmpdir'] || '_chatgpt-translate'
|
|
35
36
|
key = api_key(config)
|
|
@@ -41,101 +42,100 @@ class GptTranslate::Generator < Jekyll::Generator
|
|
|
41
42
|
version = config['version'] || GptTranslate::VERSION
|
|
42
43
|
threshold = config['threshold'] || 1024
|
|
43
44
|
min_chars = config['min_chars'] || 128
|
|
44
|
-
start = Time.now
|
|
45
45
|
translated = 0
|
|
46
46
|
copied = 0
|
|
47
47
|
model = config['model'] || 'gpt-3.5-turbo'
|
|
48
|
-
marker = "Translated by ChatGPT #{model}#{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
62
|
-
path = File.join(home, lang, doc.basename.gsub(/\.md$/, "-#{lang}.md"))
|
|
63
|
-
FileUtils.mkdir_p(File.dirname(path))
|
|
64
|
-
File.write(
|
|
65
|
-
path,
|
|
66
|
-
[
|
|
67
|
-
'---',
|
|
68
|
-
"layout: #{target['layout'] || layout}",
|
|
69
|
-
"title: #{doc['title'].to_json}",
|
|
70
|
-
"description: #{doc['description'].to_json}",
|
|
71
|
-
"permalink: #{link.to_json}",
|
|
72
|
-
'chatgpt-translate:',
|
|
73
|
-
" original-url: #{doc.url.to_json}",
|
|
74
|
-
" language: #{lang.to_json}",
|
|
75
|
-
" model: #{model.to_json}",
|
|
76
|
-
'---'
|
|
77
|
-
].join("\n")
|
|
78
|
-
)
|
|
79
|
-
html = config['no_download'].nil? ? GptTranslate::Ping.new(site, link).download : nil
|
|
80
|
-
needed = false
|
|
81
|
-
added = false
|
|
82
|
-
if html.nil?
|
|
83
|
-
Jekyll.logger.info("The page is absent, need to translate #{link.inspect}")
|
|
84
|
-
needed = true
|
|
85
|
-
else
|
|
86
|
-
copied += 1
|
|
87
|
-
site.static_files << DownloadedFile.new(site, link, html)
|
|
88
|
-
added = true
|
|
89
|
-
if version.empty?
|
|
90
|
-
Jekyll.logger.info("Re-translation not required, since version is empty: #{link.inspect}")
|
|
91
|
-
elsif html.include?(marker)
|
|
92
|
-
Jekyll.logger.info("No need to translate, the page exists at \
|
|
93
|
-
#{link.inspect} (#{html.split.count} words)")
|
|
94
|
-
else
|
|
95
|
-
Jekyll.logger.info("Re-translation required for #{link.inspect}")
|
|
96
|
-
needed = true
|
|
48
|
+
marker = "Translated by ChatGPT #{model}#{"/#{version}" unless version.empty?}"
|
|
49
|
+
elapsed(Jekyll.logger) do
|
|
50
|
+
site.posts.docs.shuffle.each_with_index do |doc, pos|
|
|
51
|
+
plain = GptTranslate::Plain.new(doc.content).to_s
|
|
52
|
+
layout = doc['layout']
|
|
53
|
+
config['targets'].each do |target|
|
|
54
|
+
link = GptTranslate::Permalink.new(doc, target['permalink']).to_path
|
|
55
|
+
lang = target['language']
|
|
56
|
+
raise 'Language must be defined for each target' if target.nil?
|
|
57
|
+
only = target['only']
|
|
58
|
+
if !only.nil? && layout != only
|
|
59
|
+
Jekyll.logger.debug("Not translating #{link.inspect}, b/c 'only' set to '#{only}'")
|
|
60
|
+
next
|
|
97
61
|
end
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Jekyll.logger.info("Page ##{pos} is ignored, we are over the threshold of #{threshold}: #{link}")
|
|
101
|
-
elsif needed
|
|
102
|
-
gpt = GptTranslate::ChatGPT.new(
|
|
103
|
-
key,
|
|
104
|
-
model,
|
|
105
|
-
target['source'] || config['source'] || 'en',
|
|
106
|
-
lang
|
|
107
|
-
)
|
|
108
|
-
foreign = gpt.translate(
|
|
109
|
-
plain,
|
|
110
|
-
min: min_chars,
|
|
111
|
-
window_length: (config['window_length'] || '2048').to_i
|
|
112
|
-
)
|
|
62
|
+
path = File.join(home, lang, doc.basename.gsub(/\.md$/, "-#{lang}.md"))
|
|
63
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
113
64
|
File.write(
|
|
114
65
|
path,
|
|
115
66
|
[
|
|
116
|
-
'',
|
|
117
|
-
|
|
118
|
-
'',
|
|
119
|
-
"
|
|
120
|
-
|
|
121
|
-
|
|
67
|
+
'---',
|
|
68
|
+
"layout: #{target['layout'] || layout}",
|
|
69
|
+
"title: #{doc['title'].to_json}",
|
|
70
|
+
"description: #{doc['description'].to_json}",
|
|
71
|
+
"permalink: #{link.to_json}",
|
|
72
|
+
'chatgpt-translate:',
|
|
73
|
+
" original-url: #{doc.url.to_json}",
|
|
74
|
+
" language: #{lang.to_json}",
|
|
75
|
+
" model: #{model.to_json}",
|
|
76
|
+
'---'
|
|
77
|
+
].join("\n")
|
|
122
78
|
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
added =
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
79
|
+
html = config['no_download'].nil? ? GptTranslate::Ping.new(site, link).download : nil
|
|
80
|
+
needed = false
|
|
81
|
+
added = false
|
|
82
|
+
if html.nil?
|
|
83
|
+
Jekyll.logger.info("The page is absent, need to translate #{link.inspect}")
|
|
84
|
+
needed = true
|
|
85
|
+
else
|
|
86
|
+
copied += 1
|
|
87
|
+
site.static_files << DownloadedFile.new(site, link, html)
|
|
88
|
+
added = true
|
|
89
|
+
if version.empty?
|
|
90
|
+
Jekyll.logger.info("Re-translation not required, since version is empty: #{link.inspect}")
|
|
91
|
+
elsif html.include?(marker)
|
|
92
|
+
Jekyll.logger.info("The page exists at #{link.inspect} (#{html.split.count} words)")
|
|
93
|
+
else
|
|
94
|
+
Jekyll.logger.info("Re-translation required for #{link.inspect}")
|
|
95
|
+
needed = true
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
if translated >= threshold
|
|
99
|
+
Jekyll.logger.info("Page ##{pos} is ignored, we are over the threshold of #{threshold}: #{link}")
|
|
100
|
+
elsif needed
|
|
101
|
+
elapsed(Jekyll.logger) do
|
|
102
|
+
gpt = GptTranslate::ChatGPT.new(
|
|
103
|
+
key,
|
|
104
|
+
model,
|
|
105
|
+
target['source'] || config['source'] || 'en',
|
|
106
|
+
lang
|
|
107
|
+
)
|
|
108
|
+
foreign = gpt.translate(
|
|
109
|
+
plain,
|
|
110
|
+
min: min_chars,
|
|
111
|
+
window_length: (config['window_length'] || '2048').to_i
|
|
112
|
+
)
|
|
113
|
+
File.write(
|
|
114
|
+
path,
|
|
115
|
+
[
|
|
116
|
+
'',
|
|
117
|
+
foreign,
|
|
118
|
+
'',
|
|
119
|
+
"#{marker} on #{Time.now.strftime('%Y-%m-%d at %H:%M')}\n{: .jekyll-chatgpt-translate}"
|
|
120
|
+
].join("\n"),
|
|
121
|
+
mode: 'a+'
|
|
122
|
+
)
|
|
123
|
+
site.pages << Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path))
|
|
124
|
+
site.static_files.delete_if { |f| f.is_a?(DownloadedFile) && f.link == link }
|
|
125
|
+
added = true
|
|
126
|
+
translated += 1
|
|
127
|
+
throw :"Translated via ChatGPT #{path} (#{File.size(path)} bytes)"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
next unless added
|
|
131
|
+
doc.data['chatgpt-translate'] ||= {}
|
|
132
|
+
doc.data['chatgpt-translate']['model'] ||= model
|
|
133
|
+
doc.data['chatgpt-translate']['urls'] ||= {}
|
|
134
|
+
doc.data['chatgpt-translate']['urls'][lang] = link
|
|
129
135
|
end
|
|
130
|
-
next unless added
|
|
131
|
-
doc.data['chatgpt-translate'] ||= {}
|
|
132
|
-
doc.data['chatgpt-translate']['model'] ||= model
|
|
133
|
-
doc.data['chatgpt-translate']['urls'] ||= {}
|
|
134
|
-
doc.data['chatgpt-translate']['urls'][lang] = link
|
|
135
136
|
end
|
|
137
|
+
throw :"#{translated} page(s) translated and #{copied} page(s) copied"
|
|
136
138
|
end
|
|
137
|
-
Jekyll.logger.info("jekyll-chatgpt-translate #{GptTranslate::VERSION}: \
|
|
138
|
-
#{translated} pages translated and #{copied} pages copied in #{(Time.now - start).round(2)}s")
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
# The file we just downloaded.
|
|
@@ -148,12 +148,14 @@ in #{(Time.now - pstart).round(2)}s: #{path} (#{File.size(path)} bytes)")
|
|
|
148
148
|
@link = link
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
+
# rubocop:disable Naming/PredicateMethod
|
|
151
152
|
def write(_dest)
|
|
152
153
|
FileUtils.mkdir_p(File.dirname(path))
|
|
153
154
|
File.write(path, @html)
|
|
154
155
|
Jekyll.logger.info("Saved #{@html.split.count} words to #{path.inspect}")
|
|
155
156
|
true
|
|
156
157
|
end
|
|
158
|
+
# rubocop:enable Naming/PredicateMethod
|
|
157
159
|
end
|
|
158
160
|
|
|
159
161
|
private
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
# The module we are in.
|
|
@@ -8,7 +8,7 @@ module GptTranslate; end
|
|
|
8
8
|
|
|
9
9
|
# Markdown broken down ito pars.
|
|
10
10
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
11
|
-
# Copyright:: Copyright (c) 2023-
|
|
11
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
12
12
|
# License:: MIT
|
|
13
13
|
class GptTranslate::Pars
|
|
14
14
|
# Ctor.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'cgi'
|
|
@@ -10,7 +10,7 @@ module GptTranslate; end
|
|
|
10
10
|
|
|
11
11
|
# Permalink.
|
|
12
12
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
13
|
-
# Copyright:: Copyright (c) 2023-
|
|
13
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
14
14
|
# License:: MIT
|
|
15
15
|
class GptTranslate::Permalink
|
|
16
16
|
def initialize(doc, template)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'iri'
|
|
@@ -17,7 +17,7 @@ module GptTranslate; end
|
|
|
17
17
|
|
|
18
18
|
# Ping one page of a site.
|
|
19
19
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
20
|
-
# Copyright:: Copyright (c) 2023-
|
|
20
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
21
21
|
# License:: MIT
|
|
22
22
|
class GptTranslate::Ping
|
|
23
23
|
# Ctor.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'redcarpet'
|
|
@@ -10,7 +10,7 @@ module GptTranslate; end
|
|
|
10
10
|
|
|
11
11
|
# Markdown to plain text.
|
|
12
12
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
13
|
-
# Copyright:: Copyright (c) 2023-
|
|
13
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
14
14
|
# License:: MIT
|
|
15
15
|
class GptTranslate::Plain
|
|
16
16
|
# Ctor.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'iso-639'
|
|
@@ -11,7 +11,7 @@ module GptTranslate; end
|
|
|
11
11
|
|
|
12
12
|
# Prompt for ChatGPT.
|
|
13
13
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
14
|
-
# Copyright:: Copyright (c) 2023-
|
|
14
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
15
15
|
# License:: MIT
|
|
16
16
|
class GptTranslate::Prompt
|
|
17
17
|
# Ctor.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
module GptTranslate
|
|
7
|
-
VERSION = '0.
|
|
7
|
+
VERSION = '0.3.0'
|
|
8
8
|
end
|
data/test/test__helper.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
$stdout.sync = true
|
|
@@ -28,6 +28,7 @@ end
|
|
|
28
28
|
|
|
29
29
|
require 'minitest/reporters'
|
|
30
30
|
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
|
|
31
|
+
Minitest.load :minitest_reporter
|
|
31
32
|
|
|
32
33
|
require 'minitest/autorun'
|
|
33
34
|
|
|
@@ -39,7 +40,7 @@ module GptTranslate; end
|
|
|
39
40
|
|
|
40
41
|
# Fake.
|
|
41
42
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
42
|
-
# Copyright:: Copyright (c) 2023-
|
|
43
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
43
44
|
# License:: MIT
|
|
44
45
|
class GptTranslate::FakeSite
|
|
45
46
|
attr_reader :config, :pages, :static_files
|
|
@@ -87,7 +88,7 @@ end
|
|
|
87
88
|
|
|
88
89
|
# Fake.
|
|
89
90
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
90
|
-
# Copyright:: Copyright (c) 2023-
|
|
91
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
91
92
|
# License:: MIT
|
|
92
93
|
class GptTranslate::FakeDocument
|
|
93
94
|
attr_reader :data
|
|
@@ -124,7 +125,7 @@ end
|
|
|
124
125
|
|
|
125
126
|
# Fake.
|
|
126
127
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
127
|
-
# Copyright:: Copyright (c) 2023-
|
|
128
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
128
129
|
# License:: MIT
|
|
129
130
|
class GptTranslate::FakePosts
|
|
130
131
|
attr_reader :config
|
data/test/test_chatgpt.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'webmock/minitest'
|
|
@@ -9,7 +9,7 @@ require_relative '../lib/jekyll-chatgpt-translate/chatgpt'
|
|
|
9
9
|
|
|
10
10
|
# ChatGPT test.
|
|
11
11
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
12
|
-
# Copyright:: Copyright (c) 2023-
|
|
12
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
13
13
|
# License:: MIT
|
|
14
14
|
class GptTranslate::ChatGPTTest < Minitest::Test
|
|
15
15
|
def test_short_text
|
data/test/test_generator.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'tmpdir'
|
|
@@ -10,7 +10,7 @@ require_relative '../lib/jekyll-chatgpt-translate/generator'
|
|
|
10
10
|
|
|
11
11
|
# Generator test.
|
|
12
12
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
13
|
-
# Copyright:: Copyright (c) 2023-
|
|
13
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
14
14
|
# License:: MIT
|
|
15
15
|
class GptTranslate::GeneratorTest < Minitest::Test
|
|
16
16
|
def test_simple_scenario
|
data/test/test_pars.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require_relative 'test__helper'
|
|
@@ -8,7 +8,7 @@ require_relative '../lib/jekyll-chatgpt-translate/pars'
|
|
|
8
8
|
|
|
9
9
|
# Test for Pars.
|
|
10
10
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
11
|
-
# Copyright:: Copyright (c) 2023-
|
|
11
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
12
12
|
# License:: MIT
|
|
13
13
|
class GptTranslate::ParsTest < Minitest::Test
|
|
14
14
|
def test_simple_cases
|
data/test/test_permalink.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require_relative 'test__helper'
|
|
@@ -8,7 +8,7 @@ require_relative '../lib/jekyll-chatgpt-translate/permalink'
|
|
|
8
8
|
|
|
9
9
|
# Permalink test.
|
|
10
10
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
11
|
-
# Copyright:: Copyright (c) 2023-
|
|
11
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
12
12
|
# License:: MIT
|
|
13
13
|
class GptTranslate::PermalinkTest < Minitest::Test
|
|
14
14
|
def test_simple_link
|
data/test/test_ping.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'webmock/minitest'
|
|
@@ -11,7 +11,7 @@ require_relative '../lib/jekyll-chatgpt-translate/ping'
|
|
|
11
11
|
|
|
12
12
|
# Ping test.
|
|
13
13
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
14
|
-
# Copyright:: Copyright (c) 2023-
|
|
14
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
15
15
|
# License:: MIT
|
|
16
16
|
class GptTranslate::PingTest < Minitest::Test
|
|
17
17
|
def test_when_exists
|
data/test/test_plain.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require_relative 'test__helper'
|
|
@@ -8,7 +8,7 @@ require_relative '../lib/jekyll-chatgpt-translate/plain'
|
|
|
8
8
|
|
|
9
9
|
# Plain test.
|
|
10
10
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
11
|
-
# Copyright:: Copyright (c) 2023-
|
|
11
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
12
12
|
# License:: MIT
|
|
13
13
|
class GptTranslate::PlainTest < Minitest::Test
|
|
14
14
|
def test_simple_map
|
data/test/test_prompt.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2023-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require_relative 'test__helper'
|
|
@@ -8,7 +8,7 @@ require_relative '../lib/jekyll-chatgpt-translate/prompt'
|
|
|
8
8
|
|
|
9
9
|
# Prompt test.
|
|
10
10
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
11
|
-
# Copyright:: Copyright (c) 2023-
|
|
11
|
+
# Copyright:: Copyright (c) 2023-2026 Yegor Bugayenko
|
|
12
12
|
# License:: MIT
|
|
13
13
|
class GptTranslate::PromptTest < Minitest::Test
|
|
14
14
|
def head(source, target)
|
metadata
CHANGED
|
@@ -1,127 +1,161 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-chatgpt-translate
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: base64
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.3'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.3'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: elapsed
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.2'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0.2'
|
|
13
41
|
- !ruby/object:Gem::Dependency
|
|
14
42
|
name: humanize
|
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
|
16
44
|
requirements:
|
|
17
|
-
- - "
|
|
45
|
+
- - "~>"
|
|
18
46
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
47
|
+
version: '3.1'
|
|
20
48
|
type: :runtime
|
|
21
49
|
prerelease: false
|
|
22
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
51
|
requirements:
|
|
24
|
-
- - "
|
|
52
|
+
- - "~>"
|
|
25
53
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
54
|
+
version: '3.1'
|
|
27
55
|
- !ruby/object:Gem::Dependency
|
|
28
56
|
name: iri
|
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
|
30
58
|
requirements:
|
|
31
|
-
- - "
|
|
59
|
+
- - "~>"
|
|
32
60
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
61
|
+
version: '0.11'
|
|
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: '0'
|
|
68
|
+
version: '0.11'
|
|
41
69
|
- !ruby/object:Gem::Dependency
|
|
42
70
|
name: iso-639
|
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
|
44
72
|
requirements:
|
|
45
|
-
- - "
|
|
73
|
+
- - "~>"
|
|
46
74
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0'
|
|
75
|
+
version: '0.3'
|
|
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: '0'
|
|
82
|
+
version: '0.3'
|
|
55
83
|
- !ruby/object:Gem::Dependency
|
|
56
84
|
name: jekyll
|
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
|
58
86
|
requirements:
|
|
59
87
|
- - ">="
|
|
60
88
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '3'
|
|
89
|
+
version: '3.0'
|
|
90
|
+
- - "<"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '5.0'
|
|
62
93
|
type: :runtime
|
|
63
94
|
prerelease: false
|
|
64
95
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
96
|
requirements:
|
|
66
97
|
- - ">="
|
|
67
98
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '3'
|
|
99
|
+
version: '3.0'
|
|
100
|
+
- - "<"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '5.0'
|
|
69
103
|
- !ruby/object:Gem::Dependency
|
|
70
104
|
name: json
|
|
71
105
|
requirement: !ruby/object:Gem::Requirement
|
|
72
106
|
requirements:
|
|
73
|
-
- - "
|
|
107
|
+
- - "~>"
|
|
74
108
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '2'
|
|
109
|
+
version: '2.18'
|
|
76
110
|
type: :runtime
|
|
77
111
|
prerelease: false
|
|
78
112
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
113
|
requirements:
|
|
80
|
-
- - "
|
|
114
|
+
- - "~>"
|
|
81
115
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '2'
|
|
116
|
+
version: '2.18'
|
|
83
117
|
- !ruby/object:Gem::Dependency
|
|
84
118
|
name: redcarpet
|
|
85
119
|
requirement: !ruby/object:Gem::Requirement
|
|
86
120
|
requirements:
|
|
87
|
-
- - "
|
|
121
|
+
- - "~>"
|
|
88
122
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '3'
|
|
123
|
+
version: '3.6'
|
|
90
124
|
type: :runtime
|
|
91
125
|
prerelease: false
|
|
92
126
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
127
|
requirements:
|
|
94
|
-
- - "
|
|
128
|
+
- - "~>"
|
|
95
129
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '3'
|
|
130
|
+
version: '3.6'
|
|
97
131
|
- !ruby/object:Gem::Dependency
|
|
98
132
|
name: ruby-openai
|
|
99
133
|
requirement: !ruby/object:Gem::Requirement
|
|
100
134
|
requirements:
|
|
101
|
-
- - "
|
|
135
|
+
- - "~>"
|
|
102
136
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
137
|
+
version: '8.3'
|
|
104
138
|
type: :runtime
|
|
105
139
|
prerelease: false
|
|
106
140
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
141
|
requirements:
|
|
108
|
-
- - "
|
|
142
|
+
- - "~>"
|
|
109
143
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
144
|
+
version: '8.3'
|
|
111
145
|
- !ruby/object:Gem::Dependency
|
|
112
146
|
name: tiktoken_ruby
|
|
113
147
|
requirement: !ruby/object:Gem::Requirement
|
|
114
148
|
requirements:
|
|
115
|
-
- - "
|
|
149
|
+
- - "~>"
|
|
116
150
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: 0.0
|
|
151
|
+
version: '0.0'
|
|
118
152
|
type: :runtime
|
|
119
153
|
prerelease: false
|
|
120
154
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
155
|
requirements:
|
|
122
|
-
- - "
|
|
156
|
+
- - "~>"
|
|
123
157
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: 0.0
|
|
158
|
+
version: '0.0'
|
|
125
159
|
description: Add this plugin to your Jekyll site and all posts will be automatically
|
|
126
160
|
translated to the languages of your choice through ChatGPT
|
|
127
161
|
email: yegor256@gmail.com
|
|
@@ -138,6 +172,7 @@ files:
|
|
|
138
172
|
- ".github/workflows/pdd.yml"
|
|
139
173
|
- ".github/workflows/rake.yml"
|
|
140
174
|
- ".github/workflows/reuse.yml"
|
|
175
|
+
- ".github/workflows/typos.yml"
|
|
141
176
|
- ".github/workflows/xcop.yml"
|
|
142
177
|
- ".github/workflows/yamllint.yml"
|
|
143
178
|
- ".gitignore"
|