Spaces:
Running
Running
wony617
Claude
commited on
Commit
ยท
d229b84
1
Parent(s):
1b1c0d8
refactor: fix multi-project GitHub PR targeting and improve error messages
Browse files- Refactor GitHubPRAgent to accept repository parameters in constructor
- Fix PR creation to target correct repository based on selected project
- Update TocTreeHandler to support project-specific toctree files
- Improve error messages with specific project mismatch detection
- Pass project parameter from handler to ensure proper repository targeting
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- agent/handler.py +118 -30
- agent/toctree_handler.py +13 -4
- agent/workflow.py +59 -23
- app.py +53 -9
- pr_generator/agent.py +17 -12
- translator/content.py +8 -5
agent/handler.py
CHANGED
|
@@ -108,7 +108,7 @@ def process_file_search_handler(project: str, lang: str, k: int, history: list)
|
|
| 108 |
2. Click "๐พ Save Configuration"
|
| 109 |
3. Try "Find Files" again"""
|
| 110 |
history.append(["File search request", response])
|
| 111 |
-
return history, "", update_status(), gr.Tabs(selected=0), gr.update(choices=[])
|
| 112 |
else:
|
| 113 |
raise # Re-raise non-rate-limit errors
|
| 114 |
state.files_to_translate = (
|
|
@@ -141,14 +141,13 @@ def process_file_search_handler(project: str, lang: str, k: int, history: list)
|
|
| 141 |
# Add to history
|
| 142 |
history.append(["Please find files that need translation", response])
|
| 143 |
cleared_input = ""
|
| 144 |
-
selected_tab = 1 if state.files_to_translate else 0
|
| 145 |
|
| 146 |
# ๋๋กญ๋ค์ด choices๋ก ์ธ ํ์ผ ๋ฆฌ์คํธ ๋ฐํ ์ถ๊ฐ
|
| 147 |
return (
|
| 148 |
history,
|
| 149 |
cleared_input,
|
| 150 |
update_status(),
|
| 151 |
-
gr.Tabs(
|
| 152 |
update_dropdown_choices(state.files_to_translate),
|
| 153 |
)
|
| 154 |
|
|
@@ -157,7 +156,30 @@ def update_dropdown_choices(file_list):
|
|
| 157 |
return gr.update(choices=file_list, value=None)
|
| 158 |
|
| 159 |
|
| 160 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
"""Start the translation process for the first file"""
|
| 162 |
if not state.files_to_translate:
|
| 163 |
return "โ No files available for translation.", ""
|
|
@@ -166,8 +188,8 @@ def start_translation_process():
|
|
| 166 |
|
| 167 |
# Call translation function (simplified for demo)
|
| 168 |
try:
|
| 169 |
-
translated = translate_docs_interactive(
|
| 170 |
-
state.target_language, [[current_file]], state.additional_instruction
|
| 171 |
)
|
| 172 |
|
| 173 |
state.current_file_content = {"translated": translated}
|
|
@@ -184,13 +206,17 @@ def start_translation_process():
|
|
| 184 |
print("Compeleted translation:\n")
|
| 185 |
print(translated)
|
| 186 |
print("----------------------------")
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
""
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
return response, translated
|
| 195 |
|
| 196 |
|
|
@@ -228,7 +254,12 @@ Currently available actions with quick controls:
|
|
| 228 |
else:
|
| 229 |
return """I understand you want to work on translations!
|
| 230 |
|
| 231 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
"""
|
| 233 |
|
| 234 |
|
|
@@ -325,7 +356,25 @@ def sync_language_displays(lang):
|
|
| 325 |
return lang
|
| 326 |
|
| 327 |
|
| 328 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 329 |
"""Update persistent configuration settings."""
|
| 330 |
global state
|
| 331 |
|
|
@@ -353,7 +402,15 @@ def update_persistent_config(anthropic_key, github_token, github_owner, github_r
|
|
| 353 |
"reference_pr_url": reference_pr_url or "",
|
| 354 |
})
|
| 355 |
|
| 356 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 357 |
|
| 358 |
|
| 359 |
def update_github_config(token, owner, repo, reference_pr_url):
|
|
@@ -374,7 +431,7 @@ def update_prompt_preview(language, file_path, additional_instruction):
|
|
| 374 |
translation_lang = language
|
| 375 |
|
| 376 |
# Get sample content (first 500 characters)
|
| 377 |
-
content = get_content(file_path)
|
| 378 |
to_translate = preprocess_content(content)
|
| 379 |
|
| 380 |
# Truncate for preview
|
|
@@ -385,7 +442,10 @@ def update_prompt_preview(language, file_path, additional_instruction):
|
|
| 385 |
|
| 386 |
return prompt
|
| 387 |
except Exception as e:
|
| 388 |
-
|
|
|
|
|
|
|
|
|
|
| 389 |
|
| 390 |
|
| 391 |
def send_message(message, history):
|
|
@@ -394,21 +454,39 @@ def send_message(message, history):
|
|
| 394 |
|
| 395 |
|
| 396 |
# Button handlers with tab switching
|
| 397 |
-
def start_translate_handler(history, file_to_translate, additional_instruction=""):
|
| 398 |
# Use persistent anthropic key
|
| 399 |
anthropic_key = state.persistent_settings["anthropic_api_key"]
|
| 400 |
if not anthropic_key:
|
| 401 |
response = "โ Please set Anthropic API key in Configuration panel first."
|
| 402 |
history.append(["Translation request", response])
|
| 403 |
-
return history, "", update_status(), gr.Tabs(
|
| 404 |
|
| 405 |
os.environ["ANTHROPIC_API_KEY"] = anthropic_key
|
| 406 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
state.additional_instruction = additional_instruction
|
| 408 |
state.files_to_translate = [file_to_translate]
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
|
| 413 |
|
| 414 |
def approve_handler(history, owner, repo, reference_pr_url):
|
|
@@ -416,15 +494,21 @@ def approve_handler(history, owner, repo, reference_pr_url):
|
|
| 416 |
global state
|
| 417 |
state.step = "create_github_pr"
|
| 418 |
|
| 419 |
-
#
|
| 420 |
github_config = state.persistent_settings["github_config"]
|
|
|
|
|
|
|
| 421 |
if not github_config.get("token"):
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 428 |
history.append(["GitHub PR creation request", response])
|
| 429 |
return history, "", update_status()
|
| 430 |
|
|
@@ -435,6 +519,9 @@ def approve_handler(history, owner, repo, reference_pr_url):
|
|
| 435 |
# Use persistent settings
|
| 436 |
github_config = state.persistent_settings["github_config"]
|
| 437 |
|
|
|
|
|
|
|
|
|
|
| 438 |
# If reference PR is not provided, use the agent to find one
|
| 439 |
if not github_config.get("reference_pr_url"):
|
| 440 |
response = "๐ค **Reference PR URL not found. The agent will now search for a suitable one...**"
|
|
@@ -490,6 +577,7 @@ def approve_handler(history, owner, repo, reference_pr_url):
|
|
| 490 |
translated_content=translated_content,
|
| 491 |
github_config=state.github_config,
|
| 492 |
en_title=file_name,
|
|
|
|
| 493 |
)
|
| 494 |
response += f"\n{pr_response}"
|
| 495 |
else:
|
|
|
|
| 108 |
2. Click "๐พ Save Configuration"
|
| 109 |
3. Try "Find Files" again"""
|
| 110 |
history.append(["File search request", response])
|
| 111 |
+
return history, "", update_status(), gr.Tabs(selected=0), gr.update(choices=[]), gr.update(visible=False)
|
| 112 |
else:
|
| 113 |
raise # Re-raise non-rate-limit errors
|
| 114 |
state.files_to_translate = (
|
|
|
|
| 141 |
# Add to history
|
| 142 |
history.append(["Please find files that need translation", response])
|
| 143 |
cleared_input = ""
|
|
|
|
| 144 |
|
| 145 |
# ๋๋กญ๋ค์ด choices๋ก ์ธ ํ์ผ ๋ฆฌ์คํธ ๋ฐํ ์ถ๊ฐ
|
| 146 |
return (
|
| 147 |
history,
|
| 148 |
cleared_input,
|
| 149 |
update_status(),
|
| 150 |
+
gr.Tabs(), # Don't change tab
|
| 151 |
update_dropdown_choices(state.files_to_translate),
|
| 152 |
)
|
| 153 |
|
|
|
|
| 156 |
return gr.update(choices=file_list, value=None)
|
| 157 |
|
| 158 |
|
| 159 |
+
def confirm_and_go_translate_handler(history):
|
| 160 |
+
"""Confirm selection and go to translate tab"""
|
| 161 |
+
global state
|
| 162 |
+
|
| 163 |
+
response = f"โ
**Selection confirmed!**\n\n๐ฏ **Project:** {state.selected_project}\n๐ **Language:** {state.target_language}\n\n**โก๏ธ Go to Tab 2 to start translation.**"
|
| 164 |
+
history.append(["Confirm selection", response])
|
| 165 |
+
return history, "", update_status(), gr.Tabs(selected=1)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def confirm_translation_and_go_upload_handler(history):
|
| 169 |
+
"""Confirm translation and go to upload PR tab"""
|
| 170 |
+
global state
|
| 171 |
+
|
| 172 |
+
if not state.current_file_content.get("translated"):
|
| 173 |
+
response = "โ No translation available. Please complete translation first."
|
| 174 |
+
history.append(["Upload PR request", response])
|
| 175 |
+
return history, "", update_status(), gr.Tabs()
|
| 176 |
+
|
| 177 |
+
response = f"โ
**Translation confirmed!**\n\n๐ **File:** `{state.files_to_translate[0] if state.files_to_translate else 'Unknown'}`\n\n**โก๏ธ Go to Tab 3 to upload PR.**"
|
| 178 |
+
history.append(["Upload PR request", response])
|
| 179 |
+
return history, "", update_status(), gr.Tabs(selected=2)
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
def start_translation_process(force_retranslate=False):
|
| 183 |
"""Start the translation process for the first file"""
|
| 184 |
if not state.files_to_translate:
|
| 185 |
return "โ No files available for translation.", ""
|
|
|
|
| 188 |
|
| 189 |
# Call translation function (simplified for demo)
|
| 190 |
try:
|
| 191 |
+
status, translated = translate_docs_interactive(
|
| 192 |
+
state.target_language, [[current_file]], state.additional_instruction, state.selected_project, force_retranslate
|
| 193 |
)
|
| 194 |
|
| 195 |
state.current_file_content = {"translated": translated}
|
|
|
|
| 206 |
print("Compeleted translation:\n")
|
| 207 |
print(translated)
|
| 208 |
print("----------------------------")
|
| 209 |
+
|
| 210 |
+
# Different response format for existing vs new translation
|
| 211 |
+
if isinstance(status, str) and "Existing translation loaded" in status:
|
| 212 |
+
response = f"{status}\n**๐ Original Content Link:** {original_file_link}\n\n**๐ Translated Content:**"
|
| 213 |
+
else:
|
| 214 |
+
response = (
|
| 215 |
+
f"""๐ Translation for: `{current_file}`\n"""
|
| 216 |
+
f"**๐ Original Content Link:** {original_file_link}\n\n"
|
| 217 |
+
f"{status}\n\n"
|
| 218 |
+
"**๐ Translated Content:**"
|
| 219 |
+
)
|
| 220 |
return response, translated
|
| 221 |
|
| 222 |
|
|
|
|
| 254 |
else:
|
| 255 |
return """I understand you want to work on translations!
|
| 256 |
|
| 257 |
+
**Two ways to get started:**
|
| 258 |
+
|
| 259 |
+
1. **๐ Find Files first** - Use Tab 1 to discover files that need translation
|
| 260 |
+
2. **๐ Direct Translation** - Go to Tab 2 and enter a file path directly (e.g., `docs/source/en/model_doc/bert.md`)
|
| 261 |
+
|
| 262 |
+
Make sure to configure your API keys in the Configuration panel above.
|
| 263 |
"""
|
| 264 |
|
| 265 |
|
|
|
|
| 356 |
return lang
|
| 357 |
|
| 358 |
|
| 359 |
+
def update_project_selection(project, history):
|
| 360 |
+
"""Update state when project is selected"""
|
| 361 |
+
global state
|
| 362 |
+
state.selected_project = project
|
| 363 |
+
response = f"Selection confirmed: ๐ฏ Project โ **{project}**"
|
| 364 |
+
history.append(["Project selection", response])
|
| 365 |
+
return history, "", update_status()
|
| 366 |
+
|
| 367 |
+
|
| 368 |
+
def update_language_selection(lang, history):
|
| 369 |
+
"""Update state when language is selected"""
|
| 370 |
+
global state
|
| 371 |
+
state.target_language = lang
|
| 372 |
+
response = f"Selection confirmed: ๐ Language โ **{lang}**"
|
| 373 |
+
history.append(["Language selection", response])
|
| 374 |
+
return history, "", update_status(), lang
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def update_persistent_config(anthropic_key, github_token, github_owner, github_repo, reference_pr_url, history):
|
| 378 |
"""Update persistent configuration settings."""
|
| 379 |
global state
|
| 380 |
|
|
|
|
| 402 |
"reference_pr_url": reference_pr_url or "",
|
| 403 |
})
|
| 404 |
|
| 405 |
+
# Build response message based on what was configured
|
| 406 |
+
response = "โ
Configuration saved!"
|
| 407 |
+
if github_owner and github_repo:
|
| 408 |
+
response += f" GitHub: {github_owner}/{github_repo}"
|
| 409 |
+
elif anthropic_key:
|
| 410 |
+
response += " Anthropic API key updated."
|
| 411 |
+
|
| 412 |
+
history.append(["Configuration update", response])
|
| 413 |
+
return history, "", update_status()
|
| 414 |
|
| 415 |
|
| 416 |
def update_github_config(token, owner, repo, reference_pr_url):
|
|
|
|
| 431 |
translation_lang = language
|
| 432 |
|
| 433 |
# Get sample content (first 500 characters)
|
| 434 |
+
content = get_content(file_path, state.selected_project)
|
| 435 |
to_translate = preprocess_content(content)
|
| 436 |
|
| 437 |
# Truncate for preview
|
|
|
|
| 442 |
|
| 443 |
return prompt
|
| 444 |
except Exception as e:
|
| 445 |
+
error_str = str(e)
|
| 446 |
+
if "Failed to retrieve content from the URL" in error_str:
|
| 447 |
+
return f"โ **File not found:** `{file_path}`\n\n๐ก **Please check:**\n1. Is this file in the **{state.selected_project}** project?\n2. Use \"๐ Find Files to Translate\" to see available files\n3. Verify the file path is correct"
|
| 448 |
+
return f"Error generating prompt preview: {error_str}"
|
| 449 |
|
| 450 |
|
| 451 |
def send_message(message, history):
|
|
|
|
| 454 |
|
| 455 |
|
| 456 |
# Button handlers with tab switching
|
| 457 |
+
def start_translate_handler(history, file_to_translate, additional_instruction="", force_retranslate=False):
|
| 458 |
# Use persistent anthropic key
|
| 459 |
anthropic_key = state.persistent_settings["anthropic_api_key"]
|
| 460 |
if not anthropic_key:
|
| 461 |
response = "โ Please set Anthropic API key in Configuration panel first."
|
| 462 |
history.append(["Translation request", response])
|
| 463 |
+
return history, "", update_status(), gr.Tabs(), gr.update(), gr.update()
|
| 464 |
|
| 465 |
os.environ["ANTHROPIC_API_KEY"] = anthropic_key
|
| 466 |
|
| 467 |
+
# Check if file path is provided
|
| 468 |
+
if not file_to_translate or not file_to_translate.strip():
|
| 469 |
+
response = "โ Please select a file from the dropdown or enter a file path to translate."
|
| 470 |
+
history.append(["Translation request", response])
|
| 471 |
+
return history, "", update_status(), gr.Tabs(), gr.update(), gr.update()
|
| 472 |
+
|
| 473 |
state.additional_instruction = additional_instruction
|
| 474 |
state.files_to_translate = [file_to_translate]
|
| 475 |
+
state.step = "translate"
|
| 476 |
+
|
| 477 |
+
# Start translation directly
|
| 478 |
+
if force_retranslate:
|
| 479 |
+
history.append(["Translation request", "๐ **Force retranslation started...**"])
|
| 480 |
+
response, translated = start_translation_process(force_retranslate)
|
| 481 |
+
history.append(["", response])
|
| 482 |
+
if translated:
|
| 483 |
+
history.append(["", translated])
|
| 484 |
+
|
| 485 |
+
# Update button text and show confirm button after translation
|
| 486 |
+
start_btn_text = "๐ Retranslation" if state.current_file_content["translated"] else "๐ Start Translation"
|
| 487 |
+
confirm_btn_visible = bool(state.current_file_content["translated"])
|
| 488 |
+
|
| 489 |
+
return history, "", update_status(), gr.Tabs(), gr.update(value=start_btn_text), gr.update(visible=confirm_btn_visible)
|
| 490 |
|
| 491 |
|
| 492 |
def approve_handler(history, owner, repo, reference_pr_url):
|
|
|
|
| 494 |
global state
|
| 495 |
state.step = "create_github_pr"
|
| 496 |
|
| 497 |
+
# Check all required GitHub configuration at once
|
| 498 |
github_config = state.persistent_settings["github_config"]
|
| 499 |
+
missing_config = []
|
| 500 |
+
|
| 501 |
if not github_config.get("token"):
|
| 502 |
+
missing_config.append("GitHub Token")
|
| 503 |
+
if not owner:
|
| 504 |
+
missing_config.append("GitHub Owner")
|
| 505 |
+
if not repo:
|
| 506 |
+
missing_config.append("Repository Name")
|
| 507 |
+
|
| 508 |
+
if missing_config:
|
| 509 |
+
config = get_project_config(state.selected_project)
|
| 510 |
+
repo_name = config.repo_url.split('/')[-1] # Extract repo name from URL
|
| 511 |
+
response = f"โ Please set the following in Configuration panel first: {', '.join(missing_config)}\n\n๐ก **Note:** GitHub Owner/Repository should be your fork of [`{repo_name}`]({config.repo_url}) (e.g., Owner: `your-username`, Repository: `{repo_name}`)"
|
| 512 |
history.append(["GitHub PR creation request", response])
|
| 513 |
return history, "", update_status()
|
| 514 |
|
|
|
|
| 519 |
# Use persistent settings
|
| 520 |
github_config = state.persistent_settings["github_config"]
|
| 521 |
|
| 522 |
+
# Initialize response variable
|
| 523 |
+
response = ""
|
| 524 |
+
|
| 525 |
# If reference PR is not provided, use the agent to find one
|
| 526 |
if not github_config.get("reference_pr_url"):
|
| 527 |
response = "๐ค **Reference PR URL not found. The agent will now search for a suitable one...**"
|
|
|
|
| 577 |
translated_content=translated_content,
|
| 578 |
github_config=state.github_config,
|
| 579 |
en_title=file_name,
|
| 580 |
+
project=state.selected_project,
|
| 581 |
)
|
| 582 |
response += f"\n{pr_response}"
|
| 583 |
else:
|
agent/toctree_handler.py
CHANGED
|
@@ -4,9 +4,17 @@ from typing import Dict, List, Any
|
|
| 4 |
import os
|
| 5 |
|
| 6 |
class TocTreeHandler:
|
| 7 |
-
def __init__(self):
|
| 8 |
-
|
| 9 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
self.local_docs_path = "docs/source/ko"
|
| 11 |
|
| 12 |
def fetch_toctree(self, url: str) -> Dict[str, Any]:
|
|
@@ -245,7 +253,8 @@ Korean title:"""
|
|
| 245 |
translation_result: dict,
|
| 246 |
filepath: str,
|
| 247 |
pr_agent,
|
| 248 |
-
github_config: dict
|
|
|
|
| 249 |
) -> dict:
|
| 250 |
"""Update toctree after successful translation PR.
|
| 251 |
|
|
|
|
| 4 |
import os
|
| 5 |
|
| 6 |
class TocTreeHandler:
|
| 7 |
+
def __init__(self, project: str = "transformers"):
|
| 8 |
+
from translator.project_config import get_project_config
|
| 9 |
+
self.project = project
|
| 10 |
+
self.project_config = get_project_config(project)
|
| 11 |
+
|
| 12 |
+
# Extract repository path from config
|
| 13 |
+
repo_path = self.project_config.repo_url.replace("https://github.com/", "")
|
| 14 |
+
|
| 15 |
+
# Build project-specific URLs
|
| 16 |
+
self.en_toctree_url = f"https://raw.githubusercontent.com/{repo_path}/main/docs/source/en/_toctree.yml"
|
| 17 |
+
self.ko_toctree_url = f"https://raw.githubusercontent.com/{repo_path}/main/docs/source/ko/_toctree.yml"
|
| 18 |
self.local_docs_path = "docs/source/ko"
|
| 19 |
|
| 20 |
def fetch_toctree(self, url: str) -> Dict[str, Any]:
|
|
|
|
| 253 |
translation_result: dict,
|
| 254 |
filepath: str,
|
| 255 |
pr_agent,
|
| 256 |
+
github_config: dict,
|
| 257 |
+
project: str = "transformers"
|
| 258 |
) -> dict:
|
| 259 |
"""Update toctree after successful translation PR.
|
| 260 |
|
agent/workflow.py
CHANGED
|
@@ -62,23 +62,24 @@ def report_translation_target_files(
|
|
| 62 |
return status_report, [[file] for file in filepath_list]
|
| 63 |
|
| 64 |
|
| 65 |
-
def translate_docs(lang: str, file_path: str, additional_instruction: str = "") -> tuple[str, str]:
|
| 66 |
"""Translate documentation."""
|
| 67 |
-
# Check if translation already exists
|
| 68 |
translation_file_path = (
|
| 69 |
Path(__file__).resolve().parent.parent
|
| 70 |
/ f"translation_result/{file_path}"
|
| 71 |
)
|
| 72 |
|
| 73 |
-
if translation_file_path.exists():
|
| 74 |
print(f"๐ Found existing translation: {translation_file_path}")
|
| 75 |
with open(translation_file_path, "r", encoding="utf-8") as f:
|
| 76 |
existing_content = f.read()
|
| 77 |
if existing_content.strip():
|
| 78 |
-
|
|
|
|
| 79 |
|
| 80 |
# step 1. Get content from file path
|
| 81 |
-
content = get_content(file_path)
|
| 82 |
to_translate = preprocess_content(content)
|
| 83 |
|
| 84 |
# step 2. Prepare prompt with docs content
|
|
@@ -101,7 +102,7 @@ def translate_docs(lang: str, file_path: str, additional_instruction: str = "")
|
|
| 101 |
|
| 102 |
|
| 103 |
def translate_docs_interactive(
|
| 104 |
-
translate_lang: str, selected_files: list[list[str]], additional_instruction: str = ""
|
| 105 |
) -> tuple[str, str]:
|
| 106 |
"""Interactive translation function that processes files one by one.
|
| 107 |
|
|
@@ -115,14 +116,22 @@ def translate_docs_interactive(
|
|
| 115 |
# Start with the first file
|
| 116 |
current_file = file_paths[0]
|
| 117 |
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
|
| 122 |
print(callback_result)
|
| 123 |
print(status)
|
| 124 |
|
| 125 |
-
return translated_content
|
| 126 |
|
| 127 |
|
| 128 |
def generate_github_pr(
|
|
@@ -131,6 +140,7 @@ def generate_github_pr(
|
|
| 131 |
translated_content: str = None,
|
| 132 |
github_config: dict = None,
|
| 133 |
en_title: str = None,
|
|
|
|
| 134 |
) -> str:
|
| 135 |
"""Generate a GitHub PR for translated documentation.
|
| 136 |
|
|
@@ -148,7 +158,7 @@ def generate_github_pr(
|
|
| 148 |
return "โ GitHub PR Agent is not available. Please install required libraries."
|
| 149 |
|
| 150 |
if not github_config:
|
| 151 |
-
return "โ GitHub configuration not provided."
|
| 152 |
|
| 153 |
# Validate required configuration
|
| 154 |
required_fields = ["token", "owner", "repo_name", "reference_pr_url"]
|
|
@@ -157,7 +167,7 @@ def generate_github_pr(
|
|
| 157 |
]
|
| 158 |
|
| 159 |
if missing_fields:
|
| 160 |
-
return f"โ Missing required configuration: {', '.join(missing_fields)}
|
| 161 |
|
| 162 |
# Set token in environment for the agent.
|
| 163 |
os.environ["GITHUB_TOKEN"] = github_config["token"]
|
|
@@ -170,29 +180,39 @@ def generate_github_pr(
|
|
| 170 |
/ f"translation_result/{filepath}"
|
| 171 |
)
|
| 172 |
if not translation_file_path.exists():
|
| 173 |
-
return f"โ Translation file not found: {translation_file_path}"
|
| 174 |
|
| 175 |
with open(translation_file_path, "r", encoding="utf-8") as f:
|
| 176 |
translated_content = f.read()
|
| 177 |
|
| 178 |
if not translated_content or not translated_content.strip():
|
| 179 |
-
return "โ Translated content is empty."
|
| 180 |
|
| 181 |
# Execute GitHub PR Agent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
print(f"๐ Starting GitHub PR creation...")
|
| 183 |
print(f" ๐ File: {filepath}")
|
| 184 |
print(f" ๐ Language: {target_language}")
|
| 185 |
print(f" ๐ Reference PR: {github_config['reference_pr_url']}")
|
| 186 |
-
print(f" ๐
|
| 187 |
-
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
result = agent.run_translation_pr_workflow(
|
| 190 |
reference_pr_url=github_config["reference_pr_url"],
|
| 191 |
target_language=target_language,
|
| 192 |
filepath=filepath,
|
| 193 |
translated_doc=translated_content,
|
| 194 |
-
owner=github_config["owner"],
|
| 195 |
-
repo_name=github_config["repo_name"],
|
| 196 |
base_branch=github_config.get("base_branch", "main"),
|
| 197 |
)
|
| 198 |
# TEST CODE
|
|
@@ -206,9 +226,9 @@ def generate_github_pr(
|
|
| 206 |
toctree_result = None
|
| 207 |
if en_title:
|
| 208 |
from agent.toctree_handler import TocTreeHandler
|
| 209 |
-
toctree_handler = TocTreeHandler()
|
| 210 |
toctree_result = toctree_handler.update_toctree_after_translation(
|
| 211 |
-
result, filepath, agent, github_config
|
| 212 |
)
|
| 213 |
|
| 214 |
# Process result
|
|
@@ -252,13 +272,29 @@ def generate_github_pr(
|
|
| 252 |
{result.get("error_details", "Unknown error")}"""
|
| 253 |
|
| 254 |
else:
|
|
|
|
| 255 |
return f"""โ **GitHub PR Creation Failed**
|
| 256 |
|
| 257 |
**Error Message:**
|
| 258 |
-
{result["message"]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
|
| 260 |
except Exception as e:
|
| 261 |
-
error_msg = f"โ Unexpected
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
print(error_msg)
|
| 263 |
return error_msg
|
| 264 |
|
|
|
|
| 62 |
return status_report, [[file] for file in filepath_list]
|
| 63 |
|
| 64 |
|
| 65 |
+
def translate_docs(lang: str, file_path: str, additional_instruction: str = "", project: str = "transformers", force_retranslate: bool = False) -> tuple[str, str]:
|
| 66 |
"""Translate documentation."""
|
| 67 |
+
# Check if translation already exists (unless force retranslate is enabled)
|
| 68 |
translation_file_path = (
|
| 69 |
Path(__file__).resolve().parent.parent
|
| 70 |
/ f"translation_result/{file_path}"
|
| 71 |
)
|
| 72 |
|
| 73 |
+
if not force_retranslate and translation_file_path.exists():
|
| 74 |
print(f"๐ Found existing translation: {translation_file_path}")
|
| 75 |
with open(translation_file_path, "r", encoding="utf-8") as f:
|
| 76 |
existing_content = f.read()
|
| 77 |
if existing_content.strip():
|
| 78 |
+
existing_msg = f"โป๏ธ **Existing translation loaded** (no tokens used)\n๐ **File:** `{file_path}`\n๐
**Loaded from:** `{translation_file_path}`\n๐ก **To retranslate:** Check 'Force Retranslate' option."
|
| 79 |
+
return existing_msg, existing_content
|
| 80 |
|
| 81 |
# step 1. Get content from file path
|
| 82 |
+
content = get_content(file_path, project)
|
| 83 |
to_translate = preprocess_content(content)
|
| 84 |
|
| 85 |
# step 2. Prepare prompt with docs content
|
|
|
|
| 102 |
|
| 103 |
|
| 104 |
def translate_docs_interactive(
|
| 105 |
+
translate_lang: str, selected_files: list[list[str]], additional_instruction: str = "", project: str = "transformers", force_retranslate: bool = False
|
| 106 |
) -> tuple[str, str]:
|
| 107 |
"""Interactive translation function that processes files one by one.
|
| 108 |
|
|
|
|
| 116 |
# Start with the first file
|
| 117 |
current_file = file_paths[0]
|
| 118 |
|
| 119 |
+
callback_result, translated_content = translate_docs(translate_lang, current_file, additional_instruction, project, force_retranslate)
|
| 120 |
+
|
| 121 |
+
# Check if existing translation was loaded
|
| 122 |
+
if isinstance(callback_result, str) and "Existing translation loaded" in callback_result:
|
| 123 |
+
status = callback_result # Use the existing translation message
|
| 124 |
+
else:
|
| 125 |
+
if force_retranslate:
|
| 126 |
+
status = f"๐ **Force Retranslation completed**: `{current_file}` โ `{translate_lang}`\n\n"
|
| 127 |
+
else:
|
| 128 |
+
status = f"โ
Translation completed: `{current_file}` โ `{translate_lang}`\n\n"
|
| 129 |
+
status += f"๐ฐ Used token and cost: \n```\n{callback_result}\n```"
|
| 130 |
|
| 131 |
print(callback_result)
|
| 132 |
print(status)
|
| 133 |
|
| 134 |
+
return status, translated_content
|
| 135 |
|
| 136 |
|
| 137 |
def generate_github_pr(
|
|
|
|
| 140 |
translated_content: str = None,
|
| 141 |
github_config: dict = None,
|
| 142 |
en_title: str = None,
|
| 143 |
+
project: str = "transformers",
|
| 144 |
) -> str:
|
| 145 |
"""Generate a GitHub PR for translated documentation.
|
| 146 |
|
|
|
|
| 158 |
return "โ GitHub PR Agent is not available. Please install required libraries."
|
| 159 |
|
| 160 |
if not github_config:
|
| 161 |
+
return "โ GitHub configuration not provided. Please set up GitHub token, owner, and repository in Configuration panel."
|
| 162 |
|
| 163 |
# Validate required configuration
|
| 164 |
required_fields = ["token", "owner", "repo_name", "reference_pr_url"]
|
|
|
|
| 167 |
]
|
| 168 |
|
| 169 |
if missing_fields:
|
| 170 |
+
return f"โ Missing required GitHub configuration: {', '.join(missing_fields)}\n\n๐ก Go to Configuration panel and set:\n" + "\n".join([f" โข {field}" for field in missing_fields])
|
| 171 |
|
| 172 |
# Set token in environment for the agent.
|
| 173 |
os.environ["GITHUB_TOKEN"] = github_config["token"]
|
|
|
|
| 180 |
/ f"translation_result/{filepath}"
|
| 181 |
)
|
| 182 |
if not translation_file_path.exists():
|
| 183 |
+
return f"โ Translation file not found: {translation_file_path}\n\n๐ก Please complete translation first in Tab 2 for file: {filepath}"
|
| 184 |
|
| 185 |
with open(translation_file_path, "r", encoding="utf-8") as f:
|
| 186 |
translated_content = f.read()
|
| 187 |
|
| 188 |
if not translated_content or not translated_content.strip():
|
| 189 |
+
return f"โ Translated content is empty for file: {filepath}\n\n๐ก Please complete translation first in Tab 2."
|
| 190 |
|
| 191 |
# Execute GitHub PR Agent
|
| 192 |
+
# Get base repository from project config
|
| 193 |
+
from translator.project_config import get_project_config
|
| 194 |
+
project_config = get_project_config(project)
|
| 195 |
+
base_repo_path = project_config.repo_url.replace("https://github.com/", "")
|
| 196 |
+
base_owner, base_repo = base_repo_path.split("/")
|
| 197 |
+
|
| 198 |
print(f"๐ Starting GitHub PR creation...")
|
| 199 |
print(f" ๐ File: {filepath}")
|
| 200 |
print(f" ๐ Language: {target_language}")
|
| 201 |
print(f" ๐ Reference PR: {github_config['reference_pr_url']}")
|
| 202 |
+
print(f" ๐ User Fork: {github_config['owner']}/{github_config['repo_name']}")
|
| 203 |
+
print(f" ๐ฏ Base Repository: {base_owner}/{base_repo}")
|
| 204 |
+
|
| 205 |
+
agent = GitHubPRAgent(
|
| 206 |
+
user_owner=github_config["owner"],
|
| 207 |
+
user_repo=github_config["repo_name"],
|
| 208 |
+
base_owner=base_owner,
|
| 209 |
+
base_repo=base_repo,
|
| 210 |
+
)
|
| 211 |
result = agent.run_translation_pr_workflow(
|
| 212 |
reference_pr_url=github_config["reference_pr_url"],
|
| 213 |
target_language=target_language,
|
| 214 |
filepath=filepath,
|
| 215 |
translated_doc=translated_content,
|
|
|
|
|
|
|
| 216 |
base_branch=github_config.get("base_branch", "main"),
|
| 217 |
)
|
| 218 |
# TEST CODE
|
|
|
|
| 226 |
toctree_result = None
|
| 227 |
if en_title:
|
| 228 |
from agent.toctree_handler import TocTreeHandler
|
| 229 |
+
toctree_handler = TocTreeHandler(project)
|
| 230 |
toctree_result = toctree_handler.update_toctree_after_translation(
|
| 231 |
+
result, filepath, agent, github_config, project
|
| 232 |
)
|
| 233 |
|
| 234 |
# Process result
|
|
|
|
| 272 |
{result.get("error_details", "Unknown error")}"""
|
| 273 |
|
| 274 |
else:
|
| 275 |
+
error_details = result.get("error_details", "No additional details")
|
| 276 |
return f"""โ **GitHub PR Creation Failed**
|
| 277 |
|
| 278 |
**Error Message:**
|
| 279 |
+
{result["message"]}
|
| 280 |
+
|
| 281 |
+
**Error Details:**
|
| 282 |
+
{error_details}
|
| 283 |
+
|
| 284 |
+
๐ก **Common Solutions:**
|
| 285 |
+
1. **Project Mismatch**: Selected project '{project}' but fork is '{github_config.get('repo_name', 'REPO')}' - ensure they match
|
| 286 |
+
2. Check if your GitHub fork exists: {github_config.get('owner', 'USER')}/{github_config.get('repo_name', 'REPO')}
|
| 287 |
+
3. Verify GitHub token has write access to your fork"""
|
| 288 |
|
| 289 |
except Exception as e:
|
| 290 |
+
error_msg = f"""โ **Unexpected Error During PR Creation**
|
| 291 |
+
|
| 292 |
+
**Error:** {str(e)}
|
| 293 |
+
|
| 294 |
+
**Configuration:**
|
| 295 |
+
โข Project: {project}
|
| 296 |
+
โข File: {filepath}
|
| 297 |
+
โข Target: {github_config.get('owner', 'USER')}/{github_config.get('repo_name', 'REPO')} โ {base_owner if 'base_owner' in locals() else 'BASE'}/{base_repo if 'base_repo' in locals() else 'REPO'}"""
|
| 298 |
print(error_msg)
|
| 299 |
return error_msg
|
| 300 |
|
app.py
CHANGED
|
@@ -8,12 +8,16 @@ from dotenv import load_dotenv
|
|
| 8 |
|
| 9 |
from agent.handler import (
|
| 10 |
approve_handler,
|
|
|
|
|
|
|
| 11 |
get_welcome_message,
|
| 12 |
process_file_search_handler,
|
| 13 |
restart_handler,
|
| 14 |
send_message,
|
| 15 |
start_translate_handler,
|
| 16 |
sync_language_displays,
|
|
|
|
|
|
|
| 17 |
update_prompt_preview,
|
| 18 |
update_status,
|
| 19 |
update_github_config,
|
|
@@ -188,6 +192,11 @@ with gr.Blocks(
|
|
| 188 |
"๐ Find Files to Translate",
|
| 189 |
elem_classes="action-button",
|
| 190 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
with gr.TabItem("2. Translate", id=1):
|
| 193 |
with gr.Group():
|
|
@@ -214,9 +223,13 @@ with gr.Blocks(
|
|
| 214 |
lines=2,
|
| 215 |
)
|
| 216 |
|
| 217 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
prompt_preview = gr.Textbox(
|
| 219 |
-
label="Current Translation Prompt",
|
| 220 |
lines=8,
|
| 221 |
interactive=False,
|
| 222 |
placeholder="Select a file and language to see the prompt preview...",
|
|
@@ -226,6 +239,12 @@ with gr.Blocks(
|
|
| 226 |
start_translate_btn = gr.Button(
|
| 227 |
"๐ Start Translation", elem_classes="action-button"
|
| 228 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
|
| 230 |
with gr.TabItem("3. Upload PR", id=2):
|
| 231 |
with gr.Group():
|
|
@@ -247,12 +266,31 @@ with gr.Blocks(
|
|
| 247 |
inputs=[project_dropdown, lang_dropdown, k_input, chatbot],
|
| 248 |
outputs=[chatbot, msg_input, status_display, control_tabs, files_to_translate],
|
| 249 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
|
| 251 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
lang_dropdown.change(
|
| 253 |
-
fn=
|
| 254 |
-
inputs=[lang_dropdown],
|
| 255 |
-
outputs=[translate_lang_display],
|
| 256 |
)
|
| 257 |
|
| 258 |
#
|
|
@@ -265,15 +303,21 @@ with gr.Blocks(
|
|
| 265 |
# Button event handlers
|
| 266 |
start_translate_btn.click(
|
| 267 |
fn=start_translate_handler,
|
| 268 |
-
inputs=[chatbot, file_to_translate_input, additional_instruction],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
outputs=[chatbot, msg_input, status_display, control_tabs],
|
| 270 |
)
|
| 271 |
|
| 272 |
# Configuration Save
|
| 273 |
save_config_btn.click(
|
| 274 |
fn=update_persistent_config,
|
| 275 |
-
inputs=[config_anthropic_key, config_github_token, config_github_owner, config_github_repo, reference_pr_url],
|
| 276 |
-
outputs=[msg_input],
|
| 277 |
)
|
| 278 |
|
| 279 |
approve_btn.click(
|
|
|
|
| 8 |
|
| 9 |
from agent.handler import (
|
| 10 |
approve_handler,
|
| 11 |
+
confirm_and_go_translate_handler,
|
| 12 |
+
confirm_translation_and_go_upload_handler,
|
| 13 |
get_welcome_message,
|
| 14 |
process_file_search_handler,
|
| 15 |
restart_handler,
|
| 16 |
send_message,
|
| 17 |
start_translate_handler,
|
| 18 |
sync_language_displays,
|
| 19 |
+
update_language_selection,
|
| 20 |
+
update_project_selection,
|
| 21 |
update_prompt_preview,
|
| 22 |
update_status,
|
| 23 |
update_github_config,
|
|
|
|
| 192 |
"๐ Find Files to Translate",
|
| 193 |
elem_classes="action-button",
|
| 194 |
)
|
| 195 |
+
|
| 196 |
+
confirm_go_btn = gr.Button(
|
| 197 |
+
"โ
Confirm Selection & Go to Translate",
|
| 198 |
+
elem_classes="action-button",
|
| 199 |
+
)
|
| 200 |
|
| 201 |
with gr.TabItem("2. Translate", id=1):
|
| 202 |
with gr.Group():
|
|
|
|
| 223 |
lines=2,
|
| 224 |
)
|
| 225 |
|
| 226 |
+
force_retranslate = gr.Checkbox(
|
| 227 |
+
label="๐ Force Retranslate (ignore existing translations)",
|
| 228 |
+
value=False,
|
| 229 |
+
)
|
| 230 |
+
|
| 231 |
+
with gr.Accordion("๐ Preview Translation Prompt", open=False):
|
| 232 |
prompt_preview = gr.Textbox(
|
|
|
|
| 233 |
lines=8,
|
| 234 |
interactive=False,
|
| 235 |
placeholder="Select a file and language to see the prompt preview...",
|
|
|
|
| 239 |
start_translate_btn = gr.Button(
|
| 240 |
"๐ Start Translation", elem_classes="action-button"
|
| 241 |
)
|
| 242 |
+
|
| 243 |
+
confirm_upload_btn = gr.Button(
|
| 244 |
+
"โ
Confirm Translation & Upload PR",
|
| 245 |
+
elem_classes="action-button",
|
| 246 |
+
visible=False,
|
| 247 |
+
)
|
| 248 |
|
| 249 |
with gr.TabItem("3. Upload PR", id=2):
|
| 250 |
with gr.Group():
|
|
|
|
| 266 |
inputs=[project_dropdown, lang_dropdown, k_input, chatbot],
|
| 267 |
outputs=[chatbot, msg_input, status_display, control_tabs, files_to_translate],
|
| 268 |
)
|
| 269 |
+
|
| 270 |
+
confirm_go_btn.click(
|
| 271 |
+
fn=confirm_and_go_translate_handler,
|
| 272 |
+
inputs=[chatbot],
|
| 273 |
+
outputs=[chatbot, msg_input, status_display, control_tabs],
|
| 274 |
+
)
|
| 275 |
|
| 276 |
+
# Auto-save selections to state and update prompt preview
|
| 277 |
+
project_dropdown.change(
|
| 278 |
+
fn=update_project_selection,
|
| 279 |
+
inputs=[project_dropdown, chatbot],
|
| 280 |
+
outputs=[chatbot, msg_input, status_display],
|
| 281 |
+
)
|
| 282 |
+
|
| 283 |
+
# Update prompt preview when project changes
|
| 284 |
+
project_dropdown.change(
|
| 285 |
+
fn=update_prompt_preview,
|
| 286 |
+
inputs=[translate_lang_display, file_to_translate_input, additional_instruction],
|
| 287 |
+
outputs=[prompt_preview],
|
| 288 |
+
)
|
| 289 |
+
|
| 290 |
lang_dropdown.change(
|
| 291 |
+
fn=update_language_selection,
|
| 292 |
+
inputs=[lang_dropdown, chatbot],
|
| 293 |
+
outputs=[chatbot, msg_input, status_display, translate_lang_display],
|
| 294 |
)
|
| 295 |
|
| 296 |
#
|
|
|
|
| 303 |
# Button event handlers
|
| 304 |
start_translate_btn.click(
|
| 305 |
fn=start_translate_handler,
|
| 306 |
+
inputs=[chatbot, file_to_translate_input, additional_instruction, force_retranslate],
|
| 307 |
+
outputs=[chatbot, msg_input, status_display, control_tabs, start_translate_btn, confirm_upload_btn],
|
| 308 |
+
)
|
| 309 |
+
|
| 310 |
+
confirm_upload_btn.click(
|
| 311 |
+
fn=confirm_translation_and_go_upload_handler,
|
| 312 |
+
inputs=[chatbot],
|
| 313 |
outputs=[chatbot, msg_input, status_display, control_tabs],
|
| 314 |
)
|
| 315 |
|
| 316 |
# Configuration Save
|
| 317 |
save_config_btn.click(
|
| 318 |
fn=update_persistent_config,
|
| 319 |
+
inputs=[config_anthropic_key, config_github_token, config_github_owner, config_github_repo, reference_pr_url, chatbot],
|
| 320 |
+
outputs=[chatbot, msg_input, status_display],
|
| 321 |
)
|
| 322 |
|
| 323 |
approve_btn.click(
|
pr_generator/agent.py
CHANGED
|
@@ -34,9 +34,13 @@ except ImportError as e:
|
|
| 34 |
class GitHubPRAgent:
|
| 35 |
"""Agent class for GitHub PR creation"""
|
| 36 |
|
| 37 |
-
def __init__(self):
|
| 38 |
self._github_client = None
|
| 39 |
self._llm = None
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
@property
|
| 42 |
def github_client(self) -> Optional[Github]:
|
|
@@ -433,8 +437,6 @@ Please return only the commit message. No other explanation is needed."""
|
|
| 433 |
target_language: str,
|
| 434 |
filepath: str,
|
| 435 |
translated_doc: str,
|
| 436 |
-
owner: str,
|
| 437 |
-
repo_name: str,
|
| 438 |
base_branch: str = "main",
|
| 439 |
) -> Dict[str, Any]:
|
| 440 |
"""Execute translation document PR creation workflow."""
|
|
@@ -458,19 +460,20 @@ Please return only the commit message. No other explanation is needed."""
|
|
| 458 |
)
|
| 459 |
|
| 460 |
# 3. Get main branch SHA from upstream and create branch in fork
|
| 461 |
-
upstream_repo = self.github_client.get_repo(f"
|
| 462 |
main_branch = upstream_repo.get_branch(base_branch)
|
| 463 |
main_sha = main_branch.commit.sha
|
| 464 |
|
| 465 |
print(f"๐ฟ Creating branch: {branch_name} in fork repository")
|
| 466 |
-
branch_result = self.create_branch(
|
| 467 |
|
| 468 |
# Check branch creation result
|
| 469 |
if branch_result.startswith("ERROR"):
|
| 470 |
return {
|
| 471 |
"status": "error",
|
| 472 |
-
"message": f"Branch creation failed: {branch_result}",
|
| 473 |
"branch": branch_name,
|
|
|
|
| 474 |
}
|
| 475 |
elif branch_result.startswith("WARNING"):
|
| 476 |
print(f"โ ๏ธ {branch_result}")
|
|
@@ -489,8 +492,8 @@ Please return only the commit message. No other explanation is needed."""
|
|
| 489 |
|
| 490 |
print(f"๐ Saving file: {target_filepath}")
|
| 491 |
file_result = self.create_or_update_file(
|
| 492 |
-
|
| 493 |
-
|
| 494 |
target_filepath,
|
| 495 |
commit_message,
|
| 496 |
translated_doc,
|
|
@@ -500,9 +503,10 @@ Please return only the commit message. No other explanation is needed."""
|
|
| 500 |
if not file_result.startswith("SUCCESS"):
|
| 501 |
return {
|
| 502 |
"status": "error",
|
| 503 |
-
"message": "
|
| 504 |
"branch": branch_name,
|
| 505 |
"file_path": target_filepath,
|
|
|
|
| 506 |
}
|
| 507 |
|
| 508 |
print(f"{file_result}")
|
|
@@ -518,11 +522,11 @@ Please return only the commit message. No other explanation is needed."""
|
|
| 518 |
)
|
| 519 |
|
| 520 |
print(f"๐ Creating PR: {pr_title}")
|
| 521 |
-
print(f" Head: {
|
| 522 |
|
| 523 |
# Create PR from fork to upstream repository
|
| 524 |
pr_result = self.create_pull_request(
|
| 525 |
-
|
| 526 |
)
|
| 527 |
|
| 528 |
if pr_result.startswith("ERROR"):
|
|
@@ -554,7 +558,8 @@ Please return only the commit message. No other explanation is needed."""
|
|
| 554 |
except Exception as e:
|
| 555 |
return {
|
| 556 |
"status": "error",
|
| 557 |
-
"message": f"
|
|
|
|
| 558 |
}
|
| 559 |
|
| 560 |
|
|
|
|
| 34 |
class GitHubPRAgent:
|
| 35 |
"""Agent class for GitHub PR creation"""
|
| 36 |
|
| 37 |
+
def __init__(self, user_owner: str = None, user_repo: str = None, base_owner: str = None, base_repo: str = None):
|
| 38 |
self._github_client = None
|
| 39 |
self._llm = None
|
| 40 |
+
self.user_owner = user_owner
|
| 41 |
+
self.user_repo = user_repo
|
| 42 |
+
self.base_owner = base_owner
|
| 43 |
+
self.base_repo = base_repo
|
| 44 |
|
| 45 |
@property
|
| 46 |
def github_client(self) -> Optional[Github]:
|
|
|
|
| 437 |
target_language: str,
|
| 438 |
filepath: str,
|
| 439 |
translated_doc: str,
|
|
|
|
|
|
|
| 440 |
base_branch: str = "main",
|
| 441 |
) -> Dict[str, Any]:
|
| 442 |
"""Execute translation document PR creation workflow."""
|
|
|
|
| 460 |
)
|
| 461 |
|
| 462 |
# 3. Get main branch SHA from upstream and create branch in fork
|
| 463 |
+
upstream_repo = self.github_client.get_repo(f"{self.base_owner}/{self.base_repo}")
|
| 464 |
main_branch = upstream_repo.get_branch(base_branch)
|
| 465 |
main_sha = main_branch.commit.sha
|
| 466 |
|
| 467 |
print(f"๐ฟ Creating branch: {branch_name} in fork repository")
|
| 468 |
+
branch_result = self.create_branch(self.user_owner, self.user_repo, branch_name, main_sha)
|
| 469 |
|
| 470 |
# Check branch creation result
|
| 471 |
if branch_result.startswith("ERROR"):
|
| 472 |
return {
|
| 473 |
"status": "error",
|
| 474 |
+
"message": f"Branch creation failed: {branch_result}\n\nTarget: {self.user_owner}/{self.user_repo}\nBranch: {branch_name}\nBase SHA: {main_sha[:8]}",
|
| 475 |
"branch": branch_name,
|
| 476 |
+
"error_details": branch_result,
|
| 477 |
}
|
| 478 |
elif branch_result.startswith("WARNING"):
|
| 479 |
print(f"โ ๏ธ {branch_result}")
|
|
|
|
| 492 |
|
| 493 |
print(f"๐ Saving file: {target_filepath}")
|
| 494 |
file_result = self.create_or_update_file(
|
| 495 |
+
self.user_owner,
|
| 496 |
+
self.user_repo,
|
| 497 |
target_filepath,
|
| 498 |
commit_message,
|
| 499 |
translated_doc,
|
|
|
|
| 503 |
if not file_result.startswith("SUCCESS"):
|
| 504 |
return {
|
| 505 |
"status": "error",
|
| 506 |
+
"message": f"File save failed: {file_result}\n\n๐ฏ Target: {self.user_owner}/{self.user_repo} (expected: {target_language} fork of {self.base_owner}/{self.base_repo})\n๐ฟ Branch: {branch_name}\n๐ File: {target_filepath}",
|
| 507 |
"branch": branch_name,
|
| 508 |
"file_path": target_filepath,
|
| 509 |
+
"error_details": file_result,
|
| 510 |
}
|
| 511 |
|
| 512 |
print(f"{file_result}")
|
|
|
|
| 522 |
)
|
| 523 |
|
| 524 |
print(f"๐ Creating PR: {pr_title}")
|
| 525 |
+
print(f" Head: {self.user_owner}:{branch_name} โ Base: {self.base_owner}:{base_branch}")
|
| 526 |
|
| 527 |
# Create PR from fork to upstream repository
|
| 528 |
pr_result = self.create_pull_request(
|
| 529 |
+
self.base_owner, self.base_repo, pr_title, f"{self.user_owner}:{branch_name}", base_branch, pr_body, draft=True
|
| 530 |
)
|
| 531 |
|
| 532 |
if pr_result.startswith("ERROR"):
|
|
|
|
| 558 |
except Exception as e:
|
| 559 |
return {
|
| 560 |
"status": "error",
|
| 561 |
+
"message": f"Workflow execution failed: {str(e)}\n\nConfig: {self.user_owner}/{self.user_repo} โ {self.base_owner}/{self.base_repo}\nFile: {filepath if 'filepath' in locals() else 'Unknown'}",
|
| 562 |
+
"error_details": str(e),
|
| 563 |
}
|
| 564 |
|
| 565 |
|
translator/content.py
CHANGED
|
@@ -6,15 +6,18 @@ from langchain.callbacks import get_openai_callback
|
|
| 6 |
from langchain_anthropic import ChatAnthropic
|
| 7 |
|
| 8 |
from translator.prompt_glossary import PROMPT_WITH_GLOSSARY
|
|
|
|
| 9 |
|
| 10 |
|
| 11 |
-
def get_content(filepath: str) -> str:
|
| 12 |
if filepath == "":
|
| 13 |
raise ValueError("No files selected for translation.")
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
|
|
|
|
|
|
| 18 |
response = requests.get(url)
|
| 19 |
if response.status_code == 200:
|
| 20 |
content = response.text
|
|
@@ -170,4 +173,4 @@ def llm_translate(to_translate: str) -> tuple[str, str]:
|
|
| 170 |
)
|
| 171 |
ai_message = model.invoke(to_translate)
|
| 172 |
print("cb:", cb)
|
| 173 |
-
return cb, ai_message.content
|
|
|
|
| 6 |
from langchain_anthropic import ChatAnthropic
|
| 7 |
|
| 8 |
from translator.prompt_glossary import PROMPT_WITH_GLOSSARY
|
| 9 |
+
from translator.project_config import get_project_config
|
| 10 |
|
| 11 |
|
| 12 |
+
def get_content(filepath: str, project: str = "transformers") -> str:
|
| 13 |
if filepath == "":
|
| 14 |
raise ValueError("No files selected for translation.")
|
| 15 |
|
| 16 |
+
config = get_project_config(project)
|
| 17 |
+
# Extract repo path from repo_url (e.g., "huggingface/transformers")
|
| 18 |
+
repo_path = config.repo_url.replace("https://github.com/", "")
|
| 19 |
+
|
| 20 |
+
url = f"https://raw.githubusercontent.com/{repo_path}/main/{filepath}"
|
| 21 |
response = requests.get(url)
|
| 22 |
if response.status_code == 200:
|
| 23 |
content = response.text
|
|
|
|
| 173 |
)
|
| 174 |
ai_message = model.invoke(to_translate)
|
| 175 |
print("cb:", cb)
|
| 176 |
+
return str(cb), ai_message.content
|