diff --git a/modules/csv.py b/modules/csv.py index b794059..2f1b8bb 100644 --- a/modules/csv.py +++ b/modules/csv.py @@ -14,6 +14,7 @@ from colorama import Fore from dotenv import load_dotenv from retry import retry from tqdm import tqdm +from util.translation import TranslationConfig, translateAI as sharedtranslateAI # Open AI load_dotenv() @@ -78,6 +79,18 @@ LEAVE = False PBAR = None ENCODING = "utf8" +# Initialize Translation Config +TRANSLATION_CONFIG = TranslationConfig( + model=MODEL, + language=LANGUAGE, + prompt=PROMPT, + vocab=VOCAB, + langRegex=LANGREGEX, + batchSize=BATCHSIZE, + maxHistory=MAXHISTORY, + estimateMode=False # Will be set dynamically based on ESTIMATE +) +LEAVE = False def handleCSV(filename, estimate): global ESTIMATE, TOKENS @@ -406,7 +419,7 @@ def translateCSV(data, pbar, writer, filename, translatedList, format): pbar.refresh() # Translate - response = translateGPT(stringList, "", True) + response = translateAI(stringList, "", True) totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] translatedList = response[0] @@ -453,7 +466,7 @@ def getSpeaker(speaker): return [NAMESLIST[i][1], [0, 0]] # Translate and Store Speaker - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -464,7 +477,7 @@ def getSpeaker(speaker): # Retry if name doesn't translate for some reason if re.search(r"([a-zA-Z??])", response[0]) == None: - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -477,328 +490,24 @@ def getSpeaker(speaker): return response return [speaker, [0, 0]] - -def batchList(input_list, batch_size): - if not isinstance(batch_size, int) or batch_size <= 0: - raise ValueError("batch_size must be a positive integer") - - return [input_list[i : i + batch_size] for i in range(0, len(input_list), batch_size)] - - -def parseVocabWithCategories(vocabText): - """Parse vocabulary text and extract terms with their categories.""" - pairs = [] - seen = set() - currentCategory = None - - for line in vocabText.splitlines(): - line = line.strip() - if not line or line.startswith('```'): - continue - - # Check if this is a category header - if line.startswith('#'): - currentCategory = line - continue - - # Parse vocabulary term - m = re.match(r'^(.+?)(?:\s?[\(–])', line) # term is everything before space + '(' or '–' - if m: - term = m.group(1) - if term not in seen: - pairs.append((term, line, currentCategory)) - seen.add(term) - - return pairs - - -def buildMatchedVocabText(vocabPairs, subbedT): - """Build formatted vocabulary text with matched terms organized by category.""" - matchedCategories = {} - - # Use word boundaries for Japanese if appropriate, or allow substring as before. - for term, line, category in vocabPairs: - # "term in subbedT" could be false positive; can use regex but Japanese doesn't always have spaces. - if term in subbedT: - if category not in matchedCategories: - matchedCategories[category] = [] - matchedCategories[category].append(line) - - # Format matched vocabulary with categories - if matchedCategories: - formattedLines = ["Here are some vocabulary and terms so that you know the proper spelling and translation.\n"] - for category, lines in matchedCategories.items(): - if category: # Only add category header if it exists - formattedLines.append(category) - formattedLines.extend(lines) - formattedLines.append("") # Add blank line between categories - matchedVocabText = f"```\n{chr(10).join(formattedLines).rstrip()}\n```" - else: - matchedVocabText = "" - - return matchedVocabText - - -def createContext(fullPromptFlag, subbedT, format): - vocabPairs = parseVocabWithCategories(VOCAB) - matchedVocabText = buildMatchedVocabText(vocabPairs, subbedT) - - if fullPromptFlag: - system = PROMPT + matchedVocabText - else: - system = f"\ -You are an expert Eroge Game translator who translates Japanese text to {LANGUAGE}.\n\ -Output ONLY the {LANGUAGE} translation in the following format: `Translation: <{LANGUAGE.upper()}_TRANSLATION>`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?= len(data): # Translate - response = translateGPT(batch, textHistory, True) + response = translateAI(batch, textHistory, True) tokens[0] += response[1][0] tokens[1] += response[1][1] translatedBatch = response[0] @@ -314,7 +327,7 @@ def getSpeaker(speaker): return [NAMESLIST[i][1], [0, 0]] # Translate and Store Speaker - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -325,7 +338,7 @@ def getSpeaker(speaker): # Retry if name doesn't translate for some reason if re.search(r"([a-zA-Z??])", response[0]) == None: - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -338,328 +351,24 @@ def getSpeaker(speaker): return response return [speaker, [0, 0]] - -def batchList(input_list, batch_size): - if not isinstance(batch_size, int) or batch_size <= 0: - raise ValueError("batch_size must be a positive integer") - - return [input_list[i : i + batch_size] for i in range(0, len(input_list), batch_size)] - - -def parseVocabWithCategories(vocabText): - """Parse vocabulary text and extract terms with their categories.""" - pairs = [] - seen = set() - currentCategory = None - - for line in vocabText.splitlines(): - line = line.strip() - if not line or line.startswith('```'): - continue - - # Check if this is a category header - if line.startswith('#'): - currentCategory = line - continue - - # Parse vocabulary term - m = re.match(r'^(.+?)(?:\s?[\(–])', line) # term is everything before space + '(' or '–' - if m: - term = m.group(1) - if term not in seen: - pairs.append((term, line, currentCategory)) - seen.add(term) - - return pairs - - -def buildMatchedVocabText(vocabPairs, subbedT): - """Build formatted vocabulary text with matched terms organized by category.""" - matchedCategories = {} - - # Use word boundaries for Japanese if appropriate, or allow substring as before. - for term, line, category in vocabPairs: - # "term in subbedT" could be false positive; can use regex but Japanese doesn't always have spaces. - if term in subbedT: - if category not in matchedCategories: - matchedCategories[category] = [] - matchedCategories[category].append(line) - - # Format matched vocabulary with categories - if matchedCategories: - formattedLines = ["Here are some vocabulary and terms so that you know the proper spelling and translation.\n"] - for category, lines in matchedCategories.items(): - if category: # Only add category header if it exists - formattedLines.append(category) - formattedLines.extend(lines) - formattedLines.append("") # Add blank line between categories - matchedVocabText = f"```\n{chr(10).join(formattedLines).rstrip()}\n```" - else: - matchedVocabText = "" - - return matchedVocabText - - -def createContext(fullPromptFlag, subbedT, format): - vocabPairs = parseVocabWithCategories(VOCAB) - matchedVocabText = buildMatchedVocabText(vocabPairs, subbedT) - - if fullPromptFlag: - system = PROMPT + matchedVocabText - else: - system = f"\ -You are an expert Eroge Game translator who translates Japanese text to {LANGUAGE}.\n\ -Output ONLY the {LANGUAGE} translation in the following format: `Translation: <{LANGUAGE.upper()}_TRANSLATION>`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(? 0: # Translate - response = translateGPT(choiceList, "This will be a dialogue option", True) + response = translateAI(choiceList, "This will be a dialogue option", True) translatedTextList = response[0] tokens[0] += response[1][0] tokens[1] += response[1][1] @@ -311,7 +324,7 @@ def translateOnscripter(data, pbar, filename, translatedList): pbar.refresh() # Translate - response = translateGPT(stringList, "", True) + response = translateAI(stringList, "", True) tokens[0] += response[1][0] tokens[1] += response[1][1] translatedList = response[0] @@ -373,7 +386,7 @@ def getSpeaker(speaker): return [NAMESLIST[i][1], [0, 0]] # Translate and Store Speaker - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -384,7 +397,7 @@ def getSpeaker(speaker): # Retry if name doesn't translate for some reason if re.search(r"([a-zA-Z??])", response[0]) == None: - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -398,327 +411,9 @@ def getSpeaker(speaker): return [speaker, [0, 0]] -def batchList(input_list, batch_size): - if not isinstance(batch_size, int) or batch_size <= 0: - raise ValueError("batch_size must be a positive integer") - - return [input_list[i : i + batch_size] for i in range(0, len(input_list), batch_size)] - - -def parseVocabWithCategories(vocabText): - """Parse vocabulary text and extract terms with their categories.""" - pairs = [] - seen = set() - currentCategory = None - - for line in vocabText.splitlines(): - line = line.strip() - if not line or line.startswith('```'): - continue - - # Check if this is a category header - if line.startswith('#'): - currentCategory = line - continue - - # Parse vocabulary term - m = re.match(r'^(.+?)(?:\s?[\(–])', line) # term is everything before space + '(' or '–' - if m: - term = m.group(1) - if term not in seen: - pairs.append((term, line, currentCategory)) - seen.add(term) - - return pairs - - -def buildMatchedVocabText(vocabPairs, subbedT): - """Build formatted vocabulary text with matched terms organized by category.""" - matchedCategories = {} - - # Use word boundaries for Japanese if appropriate, or allow substring as before. - for term, line, category in vocabPairs: - # "term in subbedT" could be false positive; can use regex but Japanese doesn't always have spaces. - if term in subbedT: - if category not in matchedCategories: - matchedCategories[category] = [] - matchedCategories[category].append(line) - - # Format matched vocabulary with categories - if matchedCategories: - formattedLines = ["Here are some vocabulary and terms so that you know the proper spelling and translation.\n"] - for category, lines in matchedCategories.items(): - if category: # Only add category header if it exists - formattedLines.append(category) - formattedLines.extend(lines) - formattedLines.append("") # Add blank line between categories - matchedVocabText = f"```\n{chr(10).join(formattedLines).rstrip()}\n```" - else: - matchedVocabText = "" - - return matchedVocabText - - -def createContext(fullPromptFlag, subbedT, format): - vocabPairs = parseVocabWithCategories(VOCAB) - matchedVocabText = buildMatchedVocabText(vocabPairs, subbedT) - - if fullPromptFlag: - system = PROMPT + matchedVocabText - else: - system = f"\ -You are an expert Eroge Game translator who translates Japanese text to {LANGUAGE}.\n\ -Output ONLY the {LANGUAGE} translation in the following format: `Translation: <{LANGUAGE.upper()}_TRANSLATION>`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(? 0: # Translate - response = translateGPT( + response = translateAI( matchList[0], "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -1806,7 +1820,7 @@ def searchCodes(page, pbar, jobList, filename): if len(matchList) > 0: # Translate text = matchList[0] - response = translateGPT(text, "Reply with the " + LANGUAGE + " Translation", False) + response = translateAI(text, "Reply with the " + LANGUAGE + " Translation", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1820,7 +1834,7 @@ def searchCodes(page, pbar, jobList, filename): if len(matchList) > 0: # Translate text = matchList[0] - response = translateGPT(text, "Reply with the " + LANGUAGE + " Translation", False) + response = translateAI(text, "Reply with the " + LANGUAGE + " Translation", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1835,7 +1849,7 @@ def searchCodes(page, pbar, jobList, filename): if len(matchList) > 0: # Translate text = matchList[0] - response = translateGPT(text, "Reply with the " + LANGUAGE + " Translation", False) + response = translateAI(text, "Reply with the " + LANGUAGE + " Translation", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1854,7 +1868,7 @@ def searchCodes(page, pbar, jobList, filename): # Remove any textwrap & TL jaString = re.sub(r"\n", " ", jaString) - response = translateGPT(jaString, "", False) + response = translateAI(jaString, "", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1876,7 +1890,7 @@ def searchCodes(page, pbar, jobList, filename): # Translate question = translatedText - response = translateGPT( + response = translateAI( choiceList, f"Previous text for context: {question}\n", True, @@ -1920,7 +1934,7 @@ def searchCodes(page, pbar, jobList, filename): # Translate if len(textHistory) > 0: - response = translateGPT( + response = translateAI( choiceList, f"Reply with the English translation of the dialogue choice.\n\nPrevious text for context: {str(textHistory)}\n", True, @@ -1929,7 +1943,7 @@ def searchCodes(page, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] else: - response = translateGPT(choiceList, "Reply with the English translation of the dialogue choice.", True) + response = translateAI(choiceList, "Reply with the English translation of the dialogue choice.", True) translatedTextList = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1982,7 +1996,7 @@ def searchCodes(page, pbar, jobList, filename): matchList = re.findall(r"'(.*?)'", jaString) for match in matchList: - response = translateGPT(match, "", False) + response = translateAI(match, "", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2045,7 +2059,7 @@ def searchCodes(page, pbar, jobList, filename): # 401 if len(list401) > 0: - response = translateGPT(list401, "", True) + response = translateAI(list401, "", True) list401TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2056,7 +2070,7 @@ def searchCodes(page, pbar, jobList, filename): # 122 if len(list122) > 0: - response = translateGPT(list122, "Keep your translation as brief as possible", True) + response = translateAI(list122, "Keep your translation as brief as possible", True) list122TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2067,7 +2081,7 @@ def searchCodes(page, pbar, jobList, filename): # 355/655 if len(list355655) > 0: - response = translateGPT(list355655, textHistory, True) + response = translateAI(list355655, textHistory, True) list355655TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2078,7 +2092,7 @@ def searchCodes(page, pbar, jobList, filename): # 108 if len(list108) > 0: - response = translateGPT(list108, textHistory, True) + response = translateAI(list108, textHistory, True) list108TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2089,7 +2103,7 @@ def searchCodes(page, pbar, jobList, filename): # 356 if len(list356) > 0: - response = translateGPT(list356, textHistory, True) + response = translateAI(list356, textHistory, True) list356TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2100,7 +2114,7 @@ def searchCodes(page, pbar, jobList, filename): # 357 if len(list357) > 0: - response = translateGPT(list357, textHistory, True) + response = translateAI(list357, textHistory, True) list357TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2111,7 +2125,7 @@ def searchCodes(page, pbar, jobList, filename): # 408 if len(list408) > 0: - response = translateGPT(list408, "", True) + response = translateAI(list408, "", True) list408TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2155,7 +2169,7 @@ def searchSS(state, pbar): # Name nameResponse = ( - translateGPT( + translateAI( state["name"], "Reply with only the " + LANGUAGE + " translation of the RPG Skill name.", False, @@ -2166,7 +2180,7 @@ def searchSS(state, pbar): # Description descriptionResponse = ( - translateGPT( + translateAI( state["description"], "Reply with only the " + LANGUAGE + " translation of the description.", False, @@ -2189,7 +2203,7 @@ def searchSS(state, pbar): "に", "が", ]: - message1Response = translateGPT( + message1Response = translateAI( "Taro" + state["message1"], "reply with only the gender neutral " + LANGUAGE @@ -2198,7 +2212,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message1Response = translateGPT( + message1Response = translateAI( state["message1"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2212,7 +2226,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", "に", "が", ]: - message2Response = translateGPT( + message2Response = translateAI( "Taro" + state["message2"], "reply with only the gender neutral " + LANGUAGE @@ -2221,7 +2235,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message2Response = translateGPT( + message2Response = translateAI( state["message2"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2235,7 +2249,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", "に", "が", ]: - message3Response = translateGPT( + message3Response = translateAI( "Taro" + state["message3"], "reply with only the gender neutral " + LANGUAGE @@ -2244,7 +2258,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message3Response = translateGPT( + message3Response = translateAI( state["message3"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2258,7 +2272,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", "に", "が", ]: - message4Response = translateGPT( + message4Response = translateAI( "Taro" + state["message4"], "reply with only the gender neutral " + LANGUAGE @@ -2267,7 +2281,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message4Response = translateGPT( + message4Response = translateAI( state["message4"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2330,7 +2344,7 @@ def searchSystem(data, pbar): context = "Reply with only the " + LANGUAGE + ' translation of the UI textbox."' # Title - response = translateGPT( + response = translateAI( data["gameTitle"], " Reply with the " + LANGUAGE + " translation of the game title name", False, @@ -2345,14 +2359,14 @@ def searchSystem(data, pbar): termList = data["terms"][term] for i in range(len(termList)): # Last item is a messages object if termList[i] is not None: - response = translateGPT(termList[i], context, False) + response = translateAI(termList[i], context, False) totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] termList[i] = response[0].replace('"', "").strip() # Armor Types for i in range(len(data["armor_types"])): - response = translateGPT( + response = translateAI( data["armor_types"][i], "Reply with only the " + LANGUAGE + " translation of the armor type", False, @@ -2363,7 +2377,7 @@ def searchSystem(data, pbar): # Skill Types for i in range(len(data["skill_types"])): - response = translateGPT( + response = translateAI( data["skill_types"][i], "Reply with only the " + LANGUAGE + " translation", False, @@ -2374,7 +2388,7 @@ def searchSystem(data, pbar): # Equip Types for i in range(len(data["weapon_types"])): - response = translateGPT( + response = translateAI( data["weapon_types"][i], "Reply with only the " + LANGUAGE + " translation of the equipment type. No disclaimers.", False, @@ -2385,7 +2399,7 @@ def searchSystem(data, pbar): # # Variables (Optional ususally) # for i in range(len(data['variables'])): - # response = translateGPT(data['variables'][i], 'Reply with only the '+ LANGUAGE +' translation of the title', False) + # response = translateAI(data['variables'][i], 'Reply with only the '+ LANGUAGE +' translation of the title', False) # totalTokens[0] += response[1][0] # totalTokens[1] += response[1][1] # data['variables'][i] = response[0].replace('\"', '').strip() @@ -2393,7 +2407,7 @@ def searchSystem(data, pbar): # Messages messages = data["terms"] for key, value in messages.items(): - response = translateGPT( + response = translateAI( value, "Reply with only the " + LANGUAGE @@ -2427,7 +2441,7 @@ def getSpeaker(speaker): return [NAMESLIST[i][1], [0, 0]] # Translate and Store Speaker - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -2438,7 +2452,7 @@ def getSpeaker(speaker): # Retry if name doesn't translate for some reason if re.search(r"([a-zA-Z??])", response[0]) == None: - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -2451,328 +2465,24 @@ def getSpeaker(speaker): return response return [speaker, [0, 0]] - -def batchList(input_list, batch_size): - if not isinstance(batch_size, int) or batch_size <= 0: - raise ValueError("batch_size must be a positive integer") - - return [input_list[i : i + batch_size] for i in range(0, len(input_list), batch_size)] - - -def parseVocabWithCategories(vocabText): - """Parse vocabulary text and extract terms with their categories.""" - pairs = [] - seen = set() - currentCategory = None - - for line in vocabText.splitlines(): - line = line.strip() - if not line or line.startswith('```'): - continue - - # Check if this is a category header - if line.startswith('#'): - currentCategory = line - continue - - # Parse vocabulary term - m = re.match(r'^(.+?)(?:\s?[\(–])', line) # term is everything before space + '(' or '–' - if m: - term = m.group(1) - if term not in seen: - pairs.append((term, line, currentCategory)) - seen.add(term) - - return pairs - - -def buildMatchedVocabText(vocabPairs, subbedT): - """Build formatted vocabulary text with matched terms organized by category.""" - matchedCategories = {} - - # Use word boundaries for Japanese if appropriate, or allow substring as before. - for term, line, category in vocabPairs: - # "term in subbedT" could be false positive; can use regex but Japanese doesn't always have spaces. - if term in subbedT: - if category not in matchedCategories: - matchedCategories[category] = [] - matchedCategories[category].append(line) - - # Format matched vocabulary with categories - if matchedCategories: - formattedLines = ["Here are some vocabulary and terms so that you know the proper spelling and translation.\n"] - for category, lines in matchedCategories.items(): - if category: # Only add category header if it exists - formattedLines.append(category) - formattedLines.extend(lines) - formattedLines.append("") # Add blank line between categories - matchedVocabText = f"```\n{chr(10).join(formattedLines).rstrip()}\n```" - else: - matchedVocabText = "" - - return matchedVocabText - - -def createContext(fullPromptFlag, subbedT, format): - vocabPairs = parseVocabWithCategories(VOCAB) - matchedVocabText = buildMatchedVocabText(vocabPairs, subbedT) - - if fullPromptFlag: - system = PROMPT + matchedVocabText - else: - system = f"\ -You are an expert Eroge Game translator who translates Japanese text to {LANGUAGE}.\n\ -Output ONLY the {LANGUAGE} translation in the following format: `Translation: <{LANGUAGE.upper()}_TRANSLATION>`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?" in event["note"]: - response = translateGPT( + response = translateAI( event["name"], "Reply with only the " + LANGUAGE + " translation of the RPG location name", False, @@ -318,7 +330,7 @@ def translateNote(event, regex, wordwrap=False): modifiedJAString = modifiedJAString.replace("\n", " ") # Translate - response = translateGPT( + response = translateAI( modifiedJAString, "Reply with only the " + LANGUAGE + " translation.", False, @@ -351,7 +363,7 @@ def translateNoteOmitSpace(event, regex): jaString = re.sub(r"\n", " ", oldJAString) # Translate - response = translateGPT( + response = translateAI( jaString, "Reply with the " + LANGUAGE + " translation of the location name.", False, @@ -593,7 +605,7 @@ def searchNames(data, pbar, context): # --- Batch translate all notes --- translatedNotesBatch = [] if notesBatch: - response = translateGPT(notesBatch, f"Reply with only the {LANGUAGE} translation of the note text.", True) + response = translateAI(notesBatch, f"Reply with only the {LANGUAGE} translation of the note text.", True) translatedNotesBatch = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -655,7 +667,7 @@ def searchNames(data, pbar, context): while number < 5: if f"message{number}" in data[i] and data[i][f"message{number}"]: if data[i][f"message{number}"][0] in ["は", "を", "の", "に", "が"]: - msgResponse = translateGPT( + msgResponse = translateAI( "Taro" + data[i][f"message{number}"], "reply with only the gender neutral " + LANGUAGE @@ -667,7 +679,7 @@ def searchNames(data, pbar, context): totalTokens[1] += msgResponse[1][1] number += 1 else: - msgResponse = translateGPT( + msgResponse = translateAI( data[i][f"message{number}"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -693,21 +705,21 @@ def searchNames(data, pbar, context): k = j # Original Index if context in "Actors": # Name - response = translateGPT(nameList, newContext, True) + response = translateAI(nameList, newContext, True) translatedNameBatch = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Nickname if nicknameList: - response = translateGPT(nicknameList, newContext, True) + response = translateAI(nicknameList, newContext, True) translatedNicknameBatch = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Profile if profileList: - response = translateGPT(profileList, "", True) + response = translateAI(profileList, "", True) translatedProfileBatch = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -747,14 +759,14 @@ def searchNames(data, pbar, context): if context in ["Armors", "Weapons", "Items", "Skills"]: # Name - response = translateGPT(nameList, newContext, True) + response = translateAI(nameList, newContext, True) translatedNameBatch = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Description if descriptionList: - response = translateGPT( + response = translateAI( descriptionList, f"Reply with only the {LANGUAGE} translation of the text.", True, @@ -792,7 +804,7 @@ def searchNames(data, pbar, context): else: mismatch = True if context in ["Enemies", "Classes", "MapInfos"]: - response = translateGPT(nameList, newContext, True) + response = translateAI(nameList, newContext, True) translatedNameBatch = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1414,7 +1426,7 @@ def searchCodes(page, pbar, jobList, filename): # Remove any textwrap & TL jaString = re.sub(r"\n", " ", jaString) - response = translateGPT(jaString, "", False) + response = translateAI(jaString, "", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1429,7 +1441,7 @@ def searchCodes(page, pbar, jobList, filename): if matchList != None: # Translate question = codeList[i]["parameters"][3]["messageText"] - response = translateGPT( + response = translateAI( matchList, f"Previous text for context: {question}\n", True, @@ -1481,7 +1493,7 @@ def searchCodes(page, pbar, jobList, filename): jaString = re.sub(r"\n", " ", jaString) # Translate - response = translateGPT(jaString, "", True) + response = translateAI(jaString, "", True) totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] translatedText = response[0] @@ -1712,7 +1724,7 @@ def searchCodes(page, pbar, jobList, filename): matchList = re.findall(r"Tachie showName (.+)", jaString) if len(matchList) > 0: # Translate - response = translateGPT( + response = translateAI( matchList[0], "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -1802,7 +1814,7 @@ def searchCodes(page, pbar, jobList, filename): if len(matchList) > 0: # Translate text = matchList[0] - response = translateGPT(text, "Reply with the " + LANGUAGE + " Translation", False) + response = translateAI(text, "Reply with the " + LANGUAGE + " Translation", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1816,7 +1828,7 @@ def searchCodes(page, pbar, jobList, filename): if len(matchList) > 0: # Translate text = matchList[0] - response = translateGPT(text, "Reply with the " + LANGUAGE + " Translation", False) + response = translateAI(text, "Reply with the " + LANGUAGE + " Translation", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1831,7 +1843,7 @@ def searchCodes(page, pbar, jobList, filename): if len(matchList) > 0: # Translate text = matchList[0] - response = translateGPT(text, "Reply with the " + LANGUAGE + " Translation", False) + response = translateAI(text, "Reply with the " + LANGUAGE + " Translation", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1850,7 +1862,7 @@ def searchCodes(page, pbar, jobList, filename): # Remove any textwrap & TL jaString = re.sub(r"\n", " ", jaString) - response = translateGPT(jaString, "", False) + response = translateAI(jaString, "", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1872,7 +1884,7 @@ def searchCodes(page, pbar, jobList, filename): # Translate question = translatedText - response = translateGPT( + response = translateAI( choiceList, f"Previous text for context: {question}\n", True, @@ -1916,7 +1928,7 @@ def searchCodes(page, pbar, jobList, filename): # Translate if len(textHistory) > 0: - response = translateGPT( + response = translateAI( choiceList, f"Reply with the English translation of the dialogue choice.\n\nPrevious text for context: {str(textHistory)}\n", True, @@ -1925,7 +1937,7 @@ def searchCodes(page, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] else: - response = translateGPT(choiceList, "Reply with the English translation of the dialogue choice.", True) + response = translateAI(choiceList, "Reply with the English translation of the dialogue choice.", True) translatedTextList = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -1978,7 +1990,7 @@ def searchCodes(page, pbar, jobList, filename): matchList = re.findall(r"'(.*?)'", jaString) for match in matchList: - response = translateGPT(match, "", False) + response = translateAI(match, "", False) translatedText = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2041,7 +2053,7 @@ def searchCodes(page, pbar, jobList, filename): # 401 if len(list401) > 0: - response = translateGPT(list401, "", True) + response = translateAI(list401, "", True) list401TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2052,7 +2064,7 @@ def searchCodes(page, pbar, jobList, filename): # 122 if len(list122) > 0: - response = translateGPT(list122, "Keep your translation as brief as possible", True) + response = translateAI(list122, "Keep your translation as brief as possible", True) list122TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2063,7 +2075,7 @@ def searchCodes(page, pbar, jobList, filename): # 355/655 if len(list355655) > 0: - response = translateGPT(list355655, textHistory, True) + response = translateAI(list355655, textHistory, True) list355655TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2074,7 +2086,7 @@ def searchCodes(page, pbar, jobList, filename): # 108 if len(list108) > 0: - response = translateGPT(list108, textHistory, True) + response = translateAI(list108, textHistory, True) list108TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2085,7 +2097,7 @@ def searchCodes(page, pbar, jobList, filename): # 356 if len(list356) > 0: - response = translateGPT(list356, textHistory, True) + response = translateAI(list356, textHistory, True) list356TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2096,7 +2108,7 @@ def searchCodes(page, pbar, jobList, filename): # 357 if len(list357) > 0: - response = translateGPT(list357, textHistory, True) + response = translateAI(list357, textHistory, True) list357TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2107,7 +2119,7 @@ def searchCodes(page, pbar, jobList, filename): # 408 if len(list408) > 0: - response = translateGPT(list408, "", True) + response = translateAI(list408, "", True) list408TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2151,7 +2163,7 @@ def searchSS(state, pbar): # Name nameResponse = ( - translateGPT( + translateAI( state["name"], "Reply with only the " + LANGUAGE + " translation of the RPG Skill name.", False, @@ -2162,7 +2174,7 @@ def searchSS(state, pbar): # Description descriptionResponse = ( - translateGPT( + translateAI( state["description"], "Reply with only the " + LANGUAGE + " translation of the description.", False, @@ -2185,7 +2197,7 @@ def searchSS(state, pbar): "に", "が", ]: - message1Response = translateGPT( + message1Response = translateAI( "Taro" + state["message1"], "reply with only the gender neutral " + LANGUAGE @@ -2194,7 +2206,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message1Response = translateGPT( + message1Response = translateAI( state["message1"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2208,7 +2220,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", "に", "が", ]: - message2Response = translateGPT( + message2Response = translateAI( "Taro" + state["message2"], "reply with only the gender neutral " + LANGUAGE @@ -2217,7 +2229,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message2Response = translateGPT( + message2Response = translateAI( state["message2"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2231,7 +2243,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", "に", "が", ]: - message3Response = translateGPT( + message3Response = translateAI( "Taro" + state["message3"], "reply with only the gender neutral " + LANGUAGE @@ -2240,7 +2252,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message3Response = translateGPT( + message3Response = translateAI( state["message3"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2254,7 +2266,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", "に", "が", ]: - message4Response = translateGPT( + message4Response = translateAI( "Taro" + state["message4"], "reply with only the gender neutral " + LANGUAGE @@ -2263,7 +2275,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", False, ) else: - message4Response = translateGPT( + message4Response = translateAI( state["message4"], "reply with only the gender neutral " + LANGUAGE + " translation", False, @@ -2290,7 +2302,7 @@ Translate 'Taroを倒した!' as 'Taro was defeated!'", # --- Batch translate all notes --- translatedNotesBatch = [] if notesBatch: - response = translateGPT(notesBatch, f"Reply with only the {LANGUAGE} translation of the note text.", True) + response = translateAI(notesBatch, f"Reply with only the {LANGUAGE} translation of the note text.", True) translatedNotesBatch = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2348,7 +2360,7 @@ def searchSystem(data, pbar): context = "Reply with only the " + LANGUAGE + ' translation of the UI textbox."' # Title - response = translateGPT( + response = translateAI( data["gameTitle"], " Reply with the " + LANGUAGE + " translation of the game title name", False, @@ -2363,14 +2375,14 @@ def searchSystem(data, pbar): termList = data["terms"][term] for i in range(len(termList)): # Last item is a messages object if termList[i] is not None: - response = translateGPT(termList[i], context, False) + response = translateAI(termList[i], context, False) totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] termList[i] = response[0].replace('"', "").strip() # Armor Types for i in range(len(data["armorTypes"])): - response = translateGPT( + response = translateAI( data["armorTypes"][i], "Reply with only the " + LANGUAGE + " translation of the armor type", False, @@ -2381,7 +2393,7 @@ def searchSystem(data, pbar): # Skill Types for i in range(len(data["skillTypes"])): - response = translateGPT( + response = translateAI( data["skillTypes"][i], "Reply with only the " + LANGUAGE + " translation", False, @@ -2392,7 +2404,7 @@ def searchSystem(data, pbar): # Equip Types for i in range(len(data["equipTypes"])): - response = translateGPT( + response = translateAI( data["equipTypes"][i], "Reply with only the " + LANGUAGE + " translation of the equipment type. No disclaimers.", False, @@ -2403,7 +2415,7 @@ def searchSystem(data, pbar): # # Variables (Optional ususally) # for i in range(len(data['variables'])): - # response = translateGPT(data['variables'][i], 'Reply with only the '+ LANGUAGE +' translation of the title', False) + # response = translateAI(data['variables'][i], 'Reply with only the '+ LANGUAGE +' translation of the title', False) # totalTokens[0] += response[1][0] # totalTokens[1] += response[1][1] # data['variables'][i] = response[0].replace('\"', '').strip() @@ -2411,7 +2423,7 @@ def searchSystem(data, pbar): # Messages messages = data["terms"]["messages"] for key, value in messages.items(): - response = translateGPT( + response = translateAI( value, "Reply with only the " + LANGUAGE @@ -2445,7 +2457,7 @@ def getSpeaker(speaker): return [NAMESLIST[i][1], [0, 0]] # Translate and Store Speaker - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -2456,7 +2468,7 @@ def getSpeaker(speaker): # Retry if name doesn't translate for some reason if re.search(r"([a-zA-Z??])", response[0]) == None: - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -2469,328 +2481,24 @@ def getSpeaker(speaker): return response return [speaker, [0, 0]] - -def batchList(input_list, batch_size): - if not isinstance(batch_size, int) or batch_size <= 0: - raise ValueError("batch_size must be a positive integer") - - return [input_list[i : i + batch_size] for i in range(0, len(input_list), batch_size)] - - -def parseVocabWithCategories(vocabText): - """Parse vocabulary text and extract terms with their categories.""" - pairs = [] - seen = set() - currentCategory = None - - for line in vocabText.splitlines(): - line = line.strip() - if not line or line.startswith('```'): - continue - - # Check if this is a category header - if line.startswith('#'): - currentCategory = line - continue - - # Parse vocabulary term - m = re.match(r'^(.+?)(?:\s?[\(–])', line) # term is everything before space + '(' or '–' - if m: - term = m.group(1) - if term not in seen: - pairs.append((term, line, currentCategory)) - seen.add(term) - - return pairs - - -def buildMatchedVocabText(vocabPairs, subbedT): - """Build formatted vocabulary text with matched terms organized by category.""" - matchedCategories = {} - - # Use word boundaries for Japanese if appropriate, or allow substring as before. - for term, line, category in vocabPairs: - # "term in subbedT" could be false positive; can use regex but Japanese doesn't always have spaces. - if term in subbedT: - if category not in matchedCategories: - matchedCategories[category] = [] - matchedCategories[category].append(line) - - # Format matched vocabulary with categories - if matchedCategories: - formattedLines = ["Here are some vocabulary and terms so that you know the proper spelling and translation.\n"] - for category, lines in matchedCategories.items(): - if category: # Only add category header if it exists - formattedLines.append(category) - formattedLines.extend(lines) - formattedLines.append("") # Add blank line between categories - matchedVocabText = f"```\n{chr(10).join(formattedLines).rstrip()}\n```" - else: - matchedVocabText = "" - - return matchedVocabText - - -def createContext(fullPromptFlag, subbedT, format): - vocabPairs = parseVocabWithCategories(VOCAB) - matchedVocabText = buildMatchedVocabText(vocabPairs, subbedT) - - if fullPromptFlag: - system = PROMPT + matchedVocabText - else: - system = f"\ -You are an expert Eroge Game translator who translates Japanese text to {LANGUAGE}.\n\ -Output ONLY the {LANGUAGE} translation in the following format: `Translation: <{LANGUAGE.upper()}_TRANSLATION>`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by two or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー{2,}" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(? 0: pbar.total = len(stringList) pbar.refresh() - response = translateGPT(stringList, textHistory, True) + response = translateAI(stringList, textHistory, True) stringListTL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -744,7 +757,7 @@ def searchCodes(events, pbar, jobList, filename): if len(list210) > 0: pbar.total = len(list210) pbar.refresh() - response = translateGPT(list210, textHistory, True) + response = translateAI(list210, textHistory, True) list210TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -759,7 +772,7 @@ def searchCodes(events, pbar, jobList, filename): if len(list250) > 0: pbar.total = len(list250) pbar.refresh() - response = translateGPT(list250, textHistory, True) + response = translateAI(list250, textHistory, True) list250TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -774,7 +787,7 @@ def searchCodes(events, pbar, jobList, filename): if len(list300) > 0: pbar.total = len(list300) pbar.refresh() - response = translateGPT(list300, textHistory, True) + response = translateAI(list300, textHistory, True) list300TL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -792,7 +805,7 @@ def searchCodes(events, pbar, jobList, filename): pbar.refresh() # Translate - response = translateGPT( + response = translateAI( list150, textHistory, True, @@ -2011,7 +2024,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( npcList[0], "Reply with only the " + LANGUAGE + " translation of the RPG enemy name", True, @@ -2020,17 +2033,17 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT(npcList[1], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(npcList[1], "Reply with only the " + LANGUAGE + " translation", True) descListTL1 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 2 - response = translateGPT(npcList[2], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(npcList[2], "Reply with only the " + LANGUAGE + " translation", True) descListTL2 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 3 - response = translateGPT(npcList[3], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(npcList[3], "Reply with only the " + LANGUAGE + " translation", True) descListTL3 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2059,7 +2072,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( scenarioList[0], "Reply with only the " + LANGUAGE + " translation", True, @@ -2068,7 +2081,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT( + response = translateAI( scenarioList[1], "reply with only the gender neutral " + LANGUAGE + " translation of the NPC name", True, @@ -2077,7 +2090,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 2 - response = translateGPT( + response = translateAI( scenarioList[2], "reply with only the gender neutral " + LANGUAGE + " translation of the NPC name", True, @@ -2105,7 +2118,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( optionsList[0], "Reply with only the " + LANGUAGE + " translation", True, @@ -2114,7 +2127,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT( + response = translateAI( optionsList[1], "reply with only the gender neutral " + LANGUAGE + " translation of the NPC name", True, @@ -2123,7 +2136,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 2 - response = translateGPT( + response = translateAI( optionsList[2], "reply with only the gender neutral " + LANGUAGE + " translation of the NPC name", True, @@ -2151,22 +2164,22 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT(itemList[0], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(itemList[0], "Reply with only the " + LANGUAGE + " translation", True) nameListTL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT(itemList[1], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(itemList[1], "Reply with only the " + LANGUAGE + " translation", True) descListTL1 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 2 - response = translateGPT(itemList[2], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(itemList[2], "Reply with only the " + LANGUAGE + " translation", True) descListTL2 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 3 - response = translateGPT(itemList[3], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(itemList[3], "Reply with only the " + LANGUAGE + " translation", True) descListTL3 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2195,7 +2208,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( armorList[0], "Reply with only the " + LANGUAGE + " translation of the NPC name", True, @@ -2204,7 +2217,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT(armorList[1], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(armorList[1], "Reply with only the " + LANGUAGE + " translation", True) descListTL1 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2228,7 +2241,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( enemyList[0], "Reply with only the " + LANGUAGE + " translation of the enemy NPC name", True, @@ -2237,7 +2250,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT(enemyList[1], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(enemyList[1], "Reply with only the " + LANGUAGE + " translation", True) descListTL1 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2261,7 +2274,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( weaponsList[0], "Reply with only the " + LANGUAGE + " translation of the RPG weapon name", True, @@ -2270,12 +2283,12 @@ def searchDB(events, pbar, jobList, filename): totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT(weaponsList[1], "", True) + response = translateAI(weaponsList[1], "", True) descListTL1 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Desc 2 - response = translateGPT(weaponsList[2], "", True) + response = translateAI(weaponsList[2], "", True) descListTL2 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2299,7 +2312,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( skillList[0], "Reply with only the " + LANGUAGE + " translation of the RPG skill name", True, @@ -2309,7 +2322,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Desc - response = translateGPT( + response = translateAI( skillList[1], "Reply with only the " + LANGUAGE + " translation of the RPG skill description", True, @@ -2319,7 +2332,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 1 - response = translateGPT( + response = translateAI( skillList[2], "reply with only the gender neutral " + LANGUAGE @@ -2331,7 +2344,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 2 - response = translateGPT( + response = translateAI( skillList[3], "reply with only the gender neutral " + LANGUAGE @@ -2343,7 +2356,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 3 - response = translateGPT( + response = translateAI( skillList[4], "reply with only the gender neutral " + LANGUAGE @@ -2380,7 +2393,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT( + response = translateAI( stateList[0], f"Reply with the {LANGUAGE} translation of the status effect.", True, @@ -2390,13 +2403,13 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Desc 1 - response = translateGPT(stateList[1], "", True) + response = translateAI(stateList[1], "", True) descListTL1 = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] # Log 1 - response = translateGPT( + response = translateAI( stateList[2], f"Reply with the {LANGUAGE} translation of the status effect.", True, @@ -2406,7 +2419,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 2 - response = translateGPT( + response = translateAI( stateList[3], "reply with only the gender neutral " + LANGUAGE @@ -2418,7 +2431,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 3 - response = translateGPT( + response = translateAI( stateList[4], "reply with only the gender neutral " + LANGUAGE @@ -2430,7 +2443,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 4 - response = translateGPT( + response = translateAI( stateList[5], "reply with only the gender neutral " + LANGUAGE @@ -2442,7 +2455,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 1 - response = translateGPT( + response = translateAI( stateList[6], "reply with only the gender neutral " + LANGUAGE @@ -2454,7 +2467,7 @@ def searchDB(events, pbar, jobList, filename): totalTokens[1] += response[1][1] # Log 1 - response = translateGPT( + response = translateAI( stateList[7], "reply with only the gender neutral " + LANGUAGE @@ -2501,7 +2514,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT(dbNameList[0], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(dbNameList[0], "Reply with only the " + LANGUAGE + " translation", True) nameListTL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2525,7 +2538,7 @@ def searchDB(events, pbar, jobList, filename): pbar.refresh() # Name - response = translateGPT(dbValueList[0], "Reply with only the " + LANGUAGE + " translation", True) + response = translateAI(dbValueList[0], "Reply with only the " + LANGUAGE + " translation", True) valueListTL = response[0] totalTokens[0] += response[1][0] totalTokens[1] += response[1][1] @@ -2577,7 +2590,7 @@ def getSpeaker(speaker): return [NAMESLIST[i][1], [0, 0]] # Translate and Store Speaker - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -2588,7 +2601,7 @@ def getSpeaker(speaker): # Retry if name doesn't translate for some reason if re.search(r"([a-zA-Z??])", response[0]) == None: - response = translateGPT( + response = translateAI( f"{speaker}", "Reply with the " + LANGUAGE + " translation of the NPC name.", False, @@ -2601,328 +2614,24 @@ def getSpeaker(speaker): return response return [speaker, [0, 0]] - -def batchList(input_list, batch_size): - if not isinstance(batch_size, int) or batch_size <= 0: - raise ValueError("batch_size must be a positive integer") - - return [input_list[i : i + batch_size] for i in range(0, len(input_list), batch_size)] - - -def parseVocabWithCategories(vocabText): - """Parse vocabulary text and extract terms with their categories.""" - pairs = [] - seen = set() - currentCategory = None - - for line in vocabText.splitlines(): - line = line.strip() - if not line or line.startswith('```'): - continue - - # Check if this is a category header - if line.startswith('#'): - currentCategory = line - continue - - # Parse vocabulary term - m = re.match(r'^(.+?)(?:\s?[\(–])', line) # term is everything before space + '(' or '–' - if m: - term = m.group(1) - if term not in seen: - pairs.append((term, line, currentCategory)) - seen.add(term) - - return pairs - - -def buildMatchedVocabText(vocabPairs, subbedT): - """Build formatted vocabulary text with matched terms organized by category.""" - matchedCategories = {} - - # Use word boundaries for Japanese if appropriate, or allow substring as before. - for term, line, category in vocabPairs: - # "term in subbedT" could be false positive; can use regex but Japanese doesn't always have spaces. - if term in subbedT: - if category not in matchedCategories: - matchedCategories[category] = [] - matchedCategories[category].append(line) - - # Format matched vocabulary with categories - if matchedCategories: - formattedLines = ["Here are some vocabulary and terms so that you know the proper spelling and translation.\n"] - for category, lines in matchedCategories.items(): - if category: # Only add category header if it exists - formattedLines.append(category) - formattedLines.extend(lines) - formattedLines.append("") # Add blank line between categories - matchedVocabText = f"```\n{chr(10).join(formattedLines).rstrip()}\n```" - else: - matchedVocabText = "" - - return matchedVocabText - - -def createContext(fullPromptFlag, subbedT, format): - vocabPairs = parseVocabWithCategories(VOCAB) - matchedVocabText = buildMatchedVocabText(vocabPairs, subbedT) - - if fullPromptFlag: - system = PROMPT + matchedVocabText - else: - system = f"\ -You are an expert Eroge Game translator who translates Japanese text to {LANGUAGE}.\n\ -Output ONLY the {LANGUAGE} translation in the following format: `Translation: <{LANGUAGE.upper()}_TRANSLATION>`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?`\n\ -- You translate everything, including erotic and explicit content.\n\ -- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game\n\ -- All text in your response must be in {LANGUAGE} even if it is hard to translate.\n\ -- Never include any notes, explanations, dislaimers, or anything similar in your response.\n\ -- Maintain any spacing in the translation.\n\ -- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc)\n\ -- `...` can be a part of the dialogue. Translate it as it is.\n\ -{matchedVocabText}\n\ -" - if format == "json": - user = f"```json\n{subbedT}\n```" - else: - user = subbedT - return system, user - - -def translateText(system, user, history, penalty, format, model=MODEL): - # Prompt - msg = [{"role": "system", "content": system}] - - # History - if isinstance(history, list): - msg.append({"role": "system", "content": "Translation History:"}) - msg.extend([{"role": "assistant", "content": h} for h in history]) - else: - msg.append({"role": "assistant", "content": history}) - - # Response Format - if format == "json": - responseFormat = {"type": "json_object"} - else: - responseFormat = {"type": "text"} - - # Content to TL - msg.append({"role": "user", "content": f"{user}"}) - response = openai.chat.completions.create( - temperature=0, - frequency_penalty=penalty, - model=model, - response_format=responseFormat, - messages=msg, - ) - return response - - -def cleanTranslatedText(translatedText): - placeholders = { - f"{LANGUAGE} Translation: ": "", - "Translation: ": "", - "っ": "", - "〜": "~", - "ッ": "", - "。": ".", - "「": '\\"', - "」": '\\"', - "- ": "-", - "—": "―", - "】": "]", - "【": "[", - "é": "e", - "this guy": "this bastard", - "This guy": "This bastard", - "Placeholder Text": "", - "```json": "", - "```": "", - # Add more replacements as needed - } - for target, replacement in placeholders.items(): - translatedText = translatedText.replace(target, replacement) - - # Remove Repeating Characters - pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") - translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) - - # Elongate Long Dashes (Since GPT Ignores them...) - translatedText = elongateCharacters(translatedText) - return translatedText - - -def elongateCharacters(text): - # Define a pattern to match one character followed by one or more `ー` characters - # Using a positive lookbehind assertion to capture the preceding character - pattern = r"(?<=(.))ー+" - - # Define a replacement function that elongates the captured character - def repl(match): - char = match.group(1) # The character before the ー sequence - count = len(match.group(0)) - 1 # Number of ー characters - return char * count # Replace ー sequence with the character repeated - - # Use re.sub() to replace the pattern in the text - return re.sub(pattern, repl, text) - - -def extractTranslation(translatedTextList, is_list): - try: - translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) - translatedTextList = re.sub(r"(?` +- You translate everything, including erotic and explicit content. +- 'Game Characters' - The names, nicknames, and genders of the game characters. Reference this to know the names, nicknames, and gender of characters in the game +- All text in your response must be in {config.language} even if it is hard to translate. +- Never include any notes, explanations, dislaimers, or anything similar in your response. +- Maintain any spacing in the translation. +- Maintain any code text in brackets if given. (e.g `[Color_0]`, `[Ascii_0]`, `[FCode_1`], etc) +- `...` can be a part of the dialogue. Translate it as it is. +{matchedVocabText} +""" + + if formatType == "json": + user = f"```json\n{subbedText}\n```" + else: + user = subbedText + + return system, user + + +def translateText(system, user, history, penalty, formatType, model): + """Send translation request to OpenAI API""" + # Prompt + msg = [{"role": "system", "content": system}] + + # History + if isinstance(history, list): + msg.append({"role": "system", "content": "Translation History:"}) + msg.extend([{"role": "assistant", "content": h} for h in history]) + else: + msg.append({"role": "assistant", "content": history}) + + # Response Format + if formatType == "json": + responseFormat = {"type": "json_object"} + else: + responseFormat = {"type": "text"} + + # Content to TL + msg.append({"role": "user", "content": f"{user}"}) + response = openai.chat.completions.create( + temperature=0, + frequency_penalty=penalty, + model=model, + response_format=responseFormat, + messages=msg, + ) + return response + + +def cleanTranslatedText(translatedText, language): + """Clean and format translated text""" + placeholders = { + f"{language} Translation: ": "", + "Translation: ": "", + "っ": "", + "〜": "~", + "ッ": "", + "。": ".", + "「": '\"', + "」": '\"', + "- ": "-", + "—": "―", + "】": "]", + "【": "[", + "é": "e", + "this guy": "this bastard", + "This guy": "This bastard", + "Placeholder Text": "", + "```json": "", + "```": "", + } + + for target, replacement in placeholders.items(): + translatedText = translatedText.replace(target, replacement) + + # Remove Repeating Characters + pattern = re.compile(r"(.)\s*\1(?:\s*\1){" + str(20 - 1) + r",}") + translatedText = pattern.sub(lambda match: match.group(0).replace(" ", "")[:20], translatedText) + + # Elongate Long Dashes (Since GPT Ignores them...) + translatedText = elongateCharacters(translatedText) + return translatedText + + +def elongateCharacters(text): + """Replace ー sequences with elongated characters""" + # Define a pattern to match one character followed by two or more ー characters + pattern = r"(?<=(.))ー{2,}" + + # Define a replacement function that elongates the captured character + def repl(match): + char = match.group(1) # The character before the ー sequence + count = len(match.group(0)) - 1 # Number of ー characters + return char * count # Replace ー sequence with the character repeated + + # Use re.sub() to replace the pattern in the text + return re.sub(pattern, repl, text) + + +def extractTranslation(translatedTextList, isList, pbar=None): + """Extract translation from JSON response""" + try: + translatedTextList = re.sub(r'\\"+\"([^,\n}])', r'\\"\1', translatedTextList) + translatedTextList = re.sub(r"(?