|
5 | 5 | from PySide6.QtCore import QThread, Signal |
6 | 6 | from je_editor import language_wrapper |
7 | 7 |
|
8 | | -from pybreeze.pybreeze_ui.extend_ai_gui.ai_gui_global_variable import COT_TEMPLATE_RELATION |
9 | | -from pybreeze.pybreeze_ui.extend_ai_gui.prompt_edit_gui.cot_code_review_prompt_templates.global_rule import \ |
10 | | - build_global_rule_template |
| 8 | +from pybreeze.pybreeze_ui.extend_ai_gui.code_review.cot_chain import ( |
| 9 | + CODE_DIFF, STEP_RESULT_KEY, build_prompt |
| 10 | +) |
11 | 11 | from pybreeze.utils.logging.logger import pybreeze_logger |
12 | 12 | from pybreeze.utils.network.http_client import ( |
13 | 13 | ResponseTooLargeError, read_capped_text, CONNECT_TIMEOUT, |
@@ -40,74 +40,36 @@ def run(self): |
40 | 40 | session.close() |
41 | 41 |
|
42 | 42 | def _run_templates(self, session: requests.Session, code: str) -> None: |
43 | | - first_code_review_result = None |
44 | | - first_summary_result = None |
45 | | - linter_result = None |
46 | | - code_smell_result = None |
| 43 | + # Answers accumulate here as the chain runs; a later step quotes whichever |
| 44 | + # of them its template asks for. See cot_chain for the wiring. |
| 45 | + results: dict[str, str] = {CODE_DIFF: code} |
47 | 46 | for file in self.files: |
48 | 47 | # Stop promptly if the widget is closing instead of firing off the |
49 | 48 | # remaining per-template POSTs. |
50 | 49 | if self.isInterruptionRequested(): |
51 | 50 | return |
52 | | - match file: |
53 | | - case "first_summary_prompt.md": |
54 | | - first_summary_prompt = COT_TEMPLATE_RELATION["first_summary_prompt.md"] |
55 | | - prompt = build_global_rule_template( |
56 | | - prompt=first_summary_prompt.format(code_diff=code) |
57 | | - ) |
58 | | - case "first_code_review.md": |
59 | | - first_code_review_prompt = COT_TEMPLATE_RELATION["first_code_review.md"] |
60 | | - prompt = build_global_rule_template( |
61 | | - prompt=first_code_review_prompt.format(code_diff=code) |
62 | | - ) |
63 | | - case "linter.md": |
64 | | - linter_prompt = COT_TEMPLATE_RELATION["linter.md"] |
65 | | - prompt = build_global_rule_template( |
66 | | - prompt=linter_prompt.format(code_diff=code) |
67 | | - ) |
68 | | - case "code_smell_detector.md": |
69 | | - code_smell_detector_prompt = COT_TEMPLATE_RELATION["code_smell_detector.md"] |
70 | | - prompt = build_global_rule_template( |
71 | | - prompt=code_smell_detector_prompt.format(code_diff=code) |
72 | | - ) |
73 | | - case "total_summary.md": |
74 | | - total_summary_prompt = COT_TEMPLATE_RELATION["total_summary.md"] |
75 | | - prompt = build_global_rule_template( |
76 | | - prompt=total_summary_prompt.format( |
77 | | - first_code_review=first_code_review_result, |
78 | | - first_summary=first_summary_result, |
79 | | - linter_result=linter_result, |
80 | | - code_smell_result=code_smell_result, |
81 | | - code_diff=code, |
82 | | - ) |
83 | | - ) |
84 | | - case _: |
85 | | - continue |
86 | | - |
87 | | - try: |
88 | | - # 傳送到指定 URL(重用 session 連線) |
89 | | - resp = session.post( |
90 | | - self.url, json={"prompt": prompt}, |
91 | | - timeout=(CONNECT_TIMEOUT, 60), allow_redirects=False, stream=True, |
92 | | - ) |
93 | | - reply_text = read_capped_text(resp) |
94 | | - match file: |
95 | | - case "first_summary_prompt.md": |
96 | | - first_summary_result = reply_text |
97 | | - case "first_code_review.md": |
98 | | - first_code_review_result = reply_text |
99 | | - case "linter.md": |
100 | | - linter_result = reply_text |
101 | | - case "code_smell_detector.md": |
102 | | - code_smell_result = reply_text |
103 | | - case _: |
104 | | - # total_summary.md has no intermediate result to store but |
105 | | - # must still be emitted — `continue` here previously |
106 | | - # dropped the final summary before it reached the UI. |
107 | | - pass |
108 | | - except (requests.RequestException, ResponseTooLargeError) as e: |
109 | | - pybreeze_logger.error("CoT code review send failed for %s: %r", file, e) |
110 | | - reply_text = f"{language_wrapper.language_word_dict.get('cot_gui_error_sending')} {file} {e}" |
111 | | - |
| 51 | + prompt = build_prompt(file, results) |
| 52 | + if prompt is None: |
| 53 | + continue |
| 54 | + reply_text, answered = self._ask(session, file, prompt) |
| 55 | + result_key = STEP_RESULT_KEY.get(file) |
| 56 | + # A failure message is shown but never stored: a later step must not |
| 57 | + # quote "could not send" back to the model as if it were a review. |
| 58 | + if answered and result_key is not None: |
| 59 | + results[result_key] = reply_text |
112 | 60 | # 發送訊號更新 UI |
113 | 61 | self.update_response.emit(file, reply_text) |
| 62 | + |
| 63 | + def _ask(self, session: requests.Session, file: str, prompt: str) -> tuple[str, bool]: |
| 64 | + """Send one step's prompt; return its answer and whether it arrived.""" |
| 65 | + try: |
| 66 | + # 傳送到指定 URL(重用 session 連線) |
| 67 | + resp = session.post( |
| 68 | + self.url, json={"prompt": prompt}, |
| 69 | + timeout=(CONNECT_TIMEOUT, 60), allow_redirects=False, stream=True, |
| 70 | + ) |
| 71 | + return read_capped_text(resp), True |
| 72 | + except (requests.RequestException, ResponseTooLargeError) as error: |
| 73 | + pybreeze_logger.error("CoT code review send failed for %s: %r", file, error) |
| 74 | + word = language_wrapper.language_word_dict |
| 75 | + return f"{word.get('cot_gui_error_sending')} {file} {error}", False |
0 commit comments