Skip to main content
CIS 3500
Sli.do PrairieLearn Panopto Gradescope Canvas Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

HW3: Separation of Concerns

Important

DUE DATE: Monday, March 24th, 2025 at 11:59 PM.

SUBMISSION: Read the entire homework, created four public repositories github-actions-quickstart, hugo-mock-landing-page-autodeployed, hugo-mock-landing-page-domain-name, and daily-pennsylvanian-basic-scraper in your GitHub account, following the instructions, and committed your work as described below. At the end, deploy your hugo-mock-landing-page repository to GitHub Pages. Since all your work is public, there is nothing to submit, except in case you need an extension or are submitting the option time & issue log, see below.

TIME ESTIMATE: We estimate this will take around 6-14 hours depending on your amount of past experience, this includes a lot of careful reading.

FEEDBACK LINK: At any moment in the homework, if you have non-urgent feedback to provide, don’t hesitate (if it is useful you will earn participation credit!): Homework Feedback Form. Note: This is to provide feedback for future improvements, and not to ask questions or clarifications about the homework. (For instance, if you something was confusing, and it took you a while to figure out, but you eventually figured it out, you might provide feedback that if it had been explained differently it would have been easier to understand.)

VOTE FOR THE LOGO: We are looking for a logo for the assignment, and we would like you to vote on the best one: Vote for the Course Logo.


Learning Objectives

In this assignment you will apply the principle of separation of concerns in four contexts: diagram design, slide creation, translation, and AI-assisted note generation. By the end, you should be able to:

  1. Distinguish between content and style in diagramming (using Penrose) ().
  2. Use Markdown and Reveal.js to separate slide content from presentation format.
  3. Isolate translation functionality via a dedicated API (DeepL) and understand why a specialized service can be beneficial (DeepL’s next-gen LLM outperforms ChatGPT-4, Google, and Microsoft for translation quality).
  4. Leverage an AI (OpenAI GPT-4.5) to generate content (speaker notes) automatically, separating core slide content from supplementary explanation.

Overview

You will complete four parts: (1) Diagramming with Penrose, (2) Creating slides in Markdown and using Slides.com/Reveal.js, (3) Building a translation tool for slides using DeepL, and (4) Automating speaker notes generation with GPT-4.5. Each part includes instructions, guidance, and reflection prompts.

Please follow the steps in each section and refer to provided resources. At the end, you will submit your recreated diagrams, slide deck files, translation tool code, generated notes, and a short reflection for each part.

Part 1: Diagramming with Penrose

Learning Objectives: Understand how separating a diagram’s what (content) from how it’s drawn (style) can improve reuse and clarity. Gain exposure to the Penrose system from CMU, which enforces a separation of domain, substance, and style in diagrams (GitHub - penrose/penrose: Create beautiful diagrams just by typing notation in plain text.).

Background: Penrose Diagramming System

Penrose is an open-source platform for creating beautiful diagrams by typing plain text notation (GitHub - penrose/penrose: Create beautiful diagrams just by typing notation in plain text.). It was developed at Carnegie Mellon University and introduces a novel separation of concerns in diagramming:

  • Domain: defines the vocabulary of a diagram type (e.g., shapes, relationships allowed). It captures the abstract concepts for a field or problem domain.
  • Substance: describes the specific content of a particular diagram (the actual items and relationships you want to visualize). Think of this as the “facts” or data of your diagram instance.
  • Style: prescribes how the diagram looks – mapping substance and domain elements to visual elements (layout, shapes, colors), similar to how CSS styles HTML content ().

In Penrose, you write three small programs (Domain, Substance, Style) that together produce a diagram. This clean separation means you can change the visual appearance without altering the underlying content, and vice versa (GitHub - penrose/penrose: Create beautiful diagrams just by typing notation in plain text.).

Instructions:

  1. Research Penrose: Start by reading about Penrose on its official site or GitHub. Focus on how it separates the diagram specification into the three parts above. Note how this is analogous to HTML/CSS separation of content and presentation ().
    Resource tip: The Penrose documentation and tutorials provide examples of Domain, Substance, and Style files. Reviewing a simple example (e.g., a set theory diagram) will help you understand the structure.

  2. Choose Three Diagrams: Identify three diagrams you have previously created (in class exercises or projects). These could be any kind of diagram (flowchart, UML class diagram, network graph, etc.) that you understand well. For each diagram:

    • Include a screenshot or photo of your original diagram for reference (this helps to compare with your Penrose recreation).
    • Analyze the diagram in terms of content vs. appearance: What are the core entities and relationships (content)? What aspects are purely stylistic (shapes, positioning, colors)?
  3. Recreate in Penrose: Attempt to recreate each of your three diagrams using Penrose. You have three approaches to choose from when using Penrose:

    • (a) Create a new diagram type: Define your own Domain file (types/relations for your diagram), write a Substance file for your diagram’s content, and craft a Style file for the visual design. This is suitable if your diagram is from a domain not already in Penrose’s examples. It requires more work but gives full control.
    • (b) Modify an existing Penrose domain/style: Penrose comes with some pre-built domains (e.g., set theory, geometry, etc.). If your diagram is similar to an existing one, you can start with that domain and/or style and modify it. For example, if it’s a graph or set diagram, reuse Penrose’s library and just plug in your Substance (data) and tweak the Style as needed.
    • (c) Use a pre-existing diagram from the Penrose library: Penrose’s example gallery might already have a diagram type close to what you need. You can use it directly and simply input your own content. This is the quickest route if a suitable example exists.

    Implementation notes: Penrose has an online editor (GitHub - penrose/penrose: Create beautiful diagrams just by typing notation in plain text.) where you can try writing Domain, Substance, and Style and immediately see the output. Alternatively, you can install Penrose locally. Start with simple elements of your diagram and incrementally add complexity. For each diagram:

    • Write the Domain (if creating new) to define object types and relationships.
    • Write the Substance file listing the specific objects and relationships from your original diagram (e.g., in a flowchart, the nodes and edges).
    • Write the Style file or adapt an existing one to style those objects (e.g., mapping a “Process” type to a rectangle shape, positioning connected nodes with some constraints, etc.).
  4. Generate Variations: For one of the diagram types you created, demonstrate the power of separation of concerns by generating two different diagrams of the same type with different data. In practice, this means:

    • Use the same Domain and Style files, but create a second Substance file with a different set of objects or relationships (a different “dataset” for the diagram).
    • Compile/render it in Penrose to produce a new diagram.
      Goal: The visual style remains consistent, but the content changes. Observe how easily you produced a new diagram by only changing the Substance (content) and reusing the Style.
  5. Capture Results: For each of the three diagrams, include:

    • The screenshot of the original diagram.
    • The Penrose-generated diagram (as an image or screenshot of the output).
    • Brief notes on how you implemented it (did you create new domain/style or reuse existing? What was challenging or interesting?).
  6. Reflect: Finally, write a short reflection (1-2 paragraphs) on your experience with Penrose:

    • Was Penrose the right tool for each of your diagrams? Explain why or why not.
    • How did the separation of substance and style help (or hinder) the process of making your diagrams?
    • If Penrose struggled to handle some aspect, identify an alternative diagramming tool or library that might suit your diagram. For instance, if you found Penrose too limited for UI wireframes, you might consider traditional tools or other programmatic diagram libraries. Research at least one alternative (e.g., GraphViz, Mermaid, draw.io) and note how it differs. This shows you’ve considered the fit of the tool to the task.

Guidance and Tips:

  • Penrose Learning Curve: Penrose requires thinking in a declarative way. Start simple (perhaps with one of your easier diagrams) to get familiar with writing Substance and Style. The Penrose tutorial “Hello, Penrose” is recommended if you’ve never used it (GitHub - penrose/penrose: Create beautiful diagrams just by typing notation in plain text.).
  • Use the Community: If you run into issues (e.g., how to enforce a certain positioning), Penrose’s documentation, GitHub issues, or community Discord can be very helpful. Often there are examples similar to what you need.
  • Time Management: Creating a new Domain/Style from scratch can be time-consuming. If you find yourself stuck, consider switching to approach (b) or (c) – use an example as a starting point. The goal is to learn about separation of concerns, not to perfectly replicate every visual detail.
  • What to Submit for Part 1: Your submission should include the three original diagram images, the three Penrose-generated diagram images, and a brief write-up for each (how you made it and the reflection answers). Also include your Penrose files (Domain/Substance/Style) as attachments or in a repository for review.

Part 2: Markdown-Based Slides & Reveal.js

Learning Objectives: Practice separating content from presentation in the context of slides. You will create slides in plain Markdown (content), then use Reveal.js (via Slides.com) to handle the presentation layer. This part reinforces modularity by writing slides once and being able to present them anywhere.

Background: Slides.com and Reveal.js

Reveal.js is a popular HTML presentation framework. It allows writing slides in HTML or Markdown, and comes with themes and transitions (the “rendering” aspect). Slides.com is an online service (built by the creator of Reveal.js) that provides a user-friendly editor and hosting for Reveal.js presentations. Essentially, Slides.com is Reveal.js with a GUI on top.

One powerful feature is that you can write your slides in Markdown (a simple plain-text format) and then convert them into a Reveal.js presentation. This keeps your focus on the content of the slides, while the styling and navigation are handled by Reveal. The separation here is:

  • Slide content: written in Markdown (easy to author, version control, and reuse).
  • Slide formatting and display: handled by Reveal.js (either through Slides.com or by using Reveal.js on your own).

Markdown slides typically separate slides with a delimiter (e.g., --- for new slide, ### for headings, etc.), and you can later apply themes or styles in Reveal without changing the Markdown source.

Instructions:

  1. Explore Slides.com: Visit Slides.com and familiarize yourself with its interface and features. You may create a free account. Particularly, find out how to import slides. Slides.com can import Reveal.js presentations. While it doesn’t directly take a raw Markdown file as import, one common workflow is to convert your Markdown into Reveal HTML first and then import that (From Markdown to reveal.js). (Slides.com’s editor also allows you to write in Markdown inside a slide by enabling Markdown mode.)

  2. Markdown Template – “Separation of Concerns in CS”: We have prepared a Markdown template for a short slide deck on Separation of Concerns in Computer Science. The topics covered in the template are:

    • Modularity – how breaking systems into modules is an example of separation of concerns.
    • Functions – as a way to encapsulate behavior (separating the what from how at a smaller scale).
    • Data vs. Presentation – e.g., HTML vs CSS, or data structures vs UI, etc.
    • Rendering – e.g., using libraries or frameworks to handle rendering logic separate from application logic.

    What you need to do: Create a slide deck in Markdown on this theme. You can use the provided outline above or modify it. Each bullet can be one or more slides. Ensure you use proper Markdown slide syntax:

    • Start each slide with a heading (e.g., # Slide Title for a top-level title or ## for sub-section slides).
    • Separate slides with a horizontal rule line --- (on a blank line by itself).
    • You can include sub-points as bullet lists, bold or italic text for emphasis, etc., just like writing a document. Keep slides concise (3-5 bullet points or a single graphic/diagram per slide, etc., as you see fit).

    You have two options for generating the content:

    • Write manually: Use your own words to fill in the details for each slide. This is recommended to ensure you engage with the material.
    • Use GPT-4.5 (optionally): If you want to experiment, you can prompt an AI (like GPT-4 or GPT-4.5 via ChatGPT) to help draft content for each slide. For instance, ask it to provide bullet points explaining what modularity means in separation of concerns. If you do this, be sure to review and edit the content – make it your own and ensure accuracy. Using AI is optional; the key is the quality of the slides, not who wrote the first draft.
  3. Convert Markdown to Slides: Once you have your slides written in a Markdown file (say, separation-concerns.md), you need to get it into Reveal.js format. There are a couple of ways:

    • The simplest is to use Slides.com’s import functionality. However, Slides.com import expects an HTML file (Reveal.js presentation) not raw Markdown (Import from reveal.js – Slides Help) (Import from reveal.js – Slides Help). To import your Markdown:
      1. Option 1 – Manual copy-paste: Create a new presentation on Slides.com, add a Markdown slide deck by copying the content of your .md file into a blank slide that is set to Markdown mode (there’s a toggle for Markdown in Slides.com editor). Slides.com will parse the --- separators into slides.
      2. Option 2 – Pandoc or Converter: Use a tool like Pandoc to convert your Markdown into an HTML slideshow. For example, Pandoc can take your separation-concerns.md and output a Reveal.js HTML file. One student example is a workflow where they wrote slides in Markdown, converted to Reveal HTML, then imported into Slides.com (From Markdown to reveal.js). This automatically creates the slides for you on Slides.com.
      3. Option 3 – Reveal directly: If you are comfortable, you can bypass Slides.com and use Reveal.js locally. Reveal.js can directly parse a Markdown file at runtime using its Markdown plugin (Markdown | reveal.js) (Markdown | reveal.js). This means you could serve an HTML that points to your .md file. (This is more involved, so using Slides.com or Pandoc is fine for this assignment.)

    Whichever method you choose, aim to end up with a working Reveal.js presentation of your slides. If using Slides.com, you can apply a theme or minor styling tweaks in the editor (e.g., choose a template or change the background color) – but do not manually add content in Slides.com that isn’t in your Markdown file. The goal is that your Markdown is the single source of truth for the content.

  4. Export to Reveal.js: If you used Slides.com, use the export feature to download your presentation as Reveal.js HTML (Slides.com allows exporting to a standalone HTML or sharing a link that is essentially a Reveal.js presentation). Ensure you have a local copy of the final Reveal.html file. If you worked locally with Reveal, you already have the HTML. Name this file clearly (e.g., HW3_YourName_SoC_slides.html).

  5. Test the Slides: Open the Reveal.js HTML and verify that:

    • All slides appear as intended (content is in place, separated by --- where appropriate).
    • The theme and formatting is okay (don’t worry if it’s not fancy – the point was writing in Markdown, not design).
    • You can navigate slides and see that each section (modularity, functions, etc.) is covered.
  6. Reflect (short): In a few sentences, comment on the experience of writing slides in Markdown. Did it feel easier or harder than using a GUI tool like PowerPoint or Google Slides? How does having the content in a plain text format benefit collaboration or version control? Also, note if you used AI to help and how you ensured the content was accurate.

Guidance and Tips:

  • Slides.com Markdown Quirk: Slides.com doesn’t natively import raw Markdown files as of now (Import from reveal.js – Slides Help) (Import from reveal.js – Slides Help). The Pandoc route or copy-paste into a Markdown-enabled slide are workarounds. Don’t spend too long trying to find a direct “upload .md” – use the suggested methods.
  • Reveal.js Features: You can include horizontal rules --- for new slides and even ---- (four dashes) for vertical slides (sub-slides) if you want to try that. Also, you can add notes in Markdown by starting a line with Note: (Reveal will treat the rest of that slide’s text as speaker notes). However, for now focus on content; we’ll handle translations and notes in the next parts.
  • Keep It Simple: The provided template topics are intentionally broad. You don’t need to write an essay on each – just a slide or two highlighting the key idea. For example, Modularity slide might list a definition and 3 benefits of modular design.
  • Submission for Part 2: Provide your Markdown file and the exported Reveal.js HTML. If you used Slides.com, you can also share the Slides.com link (in case we need to see the styling there), but the HTML is what we’ll use to verify content. Ensure the Markdown and HTML match in content.

Part 3: Translating Reveal.js Slides (DeepL API)

Learning Objectives: Build a small utility that separates the concern of translation from your content. You will create a script that takes a Reveal.js HTML file (like the one from Part 2) and prepares it for translation. This involves parsing the file, extracting text nodes, and (optionally) leveraging the DeepL API to translate or mark those text spots. The focus is on writing a maintainable piece of software that isolates the text extraction and replacement logic.

Background: Why DeepL and What to Build

If you want to translate your slides to another language, doing it manually or mixing translation logic into your main program could get messy. Instead, it’s cleaner to use a dedicated translation service via an API. We chose DeepL for this assignment because it’s a service specifically focused on translation, illustrating separation of concerns — it does one thing (language translation) particularly well (DeepL’s next-gen LLM outperforms ChatGPT-4, Google, and Microsoft for translation quality). (DeepL is known for its high-quality translations, often outperforming general-purpose translators in accuracy (DeepL’s next-gen LLM outperforms ChatGPT-4, Google, and Microsoft for translation quality).)

In this part, you will build a Minimal Viable Product (MVP) tool that processes a Reveal.js HTML file and produces a modified version ready for translation:

  • The tool should find all the human-readable text in the slides (the text content of elements in the HTML).
  • It will replace or annotate these text portions with placeholders, so that a translator (or translation API) can be applied easily.
  • We’ll later actually translate them, but first, we structure the problem.

Example: If your slide HTML has <h2>Separation of Concerns</h2>, the tool might output <h2>{1}</h2> (replacing the text with a placeholder {1}) and elsewhere maybe a list mapping {1} to the original text or leaving the original text in a comment. This way, you isolate what needs translation.

Instructions:

  1. Get Access to DeepL API: Sign up for a DeepL developer account if you haven’t already. DeepL offers a free API tier. Once logged in, find your API authentication key (in your account settings under “API Keys”) (API Key for DeepL’s API – DeepL Help Center | How Can We Help You?). This key is a string like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Keep it private.
    Note: You won’t necessarily need to use the key in this part (since we might not actually call the API yet), but you’ll need it in Part 3 or 4 if you choose to actually perform translations.

  2. Research DeepL API usage: Understand how to call the DeepL API to translate text. You can use their REST API directly (via HTTP POST requests to DeepL’s endpoint) or use an official client library. For example, DeepL provides an official Python library where you can do: translator = deepl.Translator("YOUR_API_KEY") then translator.translate_text("Hello", target_lang="ES") to get a translation (Introduction | DeepL API Documentation). Similarly, they have SDKs for other languages, or you can use a simple curl command with your key in the header to call the API. Our focus here is not the translation itself but preparing the text, but it’s good to know how you will plug in the API if you try it.

  3. Plan the MVP Tool: The tool will read an input file (the Reveal.js HTML) and produce an output file (the same HTML structure, but with text nodes replaced by placeholders or wrapped for translation). Key requirements:

    • Language support: We want to demonstrate this in multiple programming languages to emphasize that the logic is what matters, not the language. We suggest providing your solution in one language, but for learning, outline how it would be done in Python, Go, Rust, and JavaScript. (We’ve given hints in each below.)
    • Text extraction: Only human-readable text should be targeted. This means text within <h1>...</h1>, <p>...</p>, list items, etc., but not within <script> tags or HTML attributes. You might use an HTML parser library to traverse the DOM and find text nodes, or use simple string operations carefully.
    • Placeholder format: Decide on a format for placeholders. For example, {1}, {2}, or %%1%% – something that won’t appear in normal text. For simplicity, numeric placeholders in braces or double braces are fine.
    • Output preservation: The output should still be a valid Reveal.js HTML file, just with translated (or placeholder) text. Preserve all tags and structure.
  4. Implement the Tool in Different Languages (Examples): Below are brief guides for each of the four languages. Choose one language to fully implement, and for the others, you can just outline or pseudo-code how it would work (unless you’re feeling ambitious and want to implement multiple). We provide a simple approach for each:

    • Python: You can use the BeautifulSoup library to parse HTML easily. For example:

      from bs4 import BeautifulSoup
      import sys
      
      html = sys.stdin.read()  # or open a file
      soup = BeautifulSoup(html, "html.parser")
      
      counter = 1
      for text_node in soup.find_all(string=True):
          # Ignore purely whitespace or text in script/style tags
          if text_node.parent.name in ["script", "style"] or text_node.isspace():
              continue
          text_node.replace_with(f"{{{counter}}}")
          counter += 1
      
      sys.stdout.write(str(soup))
      

      This script reads HTML from standard input and writes the modified HTML to standard output, replacing each text node with {1}, {2}, etc. You could also store the mapping of placeholders to original text if needed (e.g., in a dictionary or separate file) to use when feeding to the translator. Running this as python translate_mvp.py < input.html > output.html would produce an output file with placeholders.

    • Go: You can use Go’s golang.org/x/net/html package to parse HTML as a tree. Then perform a traversal to replace text nodes. For example (conceptually):

      import (
          "golang.org/x/net/html"
          "os"
          "strconv"
      )
      func main() {
          doc, _ := html.Parse(os.Stdin)
          counter := 1
          var traverse func(*html.Node)
          traverse = func(n *html.Node) {
              if n.Type == html.TextNode {
                  content := n.Data
                  if content != "" && content != "\n" {
                      n.Data = "{" + strconv.Itoa(counter) + "}"
                      counter++
                  }
              }
              for c := n.FirstChild; c != nil; c = c.NextSibling {
                  traverse(c)
              }
          }
          traverse(doc)
          html.Render(os.Stdout, doc)
      }
      

      This Go program reads from stdin, traverses all nodes, and replaces each text node’s Data with a placeholder. It writes the new HTML to stdout. You can compile this to an executable. Usage: go run translate_mvp.go < input.html > output.html. (Note: We omit error handling for brevity here.)

    • Rust: In Rust, one could use the scraper crate (which uses html5ever under the hood) or kuchiki to parse and manipulate HTML. For example, using scraper:

      use scraper::Html;
      use scraper::node::Node;
      use std::io::Read;
      fn main() {
          let mut html = String::new();
          std::io::stdin().read_to_string(&mut html).unwrap();
          let mut document = Html::parse_document(&html);
          let mut counter = 1;
          for node in document.tree_mut().root().descendants() {
              if let Node::Text(text) = node.value() {
                  let original = text.text.to_string();
                  if original.trim().is_empty() { continue; }
                  // Replace text content with placeholder
                  text.text = format!("{{{}}}", counter).into();
                  counter += 1;
              }
          }
          println!("{}", document.root_element().html());
      }
      

      This reads the HTML, parses it, then iterates through all descendant nodes. If a node is text and not just whitespace, it replaces it with a placeholder. We then print the modified HTML. Run as cargo run --bin translate_mvp < input.html > output.html. (Make sure to include scraper = "0.13" in Cargo.toml dependencies. Alternatively, kuchiki crate has a similar API.)

    • JavaScript (Node.js): Using Node, you can leverage a library like Cheerio (jQuery-like HTML parser) to easily manipulate the DOM. Steps:

      1. Install cheerio: npm install cheerio.
      2. Example script translate_mvp.js:
        const fs = require('fs');
        const cheerio = require('cheerio');
        
        const inputFile = process.argv[2];
        const outputFile = process.argv[3];
        if (!inputFile || !outputFile) {
           console.error("Usage: node translate_mvp.js <input.html> <output.html>");
           process.exit(1);
        }
        
        const html = fs.readFileSync(inputFile, 'utf8');
        const $ = cheerio.load(html);
        let counter = 1;
        // Select all nodes and replace text nodes
        $('*').contents().each(function() {
          if (this.type === 'text') {
            const text = this.data;
            if (text.trim().length > 0) {
              this.data = `{${counter}}`;
              counter++;
            }
          }
        });
        fs.writeFileSync(outputFile, $.html());
        console.log(`Replaced ${counter-1} text items with placeholders.`);
        
        This script reads an input HTML file, loads it into Cheerio, then iterates over all content nodes. If a node is a text node with non-whitespace content, it replaces it with a placeholder. It writes out a new HTML file. You could also run this by piping: e.g., modify to read from stdin by using fs.readFileSync(0, 'utf8') for Node (file descriptor 0 is stdin) if you prefer piping.
  5. Test Your Tool: Run your tool on the Reveal.js HTML from Part 2. Examine the output:

    • The structure (tags, sections, etc.) should be identical to the input.
    • All the visible text should now be placeholders (or possibly you could have chosen to surround them with a tag or marker for translation). For example, slide titles, list items, paragraph text would be {1}, {2}, … in order.
    • If you kept a mapping of placeholder -> original text, verify it covers all text from the slides.
    • Optional: If you’re comfortable, actually call the DeepL API on the extracted text. You can take your mapping of {N}: "Original Text" and loop through it, sending each to DeepL’s translate endpoint (targeting a language of your choice, e.g., Spanish “ES” or Chinese “ZH”). DeepL can return translations which you could then substitute back into the placeholders in a copy of the HTML. (This is an extension if you want to see it in action – not required, as Part 4 focuses on a different API use.)
  6. Why DeepL? (Reflection): Write a short note on why we selected DeepL for this task. Consider that DeepL’s sole purpose is translation (unlike, say, Google which has a broader ecosystem). DeepL is often praised for its accuracy and context understanding in translations, due to being a specialized language translation platform (DeepL’s next-gen LLM outperforms ChatGPT-4, Google, and Microsoft for translation quality). How does this relate to separation of concerns? (Hint: Think of how using a dedicated service means you, as a developer, don’t worry about how translation works internally – that concern is handled by DeepL. You only worry about when/where to invoke it and handling results.)

    Also, list one or two alternative translation APIs or libraries you discovered (e.g., Google Translate API, Microsoft Azure Translator, Amazon Translate, or open-source translation models). In one sentence each, note a potential advantage or trade-off of those alternatives compared to DeepL (for instance, wider language support, free quotas, or integration with other services).

Guidance and Tips:

  • Understanding the HTML: If your slides contain formatting (like bold or italic within a sentence), an HTML parser will correctly handle those as separate nodes. Ensure your logic doesn’t accidentally join or skip text in such cases. Using a proper DOM traversal (as shown in examples) is safer than regex matching HTML, which can get tricky.
  • Command-line interface: We expect your tool to be runnable from the command line. Accepting an input filename and output filename as arguments (or using stdin/stdout) makes it flexible. This also makes it easier to chain with other tools (e.g., you could pipe the output into a translator or another script).
  • DeepL usage: If you attempt the actual translation, remember that the free API might have a limit on characters per month. You might want to test with a short sample of text first. Also, DeepL requires specifying target language code (like “DE” for German, “FR” for French, etc.). The translation API call returns JSON (if using curl/HTTP) or an object (if using their SDK). Ensure you do not accidentally commit your API key if you put your code in a repository.
  • Alternatives: While using DeepL via API is one approach, note that Reveal.js slides could also be translated using other means (even manual find-replace or using Google Slides with built-in translation). Our goal here is to practice extracting and modifying structured content via code.
  • What to Submit for Part 3: Provide your source code for the tool (in whichever language you implemented). If you wrote outlines for other languages, include those as comments or separate snippets for reference. Also include the output HTML file generated from your Part 2 slides (with placeholders or translated text). If you did use the API to fully translate it, you can include that translated version as well (optional). Include your brief reflection about DeepL and alternatives.

Part 4: AI-Generated Speaker Notes (OpenAI GPT-4.5)

Learning Objectives: Automate the creation of speaker notes using an AI language model. Here you’ll integrate with OpenAI’s GPT-4.5 API to generate presenter notes for each slide, demonstrating separation of content creation from content usage. You’ll also gain experience in prompting an AI to produce useful output and incorporating it into an existing structure.

Background: Speaker Notes and GPT-4.5

Speaker notes are the private notes a presenter uses to remember what to say for each slide. In Reveal.js (and Slides.com), you can add these by including an <aside class="notes">...</aside> in your slide HTML (Speaker View | reveal.js) (Speaker View | reveal.js). They don’t show up on the slides for the audience, but the presenter (or anyone with the HTML) can open the speaker view to read them.

Writing good speaker notes can be time-consuming. They should expand on the bullet points or graphics on a slide, providing a smooth narrative or explanation. This makes them a great candidate for AI assistance: given the content of a slide, a large language model can attempt to generate a helpful explanation or script.

OpenAI GPT-4.5: By the time of this course, we assume an API for GPT-4.5 is available (similar to how GPT-4 is accessed via OpenAI’s API). GPT-4.5 would be an advanced model capable of understanding context and generating coherent paragraphs. We’ll use it to create our speaker notes.

Instructions:

  1. Set Up OpenAI API Access: If you don’t already have one, create an account on OpenAI’s platform and obtain an API key. This is typically found in your account settings under API keys (a string starting with “sk-…”). You might need to request access to GPT-4 or GPT-4.5 specifically, as OpenAI often requires whitelisting for newer models. Ensure you have sufficient credit or quota for making several API calls (one per slide).

  2. Review Slide Content: Take your Reveal.js slides from Part 2 (the version with the original English text, not the placeholders from Part 3). You will programmatically iterate through each slide’s content to generate notes. It’s important to isolate what content to feed into the AI:

    • Usually, the slide’s textual content (titles, bullet points) is enough context for the model to generate notes. If a slide has an image or diagram with no text, you might need to describe it in the prompt manually (as the model can’t see the image).
    • You might skip any slides that are just section titles or transitions, as they might not need notes.
  3. Choose Implementation Approach: You can write the automation script in any language (Python is a common choice given the availability of an openai API library). The steps your program needs to do:

    • Parse the Reveal.js HTML to identify each slide (each <section> in the file represents a slide).
    • For each slide, extract the textual content (e.g., the text of headings, paragraphs, list items within that section).
    • Call the OpenAI GPT-4.5 API with a prompt built from this content, asking for speaker notes.
    • Receive the generated note text and insert it into the slide as an <aside class="notes"> ... </aside> element.
    • Output the modified Reveal.js HTML with notes included for each slide.

    Prompt design: You should instruct the model clearly. For example, you might send a prompt like:
    “You are an assistant that writes speaker notes for presentation slides. Given the slide content below, produce helpful speaker notes that explain or elaborate on the points, in a conversational tone. Slide content: [Bullet 1, Bullet 2, …]”
    You might include the actual text or a formatted list from the slide. You can experiment with level of detail (do you want a short paragraph? a longer explanation? bullet-form notes?). Remember, you can also tell the model to output in a specific format (e.g., a certain tone or length). This is where you might need to tweak and find an optimal prompt.

  4. Implement the Notes Generator: If using Python with OpenAI’s library, a pseudo-code would be:

    import openai
    from bs4 import BeautifulSoup
    
    openai.api_key = "YOUR_API_KEY"
    html = open("slides.html").read()
    soup = BeautifulSoup(html, "html.parser")
    
    for section in soup.find_all("section"):
        # Extract visible text content of this slide (excluding any existing notes)
        slide_text = []
        for node in section.find_all(["h1","h2","h3","p","li"]):  # adjust tags as needed
            if node.name == "aside": 
                continue  # skip if somehow notes already present
            text = node.get_text(strip=True)
            if text:
                slide_text.append(text)
        if not slide_text:
            continue  # skip slides with no content
        prompt = (f"You are a helpful assistant generating speaker notes for a slide.\n"
                  f"Slide content:\n" + "\n".join(slide_text) + "\n\n"
                  "Speaker notes:")
        response = openai.ChatCompletion.create(
            model="gpt-4-5",  # or the actual model name
            messages=[{"role": "user", "content": prompt}],
            max_tokens=150, # adjust for length of notes
        )
        notes_text = response['choices'][0]['message']['content'].strip()
        # Create or replace aside.notes in the section
        notes_tag = soup.new_tag("aside", **{"class": "notes"})
        notes_tag.string = notes_text
        section.append(notes_tag)
    # Save output
    with open("slides_with_notes.html", "w") as f:
        f.write(str(soup))
    

    This is illustrative – you may need to adjust the model name, parameters, and parsing details. Ensure you handle any API errors (e.g., rate limits or empty responses). You might also want to print progress as you generate notes for each slide.

  5. Run and Verify: Execute your notes generator script on your slide deck HTML. After it completes:

    • Open the new slides_with_notes.html in a browser (if you have Reveal’s speaker view enabled, or just inspect the HTML). Verify that each <section> now contains an <aside class="notes">...</aside> with text.
    • Read through the notes generated. Do they make sense for the slide? Are they accurate and useful? It’s possible the AI might hallucinate or add details not in the slide – if you find any glaring issues, you might tweak the prompt to be more specific (for example, “do not add information not present on the slide, just elaborate or give an example”).
    • If a note is too long or too short, adjust the max_tokens or instruction. You can regenerate for a slide by running just that one again with a refined prompt if needed.
  6. Optional – Output Format Customization: Our insertion simply put the raw text into the aside. You could also format the notes, e.g., always prefix with “Speaker Notes: ” or break into bullets if desired. This is not required, but feel free to experiment with prompt engineering. (For instance, you could prompt the AI: “Respond with 3-4 bullet points for speaker notes.” Then split the response by lines and insert as a list in HTML.)

  7. Reflection: Write a brief commentary on using AI for this task:

    • How well did GPT-4.5 generate speaker notes? Did it understand the slides correctly?
    • What prompt worked best? Include an example of a prompt you used and discuss why you wrote it that way.
    • Do you see this automation as useful in real life (would you use it for preparing presentations)? What are potential pitfalls? (e.g., accuracy, the risk of incorrect info, or the need to still review and edit AI-generated notes.)
    • If you know of alternative ways to generate such notes (for example, using a different model or even template-based approach), mention them. The focus is on understanding that we used a specialized service (an AI model from OpenAI) rather than writing note content ourselves – another nod to separation of concerns (content generation delegated to an AI).

Guidance and Tips:

  • API Costs and Limits: Generating notes for each slide means multiple API calls. If each call is, say, 100-200 tokens in the prompt and 100-150 tokens in the response, and you have ~10 slides, that’s a few thousand tokens – likely fine for a free trial or a few cents if billed. Just be mindful of your API usage. If you hit a rate limit, you might need to slow down calls (OpenAI might allow ~60 requests per minute, check their documentation).
  • Checking API Output: Sometimes the API might return text with formatting (like it might include its own bullet points or Markdown). You should handle or clean that if necessary. In our simple insertion, we treated it as plain text. If the model returns Markdown lists, you could convert them to HTML list tags, or adjust your prompt to request plain sentences.
  • Non-English Slides: If you actually translated your slides in Part 3 and want to generate notes in that target language, you could also do that by adjusting the prompt (and maybe using the target language in the prompt). GPT-4.5 is multilingual. But be careful mixing languages—focus on English first.
  • Security: Do not share your OpenAI API key in your submitted code. You can indicate where it should be inserted or use an environment variable. We will not run your code as-is; we’ll review it. If we test, we can insert our own keys.
  • What to Submit for Part 4: Your script or code for generating notes, the updated HTML file with notes, and the short reflection on the process. Ensure the notes file clearly shows the added <aside class="notes"> sections (you can format it or screenshot a couple of slides’ HTML if needed to illustrate).

General Instructions and Submission Guidelines

Experimentation Encouraged: This homework is open-ended in places (especially Parts 3 and 4). We encourage you to be creative and try things out. The grading will not be strictly about getting a “perfect” result, but rather about the effort, completeness, and learning demonstrated. If something doesn’t work out as expected (e.g., you couldn’t get Penrose to perfectly mimic a complex diagram, or the AI notes had some issues), explain what you tried and what you learned. That’s as valuable as a flawless execution.

Structured Format & Clarity: As this assignment itself emphasizes, maintaining a clear structure in your work is important. When you submit, organize your materials as follows:

  • A written report (can be a PDF or MarkDown or DOCX) that includes all the sections and reflections for Parts 1-4. Use headings and subheadings to mirror the assignment structure so graders can easily find each part. Include any code snippets or important excerpts in this document for reference.
  • A folder (or archive) containing:
    • Penrose files (.substance, .style, .domain) and images for Part 1.
    • The Markdown file and Reveal.html for Part 2.
    • Your code and example output for Part 3 (and translation output if applicable).
    • Your code and the slides with notes for Part 4.
    • If you used Jupyter notebooks or other formats, include those as well.
  • If any part of your work is hosted online (e.g., Slides.com deck, or a GitHub repo for code), provide the link in your report clearly.

Grading Criteria:

  • Part 1 (25%): Three diagrams recreated in Penrose, with explanation and reflection. We look for an attempt to separate content/style, and thoughtful commentary on Penrose’s suitability and alternatives.
  • Part 2 (20%): Markdown slide deck completeness and correctness. The content should cover the topics, and the process of converting to Reveal should be documented. Reflection on using Markdown for slides.
  • Part 3 (30%): The translation prep tool code quality and correctness. Does the output preserve structure and replace text appropriately? Clarity of how it could integrate with DeepL. Discussion of DeepL vs alternatives.
  • Part 4 (20%): Implementation of the notes generation and quality of notes. We’re not grading the writing prowess of GPT, but whether you successfully integrated the API and inserted notes. Reflection on prompt and results.
  • Overall (5%): Presentation, organization, and following instructions. This includes the readability of your write-up, proper citation of any sources or libraries used, and evidence of learning through the reflections.

Troubleshooting & Resources:

  • If you encounter issues with Penrose, check the Penrose GitHub discussions or open issues. Sometimes error messages can be cryptic – the community might have answers if you search.
  • For Slides.com/Reveal, the official Reveal.js documentation is a great resource (especially for Markdown features (Markdown | reveal.js) and speaker notes usage (Speaker View | reveal.js)). Slides.com’s help center also has tips (though we noted the Markdown import issue (Import from reveal.js – Slides Help)).
  • DeepL API documentation is available on the DeepL developer site. It includes examples in various languages and how to structure requests. Remember to use the correct endpoint (api-free.deepl.com for free accounts (First things to try with the DeepL API)). If your translations aren’t returning, print out the response or error; you might be hitting a limit or using an incorrect parameter.
  • OpenAI API documentation can be found on the OpenAI Developer site. Look for the section on “Chat Completions” as GPT-4.5 will likely use that interface (similar to GPT-4). There are code examples for calling the API in Python, Node, etc. If you have issues (e.g., invalid API key, model not available), double-check your credentials and access.
  • Don’t hesitate to ask for help: If you’re stuck, reach out on the course forum or office hours. But do so without sharing too much of your solution code (to avoid plagiarism issues). For instance, you can ask “Has anyone used DeepL API? I’m getting an authentication error even though I have a key” – that’s fine.

By completing this assignment, you’ll have practiced applying the separation of concerns principle in multiple domains and seen firsthand how using specialized tools or services (DSLs, Markdown, translation APIs, AI models) can simplify complex tasks by dividing responsibilities. Good luck, and have fun exploring these tools!