remove threads in modules and implement save progress for tls
This commit is contained in:
parent
217c19de5d
commit
f535e3a4e4
14 changed files with 412 additions and 63 deletions
|
|
@ -15,6 +15,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -206,7 +207,7 @@ def parseCSV(readFile, writeFile, filename):
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = translateCSV(data, pbar, writer, filename, None, format)
|
response = translateCSV(data, pbar, writeFile, writer, filename, None, format)
|
||||||
totalTokens[0] = response[0]
|
totalTokens[0] = response[0]
|
||||||
totalTokens[1] = response[1]
|
totalTokens[1] = response[1]
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -214,7 +215,24 @@ def parseCSV(readFile, writeFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
def translateCSV(data, pbar, writer, filename, translatedList, format):
|
def flush_progress_csv(writeFile, writer, rows):
|
||||||
|
"""Flush current CSV progress to the already-open output file (Windows-safe)."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE or writeFile is None:
|
||||||
|
return
|
||||||
|
with LOCK:
|
||||||
|
writeFile.seek(0)
|
||||||
|
# Recreate writer at current position to avoid state issues
|
||||||
|
tmp_writer = csv.writer(writeFile, delimiter=",")
|
||||||
|
tmp_writer.writerows(rows)
|
||||||
|
writeFile.truncate()
|
||||||
|
writeFile.flush()
|
||||||
|
os.fsync(writeFile.fileno())
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def translateCSV(data, pbar, writeFile, writer, filename, translatedList, format):
|
||||||
global LOCK, ESTIMATE, PBAR
|
global LOCK, ESTIMATE, PBAR
|
||||||
PBAR = pbar
|
PBAR = pbar
|
||||||
translatedText = ""
|
translatedText = ""
|
||||||
|
|
@ -254,6 +272,7 @@ def translateCSV(data, pbar, writer, filename, translatedList, format):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i][1] = translatedText
|
data[i][1] = translatedText
|
||||||
|
flush_progress_csv(writeFile, writer, data)
|
||||||
|
|
||||||
# Iterate
|
# Iterate
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -286,6 +305,7 @@ def translateCSV(data, pbar, writer, filename, translatedList, format):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i][targetColumn] = translatedText
|
data[i][targetColumn] = translatedText
|
||||||
|
flush_progress_csv(writeFile, writer, data)
|
||||||
|
|
||||||
# Iterate
|
# Iterate
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -369,6 +389,7 @@ def translateCSV(data, pbar, writer, filename, translatedList, format):
|
||||||
data[i][j + 1] = data[i][j + 1].replace(ojaString, f"{translatedText}")
|
data[i][j + 1] = data[i][j + 1].replace(ojaString, f"{translatedText}")
|
||||||
else:
|
else:
|
||||||
data[i][j] = data[i][j].replace(ojaString, f"{translatedText}")
|
data[i][j] = data[i][j].replace(ojaString, f"{translatedText}")
|
||||||
|
flush_progress_csv(writeFile, writer, data)
|
||||||
|
|
||||||
# Iterate
|
# Iterate
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -429,6 +450,7 @@ def translateCSV(data, pbar, writer, filename, translatedList, format):
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
data[i][textColumn] = translatedText
|
data[i][textColumn] = translatedText
|
||||||
|
flush_progress_csv(writeFile, writer, data)
|
||||||
|
|
||||||
# Iterate
|
# Iterate
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -460,6 +482,7 @@ def translateCSV(data, pbar, writer, filename, translatedList, format):
|
||||||
if not ESTIMATE:
|
if not ESTIMATE:
|
||||||
for row in data:
|
for row in data:
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
flush_progress_csv(writeFile, writer, data)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
@ -469,6 +492,7 @@ def translateCSV(data, pbar, writer, filename, translatedList, format):
|
||||||
if not ESTIMATE:
|
if not ESTIMATE:
|
||||||
for row in data:
|
for row in data:
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
flush_progress_csv(writeFile, writer, data)
|
||||||
return totalTokens
|
return totalTokens
|
||||||
|
|
||||||
return totalTokens
|
return totalTokens
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -75,8 +76,9 @@ TRANSLATION_CONFIG = TranslationConfig(
|
||||||
LEAVE = False
|
LEAVE = False
|
||||||
|
|
||||||
def handleJSON(filename, estimate):
|
def handleJSON(filename, estimate):
|
||||||
global ESTIMATE, totalTokens
|
global ESTIMATE, totalTokens, FILENAME
|
||||||
ESTIMATE = estimate
|
ESTIMATE = estimate
|
||||||
|
FILENAME = filename
|
||||||
|
|
||||||
if estimate:
|
if estimate:
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
@ -160,7 +162,7 @@ def parseJSON(data, filename):
|
||||||
pbar.desc = filename
|
pbar.desc = filename
|
||||||
PBAR = pbar
|
PBAR = pbar
|
||||||
try:
|
try:
|
||||||
result = translateJSON(data, [])
|
result = translateJSON(data, filename, [])
|
||||||
totalTokens[0] += result[0]
|
totalTokens[0] += result[0]
|
||||||
totalTokens[1] += result[1]
|
totalTokens[1] += result[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -169,7 +171,30 @@ def parseJSON(data, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
def translateJSON(data, translatedList):
|
def save_progress_json(data, filename):
|
||||||
|
"""Atomically save current JSON translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding="utf-8", newline="\n") as tmp_file:
|
||||||
|
json.dump(data, tmp_file, ensure_ascii=False, indent=4)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
# In case of exception before replace
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
# Best-effort; don't crash the run on save failures
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def translateJSON(data, filename, translatedList):
|
||||||
global LOCK, ESTIMATE, FILENAME, PBAR, MISMATCH
|
global LOCK, ESTIMATE, FILENAME, PBAR, MISMATCH
|
||||||
if translatedList:
|
if translatedList:
|
||||||
stringList = translatedList[0]
|
stringList = translatedList[0]
|
||||||
|
|
@ -266,7 +291,10 @@ def translateJSON(data, translatedList):
|
||||||
if "『" in data[i][messageKey] and "』" not in translatedText:
|
if "『" in data[i][messageKey] and "』" not in translatedText:
|
||||||
data[i][messageKey] = data[i][messageKey].replace(originalString, f"『{translatedText}』")
|
data[i][messageKey] = data[i][messageKey].replace(originalString, f"『{translatedText}』")
|
||||||
else:
|
else:
|
||||||
data[i][messageKey] = data[i][messageKey].replace(originalString, f"{translatedText}")
|
data[i][messageKey] = data[i][messageKey].replace(originalString, f"{translatedText}")
|
||||||
|
|
||||||
|
# Save progress after each message replacement
|
||||||
|
save_progress_json(data, filename)
|
||||||
# Next Value
|
# Next Value
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
@ -290,7 +318,7 @@ def translateJSON(data, translatedList):
|
||||||
MISMATCH.append(FILENAME)
|
MISMATCH.append(FILENAME)
|
||||||
|
|
||||||
# Set Strings
|
# Set Strings
|
||||||
translateJSON(data, [stringListTL])
|
translateJSON(data, filename, [stringListTL])
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
# Save some money and enter the character before translation
|
# Save some money and enter the character before translation
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -181,6 +182,27 @@ def parseKiriKiri(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_lines(lines, filename, encoding="cp932"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def translateKiriKiri(data, pbar, filename, jobList):
|
def translateKiriKiri(data, pbar, filename, jobList):
|
||||||
# Check Job Data
|
# Check Job Data
|
||||||
if len(jobList) > 0:
|
if len(jobList) > 0:
|
||||||
|
|
@ -213,6 +235,7 @@ def translateKiriKiri(data, pbar, filename, jobList):
|
||||||
tokens[0] += response[1][0]
|
tokens[0] += response[1][0]
|
||||||
tokens[1] += response[1][1]
|
tokens[1] += response[1][1]
|
||||||
data[i] = data[i].replace(speakerJA, speaker)
|
data[i] = data[i].replace(speakerJA, speaker)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# Choices
|
# Choices
|
||||||
|
|
@ -234,6 +257,7 @@ def translateKiriKiri(data, pbar, filename, jobList):
|
||||||
data[i] = data[i].replace("'", '"')
|
data[i] = data[i].replace("'", '"')
|
||||||
translatedText = translatedText.replace('"', "'")
|
translatedText = translatedText.replace('"', "'")
|
||||||
data[i] = data[i].replace(jaString, translatedText)
|
data[i] = data[i].replace(jaString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Dialogue
|
# Dialogue
|
||||||
match = re.search(dialogueRegex, data[i])
|
match = re.search(dialogueRegex, data[i])
|
||||||
|
|
@ -277,6 +301,7 @@ def translateKiriKiri(data, pbar, filename, jobList):
|
||||||
data[i] = data[i].replace("'", '"')
|
data[i] = data[i].replace("'", '"')
|
||||||
translatedText = translatedText.replace('"', "'")
|
translatedText = translatedText.replace('"', "'")
|
||||||
data[i] = data[i].replace(jaString, translatedText)
|
data[i] = data[i].replace(jaString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Next Line
|
# Next Line
|
||||||
i += 1
|
i += 1
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -168,6 +169,27 @@ def parseJSON(data, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_json(data, filename):
|
||||||
|
"""Atomically save current JSON translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding="utf-8", newline="\n") as tmp_file:
|
||||||
|
json.dump(data, tmp_file, ensure_ascii=False, indent=4)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def translateJSON(data, pbar):
|
def translateJSON(data, pbar):
|
||||||
global PBAR
|
global PBAR
|
||||||
PBAR = pbar
|
PBAR = pbar
|
||||||
|
|
@ -190,6 +212,7 @@ def translateJSON(data, pbar):
|
||||||
tokens[0] += response[1][0]
|
tokens[0] += response[1][0]
|
||||||
tokens[1] += response[1][1]
|
tokens[1] += response[1][1]
|
||||||
item["name"] = speaker
|
item["name"] = speaker
|
||||||
|
save_progress_json(data, FILENAME or "output.json")
|
||||||
else:
|
else:
|
||||||
speaker = "None"
|
speaker = "None"
|
||||||
|
|
||||||
|
|
@ -259,6 +282,7 @@ def translateJSON(data, pbar):
|
||||||
|
|
||||||
# Set Text
|
# Set Text
|
||||||
item[text] = translatedText
|
item[text] = translatedText
|
||||||
|
save_progress_json(data, FILENAME or "output.json")
|
||||||
translatedBatch.pop(0)
|
translatedBatch.pop(0)
|
||||||
speaker = ""
|
speaker = ""
|
||||||
currentGroup = []
|
currentGroup = []
|
||||||
|
|
@ -295,6 +319,8 @@ def translateJSON(data, pbar):
|
||||||
batch.clear()
|
batch.clear()
|
||||||
|
|
||||||
currentGroup = []
|
currentGroup = []
|
||||||
|
# After applying a batch, persist progress
|
||||||
|
save_progress_json(data, FILENAME or "output.json")
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
# Save some money and enter the character before translation
|
# Save some money and enter the character before translation
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -185,6 +186,27 @@ def parseOnscripter(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_lines(lines, filename, encoding="cp932"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def translateOnscripter(data, pbar, filename, translatedList):
|
def translateOnscripter(data, pbar, filename, translatedList):
|
||||||
stringList = []
|
stringList = []
|
||||||
currentGroup = []
|
currentGroup = []
|
||||||
|
|
@ -272,6 +294,7 @@ def translateOnscripter(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, f"{translatedText}")
|
data[i] = data[i].replace(originalString, f"{translatedText}")
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# Choices
|
# Choices
|
||||||
|
|
@ -295,6 +318,7 @@ def translateOnscripter(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set
|
# Set
|
||||||
data[i] = data[i].replace(choiceList[j], translatedText)
|
data[i] = data[i].replace(choiceList[j], translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# Nothing relevant. Skip Line.
|
# Nothing relevant. Skip Line.
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -168,7 +169,7 @@ def parseRegex(readFile, filename):
|
||||||
PBAR = pbar
|
PBAR = pbar
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = translateRegex(data, [])
|
result = translateRegex(data, filename, [])
|
||||||
totalTokens[0] += result[0]
|
totalTokens[0] += result[0]
|
||||||
totalTokens[1] += result[1]
|
totalTokens[1] += result[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -177,7 +178,28 @@ def parseRegex(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
def translateRegex(data, translatedList):
|
def save_progress_lines(lines, filename, encoding="utf-8-sig"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def translateRegex(data, filename, translatedList):
|
||||||
if translatedList:
|
if translatedList:
|
||||||
stringList = translatedList[0]
|
stringList = translatedList[0]
|
||||||
choiceList = translatedList[1]
|
choiceList = translatedList[1]
|
||||||
|
|
@ -213,6 +235,7 @@ def translateRegex(data, translatedList):
|
||||||
if not translatedList:
|
if not translatedList:
|
||||||
title = re.sub(r"(?<!\\)'", r"\\'", title)
|
title = re.sub(r"(?<!\\)'", r"\\'", title)
|
||||||
data[i] = data[i].replace(match.group(1), title)
|
data[i] = data[i].replace(match.group(1), title)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Speaker
|
# Speaker
|
||||||
match = re.search(lineRegexSpeaker, data[i])
|
match = re.search(lineRegexSpeaker, data[i])
|
||||||
|
|
@ -227,6 +250,7 @@ def translateRegex(data, translatedList):
|
||||||
tokens[1] += response[1][1]
|
tokens[1] += response[1][1]
|
||||||
if translatedList:
|
if translatedList:
|
||||||
data[i] = data[i].replace(match.group(1), speaker)
|
data[i] = data[i].replace(match.group(1), speaker)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 3
|
i += 3
|
||||||
else:
|
else:
|
||||||
speaker = None
|
speaker = None
|
||||||
|
|
@ -287,7 +311,8 @@ def translateRegex(data, translatedList):
|
||||||
if "「" in data[i-1] and "」" not in translatedText:
|
if "「" in data[i-1] and "」" not in translatedText:
|
||||||
data[i] = data[i].replace(originalString, f"「{translatedText}」")
|
data[i] = data[i].replace(originalString, f"「{translatedText}」")
|
||||||
else:
|
else:
|
||||||
data[i] = data[i].replace(originalString, f"{translatedText}")
|
data[i] = data[i].replace(originalString, f"{translatedText}")
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Choices
|
# Choices
|
||||||
match = re.search(choiceRegex, data[i])
|
match = re.search(choiceRegex, data[i])
|
||||||
|
|
@ -311,6 +336,7 @@ def translateRegex(data, translatedList):
|
||||||
|
|
||||||
# Set
|
# Set
|
||||||
data[i] = data[i].replace(match.group(1), translatedText)
|
data[i] = data[i].replace(match.group(1), translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
|
|
@ -350,7 +376,7 @@ def translateRegex(data, translatedList):
|
||||||
MISMATCH.append(FILENAME)
|
MISMATCH.append(FILENAME)
|
||||||
|
|
||||||
# Set Strings
|
# Set Strings
|
||||||
translateRegex(data, [stringListTL, choiceListTL])
|
translateRegex(data, filename, [stringListTL, choiceListTL])
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
# Save some money and enter the character before translation
|
# Save some money and enter the character before translation
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -172,7 +173,7 @@ def parseRenpy(readFile, filename):
|
||||||
PBAR = pbar
|
PBAR = pbar
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = translateRenpy(data, [])
|
result = translateRenpy(data, filename, [])
|
||||||
totalTokens[0] += result[0]
|
totalTokens[0] += result[0]
|
||||||
totalTokens[1] += result[1]
|
totalTokens[1] += result[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -181,7 +182,28 @@ def parseRenpy(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
def translateRenpy(data, translatedList):
|
def save_progress_lines(lines, filename, encoding="utf-8"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def translateRenpy(data, filename, translatedList):
|
||||||
stringList = []
|
stringList = []
|
||||||
currentGroup = []
|
currentGroup = []
|
||||||
tokens = [0, 0]
|
tokens = [0, 0]
|
||||||
|
|
@ -250,6 +272,7 @@ def translateRenpy(data, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -268,7 +291,7 @@ def translateRenpy(data, translatedList):
|
||||||
|
|
||||||
# Set Strings
|
# Set Strings
|
||||||
if len(stringList) == len(translatedList):
|
if len(stringList) == len(translatedList):
|
||||||
translateRenpy(data, translatedList)
|
translateRenpy(data, filename, translatedList)
|
||||||
|
|
||||||
# Mismatch
|
# Mismatch
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import traceback
|
||||||
import tiktoken
|
import tiktoken
|
||||||
import openai
|
import openai
|
||||||
import copy
|
import copy
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
# Removed concurrent.futures usage for simplicity; running synchronously
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
@ -242,6 +242,24 @@ def getResultString(translatedData, translationTime, filename):
|
||||||
return filename + ": " + totalTokenstring + timeString + Fore.RED + " \u2717 " + errorString + Fore.RESET
|
return filename + ": " + totalTokenstring + timeString + Fore.RED + " \u2717 " + errorString + Fore.RESET
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_yaml(data, filename):
|
||||||
|
"""Atomically write current YAML data to translated/filename; skip in estimate mode."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_path = os.path.join("translated", f"{filename}.tmp")
|
||||||
|
final_path = os.path.join("translated", filename)
|
||||||
|
yaml = YAML(pure=True)
|
||||||
|
yaml.width = 4096
|
||||||
|
yaml.default_style = "'"
|
||||||
|
with open(tmp_path, "w", encoding="utf-8", newline="\n") as outFile:
|
||||||
|
yaml.dump(data, outFile)
|
||||||
|
os.replace(tmp_path, final_path)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def parseMap(data, filename):
|
def parseMap(data, filename):
|
||||||
totalTokens = [0, 0]
|
totalTokens = [0, 0]
|
||||||
totalLines = 0
|
totalLines = 0
|
||||||
|
|
@ -259,26 +277,27 @@ def parseMap(data, filename):
|
||||||
totalTokens[1] += response[1][1]
|
totalTokens[1] += response[1][1]
|
||||||
data["display_name"] = response[0].replace('"', "")
|
data["display_name"] = response[0].replace('"', "")
|
||||||
|
|
||||||
# Thread for each page in file
|
# Process each page synchronously and persist after each
|
||||||
with tqdm(bar_format=BAR_FORMAT, position=POSITION, leave=LEAVE) as pbar:
|
with tqdm(bar_format=BAR_FORMAT, position=POSITION, leave=LEAVE) as pbar:
|
||||||
pbar.desc = filename
|
pbar.desc = filename
|
||||||
with ThreadPoolExecutor(max_workers=THREADS) as executor:
|
for key in events:
|
||||||
for key in events:
|
if key is not None:
|
||||||
if key is not None:
|
# This translates ID of events. (May break the game)
|
||||||
# This translates ID of events. (May break the game)
|
if "<namepop" in events[key]["name"]:
|
||||||
if "<namepop" in events[key]["name"]:
|
response = translateNoteOmitSpace(events[key], r"<namepop\s(.*?)\s?\d?>.*")
|
||||||
response = translateNoteOmitSpace(events[key], r"<namepop\s(.*?)\s?\d?>.*")
|
totalTokens[0] += response[0]
|
||||||
totalTokens[0] += response[0]
|
totalTokens[1] += response[1]
|
||||||
totalTokens[1] += response[1]
|
for page in events[key]["pages"]:
|
||||||
futures = [executor.submit(searchCodes, page, pbar, [], filename) for page in events[key]["pages"] if page is not None]
|
if page is not None:
|
||||||
for future in as_completed(futures):
|
|
||||||
try:
|
try:
|
||||||
totalTokensFuture = future.result()
|
tt = searchCodes(page, pbar, [], filename)
|
||||||
totalTokens[0] += totalTokensFuture[0]
|
totalTokens[0] += tt[0]
|
||||||
totalTokens[1] += totalTokensFuture[1]
|
totalTokens[1] += tt[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_yaml(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -356,16 +375,17 @@ def parseCommonEvents(data, filename):
|
||||||
|
|
||||||
with tqdm(bar_format=BAR_FORMAT, position=POSITION, leave=LEAVE) as pbar:
|
with tqdm(bar_format=BAR_FORMAT, position=POSITION, leave=LEAVE) as pbar:
|
||||||
pbar.desc = filename
|
pbar.desc = filename
|
||||||
with ThreadPoolExecutor(max_workers=THREADS) as executor:
|
for page in data:
|
||||||
futures = [executor.submit(searchCodes, page, pbar, [], filename) for page in data if page is not None]
|
if page is not None:
|
||||||
for future in as_completed(futures):
|
|
||||||
try:
|
try:
|
||||||
totalTokensFuture = future.result()
|
tt = searchCodes(page, pbar, [], filename)
|
||||||
totalTokens[0] += totalTokensFuture[0]
|
totalTokens[0] += tt[0]
|
||||||
totalTokens[1] += totalTokensFuture[1]
|
totalTokens[1] += tt[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_yaml(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -384,16 +404,17 @@ def parseTroops(data, filename):
|
||||||
pbar.desc = filename
|
pbar.desc = filename
|
||||||
for troop in data:
|
for troop in data:
|
||||||
if troop is not None:
|
if troop is not None:
|
||||||
with ThreadPoolExecutor(max_workers=THREADS) as executor:
|
for page in troop["pages"]:
|
||||||
futures = [executor.submit(searchCodes, page, pbar, [], filename) for page in troop["pages"] if page is not None]
|
if page is not None:
|
||||||
for future in as_completed(futures):
|
|
||||||
try:
|
try:
|
||||||
totalTokensFuture = future.result()
|
tt = searchCodes(page, pbar, [], filename)
|
||||||
totalTokens[0] += totalTokensFuture[0]
|
totalTokens[0] += tt[0]
|
||||||
totalTokens[1] += totalTokensFuture[1]
|
totalTokens[1] += tt[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_yaml(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -411,6 +432,8 @@ def parseNames(data, filename, context):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_yaml(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -430,6 +453,8 @@ def parseSS(data, filename):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_yaml(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -456,6 +481,8 @@ def parseSystem(data, filename):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_yaml(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -470,16 +497,17 @@ def parseScenario(data, filename):
|
||||||
|
|
||||||
with tqdm(bar_format=BAR_FORMAT, position=POSITION, leave=LEAVE) as pbar:
|
with tqdm(bar_format=BAR_FORMAT, position=POSITION, leave=LEAVE) as pbar:
|
||||||
pbar.desc = filename
|
pbar.desc = filename
|
||||||
with ThreadPoolExecutor(max_workers=THREADS) as executor:
|
for page in data.items():
|
||||||
futures = [executor.submit(searchCodes, page[1], pbar, [], filename) for page in data.items() if page[1] is not None]
|
if page[1] is not None:
|
||||||
for future in as_completed(futures):
|
|
||||||
try:
|
try:
|
||||||
totalTokensFuture = future.result()
|
tt = searchCodes(page[1], pbar, [], filename)
|
||||||
totalTokens[0] += totalTokensFuture[0]
|
totalTokens[0] += tt[0]
|
||||||
totalTokens[1] += totalTokensFuture[1]
|
totalTokens[1] += tt[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_yaml(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -176,6 +177,27 @@ def parsePlugin(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_lines(lines, filename, encoding="utf_8"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def translatePlugin(data, pbar, filename, translatedList):
|
def translatePlugin(data, pbar, filename, translatedList):
|
||||||
if len(translatedList) > 0:
|
if len(translatedList) > 0:
|
||||||
questList = translatedList[0]
|
questList = translatedList[0]
|
||||||
|
|
@ -259,6 +281,7 @@ def translatePlugin(data, pbar, filename, translatedList):
|
||||||
with open("translations.txt", "a+", encoding="utf-8") as tlFile:
|
with open("translations.txt", "a+", encoding="utf-8") as tlFile:
|
||||||
tlFile.write(f"{originalString} ({translatedText})\n")
|
tlFile.write(f"{originalString} ({translatedText})\n")
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Quest Name
|
# Quest Name
|
||||||
regex = r'[\\]+"QuestName[\\]+":[\\]+"(.*?)[\\]+"'
|
regex = r'[\\]+"QuestName[\\]+":[\\]+"(.*?)[\\]+"'
|
||||||
|
|
@ -295,6 +318,7 @@ def translatePlugin(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Quest Client
|
# Quest Client
|
||||||
regex = r'QuestClientName[\\]+":[\\]+"(.*?)[\\]+"'
|
regex = r'QuestClientName[\\]+":[\\]+"(.*?)[\\]+"'
|
||||||
|
|
@ -328,6 +352,7 @@ def translatePlugin(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Quest Location
|
# Quest Location
|
||||||
regex = r'QuestLocation[\\]+":[\\]+"(.*?)[\\]+"'
|
regex = r'QuestLocation[\\]+":[\\]+"(.*?)[\\]+"'
|
||||||
|
|
@ -361,6 +386,7 @@ def translatePlugin(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Quest Target
|
# Quest Target
|
||||||
regex = r'PlaceInformation[\\]+":[\\]+"(.*?)[\\]+"'
|
regex = r'PlaceInformation[\\]+":[\\]+"(.*?)[\\]+"'
|
||||||
|
|
@ -394,6 +420,7 @@ def translatePlugin(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Quest Summary
|
# Quest Summary
|
||||||
regex = r'[\\]+"QuestContent[\\]+":[\\]+"[\\]+"(.*?)[\\]+"[\\]+"'
|
regex = r'[\\]+"QuestContent[\\]+":[\\]+"[\\]+"(.*?)[\\]+"[\\]+"'
|
||||||
|
|
@ -436,6 +463,7 @@ def translatePlugin(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Quest Goal 1
|
# Quest Goal 1
|
||||||
regex = r'ObjectiveContent[\\]+":[\\]+"[\\]+"(.*?)[\\]+"'
|
regex = r'ObjectiveContent[\\]+":[\\]+"[\\]+"(.*?)[\\]+"'
|
||||||
|
|
@ -476,6 +504,7 @@ def translatePlugin(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Next Line
|
# Next Line
|
||||||
i += 1
|
i += 1
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -161,7 +162,7 @@ def parseText(readFile, filename):
|
||||||
PBAR = pbar
|
PBAR = pbar
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = translateTxt(data, [])
|
result = translateTxt(data, filename, [])
|
||||||
totalTokens[0] += result[0]
|
totalTokens[0] += result[0]
|
||||||
totalTokens[1] += result[1]
|
totalTokens[1] += result[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -170,7 +171,28 @@ def parseText(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
def translateTxt(data, translatedList):
|
def save_progress_lines(lines, filename, encoding="utf-8"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def translateTxt(data, filename, translatedList):
|
||||||
if translatedList:
|
if translatedList:
|
||||||
stringList = translatedList[0]
|
stringList = translatedList[0]
|
||||||
choiceList = translatedList[1]
|
choiceList = translatedList[1]
|
||||||
|
|
@ -224,6 +246,7 @@ def translateTxt(data, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = f"{translatedText}\n"
|
data[i] = f"{translatedText}\n"
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
|
|
@ -263,7 +286,7 @@ def translateTxt(data, translatedList):
|
||||||
MISMATCH.append(FILENAME)
|
MISMATCH.append(FILENAME)
|
||||||
|
|
||||||
# Set Strings
|
# Set Strings
|
||||||
translateTxt(data, [stringListTL, choiceListTL])
|
translateTxt(data, filename, [stringListTL, choiceListTL])
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
# Save some money and enter the character before translation
|
# Save some money and enter the character before translation
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -161,7 +162,7 @@ def parseTyrano(readFile, filename):
|
||||||
PBAR = pbar
|
PBAR = pbar
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = translateTyrano(data, [])
|
result = translateTyrano(data, filename, [])
|
||||||
totalTokens[0] += result[0]
|
totalTokens[0] += result[0]
|
||||||
totalTokens[1] += result[1]
|
totalTokens[1] += result[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -170,7 +171,28 @@ def parseTyrano(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
def translateTyrano(data, translatedList):
|
def save_progress_lines(lines, filename, encoding="utf-8"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def translateTyrano(data, filename, translatedList):
|
||||||
if translatedList:
|
if translatedList:
|
||||||
stringList = translatedList[0]
|
stringList = translatedList[0]
|
||||||
choiceList = translatedList[1]
|
choiceList = translatedList[1]
|
||||||
|
|
@ -291,6 +313,8 @@ def translateTyrano(data, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = data[i].replace(originalString, translatedText)
|
data[i] = data[i].replace(originalString, translatedText)
|
||||||
|
# Save progress after each line change
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Choices
|
# Choices
|
||||||
match = re.search(choiceRegex, data[i])
|
match = re.search(choiceRegex, data[i])
|
||||||
|
|
@ -311,6 +335,7 @@ def translateTyrano(data, translatedList):
|
||||||
|
|
||||||
# Set
|
# Set
|
||||||
data[i] = data[i].replace(match.group(1), translatedText)
|
data[i] = data[i].replace(match.group(1), translatedText)
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
|
|
@ -350,7 +375,7 @@ def translateTyrano(data, translatedList):
|
||||||
MISMATCH.append(FILENAME)
|
MISMATCH.append(FILENAME)
|
||||||
|
|
||||||
# Set Strings
|
# Set Strings
|
||||||
translateTyrano(data, [stringListTL, choiceListTL])
|
translateTyrano(data, filename, [stringListTL, choiceListTL])
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
# Save some money and enter the character before translation
|
# Save some money and enter the character before translation
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -184,6 +185,27 @@ def parseUnity(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_lines(lines, filename, encoding="utf-8"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def translateUnity(data, pbar, filename, translatedList):
|
def translateUnity(data, pbar, filename, translatedList):
|
||||||
stringList = []
|
stringList = []
|
||||||
tokens = [0, 0]
|
tokens = [0, 0]
|
||||||
|
|
@ -237,6 +259,7 @@ def translateUnity(data, pbar, filename, translatedList):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data[i] = f"{leftString}={translatedText}\n"
|
data[i] = f"{leftString}={translatedText}\n"
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# Nothing relevant. Skip Line.
|
# Nothing relevant. Skip Line.
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import time
|
||||||
import traceback
|
import traceback
|
||||||
import tiktoken
|
import tiktoken
|
||||||
import openai
|
import openai
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
# Removed concurrent.futures usage for simplicity; running synchronously
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
@ -190,6 +190,21 @@ def getResultString(translatedData, translationTime, filename):
|
||||||
return filename + ": " + totalTokenstring + timeString + Fore.RED + " \u2717 " + errorString + Fore.RESET
|
return filename + ": " + totalTokenstring + timeString + Fore.RED + " \u2717 " + errorString + Fore.RESET
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_json(data, filename):
|
||||||
|
"""Atomically write current JSON data to translated/filename; skip in estimate mode."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_path = os.path.join("translated", f"{filename}.tmp")
|
||||||
|
final_path = os.path.join("translated", filename)
|
||||||
|
with open(tmp_path, "w", encoding="utf-8", newline="\n") as outFile:
|
||||||
|
json.dump(data, outFile, ensure_ascii=False, indent=4)
|
||||||
|
os.replace(tmp_path, final_path)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def parseOther(data, filename):
|
def parseOther(data, filename):
|
||||||
totalTokens = [0, 0]
|
totalTokens = [0, 0]
|
||||||
totalLines = 0
|
totalLines = 0
|
||||||
|
|
@ -206,6 +221,8 @@ def parseOther(data, filename):
|
||||||
totalTokens[1] += translationData[1]
|
totalTokens[1] += translationData[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_json(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -225,6 +242,8 @@ def parseDB(data, filename):
|
||||||
totalTokens[1] += translationData[1]
|
totalTokens[1] += translationData[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_json(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -240,21 +259,22 @@ def parseMap(data, filename):
|
||||||
for page in event["pages"]:
|
for page in event["pages"]:
|
||||||
totalLines += len(page["list"])
|
totalLines += len(page["list"])
|
||||||
|
|
||||||
# Thread for each page in file
|
# Process pages synchronously and persist after each
|
||||||
with tqdm(bar_format=BAR_FORMAT, position=POSITION, total=totalLines, leave=LEAVE) as pbar:
|
with tqdm(bar_format=BAR_FORMAT, position=POSITION, total=totalLines, leave=LEAVE) as pbar:
|
||||||
pbar.desc = filename
|
pbar.desc = filename
|
||||||
pbar.total = totalLines
|
pbar.total = totalLines
|
||||||
with ThreadPoolExecutor(max_workers=THREADS) as executor:
|
for event in events:
|
||||||
for event in events:
|
if event is not None:
|
||||||
if event is not None:
|
for page in event["pages"]:
|
||||||
futures = [executor.submit(searchCodes, page["list"], pbar, None, filename) for page in event["pages"] if page is not None]
|
if page is not None:
|
||||||
for future in as_completed(futures):
|
|
||||||
try:
|
try:
|
||||||
totalTokensFuture = future.result()
|
tt = searchCodes(page["list"], pbar, None, filename)
|
||||||
totalTokens[0] += totalTokensFuture[0]
|
totalTokens[0] += tt[0]
|
||||||
totalTokens[1] += totalTokensFuture[1]
|
totalTokens[1] += tt[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return [data, totalTokens, e]
|
return [data, totalTokens, e]
|
||||||
|
finally:
|
||||||
|
save_progress_json(data, filename)
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from dotenv import load_dotenv
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
from util.translation import TranslationConfig, translateAI as sharedtranslateAI, getPricingConfig, calculateCost
|
||||||
|
import tempfile
|
||||||
|
|
||||||
# Open AI
|
# Open AI
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
@ -175,6 +176,27 @@ def parseWOLF(readFile, filename):
|
||||||
return [data, totalTokens, None]
|
return [data, totalTokens, None]
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_lines(lines, filename, encoding="shift_jis"):
|
||||||
|
"""Atomically save current line-based translation progress."""
|
||||||
|
try:
|
||||||
|
if ESTIMATE:
|
||||||
|
return
|
||||||
|
os.makedirs("translated", exist_ok=True)
|
||||||
|
tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated")
|
||||||
|
try:
|
||||||
|
with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file:
|
||||||
|
tmp_file.writelines(lines)
|
||||||
|
os.replace(tmp_path, os.path.join("translated", filename))
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp_path):
|
||||||
|
try:
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def translateWOLF(data, translatedList, pbar, filename):
|
def translateWOLF(data, translatedList, pbar, filename):
|
||||||
stringList = []
|
stringList = []
|
||||||
currentGroup = []
|
currentGroup = []
|
||||||
|
|
@ -193,6 +215,7 @@ def translateWOLF(data, translatedList, pbar, filename):
|
||||||
tokens[0] += response[1][0]
|
tokens[0] += response[1][0]
|
||||||
tokens[1] += response[1][1]
|
tokens[1] += response[1][1]
|
||||||
data[i] = data[i].replace(matchList[0], f"{speaker}")
|
data[i] = data[i].replace(matchList[0], f"{speaker}")
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
speaker = ""
|
speaker = ""
|
||||||
|
|
@ -221,6 +244,7 @@ def translateWOLF(data, translatedList, pbar, filename):
|
||||||
data[i] = f"//{choiceListTL[0]}\n"
|
data[i] = f"//{choiceListTL[0]}\n"
|
||||||
choiceListTL.pop(0)
|
choiceListTL.pop(0)
|
||||||
i += 1
|
i += 1
|
||||||
|
save_progress_lines(data, filename)
|
||||||
|
|
||||||
# Mismatch
|
# Mismatch
|
||||||
else:
|
else:
|
||||||
|
|
@ -278,6 +302,7 @@ def translateWOLF(data, translatedList, pbar, filename):
|
||||||
|
|
||||||
# Set Data
|
# Set Data
|
||||||
data.insert(i, f"{translatedText}\n")
|
data.insert(i, f"{translatedText}\n")
|
||||||
|
save_progress_lines(data, filename)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# Nothing relevant. Skip Line.
|
# Nothing relevant. Skip Line.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue