DH Benelux 2026 ‐ Workshop - C2DH/template_repo_JDH GitHub Wiki
DH Benelux 2026 - Journal of Digital History Workshop
Agenda
| Activity | |
|---|---|
| 14:00 - 14:20 | Word of editorial manager |
| 14:20 - 15:15 | Setup the writing environment |
| 15:15 - 15:30 | Coffee break ☕️ |
| 15:30 - 16:30 | Let's choose a track, write, commit, push and preview |
| 16:30 - 17:00 | Notebook presentation / Wrap up |
Word of our editorial manager
Part 1: Environment Setup (14:20 – 15:30)
What you need to do:
- Choose your setup approach
| Approach | Best For | How It Works |
|---|---|---|
| Local installation | Advanced users | 1. Use your own Python/Conda setup 2. Clone the repository template 3. Launch from a terminal in the directory the Jupyter Lab application with jupyter lab4. Install jupyterlab-citation-manager |
| Jupyter Stack with Docker | Beginners | 1. Docker container with pre-installed tools2. Clone the container with Jupyter Stack3. Mount the container with docker compose up in Terminal4. Insert your Zotero API key in the popping window3. Run article.ipynb from the Work directory |
💡 If at some point you are lost during the workshop, do not forget to ask for help 😃
You can also check our guidelines and follow the video tutorial :
0. Install tools
⚠️ Optional: if you choose local installation then you can install Python. If you choose the Docker installation, then Python is already integrated inside the container 😉
How to install Python ?
- You can use different tools to have Python on your machine. Choose one of them :
- Conda can help for managing Python environments
- Python official website
- Uv a very fast installer (dedicated page to work with Jupyter)
What you need to do:
- Install Docker Desktop
- Install Github Desktop
1. Zotero API Key
What you need to do:
- Install the Zotero app on your computer : https://www.zotero.org/
- Generate your API key by visiting https://www.zotero.org/settings/security
💡 Hint: The API key is like a password for your Zotero library—it allows your code to access your references programmatically.
2. Clone the Repository Template
What you need to do:
- Clone the template repository to your computer using Git by using the green
Codebutton
- Familiarize yourself with the README formatting (written in Markdown)
- You can even create your own markdown file in your new Github repository
- A good resource to be familiar with the Markdown syntax
💡 Hint: Markdown is a simple formatting language. Use # for headings, **text** for bold, *text* for italic, and - for bullet points. We can also create Table in Markdown 😉
- Learn about Git basics: commits and push operations
- Launch a Binder environment using the button in the README
💡 Hint: The Binder button lets you run code in the cloud without installing anything locally!
3. Jupyter Lab Setup
Reminder : if you do not use our Docker, to run Jupyter Lab you need to use this command line jupyter lab
💡 Hint: Not sure which to choose? If you're new to coding environments, go with the Docker option. It handles installation headaches for you!
- Explore the Tag Palette in Jupyter Lab (click on the 2 wheels icon in right-top corner)
4. JDH notebook viewer
If you want to see how your Jupyter Notebook is rendering on Journal Of Digital History website, then you can use our Preview Notebook page.
Part 2: Choose Your Track (15:30 onwards)
Track 1: Oral History
Example 1: Working with Dialogue
📖 Article used as a reference:
Venken, M. and Jaschik, J. (2024) “Chronoferencing the Italian-Slovenian Borderlands. Citizen Science, Oral History and Output Criticism,” Journal of Digital History, 3(2). Available at: https://doi.org/10.1515/JDH-2023-0020?locatt=label:JDHFULL.
You'll analyze transcribed conversations. Here's an example:
| Speaker | Text |
|---|---|
| Termine | "And euhm, euhm, what can I say? Hm. Euhm. So, hm. But we have to do 20 minutes each?" |
| Aura | "Oehm, yeah, but I have also only 15 minutes." |
| Termine | "Yeah, you were twelve. Ok, I have to talk at least two minutes." |
| Aura | "Okay." |
What to do:
- Tag dialogues using:
dialog-identifier-*(replaceidentifierwith a unique identifier likedialogue-dhbenelux-*) - See JDH styling guidelines for the list of all tags that we use
💡 Hint: These tags help organize and reference specific documents like conversation in your article.
Step 2: Insert Audio Files
Version 1: Basic Audio Playback
Download audio from the Github repository
Use this Python code:
import IPython.display as ipd
ipd.Audio('media/Audio_Fragments/AT_AUDIOCUT_1.m4v')
Tag: Add sound-identifier-* to your audio elements (same principle as for the dialog-identifier-* seen before ☝️).
💡 Hint: This simple approach is perfect for letting readers listen to your audio clips directly in the notebook.
Version 2: Visualize Audio Waveforms
📖 Article used as a reference:
Malmstedt, J. (2024) “Navigating the Radio Archive: Segmentation and analysis of Swedish broadcasting data,” Journal of Digital History, 3(1). Available at: https://doi.org/10.1515/JDH-2023-0006?locatt=label:JDHFULL.
import matplotlib
matplotlib.use('Agg')
import requests
import io
import librosa
import librosa.display
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import Image, display, Audio
def plot_waveform_and_play_audio(mp3_url):
response = requests.get(mp3_url, allow_redirects=True)
response.raise_for_status()
y, sr = librosa.load(io.BytesIO(response.content), sr=None, mono=True)
plt.figure(figsize=(12, 4))
librosa.display.waveshow(y, sr=sr, alpha=0.5)
plt.title('Waveform of {}'.format(mp3_url))
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.savefig('waveform.png', bbox_inches='tight')
plt.close()
display(Image(filename='waveform.png'))
display(Audio(data=y, rate=sr))
plot_waveform_and_play_audio('https://github.com/jdh-observer/6EWgjJtoiW6R/raw/main/media/Testradio.mp3')
💡 Hint: This visualizes the sound as a waveform—great for highlighting important moments or analyzing speech patterns!
Version 3: Transcribe Audio with AI
📖 Article used as a reference:
Hutchinson, D. (2024) “Mapping the Latent Past: Assessing Large Language Models as Digital Tools through Source Criticism,” Journal of Digital History, 3(1). Available at: https://doi.org/10.1515/JDH-2023-0018?locatt=label:JDHFULL.
- a section with LLM transcription
- on JDH
- Github Repository
# Code for transcribing oral history segment with Whisper API
import requests
from openai import OpenAI
import time
from rich.console import Console
from rich.text import Text
# Initialize the OpenAI client
client = OpenAI()
# URL for the audio file on GitHub
audio_url = "https://github.com/jdh-observer/JZx9gw7iwGxb/raw/refs/heads/main/media/A-0339_edited.mp3"
# Save location for the downloaded audio file
file_path = "./A-0339_edited.mp3"
# Download the audio file and save it locally
response = requests.get(audio_url)
with open(file_path, "wb") as audio_file:
audio_file.write(response.content)
# Measure the transcription time for the audio file
start_time = time.time()
# Transcribe the audio
with open(file_path, "rb") as audio_file:
transcription = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file
)
whisper_transcript = transcription.text
end_time = time.time()
# Calculate the actual transcription time
automation_time = end_time - start_time
# Calculate the estimated transcription time for 1 hour based on the transcription time for audio segment
audio_length_seconds = 153 # 2 minutes and 33 seconds
estimated_time_for_one_hour = (automation_time / audio_length_seconds) * 3600
# Convert estimated time for better readability
hours = int(estimated_time_for_one_hour // 3600)
minutes = int((estimated_time_for_one_hour % 3600) // 60)
seconds = int(estimated_time_for_one_hour % 60)
console = Console()
# Outputs with rich formatting
output_text = (
f"[bold]Whisper Transcription time:[/bold] {automation_time:.2f} seconds\n\n"
f"[bold]Estimated Transcription Time for an hour recording at this rate:[/bold] "
f"{hours} hours, {minutes} minutes, {seconds} seconds\n\n"
f"[bold]Raw Whisper Transcript[/bold]\n"
f"[dim]{whisper_transcript}[/dim]"
)
console.print(output_text, width=console.size.width)
💡 Hint: This uses OpenAI's Whisper API to automatically transcribe your audio. You'll need an API key! The code also estimates how long it would take to transcribe an entire hour of audio.
Track 2: Text Analysis
Version 1: Topic Modelling Basics
📖 Article used as a reference:
Oberbichler, S. and Pfanzelter, E. (2021) “Topic-specific corpus building: A step towards a representative newspaper corpus on the topic of return migration using text mining methods,” Journal of Digital History, 1(1). Available at: https://doi.org/10.1515/JDH-2021-1003?locatt=label:JDHFULL.
- a section with Topic Modelling Basics
- a section with Tokenisation
- on JDH
- Github Repository
💡 Hint: Topic modelling identifies recurring themes in large text collections automatically—useful for finding patterns you might miss manually.
Version 2: Natural Language Processing
📖 Article used as a reference:
Mourlon-Druol, E. and Bergamini, E. (2022) “Economic union in the debates on the creation of the euro: new evidence from the tapes of the Delors Committee meetings,” Journal of Digital History, 2(1). Available at: https://doi.org/10.1515/JDH-2023-0008?locatt=label:JDHFULL.
- a section with Natural Language Processing
- on JDH
- Github Repository
Test in Binder: https://mybinder.org/v2/gh/jdh-observer/4ZDXFXQwhoA8/main?filepath=article.ipynb
Important: To run in Binder, add this cell at position 47-48:
nltk.download('punkt_tab')
💡 Hint: This downloads the tools needed to break text into sentences and words—essential for text analysis!
Version 3: Advanced NLP and Topic Modelling
📖 Article used as a reference:
Michael Kurzmeier. “Contextualizing and unlocking political web defacements for research” Journal of Digital History
- a section with Topic modelling
- on JDH
- Github Repository
💡 Hint: This combines natural language processing with topic modelling for more in-depth text analysis.
Track 3: Language Models
📖 Article used as a reference:
Hutchinson, D. (2024) “Mapping the Latent Past: Assessing Large Language Models as Digital Tools through Source Criticism,” Journal of Digital History, 3(1). Available at: https://doi.org/10.1515/JDH-2023-0018?locatt=label:JDHFULL.
- a section which explains how to use the AI API
- on JDH
- Github Repository
Set up your LLM API key using this resource: https://github.com/jdh-observer/JZx9gw7iwGxb/blob/main/media/revised_original_transcript_formatted.txt
💡 Hint: Language models can help analyze, summarize, or generate historical narratives. You'll need an API key (similar to your OpenAI key if using GPT-based models).
⚠️ The problem is : how do we keep the reproducibility of the articles ?
Notebook presentations and wrap up !
Now it is time for you to present what you have done to the rest of participants 🚀