feat: export to word
This commit is contained in:
parent
e33d9ac0ae
commit
04af940144
@ -39,12 +39,14 @@
|
||||
"@electron-toolkit/preload": "^3.0.0",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"archiver": "^7.0.1",
|
||||
"docx": "^9.0.2",
|
||||
"electron-log": "^5.1.5",
|
||||
"electron-store": "^8.2.0",
|
||||
"electron-updater": "^6.3.9",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"fs-extra": "^11.2.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"markdown-it": "^14.1.0",
|
||||
"officeparser": "^4.1.1",
|
||||
"sharp": "^0.33.5",
|
||||
"unzipper": "^0.12.3",
|
||||
@ -61,6 +63,7 @@
|
||||
"@reduxjs/toolkit": "^2.2.5",
|
||||
"@types/fs-extra": "^11",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/markdown-it": "^14",
|
||||
"@types/node": "^18.19.9",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
|
||||
@ -5,17 +5,18 @@ import { BrowserWindow, ipcMain, session, shell } from 'electron'
|
||||
import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config'
|
||||
import AppUpdater from './services/AppUpdater'
|
||||
import BackupManager from './services/BackupManager'
|
||||
import { ExportService } from './services/ExportService'
|
||||
import FileManager from './services/FileManager'
|
||||
import { compress, decompress } from './utils/zip'
|
||||
import { createMinappWindow } from './window'
|
||||
|
||||
const fileManager = new FileManager()
|
||||
const backupManager = new BackupManager()
|
||||
const exportService = new ExportService(fileManager)
|
||||
|
||||
export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
||||
const { autoUpdater } = new AppUpdater(mainWindow)
|
||||
|
||||
// IPC
|
||||
ipcMain.handle('app:info', () => ({
|
||||
version: app.getVersion(),
|
||||
isPackaged: app.isPackaged,
|
||||
@ -33,13 +34,17 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
||||
|
||||
ipcMain.handle('reload', () => mainWindow.reload())
|
||||
|
||||
// zip
|
||||
ipcMain.handle('zip:compress', (_, text: string) => compress(text))
|
||||
ipcMain.handle('zip:decompress', (_, text: Buffer) => decompress(text))
|
||||
|
||||
// backup
|
||||
ipcMain.handle('backup:backup', backupManager.backup)
|
||||
ipcMain.handle('backup:restore', backupManager.restore)
|
||||
ipcMain.handle('backup:backupToWebdav', backupManager.backupToWebdav)
|
||||
ipcMain.handle('backup:restoreFromWebdav', backupManager.restoreFromWebdav)
|
||||
|
||||
// file
|
||||
ipcMain.handle('file:open', fileManager.open)
|
||||
ipcMain.handle('file:save', fileManager.save)
|
||||
ipcMain.handle('file:select', fileManager.selectFile)
|
||||
@ -54,7 +59,9 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
||||
ipcMain.handle('file:saveImage', fileManager.saveImage)
|
||||
ipcMain.handle('file:base64Image', fileManager.base64Image)
|
||||
ipcMain.handle('file:download', fileManager.downloadFile)
|
||||
ipcMain.handle('file:copy', fileManager.copyFile)
|
||||
|
||||
// minapp
|
||||
ipcMain.handle('minapp', (_, args) => {
|
||||
createMinappWindow({
|
||||
url: args.url,
|
||||
@ -66,6 +73,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
||||
})
|
||||
})
|
||||
|
||||
// theme
|
||||
ipcMain.handle('set-theme', (_, theme: 'light' | 'dark') => {
|
||||
appConfig.set('theme', theme)
|
||||
mainWindow?.setTitleBarOverlay &&
|
||||
@ -79,4 +87,6 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
||||
update: await autoUpdater.checkForUpdates()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('export:word', exportService.exportToWord)
|
||||
}
|
||||
|
||||
222
src/main/services/ExportService.ts
Normal file
222
src/main/services/ExportService.ts
Normal file
@ -0,0 +1,222 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
// ExportService
|
||||
|
||||
import { AlignmentType, BorderStyle, Document, HeadingLevel, Packer, Paragraph, ShadingType, TextRun } from 'docx'
|
||||
import { dialog } from 'electron'
|
||||
import Logger from 'electron-log'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
import FileManager from './FileManager'
|
||||
|
||||
export class ExportService {
|
||||
private fileManager: FileManager
|
||||
private md: MarkdownIt
|
||||
|
||||
constructor(fileManager: FileManager) {
|
||||
this.fileManager = fileManager
|
||||
this.md = new MarkdownIt()
|
||||
}
|
||||
|
||||
private convertMarkdownToDocxElements(markdown: string) {
|
||||
const tokens = this.md.parse(markdown, {})
|
||||
const elements: any[] = []
|
||||
let listLevel = 0
|
||||
|
||||
const processInlineTokens = (tokens: any[]): TextRun[] => {
|
||||
const runs: TextRun[] = []
|
||||
for (const token of tokens) {
|
||||
switch (token.type) {
|
||||
case 'text':
|
||||
runs.push(new TextRun(token.content))
|
||||
break
|
||||
case 'strong':
|
||||
runs.push(new TextRun({ text: token.content, bold: true }))
|
||||
break
|
||||
case 'em':
|
||||
runs.push(new TextRun({ text: token.content, italics: true }))
|
||||
break
|
||||
case 'code_inline':
|
||||
runs.push(new TextRun({ text: token.content, font: 'Consolas', size: 20 }))
|
||||
break
|
||||
}
|
||||
}
|
||||
return runs
|
||||
}
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
const token = tokens[i]
|
||||
|
||||
switch (token.type) {
|
||||
case 'heading_open':
|
||||
// 获取标题级别 (h1 -> h6)
|
||||
const level = parseInt(token.tag.slice(1)) as 1 | 2 | 3 | 4 | 5 | 6
|
||||
const headingText = tokens[i + 1].content
|
||||
elements.push(
|
||||
new Paragraph({
|
||||
text: headingText,
|
||||
heading: HeadingLevel[`HEADING_${level}`],
|
||||
spacing: {
|
||||
before: 240,
|
||||
after: 120
|
||||
}
|
||||
})
|
||||
)
|
||||
i += 2 // 跳过内容标记和闭合标记
|
||||
break
|
||||
|
||||
case 'paragraph_open':
|
||||
const inlineTokens = tokens[i + 1].children || []
|
||||
elements.push(
|
||||
new Paragraph({
|
||||
children: processInlineTokens(inlineTokens),
|
||||
spacing: {
|
||||
before: 120,
|
||||
after: 120
|
||||
}
|
||||
})
|
||||
)
|
||||
i += 2
|
||||
break
|
||||
|
||||
case 'bullet_list_open':
|
||||
listLevel++
|
||||
break
|
||||
|
||||
case 'bullet_list_close':
|
||||
listLevel--
|
||||
break
|
||||
|
||||
case 'list_item_open':
|
||||
const itemInlineTokens = tokens[i + 2].children || []
|
||||
elements.push(
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({ text: '•', bold: true }),
|
||||
new TextRun({ text: '\t' }),
|
||||
...processInlineTokens(itemInlineTokens)
|
||||
],
|
||||
indent: {
|
||||
left: listLevel * 720
|
||||
}
|
||||
})
|
||||
)
|
||||
i += 3
|
||||
break
|
||||
|
||||
case 'fence': // 代码块
|
||||
const codeLines = token.content.split('\n')
|
||||
elements.push(
|
||||
new Paragraph({
|
||||
children: codeLines.map(
|
||||
(line) =>
|
||||
new TextRun({
|
||||
text: line + '\n',
|
||||
font: 'Consolas',
|
||||
size: 20,
|
||||
break: 1
|
||||
})
|
||||
),
|
||||
shading: {
|
||||
type: ShadingType.SOLID,
|
||||
color: 'F5F5F5'
|
||||
},
|
||||
spacing: {
|
||||
before: 120,
|
||||
after: 120
|
||||
},
|
||||
border: {
|
||||
top: { style: BorderStyle.SINGLE, size: 1, color: 'DDDDDD' },
|
||||
bottom: { style: BorderStyle.SINGLE, size: 1, color: 'DDDDDD' },
|
||||
left: { style: BorderStyle.SINGLE, size: 1, color: 'DDDDDD' },
|
||||
right: { style: BorderStyle.SINGLE, size: 1, color: 'DDDDDD' }
|
||||
}
|
||||
})
|
||||
)
|
||||
break
|
||||
|
||||
case 'hr':
|
||||
elements.push(
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: '─'.repeat(50), color: '999999' })],
|
||||
alignment: AlignmentType.CENTER
|
||||
})
|
||||
)
|
||||
break
|
||||
|
||||
case 'blockquote_open':
|
||||
const quoteText = tokens[i + 2].content
|
||||
elements.push(
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: quoteText,
|
||||
italics: true
|
||||
})
|
||||
],
|
||||
indent: {
|
||||
left: 720
|
||||
},
|
||||
border: {
|
||||
left: {
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 3,
|
||||
color: 'CCCCCC'
|
||||
}
|
||||
},
|
||||
spacing: {
|
||||
before: 120,
|
||||
after: 120
|
||||
}
|
||||
})
|
||||
)
|
||||
i += 3
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return elements
|
||||
}
|
||||
|
||||
public exportToWord = async (_: Electron.IpcMainInvokeEvent, markdown: string, fileName: string): Promise<void> => {
|
||||
try {
|
||||
const elements = this.convertMarkdownToDocxElements(markdown)
|
||||
|
||||
const doc = new Document({
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: 'Normal',
|
||||
name: 'Normal',
|
||||
run: {
|
||||
size: 24,
|
||||
font: 'Arial'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
properties: {},
|
||||
children: elements
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const buffer = await Packer.toBuffer(doc)
|
||||
|
||||
const filePath = dialog.showSaveDialogSync({
|
||||
title: '保存文件',
|
||||
filters: [{ name: 'Word Document', extensions: ['docx'] }],
|
||||
defaultPath: fileName
|
||||
})
|
||||
|
||||
if (filePath) {
|
||||
await this.fileManager.writeFile(_, filePath, buffer)
|
||||
Logger.info('[ExportService] Document exported successfully')
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error('[ExportService] Export to Word failed:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,7 +301,7 @@ class FileManager {
|
||||
fileName: string,
|
||||
content: string,
|
||||
options?: SaveDialogOptions
|
||||
): Promise<void> => {
|
||||
): Promise<string | null> => {
|
||||
try {
|
||||
const result: SaveDialogReturnValue = await dialog.showSaveDialog({
|
||||
title: '保存文件',
|
||||
@ -312,8 +312,11 @@ class FileManager {
|
||||
if (!result.canceled && result.filePath) {
|
||||
await writeFileSync(result.filePath, content, { encoding: 'utf-8' })
|
||||
}
|
||||
|
||||
return result.filePath
|
||||
} catch (err) {
|
||||
logger.error('[IPC - Error]', 'An error occurred saving the file:', err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,6 +434,25 @@ class FileManager {
|
||||
|
||||
return mimeToExtension[mimeType] || '.bin'
|
||||
}
|
||||
|
||||
public copyFile = async (_: Electron.IpcMainInvokeEvent, id: string, destPath: string): Promise<void> => {
|
||||
try {
|
||||
const sourcePath = path.join(this.storageDir, id)
|
||||
|
||||
// 确保目标目录存在
|
||||
const destDir = path.dirname(destPath)
|
||||
if (!fs.existsSync(destDir)) {
|
||||
await fs.promises.mkdir(destDir, { recursive: true })
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
await fs.promises.copyFile(sourcePath, destPath)
|
||||
logger.info('[FileManager] File copied successfully:', { from: sourcePath, to: destPath })
|
||||
} catch (error) {
|
||||
logger.error('[FileManager] Copy file failed:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default FileManager
|
||||
|
||||
10
src/preload/index.d.ts
vendored
10
src/preload/index.d.ts
vendored
@ -39,10 +39,18 @@ declare global {
|
||||
create: (fileName: string) => Promise<string>
|
||||
write: (filePath: string, data: Uint8Array | string) => Promise<void>
|
||||
open: (options?: OpenDialogOptions) => Promise<{ fileName: string; filePath: string; content: Buffer } | null>
|
||||
save: (path: string, content: string | NodeJS.ArrayBufferView, options?: SaveDialogOptions) => void
|
||||
save: (
|
||||
path: string,
|
||||
content: string | NodeJS.ArrayBufferView,
|
||||
options?: SaveDialogOptions
|
||||
) => Promise<string | null>
|
||||
saveImage: (name: string, data: string) => void
|
||||
base64Image: (fileId: string) => Promise<{ mime: string; base64: string; data: string }>
|
||||
download: (url: string) => Promise<FileType | null>
|
||||
copy: (fileId: string, destPath: string) => Promise<void>
|
||||
}
|
||||
export: {
|
||||
toWord: (markdown: string, fileName: string) => Promise<void>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,11 @@ const api = {
|
||||
selectFolder: () => ipcRenderer.invoke('file:selectFolder'),
|
||||
saveImage: (name: string, data: string) => ipcRenderer.invoke('file:saveImage', name, data),
|
||||
base64Image: (fileId: string) => ipcRenderer.invoke('file:base64Image', fileId),
|
||||
download: (url: string) => ipcRenderer.invoke('file:download', url)
|
||||
download: (url: string) => ipcRenderer.invoke('file:download', url),
|
||||
copy: (fileId: string, destPath: string) => ipcRenderer.invoke('file:copy', fileId, destPath)
|
||||
},
|
||||
export: {
|
||||
toWord: (markdown: string, fileName: string) => ipcRenderer.invoke('export:word', markdown, fileName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -168,6 +168,7 @@ body,
|
||||
body[os='mac'] {
|
||||
#content-container {
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
border-left: 0.5px solid var(--color-border);
|
||||
box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
@ -84,6 +84,7 @@
|
||||
"topics.export.title": "Export",
|
||||
"topics.export.image": "Export as image",
|
||||
"topics.export.md": "Export as markdown",
|
||||
"topics.export.word": "Export as Word",
|
||||
"input.new_topic": "New Topic",
|
||||
"input.topics": " Topics ",
|
||||
"input.clear": "Clear",
|
||||
@ -387,6 +388,16 @@
|
||||
"words": {
|
||||
"knowledgeGraph": "Knowledge Graph",
|
||||
"visualization": "Visualization"
|
||||
},
|
||||
"export": {
|
||||
"attached_files": "Attached Files",
|
||||
"user": "User",
|
||||
"assistant": "Assistant",
|
||||
"created": "Created",
|
||||
"last_updated": "Last Updated",
|
||||
"messages": "Messages",
|
||||
"conversation_details": "Conversation Details",
|
||||
"conversation_history": "Conversation History"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,6 +84,7 @@
|
||||
"topics.export.title": "导出",
|
||||
"topics.export.image": "导出为图片",
|
||||
"topics.export.md": "导出为 Markdown",
|
||||
"topics.export.word": "导出为 Word",
|
||||
"input.new_topic": "新话题",
|
||||
"input.topics": " 话题 ",
|
||||
"input.clear": "清空消息",
|
||||
@ -387,6 +388,16 @@
|
||||
"words": {
|
||||
"knowledgeGraph": "知识图谱",
|
||||
"visualization": "可视化"
|
||||
},
|
||||
"export": {
|
||||
"attached_files": "附件",
|
||||
"user": "用户",
|
||||
"assistant": "助手",
|
||||
"created": "创建时间",
|
||||
"last_updated": "最后更新",
|
||||
"messages": "消息数",
|
||||
"conversation_details": "会话详情",
|
||||
"conversation_history": "会话历史"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,6 +84,7 @@
|
||||
"topics.export.title": "匯出",
|
||||
"topics.export.image": "匯出為圖片",
|
||||
"topics.export.md": "匯出為 Markdown",
|
||||
"topics.export.word": "導出為 Word",
|
||||
"input.new_topic": "新話題",
|
||||
"input.topics": " 話題 ",
|
||||
"input.clear": "清除",
|
||||
@ -387,6 +388,16 @@
|
||||
"words": {
|
||||
"knowledgeGraph": "知識圖譜",
|
||||
"visualization": "可視化"
|
||||
},
|
||||
"export": {
|
||||
"attached_files": "附件",
|
||||
"user": "用戶",
|
||||
"assistant": "助手",
|
||||
"created": "創建時間",
|
||||
"last_updated": "最後更新",
|
||||
"messages": "訊息數",
|
||||
"conversation_details": "會話詳情",
|
||||
"conversation_history": "會話歷史"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||
import store, { useAppSelector } from '@renderer/store'
|
||||
import { setGenerating } from '@renderer/store/runtime'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { exportTopicAsMarkdown } from '@renderer/utils/export'
|
||||
import { exportTopicAsMarkdown, topicToMarkdown } from '@renderer/utils/export'
|
||||
import { Dropdown, MenuProps } from 'antd'
|
||||
import dayjs from 'dayjs'
|
||||
import { findIndex } from 'lodash'
|
||||
@ -141,6 +141,14 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
label: t('chat.topics.export.md'),
|
||||
key: 'markdown',
|
||||
onClick: () => exportTopicAsMarkdown(topic)
|
||||
},
|
||||
{
|
||||
label: t('chat.topics.export.word'),
|
||||
key: 'word',
|
||||
onClick: async () => {
|
||||
const markdown = await topicToMarkdown(topic)
|
||||
window.api.export.toWord(markdown, topic.name)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,24 +1,31 @@
|
||||
import db from '@renderer/databases'
|
||||
import { Message, Topic } from '@renderer/types'
|
||||
|
||||
export const exportMessageAsMarkdown = (message: Message) => {
|
||||
if (message.role === 'user') {
|
||||
return `### User\n\n${message.content}`
|
||||
}
|
||||
export const messageToMarkdown = (message: Message) => {
|
||||
const roleText = message.role === 'user' ? '🧑💻 User' : '🤖 Assistant'
|
||||
const titleSection = `### ${roleText}`
|
||||
const contentSection = message.content
|
||||
|
||||
return `### Assistant\n\n${message.content}`
|
||||
return [titleSection, '', contentSection].join('\n')
|
||||
}
|
||||
|
||||
export const exportMessagesAsMarkdown = (messages: Message[]) => {
|
||||
return messages.map((message) => exportMessageAsMarkdown(message)).join('\n\n---\n\n')
|
||||
export const messagesToMarkdown = (messages: Message[]) => {
|
||||
return messages.map((message) => messageToMarkdown(message)).join('\n\n---\n\n')
|
||||
}
|
||||
|
||||
export const topicToMarkdown = async (topic: Topic) => {
|
||||
const topicName = `# ${topic.name}`
|
||||
const topicMessages = await db.topics.get(topic.id)
|
||||
|
||||
if (topicMessages) {
|
||||
return topicName + '\n\n' + messagesToMarkdown(topicMessages.messages)
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
export const exportTopicAsMarkdown = async (topic: Topic) => {
|
||||
const fileName = topic.name + '.md'
|
||||
const topicMessages = await db.topics.get(topic.id)
|
||||
if (topicMessages) {
|
||||
const title = '# ' + topic.name + `\n\n`
|
||||
const markdown = exportMessagesAsMarkdown(topicMessages.messages)
|
||||
window.api.file.save(fileName, title + markdown)
|
||||
}
|
||||
const markdown = await topicToMarkdown(topic)
|
||||
window.api.file.save(fileName, markdown)
|
||||
}
|
||||
|
||||
144
yarn.lock
144
yarn.lock
@ -2094,6 +2094,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/linkify-it@npm:^5":
|
||||
version: 5.0.0
|
||||
resolution: "@types/linkify-it@npm:5.0.0"
|
||||
checksum: 10c0/7bbbf45b9dde17bf3f184fee585aef0e7342f6954f0377a24e4ff42ab5a85d5b806aaa5c8d16e2faf2a6b87b2d94467a196b7d2b85c9c7de2f0eaac5487aaab8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/lodash@npm:^4.17.5":
|
||||
version: 4.17.7
|
||||
resolution: "@types/lodash@npm:4.17.7"
|
||||
@ -2101,6 +2108,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/markdown-it@npm:^14":
|
||||
version: 14.1.2
|
||||
resolution: "@types/markdown-it@npm:14.1.2"
|
||||
dependencies:
|
||||
"@types/linkify-it": "npm:^5"
|
||||
"@types/mdurl": "npm:^2"
|
||||
checksum: 10c0/34f709f0476bd4e7b2ba7c3341072a6d532f1f4cb6f70aef371e403af8a08a7c372ba6907ac426bc618d356dab660c5b872791ff6c1ead80c483e0d639c6f127
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/mathjax@npm:^0.0.40":
|
||||
version: 0.0.40
|
||||
resolution: "@types/mathjax@npm:0.0.40"
|
||||
@ -2117,6 +2134,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/mdurl@npm:^2":
|
||||
version: 2.0.0
|
||||
resolution: "@types/mdurl@npm:2.0.0"
|
||||
checksum: 10c0/cde7bb571630ed1ceb3b92a28f7b59890bb38b8f34cd35326e2df43eebfc74985e6aa6fd4184e307393bad8a9e0783a519a3f9d13c8e03788c0f98e5ec869c5e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/minimatch@npm:*":
|
||||
version: 5.1.2
|
||||
resolution: "@types/minimatch@npm:5.1.2"
|
||||
@ -2166,6 +2190,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^22.7.5":
|
||||
version: 22.8.6
|
||||
resolution: "@types/node@npm:22.8.6"
|
||||
dependencies:
|
||||
undici-types: "npm:~6.19.8"
|
||||
checksum: 10c0/d3a11f2549234a91a4c5d0ff35ab4bdcb7ba34db4d3f1d189be39b8bd41c19aac98d117150a95a9c5a9d45b1014135477ea240b2b8317c86ae3d3cf1c3b3f8f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/plist@npm:^3.0.1":
|
||||
version: 3.0.5
|
||||
resolution: "@types/plist@npm:3.0.5"
|
||||
@ -2453,6 +2486,7 @@ __metadata:
|
||||
"@reduxjs/toolkit": "npm:^2.2.5"
|
||||
"@types/fs-extra": "npm:^11"
|
||||
"@types/lodash": "npm:^4.17.5"
|
||||
"@types/markdown-it": "npm:^14"
|
||||
"@types/node": "npm:^18.19.9"
|
||||
"@types/react": "npm:^18.2.48"
|
||||
"@types/react-dom": "npm:^18.2.18"
|
||||
@ -2466,6 +2500,7 @@ __metadata:
|
||||
dayjs: "npm:^1.11.11"
|
||||
dexie: "npm:^4.0.8"
|
||||
dexie-react-hooks: "npm:^1.1.7"
|
||||
docx: "npm:^9.0.2"
|
||||
dotenv-cli: "npm:^7.4.2"
|
||||
electron: "npm:^28.3.3"
|
||||
electron-builder: "npm:^24.9.1"
|
||||
@ -2489,6 +2524,7 @@ __metadata:
|
||||
i18next: "npm:^23.11.5"
|
||||
localforage: "npm:^1.10.0"
|
||||
lodash: "npm:^4.17.21"
|
||||
markdown-it: "npm:^14.1.0"
|
||||
mime: "npm:^4.0.4"
|
||||
officeparser: "npm:^4.1.1"
|
||||
openai: "npm:^4.52.1"
|
||||
@ -4464,6 +4500,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"docx@npm:^9.0.2":
|
||||
version: 9.0.2
|
||||
resolution: "docx@npm:9.0.2"
|
||||
dependencies:
|
||||
"@types/node": "npm:^22.7.5"
|
||||
hash.js: "npm:^1.1.7"
|
||||
jszip: "npm:^3.10.1"
|
||||
nanoid: "npm:^5.0.4"
|
||||
xml: "npm:^1.0.1"
|
||||
xml-js: "npm:^1.6.8"
|
||||
checksum: 10c0/6065391bac9384084dd74f8ff1fb04ac781e8d10d0a0174bb62dc338e75130fac57f6413ff3e6b0f264d61850baddcccbfa7994be036c6fbc113127c4422d342
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dom-walk@npm:^0.1.0":
|
||||
version: 0.1.2
|
||||
resolution: "dom-walk@npm:0.1.2"
|
||||
@ -6111,6 +6161,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hash.js@npm:^1.1.7":
|
||||
version: 1.1.7
|
||||
resolution: "hash.js@npm:1.1.7"
|
||||
dependencies:
|
||||
inherits: "npm:^2.0.3"
|
||||
minimalistic-assert: "npm:^1.0.1"
|
||||
checksum: 10c0/41ada59494eac5332cfc1ce6b7ebdd7b88a3864a6d6b08a3ea8ef261332ed60f37f10877e0c825aaa4bddebf164fbffa618286aeeec5296675e2671cbfa746c4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hasha@npm:^2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "hasha@npm:2.2.0"
|
||||
@ -7410,7 +7470,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jszip@npm:^3.1.0":
|
||||
"jszip@npm:^3.1.0, jszip@npm:^3.10.1":
|
||||
version: 3.10.1
|
||||
resolution: "jszip@npm:3.10.1"
|
||||
dependencies:
|
||||
@ -7528,6 +7588,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"linkify-it@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "linkify-it@npm:5.0.0"
|
||||
dependencies:
|
||||
uc.micro: "npm:^2.0.0"
|
||||
checksum: 10c0/ff4abbcdfa2003472fc3eb4b8e60905ec97718e11e33cca52059919a4c80cc0e0c2a14d23e23d8c00e5402bc5a885cdba8ca053a11483ab3cc8b3c7a52f88e2d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"load-bmfont@npm:^1.3.1, load-bmfont@npm:^1.4.0":
|
||||
version: 1.4.2
|
||||
resolution: "load-bmfont@npm:1.4.2"
|
||||
@ -7735,6 +7804,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"markdown-it@npm:^14.1.0":
|
||||
version: 14.1.0
|
||||
resolution: "markdown-it@npm:14.1.0"
|
||||
dependencies:
|
||||
argparse: "npm:^2.0.1"
|
||||
entities: "npm:^4.4.0"
|
||||
linkify-it: "npm:^5.0.0"
|
||||
mdurl: "npm:^2.0.0"
|
||||
punycode.js: "npm:^2.3.1"
|
||||
uc.micro: "npm:^2.1.0"
|
||||
bin:
|
||||
markdown-it: bin/markdown-it.mjs
|
||||
checksum: 10c0/9a6bb444181d2db7016a4173ae56a95a62c84d4cbfb6916a399b11d3e6581bf1cc2e4e1d07a2f022ae72c25f56db90fbe1e529fca16fbf9541659dc53480d4b4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"markdown-table@npm:^3.0.0":
|
||||
version: 3.0.3
|
||||
resolution: "markdown-table@npm:3.0.3"
|
||||
@ -8005,6 +8090,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mdurl@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "mdurl@npm:2.0.0"
|
||||
checksum: 10c0/633db522272f75ce4788440669137c77540d74a83e9015666a9557a152c02e245b192edc20bc90ae953bbab727503994a53b236b4d9c99bdaee594d0e7dd2ce0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"memoize-one@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "memoize-one@npm:6.0.0"
|
||||
@ -8460,6 +8552,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimalistic-assert@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "minimalistic-assert@npm:1.0.1"
|
||||
checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:9.0.3":
|
||||
version: 9.0.3
|
||||
resolution: "minimatch@npm:9.0.3"
|
||||
@ -8675,6 +8774,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nanoid@npm:^5.0.4":
|
||||
version: 5.0.8
|
||||
resolution: "nanoid@npm:5.0.8"
|
||||
bin:
|
||||
nanoid: bin/nanoid.js
|
||||
checksum: 10c0/0281d3cc0f3d03fb3010b479f28e8ddedfafb9b5d60e54315589ef0a54a0e9cfcb0bf382dd3b620fdad6b72b8c1f5b89a15d55c6b6a9134b58b16eb230b3a3d7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"napi-build-utils@npm:^1.0.1":
|
||||
version: 1.0.2
|
||||
resolution: "napi-build-utils@npm:1.0.2"
|
||||
@ -9648,6 +9756,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"punycode.js@npm:^2.3.1":
|
||||
version: 2.3.1
|
||||
resolution: "punycode.js@npm:2.3.1"
|
||||
checksum: 10c0/1d12c1c0e06127fa5db56bd7fdf698daf9a78104456a6b67326877afc21feaa821257b171539caedd2f0524027fa38e67b13dd094159c8d70b6d26d2bea4dfdb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.1":
|
||||
version: 2.3.1
|
||||
resolution: "punycode@npm:2.3.1"
|
||||
@ -12333,6 +12448,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"uc.micro@npm:^2.0.0, uc.micro@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "uc.micro@npm:2.1.0"
|
||||
checksum: 10c0/8862eddb412dda76f15db8ad1c640ccc2f47cdf8252a4a30be908d535602c8d33f9855dfcccb8b8837855c1ce1eaa563f7fa7ebe3c98fd0794351aab9b9c55fa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unbox-primitive@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "unbox-primitive@npm:1.0.2"
|
||||
@ -12362,7 +12484,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici-types@npm:~6.19.2":
|
||||
"undici-types@npm:~6.19.2, undici-types@npm:~6.19.8":
|
||||
version: 6.19.8
|
||||
resolution: "undici-types@npm:6.19.8"
|
||||
checksum: 10c0/078afa5990fba110f6824823ace86073b4638f1d5112ee26e790155f481f2a868cc3e0615505b6f4282bdf74a3d8caad715fd809e870c2bb0704e3ea6082f344
|
||||
@ -13057,6 +13179,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml-js@npm:^1.6.8":
|
||||
version: 1.6.11
|
||||
resolution: "xml-js@npm:1.6.11"
|
||||
dependencies:
|
||||
sax: "npm:^1.2.4"
|
||||
bin:
|
||||
xml-js: ./bin/cli.js
|
||||
checksum: 10c0/c83631057f10bf90ea785cee434a8a1a0030c7314fe737ad9bf568a281083b565b28b14c9e9ba82f11fc9dc582a3a907904956af60beb725be1c9ad4b030bc5a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml-name-validator@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "xml-name-validator@npm:5.0.0"
|
||||
@ -13081,6 +13214,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "xml@npm:1.0.1"
|
||||
checksum: 10c0/04bcc9b8b5e7b49392072fbd9c6b0f0958bd8e8f8606fee460318e43991349a68cbc5384038d179ff15aef7d222285f69ca0f067f53d071084eb14c7fdb30411
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xmlbuilder@npm:>=11.0.1, xmlbuilder@npm:^15.1.1":
|
||||
version: 15.1.1
|
||||
resolution: "xmlbuilder@npm:15.1.1"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user