fix
This commit is contained in:
parent
2a3e60a16c
commit
0244ab851e
@ -1,3 +1,3 @@
|
|||||||
FROM deepseek-r1:8b
|
FROM deepseek-r1:1.5b
|
||||||
SYSTEM You are a helpful AI assistant.
|
SYSTEM You are a helpful AI assistant.
|
||||||
PARAMETER num_gpu 0
|
PARAMETER num_gpu 0
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Data Hound
|
# Data Identification Manager : Personal Edition
|
||||||
|
|
||||||
An Electron-based desktop application that uses AI to help you search and understand your files through natural language queries.
|
An Electron-based desktop application that uses AI to help you search and understand your files through natural language queries.
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ function createWindow() {
|
|||||||
const mainWindow = new BrowserWindow({
|
const mainWindow = new BrowserWindow({
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 800,
|
height: 800,
|
||||||
|
minWidth: 1200, // Minimum width
|
||||||
|
minHeight: 800, // Minimum height
|
||||||
frame: false,
|
frame: false,
|
||||||
titleBarStyle: 'hidden',
|
titleBarStyle: 'hidden',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
@ -40,7 +42,7 @@ function createWindow() {
|
|||||||
const response = await fetch(process.env.VITE_DEV_SERVER_URL);
|
const response = await fetch(process.env.VITE_DEV_SERVER_URL);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
|
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
|
||||||
mainWindow.webContents.openDevTools();
|
//mainWindow.webContents.openDevTools();
|
||||||
} else {
|
} else {
|
||||||
setTimeout(pollDevServer, 500);
|
setTimeout(pollDevServer, 500);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const { contextBridge, ipcRenderer } = require('electron');
|
const { contextBridge, ipcRenderer } = require('electron');
|
||||||
|
|
||||||
// Import types
|
// Import types
|
||||||
|
import type { IpcRendererEvent } from 'electron';
|
||||||
import type { LLMConfig, DocumentMetadata } from './types';
|
import type { LLMConfig, DocumentMetadata } from './types';
|
||||||
|
|
||||||
interface Directory {
|
interface Directory {
|
||||||
@ -73,7 +74,7 @@ contextBridge.exposeInMainWorld('electron', {
|
|||||||
checkModel: (modelName: string) => ipcRenderer.invoke('check-model', modelName),
|
checkModel: (modelName: string) => ipcRenderer.invoke('check-model', modelName),
|
||||||
pullModel: (modelName: string, onProgress: (status: string) => void) => {
|
pullModel: (modelName: string, onProgress: (status: string) => void) => {
|
||||||
const channel = `pull-model-progress-${modelName}`;
|
const channel = `pull-model-progress-${modelName}`;
|
||||||
ipcRenderer.on(channel, (_event, status) => onProgress(status));
|
ipcRenderer.on(channel, (_event: IpcRendererEvent, status: string) => onProgress(status));
|
||||||
return ipcRenderer.invoke('pull-model', modelName).finally(() => {
|
return ipcRenderer.invoke('pull-model', modelName).finally(() => {
|
||||||
ipcRenderer.removeListener(channel, onProgress);
|
ipcRenderer.removeListener(channel, onProgress);
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,7 @@ export class LLMService {
|
|||||||
): Promise<{ answer: string, sources: DocumentMetadata[] }> {
|
): Promise<{ answer: string, sources: DocumentMetadata[] }> {
|
||||||
try {
|
try {
|
||||||
const ollamaResponse = await ollamaService.chat({
|
const ollamaResponse = await ollamaService.chat({
|
||||||
model: 'damien113/datahound:latest',
|
model: 'damien113/datahound-gpu:8b',
|
||||||
messages: [{ role: 'user', content: question }],
|
messages: [{ role: 'user', content: question }],
|
||||||
temperature: 0.7,
|
temperature: 0.7,
|
||||||
onChunk,
|
onChunk,
|
||||||
@ -36,7 +36,7 @@ export class LLMService {
|
|||||||
getConfig() {
|
getConfig() {
|
||||||
return {
|
return {
|
||||||
provider: 'ollama',
|
provider: 'ollama',
|
||||||
model: 'damien113/datahound:latest',
|
model: 'damien113/datahound-gpu:8b',
|
||||||
baseUrl: 'http://localhost:11434',
|
baseUrl: 'http://localhost:11434',
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:;" />
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:;" />
|
||||||
<title>Data Hound</title>
|
<title>Data Identification Manager : Personal Edition</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@ -41,14 +41,15 @@
|
|||||||
"dist-electron/**/*"
|
"dist-electron/**/*"
|
||||||
],
|
],
|
||||||
"win": {
|
"win": {
|
||||||
"target": "nsis"
|
"target": "portable"
|
||||||
},
|
},
|
||||||
"mac": {
|
"mac": {
|
||||||
"target": "dmg"
|
"target": "dmg"
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
"target": "AppImage"
|
"target": "AppImage"
|
||||||
}
|
},
|
||||||
|
"forceCodeSigning": false
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.16",
|
"@types/node": "^20.11.16",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Box, CssBaseline, ThemeProvider, createTheme, Tabs, Tab, TextField, IconButton } from '@mui/material';
|
import { Box, CssBaseline, ThemeProvider, createTheme, Tabs, Tab, TextField, IconButton, Typography, Grow, Tooltip, Button, Chip } from '@mui/material';
|
||||||
import { Send as SendIcon, DeleteOutline as ClearIcon, Close as CloseIcon, Remove as MinimizeIcon, Fullscreen as MaximizeIcon } from '@mui/icons-material';
|
import { Send as SendIcon, DeleteOutline as ClearIcon, Close as CloseIcon, Remove as MinimizeIcon, Fullscreen as MaximizeIcon, Download, UpgradeTwoTone, OpenInBrowser } from '@mui/icons-material';
|
||||||
import { useChat } from './hooks/useChat';
|
import { useChat } from './hooks/useChat';
|
||||||
import ChatPanel from './components/ChatPanel';
|
import ChatPanel from './components/ChatPanel';
|
||||||
import FileExplorer from './components/FileExplorer';
|
import FileExplorer from './components/FileExplorer';
|
||||||
@ -97,6 +97,9 @@ function AppContent() {
|
|||||||
await sendMessage(message);
|
await sendMessage(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
window.open('https://data443.com', '_blank');
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
@ -111,7 +114,7 @@ function AppContent() {
|
|||||||
{/* Custom titlebar */}
|
{/* Custom titlebar */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
height: '28px',
|
height: '40px',
|
||||||
bgcolor: '#2f2f2f',
|
bgcolor: '#2f2f2f',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -150,7 +153,133 @@ function AppContent() {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
startIcon={<UpgradeTwoTone />}
|
||||||
|
onClick={(handleClick)}
|
||||||
|
sx={{
|
||||||
|
z:100,
|
||||||
|
'@keyframes flash': {
|
||||||
|
'0%': {
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
color: 'primary.main',
|
||||||
|
boxShadow: '0 0 0 0 rgba(25, 118, 210, 0.4)'
|
||||||
|
},
|
||||||
|
'50%': {
|
||||||
|
borderColor: 'white',
|
||||||
|
color: 'white',
|
||||||
|
boxShadow: '0 0 0 4px rgba(25, 118, 210, 0)'
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
color: 'primary.main',
|
||||||
|
boxShadow: '0 0 0 0 rgba(25, 118, 210, 0)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
width: '135px',
|
||||||
|
minHeight: '24px',
|
||||||
|
px: 2,
|
||||||
|
py: 0.5,
|
||||||
|
borderColor: 'white',
|
||||||
|
color: 'white',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '0.8125rem',
|
||||||
|
lineHeight: 1.2,
|
||||||
|
animation: 'flash 2s infinite',
|
||||||
|
cursor: 'pointer',
|
||||||
|
'& .MuiSvgIcon-root': {
|
||||||
|
animation: 'flash 2s infinite'
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'white',
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.08)',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Upgrade
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
startIcon={<OpenInBrowser />}
|
||||||
|
onClick={(handleClick)}
|
||||||
|
sx={{
|
||||||
|
ml:2,
|
||||||
|
z:100,
|
||||||
|
'@keyframes flash': {
|
||||||
|
'0%': {
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
color: 'primary.main',
|
||||||
|
boxShadow: '0 0 0 0 rgba(25, 118, 210, 0.4)'
|
||||||
|
},
|
||||||
|
'50%': {
|
||||||
|
borderColor: 'white',
|
||||||
|
color: 'white',
|
||||||
|
boxShadow: '0 0 0 4px rgba(25, 118, 210, 0)'
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
color: 'primary.main',
|
||||||
|
boxShadow: '0 0 0 0 rgba(25, 118, 210, 0)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
width: '135px',
|
||||||
|
minHeight: '24px',
|
||||||
|
px: 2,
|
||||||
|
py: 0.5,
|
||||||
|
borderColor: 'white',
|
||||||
|
color: 'white',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '0.8125rem',
|
||||||
|
lineHeight: 1.2,
|
||||||
|
animation: 'flash 2s infinite',
|
||||||
|
cursor: 'pointer',
|
||||||
|
'& .MuiSvgIcon-root': {
|
||||||
|
animation: 'flash 2s infinite'
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'white',
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.08)',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Enterprise
|
||||||
|
</Button>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
width: 'auto',
|
||||||
|
textAlign: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Data Identification Manager
|
||||||
|
</Typography>
|
||||||
<div className="window-controls">
|
<div className="window-controls">
|
||||||
|
<Chip
|
||||||
|
label="Personal Edition (Free)"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
sx={{
|
||||||
|
bgcolor: 'primary.main', // or 'secondary.main', 'error.main', etc.
|
||||||
|
color: 'primary.contrastText',
|
||||||
|
borderRadius: 1,
|
||||||
|
height: 'auto',
|
||||||
|
'& .MuiChip-label': {
|
||||||
|
padding: '4px 8px',
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<button
|
<button
|
||||||
className="control-button"
|
className="control-button"
|
||||||
onClick={() => window.electron.closeWindow()}
|
onClick={() => window.electron.closeWindow()}
|
||||||
@ -200,8 +329,9 @@ function AppContent() {
|
|||||||
<Tab label="Home" />
|
<Tab label="Home" />
|
||||||
<Tab label="Chat" />
|
<Tab label="Chat" />
|
||||||
<Tab label="Settings" />
|
<Tab label="Settings" />
|
||||||
<Tab label="Scanning" />
|
<Tab disabled label="Scanning" />
|
||||||
<Tab label="Reports" />
|
<Tab disabled label="Reports" />
|
||||||
|
<Tab disabled label="Cleanup" />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
@ -264,13 +394,34 @@ function AppContent() {
|
|||||||
>
|
>
|
||||||
<SendIcon />
|
<SendIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
<Tooltip title="Clear all messages"
|
||||||
|
arrow
|
||||||
|
placement="top">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={clearMessages}
|
onClick={clearMessages}
|
||||||
color="error"
|
color="error"
|
||||||
disabled={messages.length === 0}
|
disabled={messages.length === 0}
|
||||||
|
sx={{
|
||||||
|
'@keyframes glow': {
|
||||||
|
'0%': {
|
||||||
|
boxShadow: '0 0 0 0 rgba(211, 47, 47, 0.4)' // error color with opacity
|
||||||
|
},
|
||||||
|
'50%': {
|
||||||
|
boxShadow: '0 0 0 8px rgba(211, 47, 47, 0)'
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
boxShadow: '0 0 0 0 rgba(211, 47, 47, 0)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animation: messages.length > 0 ? 'glow 2s infinite' : 'none',
|
||||||
|
'&:hover': {
|
||||||
|
animation: 'none' // Stop animation on hover
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ClearIcon />
|
<ClearIcon /> {/* Added back the icon */}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
@ -283,7 +434,7 @@ function App() {
|
|||||||
return (
|
return (
|
||||||
<ElectronProvider>
|
<ElectronProvider>
|
||||||
{!ollamaInstalled ? (
|
{!ollamaInstalled ? (
|
||||||
<OllamaCheck onInstalled={() => setOllamaInstalled(true)} />
|
<OllamaCheck onInstalled={(arg: boolean) => setOllamaInstalled(arg)} />
|
||||||
) : (
|
) : (
|
||||||
<AppContent />
|
<AppContent />
|
||||||
)}
|
)}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React, { useEffect, useRef, useState, useMemo } from 'react';
|
import React, { useEffect, useRef, useState, useMemo } from 'react';
|
||||||
import { Box, Typography, Paper, Avatar, IconButton } from '@mui/material';
|
import { Box, Typography, Paper, Avatar, IconButton, List, ListItem, ListItemIcon, ListItemText, useTheme } from '@mui/material';
|
||||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
||||||
import type { DocumentMetadata } from '../../../electron/types';
|
import type { DocumentMetadata } from '../../../electron/types';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import rehypeHighlight from 'rehype-highlight';
|
import rehypeHighlight from 'rehype-highlight';
|
||||||
import 'highlight.js/styles/github.css';
|
import 'highlight.js/styles/github.css';
|
||||||
|
import { Keyboard, Waves, Shield, DataObject, Folder, Lock } from '@mui/icons-material';
|
||||||
|
|
||||||
interface ChatMessage {
|
interface ChatMessage {
|
||||||
id: string;
|
id: string;
|
||||||
@ -54,6 +55,10 @@ export default function MessageList({ messages }: MessageListProps) {
|
|||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
},
|
},
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
|
{messages.length>0 ? (
|
||||||
|
<>
|
||||||
|
|
||||||
{messages.map((message) => (
|
{messages.map((message) => (
|
||||||
<Box
|
<Box
|
||||||
key={message.id}
|
key={message.id}
|
||||||
@ -85,14 +90,16 @@ export default function MessageList({ messages }: MessageListProps) {
|
|||||||
fontWeight: 500
|
fontWeight: 500
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{message.isUser ? 'User' : 'Data Hound'}
|
{message.isUser ? 'User' : 'Data Identification Manager'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
component={Paper}
|
component={Paper}
|
||||||
elevation={1}
|
elevation={1}
|
||||||
sx={{
|
sx={{
|
||||||
p: 2.5,
|
px: 2.5, // Keep horizontal padding
|
||||||
|
py: message.text.includes('<think>') ? 0 : 1.5, // Reduce vertical padding
|
||||||
|
pb: 1.5,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
bgcolor: message.isUser ? 'primary.main' : 'background.paper',
|
bgcolor: message.isUser ? 'primary.main' : 'background.paper',
|
||||||
color: message.isUser ? 'primary.contrastText' : 'text.primary',
|
color: message.isUser ? 'primary.contrastText' : 'text.primary',
|
||||||
@ -106,31 +113,29 @@ export default function MessageList({ messages }: MessageListProps) {
|
|||||||
>
|
>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
'& .markdown-body': {
|
'& .markdown-body': {
|
||||||
whiteSpace: 'pre-wrap',
|
|
||||||
wordBreak: 'break-word',
|
wordBreak: 'break-word',
|
||||||
minHeight: '1.5em',
|
minHeight: '1.5em',
|
||||||
lineHeight: 1.6,
|
lineHeight: 1.6,
|
||||||
'& pre': {
|
'& pre': {
|
||||||
backgroundColor: (theme) => theme.palette.mode === 'dark' ? '#1e1e1e' : '#f6f8fa',
|
backgroundColor: (theme) => theme.palette.mode === 'dark' ? '#1e1e1e' : '#f6f8fa',
|
||||||
padding: 2,
|
padding: 0,
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
overflow: 'auto'
|
overflow: 'auto'
|
||||||
},
|
},
|
||||||
'& code': {
|
'& code': {
|
||||||
backgroundColor: (theme) => theme.palette.mode === 'dark' ? '#1e1e1e' : '#f6f8fa',
|
backgroundColor: (theme) => theme.palette.mode === 'dark' ? '#1e1e1e' : '#f6f8fa',
|
||||||
padding: '0.2em 0.4em',
|
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
fontSize: '85%'
|
fontSize: '85%'
|
||||||
},
|
},
|
||||||
'& h1, & h2, & h3, & h4, & h5, & h6': {
|
'& h1, & h2, & h3, & h4, & h5, & h6': {
|
||||||
marginTop: '24px',
|
marginTop: '0px', // Reduced from 24px
|
||||||
marginBottom: '16px',
|
marginBottom: '0px', // Added margin bottom for headers
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
lineHeight: 1.25
|
lineHeight: 1.25
|
||||||
},
|
},
|
||||||
'& p': {
|
'& p': {
|
||||||
marginTop: '0',
|
marginTop: '0',
|
||||||
marginBottom: '16px'
|
marginBottom: '0px' // Added margin bottom for paragraphs
|
||||||
},
|
},
|
||||||
'& a': {
|
'& a': {
|
||||||
color: (theme) => theme.palette.primary.main,
|
color: (theme) => theme.palette.primary.main,
|
||||||
@ -147,15 +152,28 @@ export default function MessageList({ messages }: MessageListProps) {
|
|||||||
padding: '0 1em',
|
padding: '0 1em',
|
||||||
color: (theme) => theme.palette.text.secondary,
|
color: (theme) => theme.palette.text.secondary,
|
||||||
borderLeft: (theme) => `0.25em solid ${theme.palette.divider}`,
|
borderLeft: (theme) => `0.25em solid ${theme.palette.divider}`,
|
||||||
margin: '0 0 16px 0'
|
margin: '0 0 0px 0'
|
||||||
},
|
},
|
||||||
'& ul, & ol': {
|
'& ul, & ol': {
|
||||||
paddingLeft: '2em',
|
paddingLeft: '2em',
|
||||||
marginBottom: '16px'
|
marginTop: '0px', // Added margin top
|
||||||
|
marginBottom: '0px'
|
||||||
|
},
|
||||||
|
'& li': { // Added specific list item styling
|
||||||
|
marginBottom: '0px' // Add space between list items
|
||||||
|
},
|
||||||
|
'& li:last-child': { // Remove bottom margin from last list item
|
||||||
|
marginBottom: '0'
|
||||||
|
},
|
||||||
|
'& li > p': { // Adjust paragraph spacing within list items
|
||||||
|
marginBottom: '0px'
|
||||||
|
},
|
||||||
|
'& li > p:last-child': {
|
||||||
|
marginBottom: '0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
{message.text.includes('<think>') ? (
|
{message.text.includes('<think>') || message.text.length==0 ? (
|
||||||
message.text.split(/<think>|<\/think>/).map((segment, index) => {
|
message.text.split(/<think>|<\/think>/).map((segment, index) => {
|
||||||
if (index % 2 === 1) { // This is a thinking section
|
if (index % 2 === 1) { // This is a thinking section
|
||||||
// Calculate thinking time - assume 1 character = 0.1s
|
// Calculate thinking time - assume 1 character = 0.1s
|
||||||
@ -181,13 +199,19 @@ export default function MessageList({ messages }: MessageListProps) {
|
|||||||
/>
|
/>
|
||||||
<span>Reasoning</span>
|
<span>Reasoning</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="timestamp">(thought for {thinkingTime}s)</span>
|
<span className="timestamp">(thought for {thinkingTime}ms)</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id={`thinking-content-${message.id}-${index}`}
|
id={`thinking-content-${message.id}-${index}`}
|
||||||
className="thinking-content"
|
className="thinking-content"
|
||||||
|
>
|
||||||
|
<ReactMarkdown
|
||||||
|
key={index}
|
||||||
|
className="markdown-body"
|
||||||
|
rehypePlugins={[rehypeHighlight]}
|
||||||
>
|
>
|
||||||
{segment}
|
{segment}
|
||||||
|
</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -247,16 +271,178 @@ export default function MessageList({ messages }: MessageListProps) {
|
|||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color={message.isUser ? '#ffffff' : 'text.secondary'}
|
|
||||||
sx={{ display: 'block', mt: 0.5 }}
|
|
||||||
>
|
|
||||||
{new Date(message.timestamp).toLocaleTimeString()}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
|
</>
|
||||||
|
):(
|
||||||
|
<>
|
||||||
|
<WelcomeMessage/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const WelcomeMessage = () => {
|
||||||
|
const [text, setText] = useState('');
|
||||||
|
const fullText = 'Send a message...';
|
||||||
|
const [showCursor, setShowCursor] = useState(true);
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (text.length < fullText.length) {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setText(fullText.slice(0, text.length + 1));
|
||||||
|
}, 100);
|
||||||
|
return () => clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}, [text]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const cursorInterval = setInterval(() => {
|
||||||
|
setShowCursor(prev => !prev);
|
||||||
|
}, 530);
|
||||||
|
return () => clearInterval(cursorInterval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper
|
||||||
|
elevation={0}
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '4xl',
|
||||||
|
mx: 'auto',
|
||||||
|
p: 4,
|
||||||
|
background: 'rgb(0,0,0,0)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3 }}>
|
||||||
|
{/* Animated Keyboard and Hands */}
|
||||||
|
<Box sx={{ position: 'relative' }}>
|
||||||
|
<Keyboard
|
||||||
|
style={{
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
animation: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: -16,
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Waves
|
||||||
|
style={{
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
color: theme.palette.primary.light,
|
||||||
|
animation: 'bounce 1s infinite'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Typing Animation */}
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
mt: 2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
<Box
|
||||||
|
component="span"
|
||||||
|
sx={{
|
||||||
|
ml: 0.5,
|
||||||
|
opacity: showCursor ? 1 : 0,
|
||||||
|
transition: 'opacity 0.3s'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Example Questions */}
|
||||||
|
<List sx={{ width: '100%', mt: 4 }}>
|
||||||
|
<ListItem
|
||||||
|
component={Paper}
|
||||||
|
elevation={1}
|
||||||
|
sx={{
|
||||||
|
mb: 2,
|
||||||
|
borderRadius: 1,
|
||||||
|
transition: 'box-shadow 0.3s',
|
||||||
|
'&:hover': { boxShadow: 3 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Folder style={{ color: theme.palette.primary.main }} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="Can you analyze my CSV file and create a visualization of the trends?"
|
||||||
|
sx={{ color: theme.palette.text.primary }}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
component={Paper}
|
||||||
|
elevation={1}
|
||||||
|
sx={{
|
||||||
|
mb: 2,
|
||||||
|
borderRadius: 1,
|
||||||
|
transition: 'box-shadow 0.3s',
|
||||||
|
'&:hover': { boxShadow: 3 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Shield style={{ color: theme.palette.success.main }} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="What security measures does Data443 implement for data protection?"
|
||||||
|
sx={{ color: theme.palette.text.primary }}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
component={Paper}
|
||||||
|
elevation={1}
|
||||||
|
sx={{
|
||||||
|
mb: 2,
|
||||||
|
borderRadius: 1,
|
||||||
|
transition: 'box-shadow 0.3s',
|
||||||
|
'&:hover': { boxShadow: 3 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Lock style={{ color: theme.palette.secondary.main }} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="How can Data443's products help with GDPR compliance?"
|
||||||
|
sx={{ color: theme.palette.text.primary }}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
{/* Footer Note */}
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
textAlign: 'center',
|
||||||
|
mt: 3
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Ask me anything about your data, security needs, or Data443 products
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -13,6 +13,9 @@ import {
|
|||||||
Alert,
|
Alert,
|
||||||
Box,
|
Box,
|
||||||
Typography,
|
Typography,
|
||||||
|
InputAdornment,
|
||||||
|
IconButton,
|
||||||
|
TextField,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
Folder as FolderIcon,
|
Folder as FolderIcon,
|
||||||
@ -21,6 +24,8 @@ import {
|
|||||||
Cloud as DropboxIcon,
|
Cloud as DropboxIcon,
|
||||||
Chat as DiscordIcon,
|
Chat as DiscordIcon,
|
||||||
Computer as LocalIcon,
|
Computer as LocalIcon,
|
||||||
|
X,
|
||||||
|
Search,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useElectron } from '../../hooks/useElectron';
|
import { useElectron } from '../../hooks/useElectron';
|
||||||
|
|
||||||
@ -105,16 +110,48 @@ export default function DirectoryPicker({ onSelect }: DirectoryPickerProps) {
|
|||||||
mr: 2,
|
mr: 2,
|
||||||
mb: 2,
|
mb: 2,
|
||||||
}}>
|
}}>
|
||||||
<Typography sx={{ pl:2 ,flexGrow: 1 }} variant="h6">Folders</Typography>
|
|
||||||
<Button
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
size="small"
|
||||||
|
placeholder="Search..."
|
||||||
|
variant="outlined"
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<Search color="action" />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
// endAdornment: && (
|
||||||
|
// <InputAdornment position="end">
|
||||||
|
// <IconButton
|
||||||
|
// aria-label="clear search"
|
||||||
|
// edge="end"
|
||||||
|
// size="small"
|
||||||
|
// >
|
||||||
|
// <CloseIcon />
|
||||||
|
// </IconButton>
|
||||||
|
// </InputAdornment>
|
||||||
|
// )
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
pl:2,
|
||||||
|
pr:2,
|
||||||
|
maxWidth: 'md',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/> <Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={handleOpen}
|
onClick={handleOpen}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{
|
sx={{
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
width: '32px',
|
width: '40px',
|
||||||
height: '32px',
|
height: '40px',
|
||||||
borderRadius: '50%',
|
|
||||||
padding: 0,
|
padding: 0,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
backgroundColor: 'primary.main',
|
backgroundColor: 'primary.main',
|
||||||
@ -130,16 +167,15 @@ export default function DirectoryPicker({ onSelect }: DirectoryPickerProps) {
|
|||||||
},
|
},
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: 'primary.dark',
|
backgroundColor: 'primary.dark',
|
||||||
width: '180px',
|
width: '400px',
|
||||||
borderRadius: '16px',
|
|
||||||
'& .buttonText': {
|
'& .buttonText': {
|
||||||
width: '110px',
|
width: '300px',
|
||||||
marginLeft: '8px',
|
marginLeft: '8px',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AddIcon sx={{ fontSize: 20 }} />
|
<AddIcon sx={{ ml:0.25, fontSize: 20 }} />
|
||||||
<span className="buttonText">Add New Folder</span>
|
<span className="buttonText">Add New Folder</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -15,7 +15,7 @@ const HomePanel = () => {
|
|||||||
}}>
|
}}>
|
||||||
|
|
||||||
<Paper sx={{ p: 3, mb: 3 }}>
|
<Paper sx={{ p: 3, mb: 3 }}>
|
||||||
<Typography variant="h5" gutterBottom>Welcome to Data Hound</Typography>
|
<Typography variant="h5" gutterBottom>Welcome to Data Identification Manager</Typography>
|
||||||
<Typography variant="body1" paragraph>
|
<Typography variant="body1" paragraph>
|
||||||
This application helps you search through your files and interact with their contents using AI assistance.
|
This application helps you search through your files and interact with their contents using AI assistance.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -19,7 +19,7 @@ const theme = createTheme({
|
|||||||
});
|
});
|
||||||
|
|
||||||
interface OllamaCheckProps {
|
interface OllamaCheckProps {
|
||||||
onInstalled: () => void;
|
onInstalled: (arg:boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OllamaStatus {
|
interface OllamaStatus {
|
||||||
@ -37,7 +37,7 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
const [modelStatus, setModelStatus] = useState<ModelStatus | null>(null);
|
const [modelStatus, setModelStatus] = useState<ModelStatus | null>(null);
|
||||||
const [isChecking, setIsChecking] = useState(true);
|
const [isChecking, setIsChecking] = useState(true);
|
||||||
const [downloadProgress, setDownloadProgress] = useState<number>(0);
|
const [downloadProgress, setDownloadProgress] = useState<number>(0);
|
||||||
const MODEL_NAME = 'damien113/datahound:latest';
|
const MODEL_NAME = 'damien113/datahound-gpu:8b';
|
||||||
|
|
||||||
const checkOllama = async () => {
|
const checkOllama = async () => {
|
||||||
try {
|
try {
|
||||||
@ -53,17 +53,21 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkModel = async () => {
|
const checkModel = async (retries = 3) => {
|
||||||
try {
|
try {
|
||||||
const status = await window.electron.checkModel(MODEL_NAME);
|
const status = await window.electron.checkModel(MODEL_NAME);
|
||||||
setModelStatus(status);
|
setModelStatus(status);
|
||||||
if (status.installed) {
|
if (status.installed) {
|
||||||
onInstalled();
|
onInstalled(true);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error checking model:', error);
|
console.error('Error checking model:', error);
|
||||||
|
if (retries > 0) {
|
||||||
|
setTimeout(() => checkModel(retries - 1), 2000);
|
||||||
|
} else {
|
||||||
setModelStatus({ installed: false, installing: false });
|
setModelStatus({ installed: false, installing: false });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [installError, setInstallError] = useState<string | null>(null);
|
const [installError, setInstallError] = useState<string | null>(null);
|
||||||
@ -72,6 +76,7 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
try {
|
try {
|
||||||
// Set initial installation state once at the start
|
// Set initial installation state once at the start
|
||||||
setModelStatus({ installed: false, installing: true });
|
setModelStatus({ installed: false, installing: true });
|
||||||
|
onInstalled(false);
|
||||||
setInstallError(null);
|
setInstallError(null);
|
||||||
setDownloadProgress(0);
|
setDownloadProgress(0);
|
||||||
let downloadComplete = false;
|
let downloadComplete = false;
|
||||||
@ -96,7 +101,7 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
// Show verification screen for a moment before transitioning
|
// Show verification screen for a moment before transitioning
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000)); // 2 second delay
|
await new Promise(resolve => setTimeout(resolve, 2000)); // 2 second delay
|
||||||
setModelStatus({ installed: true, installing: false });
|
setModelStatus({ installed: true, installing: false });
|
||||||
onInstalled();
|
onInstalled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +113,8 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error installing model:', error);
|
console.error('Error installing model:', error);
|
||||||
setModelStatus({ installed: false, installing: false });
|
setModelStatus({ installed: false, installing: false });
|
||||||
|
|
||||||
|
onInstalled(false);
|
||||||
setInstallError(error instanceof Error ? error.message : 'Unknown error occurred');
|
setInstallError(error instanceof Error ? error.message : 'Unknown error occurred');
|
||||||
setDownloadProgress(0);
|
setDownloadProgress(0);
|
||||||
}
|
}
|
||||||
@ -126,7 +133,7 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
if (!ollamaStatus?.installed || !ollamaStatus?.running) {
|
if (!ollamaStatus?.installed || !ollamaStatus?.running) {
|
||||||
checkOllama();
|
checkOllama();
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 2000);
|
||||||
|
|
||||||
// Cleanup interval on unmount
|
// Cleanup interval on unmount
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
@ -236,7 +243,7 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
color: 'text.primary',
|
color: 'text.primary',
|
||||||
}}>
|
}}>
|
||||||
<Typography variant="h5" sx={{ color: 'text.primary', mb: 1 }}>
|
<Typography variant="h5" sx={{ color: 'text.primary', mb: 1 }}>
|
||||||
{modelStatus?.installing ? 'Installing Data Hound AI Model' : 'AI Model Required'}
|
{modelStatus?.installing ? 'Installing Data Identification Manager AI Model' : 'AI Model Required'}
|
||||||
</Typography>
|
</Typography>
|
||||||
{installError && (
|
{installError && (
|
||||||
<Typography sx={{ color: 'error.main', mb: 2, textAlign: 'center' }}>
|
<Typography sx={{ color: 'error.main', mb: 2, textAlign: 'center' }}>
|
||||||
@ -284,7 +291,7 @@ export function OllamaCheck({ onInstalled }: OllamaCheckProps) {
|
|||||||
fontSize: '1.1rem',
|
fontSize: '1.1rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Download Data Hound AI Model
|
Download Data Identification Manager AI Model
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -33,7 +33,7 @@ html, body {
|
|||||||
|
|
||||||
.thinking-section {
|
.thinking-section {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin: 0 0 8px 0;
|
margin: 0 0 28px 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: #1976d2;
|
background-color: #1976d2;
|
||||||
color: white;
|
color: white;
|
||||||
@ -42,11 +42,10 @@ html, body {
|
|||||||
[data-theme="dark"] .thinking-section {
|
[data-theme="dark"] .thinking-section {
|
||||||
background-color: #1565c0;
|
background-color: #1565c0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thinking-header {
|
.thinking-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between; /* Ensures left content stays left, timestamp stays right */
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@ -68,13 +67,17 @@ html, body {
|
|||||||
[data-theme="dark"] .thinking-header:hover {
|
[data-theme="dark"] .thinking-header:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
.markdown-body {
|
||||||
|
padding-top: ;
|
||||||
|
}
|
||||||
|
|
||||||
.thinking-header-left {
|
.thinking-header-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px; /* Controls spacing between chevron and "Reasoning" */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.thinking-header .indicator {
|
.thinking-header .indicator {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@ -87,8 +90,7 @@ html, body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.thinking-header .timestamp {
|
.thinking-header .timestamp {
|
||||||
font-size: 0.85rem;
|
margin-left: auto; /* Pushes it to the right */
|
||||||
color: rgba(255, 255, 255, 0.7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.thinking-content {
|
.thinking-content {
|
||||||
|
@ -5,17 +5,23 @@ import path from 'path';
|
|||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
base: process.env.ELECTRON_VITE_DEV_SERVER_URL ? '/' : './',
|
base: './',
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
emptyOutDir: true,
|
emptyOutDir: true,
|
||||||
target: 'esnext',
|
target: 'esnext',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['http', 'https', 'path', 'fs', 'electron']
|
external: ['electron', 'electron-store', ...Object.keys(require('./package.json').dependencies)],
|
||||||
|
output: {
|
||||||
|
format: 'es',
|
||||||
|
entryFileNames: '[name].js',
|
||||||
|
chunkFileNames: '[name].js',
|
||||||
|
assetFileNames: '[name][extname]'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
assetsDir: '.',
|
assetsInlineLimit: 0,
|
||||||
minify: true,
|
minify: 'esbuild',
|
||||||
sourcemap: false
|
sourcemap: true
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user