llm_translate 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1231cf03fe5984a00c4bccf9596b2255dd83c4852bac5bd554068e3853f1fad
4
- data.tar.gz: 208488f548d281ae103eb10ad3790201c41a62cff8acb0b24c36e786181da3ed
3
+ metadata.gz: b3d7bffb10cabd77729e1e806a256a16bd7a036faa0ea52b7024e3a521dada5e
4
+ data.tar.gz: 50fcf8a22940afb311387913d2455dc519812abe8618be54c47541808193afd6
5
5
  SHA512:
6
- metadata.gz: bc4713b2292f56da626f79beafda11144a45f8fc84ed660f4f333afa2cf93b592285bb74b5746cb2610cf5bf41c81006ffb8ad648c6784365692404e4ff56495
7
- data.tar.gz: 0f618ca45a6b97cf3fed6410d2dcf73bd80fd17abc0e91c443110021da5da0b484945b45f9813ef46aa671714c821ad1aa73f51530165cc9eceea437b32ed3e3
6
+ metadata.gz: 76e635e0838f893377ed9ba05e8e4e04c36053cbb4c68b2ab09cbd8c69d8a7433400886e1f817647d9b322fc7dad1e4643cc53b6471fc7ed2b6538df015108d7
7
+ data.tar.gz: 713bb859602fd5f511444f8e491bcd556beb7954f2f03cb36ff79938ff1e07e60c5419dd2c9818dc4d1f95136af8d4722b649a267e4217128598a26036b50532
data/README.zh.md CHANGED
@@ -1,17 +1,17 @@
1
1
  # LlmTranslate
2
2
 
3
- AI 驱动的 Markdown 翻译工具,可在使用各种 AI 提供商翻译内容时保留格式。
3
+ AI 驱动的 Markdown 翻译工具,在使用各种 AI 提供商翻译内容的同时保持格式不变。
4
4
 
5
5
  ## 功能特性
6
6
 
7
7
  - 🤖 **AI 驱动翻译**:支持 OpenAI、Anthropic 和 Ollama
8
- - 📝 **Markdown 格式保留**:保持代码块、链接、图片和格式完整
8
+ - 📝 **Markdown 格式保留**:保持代码块、链接、图片和格式不变
9
9
  - 🔧 **灵活配置**:基于 YAML 的配置,支持环境变量
10
10
  - 📁 **批量处理**:递归处理整个目录结构
11
- - 🚀 **CLI 界面**:使用 Thor 的易用命令行界面
11
+ - 🚀 **CLI 界面**:使用 Thor 实现的易用命令行界面
12
12
  - 📊 **进度跟踪**:内置日志记录和报告功能
13
- - ⚡ **错误处理**:带有重试机制的强大错误处理
14
- - 🎯 **可定制**:自定义提示、文件模式和输出策略
13
+ - ⚡ **错误处理**:具有重试机制的强大错误处理
14
+ - 🎯 **可定制性**:自定义提示、文件模式和输出策略
15
15
 
16
16
  ## 安装
17
17
 
@@ -149,7 +149,7 @@ Options:
149
149
  -o, --output PATH 输出目录(覆盖配置)
150
150
  -p, --prompt TEXT 自定义翻译提示(覆盖配置)
151
151
  -v, --verbose 启用详细输出
152
- -d, --dry-run 执行试运行,不进行实际翻译
152
+ -d, --dry-run 执行试运行而不进行实际翻译
153
153
 
154
154
  Other Commands:
155
155
  llm_translate init 初始化新的配置文件
@@ -70,24 +70,19 @@ module LlmTranslate
70
70
  end
71
71
 
72
72
  # Translate files
73
- success_count = 0
74
- error_count = 0
75
-
76
- files.each_with_index do |file_path, index|
77
- logger.info "[#{index + 1}/#{files.length}] Processing: #{file_path}"
78
-
79
- translator_engine.translate_file(file_path) unless options[:dry_run]
73
+ if options[:dry_run]
74
+ logger.info "DRY RUN: Would translate #{files.length} files with #{config.concurrent_files} concurrent threads"
75
+ success_count = files.length
76
+ error_count = 0
77
+ else
78
+ logger.info "Starting translation with #{config.concurrent_files} concurrent files"
80
79
 
81
- success_count += 1
82
- logger.info "✓ Successfully processed: #{file_path}"
83
- rescue StandardError => e
84
- error_count += 1
85
- logger.error "✗ Failed to process #{file_path}: #{e.message}"
80
+ results = translator_engine.translate_files_concurrently(files)
81
+ success_count = results[:success].length
82
+ error_count = results[:error].length
86
83
 
87
- if config.should_stop_on_error?(error_count)
88
- logger.error 'Stopping due to too many consecutive errors'
89
- break
90
- end
84
+ # Check if we should stop on too many errors
85
+ logger.error "Stopping due to too many errors (#{error_count})" if config.should_stop_on_error?(error_count)
91
86
  end
92
87
 
93
88
  # Summary
@@ -120,10 +120,6 @@ module LlmTranslate
120
120
  data.dig('files', 'overwrite_policy') || 'ask'
121
121
  end
122
122
 
123
- def backup_directory
124
- data.dig('files', 'backup_directory') || './backups'
125
- end
126
-
127
123
  # Logging Configuration
128
124
  def log_level
129
125
  cli_options[:verbose] ? 'debug' : (data.dig('logging', 'level') || 'info')
@@ -133,18 +129,10 @@ module LlmTranslate
133
129
  data.dig('logging', 'output') || 'console'
134
130
  end
135
131
 
136
- def log_file_path
137
- data.dig('logging', 'file_path') || './logs/llm_translate.log'
138
- end
139
-
140
132
  def verbose_translation?
141
133
  cli_options[:verbose] || data.dig('logging', 'verbose_translation') == true
142
134
  end
143
135
 
144
- def error_log_path
145
- data.dig('logging', 'error_log_path') || './logs/errors.log'
146
- end
147
-
148
136
  # Error Handling Configuration
149
137
  def on_error
150
138
  data.dig('error_handling', 'on_error') || 'log_and_continue'
@@ -162,10 +150,6 @@ module LlmTranslate
162
150
  data.dig('error_handling', 'generate_error_report') != false
163
151
  end
164
152
 
165
- def error_report_path
166
- data.dig('error_handling', 'error_report_path') || './logs/error_report.md'
167
- end
168
-
169
153
  def should_stop_on_error?(error_count)
170
154
  on_error == 'stop' || error_count >= max_consecutive_errors
171
155
  end
@@ -175,27 +159,11 @@ module LlmTranslate
175
159
  data.dig('performance', 'concurrent_files') || 3
176
160
  end
177
161
 
178
- def batch_size
179
- data.dig('performance', 'batch_size') || 5
180
- end
181
-
182
162
  def request_interval
183
163
  data.dig('performance', 'request_interval') || 1
184
164
  end
185
165
 
186
- def max_memory_mb
187
- data.dig('performance', 'max_memory_mb') || 500
188
- end
189
-
190
166
  # Output Configuration
191
- def show_progress?
192
- data.dig('output', 'show_progress') != false
193
- end
194
-
195
- def show_statistics?
196
- data.dig('output', 'show_statistics') != false
197
- end
198
-
199
167
  def generate_report?
200
168
  data.dig('output', 'generate_report') != false
201
169
  end
@@ -204,14 +172,6 @@ module LlmTranslate
204
172
  data.dig('output', 'report_path') || './reports/translation_report.md'
205
173
  end
206
174
 
207
- def output_format
208
- data.dig('output', 'format') || 'markdown'
209
- end
210
-
211
- def include_metadata?
212
- data.dig('output', 'include_metadata') != false
213
- end
214
-
215
175
  private
216
176
 
217
177
  def load_config_file(config_path)
@@ -67,7 +67,7 @@ module LlmTranslate
67
67
  when 'console'
68
68
  create_console_logger
69
69
  when 'file'
70
- create_file_logger(config.log_file_path)
70
+ create_file_logger('./logs/llm_translate.log')
71
71
  when 'both'
72
72
  create_multi_logger
73
73
  else
@@ -76,15 +76,8 @@ module LlmTranslate
76
76
  end
77
77
 
78
78
  def create_error_logger
79
- return nil unless config.error_log_path
80
-
81
- FileUtils.mkdir_p(File.dirname(config.error_log_path))
82
- error_logger = ::Logger.new(config.error_log_path)
83
- error_logger.level = log_level_constant
84
- error_logger.formatter = proc do |severity, datetime, _progname, msg|
85
- "[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}] #{severity}: #{msg}\n"
86
- end
87
- error_logger
79
+ # Error logger is no longer supported, return nil
80
+ nil
88
81
  end
89
82
 
90
83
  def create_console_logger
@@ -119,7 +112,7 @@ module LlmTranslate
119
112
 
120
113
  def create_multi_logger
121
114
  console_logger = create_console_logger
122
- file_logger = create_file_logger(config.log_file_path)
115
+ file_logger = create_file_logger('./logs/llm_translate.log')
123
116
 
124
117
  MultiLogger.new([console_logger, file_logger])
125
118
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'fileutils'
5
+ require 'async'
5
6
 
6
7
  module LlmTranslate
7
8
  class TranslatorEngine
@@ -53,6 +54,66 @@ module LlmTranslate
53
54
  sleep(config.request_interval) if config.request_interval.positive?
54
55
  end
55
56
 
57
+ def translate_files_concurrently(file_paths)
58
+ return translate_files_sequentially(file_paths) if config.concurrent_files <= 1
59
+
60
+ results = { success: [], error: [] }
61
+
62
+ # Use Async to run concurrent translation tasks
63
+ Async do |task|
64
+ # Process files in batches to limit concurrency
65
+ file_paths.each_slice(config.concurrent_files) do |batch|
66
+ # Create async tasks for the current batch
67
+ batch_tasks = batch.map.with_index do |file_path, _batch_index|
68
+ # Calculate overall index
69
+ overall_index = file_paths.index(file_path) + 1
70
+
71
+ task.async do
72
+ logger.info "[#{overall_index}/#{file_paths.length}] Processing: #{file_path}"
73
+
74
+ # Translate the file
75
+ translate_file(file_path)
76
+
77
+ # Collect successful result
78
+ results[:success] << file_path
79
+
80
+ logger.info "✓ Successfully processed: #{file_path}"
81
+ { status: :success, file: file_path }
82
+ rescue StandardError => e
83
+ # Collect error result
84
+ results[:error] << { file: file_path, error: e.message }
85
+
86
+ logger.error "✗ Failed to process #{file_path}: #{e.message}"
87
+ { status: :error, file: file_path, error: e.message }
88
+ end
89
+ end
90
+
91
+ # Wait for all tasks in this batch to complete before starting the next batch
92
+ batch_tasks.each(&:wait)
93
+ end
94
+ end
95
+
96
+ results
97
+ end
98
+
99
+ def translate_files_sequentially(file_paths)
100
+ results = { success: [], error: [] }
101
+
102
+ file_paths.each_with_index do |file_path, index|
103
+ logger.info "[#{index + 1}/#{file_paths.length}] Processing: #{file_path}"
104
+
105
+ translate_file(file_path)
106
+
107
+ results[:success] << file_path
108
+ logger.info "✓ Successfully processed: #{file_path}"
109
+ rescue StandardError => e
110
+ results[:error] << { file: file_path, error: e.message }
111
+ logger.error "✗ Failed to process #{file_path}: #{e.message}"
112
+ end
113
+
114
+ results
115
+ end
116
+
56
117
  def translate_content(content, file_path = nil)
57
118
  if config.preserve_formatting?
58
119
  translate_with_format_preservation(content)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LlmTranslate
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.require_paths = ['lib']
32
32
 
33
33
  # Dependencies
34
+ spec.add_dependency 'async', '~> 2.0'
34
35
  spec.add_dependency 'ruby_llm', '~> 1.6'
35
36
  spec.add_dependency 'thor', '~> 1.3'
36
37
 
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llm_translate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LlmTranslate Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-19 00:00:00.000000000 Z
11
+ date: 2025-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: async
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: ruby_llm
15
29
  requirement: !ruby/object:Gem::Requirement