diff --git a/03.Code/업로드용/handlers/report/processor.py b/03.Code/업로드용/handlers/report/processor.py index 5c9fb67..66361e9 100644 --- a/03.Code/업로드용/handlers/report/processor.py +++ b/03.Code/업로드용/handlers/report/processor.py @@ -1,3 +1,161 @@ -# 보고서 처리기 +# -*- coding: utf-8 -*- +""" +보고서 (report) 처리 로직 +- 다면 보고서 +- 원본 구조 유지 +- RAG 파이프라인 연동 (긴 문서) +""" + +import os +import re +from pathlib import Path +from flask import session + +from handlers.common import call_claude, extract_html, load_prompt, client +from converters.pipeline.router import process_document, convert_image_paths + + class ReportProcessor: - pass + """보고서 처리 클래스""" + + def __init__(self): + self.prompts_dir = Path(__file__).parent / 'prompts' + + def _load_prompt(self, filename: str) -> str: + """프롬프트 로드""" + return load_prompt(str(self.prompts_dir), filename) + + def generate(self, content: str, options: dict) -> dict: + """보고서 생성""" + try: + if not content.strip(): + return {'error': '내용이 데이터가 없습니다.'} + + # 특정 스타일 로드 + template_id = options.get('template_id') + if template_id: + from handlers.template import TemplateProcessor + template_processor = TemplateProcessor() + style = template_processor.get_style(template_id) + if style and style.get('css'): + options['template_css'] = style['css'] + + # 이미지 경로 변환 + processed_html = convert_image_paths(content) + + # router를 통해 분석 및 데이터 파이프라인 적용 + result = process_document(processed_html, options) + + if result.get('success'): + session['original_html'] = content + session['current_html'] = result.get('html', '') + + return result + + except Exception as e: + import traceback + return {'error': str(e), 'trace': traceback.format_exc()} + + def refine(self, feedback: str, current_html: str, original_html: str = '') -> dict: + """피드백 반영""" + try: + if not feedback.strip(): + return {'error': '피드백 내용을 입력해주십시오.'} + + if not current_html: + return {'error': '수정할 HTML이 없습니다.'} + + refine_prompt = f"""당신은 HTML 보고서 수정 전문가입니다. + +사용자 피드백을 반영하여 현재 HTML을 수정합니다. + +## 규칙 +1. 피드백에서 언급된 부분만 정확히 수정 +2. 전체 구조(sheet, body-content, page-header 등)는 절대 변경하지 마십시오** +3. 완성된 HTML 문서로 출력 ( ~ ) +4. 코드 블록에 출력 + +## 현재 HTML +{current_html} + +## 사용자 피드백 +{feedback} + +--- +위 피드백을 반영한 최종 수정된 HTML을 출력하세요.""" + + response = call_claude("", refine_prompt, max_tokens=8000) + new_html = extract_html(response) + + session['current_html'] = new_html + + return { + 'success': True, + 'html': new_html + } + + except Exception as e: + return {'error': str(e)} + + def refine_selection(self, current_html: str, selected_text: str, user_request: str) -> dict: + """선택 부분만 수정 (보고서용 - 페이지 구조 보존)""" + try: + if not current_html or not selected_text or not user_request: + return {'error': '필수 데이터가 없습니다.'} + + message = client.messages.create( + model="claude-sonnet-4-20250514", + max_tokens=8000, + messages=[{ + "role": "user", + "content": f"""HTML 문서에서 지정된 부분만 수정해주십시오. + +## 전체 문서 (컨텍스트 파악용) +{current_html[:5000]} + +## 선택된 텍스트 +"{selected_text}" + +## 수정 요청 +{user_request} + +## 규칙 +1. **절대로 페이지 구조(sheet, body-content, page-header, page-footer)를 변경하지 마십시오** +2. 수정할 텍스트만 출력하고, 주변 HTML 태그는 그대로 유지 +3. 요청 분석하여 수정 유형 판단: + - TEXT: 텍스트 내용만 수정 (요약, 문장 변경, 단어 수정, 번역 등) + - STRUCTURE: HTML 구조 변경 필요 (표 생성, 배치 추가 등) + +4. 반드시 다음 형식으로만 출력: + +TYPE: (TEXT 또는 STRUCTURE) +CONTENT: +(수정된 내용 - 선택된 텍스트의 수정본만) + +5. TEXT형: 수정된 텍스트만 출력 (HTML 태그 포함하지 않은 수정본만) +6. STRUCTURE형: 해당 요소만 출력 (전체 페이지 구조 X) +7. 문체유지 (~함, ~임, ~함) +""" + }] + ) + + result = message.content[0].text + result = result.replace('```html', '').replace('```', '').strip() + + edit_type = 'TEXT' + content = result + + if 'TYPE:' in result and 'CONTENT:' in result: + type_line = result.split('CONTENT:')[0] + if 'STRUCTURE' in type_line: + edit_type = 'STRUCTURE' + content = result.split('CONTENT:')[1].strip() + + return { + 'success': True, + 'type': edit_type, + 'html': content + } + + except Exception as e: + return {'error': str(e)} \ No newline at end of file