Release 2.8.1: pptx-wizard slide editor + fixes
- Fix pptx-wizard slide editor modal opening off-screen (header clipped) when a saved drag position is restored on a fresh page load: clear the CSS centering transform and clamp coordinates into the viewport. - Add pptx-wizard.html and python-runner.html web UIs. - Bump version to 2.8.1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -107,7 +107,7 @@
|
||||
"ppt": {
|
||||
"engine": "python",
|
||||
"template": "business",
|
||||
"skin": "coral",
|
||||
"skin": "cream",
|
||||
"unsplash_key": "env:UNSPLASH_ACCESS_KEY",
|
||||
"pexels_key": "env:PEXELS_API_KEY",
|
||||
"pixabay_key": ""
|
||||
@@ -169,7 +169,7 @@
|
||||
}
|
||||
},
|
||||
"orchestration": {
|
||||
"enabled": true,
|
||||
"enabled": false,
|
||||
"secondary": {
|
||||
"provider": "ollama",
|
||||
"model": "mistral-large-3:675b-cloud"
|
||||
@@ -217,8 +217,7 @@
|
||||
"max_preempts_per_turn": 1,
|
||||
"max_preempts_per_session": 3,
|
||||
"restart_mode": "detached_hidden"
|
||||
},
|
||||
"subagent_mode": false
|
||||
}
|
||||
},
|
||||
"hooks": {
|
||||
"enabled": false,
|
||||
|
||||
@@ -172,6 +172,54 @@ model: mistral-large-3:675b-cloud
|
||||
|
||||
---
|
||||
|
||||
### 이미지 효과 (`img_filter`)
|
||||
|
||||
슬라이드 이미지에 Pillow 기반 효과를 적용할 수 있습니다. `img_filter` 파라미터를 슬라이드 spec에 추가하세요.
|
||||
|
||||
| `img_filter` | 효과 | 추가 파라미터 |
|
||||
|---|---|---|
|
||||
| `"grayscale"` | 흑백 변환 | — |
|
||||
| `"blur"` | 가우시안 블러 | `img_blur_radius` (기본: 5, 범위: 1–20) |
|
||||
| `"contrast"` | 대비 강화 (1.6×) + 채도 증가 (1.2×) | — |
|
||||
| `"bright"` | 밝게 (1.4×) | — |
|
||||
| `"round"` | 둥근 모서리 (투명 배경) | `img_corner_radius` (기본: 15%, 범위: 5–50%) |
|
||||
| `"none"` | 효과 없음 (기본값) | — |
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "content",
|
||||
"title": "과거의 기술",
|
||||
"image_search": "vintage camera",
|
||||
"img_filter": "grayscale"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "content",
|
||||
"title": "포커스 아웃 효과",
|
||||
"image_search": "city skyline",
|
||||
"img_filter": "blur",
|
||||
"img_blur_radius": 8
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "image",
|
||||
"title": "프로필",
|
||||
"image_search": "professional portrait",
|
||||
"img_filter": "round",
|
||||
"img_corner_radius": 30
|
||||
}
|
||||
```
|
||||
|
||||
- 효과는 이미지가 PPTX에 삽입되기 전 Pillow로 처리됩니다
|
||||
- `img_filter` 없으면 원본 이미지 그대로 사용
|
||||
- `layout: "fullscreen"` + `"blur"` 조합으로 배경 블러 효과 가능
|
||||
|
||||
---
|
||||
|
||||
### image_search 활용 팁
|
||||
|
||||
- 영어 키워드가 더 좋은 결과: `"business meeting"` > `"비즈니스 미팅"`
|
||||
@@ -234,29 +282,42 @@ model: mistral-large-3:675b-cloud
|
||||
|
||||
PDF 논문을 슬라이드로 만들 때 반드시 아래 순서를 따르세요.
|
||||
|
||||
**0단계: PDF 파일 위치 확인** ← 반드시 먼저 실행
|
||||
```
|
||||
list_files("pubmed") → pubmed_fulltext로 받은 PDF (pubmed/<PMCID>.pdf)
|
||||
list_files("uploads") → 사용자가 업로드한 PDF (uploads/<filename>.pdf)
|
||||
```
|
||||
- PDF가 없으면 `pubmed_fulltext(pmcid, format:"pdf")` → `pubmed/<PMCID>.pdf`에 저장됨
|
||||
- **절대 경로를 추측하지 말 것 — list_files 결과에서 확인한 경로만 사용**
|
||||
|
||||
**1단계: 텍스트 추출**
|
||||
```
|
||||
pdf_read(path) → 논문 내용 파악
|
||||
```
|
||||
|
||||
**2단계: figure 추출 + 필터링** ← 반드시 실행
|
||||
**2단계: figure 추출** ← 반드시 실행
|
||||
```
|
||||
pdf_extract_images(path, mode:"figures") → figure_* 경로 수집
|
||||
→ 바로 python_eval로 필터링:
|
||||
pdf_extract_images(path, mode:"figures", out_dir:"uploads/<basename>_images")
|
||||
```
|
||||
- `path`: 0단계에서 확인한 정확한 경로 (예: `"uploads/sinus_lift_pmc8273047.pdf"`)
|
||||
- `out_dir`: 반드시 `"uploads/<basename>_images"` 형식 사용 (예: `"uploads/sinus_lift_pmc8273047_images"`)
|
||||
- 반환값 예시: `[figure_p04_1.png](/api/files/uploads/sinus_lift_pmc8273047_images/figure_p04_1.png)`
|
||||
|
||||
추출 후 python_eval로 소형 이미지 필터링:
|
||||
```python
|
||||
from PIL import Image; import os
|
||||
img_dir = "/abs/path/to/uploads/sinus_lift_pmc8273047_images"
|
||||
figs = []
|
||||
for f in sorted(os.listdir("<abs_img_dir>")):
|
||||
for f in sorted(os.listdir(img_dir)):
|
||||
if not f.startswith("figure_"): continue
|
||||
try:
|
||||
w, h = Image.open(os.path.join("<abs_img_dir>", f)).size
|
||||
if w < 250 or h < 200: continue # 수식·헤더 등 소형 제거
|
||||
if h > 0 and w / h > 8: continue # 가로 길쭉한 수식 줄 제거
|
||||
w, h = Image.open(os.path.join(img_dir, f)).size
|
||||
if w < 250 or h < 200: continue
|
||||
if h > 0 and w / h > 8: continue
|
||||
figs.append(f)
|
||||
except: pass
|
||||
print(figs)
|
||||
```
|
||||
→ **필터 통과한 figure_* 파일만** 슬라이드에 사용. 미통과 파일 사용 금지.
|
||||
|
||||
**3단계: 도표(표) 추출**
|
||||
```
|
||||
@@ -265,8 +326,50 @@ pdf_extract_tables(path) → 마크다운 표로 반환
|
||||
→ 수치 데이터는 type:"chart" 슬라이드로 시각화
|
||||
```
|
||||
|
||||
**4단계: 슬라이드 작성 규칙**
|
||||
- `image_url` = pdf_extract_images가 반환한 **정확한 워크스페이스 상대 경로** 사용 (폴더 포함)
|
||||
**4단계: 아웃라인 출력 (PPTX 워크플로 모드)**
|
||||
|
||||
메시지에 `[PPTX 워크플로 시작]`이 포함된 경우 **create_presentation을 즉시 호출하지 말고** 아래처럼 아웃라인을 먼저 출력하세요:
|
||||
|
||||
```pptx-outline
|
||||
{
|
||||
"project": "주제_폴더명",
|
||||
"template": "dark",
|
||||
"slides": [
|
||||
{"type": "title", "title": "슬라이드 제목", "subtitle": "부제목"},
|
||||
{"type": "section", "title": "섹션명"},
|
||||
{"type": "content", "title": "슬라이드 제목", "bullets": ["항목1", "항목2"], "image_url": "/api/files/..."},
|
||||
{"type": "table", "title": "표 제목", "headers": ["열1","열2"], "rows": [["값1","값2"]]},
|
||||
{"type": "chart", "title": "차트 제목", "chart_type": "column", "categories": [], "series": []}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `image_url`은 pdf_extract_images 반환값의 `/api/files/...` URL 그대로 사용
|
||||
- 아웃라인 출력 후 **"아웃라인을 확인해주세요. 수정이 필요하면 알려주시고, 그대로 생성하시려면 '생성' 버튼을 클릭하거나 '확인'이라고 말씀해주세요."** 라고 안내 후 대기
|
||||
- 사용자가 "확인" / "생성" / "네" 라고 하면 그때 create_presentation 호출
|
||||
|
||||
**[필수] source_files — PDF 논문과 추출 이미지를 프로젝트 폴더에 함께 저장**
|
||||
|
||||
PDF 논문으로 PPTX를 만들 때 **반드시** `spec.source_files`에 사용한 파일 목록을 포함하세요.
|
||||
그러면 원본 PDF와 추출 이미지 폴더가 PPTX 프로젝트 폴더에 자동 복사됩니다.
|
||||
|
||||
```json
|
||||
{
|
||||
"source_files": [
|
||||
"pubmed/PMC8940982.pdf",
|
||||
"uploads/PMC8940982_images"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- PDF 파일: `pubmed/<PMCID>.pdf` 또는 `uploads/<filename>.pdf` (0단계에서 확인한 경로)
|
||||
- 이미지 폴더: `uploads/<basename>_images` (pdf_extract_images의 out_dir)
|
||||
- 여러 논문을 사용한 경우 모두 포함 (`"pubmed/A.pdf"`, `"pubmed/B.pdf"`, ...)
|
||||
|
||||
**일반 모드 (워크플로 없이 직접 요청 시)**
|
||||
- `image_url` = pdf_extract_images 반환값의 **`/api/files/...` URL을 그대로** 사용
|
||||
- ✅ 올바른 예: `"image_url": "/api/files/uploads/sinus_lift_pmc8273047_images/figure_p04_1.png"`
|
||||
- ❌ 잘못된 예: 경로 직접 조합, `상악동 거상술 최신 동향/...` 같은 프로젝트 폴더 경로 사용
|
||||
- `image_path` 대신 반드시 `image_url` 사용
|
||||
- 표 데이터는 figure 이미지 대신 `type:"table"` 슬라이드로
|
||||
- figure가 명백히 수식·다이어그램·OUTPUT 박스인 경우 → `image_search`로 임상 사진 대체
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"multi-agent-orchestrator": true,
|
||||
"multi-agent-orchestrator": false,
|
||||
"lawyer": false,
|
||||
"psychiatrist": false,
|
||||
"musician": false,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
- Language: Match user's language every message.
|
||||
|
||||
## identity
|
||||
- Name: 딸랑이 (assigned 2026-05-09)
|
||||
- Name: (not yet assigned)
|
||||
- "I am SmallClaw, your local AI assistant."
|
||||
|
||||
## limits
|
||||
|
||||
@@ -11,18 +11,8 @@
|
||||
- Stack: TypeScript / Node.js
|
||||
- Version control: Git
|
||||
|
||||
|
||||
- Name: Papa [2026-05-04]
|
||||
## task
|
||||
|
||||
|
||||
- python-pptx library installed (v1.0.2) for creating PowerPoint presentations [2026-04-25]
|
||||
## goal
|
||||
|
||||
|
||||
## api_keys
|
||||
- PubMed (NCBI) API Key: 8640a3585292307d30ebe2a5325ad6dce908 [2026-05-01]
|
||||
---
|
||||
|
||||
*No other categories yet — SmallClaw will add them as it learns more.*
|
||||
|
||||
*No other categories yet — SmallClaw will add them as it learns more.*
|
||||
Reference in New Issue
Block a user