Extract und KI-Summary

Für den letzten Block, den Download der relevanten PDF-Files und dem Zusammenfassen braucht es einige Scripts.

Für den Download habe ich auf das PyPaperBot Script von Vito Ferrulli zurückgegriffen, vielen Dank an dieser Stelle für die Entwicklung. Für den Download aller verfügbaren Files macht man eine Textdatei mit den relevanten DOIS und übergibt diese dem Script mit:

python -m PyPaperBot --doi-file="file.txt" --dwn-dir="\papers"`

Um einen Prozess im Verzeichnis „paperlib“ aufzusetzen habe ich – die Scripts kommen dann nachher – eine Filestruktur aufgesetzt, in der meine PDF-Files in „./paperlib/upload“ sind.

./etc/

im Verzeichnis ./etc/ finden sich die Konfigurationsdaten und der GPT-Prompt:

die Datei config.cfg

[openai]
api_key = sfjhklsdfjlkjfdlskjflkjdfljsflsdljsdlkdsf 
model = gpt-4o
max_input_tokens = 15000 
max_output_tokens = 1000
wait_time_seconds = 120 

die Datei prompt

Du bist Sozialwissenschafter und schreibst wissenschaftlich in deutscher Sprache für eine Literaturreview. Formatiere den output in korrektem html, in dem die Umlaute richtig codiert werden.
Mache eine Zusammenfassung des Artikels, strukturiert, im html format. ü1 In der Überschift eine korrekte Zitierung mit Autor/en(Jahr): Titel und Quelle,  DOI. 

Dann die Kurzzusammenfassung in einem Absatz. Darunter bis zu fünf Keywords getrennt mit Semicolons

Danach Beschreibe, ob es sich beim Untersuchungsgegenstand um eine NPO oder eine andere Organisation/Unternehmen handelt - dann welche Branche/Industry, In einem Absatz mit Überschrift "Konzepte und theoretische Konstrukte" extrahiere jeweils die relevanten wissenschaftlichen Konzepte(z.B. Brand Equity, Reputation, Motivation, ...) und die zugrunde liegenden Faktoren als liste  und beschreibe in einem neuen absatz die wesentlichen Erkenntnisse des Papers. Am Ende die relevanten zitierten Autoren für die Konzeptionelle Struktur (max 3) in Kurzzitatform, Also Autor(Jahr). Bitte insgesamt eine Seite. jeder Absatz hat eine formatierte Überschrift. Write in German scholarely language

Die Skripte

Die Skripte finden sich im Verzeichnis ./bin/

Ich bedanke mich bei ChatGPT für die Coautorenschaft dieser beiden Skripte. Das erste pdf_to_chatgpt.py liest ein PDF File als Text und sendet es gemeinsam mit dem Prompt an das chatGPT-API, das zweite File liest die PDF-Files in ./upload/ und ruft jeweils das zweite Script auf. Danach kopiert es die PDFs ins Verzeichnis ./data/pdf und die HTML-Zusammenfassungen nach ./data/html/ ausserdem wird eine Wartezeit eingehalten, um die API-Tokenbremse einzuhalten.

pdf_to_chatgpt.py

import fitz  # PyMuPDF
import openai
import argparse
import tiktoken
import configparser
import os

def extract_text_from_pdf(pdf_path):
    doc = fitz.open(pdf_path)
    text = ""
    for page_num in range(len(doc)):
        page = doc.load_page(page_num)
        text += page.get_text()
    return text

def read_prompt_from_file(prompt_path):
    with open(prompt_path, 'r') as file:
        prompt = file.read()
    return prompt

def limit_tokens(text, max_tokens, encoding_name="cl100k_base"):
    enc = tiktoken.get_encoding(encoding_name)
    tokens = enc.encode(text)
    return enc.decode(tokens[:max_tokens])

def send_text_to_chatgpt(api_key, model, max_input_tokens, max_output_tokens, prompt, pdf_content):
    combined_content = prompt + "\n\n" + pdf_content
    combined_content = limit_tokens(combined_content, max_input_tokens)

    openai.api_key = api_key

    response = openai.ChatCompletion.create(
        model=model,
        messages=[{"role": "user", "content": combined_content}],
        max_tokens=max_output_tokens
    )
    
    return response

if __name__ == "__main__":
    # Konfiguration aus Datei lesen
    config = configparser.ConfigParser()
    config.read(os.path.join('../etc', 'config.cfg'))

    api_key = config.get('openai', 'api_key')
    model = config.get('openai', 'model')
    max_input_tokens = config.getint('openai', 'max_input_tokens')
    max_output_tokens = config.getint('openai', 'max_output_tokens')

    parser = argparse.ArgumentParser(description="Send a PDF to the ChatGPT API and get structured data as text.")
    parser.add_argument('pdf_path', type=str, help="The path to the PDF file")
    parser.add_argument('--prompt', type=str, help="The path to the prompt text file", required=True)

    args = parser.parse_args()

    prompt = read_prompt_from_file(args.prompt)
    pdf_content = extract_text_from_pdf(args.pdf_path)

    response = send_text_to_chatgpt(api_key, model, max_input_tokens, max_output_tokens, prompt, pdf_content)

    # Fehlerbehandlung und Ausgabe der Antwort
    if "choices" in response:
        print(response["choices"][0]["message"]["content"])
    else:
        print("Fehler: Die API-Antwort enthält keine 'choices'.")
        print("API-Antwort:", response)

und das Script pdf2chat2html.py

import os
import subprocess
import shutil
import configparser
import time

def process_pdfs_in_directory(directory, cfg_path, prompt_path):
    # Konfiguration aus Datei lesen
    config = configparser.ConfigParser()
    config.read(cfg_path)

    api_key = config.get('openai', 'api_key')
    model = config.get('openai', 'model')
    max_input_tokens = config.getint('openai', 'max_input_tokens')
    max_output_tokens = config.getint('openai', 'max_output_tokens')
    wait_time_seconds = config.getint('openai', 'wait_time_seconds')

    # Liste alle PDF-Dateien im Verzeichnis auf
    pdf_files = [f for f in os.listdir(directory) if f.endswith('.pdf')]
    
    # Verarbeite jede PDF-Datei
    for pdf_file in pdf_files:
        pdf_path = os.path.join(directory, pdf_file)
        output_html_file = os.path.join('../data/html', pdf_file.replace('.pdf', '.html'))
        
        # Ruf das Skript pdf_to_chatgpt.py auf und speichere die Ausgabe in eine HTML-Datei
        result = subprocess.run(
            ['python3', 'pdf_to_chatgpt.py', pdf_path, '--prompt', prompt_path],
            capture_output=True,
            text=True
        )
        
        if result.returncode == 0:
            with open(output_html_file, 'w', encoding='utf-8') as file:
                file.write(result.stdout)
            print(f"OK: {pdf_file}")
            
            # Verschiebe die PDF-Datei ins Zielverzeichnis
            shutil.move(pdf_path, os.path.join('../data/pdf', pdf_file))
        else:
            print(f"Fehler beim Verarbeiten von {pdf_file}: {result.stderr}")
        
        # Wartezeit vor dem nächsten API-Aufruf
        print(f"Warte {wait_time_seconds} Sekunden vor dem nächsten API-Aufruf...")
        time.sleep(wait_time_seconds)

if __name__ == "__main__":
    directory = '../upload'
    cfg_path = '../etc/config.cfg'
    prompt_path = '../etc/prompt'

    process_pdfs_in_directory(directory, cfg_path, prompt_path)

Die Ergebnisse sind durchaus praktisch, um in nächsten Schritten ins detailliertere Reviewing, das heißt exzerpieren und paraphrasieren zu gehen.

Hier das Beispiel des ChatGPT-Exzerps eines relevanten Artikels:

James B. Faircloth (2005): "Factors Influencing Nonprofit Resource Provider Support Decisions: Applying the Brand Equity Concept to Nonprofits", Journal of Marketing Theory and Practice. DOI: 10.1080/10696679.2005.11658546
Kurzzusammenfassung
Die explorative Forschung von Faircloth (2005) untersucht, wie verschiedene Vorläuferfaktoren die Entscheidung von Ressourcenbereitstellern (z.B. Freiwillige und Spender), eine Nonprofit-Organisation (NPO) zu unterstützen, beeinflussen. Erstmals wird das Konzept der Markenwertigkeit (Brand Equity) auf den Nonprofit-Sektor angewendet. Die Studie zeigt, dass Markenpersönlichkeit, Markenimage und Markenbewusstsein wesentliche Einflussfaktoren auf die Unterstützung der Nonprofit-Organisation sind, auch nach Berücksichtigung altruistischer Freiwilligenarbeit.

Keywords: Nonprofit-Organisation; Markenwertigkeit; Freiwilligenarbeit; Spenderverhalten; Markenbewusstsein

Untersuchungsgegenstand
Die im Artikel untersuchte Organisation ist eine Nonprofit-Organisation (NPO), die Dienstleistungen und Unterstützung für Menschen mit Entwicklungsstörungen anbietet. Die Branche ist daher der soziale Dienstleistungssektor.

Konzepte und theoretische Konstrukte
Markenwertigkeit (Brand Equity): Ein bedeutendes Konzept, das die Bias zugunsten des Verhaltens zu einer Marke beschreibt. Diese wird durch die Wahrnehmung verstärkter Markenmerkmale und der Bereitschaft, höhere Preise zu zahlen, aufbauend auf Aaker (1991) und Keller (1993) gemessen.
Markenpersönlichkeit (Brand Personality): Die wahrgenommenen menschlichen Merkmale einer Marke, die teilweise unabhängig vom Markenimage betrachtet werden können. Sie umfasst die Dimensionen Markenrespekt und Markendifferenzierung.
Markenimage (Brand Image): Die Wahrnehmung der Gesamtheit aller Assoziationen einer Marke durch den Konsumenten. Dies schließt die Dimensionen Markencharakter und Markenskala ein.
Markenbewusstsein (Brand Awareness): Bekanntheit und Vertrautheit der Marke, einschließlich der Fähigkeit, die Marke aus dem Gedächtnis abzurufen (Erstrekognition) und der Vertrautheit mit der Marke.
Wesentliche Erkenntnisse
Die Studie zeigt, dass die Dimensionen der Markenpersönlichkeit, speziell der Markenrespekt und die Markendifferenzierung, signifikanten Einfluss auf die Unterstützung der NPO haben. Das Image der Marke, insbesondere die wahrgenommene Skala der Marke, war ein weiterer wichtiger Faktor, während der Markencharakter weniger signifikant war. Bezüglich des Markenbewusstseins stellte sich heraus, dass die Vertrautheit mit der Marke einen negativen Einfluss auf die Unterstützung hat, was auf mögliche negative Wahrnehmungen der Organisation zurückzuführen sein könnte. Laut diesen Ergebnissen können NPOs durch gezielte Pflege der beschriebenen Vorläuferfaktoren eine stärkere Ressourcenunterstützung erzielen.

Relevante zitierte Autoren
Aaker (1991); Keller (1993); Fournier (1998)

Bei in Summe 88 Artikeln macht es Sinn, für jeden Text dieses Deckblatt mit den relevanten Inhalten zu erstellen, um immer einen raschen Überblick zu haben. Ohne die Artikel zu lesen geht es trotzdem nicht, der Selektionsprozess wird aber erleichtert.