Skip to content

Instantly share code, notes, and snippets.

@htlin222
Created July 31, 2026 15:35
Show Gist options
  • Select an option

  • Save htlin222/37372cc3ec8e5dd2ca4d1ddd3174620b to your computer and use it in GitHub Desktop.

Select an option

Save htlin222/37372cc3ec8e5dd2ca4d1ddd3174620b to your computer and use it in GitHub Desktop.
Convert Zotero CSV exports to Marp markdown slides with PubMed abstracts and ChatGPT-summarized bullet points. Usage: `python script.py -f collection.csv`
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Zotero CSV to Marp Slide Generator
Converts Zotero bibliography exports (CSV format) into Marp-compatible markdown presentations.
Fetches PubMed abstracts via DOI, summarizes with ChatGPT into bullet points.
Dependencies: openai, pandas, biopython, requests
Usage: python script.py -f zotero_export.csv
Output: output.md (marp-compatible presentation)
"""
import os
import re
import subprocess
import sys
import openai
import pandas as pd
import requests
from Bio import Entrez
def respond(prompt):
openai.api_key = "YOUR_API_KEY"
completions = openai.Completion.create(
engine="text-davinci-002",
prompt=prompt,
max_tokens=1000,
n=1,
stop=None,
temperature=0.5,
)
message = completions.choices[0].text
return message
def doi_to_pmid(doi):
"""Convert DOI to PubMed ID via NCBI esearch API."""
base_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"
params = {"db": "pubmed", "term": f"{doi}[DOI]", "retmode": "json"}
response = requests.get(base_url, params=params)
response_json = response.json()
if "esearchresult" in response_json and "idlist" in response_json[
"esearchresult"]:
pmids = response_json["esearchresult"]["idlist"]
if pmids:
return pmids[0]
return None
def get_abstract_from_pmid(pmid):
"""Fetch abstract text from PubMed ID."""
# NCBI 要求提供聯絡信箱;設環境變數 NCBI_EMAIL 即可
Entrez.email = os.environ.get("NCBI_EMAIL", "your-email@example.com")
handle = Entrez.efetch(db="pubmed", id=pmid, retmode="xml")
records = Entrez.read(handle)
try:
abstract = records["PubmedArticle"][0]["MedlineCitation"]["Article"][
"Abstract"]["AbstractText"][0]
except (KeyError, IndexError):
abstract = "Abstract not available"
return abstract
def get_abstract(doi):
"""Retrieve abstract from DOI."""
pmid = doi_to_pmid(doi)
print(pmid)
if pmid:
return get_abstract_from_pmid(pmid)
else:
print("No DOI Found")
return None
def clean_text(string):
"""Format bullet points with slide separators every 3 items."""
lines = string.split("\n")
filtered_lines = [line for line in lines if line.startswith("- ")]
grouped_lines = []
for i in range(0, len(filtered_lines), 3):
grouped_lines.extend(filtered_lines[i:i + 3])
if i + 3 < len(filtered_lines):
grouped_lines.append("\n\n---\n\n")
return "\n".join(grouped_lines)
def extract_plain_text_line_by_line(string: str) -> str:
"""Extract plain text from HTML-formatted notes."""
lines = re.split(r"<\/[^>]+>", string)
lines = [
re.sub(r"<[^>]+>", "", line).strip() for line in lines
if re.sub(r"<[^>]+>", "", line).strip()
]
combined = "- " + "\n- ".join(lines)
combined = clean_text(combined)
return combined
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: script_name.py -f filename.csv")
sys.exit(1)
flag, filename = sys.argv[1], sys.argv[2]
if flag != "-f":
print("Usage: script_name.py -f filename.csv")
sys.exit(1)
df = pd.read_csv(filename)
doi_list = df["DOI"].dropna().unique().tolist()
markdown_content = "# Title Page\n\n---\n\n"
for doi in doi_list:
title = df[df["DOI"] == doi]["Title"].iloc[0]
note = df[df["DOI"] == doi]["Notes"].iloc[0]
if isinstance(note, str) and len(note) > 0:
cleaned_note = (f"## {title}\n\n### Hightlights\n\n" +
extract_plain_text_line_by_line(note) +
"\n\n---\n\n")
else:
cleaned_note = ""
print(title)
abstract = get_abstract(doi)
response = respond(
f"transferred to bullet points in markdown, like '- content\n- content' here are the context:\n{abstract}"
)
lines = [line for line in response.splitlines() if line.strip()]
bullet_points = "\n".join(lines)
bullet_points = clean_text(bullet_points)
year = df[df["DOI"] == doi]["Publication Year"].iloc[0]
markdown_content += f"{cleaned_note}## {title}\n\n### Summary\n\n{bullet_points}\n\n<!-- {abstract} -->\n\n> {title} ({year}). DOI: {doi}\n\n---\n\n"
markdown_content += "\n\n## Thank You for Your Listening\n"
with open("output.md", "w") as file:
file.write(markdown_content)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment