(self, section: Section, video_path: str, round_number: int = 1)
| 400 | return False |
| 401 | |
| 402 | def get_mllm_feedback(self, section: Section, video_path: str, round_number: int = 1) -> VideoFeedback: |
| 403 | print(f"🤖 {self.learning_topic} Using MLLM to analyze video ({round_number}/{self.feedback_rounds}): {section.id}") |
| 404 | |
| 405 | current_code = self.section_codes[section.id] |
| 406 | positions = self.extractor.extract_grid_positions(current_code) |
| 407 | position_table = self.extractor.generate_position_table(positions) |
| 408 | analysis_prompt = get_prompt4_layout_feedback(section=section, position_table=position_table) |
| 409 | |
| 410 | def _parse_layout(feedback_content): |
| 411 | has_layout_issues, suggested_improvements = False, [] |
| 412 | try: |
| 413 | data = json.loads(feedback_content) |
| 414 | lay = data.get("layout", {}) |
| 415 | has_layout_issues = bool(lay.get("has_issues", False)) |
| 416 | for it in lay.get("improvements", []) or []: |
| 417 | if isinstance(it, dict): |
| 418 | prob = str(it.get("problem", "")).strip() |
| 419 | sol = str(it.get("solution", "")).strip() |
| 420 | if prob or sol: |
| 421 | suggested_improvements.append(f"[LAYOUT] Problem: {prob}; Solution: {sol}") |
| 422 | |
| 423 | except json.JSONDecodeError: |
| 424 | print(f"⚠️ {self.learning_topic} JSON parse failed, fallback to keyword analysis") |
| 425 | |
| 426 | for m in re.finditer( |
| 427 | r"Problem:\s*(.*?);\s*Solution:\s*(.*?)(?=\n|$)", feedback_content, flags=re.IGNORECASE | re.DOTALL |
| 428 | ): |
| 429 | suggested_improvements.append(f"[LAYOUT] Problem: {m.group(1).strip()}; Solution: {m.group(2).strip()}") |
| 430 | |
| 431 | if not suggested_improvements: |
| 432 | for sol in re.findall(r"Solution\s*:\s*(.+)", feedback_content, flags=re.IGNORECASE): |
| 433 | suggested_improvements.append(f"[LAYOUT] Problem: ; Solution: {sol.strip()}") |
| 434 | |
| 435 | return has_layout_issues, suggested_improvements |
| 436 | |
| 437 | try: |
| 438 | response = request_gemini_video_img(prompt=analysis_prompt, video_path=video_path, image_path=self.GRID_IMG_PATH) |
| 439 | feedback_content = extract_answer_from_response(response) |
| 440 | has_layout_issues, suggested_improvements = _parse_layout(feedback_content) |
| 441 | feedback = VideoFeedback( |
| 442 | section_id=section.id, |
| 443 | video_path=video_path, |
| 444 | has_issues=has_layout_issues, |
| 445 | suggested_improvements=suggested_improvements, |
| 446 | raw_response=feedback_content, |
| 447 | ) |
| 448 | self.video_feedbacks[f"{section.id}_round{round_number}"] = feedback |
| 449 | return feedback |
| 450 | |
| 451 | except Exception as e: |
| 452 | print(f"❌ {self.learning_topic} MLLM analysis failed: {str(e)}") |
| 453 | return VideoFeedback( |
| 454 | section_id=section.id, |
| 455 | video_path=video_path, |
| 456 | has_issues=False, |
| 457 | suggested_improvements=[], |
| 458 | raw_response=f"Error: {str(e)}", |
| 459 | ) |
no test coverage detected