light_tr 1.0.0 → 2.0.1
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/.github/FUNDING.yml +3 -0
- data/Gemfile.lock +19 -2
- data/exe/trans +16 -8
- data/lib/light_tr/chat_gpt.rb +59 -0
- data/lib/light_tr/commands.rb +55 -6
- data/lib/light_tr/config.rb +15 -1
- data/lib/light_tr/version.rb +1 -1
- data/lib/light_tr.rb +1 -0
- data/light_tr.gemspec +2 -0
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b2f82e905041870f9f842318362e0c01cf4be7ca0e754703cc24d5d479eaaf3
|
4
|
+
data.tar.gz: 300eb6fb7519db67951e4432627e855d80c0335d3f22a2cd4b9417d80c4aa47e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4c558e2eb2fc941538e8d542ab38f52b6f354929821f66877606485b74aa0172c216d7febe5857c7ed94956a3579b5798ece72dfc4705a62fa06fe30f237137
|
7
|
+
data.tar.gz: 9c2b18fcfc3754f7ff51840eee3d7c45b3792867cd65944bc5cd05500af869e67cf880b44079e78dbcd11cedc65416c38ed27c1a89f6fa319def60b77190fcf8
|
data/.github/FUNDING.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
light_tr (
|
4
|
+
light_tr (2.0.1)
|
5
5
|
awesome_print (~> 1.2)
|
6
6
|
executable (~> 1.2)
|
7
|
+
faraday (~> 2.0)
|
8
|
+
faraday-mashify (~> 0.1)
|
7
9
|
hashie (~> 2.1)
|
8
10
|
lockbox (~> 0.6)
|
9
11
|
|
@@ -15,6 +17,15 @@ GEM
|
|
15
17
|
coderay (1.1.3)
|
16
18
|
diff-lcs (1.4.4)
|
17
19
|
executable (1.2.1)
|
20
|
+
faraday (2.12.0)
|
21
|
+
faraday-net_http (>= 2.0, < 3.4)
|
22
|
+
json
|
23
|
+
logger
|
24
|
+
faraday-mashify (0.1.1)
|
25
|
+
faraday (~> 2.0)
|
26
|
+
hashie
|
27
|
+
faraday-net_http (3.3.0)
|
28
|
+
net-http
|
18
29
|
ffi (1.15.4)
|
19
30
|
formatador (0.3.0)
|
20
31
|
guard (2.18.0)
|
@@ -29,13 +40,17 @@ GEM
|
|
29
40
|
guard-rspec (0.7.3)
|
30
41
|
guard (>= 0.10.0)
|
31
42
|
hashie (2.1.2)
|
43
|
+
json (2.7.2)
|
32
44
|
listen (3.7.0)
|
33
45
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
34
46
|
rb-inotify (~> 0.9, >= 0.9.10)
|
35
|
-
lockbox (0.6.
|
47
|
+
lockbox (0.6.8)
|
48
|
+
logger (1.6.1)
|
36
49
|
lumberjack (1.2.8)
|
37
50
|
method_source (1.0.0)
|
38
51
|
nenv (0.3.0)
|
52
|
+
net-http (0.4.1)
|
53
|
+
uri
|
39
54
|
notiffany (0.1.3)
|
40
55
|
nenv (~> 0.1)
|
41
56
|
shellany (~> 0.0)
|
@@ -80,9 +95,11 @@ GEM
|
|
80
95
|
shellany (0.0.1)
|
81
96
|
thor (1.1.0)
|
82
97
|
unicode-display_width (2.1.0)
|
98
|
+
uri (0.13.1)
|
83
99
|
|
84
100
|
PLATFORMS
|
85
101
|
arm64-darwin-20
|
102
|
+
arm64-darwin-21
|
86
103
|
|
87
104
|
DEPENDENCIES
|
88
105
|
guard-rspec (~> 0)
|
data/exe/trans
CHANGED
@@ -12,26 +12,34 @@ languages = (override_language ? ARGV[0].strip[1..2] : LightTr::Config.l
|
|
12
12
|
full_text = (override_language ? ARGV[1..] : ARGV).join(' ')
|
13
13
|
store = LightTr::Store.new(name: 'translations', file_path: LightTr::Config.config_path)
|
14
14
|
translator = LightTr::Translator.new(LightTr::Config.api_key)
|
15
|
+
gpt = LightTr::ChatGpt.new(LightTr::Config.open_ai_key, LightTr::Config.model)
|
15
16
|
text = full_text.gsub(/[[:space:]]+/, ' ').strip
|
16
17
|
interactive = command == '-i'
|
17
18
|
|
18
19
|
unless text.empty?
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
if LightTr::Config.provider == 'google'
|
21
|
+
runner = LightTr::Runner.new(store, translator)
|
22
|
+
return puts runner.translate(languages[0], text) if languages.count == 1
|
23
|
+
languages.each { |target| puts "#{target.upcase}: #{runner.translate(target, text)}" }
|
24
|
+
else
|
25
|
+
puts gpt.translate(text, languages)
|
26
|
+
end
|
22
27
|
end
|
23
28
|
|
24
29
|
if interactive
|
25
30
|
puts 'Interactive mode! (quit by /q or empty line)'
|
26
|
-
puts
|
31
|
+
puts "Type any sentence now:\n"
|
27
32
|
|
28
33
|
loop do
|
29
34
|
text = STDIN.gets.chomp.to_s.gsub(/[[:space:]]+/, ' ').strip
|
30
35
|
break if text == '/q' || text.empty?
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
36
|
+
if LightTr::Config.provider == 'google'
|
37
|
+
runner = LightTr::Runner.new(store, translator)
|
38
|
+
return puts " " + runner.translate(languages[0], text) if languages.count == 1
|
39
|
+
languages.each { |target| puts " #{target.upcase}: #{runner.translate(target, text)}" }
|
40
|
+
else
|
41
|
+
puts gpt.translate(text, languages)
|
42
|
+
end
|
35
43
|
puts "\n"
|
36
44
|
end
|
37
45
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'faraday/mashify'
|
5
|
+
|
6
|
+
module LightTr
|
7
|
+
class ChatGpt
|
8
|
+
SUPPORTED_LANGUAGES_MAP = { 'af' => 'Afrikaans', 'ga' => 'Irish', 'sq' => 'Albanian', 'it' => 'Italian', 'ar' => 'Arabic', 'ja' => 'Japanese', 'az' => 'Azerbaijani', 'kn' => 'Kannada', 'eu' => 'Basque', 'ko' => 'Korean', 'bn' => 'Bengali', 'la' => 'Latin', 'be' => 'Belarusian', 'lv' => 'Latvian', 'bg' => 'Bulgarian', 'lt' => 'Lithuanian', 'ca' => 'Catalan', 'mk' => 'Macedonian', 'ms' => 'Malay', 'mt' => 'Maltese', 'hr' => 'Croatian', 'no' => 'Norwegian', 'cs' => 'Czech', 'fa' => 'Persian', 'da' => 'Danish', 'pl' => 'Polish', 'nl' => 'Dutch', 'pt' => 'Portuguese', 'en' => 'English', 'ro' => 'Romanian', 'eo' => 'Esperanto', 'ru' => 'Russian', 'et' => 'Estonian', 'sr' => 'Serbian', 'tl' => 'Filipino', 'sk' => 'Slovak', 'fi' => 'Finnish', 'sl' => 'Slovenian', 'fr' => 'French', 'es' => 'Spanish', 'gl' => 'Galician', 'sw' => 'Swahili', 'ka' => 'Georgian', 'sv' => 'Swedish', 'de' => 'German', 'ta' => 'Tamil', 'el' => 'Greek', 'te' => 'Telugu', 'gu' => 'Gujarati', 'th' => 'Thai', 'ht' => 'Haitian Creole', 'tr' => 'Turkish', 'iw' => 'Hebrew', 'uk' => 'Ukrainian', 'hi' => 'Hindi', 'ur' => 'Urdu', 'hu' => 'Hungarian', 'vi' => 'Vietnamese', 'is' => 'Icelandic', 'cy' => 'Welsh', 'id' => 'Indonesian', 'yi' => 'Yiddish', 'zh-CN' => 'Chinese (Simplified)', 'zh-TW' => 'Chinese (Traditional)' }.freeze # rubocop:disable Layout/LineLength
|
9
|
+
|
10
|
+
def initialize(api_key, model = 'gpt-3.5-turbo')
|
11
|
+
@api_key = api_key
|
12
|
+
@model = model
|
13
|
+
end
|
14
|
+
|
15
|
+
def translate(query, languages)
|
16
|
+
completion(query, languages)
|
17
|
+
end
|
18
|
+
|
19
|
+
def models
|
20
|
+
@models ||= client.get('models').body.data.map(&:id).select { |id| id.include?('gpt') }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :api_key, :model
|
26
|
+
|
27
|
+
def system(languages)
|
28
|
+
langs = languages.map { |lang| SUPPORTED_LANGUAGES_MAP[lang] }
|
29
|
+
intro = if langs.count == 1
|
30
|
+
"You are a translator, everything you receive next should be translated into #{langs[0]}."
|
31
|
+
else
|
32
|
+
"You are a translator, everything you receive next should be translated into #{langs[0]} or #{langs[1]}.\nIf the given text is in #{langs[1]}, translate it into #{langs[0]}.\nIf the text is in #{langs[0]}, translate it into #{langs[1]}." # rubocop:disable Layout/LineLength
|
33
|
+
end
|
34
|
+
intro + "\nTry to translate in a way that sounds natural to a native speaker of that language.\nOnly return the translation of the text; you don’t need to translate the code." # rubocop:disable Layout/LineLength
|
35
|
+
end
|
36
|
+
|
37
|
+
def completion(query, languages)
|
38
|
+
client.post(
|
39
|
+
'chat/completions', {
|
40
|
+
model: model,
|
41
|
+
temperature: 0.7,
|
42
|
+
messages: [
|
43
|
+
{ role: 'system', content: system(languages) },
|
44
|
+
{ role: 'user', content: query }
|
45
|
+
] }
|
46
|
+
).body.choices[0].message.content
|
47
|
+
end
|
48
|
+
|
49
|
+
def client
|
50
|
+
@client ||= Faraday.new(url: 'https://api.openai.com/v1') do |faraday|
|
51
|
+
faraday.request :authorization, 'Bearer', api_key
|
52
|
+
faraday.request :json
|
53
|
+
faraday.response :mashify
|
54
|
+
faraday.response :json
|
55
|
+
faraday.adapter Faraday.default_adapter
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/light_tr/commands.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'fileutils'
|
3
3
|
require 'lockbox'
|
4
|
+
require 'light_tr/chat_gpt'
|
4
5
|
|
5
6
|
module LightTr
|
6
7
|
class Commands
|
@@ -36,8 +37,8 @@ module LightTr
|
|
36
37
|
puts "\noptions:"
|
37
38
|
puts ' -config : init configuration'
|
38
39
|
puts ' -show_config : show configuration'
|
39
|
-
puts ' -clear_cache : clear translation cache'
|
40
|
-
puts ' -pl : translate only one language (pl can be changed on any supported language)'
|
40
|
+
puts ' -clear_cache : clear translation cache [only for google provider]'
|
41
|
+
puts ' -pl : translate only one language (pl can be changed on any supported language) [only for google provider]'
|
41
42
|
puts ' -i : run translator in interactive mode'
|
42
43
|
end
|
43
44
|
|
@@ -48,11 +49,14 @@ module LightTr
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def self.show_config
|
51
|
-
api_key
|
52
|
+
api_key = ::LightTr::Config.api_key
|
52
53
|
show_key = api_key[..10] + ('*' * (api_key.size - 10))
|
53
54
|
puts 'Current configuration:'
|
54
55
|
puts "\nlanguages : #{::LightTr::Config.languages}"
|
55
56
|
puts "Goggle Translate API key : #{show_key}\n"
|
57
|
+
puts "OpenAI API key : #{::LightTr::Config.open_ai_key}"
|
58
|
+
puts "Provider : #{::LightTr::Config.provider}"
|
59
|
+
puts "Model : #{::LightTr::Config.model}"
|
56
60
|
end
|
57
61
|
|
58
62
|
def self.supported_languages
|
@@ -80,21 +84,63 @@ module LightTr
|
|
80
84
|
value.to_s.split(',').map(&:strip).compact
|
81
85
|
end
|
82
86
|
|
87
|
+
def self.default_model
|
88
|
+
'gpt-3.5-turbo'
|
89
|
+
end
|
90
|
+
|
83
91
|
def self.update_config
|
84
92
|
FileUtils.mkdir_p(::LightTr::Config.config_path) unless File.directory?(::LightTr::Config.config_path)
|
85
93
|
puts 'Hello my friend lets setup Light Translator now!'
|
86
94
|
puts 'We will need only two things, Google Translate API key and your favorite languages'
|
87
95
|
puts "When you complete setup in your home directory will be created .light_tr/.config file with encrypted configuration"
|
96
|
+
puts "\n"
|
97
|
+
puts "\nYou can use two providers and set which one will be default: 'google' or 'openai'"
|
88
98
|
puts "\nLet's add Google Translate API key first. Instructions on: https://cloud.google.com/translate/docs/quickstarts"
|
89
|
-
print 'Give me the Google Translate API key: '
|
99
|
+
print 'Give me the Google Translate API key: (empty to skip) '
|
90
100
|
api_key = STDIN.gets.chomp
|
91
101
|
|
92
|
-
puts "\
|
102
|
+
puts "\n"
|
103
|
+
puts "\nYou can choice multiple languages example: pl, en, ru"
|
104
|
+
puts "\nBut openia provider support only two languages because it's working a little bit differently."
|
105
|
+
puts "\nIt is detecting source language and translate to target language automatically. For example: pl, en"
|
106
|
+
puts "\n`Jak się dziś masz?` -> `How are you today?`"
|
93
107
|
print 'Give me languages: '
|
94
108
|
languages = prepare_languages(STDIN.gets.chomp).join(', ')
|
95
109
|
|
110
|
+
puts "\n"
|
111
|
+
puts "\nLet's add OpenAI API key now. Instructions on: https://platform.openai.com/api-keys"
|
112
|
+
print 'Give me the OpenAI API key key: (empty to skip) '
|
113
|
+
open_ai_api_key = STDIN.gets.chomp
|
114
|
+
models = open_ai_api_key.empty? ? [default_model] : ::LightTr::ChatGpt.new(open_ai_api_key).models
|
115
|
+
model = unless open_ai_api_key.empty?
|
116
|
+
puts "\n"
|
117
|
+
puts "\nLet's choice model for OpenAI. Default is (gpt-4o-mini)"
|
118
|
+
puts "\nAll available models:"
|
119
|
+
models.each { |m| puts m }
|
120
|
+
|
121
|
+
print 'Give me the model: (default is gpt-3.5-turbo) '
|
122
|
+
STDIN.gets.chomp
|
123
|
+
end
|
124
|
+
|
125
|
+
model = models.include?(model) ? model : default_model
|
126
|
+
|
127
|
+
puts "\n"
|
128
|
+
puts "\n Now let's set default provider. You can choice between 'google' and 'openai' (default is google if present)"
|
129
|
+
print 'Give me the provider: (you can use just letters g, o)'
|
130
|
+
provider = STDIN.gets.chomp
|
131
|
+
if %w[g google].include?(provider.downcase) && !api_key.empty?
|
132
|
+
provider = 'google'
|
133
|
+
elsif %w[o openai].include?(provider.downcase) && !open_ai_api_key.empty?
|
134
|
+
provider = 'openai'
|
135
|
+
else
|
136
|
+
provider = 'google'
|
137
|
+
end
|
138
|
+
|
96
139
|
puts "\nYour configuration is:"
|
97
|
-
puts "API key: #{api_key}"
|
140
|
+
puts "Google API key: #{api_key}"
|
141
|
+
puts "OpenAI API key: #{open_ai_api_key}"
|
142
|
+
puts "OpenAI model: #{model.empty? ? default_model : model}"
|
143
|
+
puts "Provider: #{provider}"
|
98
144
|
puts "languages: #{languages}\n\n"
|
99
145
|
|
100
146
|
return languages_errors_and_update_config(languages) unless languages_valid?(languages)
|
@@ -109,6 +155,9 @@ module LightTr
|
|
109
155
|
::LightTr::Config.set({ 'master_key' => master_key })
|
110
156
|
::LightTr::Config.set({ 'api_key' => Lockbox.new(key: master_key).encrypt(api_key.strip) })
|
111
157
|
::LightTr::Config.set({ 'languages' => languages.strip })
|
158
|
+
::LightTr::Config.set({ 'open_ai_key' => Lockbox.new(key: master_key).encrypt(open_ai_api_key.strip) })
|
159
|
+
::LightTr::Config.set({ 'provider' => provider.strip })
|
160
|
+
::LightTr::Config.set({ 'model' => (model.empty? ? default_model : model).strip })
|
112
161
|
|
113
162
|
puts "\nHappy translating!"
|
114
163
|
end
|
data/lib/light_tr/config.rb
CHANGED
@@ -11,18 +11,32 @@ module LightTr
|
|
11
11
|
get['languages']
|
12
12
|
end
|
13
13
|
|
14
|
+
def self.open_ai_key
|
15
|
+
get['open_ai_key'] || raise('OpenAI API key missing. Try to update configuration via `trans -config`')
|
16
|
+
master_key = get['master_key'] || raise('Config file corrupted. Try to update configuration via `trans -config`')
|
17
|
+
Lockbox.new(key: master_key).decrypt(get['open_ai_key'])
|
18
|
+
end
|
19
|
+
|
14
20
|
def self.api_key
|
15
21
|
get['api_key'] || raise('Google Translation API key missing. Try to update configuration via `trans -config`')
|
16
22
|
master_key = get['master_key'] || raise('Config file corrupted. Try to update configuration via `trans -config`')
|
17
23
|
Lockbox.new(key: master_key).decrypt(get['api_key'])
|
18
24
|
end
|
19
25
|
|
26
|
+
def self.provider
|
27
|
+
get['provider'] || 'google'
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.model
|
31
|
+
get['model'] || 'gpt-3.5-turbo'
|
32
|
+
end
|
33
|
+
|
20
34
|
def self.config_path
|
21
35
|
File.join(Dir.home, '.light_tr')
|
22
36
|
end
|
23
37
|
|
24
38
|
def self.config_exists?
|
25
|
-
File.
|
39
|
+
File.exist?(config_file)
|
26
40
|
end
|
27
41
|
|
28
42
|
def self.config_missing?
|
data/lib/light_tr/version.rb
CHANGED
data/lib/light_tr.rb
CHANGED
data/light_tr.gemspec
CHANGED
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency 'rspec', '~> 2.12'
|
28
28
|
spec.add_development_dependency 'guard-rspec', '~> 0'
|
29
29
|
spec.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
spec.add_dependency 'faraday-mashify', '~> 0.1'
|
31
|
+
spec.add_dependency 'faraday', '~> 2.0'
|
30
32
|
spec.add_dependency 'hashie', '~> 2.1'
|
31
33
|
spec.add_dependency 'executable', '~> 1.2'
|
32
34
|
spec.add_dependency 'awesome_print', '~> 1.2'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: light_tr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paweł Niemczyk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faraday-mashify
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: faraday
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: hashie
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,6 +144,7 @@ executables:
|
|
116
144
|
extensions: []
|
117
145
|
extra_rdoc_files: []
|
118
146
|
files:
|
147
|
+
- ".github/FUNDING.yml"
|
119
148
|
- ".gitignore"
|
120
149
|
- ".rspec"
|
121
150
|
- ".rubocop.yml"
|
@@ -128,6 +157,7 @@ files:
|
|
128
157
|
- bin/setup
|
129
158
|
- exe/trans
|
130
159
|
- lib/light_tr.rb
|
160
|
+
- lib/light_tr/chat_gpt.rb
|
131
161
|
- lib/light_tr/commands.rb
|
132
162
|
- lib/light_tr/config.rb
|
133
163
|
- lib/light_tr/runner.rb
|