4.8 KiB
Implement Task 3 — ChatGPT DOM Extractor for the Project Thoth ChatGPT Capture Connector MVP.
Context:
- This is a Manifest V3 Chrome/Edge extension.
- Task 1 extension skeleton is complete.
- Task 2 activeTab capture flow is complete.
- The service worker can inject or invoke a content script and receive a placeholder payload.
- This task replaces the placeholder capture logic with a ChatGPT-specific DOM extractor.
- Capture Connectors must only capture source material. Do not reason, summarize, classify, call LLMs, generate Project Thoth metadata, or write to the vault.
Goal: Create a ChatGPT-specific DOM extractor module that returns an ordered conversation capture payload with title, URL, capture timestamp, and messages.
Files to update or create:
- src/chatgptExtractor.js
- src/background.js only if needed to integrate the extractor result
- README.md only if testing instructions need updating
Expected output shape:
{ sourcePlatform: "ChatGPT", title: "Detected conversation title", url: "https://chatgpt.com/...", capturedAt: "2026-07-08T...", messages: [ { role: "user", content: "..." }, { role: "assistant", content: "..." } ] }
Extractor requirements:
-
Extract the conversation title if available.
- Prefer a visible conversation title if one exists.
- Fall back to document.title.
- Fall back to "ChatGPT Conversation".
-
Extract ordered message blocks.
- Preserve the page order of messages.
- Return messages in the same order they appear in the conversation.
- Ignore navigation, sidebar, composer/input box, buttons, menus, and unrelated UI chrome.
-
Detect speaker role when possible.
- Detect user messages as role: "user".
- Detect assistant messages as role: "assistant".
- If role cannot be determined, use role: "unknown" rather than guessing too aggressively.
- Keep role detection logic isolated and easy to revise because ChatGPT DOM structure may change.
-
Extract text content.
- Extract the readable content of each message.
- Trim leading/trailing whitespace.
- Collapse excessive blank lines where appropriate.
- Do not include copy buttons, feedback controls, model labels, timestamps, or hidden UI text.
-
Preserve basic formatting where practical.
- Preserve paragraph breaks.
- Preserve markdown-like headings.
- Preserve bullet and numbered lists as readable text.
- Preserve code blocks using fenced markdown when detectable.
- Preserve inline code as readable text when detectable.
- Do not attempt perfect HTML-to-Markdown conversion in this task.
-
Handle code blocks.
- Detect pre/code blocks inside assistant messages.
- Output fenced code blocks.
- Include a language tag if available from the DOM; otherwise use a plain triple-backtick fence.
- Avoid duplicating code block content in the surrounding extracted text.
-
Be defensive against ChatGPT DOM instability.
- Use multiple selector strategies where reasonable.
- Prefer semantic attributes when available, such as data-testid, role, aria-label, or known message container patterns.
- Keep selectors centralized near the top of the extractor.
- Add comments explaining selector assumptions.
-
Return useful failure states.
- If no messages are found, return a structured payload with messages: [] and an error field such as: { error: "No ChatGPT conversation messages were detected." }
- Do not throw unhandled exceptions from normal extraction failure.
-
No browser download logic in this task.
-
No markdown normalizer in this task.
-
No Project Thoth application dependency.
-
No LLM calls.
Suggested module API:
export function extractChatGPTConversation() { return { sourcePlatform: "ChatGPT", title, url: window.location.href, capturedAt: new Date().toISOString(), messages }; }
Suggested helper functions:
- getConversationTitle()
- findMessageElements()
- detectMessageRole(element)
- extractMessageContent(element)
- extractNodeAsMarkdown(node)
- normalizeWhitespace(text)
Integration:
- The activeTab capture flow should invoke extractChatGPTConversation() from the injected content context.
- The service worker should receive and log the returned payload.
- Existing Task 2 message passing should remain intact.
Acceptance criteria:
- On an open ChatGPT conversation, clicking the extension button returns a payload with title, URL, capturedAt, and ordered messages.
- User and assistant roles are detected when possible.
- Message content is readable and excludes obvious UI chrome.
- Paragraphs, lists, headings, and code blocks remain usable in the extracted content.
- If no conversation is detected, the payload clearly reports that no messages were found.
- The implementation remains modular so Task 4 can consume the payload and convert it into canonical conversation.md format.