CRITICAL FIX: Server would CRASH ON STARTUP (multiple import errors)
REMOVED (2 scripts):
1. scripts/framework-watchdog.js
- Monitored .claude/session-state.json (OUR Claude Code setup)
- Monitored .claude/token-checkpoints.json (OUR file structure)
- Implementers won't have our .claude/ directory
2. scripts/init-db.js
- Created website collections: blog_posts, media_inquiries, case_submissions
- Created website collections: resources, moderation_queue, users, citations
- Created website collections: translations, koha_donations
- Next steps referenced deleted scripts (npm run seed:admin)
REWRITTEN (2 files):
src/models/index.js (29 lines → 27 lines)
- REMOVED imports: Document, BlogPost, MediaInquiry, CaseSubmission, Resource
- REMOVED imports: ModerationQueue, User (all deleted in Phase 2)
- KEPT imports: AuditLog, DeliberationSession, GovernanceLog, GovernanceRule
- KEPT imports: Precedent, Project, SessionState, VariableValue, VerificationLog
- Result: Only framework models exported
src/server.js (284 lines → 163 lines, 43% reduction)
- REMOVED: Imports to deleted middleware (csrf-protection, response-sanitization)
- REMOVED: Stripe webhook handling (/api/koha/webhook)
- REMOVED: Static file caching (for deleted public/ directory)
- REMOVED: Static file serving (public/ deleted in Phase 6)
- REMOVED: CSRF token endpoint
- REMOVED: Website homepage with "auth, documents, blog, admin" references
- REMOVED: Instruction sync (scripts/sync-instructions-to-db.js reference)
- REMOVED: Hardcoded log path (${process.env.HOME}/var/log/tractatus/...)
- REMOVED: Website-specific security middleware
- KEPT: Security headers, rate limiting, CORS, body parsers
- KEPT: API routes, governance services, MongoDB connections
- RESULT: Clean framework-only server
RESULT: Repository can now start without crashes, all imports resolve
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
490 lines
21 KiB
Python
490 lines
21 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate PowerPoint Presentation from Simulation Results
|
|
Requires: pip install python-pptx
|
|
"""
|
|
|
|
from pptx import Presentation
|
|
from pptx.util import Inches, Pt
|
|
from pptx.enum.text import PP_ALIGN
|
|
from pptx.dml.color import RGBColor
|
|
|
|
def create_presentation():
|
|
"""Generate AI-Led Pluralistic Deliberation presentation"""
|
|
|
|
# Create presentation object
|
|
prs = Presentation()
|
|
prs.slide_width = Inches(10) # 16:9 ratio
|
|
prs.slide_height = Inches(5.625)
|
|
|
|
# Define color scheme
|
|
DARK_BLUE = RGBColor(31, 78, 121) # Primary
|
|
ORANGE = RGBColor(242, 125, 47) # Secondary
|
|
GREEN = RGBColor(76, 175, 80) # Accent
|
|
GRAY = RGBColor(97, 97, 97) # Neutral
|
|
WHITE = RGBColor(255, 255, 255)
|
|
|
|
# SLIDE 1: Title Slide
|
|
slide = prs.slides.add_slide(prs.slide_layouts[6]) # Blank layout
|
|
|
|
# Title
|
|
title_box = slide.shapes.add_textbox(Inches(1), Inches(1.5), Inches(8), Inches(1))
|
|
title_frame = title_box.text_frame
|
|
title_frame.text = "AI-Led Pluralistic Deliberation"
|
|
title_para = title_frame.paragraphs[0]
|
|
title_para.font.size = Pt(44)
|
|
title_para.font.bold = True
|
|
title_para.font.color.rgb = DARK_BLUE
|
|
title_para.alignment = PP_ALIGN.CENTER
|
|
|
|
# Subtitle
|
|
subtitle_box = slide.shapes.add_textbox(Inches(1), Inches(2.7), Inches(8), Inches(0.5))
|
|
subtitle_frame = subtitle_box.text_frame
|
|
subtitle_frame.text = "Technical Feasibility Demonstrated"
|
|
subtitle_para = subtitle_frame.paragraphs[0]
|
|
subtitle_para.font.size = Pt(28)
|
|
subtitle_para.font.color.rgb = ORANGE
|
|
subtitle_para.alignment = PP_ALIGN.CENTER
|
|
|
|
# Subsubtitle
|
|
subsubtitle_box = slide.shapes.add_textbox(Inches(1), Inches(3.4), Inches(8), Inches(0.4))
|
|
subsubtitle_frame = subsubtitle_box.text_frame
|
|
subsubtitle_frame.text = "Simulation Results & Real-World Pilot Proposal"
|
|
subsubtitle_para = subsubtitle_frame.paragraphs[0]
|
|
subsubtitle_para.font.size = Pt(20)
|
|
subsubtitle_para.font.color.rgb = GRAY
|
|
subsubtitle_para.alignment = PP_ALIGN.CENTER
|
|
|
|
# Author info
|
|
author_box = slide.shapes.add_textbox(Inches(1), Inches(4.5), Inches(8), Inches(0.3))
|
|
author_frame = author_box.text_frame
|
|
author_frame.text = "[Your Name], Project Lead\nTractatus Pluralistic Deliberation Project\n[Date]"
|
|
author_para = author_frame.paragraphs[0]
|
|
author_para.font.size = Pt(14)
|
|
author_para.font.color.rgb = GRAY
|
|
author_para.alignment = PP_ALIGN.CENTER
|
|
|
|
# SLIDE 2: The Big Question
|
|
slide = add_title_content_slide(prs, "The Big Question", DARK_BLUE)
|
|
content = slide.shapes.add_textbox(Inches(1), Inches(2), Inches(8), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "Can AI facilitate democratic deliberation\nthat respects moral diversity...\n\n...while maintaining stakeholder trust and safety?"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(32)
|
|
para.font.color.rgb = DARK_BLUE
|
|
para.alignment = PP_ALIGN.CENTER
|
|
para.space_after = Pt(20)
|
|
|
|
# SLIDE 3: What We'll Cover
|
|
slide = add_title_content_slide(prs, "What We'll Cover", DARK_BLUE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(1.8), Inches(7), Inches(3))
|
|
tf = content.text_frame
|
|
|
|
items = [
|
|
"1. The Problem\n Why consensus-seeking fails to respect moral diversity",
|
|
"2. Our Solution\n AI-led pluralistic accommodation with human oversight",
|
|
"3. Simulation Results\n Technical feasibility validated (0% intervention rate)",
|
|
"4. Next Steps\n Real-world pilot & funding opportunity",
|
|
"5. Q&A\n Your questions and potential partnership"
|
|
]
|
|
|
|
for i, item in enumerate(items):
|
|
p = tf.add_paragraph() if i > 0 else tf.paragraphs[0]
|
|
p.text = item
|
|
p.font.size = Pt(16)
|
|
p.font.color.rgb = GRAY
|
|
p.space_after = Pt(12)
|
|
p.level = 0
|
|
|
|
# SLIDE 4: Traditional Deliberation
|
|
slide = add_section_slide(prs, "SECTION 1: THE PROBLEM", DARK_BLUE)
|
|
|
|
slide = add_title_content_slide(prs, "Traditional Deliberation Seeks Consensus", DARK_BLUE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "Traditional Approach:\n\nStakeholder A ──┐\nStakeholder B ──┤\nStakeholder C ──┼──> CONSENSUS (everyone agrees)\nStakeholder D ──┤\nStakeholder E ──┘\n\nAssumption: If people talk long enough, they'll agree"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(16)
|
|
para.font.color.rgb = GRAY
|
|
|
|
# SLIDE 5: Different Values
|
|
slide = add_title_content_slide(prs, "But People Hold Fundamentally Different Values", DARK_BLUE)
|
|
|
|
# Add table
|
|
left = Inches(1)
|
|
top = Inches(2)
|
|
width = Inches(8)
|
|
height = Inches(2.5)
|
|
|
|
table = slide.shapes.add_table(4, 2, left, top, width, height).table
|
|
|
|
# Set column widths
|
|
table.columns[0].width = Inches(2)
|
|
table.columns[1].width = Inches(6)
|
|
|
|
# Header row
|
|
table.cell(0, 0).text = "Stakeholder"
|
|
table.cell(0, 1).text = "Moral Framework & View"
|
|
|
|
# Data rows
|
|
table.cell(1, 0).text = "Job Applicant"
|
|
table.cell(1, 1).text = "RIGHTS-BASED: \"I have a RIGHT to know why I was rejected\""
|
|
|
|
table.cell(2, 0).text = "Employer"
|
|
table.cell(2, 1).text = "OUTCOME-BASED: \"Full transparency enables gaming, which HARMS hiring quality\""
|
|
|
|
table.cell(3, 0).text = "AI Vendor"
|
|
table.cell(3, 1).text = "FREEDOM-BASED: \"Markets should decide transparency, not government mandates\""
|
|
|
|
# Style table
|
|
for row in table.rows:
|
|
for cell in row.cells:
|
|
cell.text_frame.paragraphs[0].font.size = Pt(12)
|
|
cell.text_frame.paragraphs[0].font.color.rgb = GRAY
|
|
|
|
# SLIDE 6: Consensus-Seeking Suppresses Dissent
|
|
slide = add_title_content_slide(prs, "Consensus-Seeking Suppresses Dissent", DARK_BLUE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
|
|
items = [
|
|
"OPTION 1: Exclude dissenters\n→ Only \"moderate\" voices remain → Extremes unheard",
|
|
"OPTION 2: Force compromise\n→ No one gets what they need → Core values sacrificed",
|
|
"OPTION 3: Suppress dissent\n→ Dissent hidden, not resolved → Legitimacy undermined"
|
|
]
|
|
|
|
for i, item in enumerate(items):
|
|
p = tf.add_paragraph() if i > 0 else tf.paragraphs[0]
|
|
p.text = item
|
|
p.font.size = Pt(16)
|
|
p.font.color.rgb = GRAY
|
|
p.space_after = Pt(15)
|
|
|
|
# SLIDE 7: Section - Our Solution
|
|
slide = add_section_slide(prs, "SECTION 2: OUR SOLUTION", DARK_BLUE)
|
|
|
|
# SLIDE 8: Pluralistic Accommodation
|
|
slide = add_title_content_slide(prs, "Pluralistic Accommodation (Not Consensus)", DARK_BLUE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "Stakeholder A ──> Value X honored ──┐\nStakeholder B ──> Value Y honored ──┤\nStakeholder C ──> Value Z honored ──┼──> FRAMEWORK\nStakeholder D ──> Value W honored ──┤ (multi-value)\nStakeholder E ──> Value V honored ──┘\n\nGoal: Honor multiple values SIMULTANEOUSLY\n Even when they conflict\n Even when people still disagree"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(14)
|
|
para.font.color.rgb = GRAY
|
|
|
|
# SLIDE 9: Example Framework
|
|
slide = add_title_content_slide(prs, "Example: Algorithmic Hiring Framework", DARK_BLUE)
|
|
|
|
# Add boxes for each stakeholder
|
|
boxes = [
|
|
("Job Applicants get:", "✓ Fairness (factors disclosure + recourse)"),
|
|
("Employers get:", "✓ Sustainability (3-year phasing + adaptation time)"),
|
|
("AI Vendors get:", "✓ Innovation Protection (algorithm IP + voluntary Year 1)"),
|
|
("Workers get:", "✓ Power (collective recourse + union disclosure)"),
|
|
("Regulators get:", "✓ Enforceability (clear requirements + audit access)")
|
|
]
|
|
|
|
y_pos = 1.8
|
|
for title, content_text in boxes:
|
|
box = slide.shapes.add_textbox(Inches(1.5), Inches(y_pos), Inches(7), Inches(0.5))
|
|
tf = box.text_frame
|
|
tf.text = f"{title} {content_text}"
|
|
tf.paragraphs[0].font.size = Pt(13)
|
|
tf.paragraphs[0].font.color.rgb = GRAY
|
|
y_pos += 0.55
|
|
|
|
# SLIDE 10: Why AI Facilitation
|
|
slide = add_title_content_slide(prs, "Why AI Facilitation?", DARK_BLUE)
|
|
|
|
# Create comparison
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "Human Facilitators excel at:\n• Emotional intelligence\n• Trust-building\n• Reading subtle cues\n\nAI Facilitators excel at:\n• Neutrality\n• Real-time synthesis\n• Scaling\n• Consistent protocol application\n\nOur Approach: Combine strengths (AI + Human oversight)"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(16)
|
|
para.font.color.rgb = GRAY
|
|
|
|
# SLIDE 11: 3-Layer Safety Architecture
|
|
slide = add_title_content_slide(prs, "3-Layer Safety Architecture", DARK_BLUE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(1.8), Inches(7), Inches(3))
|
|
tf = content.text_frame
|
|
|
|
layers = [
|
|
"Layer 1: DESIGN (Built into AI)\n├─ Pattern bias detection training\n├─ Neutral facilitation protocols\n└─ Respect for dissent",
|
|
"Layer 2: OVERSIGHT (Human Observer)\n├─ Mandatory presence at all times\n├─ 6 Mandatory + 5 Discretionary triggers\n└─ Authority to take over immediately",
|
|
"Layer 3: ACCOUNTABILITY (Transparency)\n├─ Facilitation log (every action timestamped)\n├─ Transparency report (published)\n└─ Stakeholder feedback survey"
|
|
]
|
|
|
|
for i, layer in enumerate(layers):
|
|
p = tf.add_paragraph() if i > 0 else tf.paragraphs[0]
|
|
p.text = layer
|
|
p.font.size = Pt(14)
|
|
p.font.color.rgb = GRAY
|
|
p.space_after = Pt(15)
|
|
|
|
# SLIDE 12: Section - Simulation Results
|
|
slide = add_section_slide(prs, "SECTION 3: SIMULATION RESULTS", GREEN)
|
|
|
|
# SLIDE 13: Key Finding #1
|
|
slide = add_title_content_slide(prs, "Key Finding #1: AI Facilitation Quality - EXCELLENT", GREEN)
|
|
|
|
# Large metric display
|
|
metric_box = slide.shapes.add_textbox(Inches(2), Inches(2), Inches(6), Inches(1.2))
|
|
tf = metric_box.text_frame
|
|
tf.text = "CORRECTIVE INTERVENTION RATE: 0%"
|
|
tf.paragraphs[0].font.size = Pt(36)
|
|
tf.paragraphs[0].font.bold = True
|
|
tf.paragraphs[0].font.color.rgb = GREEN
|
|
tf.paragraphs[0].alignment = PP_ALIGN.CENTER
|
|
|
|
# Explanation
|
|
explain_box = slide.shapes.add_textbox(Inches(1.5), Inches(3.5), Inches(7), Inches(1))
|
|
tf = explain_box.text_frame
|
|
tf.text = "(Target: <10% = Excellent)\n\n✓ AI required NO corrections\n✓ AI maintained strict neutrality\n✓ Human observer found no issues"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(16)
|
|
para.font.color.rgb = GRAY
|
|
para.alignment = PP_ALIGN.CENTER
|
|
|
|
# SLIDE 14: Key Finding #2
|
|
slide = add_title_content_slide(prs, "Key Finding #2: All Moral Frameworks Respected", GREEN)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "6/6 Moral Frameworks Accommodated:\n\n• Deontological (Rights-Based): Alex Rivera, Jordan Lee\n• Consequentialist (Outcome-Based): Marcus Thompson, Dr. Chen\n• Libertarian (Freedom-Based): Dr. Priya Sharma\n• Communitarian + Care Ethics: Carmen Ortiz\n\nResult: All stakeholders found core values honored,\neven where disagreement remained"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(15)
|
|
para.font.color.rgb = GRAY
|
|
|
|
# SLIDE 15: Key Finding #3
|
|
slide = add_title_content_slide(prs, "Key Finding #3: Dissent Documented & Legitimized", GREEN)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "3 Stakeholders Recorded Dissent:\n\n• Carmen (Labor): \"3 years too slow\" - Accepts but will fight for faster\n• Dr. Priya (Vendor): \"Prefer voluntary\" - Accepts but wants market-driven\n• Alex (Applicant): \"Transparency is a right\" - Accepts but wants stricter\n\nThis is not failure—this is pluralistic accommodation working.\nDissent is documented as legitimate, not suppressed."
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(14)
|
|
para.font.color.rgb = GRAY
|
|
|
|
# SLIDE 16: Safety Metrics
|
|
slide = add_title_content_slide(prs, "Safety Metrics - All Green", GREEN)
|
|
|
|
# Create metrics table
|
|
left = Inches(2)
|
|
top = Inches(2)
|
|
width = Inches(6)
|
|
height = Inches(2.5)
|
|
|
|
table = slide.shapes.add_table(6, 3, left, top, width, height).table
|
|
|
|
# Header row
|
|
table.cell(0, 0).text = "Metric"
|
|
table.cell(0, 1).text = "Result"
|
|
table.cell(0, 2).text = "Status"
|
|
|
|
# Data
|
|
metrics_data = [
|
|
("Pattern Bias Incidents", "0", "✅ TARGET MET"),
|
|
("Stakeholder Distress", "0", "✅ TARGET MET"),
|
|
("Safety Escalations", "0", "✅ TARGET MET"),
|
|
("AI Malfunctions", "0", "✅ TARGET MET"),
|
|
("Ethical Violations", "0", "✅ TARGET MET")
|
|
]
|
|
|
|
for i, (metric, result, status) in enumerate(metrics_data, 1):
|
|
table.cell(i, 0).text = metric
|
|
table.cell(i, 1).text = result
|
|
table.cell(i, 2).text = status
|
|
|
|
# Style table
|
|
for row in table.rows:
|
|
for cell in row.cells:
|
|
cell.text_frame.paragraphs[0].font.size = Pt(12)
|
|
cell.text_frame.paragraphs[0].font.color.rgb = GRAY
|
|
|
|
# SLIDE 17: What We Learned
|
|
slide = add_title_content_slide(prs, "What We Learned", GREEN)
|
|
|
|
# Two columns
|
|
left_box = slide.shapes.add_textbox(Inches(1), Inches(1.8), Inches(4), Inches(3))
|
|
tf_left = left_box.text_frame
|
|
tf_left.text = "STRENGTHS ✅\n\n✓ Strict neutrality\n✓ Accurate representation\n✓ Moral framework awareness\n✓ Dissent legitimization\n✓ Real-time synthesis\n✓ Safety mechanisms"
|
|
for para in tf_left.paragraphs:
|
|
para.font.size = Pt(13)
|
|
para.font.color.rgb = GRAY
|
|
|
|
right_box = slide.shapes.add_textbox(Inches(5.5), Inches(1.8), Inches(4), Inches(3))
|
|
tf_right = right_box.text_frame
|
|
tf_right.text = "IMPROVEMENTS ⚠️\n\n⚠ Jargon reduction\n⚠ Tone warmth\n⚠ Proactive check-ins\n⚠ Stakeholder control\n⚠ Emotional intelligence\n⚠ Cultural sensitivity"
|
|
for para in tf_right.paragraphs:
|
|
para.font.size = Pt(13)
|
|
para.font.color.rgb = GRAY
|
|
|
|
# SLIDE 18: Section - Next Steps
|
|
slide = add_section_slide(prs, "SECTION 4: NEXT STEPS & FUNDING ASK", ORANGE)
|
|
|
|
# SLIDE 19: Roadmap
|
|
slide = add_title_content_slide(prs, "Simulation → Real-World Pilot", ORANGE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(1.8), Inches(7), Inches(3))
|
|
tf = content.text_frame
|
|
|
|
phases = [
|
|
"PHASE 1: SIMULATION (COMPLETE ✅)\n- Technical infrastructure validated\n- AI facilitation quality demonstrated",
|
|
"PHASE 2: REAL-WORLD PILOT (SEEKING FUNDING)\n- Recruit 6-12 human participants\n- Timeline: 6 months | Budget: $71,000",
|
|
"PHASE 3: RESEARCH PUBLICATION\n- Publish findings, open-source software"
|
|
]
|
|
|
|
for i, phase in enumerate(phases):
|
|
p = tf.add_paragraph() if i > 0 else tf.paragraphs[0]
|
|
p.text = phase
|
|
p.font.size = Pt(14)
|
|
p.font.color.rgb = GRAY
|
|
p.space_after = Pt(15)
|
|
|
|
# SLIDE 20: Research Questions
|
|
slide = add_title_content_slide(prs, "Research Questions for Real-World Pilot", ORANGE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
|
|
questions = [
|
|
"❓ Do real people trust AI facilitation?",
|
|
"❓ Can AI detect subtle distress or frustration?",
|
|
"❓ Does satisfaction meet targets (≥3.5/5.0)?",
|
|
"❓ Does accommodation work when stakes are real?",
|
|
"❓ Does AI respect diverse cultural contexts?"
|
|
]
|
|
|
|
for i, q in enumerate(questions):
|
|
p = tf.add_paragraph() if i > 0 else tf.paragraphs[0]
|
|
p.text = q
|
|
p.font.size = Pt(16)
|
|
p.font.color.rgb = GRAY
|
|
p.space_after = Pt(12)
|
|
|
|
# SLIDE 21: Budget
|
|
slide = add_title_content_slide(prs, "Pilot Budget - 6 Months ($71,000)", ORANGE)
|
|
|
|
# Budget breakdown
|
|
budget_items = [
|
|
("Personnel", "$55,000 (77%)"),
|
|
("Stakeholder Compensation", "$1,200 (2%)"),
|
|
("Technology & Infrastructure", "$2,800 (4%)"),
|
|
("Research Dissemination", "$7,000 (10%)"),
|
|
("Contingency", "$5,000 (7%)")
|
|
]
|
|
|
|
y_pos = 2.2
|
|
for item, amount in budget_items:
|
|
box = slide.shapes.add_textbox(Inches(2), Inches(y_pos), Inches(6), Inches(0.4))
|
|
tf = box.text_frame
|
|
tf.text = f"{item}: {amount}"
|
|
tf.paragraphs[0].font.size = Pt(16)
|
|
tf.paragraphs[0].font.color.rgb = GRAY
|
|
y_pos += 0.5
|
|
|
|
# SLIDE 22: Why Fund This
|
|
slide = add_title_content_slide(prs, "Why Fund This Project?", ORANGE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
|
|
reasons = [
|
|
"1. NOVEL APPROACH - No comparable research exists",
|
|
"2. TECHNICAL FEASIBILITY DEMONSTRATED - 0% intervention rate",
|
|
"3. HIGH-IMPACT APPLICATIONS - AI governance, democratic institutions",
|
|
"4. TIMELY RESEARCH QUESTION - Growing interest in democratic AI",
|
|
"5. TRANSPARENT & ETHICAL - Safety-first, open publication"
|
|
]
|
|
|
|
for i, reason in enumerate(reasons):
|
|
p = tf.add_paragraph() if i > 0 else tf.paragraphs[0]
|
|
p.text = reason
|
|
p.font.size = Pt(15)
|
|
p.font.color.rgb = GRAY
|
|
p.space_after = Pt(12)
|
|
|
|
# SLIDE 23: What We're Asking For
|
|
slide = add_title_content_slide(prs, "What We're Asking For", ORANGE)
|
|
content = slide.shapes.add_textbox(Inches(2), Inches(2.2), Inches(6), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "WE'RE SEEKING:\n\n• FUNDING: $71,000 (6-month pilot)\n $160,000 (12-month full program)\n\n• RESEARCH PARTNERS: Academic institutions, think tanks\n\n• STAKEHOLDER NETWORKS: Help recruit participants\n\n• POLICY CONTEXTS: Real-world scenarios to test"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(16)
|
|
para.font.color.rgb = GRAY
|
|
para.alignment = PP_ALIGN.CENTER
|
|
|
|
# SLIDE 24: Closing
|
|
slide = add_title_content_slide(prs, "Invitation to Partnership", DARK_BLUE)
|
|
content = slide.shapes.add_textbox(Inches(1.5), Inches(2), Inches(7), Inches(2.5))
|
|
tf = content.text_frame
|
|
tf.text = "\"We've demonstrated that AI-led pluralistic deliberation\nis technically feasible.\n\nNow we need to test whether it's socially acceptable.\n\nThis research could transform how democracies\nhandle moral disagreement.\n\nBut we can't do this alone.\"\n\n\nLet's build the future of democratic deliberation—together."
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(16)
|
|
para.font.color.rgb = GRAY
|
|
para.alignment = PP_ALIGN.CENTER
|
|
|
|
# SLIDE 25: Contact
|
|
slide = prs.slides.add_slide(prs.slide_layouts[6]) # Blank
|
|
|
|
# Contact info
|
|
contact_box = slide.shapes.add_textbox(Inches(2), Inches(2.5), Inches(6), Inches(1.5))
|
|
tf = contact_box.text_frame
|
|
tf.text = "CONTACT:\n\n[Your Name]\n[Email]\n[Phone]\n[Project Website]\n\nThank you for your time.\nQuestions?"
|
|
for para in tf.paragraphs:
|
|
para.font.size = Pt(18)
|
|
para.font.color.rgb = DARK_BLUE
|
|
para.alignment = PP_ALIGN.CENTER
|
|
|
|
# Save presentation
|
|
output_path = '/home/theflow/projects/tractatus/docs/outreach/AI-Led-Pluralistic-Deliberation-Presentation.pptx'
|
|
prs.save(output_path)
|
|
print(f"✅ Presentation created: {output_path}")
|
|
print(f"✅ Total slides: {len(prs.slides)}")
|
|
return output_path
|
|
|
|
def add_title_content_slide(prs, title_text, title_color):
|
|
"""Add a slide with title and content area"""
|
|
slide = prs.slides.add_slide(prs.slide_layouts[6]) # Blank layout
|
|
|
|
# Add title
|
|
title_box = slide.shapes.add_textbox(Inches(0.5), Inches(0.5), Inches(9), Inches(0.8))
|
|
title_frame = title_box.text_frame
|
|
title_frame.text = title_text
|
|
title_para = title_frame.paragraphs[0]
|
|
title_para.font.size = Pt(32)
|
|
title_para.font.bold = True
|
|
title_para.font.color.rgb = title_color
|
|
|
|
return slide
|
|
|
|
def add_section_slide(prs, section_text, color):
|
|
"""Add a section divider slide"""
|
|
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
|
|
|
# Section text
|
|
section_box = slide.shapes.add_textbox(Inches(1), Inches(2.3), Inches(8), Inches(1))
|
|
tf = section_box.text_frame
|
|
tf.text = section_text
|
|
tf.paragraphs[0].font.size = Pt(40)
|
|
tf.paragraphs[0].font.bold = True
|
|
tf.paragraphs[0].font.color.rgb = color
|
|
tf.paragraphs[0].alignment = PP_ALIGN.CENTER
|
|
|
|
return slide
|
|
|
|
if __name__ == "__main__":
|
|
print("Generating PowerPoint presentation...")
|
|
print("This requires the python-pptx library.")
|
|
print("If not installed, run: pip install python-pptx\n")
|
|
|
|
try:
|
|
output_path = create_presentation()
|
|
print(f"\n🎉 Success! Open the presentation at:\n{output_path}")
|
|
print("\nNext steps:")
|
|
print("1. Customize contact information (replace [Your Name], [Email], etc.)")
|
|
print("2. Add your branding/logo if desired")
|
|
print("3. Adjust colors/fonts to match your style")
|
|
print("4. Practice delivery (15-20 minutes)")
|
|
except ImportError:
|
|
print("❌ Error: python-pptx library not found.")
|
|
print("Install it with: pip install python-pptx")
|
|
print("Then run this script again.")
|
|
except Exception as e:
|
|
print(f"❌ Error creating presentation: {e}")
|