Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,35 @@ Contribs from:
* DarkFlib
* Wsuff
* your name could be here... contribute some code

## Gemini.js
**Key Adaptations**

1. **Selectors:**
* `'chat-window-content .conversation-container'` to get each turn.
* `'user-query-content .query-text'` to get user input.
* `'response-container .response-content'` to get model output.
2. **`extractTextContent` and `extractHTMLContent`:**
* `extractTextContent` now uses `innerText` to get plain text from user queries.
* `extractHTMLContent` uses `innerHTML` to preserve formatting in model responses.
3. **Role Assignment:**
* User queries are assigned the `role: 'user'`.
* Model responses are assigned the `role: 'assistant'`.
4. **Position Sorting:**
* The `getNodePosition` function and sorting logic are retained to ensure the correct conversation order.
5. **JSON Structure:**
* The output JSON includes `title`, `timestamp`, and `conversation` (an array of messages).


**How to Use**

1. Open the Gemini chat you want to extract.
2. Open the browser console.
3. Paste the script.
4. Press Enter.

This script should now provide you with a JSON file in the desired format, consistent with the ChatArchiver's expectations.

### Bugs
- Gemini doesn't appear to keep Conversation Title anywhere but the nav bar, so this doesn't populate that correctly yet.
- Output is still HTML as displayed. Post process likely needed but rather not write my own.
107 changes: 107 additions & 0 deletions gemini.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
(function extractGeminiChat() {
function extractTextContent(element) {
if (!element) return '';
return element.innerText.trim(); // Use innerText for consistency
}

function extractHTMLContent(element) {
if (!element) return '';
return element.innerHTML.trim(); // Use innerHTML for model responses
}

function getNodePosition(element) {
let positions = [];
while (element) {
let position = 0;
let sibling = element;
while ((sibling = sibling.previousSibling)) {
position++;
}
positions.unshift(position);
element = element.parentNode;
}
return positions.join('.');
}

const conversationContainers = document.querySelectorAll(
'chat-window-content .conversation-container'
);

let allMessages = [];

conversationContainers.forEach((container) => {
const position = getNodePosition(container);

const userQueryElement = container.querySelector(
'user-query-content .query-text'
);
const modelResponseElement = container.querySelector(
'response-container .response-content'
);

if (userQueryElement) {
allMessages.push({
role: 'user',
content: extractTextContent(userQueryElement),
position,
});
}

if (modelResponseElement) {
allMessages.push({
role: 'assistant',
content: extractHTMLContent(modelResponseElement),
position,
});
}
});

allMessages.sort((a, b) => {
const posA = a.position.split('.').map(Number);
const posB = b.position.split('.').map(Number);

for (let i = 0; i < Math.min(posA.length, posB.length); i++) {
if (posA[i] !== posB[i]) {
return posA[i] - posB[i];
}
}
return posA.length - posB.length;
});

allMessages.forEach((msg) => {
delete msg.position;
});

const chatData = {
title: document.title || 'Gemini Chat',
timestamp: new Date().toISOString(),
conversation: allMessages,
};

function downloadJSON(data, filename) {
const blob = new Blob([JSON.stringify(data, null, 2)], {
type: 'application/json',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(url);
document.body.removeChild(a);
}

const filename = `gemini-chat-${new Date()
.toISOString()
.slice(0, 19)
.replace(/:/g, '-')}.json`;
downloadJSON(chatData, filename);

console.log(
`Chat extracted with ${allMessages.length} messages. Downloading as ${filename}`
);

return `Successfully extracted ${allMessages.length} messages from the Gemini chat.`;
})();