### Quick Start Installation
Source: https://github.com/aidotnet/opencowork/blob/main/README.md
Instructions to clone the repository, install dependencies, and run the development server.
```bash
git clone https://github.com/AIDotNet/OpenCowork.git
cd OpenCowork
npm install
npm run dev
```
--------------------------------
### Usage Example: Recommended Method (python-docx)
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/CHANGELOG.md
Bash commands to install dependencies and run the simple and full example scripts for adding comments using python-docx.
```bash
# Install dependencies
pip install python-docx
# Use the simple script
python scripts/add_comment_simple.py input.docx output.docx
# Use the full example
python scripts/examples/add_comments_pythondocx.py document.docx reviewed.docx
```
--------------------------------
### Headers/Footers & Page Setup
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/docx-js.md
Example of configuring document sections with custom page margins, orientation, page numbers, default headers, and footers.
```javascript
const doc = new Document({
sections: [
{
properties: {
page: {
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }, // 1440 = 1 inch
size: { orientation: PageOrientation.LANDSCAPE },
pageNumbers: { start: 1, formatType: 'decimal' } // "upperRoman", "lowerRoman", "upperLetter", "lowerLetter"
}
},
headers: {
default: new Header({
children: [
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [new TextRun('Header Text')]
})
]
})
},
footers: {
default: new Footer({
children: [
new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new TextRun('Page '),
new TextRun({ children: [PageNumber.CURRENT] }),
new TextRun(' of '),
new TextRun({ children: [PageNumber.TOTAL_PAGES] })
]
})
]
})
},
children: [
/* content */
]
}
]
})
```
--------------------------------
### Complete TOC Implementation Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
A comprehensive Python example demonstrating how to implement an auto-generated Table of Contents using ReportLab's `TableOfContents` and a custom `TocDocTemplate`.
```python
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Spacer
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
class TocDocTemplate(SimpleDocTemplate):
def __init__(self, *args, **kwargs):
SimpleDocTemplate.__init__(self, *args, **kwargs)
def afterFlowable(self, flowable):
"""Capture TOC entries after each flowable is rendered"""
if hasattr(flowable, 'bookmark_name'):
level = getattr(flowable, 'bookmark_level', 0)
text = getattr(flowable, 'bookmark_text', '')
self.notify('TOCEntry', (level, text, self.page))
# Create document
doc = TocDocTemplate("document.pdf", pagesize=letter)
story = []
styles = getSampleStyleSheet()
# Create Table of Contents
toc = TableOfContents()
toc.levelStyles = [
ParagraphStyle(name='TOCHeading1', fontSize=14, leftIndent=20,
fontName='Times New Roman'),
ParagraphStyle(name='TOCHeading2', fontSize=12, leftIndent=40,
fontName='Times New Roman'),
]
story.append(Paragraph("Table of Contents", styles['Title']))
story.append(Spacer(1, 0.2*inch))
story.append(toc)
story.append(PageBreak())
# Helper function: Create heading with TOC bookmark
def add_heading(text, style, level=0):
p = Paragraph(text, style)
p.bookmark_name = text
p.bookmark_level = level
p.bookmark_text = text
return p
# Chapter 1: Introduction
story.append(add_heading("Chapter 1: Introduction", styles['Heading1'], 0))
story.append(Paragraph("This is the introduction chapter with some example content.",
styles['Normal']))
story.append(Spacer(1, 0.2*inch))
story.append(add_heading("1.1 Background", styles['Heading2'], 1))
story.append(Paragraph("Background information goes here.", styles['Normal']))
# Chapter 2: Conclusion
story.append(add_heading("Chapter 2: Conclusion", styles['Heading1'], 0))
story.append(Paragraph("This concludes our document.", styles['Normal']))
story.append(Spacer(1, 0.2*inch))
story.append(add_heading("2.1 Summary", styles['Heading2'], 1))
story.append(Paragraph("Summary of the document.", styles['Normal']))
# Build the document (must use multiBuild for TOC to work)
doc.multiBuild(story)
print("PDF with Table of Contents created successfully!")
```
--------------------------------
### Complete Table Example with Styles
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Provides a comprehensive example of creating a table using ReportLab, including defining various ParagraphStyles for headers and cells with different alignments, and importing necessary components.
```python
from reportlab.platypus import Table, TableStyle, Paragraph, Image
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT, TA_JUSTIFY
# Define styles for table cells
header_style = ParagraphStyle(
name='TableHeader',
fontName='Times New Roman',
fontSize=11,
textColor=colors.white,
alignment=TA_CENTER
)
cell_style = ParagraphStyle(
name='TableCell',
fontName='Times New Roman',
fontSize=10,
textColor=colors.black,
alignment=TA_CENTER
)
cell_style_jus = ParagraphStyle(
name='TableCellLeft',
fontName='Times New Roman',
fontSize=10,
textColor=colors.black,
alignment=TA_JUSTIFY
)
cell_style_right = ParagraphStyle(
name='TableCellRight',
fontName='Times New Roman',
fontSize=10,
textColor=colors.black,
alignment=TA_RIGHT
)
```
--------------------------------
### Cover Page Style Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Python code example demonstrating cover page styling with specific font sizes, spacing, and alignment.
```python
story.append(Paragraph(
'RoutinAI Copilot (RoutinAI 协作助手) is built by routin.ai'
'My name is RoutinAI Analyst (洞察顾问)',
enbody_style
))
cnbody_style = ParagraphStyle(
name="CNBodyStyle",
fontName="SimHei", # Base font for Chinese
fontSize=10.5,
leading=18,
alignment=TA_JUSTIFY,
)
# Wrap Chinese segments with tag
story.append(Paragraph(
'本报告使用 GPT-4 '
'和 GLM 进行测试。',
cnbody_style
))
```
--------------------------------
### Font Rules Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example of registering fonts and applying them to paragraphs with mixed languages.
```python
from reportlab.lib.styles import ParagraphStyle
from reportlab.platypus import Paragraph
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont('SimHei', '/usr/share/fonts/truetype/chinese/SimHei.ttf'))
pdfmetrics.registerFont(TTFont('Times New Roman', '/usr/share/fonts/truetype/english/Times-New-Roman.ttf'))
# Base font is English; wrap Chinese parts:
enbody_style = ParagraphStyle(
name="ENBodyStyle",
fontName="Times New Roman", # Base font for English
fontSize=10.5,
leading=18,
alignment=TA_JUSTIFY,
)
# Wrap Chinese segments with tag
story.append(Paragraph(
'RoutinAI Copilot (RoutinAI 协作助手) is built by routin.ai'
'My name is RoutinAI Analyst (洞察顾问)',
'企业智能文档 services are powered by routin.ai.',
enbody_style
))
```
--------------------------------
### Simple tweet example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/post-to-x/SKILL.md
An example of posting a simple tweet.
```bash
# Simple tweet
python scripts/post_to_x.py "Hello X! 👋"
```
--------------------------------
### Creating a Table with Styled Data
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example demonstrating how to create a table with styled text, including bolding, superscripts, and subscripts, using the reportlab library.
```python
data = [
# Header row - bold text with Paragraph
[
Paragraph('Parameter', header_style),
Paragraph('Unit', header_style),
Paragraph('Value', header_style),
Paragraph('Note', header_style)
],
# Data rows - all text in Paragraph
[
Paragraph('Temperature', cell_style_jus),
Paragraph('°C', cell_style),
Paragraph('25.5', cell_style_jus),
Paragraph('Ambient', cell_style)
],
[
Paragraph('Pressure', cell_style_jus),
Paragraph('Pa', cell_style),
Paragraph('1.01 × 105', cell_style_jus), # Scientific notation
Paragraph('Standard', cell_style)
],
[
Paragraph('Density', cell_style_jus),
Paragraph('kg/m3', cell_style), # Unit with exponent
Paragraph('1.225', cell_style_jus),
Paragraph('Air at STP', cell_style)
],
[
Paragraph('H2O Content', cell_style_jus), # Subscript
Paragraph('%', cell_style),
Paragraph('45.2', cell_style_jus),
Paragraph('Relative humidity', cell_style)
]
]
# Create table
table = Table(data, colWidths=[120, 80, 100, 120])
table.setStyle(TableStyle([
# Header styling
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#1F4E79')),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
# Alternating row colors
('BACKGROUND', (0, 1), (-1, 1), colors.white),
('BACKGROUND', (0, 2), (-1, 2), colors.HexColor('#F5F5F5')),
('BACKGROUND', (0, 3), (-1, 3), colors.white),
('BACKGROUND', (0, 4), (-1, 4), colors.HexColor('#F5F5F5')),
# Grid and alignment
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 8),
('RIGHTPADDING', (0, 0), (-1, -1), 8),
('TOPPADDING', (0, 0), (-1, -1), 6),
('BOTTOMPADDING', (0, 0), (-1, -1), 6),
]))
```
--------------------------------
### Complete Python Example for Character Handling
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Demonstrates how to register fonts, define paragraph styles, and use Paragraph objects with tags for bold text, scientific notation with superscripts, and chemical formulas with subscripts.
```python
# --- Register fonts and font family ---
pdfmetrics.registerFont(TTFont('Times New Roman', '/usr/share/fonts/truetype/english/Times-New-Roman.ttf'))
# CRITICAL: Must call registerFontFamily() to enable and tags
registerFontFamily('Times New Roman', normal='Times New Roman', bold='Times New Roman')
# --- Define styles ---
body_style = ParagraphStyle(
name='BodyStyle',
fontName='Times New Roman',
fontSize=10,
textColor=colors.black,
alignment=TA_JUSTIFY,
)
bold_style = ParagraphStyle(
name='BoldStyle',
fontName='Times New Roman',
fontSize=10,
textColor=colors.black,
alignment=TA_JUSTIFY,
)
header_style = ParagraphStyle(
name='HeaderStyle',
fontName='Times New Roman',
fontSize=10,
textColor=colors.white,
alignment=TA_JUSTIFY,
)
# --- Body text examples ---
# Bold title
title = Paragraph('Scientific Formulas and Chemical Expressions', bold_style)
# Math formula with superscript and mathematical symbol ×
math_text = Paragraph(
'The Einstein mass-energy equivalence is expressed as E = mc2. '
'In applied physics, the gravitational force is F = 6.674 × 10-11 × '
'm1m2/r2, '
'and the quadratic formula solves a2 + b2 = c2.',
body_style,
)
# Chemical expressions with subscript
chem_text = Paragraph(
'The combustion of methane: CH4 + 2O2 '
'= CO2 + 2H2O. '
'Sulfuric acid (H2SO4) reacts with sodium hydroxide to produce '
'Na2SO4 and water.',
body_style,
)
```
--------------------------------
### Dependencies - LibreOffice installation
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/SKILL.md
Install LibreOffice using apt-get.
```bash
sudo apt-get install libreoffice
```
--------------------------------
### Multi-line tweet example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/post-to-x/SKILL.md
An example of posting a multi-line tweet with hashtags.
```bash
# Multi-line tweet
python scripts/post_to_x.py "🚀 New product launch!\n\n✨ Feature 1: xxx\n✨ Feature 2: yyy\n\n#ProductLaunch #NewFeature"
```
--------------------------------
### Basic PDF Creation Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
A simple Python script using reportlab to create a PDF file, add text, draw a line, and save the document.
```python
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
c = canvas.Canvas("hello.pdf", pagesize=letter)
width, height = letter
# Add text
c.drawString(100, height - 100, "Hello World!")
c.drawString(100, height - 120, "This is a PDF created with reportlab")
# Add a line
c.line(100, height - 140, 400, height - 140)
# Save
c.save()
```
--------------------------------
### Dependencies - pandoc installation
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/SKILL.md
Install pandoc using apt-get.
```bash
sudo apt-get install pandoc
```
--------------------------------
### ReportLab Paragraph Examples
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Demonstrates how to use ReportLab's Paragraph object with tags for superscripts, subscripts, bold text, and mathematical operators, along with setting up paragraph styles.
```python
from reportlab.platypus import Paragraph
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER
body_style = enbody_style = ParagraphStyle(
name="ENBodyStyle",
fontName="Times New Roman",
fontSize=10.5,
leading=18,
alignment=TA_JUSTIFY,
)
header_style = ParagraphStyle(
name='CoverTitle',
fontName='Times New Roman',
fontSize=42,
leading=50,
alignment=TA_CENTER,
spaceAfter=36
)
# Superscript: area unit
Paragraph('Total area: 500 m2', body_style)
# Subscript: chemical formula
Paragraph('The reaction produces CO2 and H2O', body_style)
# Scientific notation: large number with superscript
Paragraph('Speed of light: 3.0 × 108 m/s', body_style)
# Combined superscript and subscript
Paragraph('Ek = mv2/2', body_style)
# Bold heading
Paragraph('Chapter 1: Introduction', header_style)
# Math symbols in body text
Paragraph('When ∠ A = 90°, AB ⊥ AC and ΔABC ≅ ΔDEF', body_style)
```
--------------------------------
### Dependencies - docx installation
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/SKILL.md
Install the 'docx' package using bun.
```bash
bun add docx
```
--------------------------------
### Fetch a Web Page (Static) - Example 1
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/web-scraper/SKILL.md
Example of fetching an article from a given URL.
```bash
# Fetch an article
python fetch_page.py "https://example.com/article"
```
--------------------------------
### Fetch a Web Page (Static) - Example 3
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/web-scraper/SKILL.md
Example of fetching raw full-page Markdown with a character limit.
```bash
# Fetch raw full-page markdown, limit to 5000 chars
python fetch_page.py "https://example.com" --raw --max-length 5000
```
--------------------------------
### Example: Cold outreach
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/email-drafter/SKILL.md
Example of generating a cold outreach email and saving it to a file.
```bash
# Cold outreach
python scripts/email_draft.py --type cold-outreach --to "Sarah" --from "Alex" --subject "Partnership opportunity" --body "mutual benefit;our platform capabilities;propose a call" --tone professional --save outreach.txt
```
--------------------------------
### Dependencies - Poppler installation
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/SKILL.md
Install Poppler utilities (including pdftoppm) using apt-get.
```bash
sudo apt-get install poppler-utils
```
--------------------------------
### Palette and Application Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/xlsx/SKILL.md
Shows the color palette constraints and an example of applying styles to data headers and titles using openpyxl.
```python
# Palette
from openpyxl.styles import Alignment, Border, Font, Side, PatternFill,
# Base & Accents
background_white = "FFFFFF" # background
background_row_alt = "E9E9E9" # Alternating row fill
grey_header = "333333" # Section headers
border_grey = "E3DEDE" # Standard borders
blue_primary = "0B5CAD" # Primary Accent
# Application Example: Data Headers (NOT Titles)
header_fill = PatternFill(start_color=grey_header, end_color=grey_header, fill_type="solid")
header_font = Font(name='Times New Roman', color="FFFFFF", bold=True)
for cell in sheet['B3:E3'][0]:
cell.fill = header_fill
cell.font = header_font
# Example: Title style (NO shading, left-aligned)
title_font = Font(name='Times New Roman', size=18, bold=True, color="000000")
title_alignment = Alignment(horizontal='left', vertical='center')
sheet['B2'].font = title_font
sheet['B2'].alignment = title_alignment
# NO fill for titles
```
--------------------------------
### Install Dependencies (Lightweight)
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/web-scraper/SKILL.md
Installs dependencies for lightweight scraping of static pages, search, and link extraction.
```bash
pip install requests beautifulsoup4 readability-lxml html2text ddgs
```
--------------------------------
### Search the Web - Example 1
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/web-scraper/SKILL.md
Example of a general web search query.
```bash
# General search
python search_web.py "Python web scraping best practices 2025"
```
--------------------------------
### Example MCP Server Configuration
Source: https://github.com/aidotnet/opencowork/blob/main/docs/docs/capabilities/mcp-servers.mdx
An example JSON configuration for an MCP server, specifically for integrating with GitHub.
```json
{
"id": "github",
"name": "GitHub MCP",
"enabled": true,
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "..."
}
}
```
--------------------------------
### Fetch a Web Page (Static) - Example 2
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/web-scraper/SKILL.md
Example of extracting only table elements from a URL.
```bash
# Extract only tables
python fetch_page.py "https://example.com/data" --selector "table"
```
--------------------------------
### Setup and Initialization
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/docx-js.md
Imports necessary components from the 'docx' library and demonstrates basic document creation and saving for both Node.js and browser environments.
```javascript
const {
Document,
Packer,
Paragraph,
TextRun,
Table,
TableRow,
TableCell,
ImageRun,
Media,
Header,
Footer,
AlignmentType,
PageOrientation,
LevelFormat,
ExternalHyperlink,
InternalHyperlink,
TableOfContents,
HeadingLevel,
BorderStyle,
WidthType,
TabStopType,
TabStopPosition,
UnderlineType,
ShadingType,
VerticalAlign,
SymbolRun,
PageNumber,
FootnoteReferenceRun,
Footnote,
PageBreak
} = require('docx')
// Create & Save
const doc = new Document({
sections: [
{
children: [
/* content */
]
}
]
})
Packer.toBuffer(doc).then((buffer) => fs.writeFileSync('doc.docx', buffer)) // Node.js
Packer.toBlob(doc).then((blob) => {
/* download logic */
}) // Browser
```
--------------------------------
### Install Dependencies
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/excel-processor/SKILL.md
Installs the necessary openpyxl library for Excel processing. This is a one-time setup.
```bash
pip install openpyxl
```
--------------------------------
### Prerequisites
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/post-to-x/SKILL.md
Installs Playwright and downloads the Chromium browser.
```bash
pip install playwright
playwright install chromium
```
--------------------------------
### Docs Site Build Commands
Source: https://github.com/aidotnet/opencowork/blob/main/docs/docs/reference/building.mdx
Commands for installing dependencies, running the development server, and building the documentation site for production.
```bash
cd docs
npm install
npm run dev # Local development
npm run build # Production build (output: standalone)
```
--------------------------------
### PROHIBIT - Manual TOC Entry Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
An example of how NOT to create TOC entries, demonstrating manual creation of entries with hardcoded page numbers and leader dots.
```python
toc_entries = [("1. Title", "5"), ("2. Section", "10")]
for entry, page in toc_entries:
story.append(Paragraph(f"{entry} {'.'*50} {page}", style))
```
--------------------------------
### Basic List Syntax with Numbering Configuration
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/docx-js.md
Provides an example of setting up numbering configurations for bullet lists and numbered lists, and then creating paragraphs that utilize these configurations. It highlights the importance of using `LevelFormat.BULLET` and different references for independent lists.
```javascript
// Bullets - ALWAYS use the numbering config, NOT unicode symbols
// CRITICAL: Use LevelFormat.BULLET constant, NOT the string "bullet"
const doc = new Document({
numbering: {
config: [
{
reference: 'bullet-list',
levels: [
{
level: 0,
format: LevelFormat.BULLET,
text: '•',
alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
}
]
},
{
reference: 'first-numbered-list',
levels: [
{
level: 0,
format: LevelFormat.DECIMAL,
text: '%1.',
alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
}
]
},
{
reference: 'second-numbered-list', // Different reference = restarts at 1
levels: [
{
level: 0,
format: LevelFormat.DECIMAL,
text: '%1.',
alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
}
]
}
]
},
sections: [
{
children: [
// Bullet list items
new Paragraph({
numbering: { reference: 'bullet-list', level: 0 },
children: [new TextRun('First bullet point')]
}),
new Paragraph({
numbering: { reference: 'bullet-list', level: 0 },
children: [new TextRun('Second bullet point')]
}),
// Numbered list items
new Paragraph({
numbering: { reference: 'first-numbered-list', level: 0 },
children: [new TextRun('First numbered item')]
}),
new Paragraph({
numbering: { reference: 'first-numbered-list', level: 0 },
children: [new TextRun('Second numbered item')]
}),
// ⚠️ CRITICAL: Different reference = INDEPENDENT list that restarts at 1
// Same reference = CONTINUES previous numbering
new Paragraph({
numbering: { reference: 'second-numbered-list', level: 0 },
children: [new TextRun('Starts at 1 again (because different reference)')]
})
]
}
]
})
// ⚠️ CRITICAL: NEVER use unicode bullets - they create fake lists that don't work properly
// new TextRun("• Item") // WRONG
// new SymbolRun({ char: "2022" }) // WRONG
// ✅ ALWAYS use numbering config with LevelFormat.BULLET for real Word lists
```
--------------------------------
### Table Styling Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/docx-js.md
Demonstrates creating a centered table with specific cell styling, including vertical alignment, shading, and borders.
```javascript
new Table({
alignment: AlignmentType.CENTER,
rows: [
new TableRow({
children: [
new TableCell({
children: [
new Paragraph({
text: 'centered text',
alignment: AlignmentType.CENTER
})
],
verticalAlign: VerticalAlign.CENTER,
shading: { fill: colors.tableBg },
borders: cellBorders
})
]
})
]
})
```
--------------------------------
### Show help
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Display help information for the add_routinai_metadata.py script.
```bash
# Show help
python scripts/add_routinai_metadata.py --help
```
--------------------------------
### Set/Update Metadata (RoutinAI Branding)
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Command-line examples for adding RoutinAI branding metadata to PDFs.
```bash
# Add metadata to a single PDF (in-place)
python scripts/add_routinai_metadata.py document.pdf
# Add metadata with custom title
python scripts/add_routinai_metadata.py report.pdf -t "Q4 Financial Analysis"
# Batch process multiple PDFs
python scripts/add_routinai_metadata.py *.pdf
```
--------------------------------
### Read a PDF and Extract Text
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example of reading a PDF and extracting all its text content using pypdf.
```python
from pypdf import PdfReader, PdfWriter
# Read a PDF
reader = PdfReader("document.pdf")
print(f"Pages: {len(reader.pages)}")
# Extract text
text = ""
for page in reader.pages:
text += page.extract_text()
```
--------------------------------
### Wrap Chinese segments with tag
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example of appending paragraphs with Chinese segments wrapped in a tag for specific font rendering.
```python
story.append(Paragraph(
'RoutinAI Copilot (RoutinAI 协作助手) is built by routin.ai'
'My name is RoutinAI Analyst (洞察顾问)',
'企业智能文档 services are powered by routin.ai.'
enbody_style
))
```
--------------------------------
### Registering a Viewer
Source: https://github.com/aidotnet/opencowork/blob/main/docs/docs/capabilities/file-preview.mdx
Example of how to register a new viewer for specific file extensions.
```typescript
viewerRegistry.register({
type: 'markdown',
extensions: ['.md', '.mdx'],
component: MarkdownViewer
})
```
--------------------------------
### Table Cell Content Formatting (Prohibited Example)
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Illustrates a prohibited way of adding plain strings to table cells, which will not render formatting tags.
```python
# NEVER DO THIS - formatting will NOT work
data = [
['Header', 'Value'], # Bold won't render
['Temperature', '25°C'], # No style control
['Pressure', '1.01 × 105'], # Superscript won't work
]
```
--------------------------------
### Usage Example: Advanced Method (OOXML)
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/CHANGELOG.md
Bash commands demonstrating the workflow for the OOXML method, involving unpacking, adding comments, and repacking the document.
```bash
# Unpack, process, and pack
python ooxml/scripts/unpack.py document.docx unpacked
python scripts/add_comment.py unpacked 10 "批注内容"
python ooxml/scripts/pack.py unpacked output.docx
```
--------------------------------
### Chinese and English Text Formatting
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example of setting a base font for Chinese and wrapping English segments with a font tag within a Paragraph object.
```python
cnbody_style = ParagraphStyle(
name="CNBodyStyle",
fontName="SimHei", # Base font for Chinese
fontSize=10.5,
leading=18,
alignment=TA_JUSTIFY,
)
# Wrap Chinese segments with tag
story.append(Paragraph(
'本报告使用 GPT-4 '
'和 GLM 进行测试。',
cnbody_style
))
```
--------------------------------
### 更新文档
Source: https://github.com/aidotnet/opencowork/blob/main/docs/docs/reference/contributing.mdx
Commands to run the documentation development server.
```bash
cd docs
npm run dev
```
--------------------------------
### Base font is Chinese; wrap English parts
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example of setting a base Chinese font and wrapping English segments with a specific font tag.
```python
cnbody_style = ParagraphStyle(
name="CNBodyStyle",
fontName="SimHei", # Base font for Chinese
fontSize=10.5,
leading=18,
alignment=TA_JUSTIFY,
)
# Wrap Chinese segments with tag
story.append(Paragraph(
'本报告使用 GPT-4 '
'和 GLM 进行测试。',
cnbody_style
))
```
--------------------------------
### Create PDF
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Basic PDF creation step before adding metadata.
```python
doc.build(story)
print("PDF built")
```
--------------------------------
### Build Commands
Source: https://github.com/aidotnet/opencowork/blob/main/docs/docs/reference/building.mdx
Commands for type checking, building the production version, and packaging for different platforms.
```bash
# Type checking + build (recommended)
npm run build
# Build platform-specific installers
npm run build:win # Windows (.exe)
npm run build:mac # macOS (.dmg)
npm run build:linux # Linux (.AppImage / .deb)
```
--------------------------------
### Preventing Unwanted Line Breaks - Non-breaking Space
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example showing how to use a non-breaking space (U+00A0) to prevent English names from breaking at awkward positions.
```python
# PROHIBITED: "K.G. Palepu" may break after "K.G."
text = Paragraph("Professors (K.G. Palepu) proposed...",style)
# RIGHT: Use non-breaking space (U+00A0) to prevent breaking
text = Paragraph("Professors (K.G.\u00A0Palepu) proposed...",style)
```
--------------------------------
### Table Cell Content Formatting (Required Example)
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Demonstrates the mandatory way to wrap all text content in table cells with Paragraph() objects to ensure proper formatting.
```python
# ALWAYS DO THIS
data = [
[Paragraph('Header', header_style), Paragraph('Value', header_style)],
[Paragraph('Temperature', cell_style), Paragraph('25°C', cell_style)],
[Paragraph('Pressure', cell_style), Paragraph('1.01 × 105', cell_style)],
]
```
--------------------------------
### Preventing Unwanted Line Breaks - Word Wrap for Punctuation
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example demonstrating the use of 'wordWrap="CJK"' in ParagraphStyle to handle punctuation at the beginning of a line correctly.
```python
# RIGHT: Add wordWrap='CJK' for proper typography
styles.add(ParagraphStyle(
name='BodyStyle',
fontName='SimHei',
fontSize=10.5,
leading=18,
alignment=TA_LEFT,
wordWrap='CJK' # Prevents orphaned punctuation
))
```
--------------------------------
### Custom Styles Example
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/docx/docx-js.md
Example of defining custom styles for a Word document, including font size, bolding, font family, and paragraph spacing.
```javascript
styles.create({
paragraphStyles: [
{
id: 'Heading1',
name: 'Heading 1',
basedOn: 'Normal',
next: 'Normal',
quickFormat: true,
run: { size: 32, bold: true, font: 'SimSun' }, // SimSun 16pt for H1
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 }
},
{
id: 'Heading2',
name: 'Heading 2',
basedOn: 'Normal',
next: 'Normal',
quickFormat: true,
run: { size: 28, bold: true, font: 'SimHei' }, // SimHei 14pt for H2
paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 }
}
]
})
```
--------------------------------
### Development Commands
Source: https://github.com/aidotnet/opencowork/blob/main/docs/AGENTS.md
Common commands for development, building, and testing the project.
```bash
npm install
npm run dev
npm run types:check
npm run build
npm run start
docker compose up --build
```
--------------------------------
### Creating New PDFs with Metadata
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example using reportlab to create a new PDF document and set essential metadata fields like Title, Author, Creator, Subject, and Description.
```python
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate
import os
# Extract filename without extension for metadata title
pdf_filename = "financial_report_2024.pdf"
title_for_metadata = os.path.splitext(pdf_filename)[0] # "financial_report_2024"
doc = SimpleDocTemplate(
pdf_filename,
pagesize=letter,
title=title_for_metadata, # MUST: Match filename
author='RoutinAI', # MUST: Set to "RoutinAI"
creator='RoutinAI', # MUST: Set to "RoutinAI"
subject='Annual financial analysis and performance metrics' # SHOULD: Describe purpose
)
```
--------------------------------
### Modifying Existing PDFs with Metadata
Source: https://github.com/aidotnet/opencowork/blob/main/resources/skills/pdf/SKILL.md
Example using pypdf to read an existing PDF, add pages to a writer object, and set required metadata fields (Title, Author, Creator, Subject).
```python
from pypdf import PdfReader, PdfWriter
import os
pdf_filename = "output.pdf"
title_for_metadata = os.path.splitext(os.path.basename(pdf_filename))[0]
reader = PdfReader("input.pdf")
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
# Set metadata: Title, Author, Creator are REQUIRED
writer.add_metadata({
'/Title': title_for_metadata, # MUST: Match filename
'/Author': 'RoutinAI', # MUST: Set to "RoutinAI"
'/Subject': 'Document purpose description', # SHOULD: Describe purpose
'/Creator': 'RoutinAI' # MUST: Set to "RoutinAI"
})
with open(pdf_filename, "wb") as output:
writer.write(output)
```