Atlas / Skills / opensensenova / Ppt Analysis

Ppt AnalysisSAFE

skills/opensensenova/ppt-analysis

Modular SenseNova skills for building AI-powered office assistants and productivity workflows

Verdict
SAFE
Grade
B
Trust score
89 /100
Version
—
Hosts
—
License
MIT
Stars
5,744
01

Overview

Modular SenseNova skills for building AI-powered office assistants and productivity workflows

Read from source at commit 657860e4d389OBSERVED · 2026-10-07
02

What it tells the agent

The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.

---
name: ppt-analysis
description: "PPT (.pptx/.ppt) 全量解析。覆盖:所有 slide 文本/表格/图表提取、嵌入图片 caption、纯图片 slide 渲染识别、数据标签提取。"
---

# PPT Analysis — .pptx / .ppt

## Environment

```python
from pptx import Presentation
from pptx.util import Inches
import os, subprocess, json

# python-pptx is available
# For .ppt (old binary format): convert via libreoffice
def load_pptx(path):
    if path.lower().endswith('.ppt'):
        import subprocess
        out_dir = os.path.dirname(path)
        subprocess.run(
            ['libreoffice', '--headless', '--convert-to', 'pptx', '--outdir', out_dir, path],
            check=True, capture_output=True
        )
        path = path.rsplit('.', 1)[0] + '.pptx'
    return Presentation(path), path
```

---

## Core Method 1: Full Text Extraction (ALL slides)

```python
def extract_all_slides_text(pptx_path):
    """
    Extract text from every slide: text frames, tables, chart titles.
    For slides with no extractable text, flag them for image captioning.
    """
    prs, _ = load_pptx(pptx_path)
    slides_data = []

    for slide_num, slide in enumerate(prs.slides, start=1):
        slide_texts = []
        has_text = False

        for shape in slide.shapes:
            # Text frame (most common)
            if shape.has_text_frame:
                for para in shape.text_frame.paragraphs:
                    text = para.text.strip()
                    if text:
                        slide_texts.append(text)
                        has_text = True

            # Table
            if shape.has_table:
                tbl = shape.table
                for row in tbl.rows:
                    row_text = '\t'.join(cell.text.strip() for cell in row.cells)
                    if row_text.strip():
                        slide_texts.append(row_text)
                        has_text = True

            # Chart title
            if shape.shape_type == 3:  # MSO_SHAPE_TYPE.CHART
                try:
                    if shape.chart.has_title:
                        title = shape.chart.chart_title.text_frame.text
                        slide_texts.append(f"[Chart: {title}]")
                        has_text = True
                except Exception:
                    pass

        slides_data.append({
            'slide': slide_num,
            'text': '\n'.join(slide_texts),
            'has_text': has_text,
            'needs_caption': not has_text  # flag image-only slides
        })

    print(f"Total slides: {len(slides_data)}")
    image_only = sum(1 for s in slides_data if s['needs_caption'])
    print(f"Slides with text: {len(slides_data) - image_only}, image-only: {image_only}")
    return slides_data
```

---

## Core Method 2: Table Extraction (Structured)

```python
import pandas as pd

def extract_pptx_tables(pptx_path):
    """Extract all tables from all slides as DataFrames."""
    prs, _ = load_pptx(pptx_path)
    all_tables = []

    for slide_num, slide in enumerate(prs.slides, start=1):
        for shape in slide.shapes:
            if not shape.has_table:
                continue
            tbl = shape.table
            rows = []
            for row in tbl.rows:
                rows.append([cell.text.strip() for cell in row.cells])

            if not rows:
                continue

            # Use first row as header
            try:
                df = pd.DataFrame(rows[1:], columns=rows[0])
            except Exception:
                df = pd.DataFrame(rows)

            all_tables.append({'slide': slide_num, 'df': df})
            print(f"  Slide {slide_num}: table {df.shape[0]}r × {df.shape[1]}c")
            print(df.head(3).to_string())

    return all_tables
```

---

## Core Method 3: Chart Data Extraction

`python-pptx` can read Chart data when it's stored as embedded Excel data.
If that fails, fall back to captioning the slide image.

```python
def extract_chart_data(pptx_path):
    """
    Extract data series from Chart shapes.
    Returns list of {slide, chart_title, series_name, categories, values}.
    """
    prs, _ = load_pptx(pptx_path)
    charts = []

    for slide_num, slide in enumerate(prs.slides, start=1):
        for shape in slide.shapes:
            if shape.shape_type != 3:  # not a chart
                continue
            try:
                chart = shape.chart
                title = chart.chart_title.text_frame.text if chart.has_title else f"Chart_S{slide_num}"

                for plot in chart.plots:
                    for series in plot.series:
                        try:
                            categories = [str(pt.label) for pt in series.data_labels] if hasattr(series, 'data_labels') else []
                            values = [pt.value for pt in series.values] if hasattr(series, 'values') else []
                            # Alternative: use xChart data
                            if not values:
                                values = list(series.values)
                        except Exception as e:
                            values = []
                            categories = []

                        charts.append({
                            'slide': slide_num,
                            'chart_title': title,
                            'series': getattr(series, 'name', ''),
                            'categories': categories,
                            'values': values
                        })
            except Exception as e:
                print(f"  Slide {slide_num}: chart extraction failed ({e}) — will use caption")

    return charts
```

---

## Core Method 4: Render Image-Only Slides → Caption

When a slide has no extractable text (pure image/screenshot slides):

```python
import fitz  # PyMuPDF can also render PPTX via LibreOffice conversion

CAPTION = "/path/to/skills/sn-da-image-caption/scripts/caption.py"

def caption_image_slides(pptx_path, slides_data, prompt=None):
    """
    For slides flagged as 'needs_caption', render to PNG and caption.
    Uses LibreOffice
03

Trust audit

SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeNA
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
none-observed
Shell
none-observed
Dependencies
pinned
Secrets in source
none-found

Findings (0)

No findings outside the package's declared scope.

Gates applied: no_behavioural_pass.

Audited 2026-10-07 · audit v0.4.1 · source sha 657860e4d389full audit observations/trust-audit/skill/opensensenova__ppt-analysis.json · Report an issue / request a re-scan
04

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-10-07657860e4d389SAFEB89first audit
05

Questions

What does the Ppt Analysis skill do?

Modular SenseNova skills for building AI-powered office assistants and productivity workflows

Is Ppt Analysis safe to install?

The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.

What can Ppt Analysis access on my machine?

The audit observed no filesystem, network or shell use at all in its source.

How current is this page?

The grade is for one exact copy of the source (657860e4d389), read on 2026-10-07. The repository is watched, and a new audit runs when it changes — this is the first audit.

Advertisement