📦 Initialize Geulbeot structure and merge Prompts & test projects

This commit is contained in:
2026-03-05 11:32:29 +09:00
commit 555a954458
687 changed files with 205247 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
"""
보고서(report) 처리 모듈
"""
from .processor import ReportProcessor

View File

@@ -0,0 +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:
"""보고서 처리 클래스"""
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 문서로 출력 (<!DOCTYPE html> ~ </html>)
4. 코드 블록(```) 없이 순수 HTML만 출력
## 현재 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)}

View File

@@ -0,0 +1,104 @@
당신은 임원보고용 문서 구성 전문가입니다.
step1에서 추출된 JSON 구조를 분석하여, 각 요소의 역할을 분류하고 페이지 배치 계획을 수립합니다.
## 입력
- step1에서 추출된 JSON 구조 데이터
## 출력
- 페이지별 배치 계획 JSON (설명 없이 JSON만 출력)
---
## 배치 원칙
### 1페이지 (본문) - "왜? 무엇이 문제?"
- **lead-box**: 문서 전체의 핵심 명제/주제 문장 선정
- **본문 섹션**: 논리, 근거, 리스크, 주의사항 중심
- **bottom-box**: 문서 전체를 관통하는 핵심 결론 (1~2문장)
### 2페이지~ (첨부) - "어떻게? 상세 기준"
- **첨부 제목**: 해당 페이지 내용을 대표하는 제목
- **본문 섹션**: 프로세스, 절차, 표, 체크리스트, 상세 가이드
- **bottom-box**: 해당 페이지 내용 요약
---
## 요소 역할 분류 기준
| 역할 | 설명 | 배치 |
|------|------|------|
| 핵심명제 | 문서 전체 주제를 한 문장으로 | 1p lead-box |
| 논리/근거 | 왜 그런가? 정당성, 법적 근거 | 1p 본문 |
| 리스크 | 주의해야 할 세무/법적 위험 | 1p 본문 |
| 주의사항 | 실무상 유의점, 제언 | 1p 본문 |
| 핵심결론 | 문서 요약 한 문장 | 1p bottom-box |
| 프로세스 | 단계별 절차, Step | 첨부 |
| 기준표 | 할인율, 판정 기준 등 표 | 첨부 |
| 체크리스트 | 항목별 점검사항 | 첨부 |
| 상세가이드 | 세부 설명, 예시 | 첨부 |
| 실무멘트 | 대응 스크립트, 방어 논리 | 첨부 bottom-box |
---
## 출력 JSON 스키마
```json
{
"page_plan": {
"page_1": {
"type": "본문",
"lead": {
"source_section": "원본 섹션명 또는 null",
"text": "lead-box에 들어갈 핵심 명제 문장"
},
"sections": [
{
"source": "원본 섹션 제목",
"role": "논리/근거 | 리스크 | 주의사항",
"new_title": "변환 후 섹션 제목 (필요시 수정)"
}
],
"bottom": {
"label": "핵심 결론",
"source": "원본에서 가져올 문장 또는 조합할 키워드",
"text": "bottom-box에 들어갈 최종 문장"
}
},
"page_2": {
"type": "첨부",
"title": "[첨부] 페이지 제목",
"sections": [
{
"source": "원본 섹션 제목",
"role": "프로세스 | 기준표 | 체크리스트 | 상세가이드",
"new_title": "변환 후 섹션 제목"
}
],
"bottom": {
"label": "라벨 (예: 실무 핵심, 체크포인트 등)",
"source": "원본에서 가져올 문장",
"text": "bottom-box에 들어갈 최종 문장"
}
}
},
"page_count": 2
}
```
---
## 판단 규칙
1. **프로세스/Step 있으면** → 무조건 첨부로
2. **표(table) 있으면** → 가능하면 첨부로 (단, 핵심 리스크 표는 1p 가능)
3. **"~입니다", "~합니다" 종결문** → 개조식으로 변환 표시
4. **핵심 결론 선정**: "그래서 뭐?" 에 대한 답이 되는 문장
5. **첨부 bottom-box**: 해당 페이지 실무 적용 시 핵심 포인트
---
## 주의사항
1. 원본에 없는 내용 추가/추론 금지
2. 원본 문장을 선별/조합만 허용
3. 개조식 변환 필요한 문장 표시 (is_formal: true)
4. JSON만 출력 (설명 없이)