1
1
import PathGenerator from "./controllers/path.ts" ;
2
2
import translate , { getFileErrors } from "./controllers/recurTranslate.ts" ;
3
- import fs , { Dirent } from "fs" ;
3
+ import fs from "fs" ;
4
4
import util from "util" ;
5
5
import path from "path" ;
6
6
import { fileURLToPath } from "url" ;
7
7
import { dirname } from "path" ;
8
- import OpenAI from "openai" ;
9
- import { max_trans_num , translationSummaryPrefix } from "./config.ts" ;
8
+ import { max_trans_num } from "./config.ts" ;
9
+ import { saveSummaryLog } from "./controllers/loggers.ts" ;
10
+ import { setupCleanupHandlers } from "./initializers/processHandler.ts" ;
11
+ import { findAllXmlFiles , needsTranslation } from "./controllers/fileUtilities.ts" ;
10
12
11
13
// Get the directory name of the current module
12
14
const __filename = fileURLToPath ( import . meta. url ) ;
@@ -27,201 +29,14 @@ let failureCount = 0;
27
29
let processedCount = 0 ;
28
30
let failures : { file : string ; error : any } [ ] = [ ] ;
29
31
30
- // Function to save summary log - can be called from signal handlers
31
- async function saveSummaryLog ( ) {
32
- try {
33
- const ai = new OpenAI ( {
34
- apiKey : process . env . API_KEY ,
35
- baseURL : process . env . AI_BASEURL
36
- } ) ;
37
-
38
- // list and delete all assistants
39
- const assistants = await ai . beta . assistants . list ( { limit : 100 } ) ;
40
- const failedDel : string [ ] = [ ] ;
41
- await Promise . all (
42
- assistants . data . map ( async assistant => {
43
- try {
44
- await ai . beta . assistants . del ( assistant . id ) ;
45
- } catch ( error ) {
46
- failedDel . push ( assistant . id ) ;
47
- }
48
- } )
49
- ) . then ( ( ) => console . log ( "successfully removed all assistants" ) ) ;
50
-
51
- // list and delete all uploaded files
52
- const files = await ai . files . list ( ) ;
53
- await Promise . all (
54
- files . data . map ( async file => {
55
- try {
56
- await ai . files . del ( file . id ) ;
57
- } catch ( error ) {
58
- failedDel . push ( file . id ) ;
59
- }
60
- } )
61
- ) . then ( ( ) => console . log ( "successfully deleted all files" ) ) ;
62
-
63
- const timestamp = new Date ( ) . toISOString ( ) . replace ( / [: .] / g, "-" ) ;
64
- let summaryLog = `
65
- Translation Summary (${ timestamp } )
66
- ================================
67
- Total files scanned: ${ xmlFiles . length }
68
- Files needing translation: ${ filesToTranslate . length }
69
- Successfully translated: ${ successCount }
70
- Failed translations: ${ failureCount }
71
- Success rate: ${ filesToTranslate . length > 0 ? ( ( successCount / filesToTranslate . length ) * 100 ) . toFixed ( 2 ) : 0 } %
72
- ` ;
73
-
74
- if ( failedDel . length > 0 ) {
75
- summaryLog += `\nFailed to remove ${ failedDel . length } assistants\n` ;
76
- failedDel . forEach (
77
- ( assistant , index ) => ( summaryLog += `${ index + 1 } . ${ assistant } \n` )
78
- ) ;
79
- }
80
-
81
- // Add failed translations to the log
82
- if ( failures . length > 0 ) {
83
- summaryLog += `\nFailed Translations (High-level errors):\n` ;
84
- failures . forEach ( ( failure , index ) => {
85
- summaryLog += `${ index + 1 } . ${ failure . file } \n Error: ${ failure . error } \n\n` ;
86
- } ) ;
87
- }
88
-
89
- // Add detailed errors captured during translation process
90
- const fileErrors = getFileErrors ( ) ;
91
- if ( Object . keys ( fileErrors ) . length > 0 ) {
92
- failureCount = Object . keys ( fileErrors ) . length ;
93
- summaryLog += `\nDetailed Translation Errors:\n` ;
94
- summaryLog += `============================\n` ;
95
-
96
- for ( const [ filePath , errors ] of Object . entries ( fileErrors ) ) {
97
- summaryLog += `\nFile: ${ filePath } \n` ;
98
- errors . forEach ( ( error , index ) => {
99
- summaryLog += ` ${ index + 1 } . ${ error . error } \n` ;
100
- if ( error . error ) {
101
- // Format the error object/message for better readability
102
- const errorStr =
103
- typeof error . error === "object"
104
- ? JSON . stringify ( error . error , null , 2 ) . substring ( 0 , 500 ) // Limit very long errors
105
- : String ( error . error ) ;
106
- summaryLog += ` Details: ${ errorStr } \n` ;
107
- }
108
- } ) ;
109
- }
110
- }
111
-
112
- const logDir = path . resolve ( __dirname , "../logs" ) ;
113
- if ( ! fs . existsSync ( logDir ) ) {
114
- fs . mkdirSync ( logDir , { recursive : true } ) ;
115
- }
116
-
117
- const logPath = path . join ( logDir , `${ translationSummaryPrefix } -${ timestamp } .log` ) ;
118
- fs . writeFileSync ( logPath , summaryLog ) ;
119
- console . log (
120
- `Summary log saved to logs/translation-summary-${ timestamp } .log`
121
- ) ;
122
- } catch ( logError ) {
123
- console . error ( "Failed to save log file:" , logError ) ;
124
- }
125
- }
126
-
127
- // Register handlers for various termination signals
128
- async function setupCleanupHandlers ( ) {
129
- // Handle normal exit
130
- process . on ( "exit" , ( ) => {
131
- console . log ( "Process is exiting, saving summary..." ) ;
132
- // Only synchronous operations work in 'exit' handlers
133
- // We can't await here, as exit handlers must be synchronous
134
- try {
135
- // Use synchronous operations for final cleanup if needed
136
- // Note: This won't actually call the async parts of saveSummaryLog properly
137
- const timestamp = new Date ( ) . toISOString ( ) . replace ( / [: .] / g, "-" ) ;
138
- const summaryContent = `Translation interrupted during exit at ${ timestamp } ` ;
139
- const logDir = path . resolve ( __dirname , "../logs" ) ;
140
- if ( ! fs . existsSync ( logDir ) ) {
141
- fs . mkdirSync ( logDir , { recursive : true } ) ;
142
- }
143
- fs . writeFileSync (
144
- path . join ( logDir , `emergency-log-${ timestamp } .log` ) ,
145
- summaryContent
146
- ) ;
147
- } catch ( error ) {
148
- console . error ( "Failed to save emergency log during exit:" , error ) ;
149
- }
150
- } ) ;
151
-
152
- // Handle Ctrl+C
153
- process . on ( "SIGINT" , async ( ) => {
154
- console . log ( "\nReceived SIGINT (Ctrl+C). Saving summary before exit..." ) ;
155
- await saveSummaryLog ( ) ;
156
- process . exit ( 1 ) ;
157
- } ) ;
158
-
159
- // Handle SIGTERM (kill command)
160
- process . on ( "SIGTERM" , async ( ) => {
161
- console . log ( "\nReceived SIGTERM. Saving summary before exit..." ) ;
162
- await saveSummaryLog ( ) ;
163
- process . exit ( 1 ) ;
164
- } ) ;
165
-
166
- // Handle uncaught exceptions
167
- process . on ( "uncaughtException" , async error => {
168
- console . error ( "\nUncaught exception:" , error ) ;
169
- console . log ( "Saving summary before exit..." ) ;
170
- await saveSummaryLog ( ) ;
171
- process . exit ( 1 ) ;
172
- } ) ;
173
- }
174
-
175
- async function needsTranslation (
176
- enFilePath : string ,
177
- lang : string
178
- ) : Promise < boolean > {
179
- const cnFilePath = enFilePath . replace (
180
- path . sep + "en" + path . sep ,
181
- path . sep + lang + path . sep
182
- ) ;
183
- try {
184
- const cnStats = await fs . promises . stat ( cnFilePath ) ;
185
- if ( ! cnStats . isFile ( ) ) {
186
- return true ;
187
- }
188
-
189
- const enStats = await fs . promises . stat ( enFilePath ) ;
190
- return enStats . mtime > cnStats . mtime ;
191
- } catch ( error ) {
192
- throw error ;
193
- }
194
- }
195
-
196
- // Function to recursively find all XML files in a directory
197
- async function findAllXmlFiles ( directory : string ) : Promise < string [ ] > {
198
- const files = await fs . promises . readdir ( directory ) ;
199
- const xmlFiles : string [ ] = [ ] ;
200
-
201
- for ( const file of files ) {
202
- const fullPath = path . join ( directory , file ) ;
203
- const stat = await fs . promises . stat ( fullPath ) ;
204
-
205
- if ( stat . isDirectory ( ) ) {
206
- // Recursively search subdirectories
207
- const subDirFiles = await findAllXmlFiles ( fullPath ) ;
208
- xmlFiles . push ( ...subDirFiles ) ;
209
- } else if ( path . extname ( file ) . toLowerCase ( ) === ".xml" ) {
210
- // Add XML files to the list
211
- xmlFiles . push ( fullPath ) ;
212
- }
213
- }
214
-
215
- return xmlFiles ;
216
- }
217
32
218
- export default async function fancyName ( path : string , language : string ) {
33
+ export default async function translateSingle ( path : string , language : string ) {
219
34
const fullPath = PathGenerator ( path ) ;
220
35
await translate ( language , fullPath ) ;
221
36
}
222
37
223
38
( async ( ) => {
224
- await setupCleanupHandlers ( ) ;
39
+ await setupCleanupHandlers ( xmlFiles , failures , filesToTranslate . length , failureCount , successCount ) ;
225
40
226
41
try {
227
42
const languages : string [ ] = await getDirectories (
@@ -354,7 +169,7 @@ export default async function fancyName(path: string, language: string) {
354
169
}
355
170
356
171
// Save a detailed summary to a log file
357
- await saveSummaryLog ( ) ;
172
+ await saveSummaryLog ( xmlFiles , failures , filesToTranslate . length , failureCount , successCount ) ;
358
173
}
359
174
} catch ( e ) {
360
175
console . error ( "Error during translation process:" , e ) ;
0 commit comments