mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-01 01:30:51 +08:00
fix(export): robustly export reasoning and handle errors (#9221)
* fix(export): robustly export reasoning and handle errors * fix(export): normalize <br> to newline before notion parsing * feat(i18n): add notion truncation and unify export warn keys * refactor(export): add typing, state guards, and error logging * fix(export): preserve existing <br> in reasoning when convert to html * feat(export): add DOMPurify sanitization for reasoning content * chore(deps): remove unused @types/dompurify dev dep * chore(deps): remove dompurify dependency Remove dompurify from package.json and yarn. The changes delete dompurify entries and simplify the lockfile resolution so the project no longer declares dompurify as a direct dependency. This cleans up unused dependency declarations and prevents installing dompurify when it is not required.
This commit is contained in:
parent
8b5a3f734c
commit
4dad2a593b
@ -179,7 +179,6 @@
|
||||
"dexie-react-hooks": "^1.1.7",
|
||||
"diff": "^7.0.0",
|
||||
"docx": "^9.0.2",
|
||||
"dompurify": "^3.2.6",
|
||||
"dotenv-cli": "^7.4.2",
|
||||
"electron": "37.2.3",
|
||||
"electron-builder": "26.0.15",
|
||||
|
||||
@ -840,6 +840,9 @@
|
||||
"created": "Created",
|
||||
"last_updated": "Last Updated",
|
||||
"messages": "Messages",
|
||||
"notion": {
|
||||
"reasoning_truncated": "Chain of thought cannot be chunked and has been truncated."
|
||||
},
|
||||
"user": "User"
|
||||
},
|
||||
"files": {
|
||||
@ -1257,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "Failed to export to Notion. Please check connection status and configuration according to documentation",
|
||||
"no_api_key": "Notion ApiKey or Notion DatabaseID is not configured"
|
||||
"no_api_key": "Notion ApiKey or Notion DatabaseID is not configured",
|
||||
"no_content": "There is nothing to export to Notion."
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Failed to export to Siyuan Note, please check connection status and configuration according to documentation",
|
||||
@ -1383,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "Exporting to Notion, please do not request export repeatedly!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "Exporting to Siyuan Note, please do not request export repeatedly!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "Exporting to Yuque, please do not request export repeatedly!"
|
||||
"export": {
|
||||
"exporting": "Another export is in progress. Please wait for the previous export to complete and then try again."
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
|
||||
@ -840,6 +840,9 @@
|
||||
"created": "作成日",
|
||||
"last_updated": "最終更新日",
|
||||
"messages": "メッセージ",
|
||||
"notion": {
|
||||
"reasoning_truncated": "思考過程がブロック分割できません。切り捨てられています。"
|
||||
},
|
||||
"user": "ユーザー"
|
||||
},
|
||||
"files": {
|
||||
@ -1257,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "Notionへのエクスポートに失敗しました。接続状態と設定を確認してください",
|
||||
"no_api_key": "Notion ApiKey または Notion DatabaseID が設定されていません"
|
||||
"no_api_key": "Notion ApiKey または Notion DatabaseID が設定されていません",
|
||||
"no_content": "Notionにエクスポートできる内容がありません。"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "思源ノートのエクスポートに失敗しました。接続状態を確認し、ドキュメントに従って設定を確認してください",
|
||||
@ -1383,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "Notionにエクスポート中です。重複してエクスポートしないでください! "
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "思源ノートにエクスポート中です。重複してエクスポートしないでください!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "語雀にエクスポート中です。重複してエクスポートしないでください!"
|
||||
"export": {
|
||||
"exporting": "他のエクスポートが実行中です。前のエクスポートが完了するまでお待ちください。"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
|
||||
@ -840,6 +840,9 @@
|
||||
"created": "Создано",
|
||||
"last_updated": "Последнее обновление",
|
||||
"messages": "Сообщения",
|
||||
"notion": {
|
||||
"reasoning_truncated": "Цепочка мыслей не может быть разбита на блоки, обрезана"
|
||||
},
|
||||
"user": "Пользователь"
|
||||
},
|
||||
"files": {
|
||||
@ -1257,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "Ошибка экспорта в Notion, пожалуйста, проверьте состояние подключения и настройки в документации",
|
||||
"no_api_key": "Notion ApiKey или Notion DatabaseID не настроен"
|
||||
"no_api_key": "Notion ApiKey или Notion DatabaseID не настроен",
|
||||
"no_content": "Нет содержимого для экспорта в Notion"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Ошибка экспорта в Siyuan, пожалуйста, проверьте состояние подключения и настройки в документации",
|
||||
@ -1383,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "Экспортируется в Notion, пожалуйста, не отправляйте повторные запросы!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "Экспортируется в Siyuan, пожалуйста, не отправляйте повторные запросы!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "Экспортируется в Yuque, пожалуйста, не отправляйте повторные запросы!"
|
||||
"export": {
|
||||
"exporting": "Выполняется другая экспортация, подождите завершения предыдущей операции экспорта и повторите попытку"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
|
||||
@ -840,6 +840,9 @@
|
||||
"created": "创建时间",
|
||||
"last_updated": "最后更新",
|
||||
"messages": "消息数",
|
||||
"notion": {
|
||||
"reasoning_truncated": "思维链无法分块,已截断"
|
||||
},
|
||||
"user": "用户"
|
||||
},
|
||||
"files": {
|
||||
@ -1257,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "导出 Notion 错误,请检查连接状态并对照文档检查配置",
|
||||
"no_api_key": "未配置 Notion API Key 或 Notion Database ID"
|
||||
"no_api_key": "未配置 Notion API Key 或 Notion Database ID",
|
||||
"no_content": "无可导出到 Notion 的内容"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "导出思源笔记失败,请检查连接状态并对照文档检查配置",
|
||||
@ -1383,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "正在导出到 Notion, 请勿重复请求导出!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "正在导出到思源笔记,请勿重复请求导出!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "正在导出语雀,请勿重复请求导出!"
|
||||
"export": {
|
||||
"exporting": "正在进行其他导出,请等待上一导出完成后重试"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
|
||||
@ -840,6 +840,9 @@
|
||||
"created": "建立時間",
|
||||
"last_updated": "最後更新",
|
||||
"messages": "訊息數",
|
||||
"notion": {
|
||||
"reasoning_truncated": "思維鏈無法分塊,已截斷"
|
||||
},
|
||||
"user": "使用者"
|
||||
},
|
||||
"files": {
|
||||
@ -1257,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "匯出 Notion 錯誤,請檢查連接狀態並對照文件檢查設定",
|
||||
"no_api_key": "未設定 Notion API Key 或 Notion Database ID"
|
||||
"no_api_key": "未設定 Notion API Key 或 Notion Database ID",
|
||||
"no_content": "沒有可匯出至 Notion 的內容"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "導出思源筆記失敗,請檢查連接狀態並對照文檔檢查配置",
|
||||
@ -1383,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "正在匯出到 Notion,請勿重複請求匯出!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "正在導出到思源筆記,請勿重複請求導出!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "正在導出語雀,請勿重複請求導出!"
|
||||
"export": {
|
||||
"exporting": "正在進行其他匯出,請等待上一次匯出完成後再試"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
|
||||
@ -648,6 +648,31 @@
|
||||
},
|
||||
"translate": "Μετάφραση"
|
||||
},
|
||||
"code": {
|
||||
"auto_update_to_latest": "Έλεγχος για ενημερώσεις και εγκατάσταση της τελευταίας έκδοσης",
|
||||
"bun_required_message": "Για τη λειτουργία του εργαλείου CLI πρέπει να εγκαταστήσετε το περιβάλλον Bun",
|
||||
"cli_tool": "Εργαλείο CLI",
|
||||
"cli_tool_placeholder": "Επιλέξτε το CLI εργαλείο που θέλετε να χρησιμοποιήσετε",
|
||||
"description": "Εκκίνηση γρήγορα πολλών εργαλείων CLI κώδικα, για αύξηση της αποδοτικότητας ανάπτυξης",
|
||||
"folder_placeholder": "Επιλέξτε κατάλογο εργασίας",
|
||||
"install_bun": "Εγκατάσταση Bun",
|
||||
"installing_bun": "Εγκατάσταση...",
|
||||
"launch": {
|
||||
"bun_required": "Παρακαλώ εγκαταστήστε πρώτα το περιβάλλον Bun πριν εκκινήσετε το εργαλείο CLI",
|
||||
"error": "Η εκκίνηση απέτυχε, παρακαλώ δοκιμάστε ξανά",
|
||||
"label": "Εκκίνηση",
|
||||
"success": "Επιτυχής εκκίνηση",
|
||||
"validation_error": "Συμπληρώστε όλα τα υποχρεωτικά πεδία: εργαλείο CLI, μοντέλο και κατάλογος εργασίας"
|
||||
},
|
||||
"launching": "Εκκίνηση...",
|
||||
"model": "μοντέλο",
|
||||
"model_placeholder": "Επιλέξτε το μοντέλο που θα χρησιμοποιήσετε",
|
||||
"model_required": "Επιλέξτε μοντέλο",
|
||||
"select_folder": "Επιλογή φακέλου",
|
||||
"title": "Εργαλεία κώδικα",
|
||||
"update_options": "Ενημέρωση επιλογών",
|
||||
"working_directory": "κατάλογος εργασίας"
|
||||
},
|
||||
"code_block": {
|
||||
"collapse": "συμπεριληφθείς",
|
||||
"copy": {
|
||||
@ -815,6 +840,9 @@
|
||||
"created": "Ημερομηνία Δημιουργίας",
|
||||
"last_updated": "Τελευταία ενημέρωση",
|
||||
"messages": "Αριθμός Μηνυμάτων",
|
||||
"notion": {
|
||||
"reasoning_truncated": "Η αλυσίδα σκέψης δεν μπορεί να διαιρεθεί, έχει κοπεί"
|
||||
},
|
||||
"user": "Χρήστης"
|
||||
},
|
||||
"files": {
|
||||
@ -1232,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "Σφάλμα στην εξαγωγή του Notion, παρακαλείστε να ελέγξετε τη σύνδεση και τη διαμόρφωση κατά τη διατύπωση του χειρισμού",
|
||||
"no_api_key": "Δεν έχετε διαθέσιμο το API Key του Notion ή το ID της βάσης του Notion"
|
||||
"no_api_key": "Δεν έχετε διαθέσιμο το API Key του Notion ή το ID της βάσης του Notion",
|
||||
"no_content": "Δεν υπάρχει περιεχόμενο για εξαγωγή στο Notion"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Η έκθεση σημειώσεων Siyuan απέτυχε, ελέγξτε την κατάσταση σύνδεσης και τις ρυθμίσεις σύμφωνα με τα έγγραφα",
|
||||
@ -1358,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "Εξαγωγή στο Notion, μην επαναλάβετε την διαδικασία εξαγωγής!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "Γίνεται εξαγωγή στις σημειώσεις Siyuan· μην ξαναζητήσετε την έκθεση!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "Γίνεται έκθεση Yuque· μην ξαναζητήσετε την έκθεση!"
|
||||
"export": {
|
||||
"exporting": "Παρακαλώ περιμένετε την ολοκλήρωση της προηγούμενης εξαγωγής. Εκτελείται άλλη εξαγωγή."
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
@ -2690,6 +2713,17 @@
|
||||
"title": "Εκκίνηση",
|
||||
"totray": "Εισαγωγή στην συνδρομή κατά την εκκίνηση"
|
||||
},
|
||||
"math": {
|
||||
"engine": {
|
||||
"label": "Μηχανισμός μαθηματικών τύπων",
|
||||
"none": "κανένα"
|
||||
},
|
||||
"single_dollar": {
|
||||
"label": "ενεργοποίηση $...$",
|
||||
"tip": "Επεξεργασία μαθηματικών τύπων που περικλείονται σε ένα μόνο σύμβολο δολαρίου $...$, προεπιλογή ενεργοποιημένη."
|
||||
},
|
||||
"title": "Ρύθμιση μαθηματικών τύπων"
|
||||
},
|
||||
"mcp": {
|
||||
"actions": "Ενέργειες",
|
||||
"active": "Ενεργοποίηση",
|
||||
@ -2920,10 +2954,6 @@
|
||||
"title": "Ρυθμίσεις εισαγωγής"
|
||||
},
|
||||
"markdown_rendering_input_message": "Markdown Rendering Input Message",
|
||||
"math_engine": {
|
||||
"label": "Μηχανική μαθηματικών εξισώσεων",
|
||||
"none": "Κανένα"
|
||||
},
|
||||
"metrics": "Χρόνος πρώτου χαρακτήρα {{time_first_token_millsec}}ms | {{token_speed}} tokens ανά δευτερόλεπτο",
|
||||
"model": {
|
||||
"title": "Ρυθμίσεις μοντέλου"
|
||||
@ -2935,6 +2965,7 @@
|
||||
"none": "Χωρίς εμφάνιση"
|
||||
},
|
||||
"prompt": "Λήμμα προτροπής",
|
||||
"show_message_outline": "Εμφάνιση πλαισίου μηνύματος",
|
||||
"title": "Ρυθμίσεις μηνυμάτων",
|
||||
"use_serif_font": "Χρήση μορφής Serif"
|
||||
},
|
||||
@ -3561,6 +3592,7 @@
|
||||
"title": {
|
||||
"agents": "Πράκτορες",
|
||||
"apps": "Εφαρμογές",
|
||||
"code": "Κώδικας",
|
||||
"files": "Αρχεία",
|
||||
"home": "Αρχική Σελίδα",
|
||||
"knowledge": "Βάση Γνώσης",
|
||||
|
||||
@ -648,6 +648,31 @@
|
||||
},
|
||||
"translate": "Traducir"
|
||||
},
|
||||
"code": {
|
||||
"auto_update_to_latest": "Comprobar actualizaciones e instalar la versión más reciente",
|
||||
"bun_required_message": "Se requiere instalar el entorno Bun para ejecutar la herramienta de línea de comandos",
|
||||
"cli_tool": "Herramienta de línea de comandos",
|
||||
"cli_tool_placeholder": "Seleccione la herramienta de línea de comandos que desea utilizar",
|
||||
"description": "Inicia rápidamente múltiples herramientas de línea de comandos para código, aumentando la eficiencia del desarrollo",
|
||||
"folder_placeholder": "Seleccionar directorio de trabajo",
|
||||
"install_bun": "Instalar Bun",
|
||||
"installing_bun": "Instalando...",
|
||||
"launch": {
|
||||
"bun_required": "Instale el entorno Bun antes de iniciar la herramienta de línea de comandos",
|
||||
"error": "Error al iniciar, intente nuevamente",
|
||||
"label": "Iniciar",
|
||||
"success": "Inicio exitoso",
|
||||
"validation_error": "Complete all required fields: CLI tool, model, and working directory"
|
||||
},
|
||||
"launching": "Iniciando...",
|
||||
"model": "modelo",
|
||||
"model_placeholder": "Seleccionar el modelo que se va a utilizar",
|
||||
"model_required": "Seleccione el modelo",
|
||||
"select_folder": "Seleccionar carpeta",
|
||||
"title": "Herramientas de código",
|
||||
"update_options": "Opciones de actualización",
|
||||
"working_directory": "directorio de trabajo"
|
||||
},
|
||||
"code_block": {
|
||||
"collapse": "Replegar",
|
||||
"copy": {
|
||||
@ -815,6 +840,9 @@
|
||||
"created": "Fecha de creación",
|
||||
"last_updated": "Última actualización",
|
||||
"messages": "Mensajes",
|
||||
"notion": {
|
||||
"reasoning_truncated": "La cadena de pensamiento no se puede dividir en bloques, ha sido truncada"
|
||||
},
|
||||
"user": "Usuario"
|
||||
},
|
||||
"files": {
|
||||
@ -1232,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "Error de exportación de Notion, verifique el estado de conexión y la configuración según la documentación",
|
||||
"no_api_key": "No se ha configurado la clave API de Notion o la ID de la base de datos de Notion"
|
||||
"no_api_key": "No se ha configurado la clave API de Notion o la ID de la base de datos de Notion",
|
||||
"no_content": "No hay contenido que exportar a Notion"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Error al exportar la nota de Siyuan, verifique el estado de la conexión y revise la configuración según la documentación",
|
||||
@ -1358,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "Se está exportando a Notion, ¡no solicite nuevamente la exportación!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "Exportando a Siyuan, ¡no solicite la exportación nuevamente!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "Exportando Yuque, ¡no solicite la exportación nuevamente!"
|
||||
"export": {
|
||||
"exporting": "Realizando otra exportación, espere a que finalice la anterior para intentarlo de nuevo"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
@ -2690,6 +2713,17 @@
|
||||
"title": "Inicio",
|
||||
"totray": "Minimizar a la bandeja al iniciar"
|
||||
},
|
||||
"math": {
|
||||
"engine": {
|
||||
"label": "Motor de fórmulas matemáticas",
|
||||
"none": "sin contenido"
|
||||
},
|
||||
"single_dollar": {
|
||||
"label": "habilitar $...$",
|
||||
"tip": "Renderiza fórmulas matemáticas encerradas entre un único símbolo de dólar $...$, habilitado por defecto."
|
||||
},
|
||||
"title": "Configuración de fórmulas matemáticas"
|
||||
},
|
||||
"mcp": {
|
||||
"actions": "Acciones",
|
||||
"active": "Activar",
|
||||
@ -2920,10 +2954,6 @@
|
||||
"title": "Configuración de entrada"
|
||||
},
|
||||
"markdown_rendering_input_message": "Renderizar mensajes de entrada en Markdown",
|
||||
"math_engine": {
|
||||
"label": "Motor de fórmulas matemáticas",
|
||||
"none": "Ninguno"
|
||||
},
|
||||
"metrics": "Retraso inicial {{time_first_token_millsec}}ms | {{token_speed}} tokens por segundo",
|
||||
"model": {
|
||||
"title": "Configuración del modelo"
|
||||
@ -2935,6 +2965,7 @@
|
||||
"none": "No mostrar"
|
||||
},
|
||||
"prompt": "Palabra de indicación",
|
||||
"show_message_outline": "Mostrar esquema del mensaje",
|
||||
"title": "Configuración de mensajes",
|
||||
"use_serif_font": "Usar fuente serif"
|
||||
},
|
||||
@ -3561,6 +3592,7 @@
|
||||
"title": {
|
||||
"agents": "Agentes",
|
||||
"apps": "Aplicaciones",
|
||||
"code": "Código",
|
||||
"files": "Archivos",
|
||||
"home": "Inicio",
|
||||
"knowledge": "Base de conocimiento",
|
||||
|
||||
@ -648,6 +648,31 @@
|
||||
},
|
||||
"translate": "Traduire"
|
||||
},
|
||||
"code": {
|
||||
"auto_update_to_latest": "Vérifier les mises à jour et installer la dernière version",
|
||||
"bun_required_message": "L'exécution de l'outil en ligne de commande nécessite l'installation de l'environnement Bun",
|
||||
"cli_tool": "Outil CLI",
|
||||
"cli_tool_placeholder": "Sélectionnez l'outil CLI à utiliser",
|
||||
"description": "Lancer rapidement plusieurs outils CLI de code pour améliorer l'efficacité du développement",
|
||||
"folder_placeholder": "Sélectionner le répertoire de travail",
|
||||
"install_bun": "Installer Bun",
|
||||
"installing_bun": "Installation en cours...",
|
||||
"launch": {
|
||||
"bun_required": "Veuillez d'abord installer l'environnement Bun avant de lancer l'outil en ligne de commande",
|
||||
"error": "Échec du démarrage, veuillez réessayer",
|
||||
"label": "Démarrer",
|
||||
"success": "Démarrage réussi",
|
||||
"validation_error": "Veuillez remplir tous les champs obligatoires : outil CLI, modèle et répertoire de travail"
|
||||
},
|
||||
"launching": "En cours de démarrage...",
|
||||
"model": "modèle",
|
||||
"model_placeholder": "Sélectionnez le modèle à utiliser",
|
||||
"model_required": "Veuillez sélectionner le modèle",
|
||||
"select_folder": "Sélectionner le dossier",
|
||||
"title": "Outils de code",
|
||||
"update_options": "Options de mise à jour",
|
||||
"working_directory": "répertoire de travail"
|
||||
},
|
||||
"code_block": {
|
||||
"collapse": "Réduire",
|
||||
"copy": {
|
||||
@ -815,6 +840,9 @@
|
||||
"created": "Date de création",
|
||||
"last_updated": "Dernière mise à jour",
|
||||
"messages": "Messages",
|
||||
"notion": {
|
||||
"reasoning_truncated": "La chaîne de pensée ne peut pas être fractionnée, elle a été tronquée."
|
||||
},
|
||||
"user": "Utilisateur"
|
||||
},
|
||||
"files": {
|
||||
@ -1232,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "Erreur lors de l'exportation vers Notion, veuillez vérifier l'état de la connexion et la configuration dans la documentation",
|
||||
"no_api_key": "Aucune clé API Notion ou ID de base de données Notion configurée"
|
||||
"no_api_key": "Aucune clé API Notion ou ID de base de données Notion configurée",
|
||||
"no_content": "Aucun contenu à exporter vers Notion"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Échec de l'exportation de la note Siyuan, veuillez vérifier l'état de la connexion et la configuration indiquée dans le document",
|
||||
@ -1358,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "Exportation en cours vers Notion, veuillez ne pas faire plusieurs demandes d'exportation!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "Exportation vers Siyuan en cours, veuillez ne pas demander à exporter à nouveau !"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "Exportation Yuque en cours, veuillez ne pas demander à exporter à nouveau !"
|
||||
"export": {
|
||||
"exporting": "Une autre exportation est en cours, veuillez patienter jusqu'à la fin de l'exportation précédente pour réessayer."
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
@ -2690,6 +2713,17 @@
|
||||
"title": "Démarrage",
|
||||
"totray": "Minimiser dans la barre d'état système au démarrage"
|
||||
},
|
||||
"math": {
|
||||
"engine": {
|
||||
"label": "Moteur de formules mathématiques",
|
||||
"none": "Aucun"
|
||||
},
|
||||
"single_dollar": {
|
||||
"label": "activer $...$",
|
||||
"tip": "Rendu des formules mathématiques encapsulées par un seul symbole dollar $...$, activé par défaut."
|
||||
},
|
||||
"title": "Configuration des formules mathématiques"
|
||||
},
|
||||
"mcp": {
|
||||
"actions": "Actions",
|
||||
"active": "Activer",
|
||||
@ -2920,10 +2954,6 @@
|
||||
"title": "Paramètres d'entrée"
|
||||
},
|
||||
"markdown_rendering_input_message": "Rendu Markdown des messages d'entrée",
|
||||
"math_engine": {
|
||||
"label": "Moteur de formules mathématiques",
|
||||
"none": "Aucun"
|
||||
},
|
||||
"metrics": "Latence initiale {{time_first_token_millsec}}ms | Vitesse de tokenisation {{token_speed}} tokens/s",
|
||||
"model": {
|
||||
"title": "Paramètres du modèle"
|
||||
@ -2935,6 +2965,7 @@
|
||||
"none": "Ne pas afficher"
|
||||
},
|
||||
"prompt": "Mot-clé d'affichage",
|
||||
"show_message_outline": "Afficher le plan du message",
|
||||
"title": "Paramètres des messages",
|
||||
"use_serif_font": "Utiliser une police serif"
|
||||
},
|
||||
@ -3561,6 +3592,7 @@
|
||||
"title": {
|
||||
"agents": "Agent intelligent",
|
||||
"apps": "Mini-programmes",
|
||||
"code": "Code",
|
||||
"files": "Fichiers",
|
||||
"home": "Page d'accueil",
|
||||
"knowledge": "Base de connaissances",
|
||||
|
||||
@ -648,6 +648,31 @@
|
||||
},
|
||||
"translate": "Traduzir"
|
||||
},
|
||||
"code": {
|
||||
"auto_update_to_latest": "Verificar atualizações e instalar a versão mais recente",
|
||||
"bun_required_message": "Executar a ferramenta CLI requer a instalação do ambiente Bun",
|
||||
"cli_tool": "Ferramenta de linha de comando",
|
||||
"cli_tool_placeholder": "Selecione a ferramenta de linha de comando a ser utilizada",
|
||||
"description": "Inicie rapidamente várias ferramentas de linha de comando de código, aumentando a eficiência do desenvolvimento",
|
||||
"folder_placeholder": "Selecionar diretório de trabalho",
|
||||
"install_bun": "Instalar o Bun",
|
||||
"installing_bun": "Instalando...",
|
||||
"launch": {
|
||||
"bun_required": "Instale o ambiente Bun antes de iniciar a ferramenta de linha de comando",
|
||||
"error": "Falha ao iniciar, tente novamente",
|
||||
"label": "iniciar",
|
||||
"success": "Início bem-sucedido",
|
||||
"validation_error": "Preencha todos os campos obrigatórios: ferramenta CLI, modelo e diretório de trabalho"
|
||||
},
|
||||
"launching": "Iniciando...",
|
||||
"model": "modelo",
|
||||
"model_placeholder": "Selecione o modelo a ser utilizado",
|
||||
"model_required": "Selecione o modelo",
|
||||
"select_folder": "Selecionar pasta",
|
||||
"title": "Ferramenta de código",
|
||||
"update_options": "Opções de atualização",
|
||||
"working_directory": "diretório de trabalho"
|
||||
},
|
||||
"code_block": {
|
||||
"collapse": "Recolher",
|
||||
"copy": {
|
||||
@ -815,6 +840,9 @@
|
||||
"created": "Criado em",
|
||||
"last_updated": "Última Atualização",
|
||||
"messages": "Mensagens",
|
||||
"notion": {
|
||||
"reasoning_truncated": "A cadeia de pensamento não pode ser dividida em partes, foi interrompida"
|
||||
},
|
||||
"user": "Usuário"
|
||||
},
|
||||
"files": {
|
||||
@ -1232,7 +1260,8 @@
|
||||
},
|
||||
"notion": {
|
||||
"export": "Erro ao exportar Notion, verifique o status da conexão e a configuração de acordo com a documentação",
|
||||
"no_api_key": "API Key ou Notion Database ID não configurados"
|
||||
"no_api_key": "API Key ou Notion Database ID não configurados",
|
||||
"no_content": "Nenhum conteúdo para exportar para o Notion"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Falha ao exportar nota do Siyuan, verifique o estado da conexão e confira a configuração no documento",
|
||||
@ -1358,14 +1387,8 @@
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"notion": {
|
||||
"exporting": "Exportando para Notion, não solicite novamente a exportação!"
|
||||
},
|
||||
"siyuan": {
|
||||
"exporting": "Exportando para o Siyuan, por favor não solicite a exportação novamente!"
|
||||
},
|
||||
"yuque": {
|
||||
"exporting": "Exportando para Yuque, por favor não solicite a exportação novamente!"
|
||||
"export": {
|
||||
"exporting": "A exportação de outros arquivos está em andamento, aguarde a conclusão da exportação anterior e tente novamente."
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
@ -2690,6 +2713,17 @@
|
||||
"title": "Inicialização",
|
||||
"totray": "Minimizar para bandeja ao iniciar"
|
||||
},
|
||||
"math": {
|
||||
"engine": {
|
||||
"label": "Motor de fórmulas matemáticas",
|
||||
"none": "sem conteúdo"
|
||||
},
|
||||
"single_dollar": {
|
||||
"label": "ativar $...$",
|
||||
"tip": "Renderiza fórmulas matemáticas delimitadas por um único sinal de dólar $...$, habilitado por padrão."
|
||||
},
|
||||
"title": "Configuração de fórmulas matemáticas"
|
||||
},
|
||||
"mcp": {
|
||||
"actions": "Ações",
|
||||
"active": "Ativar",
|
||||
@ -2920,10 +2954,6 @@
|
||||
"title": "Configurações de entrada"
|
||||
},
|
||||
"markdown_rendering_input_message": "Renderização de markdown na entrada de mensagens",
|
||||
"math_engine": {
|
||||
"label": "Motor de fórmulas matemáticas",
|
||||
"none": "Nenhum"
|
||||
},
|
||||
"metrics": "Atraso inicial {{time_first_token_millsec}}ms | Taxa de token por segundo {{token_speed}} tokens",
|
||||
"model": {
|
||||
"title": "Configurações de modelo"
|
||||
@ -2935,6 +2965,7 @@
|
||||
"none": "Não mostrar"
|
||||
},
|
||||
"prompt": "Exibir palavra-chave",
|
||||
"show_message_outline": "Exibir esboço da mensagem",
|
||||
"title": "Configurações de mensagem",
|
||||
"use_serif_font": "Usar fonte serif"
|
||||
},
|
||||
@ -3561,6 +3592,7 @@
|
||||
"title": {
|
||||
"agents": "Agentes",
|
||||
"apps": "Miniaplicativos",
|
||||
"code": "Código",
|
||||
"files": "Arquivos",
|
||||
"home": "Página Inicial",
|
||||
"knowledge": "Base de Conhecimento",
|
||||
|
||||
@ -12,10 +12,112 @@ import { convertMathFormula, markdownToPlainText } from '@renderer/utils/markdow
|
||||
import { getCitationContent, getMainTextContent, getThinkingContent } from '@renderer/utils/messageUtils/find'
|
||||
import { markdownToBlocks } from '@tryfabric/martian'
|
||||
import dayjs from 'dayjs'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { appendBlocks } from 'notion-helper' // 引入 notion-helper 的 appendBlocks 函数
|
||||
|
||||
const logger = loggerService.withContext('Utils:export')
|
||||
|
||||
// 全局的导出状态获取函数
|
||||
const getExportState = () => store.getState().runtime.export.isExporting
|
||||
|
||||
// 全局的导出状态设置函数,使用 dispatch 保障 Redux 状态更新正确
|
||||
const setExportingState = (isExporting: boolean) => {
|
||||
store.dispatch(setExportState({ isExporting }))
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地处理思维链内容,保留安全的 HTML 标签如 <br>,移除危险内容
|
||||
*
|
||||
* 支持的标签:
|
||||
* - 结构:br, p, div, span, h1-h6, blockquote
|
||||
* - 格式:strong, b, em, i, u, s, del, mark, small, sup, sub
|
||||
* - 列表:ul, ol, li
|
||||
* - 代码:code, pre, kbd, var, samp
|
||||
* - 表格:table, thead, tbody, tfoot, tr, td, th
|
||||
*
|
||||
* @param content 原始思维链内容
|
||||
* @returns 安全处理后的内容
|
||||
*/
|
||||
const sanitizeReasoningContent = (content: string): string => {
|
||||
// 先处理换行符转换为 <br>
|
||||
const contentWithBr = content.replace(/\n/g, '<br>')
|
||||
|
||||
// 使用 DOMPurify 清理内容,保留常用的安全标签和属性
|
||||
const cleanContent = DOMPurify.sanitize(contentWithBr, {
|
||||
ALLOWED_TAGS: [
|
||||
// 换行和基础结构
|
||||
'br',
|
||||
'p',
|
||||
'div',
|
||||
'span',
|
||||
// 文本格式化
|
||||
'strong',
|
||||
'b',
|
||||
'em',
|
||||
'i',
|
||||
'u',
|
||||
's',
|
||||
'del',
|
||||
'mark',
|
||||
'small',
|
||||
// 上标下标(数学公式、引用等)
|
||||
'sup',
|
||||
'sub',
|
||||
// 标题
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
// 引用
|
||||
'blockquote',
|
||||
// 列表
|
||||
'ul',
|
||||
'ol',
|
||||
'li',
|
||||
// 代码相关
|
||||
'code',
|
||||
'pre',
|
||||
'kbd',
|
||||
'var',
|
||||
'samp',
|
||||
// 表格(AI输出中可能包含表格)
|
||||
'table',
|
||||
'thead',
|
||||
'tbody',
|
||||
'tfoot',
|
||||
'tr',
|
||||
'td',
|
||||
'th',
|
||||
// 分隔线
|
||||
'hr'
|
||||
],
|
||||
ALLOWED_ATTR: [
|
||||
// 安全的通用属性
|
||||
'class',
|
||||
'title',
|
||||
'lang',
|
||||
'dir',
|
||||
// code 标签的语言属性
|
||||
'data-language',
|
||||
// 表格属性
|
||||
'colspan',
|
||||
'rowspan',
|
||||
// 列表属性
|
||||
'start',
|
||||
'type'
|
||||
],
|
||||
KEEP_CONTENT: true, // 保留被移除标签的文本内容
|
||||
RETURN_DOM: false,
|
||||
SANITIZE_DOM: true,
|
||||
// 允许的协议(预留,虽然目前没有允许链接标签)
|
||||
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?):|[^a-z]|[a-z+.-]+(?:[^a-z+.-:]|$))/i
|
||||
})
|
||||
|
||||
return cleanContent
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取话题的消息列表,使用TopicManager确保消息被正确加载
|
||||
* 这样可以避免从未打开过的话题导出为空的问题
|
||||
@ -33,7 +135,7 @@ async function fetchTopicMessages(topicId: string): Promise<Message[]> {
|
||||
* @param {number} [length=80] 标题最大长度,默认为 80
|
||||
* @returns {string} 提取的标题
|
||||
*/
|
||||
export function getTitleFromString(str: string, length: number = 80) {
|
||||
export function getTitleFromString(str: string, length: number = 80): string {
|
||||
let title = str.trimStart().split('\n')[0]
|
||||
|
||||
if (title.includes('。')) {
|
||||
@ -57,7 +159,7 @@ export function getTitleFromString(str: string, length: number = 80) {
|
||||
return title
|
||||
}
|
||||
|
||||
const getRoleText = (role: string, modelName?: string, providerId?: string) => {
|
||||
const getRoleText = (role: string, modelName?: string, providerId?: string): string => {
|
||||
const { showModelNameInMarkdown, showModelProviderInMarkdown } = store.getState().settings
|
||||
|
||||
if (role === 'user') {
|
||||
@ -166,7 +268,7 @@ const createBaseMarkdown = (
|
||||
includeReasoning: boolean = false,
|
||||
excludeCitations: boolean = false,
|
||||
normalizeCitations: boolean = true
|
||||
) => {
|
||||
): { titleSection: string; reasoningSection: string; contentSection: string; citation: string } => {
|
||||
const { forceDollarMathInMarkdown } = store.getState().settings
|
||||
const roleText = getRoleText(message.role, message.model?.name, message.model?.provider)
|
||||
const titleSection = `## ${roleText}`
|
||||
@ -180,13 +282,8 @@ const createBaseMarkdown = (
|
||||
} else if (reasoningContent.startsWith('<think>')) {
|
||||
reasoningContent = reasoningContent.substring(7)
|
||||
}
|
||||
reasoningContent = reasoningContent
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/\n/g, '<br>')
|
||||
// 使用 DOMPurify 安全地处理思维链内容
|
||||
reasoningContent = sanitizeReasoningContent(reasoningContent)
|
||||
if (forceDollarMathInMarkdown) {
|
||||
reasoningContent = convertMathFormula(reasoningContent)
|
||||
}
|
||||
@ -216,7 +313,7 @@ const createBaseMarkdown = (
|
||||
return { titleSection, reasoningSection, contentSection: processedContent, citation }
|
||||
}
|
||||
|
||||
export const messageToMarkdown = (message: Message, excludeCitations?: boolean) => {
|
||||
export const messageToMarkdown = (message: Message, excludeCitations?: boolean): string => {
|
||||
const { excludeCitationsInExport, standardizeCitationsInExport } = store.getState().settings
|
||||
const shouldExcludeCitations = excludeCitations ?? excludeCitationsInExport
|
||||
const { titleSection, contentSection, citation } = createBaseMarkdown(
|
||||
@ -228,7 +325,7 @@ export const messageToMarkdown = (message: Message, excludeCitations?: boolean)
|
||||
return [titleSection, '', contentSection, citation].join('\n')
|
||||
}
|
||||
|
||||
export const messageToMarkdownWithReasoning = (message: Message, excludeCitations?: boolean) => {
|
||||
export const messageToMarkdownWithReasoning = (message: Message, excludeCitations?: boolean): string => {
|
||||
const { excludeCitationsInExport, standardizeCitationsInExport } = store.getState().settings
|
||||
const shouldExcludeCitations = excludeCitations ?? excludeCitationsInExport
|
||||
const { titleSection, reasoningSection, contentSection, citation } = createBaseMarkdown(
|
||||
@ -237,10 +334,14 @@ export const messageToMarkdownWithReasoning = (message: Message, excludeCitation
|
||||
shouldExcludeCitations,
|
||||
standardizeCitationsInExport
|
||||
)
|
||||
return [titleSection, '', reasoningSection + contentSection, citation].join('\n')
|
||||
return [titleSection, '', reasoningSection, contentSection, citation].join('\n')
|
||||
}
|
||||
|
||||
export const messagesToMarkdown = (messages: Message[], exportReasoning?: boolean, excludeCitations?: boolean) => {
|
||||
export const messagesToMarkdown = (
|
||||
messages: Message[],
|
||||
exportReasoning?: boolean,
|
||||
excludeCitations?: boolean
|
||||
): string => {
|
||||
return messages
|
||||
.map((message) =>
|
||||
exportReasoning
|
||||
@ -266,7 +367,11 @@ const messagesToPlainText = (messages: Message[]): string => {
|
||||
return messages.map(formatMessageAsPlainText).join('\n\n')
|
||||
}
|
||||
|
||||
export const topicToMarkdown = async (topic: Topic, exportReasoning?: boolean, excludeCitations?: boolean) => {
|
||||
export const topicToMarkdown = async (
|
||||
topic: Topic,
|
||||
exportReasoning?: boolean,
|
||||
excludeCitations?: boolean
|
||||
): Promise<string> => {
|
||||
const topicName = `# ${topic.name}`
|
||||
|
||||
const messages = await fetchTopicMessages(topic.id)
|
||||
@ -290,7 +395,18 @@ export const topicToPlainText = async (topic: Topic): Promise<string> => {
|
||||
return topicName
|
||||
}
|
||||
|
||||
export const exportTopicAsMarkdown = async (topic: Topic, exportReasoning?: boolean, excludeCitations?: boolean) => {
|
||||
export const exportTopicAsMarkdown = async (
|
||||
topic: Topic,
|
||||
exportReasoning?: boolean,
|
||||
excludeCitations?: boolean
|
||||
): Promise<void> => {
|
||||
if (getExportState()) {
|
||||
window.message.warning({ content: i18n.t('message.warn.export.exporting'), key: 'markdown-exporting' })
|
||||
return
|
||||
}
|
||||
|
||||
setExportingState(true)
|
||||
|
||||
const { markdownExportPath } = store.getState().settings
|
||||
if (!markdownExportPath) {
|
||||
try {
|
||||
@ -305,7 +421,9 @@ export const exportTopicAsMarkdown = async (topic: Topic, exportReasoning?: bool
|
||||
}
|
||||
} catch (error: any) {
|
||||
window.message.error({ content: i18n.t('message.error.markdown.export.specified'), key: 'markdown-error' })
|
||||
logger.debug(error)
|
||||
logger.error('Failed to export topic as markdown:', error)
|
||||
} finally {
|
||||
setExportingState(false)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@ -316,7 +434,9 @@ export const exportTopicAsMarkdown = async (topic: Topic, exportReasoning?: bool
|
||||
window.message.success({ content: i18n.t('message.success.markdown.export.preconf'), key: 'markdown-success' })
|
||||
} catch (error: any) {
|
||||
window.message.error({ content: i18n.t('message.error.markdown.export.preconf'), key: 'markdown-error' })
|
||||
logger.debug(error)
|
||||
logger.error('Failed to export topic as markdown:', error)
|
||||
} finally {
|
||||
setExportingState(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -325,7 +445,14 @@ export const exportMessageAsMarkdown = async (
|
||||
message: Message,
|
||||
exportReasoning?: boolean,
|
||||
excludeCitations?: boolean
|
||||
) => {
|
||||
): Promise<void> => {
|
||||
if (getExportState()) {
|
||||
window.message.warning({ content: i18n.t('message.warn.export.exporting'), key: 'markdown-exporting' })
|
||||
return
|
||||
}
|
||||
|
||||
setExportingState(true)
|
||||
|
||||
const { markdownExportPath } = store.getState().settings
|
||||
if (!markdownExportPath) {
|
||||
try {
|
||||
@ -343,7 +470,9 @@ export const exportMessageAsMarkdown = async (
|
||||
}
|
||||
} catch (error: any) {
|
||||
window.message.error({ content: i18n.t('message.error.markdown.export.specified'), key: 'markdown-error' })
|
||||
logger.debug(error)
|
||||
logger.error('Failed to export message as markdown:', error)
|
||||
} finally {
|
||||
setExportingState(false)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@ -357,12 +486,14 @@ export const exportMessageAsMarkdown = async (
|
||||
window.message.success({ content: i18n.t('message.success.markdown.export.preconf'), key: 'markdown-success' })
|
||||
} catch (error: any) {
|
||||
window.message.error({ content: i18n.t('message.error.markdown.export.preconf'), key: 'markdown-error' })
|
||||
logger.debug(error)
|
||||
logger.error('Failed to export message as markdown:', error)
|
||||
} finally {
|
||||
setExportingState(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const convertMarkdownToNotionBlocks = async (markdown: string) => {
|
||||
const convertMarkdownToNotionBlocks = async (markdown: string): Promise<any[]> => {
|
||||
return markdownToBlocks(markdown)
|
||||
}
|
||||
|
||||
@ -371,77 +502,109 @@ const convertThinkingToNotionBlocks = async (thinkingContent: string): Promise<a
|
||||
return []
|
||||
}
|
||||
|
||||
const thinkingBlocks = [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'toggle',
|
||||
toggle: {
|
||||
rich_text: [
|
||||
{
|
||||
type: 'text',
|
||||
text: {
|
||||
content: '🤔 ' + i18n.t('common.reasoning_content')
|
||||
},
|
||||
annotations: {
|
||||
bold: true
|
||||
}
|
||||
}
|
||||
],
|
||||
children: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
paragraph: {
|
||||
rich_text: [
|
||||
{
|
||||
type: 'text',
|
||||
text: {
|
||||
content: thinkingContent
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
try {
|
||||
// 预处理思维链内容:将HTML的<br>标签转换为真正的换行符
|
||||
const processedContent = thinkingContent.replace(/<br\s*\/?>/g, '\n')
|
||||
|
||||
return thinkingBlocks
|
||||
// 使用 markdownToBlocks 处理思维链内容
|
||||
const childrenBlocks = markdownToBlocks(processedContent)
|
||||
|
||||
return [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'toggle',
|
||||
toggle: {
|
||||
rich_text: [
|
||||
{
|
||||
type: 'text',
|
||||
text: {
|
||||
content: '🤔 ' + i18n.t('common.reasoning_content')
|
||||
},
|
||||
annotations: {
|
||||
bold: true
|
||||
}
|
||||
}
|
||||
],
|
||||
children: childrenBlocks
|
||||
}
|
||||
}
|
||||
]
|
||||
} catch (error) {
|
||||
logger.error('failed to process reasoning content:', error as Error)
|
||||
// 发生错误时,回退到简单的段落处理
|
||||
return [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'toggle',
|
||||
toggle: {
|
||||
rich_text: [
|
||||
{
|
||||
type: 'text',
|
||||
text: {
|
||||
content: '🤔 ' + i18n.t('common.reasoning_content')
|
||||
},
|
||||
annotations: {
|
||||
bold: true
|
||||
}
|
||||
}
|
||||
],
|
||||
children: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
paragraph: {
|
||||
rich_text: [
|
||||
{
|
||||
type: 'text',
|
||||
text: {
|
||||
content:
|
||||
thinkingContent.length > 1800
|
||||
? thinkingContent.substring(0, 1800) + '...\n' + i18n.t('export.notion.reasoning_truncated')
|
||||
: thinkingContent
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const executeNotionExport = async (title: string, allBlocks: any[]): Promise<any> => {
|
||||
const { isExporting } = store.getState().runtime.export
|
||||
if (isExporting) {
|
||||
window.message.warning({ content: i18n.t('message.warn.notion.exporting'), key: 'notion-exporting' })
|
||||
return null
|
||||
const executeNotionExport = async (title: string, allBlocks: any[]): Promise<boolean> => {
|
||||
if (getExportState()) {
|
||||
window.message.warning({ content: i18n.t('message.warn.export.exporting'), key: 'notion-exporting' })
|
||||
return false
|
||||
}
|
||||
|
||||
setExportState({ isExporting: true })
|
||||
|
||||
title = title.slice(0, 29) + '...'
|
||||
|
||||
const { notionDatabaseID, notionApiKey } = store.getState().settings
|
||||
if (!notionApiKey || !notionDatabaseID) {
|
||||
window.message.error({ content: i18n.t('message.error.notion.no_api_key'), key: 'notion-no-apikey-error' })
|
||||
setExportState({ isExporting: false })
|
||||
return null
|
||||
return false
|
||||
}
|
||||
|
||||
if (allBlocks.length === 0) {
|
||||
window.message.error({ content: i18n.t('message.error.notion.export'), key: 'notion-no-content-error' })
|
||||
return false
|
||||
}
|
||||
|
||||
setExportingState(true)
|
||||
|
||||
// 限制标题长度
|
||||
if (title.length > 32) {
|
||||
title = title.slice(0, 29) + '...'
|
||||
}
|
||||
|
||||
try {
|
||||
const notion = new Client({ auth: notionApiKey })
|
||||
|
||||
if (allBlocks.length === 0) {
|
||||
throw new Error('No content to export')
|
||||
}
|
||||
|
||||
window.message.loading({
|
||||
content: i18n.t('message.loading.notion.preparing'),
|
||||
key: 'notion-preparing',
|
||||
duration: 0
|
||||
})
|
||||
let mainPageResponse: any = null
|
||||
let parentBlockId: string | null = null
|
||||
|
||||
const response = await notion.pages.create({
|
||||
parent: { database_id: notionDatabaseID },
|
||||
@ -451,34 +614,37 @@ const executeNotionExport = async (title: string, allBlocks: any[]): Promise<any
|
||||
}
|
||||
}
|
||||
})
|
||||
mainPageResponse = response
|
||||
parentBlockId = response.id
|
||||
|
||||
window.message.destroy('notion-preparing')
|
||||
window.message.loading({
|
||||
content: i18n.t('message.loading.notion.exporting_progress'),
|
||||
key: 'notion-exporting',
|
||||
duration: 0
|
||||
})
|
||||
if (allBlocks.length > 0) {
|
||||
await appendBlocks({
|
||||
block_id: parentBlockId,
|
||||
children: allBlocks,
|
||||
client: notion
|
||||
})
|
||||
}
|
||||
|
||||
await appendBlocks({
|
||||
block_id: response.id,
|
||||
children: allBlocks,
|
||||
client: notion
|
||||
})
|
||||
|
||||
window.message.destroy('notion-exporting')
|
||||
window.message.success({ content: i18n.t('message.success.notion.export'), key: 'notion-success' })
|
||||
return mainPageResponse
|
||||
return true
|
||||
} catch (error: any) {
|
||||
window.message.error({ content: i18n.t('message.error.notion.export'), key: 'notion-export-progress' })
|
||||
logger.debug(error)
|
||||
return null
|
||||
// 清理可能存在的loading消息
|
||||
window.message.destroy('notion-preparing')
|
||||
window.message.destroy('notion-exporting')
|
||||
|
||||
logger.error('Notion export failed:', error)
|
||||
window.message.error({ content: i18n.t('message.error.notion.export'), key: 'notion-export-error' })
|
||||
return false
|
||||
} finally {
|
||||
setExportState({ isExporting: false })
|
||||
setExportingState(false)
|
||||
}
|
||||
}
|
||||
|
||||
export const exportMessageToNotion = async (title: string, content: string, message?: Message) => {
|
||||
export const exportMessageToNotion = async (title: string, content: string, message?: Message): Promise<boolean> => {
|
||||
const { notionExportReasoning } = store.getState().settings
|
||||
|
||||
const notionBlocks = await convertMarkdownToNotionBlocks(content)
|
||||
@ -498,7 +664,7 @@ export const exportMessageToNotion = async (title: string, content: string, mess
|
||||
return executeNotionExport(title, notionBlocks)
|
||||
}
|
||||
|
||||
export const exportTopicToNotion = async (topic: Topic) => {
|
||||
export const exportTopicToNotion = async (topic: Topic): Promise<boolean> => {
|
||||
const { notionExportReasoning, excludeCitationsInExport } = store.getState().settings
|
||||
|
||||
const topicMessages = await fetchTopicMessages(topic.id)
|
||||
@ -532,12 +698,11 @@ export const exportTopicToNotion = async (topic: Topic) => {
|
||||
return executeNotionExport(topic.name, allBlocks)
|
||||
}
|
||||
|
||||
export const exportMarkdownToYuque = async (title: string, content: string) => {
|
||||
const { isExporting } = store.getState().runtime.export
|
||||
export const exportMarkdownToYuque = async (title: string, content: string): Promise<any | null> => {
|
||||
const { yuqueToken, yuqueRepoId } = store.getState().settings
|
||||
|
||||
if (isExporting) {
|
||||
window.message.warning({ content: i18n.t('message.warn.yuque.exporting'), key: 'yuque-exporting' })
|
||||
if (getExportState()) {
|
||||
window.message.warning({ content: i18n.t('message.warn.export.exporting'), key: 'yuque-exporting' })
|
||||
return
|
||||
}
|
||||
|
||||
@ -546,7 +711,7 @@ export const exportMarkdownToYuque = async (title: string, content: string) => {
|
||||
return
|
||||
}
|
||||
|
||||
setExportState({ isExporting: true })
|
||||
setExportingState(true)
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://www.yuque.com/api/v2/repos/${yuqueRepoId}/docs`, {
|
||||
@ -602,7 +767,7 @@ export const exportMarkdownToYuque = async (title: string, content: string) => {
|
||||
})
|
||||
return null
|
||||
} finally {
|
||||
setExportState({ isExporting: false })
|
||||
setExportingState(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,7 +782,14 @@ export const exportMarkdownToYuque = async (title: string, content: string) => {
|
||||
* @param attributes.folder 选择的文件夹路径或文件路径
|
||||
* @param attributes.vault 选择的Vault名称
|
||||
*/
|
||||
export const exportMarkdownToObsidian = async (attributes: any) => {
|
||||
export const exportMarkdownToObsidian = async (attributes: any): Promise<void> => {
|
||||
if (getExportState()) {
|
||||
window.message.warning({ content: i18n.t('message.warn.export.exporting'), key: 'obsidian-exporting' })
|
||||
return
|
||||
}
|
||||
|
||||
setExportingState(true)
|
||||
|
||||
try {
|
||||
// 从参数获取Vault名称
|
||||
const obsidianVault = attributes.vault
|
||||
@ -669,8 +841,10 @@ export const exportMarkdownToObsidian = async (attributes: any) => {
|
||||
window.open(obsidianUrl)
|
||||
window.message.success(i18n.t('chat.topics.export.obsidian_export_success'))
|
||||
} catch (error) {
|
||||
logger.error('导出到Obsidian失败:', error as Error)
|
||||
logger.error('Failed to export to Obsidian:', error as Error)
|
||||
window.message.error(i18n.t('chat.topics.export.obsidian_export_failed'))
|
||||
} finally {
|
||||
setExportingState(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -719,14 +893,24 @@ function transformObsidianFileName(fileName: string): string {
|
||||
return sanitized
|
||||
}
|
||||
|
||||
export const exportMarkdownToJoplin = async (title: string, contentOrMessages: string | Message | Message[]) => {
|
||||
export const exportMarkdownToJoplin = async (
|
||||
title: string,
|
||||
contentOrMessages: string | Message | Message[]
|
||||
): Promise<any | null> => {
|
||||
const { joplinUrl, joplinToken, joplinExportReasoning, excludeCitationsInExport } = store.getState().settings
|
||||
|
||||
if (getExportState()) {
|
||||
window.message.warning({ content: i18n.t('message.warn.export.exporting'), key: 'joplin-exporting' })
|
||||
return
|
||||
}
|
||||
|
||||
if (!joplinUrl || !joplinToken) {
|
||||
window.message.error(i18n.t('message.error.joplin.no_config'))
|
||||
return
|
||||
}
|
||||
|
||||
setExportingState(true)
|
||||
|
||||
let content: string
|
||||
if (typeof contentOrMessages === 'string') {
|
||||
content = contentOrMessages
|
||||
@ -763,11 +947,13 @@ export const exportMarkdownToJoplin = async (title: string, contentOrMessages: s
|
||||
}
|
||||
|
||||
window.message.success(i18n.t('message.success.joplin.export'))
|
||||
return
|
||||
return data
|
||||
} catch (error: any) {
|
||||
logger.error('Failed to export to Joplin:', error)
|
||||
window.message.error(i18n.t('message.error.joplin.export'))
|
||||
logger.debug(error)
|
||||
return
|
||||
return null
|
||||
} finally {
|
||||
setExportingState(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -776,12 +962,11 @@ export const exportMarkdownToJoplin = async (title: string, contentOrMessages: s
|
||||
* @param title 笔记标题
|
||||
* @param content 笔记内容
|
||||
*/
|
||||
export const exportMarkdownToSiyuan = async (title: string, content: string) => {
|
||||
const { isExporting } = store.getState().runtime.export
|
||||
export const exportMarkdownToSiyuan = async (title: string, content: string): Promise<void> => {
|
||||
const { siyuanApiUrl, siyuanToken, siyuanBoxId, siyuanRootPath } = store.getState().settings
|
||||
|
||||
if (isExporting) {
|
||||
window.message.warning({ content: i18n.t('message.warn.siyuan.exporting'), key: 'siyuan-exporting' })
|
||||
if (getExportState()) {
|
||||
window.message.warning({ content: i18n.t('message.warn.export.exporting'), key: 'siyuan-exporting' })
|
||||
return
|
||||
}
|
||||
|
||||
@ -790,7 +975,7 @@ export const exportMarkdownToSiyuan = async (title: string, content: string) =>
|
||||
return
|
||||
}
|
||||
|
||||
setExportState({ isExporting: true })
|
||||
setExportingState(true)
|
||||
|
||||
try {
|
||||
// test connection
|
||||
@ -826,13 +1011,13 @@ export const exportMarkdownToSiyuan = async (title: string, content: string) =>
|
||||
key: 'siyuan-success'
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('导出到思源笔记失败:', error as Error)
|
||||
logger.error('Failed to export to Siyuan:', error as Error)
|
||||
window.message.error({
|
||||
content: i18n.t('message.error.siyuan.export') + (error instanceof Error ? `: ${error.message}` : ''),
|
||||
key: 'siyuan-error'
|
||||
})
|
||||
} finally {
|
||||
setExportState({ isExporting: false })
|
||||
setExportingState(false)
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
||||
@ -8552,7 +8552,6 @@ __metadata:
|
||||
dexie-react-hooks: "npm:^1.1.7"
|
||||
diff: "npm:^7.0.0"
|
||||
docx: "npm:^9.0.2"
|
||||
dompurify: "npm:^3.2.6"
|
||||
dotenv-cli: "npm:^7.4.2"
|
||||
electron: "npm:37.2.3"
|
||||
electron-builder: "npm:26.0.15"
|
||||
@ -11446,7 +11445,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dompurify@npm:^3.2.5, dompurify@npm:^3.2.6":
|
||||
"dompurify@npm:^3.2.5":
|
||||
version: 3.2.6
|
||||
resolution: "dompurify@npm:3.2.6"
|
||||
dependencies:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user