mirror of
https://github.com/pionxzh/chatgpt-exporter.git
synced 2026-07-23 09:00:51 -05:00
@@ -10,6 +10,7 @@ export const apiUrl = API_MAPPING[baseUrl]
|
||||
export const LEGACY_KEY_FILENAME_FORMAT = 'exporter-format'
|
||||
export const KEY_LANGUAGE = 'exporter:language'
|
||||
export const KEY_FILENAME_FORMAT = 'exporter:filename_format'
|
||||
export const KEY_OFFICIAL_JSON_FORMAT = 'exporter:official_json_format'
|
||||
export const KEY_TIMESTAMP_ENABLED = 'exporter:enable_timestamp'
|
||||
export const KEY_TIMESTAMP_24H = 'exporter:timestamp_24h'
|
||||
export const KEY_TIMESTAMP_MARKDOWN = 'exporter:timestamp_markdown'
|
||||
|
||||
@@ -5,7 +5,7 @@ import { checkIfConversationStarted, getConversationChoice } from '../page'
|
||||
import { downloadFile, getFileNameWithFormat } from '../utils/download'
|
||||
import type { ApiConversationWithId } from '../api'
|
||||
|
||||
export async function exportToJson(fileNameFormat: string) {
|
||||
export async function exportToJson(fileNameFormat: string, options: { officialFormat: boolean }) {
|
||||
if (!checkIfConversationStarted()) {
|
||||
alert(i18n.t('Please start a conversation first'))
|
||||
return false
|
||||
@@ -17,12 +17,22 @@ export async function exportToJson(fileNameFormat: string) {
|
||||
const conversation = processConversation(rawConversation, conversationChoices)
|
||||
|
||||
const fileName = getFileNameWithFormat(fileNameFormat, 'json', { title: conversation.title, chatId })
|
||||
const content = conversationToJson(rawConversation)
|
||||
/**
|
||||
* The official format is just an array of the API response.
|
||||
*/
|
||||
const content = conversationToJson(options.officialFormat ? [rawConversation] : rawConversation)
|
||||
downloadFile(fileName, 'application/json', content)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export async function exportAllToOfficialJson(_fileNameFormat: string, apiConversations: ApiConversationWithId[]) {
|
||||
const content = conversationToJson(apiConversations)
|
||||
downloadFile('chatgpt-export.json', 'application/json', content)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export async function exportAllToJson(fileNameFormat: string, apiConversations: ApiConversationWithId[]) {
|
||||
const zip = new JSZip()
|
||||
const filenameMap = new Map<string, number>()
|
||||
@@ -61,6 +71,6 @@ export async function exportAllToJson(fileNameFormat: string, apiConversations:
|
||||
return true
|
||||
}
|
||||
|
||||
function conversationToJson(conversation: ApiConversationWithId) {
|
||||
function conversationToJson(conversation: ApiConversationWithId | ApiConversationWithId[]) {
|
||||
return JSON.stringify(conversation)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"Enable on HTML": "Enable on HTML files",
|
||||
"Enable on Markdown": "Enable on Markdown files",
|
||||
"Use 24-hour format": "Use 24-hour format (eg. 23:59)",
|
||||
"Export Format": "Export Format",
|
||||
"Export JSON Format Description": "Export JSON in OpenAI Official Format",
|
||||
"Export Metadata": "Export Metadata",
|
||||
"Export Metadata Description": "Add metadata to exported Markdown and HTML files.",
|
||||
"Conversation Delete Alert": "Are you sure you want to delete all selected conversations?",
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"Enable on HTML": "Habilitar en archivos HTML",
|
||||
"Enable on Markdown": "Habilitar en archivos Markdown",
|
||||
"Use 24-hour format": "Usar formato de 24 horas(ej. 23:59)",
|
||||
"Export Format": "Formato de Exportación",
|
||||
"Export JSON Format Description": "Exportar JSON en el Formato Oficial de OpenAI",
|
||||
"Export Metadata": "Exportar Metadata",
|
||||
"Export Metadata Description": "Añadir Metadata a Markdown y a HTML exportados.",
|
||||
"Conversation Delete Alert": "¿Estás seguro que quieres borrar todas las conversaciones seleccionadas?",
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"Enable on HTML": "Aktifkan pada file HTML",
|
||||
"Enable on Markdown": "Aktifkan pada file Markdown",
|
||||
"Use 24-hour format": "Gunakan format 24 jam (mis. 23:59)",
|
||||
"Export Format": "Format Ekspor",
|
||||
"Export JSON Format Description": "Ekspor JSON dalam Format Resmi OpenAI",
|
||||
"Export Metadata": "Ekspor Metadata",
|
||||
"Export Metadata Description": "Tambahkan metadata ke file Markdown dan HTML yang diekspor.",
|
||||
"Conversation Delete Alert": "Apakah Anda yakin ingin menghapus semua percakapan yang dipilih?",
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"Enable on HTML": "HTML ファイルで有効にする",
|
||||
"Enable on Markdown": "Markdown ファイルで有効にする",
|
||||
"Use 24-hour format": "24時間形式を使用する (例: 23:59)",
|
||||
"Export Format": "エクスポートフォーマット",
|
||||
"Export JSON Format Description": "OpenAI公式フォーマットでのJSONのエクスポート",
|
||||
"Export Metadata": "メタデータをエクスポート",
|
||||
"Export Metadata Description": "エクスポートされたMarkdownおよびHTMLファイルにメタデータを追加します。",
|
||||
"Conversation Delete Alert": "選択したすべての会話を削除してもよろしいですか?",
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"Enable on HTML": "HTML dosyalarında etkinleştir",
|
||||
"Enable on Markdown": "Markdown dosyalarında etkinleştir",
|
||||
"Use 24-hour format": "24 saat biçimini kullan (örn. 23:59)",
|
||||
"Export Format": "Dışa Aktarma Formatı",
|
||||
"Export JSON Format Description": "OpenAI Resmi Formatında JSON Dışa Aktarma",
|
||||
"Export Metadata": "Üst veriyi dışa aktar",
|
||||
"Export Metadata Description": "Dışa aktarılan Markdown ve HTML dosyalarına üst veri ekle",
|
||||
"Conversation Delete Alert": "Seçilen tüm konuşmaları silmek istediğinizden emin misiniz?",
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"Enable on HTML": "在 HTML 文件上启用",
|
||||
"Enable on Markdown": "在 Markdown 文件上启用",
|
||||
"Use 24-hour format": "使用24小时制 (例如 23:59)",
|
||||
"Export Format": "导出格式",
|
||||
"Export JSON Format Description": "以 OpenAI 官方格式导出JSON",
|
||||
"Export Metadata": "导出元数据",
|
||||
"Export Metadata Description": "会添加至 Markdown 以及 HTML 导出。",
|
||||
"Conversation Delete Alert": "确定要删除所有选取的对话?",
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"Enable on HTML": "在 HTML 檔案上啟用",
|
||||
"Enable on Markdown": "在 Markdown 檔案上啟用",
|
||||
"Use 24-hour format": "使用24小時制 (例如 23:59)",
|
||||
"Export Format": "匯出格式",
|
||||
"Export JSON Format Description": "以 OpenAI 官方格式匯出 JSON",
|
||||
"Export Metadata": "匯出元資料",
|
||||
"Export Metadata Description": "會添加至 Markdown 以及 HTML 匯出。",
|
||||
"Conversation Delete Alert": "確定要刪除所有選取的對話?",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { deleteConversation, fetchAllConversations, fetchConversation } from '../api'
|
||||
import { exportAllToHtml } from '../exporter/html'
|
||||
import { exportAllToJson } from '../exporter/json'
|
||||
import { exportAllToJson, exportAllToOfficialJson } from '../exporter/json'
|
||||
import { exportAllToMarkdown } from '../exporter/markdown'
|
||||
import { RequestQueue } from '../utils/queue'
|
||||
import { CheckBox } from './CheckBox'
|
||||
@@ -13,12 +13,6 @@ import type { ApiConversationItem, ApiConversationWithId } from '../api'
|
||||
import type { FC } from '../type'
|
||||
import type { ChangeEvent } from 'preact/compat'
|
||||
|
||||
const exportAllOptions = [
|
||||
{ label: 'Markdown', callback: exportAllToMarkdown },
|
||||
{ label: 'JSON', callback: exportAllToJson },
|
||||
{ label: 'HTML', callback: exportAllToHtml },
|
||||
]
|
||||
|
||||
interface ConversationSelectProps {
|
||||
conversations: ApiConversationItem[]
|
||||
selected: ApiConversationItem[]
|
||||
@@ -83,9 +77,15 @@ type ExportSource = 'API' | 'Local'
|
||||
|
||||
export const ExportDialog: FC<ExportDialogProps> = ({ format, open, onOpenChange, children }) => {
|
||||
const { t } = useTranslation()
|
||||
const { enableMeta, exportMetaList } = useSettingContext()
|
||||
const { enableMeta, exportMetaList, exportOfficialJsonFormat } = useSettingContext()
|
||||
const metaList = useMemo(() => enableMeta ? exportMetaList : [], [enableMeta, exportMetaList])
|
||||
|
||||
const exportAllOptions = useMemo(() => [
|
||||
{ label: 'Markdown', callback: exportAllToMarkdown },
|
||||
{ label: 'JSON', callback: exportOfficialJsonFormat ? exportAllToOfficialJson : exportAllToJson },
|
||||
{ label: 'HTML', callback: exportAllToHtml },
|
||||
], [exportOfficialJsonFormat])
|
||||
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
const [exportSource, setExportSource] = useState<ExportSource>('API')
|
||||
const [apiConversations, setApiConversations] = useState<ApiConversationItem[]>([])
|
||||
@@ -152,7 +152,7 @@ export const ExportDialog: FC<ExportDialogProps> = ({ format, open, onOpenChange
|
||||
if (callback) callback(format, results, metaList)
|
||||
})
|
||||
return () => off()
|
||||
}, [requestQueue, exportType, format, metaList])
|
||||
}, [requestQueue, exportAllOptions, exportType, format, metaList])
|
||||
|
||||
useEffect(() => {
|
||||
const off = deleteQueue.on('done', () => {
|
||||
@@ -185,7 +185,7 @@ export const ExportDialog: FC<ExportDialogProps> = ({ format, open, onOpenChange
|
||||
const results = localConversations.filter(c => selected.some(s => s.id === c.id))
|
||||
const callback = exportAllOptions.find(o => o.label === exportType)?.callback
|
||||
if (callback) callback(format, results, metaList)
|
||||
}, [disabled, selected, localConversations, exportType, format, metaList])
|
||||
}, [disabled, selected, localConversations, exportAllOptions, exportType, format, metaList])
|
||||
|
||||
const exportAll = useMemo(() => {
|
||||
return exportSource === 'API' ? exportAllFromApi : exportAllFromLocal
|
||||
|
||||
@@ -28,6 +28,7 @@ function MenuInner({ container }: { container: HTMLDivElement }) {
|
||||
|
||||
const {
|
||||
format,
|
||||
exportOfficialJsonFormat,
|
||||
enableTimestamp,
|
||||
timeStamp24H,
|
||||
enableMeta,
|
||||
@@ -49,7 +50,7 @@ function MenuInner({ container }: { container: HTMLDivElement }) {
|
||||
const onClickPng = useCallback(() => exportToPng(format), [format])
|
||||
const onClickMarkdown = useCallback(() => exportToMarkdown(format, metaList), [format, metaList])
|
||||
const onClickHtml = useCallback(() => exportToHtml(format, metaList), [format, metaList])
|
||||
const onClickJSON = useCallback(() => exportToJson(format), [format])
|
||||
const onClickJSON = useCallback(() => exportToJson(format, { officialFormat: exportOfficialJsonFormat }), [format, exportOfficialJsonFormat])
|
||||
|
||||
const width = useWindowResize(() => window.innerWidth)
|
||||
const isMobile = width < 768
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
KEY_FILENAME_FORMAT,
|
||||
KEY_META_ENABLED,
|
||||
KEY_META_LIST,
|
||||
KEY_OFFICIAL_JSON_FORMAT,
|
||||
KEY_TIMESTAMP_24H,
|
||||
KEY_TIMESTAMP_ENABLED,
|
||||
KEY_TIMESTAMP_HTML,
|
||||
@@ -28,6 +29,9 @@ const SettingContext = createContext({
|
||||
format: defaultFormat,
|
||||
setFormat: (_: string) => {},
|
||||
|
||||
exportOfficialJsonFormat: false,
|
||||
setExportOfficialJsonFormat: (_: boolean) => {},
|
||||
|
||||
enableTimestamp: false,
|
||||
setEnableTimestamp: (_: boolean) => {},
|
||||
timeStamp24H: false,
|
||||
@@ -48,6 +52,8 @@ const SettingContext = createContext({
|
||||
export const SettingProvider: FC = ({ children }) => {
|
||||
const [format, setFormat] = useGMStorage(KEY_FILENAME_FORMAT, defaultFormat)
|
||||
|
||||
const [exportOfficialJsonFormat, setExportOfficialJsonFormat] = useGMStorage(KEY_OFFICIAL_JSON_FORMAT, false)
|
||||
|
||||
const [enableTimestamp, setEnableTimestamp] = useGMStorage(KEY_TIMESTAMP_ENABLED, false)
|
||||
const [timeStamp24H, setTimeStamp24H] = useGMStorage(KEY_TIMESTAMP_24H, false)
|
||||
const [enableTimestampHTML, setEnableTimestampHTML] = useGMStorage(KEY_TIMESTAMP_HTML, false)
|
||||
@@ -69,6 +75,9 @@ export const SettingProvider: FC = ({ children }) => {
|
||||
format,
|
||||
setFormat,
|
||||
|
||||
exportOfficialJsonFormat,
|
||||
setExportOfficialJsonFormat,
|
||||
|
||||
enableTimestamp,
|
||||
setEnableTimestamp,
|
||||
timeStamp24H,
|
||||
|
||||
@@ -32,6 +32,7 @@ export const SettingDialog: FC<SettingDialogProps> = ({
|
||||
timeStamp24H, setTimeStamp24H,
|
||||
enableTimestampHTML, setEnableTimestampHTML,
|
||||
enableTimestampMarkdown, setEnableTimestampMarkdown,
|
||||
exportOfficialJsonFormat, setExportOfficialJsonFormat,
|
||||
enableMeta, setEnableMeta,
|
||||
exportMetaList, setExportMetaList,
|
||||
} = useSettingContext()
|
||||
@@ -108,6 +109,22 @@ export const SettingDialog: FC<SettingDialogProps> = ({
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex bg-white dark:bg-white/5 rounded p-4">
|
||||
<div>
|
||||
<dt className="text-md font-medium text-gray-800 dark:text-white">
|
||||
{t('Export Format')}
|
||||
</dt>
|
||||
<dd className="text-sm text-gray-700 dark:text-gray-300">
|
||||
<div className="mt-2">
|
||||
<Toggle
|
||||
label={t('Export JSON Format Description')}
|
||||
checked={exportOfficialJsonFormat}
|
||||
onCheckedUpdate={setExportOfficialJsonFormat}
|
||||
/>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex bg-white dark:bg-white/5 rounded p-4">
|
||||
<div>
|
||||
<dt className="text-md font-medium text-gray-800 dark:text-white">
|
||||
|
||||
Reference in New Issue
Block a user