fixsta
This commit is contained in:
		
							parent
							
								
									086e311aa4
								
							
						
					
					
						commit
						1cebb80b08
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -39,3 +39,4 @@ yarn-error.log* | |||||||
| # typescript | # typescript | ||||||
| *.tsbuildinfo | *.tsbuildinfo | ||||||
| next-env.d.ts | next-env.d.ts | ||||||
|  | /electron-file-search/datahound-win32-x64 | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								Modelfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Modelfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | FROM deepseek-r1:1.5b | ||||||
|  | # Disable GPU usage | ||||||
|  | PARAMETER num_gpu 0 | ||||||
|  | 
 | ||||||
|  | # Increase context length | ||||||
|  | PARAMETER max_tokens 16384 | ||||||
|  | 
 | ||||||
|  | # Set temperature to 0.6 | ||||||
|  | PARAMETER temperature 0.6 | ||||||
| @ -148,7 +148,7 @@ export class LLMService { | |||||||
| 
 | 
 | ||||||
|         case 'ollama': |         case 'ollama': | ||||||
|           const ollamaResponse = await ollamaService.chat({ |           const ollamaResponse = await ollamaService.chat({ | ||||||
|             model: this.#config.model || 'phi4:latest', |             model: this.#config.model || 'llama2:7b', | ||||||
|             messages: [{ role: 'user', content: question }], |             messages: [{ role: 'user', content: question }], | ||||||
|             temperature: this.#config.temperature, |             temperature: this.#config.temperature, | ||||||
|             onChunk, |             onChunk, | ||||||
| @ -195,7 +195,7 @@ export class LLMService { | |||||||
|     const cleanConfig = { |     const cleanConfig = { | ||||||
|       provider: newConfig.provider, |       provider: newConfig.provider, | ||||||
|       apiKey: newConfig.apiKey ?? null, |       apiKey: newConfig.apiKey ?? null, | ||||||
|       model: newConfig.model ?? (newConfig.provider === 'ollama' ? 'phi4' : null), |       model: newConfig.model ?? (newConfig.provider === 'ollama' ? 'llama2:7b' : null), | ||||||
|       baseUrl: newConfig.provider === 'ollama' ? (newConfig.baseUrl ?? 'http://localhost:11434') : (newConfig.baseUrl ?? null), |       baseUrl: newConfig.provider === 'ollama' ? (newConfig.baseUrl ?? 'http://localhost:11434') : (newConfig.baseUrl ?? null), | ||||||
|       temperature: typeof newConfig.temperature === 'number' ? newConfig.temperature : 0.7 |       temperature: typeof newConfig.temperature === 'number' ? newConfig.temperature : 0.7 | ||||||
|     }; |     }; | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ const schema: Store.Schema<Schema> = { | |||||||
|     additionalProperties: false, |     additionalProperties: false, | ||||||
|     default: { |     default: { | ||||||
|       provider: 'ollama', |       provider: 'ollama', | ||||||
|       model: 'phi4', |       model: 'llama2:7b', | ||||||
|       baseUrl: 'http://localhost:11434', |       baseUrl: 'http://localhost:11434', | ||||||
|       temperature: 0.7 |       temperature: 0.7 | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								electron-file-search/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								electron-file-search/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -17,6 +17,7 @@ | |||||||
|         "chokidar": "^3.5.3", |         "chokidar": "^3.5.3", | ||||||
|         "electron-store": "^8.1.0", |         "electron-store": "^8.1.0", | ||||||
|         "highlight.js": "^11.11.1", |         "highlight.js": "^11.11.1", | ||||||
|  |         "lucide-react": "^0.474.0", | ||||||
|         "ollama": "^0.5.12", |         "ollama": "^0.5.12", | ||||||
|         "openai": "^4.82.0", |         "openai": "^4.82.0", | ||||||
|         "openrouter-client": "^1.2.0", |         "openrouter-client": "^1.2.0", | ||||||
| @ -6546,6 +6547,15 @@ | |||||||
|         "yallist": "^3.0.2" |         "yallist": "^3.0.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/lucide-react": { | ||||||
|  |       "version": "0.474.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.474.0.tgz", | ||||||
|  |       "integrity": "sha512-CmghgHkh0OJNmxGKWc0qfPJCYHASPMVSyGY8fj3xgk4v84ItqDg64JNKFZn5hC6E0vHi6gxnbCgwhyVB09wQtA==", | ||||||
|  |       "license": "ISC", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/matcher": { |     "node_modules/matcher": { | ||||||
|       "version": "3.0.0", |       "version": "3.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", |       "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ | |||||||
|     "chokidar": "^3.5.3", |     "chokidar": "^3.5.3", | ||||||
|     "electron-store": "^8.1.0", |     "electron-store": "^8.1.0", | ||||||
|     "highlight.js": "^11.11.1", |     "highlight.js": "^11.11.1", | ||||||
|  |     "lucide-react": "^0.474.0", | ||||||
|     "ollama": "^0.5.12", |     "ollama": "^0.5.12", | ||||||
|     "openai": "^4.82.0", |     "openai": "^4.82.0", | ||||||
|     "openrouter-client": "^1.2.0", |     "openrouter-client": "^1.2.0", | ||||||
|  | |||||||
| @ -149,6 +149,18 @@ function AppContent() { | |||||||
|             }, |             }, | ||||||
|           }} |           }} | ||||||
|         > |         > | ||||||
|  |         <Box | ||||||
|  |           sx={{ | ||||||
|  |             display: 'flex', | ||||||
|  |             flex: 1, | ||||||
|  |             width: '100%', | ||||||
|  |             height: '100%', | ||||||
|  |             justifyContent: 'center', | ||||||
|  |             alignItems: 'center', | ||||||
|  |           }} | ||||||
|  |         > | ||||||
|  |           Data Hound V2 | ||||||
|  |         </Box> | ||||||
|           <div className="window-controls"> |           <div className="window-controls"> | ||||||
|             <button  |             <button  | ||||||
|               className="control-button" |               className="control-button" | ||||||
| @ -247,15 +259,48 @@ function AppContent() { | |||||||
|             boxSizing: 'border-box' |             boxSizing: 'border-box' | ||||||
|           }} |           }} | ||||||
|         > |         > | ||||||
|           <TextField | <TextField | ||||||
|   fullWidth |   fullWidth | ||||||
|  |   multiline | ||||||
|   variant="outlined" |   variant="outlined" | ||||||
|   placeholder="Ask a question..." |   placeholder="Ask a question..." | ||||||
|   value={input} |   value={input} | ||||||
|   onChange={(e) => setInput(e.target.value)} |   onChange={(e) => setInput(e.target.value)} | ||||||
|   disabled={isLoading} |   disabled={isLoading} | ||||||
|   size="small" |   size="small" | ||||||
|           /> |   minRows={1} | ||||||
|  |   maxRows={4} | ||||||
|  |   onKeyDown={(event) => { | ||||||
|  |     if (event.key === 'Enter') { | ||||||
|  |       if (event.shiftKey) { | ||||||
|  |         return; // Allow new line with Shift+Enter
 | ||||||
|  |       } | ||||||
|  |       event.preventDefault(); | ||||||
|  |       handleSubmit(event); | ||||||
|  |     } | ||||||
|  |   }} | ||||||
|  |   InputProps={{ | ||||||
|  |     style: { | ||||||
|  |       resize: 'vertical' | ||||||
|  |     }, | ||||||
|  |     sx: { | ||||||
|  |       '&::-webkit-scrollbar': { | ||||||
|  |         width: '8px', | ||||||
|  |         background: 'transparent', | ||||||
|  |       }, | ||||||
|  |       '&::-webkit-scrollbar-thumb': { | ||||||
|  |         background: (theme) => theme.palette.primary.main, // Using your theme's primary blue
 | ||||||
|  |         borderRadius: '2px', // Made more square
 | ||||||
|  |         '&:hover': { | ||||||
|  |           background: (theme) => theme.palette.primary.light, // Lighter blue on hover
 | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       '&::-webkit-scrollbar-track': { | ||||||
|  |         background: 'transparent', | ||||||
|  |       }, | ||||||
|  |     } | ||||||
|  |   }} | ||||||
|  | /> | ||||||
|           <IconButton  |           <IconButton  | ||||||
|             type="submit"  |             type="submit"  | ||||||
|             disabled={isLoading || !input.trim()} |             disabled={isLoading || !input.trim()} | ||||||
|  | |||||||
| @ -1,9 +1,10 @@ | |||||||
| import React, { useEffect, useRef } from 'react'; | import React, { useEffect, useRef, useState } from 'react'; | ||||||
| import { Box, Typography, Paper, Avatar } from '@mui/material'; | import { Box, Typography, Paper, Avatar, Collapse, IconButton } from '@mui/material'; | ||||||
| import type { DocumentMetadata } from '../../../electron/types'; | import { Loader2, ChevronDown, ChevronUp } from 'lucide-react'; | ||||||
| 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 type { DocumentMetadata } from '../../../electron/types'; | ||||||
| 
 | 
 | ||||||
| interface ChatMessage { | interface ChatMessage { | ||||||
|   id: string; |   id: string; | ||||||
| @ -18,91 +19,139 @@ interface MessageListProps { | |||||||
|   messages: ChatMessage[]; |   messages: ChatMessage[]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default function MessageList({ messages }: MessageListProps) { | interface ThinkingContentProps { | ||||||
|   const messageListRef = useRef<HTMLDivElement>(null); |   content: string; | ||||||
|  |   isThinking: boolean; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { | interface MessageSegment { | ||||||
|     if (messageListRef.current) { |   type: 'text' | 'thinking'; | ||||||
|       messageListRef.current.scrollTop = messageListRef.current.scrollHeight; |   content: string; | ||||||
|     } |   inProgress?: boolean; | ||||||
|   }, [messages]); | } | ||||||
|  | 
 | ||||||
|  | interface MessageContentProps { | ||||||
|  |   text: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ThinkingContent: React.FC<ThinkingContentProps> = ({ content, isThinking }) => { | ||||||
|  |   const [isExpanded, setIsExpanded] = useState<boolean>(false); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|  |     <Box sx={{ mt: 1 }}> | ||||||
|       <Box  |       <Box  | ||||||
|       ref={messageListRef} |  | ||||||
|       sx={{  |  | ||||||
|         flex: 1,  |  | ||||||
|         overflow: 'auto', |  | ||||||
|         p: 2, |  | ||||||
|         display: 'flex', |  | ||||||
|         flexDirection: 'column', |  | ||||||
|         gap: 2, |  | ||||||
|         scrollBehavior: 'smooth', |  | ||||||
|         '&::-webkit-scrollbar': { |  | ||||||
|           width: '8px', |  | ||||||
|           background: 'transparent', |  | ||||||
|         }, |  | ||||||
|         '&::-webkit-scrollbar-thumb': { |  | ||||||
|           background: (theme) => theme.palette.divider, |  | ||||||
|           borderRadius: '4px', |  | ||||||
|           '&:hover': { |  | ||||||
|             background: (theme) => theme.palette.action.hover, |  | ||||||
|           }, |  | ||||||
|         }, |  | ||||||
|         '&::-webkit-scrollbar-track': { |  | ||||||
|           background: 'transparent', |  | ||||||
|         }, |  | ||||||
|     }}> |  | ||||||
|       {messages.map((message) => ( |  | ||||||
|         <Box |  | ||||||
|           key={message.id} |  | ||||||
|         sx={{  |         sx={{  | ||||||
|           display: 'flex',  |           display: 'flex',  | ||||||
|             flexDirection: message.isUser ? 'row-reverse' : 'row', |           alignItems: 'center',  | ||||||
|             alignItems: 'flex-start', |           gap: 1, | ||||||
|             gap: 2, |           cursor: 'pointer', | ||||||
|             maxWidth: '80%', |           color: 'text.secondary' | ||||||
|             alignSelf: message.isUser ? 'flex-end' : 'flex-start', |  | ||||||
|         }} |         }} | ||||||
|  |         onClick={() => setIsExpanded(!isExpanded)} | ||||||
|       > |       > | ||||||
|           <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 0.5 }}> |         <IconButton size="small"> | ||||||
|             <Avatar |           {isExpanded ? <ChevronUp size={16} /> : <ChevronDown size={16} />} | ||||||
|               src={message.isUser ? '/profiles/user-profile.webp' : '/profiles/ai-profile.webp'} |         </IconButton> | ||||||
|               alt={message.isUser ? 'User' : 'AI'} |         <Typography variant="caption" sx={{ fontWeight: 500 }}> | ||||||
|               variant="square" |           Thinking Process | ||||||
|  |         </Typography> | ||||||
|  |         {isThinking && ( | ||||||
|  |           <Box | ||||||
|  |             component={Loader2} | ||||||
|  |             size={16} | ||||||
|  |             className="animate-spin" | ||||||
|             sx={{ |             sx={{ | ||||||
|                 width: 40,  |               animation: 'spin 1s linear infinite', | ||||||
|                 height: 40, |               '@keyframes spin': { | ||||||
|                 boxShadow: 1 |                 '0%': { | ||||||
|  |                   transform: 'rotate(0deg)', | ||||||
|  |                 }, | ||||||
|  |                 '100%': { | ||||||
|  |                   transform: 'rotate(360deg)', | ||||||
|  |                 }, | ||||||
|  |               }, | ||||||
|             }} |             }} | ||||||
|           /> |           /> | ||||||
|             <Typography  |         )} | ||||||
|               variant="caption"  |  | ||||||
|               sx={{  |  | ||||||
|                 fontSize: '0.75rem', |  | ||||||
|                 color: 'text.secondary', |  | ||||||
|                 fontWeight: 500 |  | ||||||
|               }} |  | ||||||
|             > |  | ||||||
|               {message.isUser ? 'User' : 'Data Hound'} |  | ||||||
|             </Typography> |  | ||||||
|       </Box> |       </Box> | ||||||
|           <Box |       <Collapse in={isExpanded}> | ||||||
|             component={Paper} |         <Box sx={{  | ||||||
|             elevation={1} |           pl: 4,  | ||||||
|             sx={{ |           pr: 2, | ||||||
|             p: 2, |           py: 1, | ||||||
|             flex: 1, |           mt: 1, | ||||||
|             bgcolor: message.isUser ? 'primary.main' : 'background.paper', |           borderLeft: '2px solid', | ||||||
|             color: message.isUser ? 'primary.contrastText' : 'text.primary', |           borderColor: 'divider', | ||||||
|             transition: 'all 0.2s ease-in-out', |           color: 'text.secondary' | ||||||
|             boxShadow: 1, |         }}> | ||||||
|             borderRadius: 2, |           <ReactMarkdown | ||||||
|             '&:hover': { |             className="markdown-body" | ||||||
|               boxShadow: 2, |             rehypePlugins={[rehypeHighlight]} | ||||||
|             }, |  | ||||||
|           }} |  | ||||||
|           > |           > | ||||||
|  |             {content} | ||||||
|  |           </ReactMarkdown> | ||||||
|  |         </Box> | ||||||
|  |       </Collapse> | ||||||
|  |     </Box> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const MessageContent: React.FC<MessageContentProps> = ({ text }) => { | ||||||
|  |   const [segments, setSegments] = useState<MessageSegment[]>([]); | ||||||
|  |   const [isThinking, setIsThinking] = useState<boolean>(false); | ||||||
|  | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     const parseContent = (): void => { | ||||||
|  |       const parts: MessageSegment[] = []; | ||||||
|  |       let remainingText = text; | ||||||
|  |        | ||||||
|  |       // Handle <think> tags
 | ||||||
|  |       const thinkRegex = /<think>([\s\S]*?)(?:<\/think>|$)/g; | ||||||
|  |       let lastIndex = 0; | ||||||
|  |       let match; | ||||||
|  |        | ||||||
|  |       while ((match = thinkRegex.exec(text)) !== null) { | ||||||
|  |         // Add text before the think tag if there is any
 | ||||||
|  |         const beforeText = text.slice(lastIndex, match.index).trim(); | ||||||
|  |         if (beforeText) { | ||||||
|  |           parts.push({ | ||||||
|  |             type: 'text', | ||||||
|  |             content: beforeText | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Add the thinking content
 | ||||||
|  |         parts.push({ | ||||||
|  |           type: 'thinking', | ||||||
|  |           content: match[1], | ||||||
|  |           inProgress: !match[0].endsWith('</think>') | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         lastIndex = match.index + match[0].length; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       // Add any remaining text after the last think tag
 | ||||||
|  |       const afterText = text.slice(lastIndex).trim(); | ||||||
|  |       if (afterText) { | ||||||
|  |         parts.push({ | ||||||
|  |           type: 'text', | ||||||
|  |           content: afterText | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       setSegments(parts); | ||||||
|  |       setIsThinking(parts.some(part => part.type === 'thinking' && part.inProgress)); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     parseContent(); | ||||||
|  |   }, [text]); | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <Box> | ||||||
|  |       {segments.map((segment, index) => { | ||||||
|  |                   if (segment.type === 'text' && segment.content.trim()) { | ||||||
|  |           return ( | ||||||
|  |             <Box key={index}> | ||||||
|               <Box sx={{  |               <Box sx={{  | ||||||
|                 '& .markdown-body': { |                 '& .markdown-body': { | ||||||
|                   whiteSpace: 'pre-wrap', |                   whiteSpace: 'pre-wrap', | ||||||
| @ -158,20 +207,95 @@ export default function MessageList({ messages }: MessageListProps) { | |||||||
|                   className="markdown-body" |                   className="markdown-body" | ||||||
|                   rehypePlugins={[rehypeHighlight]} |                   rehypePlugins={[rehypeHighlight]} | ||||||
|                 > |                 > | ||||||
|               {message.text} |                   {segment.content} | ||||||
|                 </ReactMarkdown> |                 </ReactMarkdown> | ||||||
|               </Box> |               </Box> | ||||||
|           {message.sources && message.sources.length > 0 && ( |             </Box> | ||||||
|             <Box sx={{ mt: 2, pt: 1, borderTop: '1px solid', borderColor: 'divider' }}> |           ); | ||||||
|               <Typography  |         } | ||||||
|                 variant="caption"  |         if (segment.type === 'thinking') { | ||||||
|                 color="text.secondary" |           return ( | ||||||
|  |             <Box key={index}> | ||||||
|  |               <ThinkingContent  | ||||||
|  |                 content={segment.content}  | ||||||
|  |                 isThinking={segment.inProgress || false} | ||||||
|  |               /> | ||||||
|  |             </Box> | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |       })} | ||||||
|  |     </Box> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const MessageList: React.FC<MessageListProps> = ({ messages }) => { | ||||||
|  |   // Memoize messages to preserve their original timestamps
 | ||||||
|  |   const memoizedMessages = React.useMemo(() => messages, [messages]); | ||||||
|  |   const messageListRef = useRef<HTMLDivElement | null>(null); | ||||||
|  | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     if (messageListRef.current) { | ||||||
|  |       messageListRef.current.scrollTop = messageListRef.current.scrollHeight; | ||||||
|  |     } | ||||||
|  |   }, [messages]); | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <Box  | ||||||
|  |       ref={messageListRef} | ||||||
|       sx={{  |       sx={{  | ||||||
|                   display: 'block', |         flex: 1,  | ||||||
|                   mb: 0.5, |         overflow: 'auto', | ||||||
|                   fontWeight: 'medium' |         p: 2, | ||||||
|  |         display: 'flex', | ||||||
|  |         flexDirection: 'column', | ||||||
|  |         gap: 2, | ||||||
|  |         scrollBehavior: 'smooth', | ||||||
|  |         '&::-webkit-scrollbar': { | ||||||
|  |           width: '8px', | ||||||
|  |           background: 'transparent', | ||||||
|  |         }, | ||||||
|  |         '&::-webkit-scrollbar-thumb': { | ||||||
|  |           background: (theme) => theme.palette.divider, | ||||||
|  |           borderRadius: '4px', | ||||||
|  |           '&:hover': { | ||||||
|  |             background: (theme) => theme.palette.action.hover, | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|       }} |       }} | ||||||
|     > |     > | ||||||
|  |       {memoizedMessages.map((message) => ( | ||||||
|  |         <Box | ||||||
|  |           key={message.id} | ||||||
|  |           sx={{ | ||||||
|  |             display: 'flex', | ||||||
|  |             flexDirection: message.isUser ? 'row-reverse' : 'row', | ||||||
|  |             alignItems: 'flex-start', | ||||||
|  |             gap: 2, | ||||||
|  |             maxWidth: '80%', | ||||||
|  |             alignSelf: message.isUser ? 'flex-end' : 'flex-start', | ||||||
|  |           }} | ||||||
|  |         > | ||||||
|  |           <Avatar | ||||||
|  |             src={message.isUser ? '/profiles/user-profile.webp' : '/profiles/ai-profile.webp'} | ||||||
|  |             alt={message.isUser ? 'User' : 'AI'} | ||||||
|  |             sx={{ width: 40, height: 40 }} | ||||||
|  |           /> | ||||||
|  |           <Paper | ||||||
|  |             elevation={1} | ||||||
|  |             sx={{ | ||||||
|  |               px: 2, | ||||||
|  |               py: 1.5, | ||||||
|  |               flex: 1, | ||||||
|  |               bgcolor: message.isUser ? 'primary.main' : 'background.paper', | ||||||
|  |               color: message.isUser ? 'primary.contrastText' : 'text.primary', | ||||||
|  |               borderRadius: 2, | ||||||
|  |             }} | ||||||
|  |           > | ||||||
|  |             <MessageContent text={message.text} /> | ||||||
|  |             {message.sources && message.sources.length > 0 && ( | ||||||
|  |               <Box sx={{ mt: 2, pt: 1, borderTop: '1px solid', borderColor: 'divider' }}> | ||||||
|  |                 <Typography variant="caption" color="text.secondary"> | ||||||
|                   Sources: |                   Sources: | ||||||
|                 </Typography> |                 </Typography> | ||||||
|                 {message.sources.map((source, index) => ( |                 {message.sources.map((source, index) => ( | ||||||
| @ -180,27 +304,17 @@ export default function MessageList({ messages }: MessageListProps) { | |||||||
|                     variant="caption" |                     variant="caption" | ||||||
|                     component="div" |                     component="div" | ||||||
|                     color="text.secondary" |                     color="text.secondary" | ||||||
|                   sx={{  |  | ||||||
|                     pl: 1, |  | ||||||
|                     borderLeft: '2px solid', |  | ||||||
|                     borderColor: 'divider' |  | ||||||
|                   }} |  | ||||||
|                   > |                   > | ||||||
|                     {source.path} |                     {source.path} | ||||||
|                   </Typography> |                   </Typography> | ||||||
|                 ))} |                 ))} | ||||||
|               </Box> |               </Box> | ||||||
|             )} |             )} | ||||||
|           <Typography |           </Paper> | ||||||
|             variant="caption" |  | ||||||
|             color={message.isUser ? '#ffffff' : 'text.secondary'} |  | ||||||
|             sx={{ display: 'block', mt: 0.5 }} |  | ||||||
|           > |  | ||||||
|             {new Date(message.timestamp).toLocaleTimeString()} |  | ||||||
|           </Typography> |  | ||||||
|           </Box> |  | ||||||
|         </Box> |         </Box> | ||||||
|       ))} |       ))} | ||||||
|     </Box> |     </Box> | ||||||
|   ); |   ); | ||||||
| } | }; | ||||||
|  | 
 | ||||||
|  | export default MessageList; | ||||||
| @ -13,6 +13,8 @@ import { | |||||||
|   Alert, |   Alert, | ||||||
|   Box, |   Box, | ||||||
|   Typography, |   Typography, | ||||||
|  |   TextField, | ||||||
|  |   InputAdornment, | ||||||
| } from '@mui/material'; | } from '@mui/material'; | ||||||
| import {  | import {  | ||||||
|   Folder as FolderIcon, |   Folder as FolderIcon, | ||||||
| @ -21,7 +23,10 @@ import { | |||||||
|   Cloud as DropboxIcon, |   Cloud as DropboxIcon, | ||||||
|   Chat as DiscordIcon, |   Chat as DiscordIcon, | ||||||
|   Computer as LocalIcon, |   Computer as LocalIcon, | ||||||
|  |   Search, | ||||||
|  |   Padding | ||||||
| } from '@mui/icons-material'; | } from '@mui/icons-material'; | ||||||
|  | 
 | ||||||
| import { useElectron } from '../../hooks/useElectron'; | import { useElectron } from '../../hooks/useElectron'; | ||||||
| 
 | 
 | ||||||
| interface Directory { | interface Directory { | ||||||
| @ -105,16 +110,46 @@ 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 | ||||||
|  |       variant="outlined" | ||||||
|  |       size="small" | ||||||
|  |       placeholder="Search..." | ||||||
|  |       InputProps={{ | ||||||
|  |         startAdornment: ( | ||||||
|  |           <InputAdornment position="start"> | ||||||
|  |             <Search className="text-gray-400"/> | ||||||
|  | 
 | ||||||
|  |           </InputAdornment> | ||||||
|  |         ), | ||||||
|  |         sx: {ml:2, | ||||||
|  |           '&::-webkit-scrollbar': { | ||||||
|  |             width: '8px', | ||||||
|  |             background: 'transparent', | ||||||
|  |           }, | ||||||
|  |           '&::-webkit-scrollbar-thumb': { | ||||||
|  |             background: '#2196f3', | ||||||
|  |             borderRadius: '2px', | ||||||
|  |             '&:hover': { | ||||||
|  |               background: '#64b5f6', | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |           '&::-webkit-scrollbar-track': { | ||||||
|  |             background: 'transparent', | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }} | ||||||
|  |     />          <Button  | ||||||
|             variant="contained"  |             variant="contained"  | ||||||
|             onClick={handleOpen} |             onClick={handleOpen} | ||||||
|             size="small" |             size="small" | ||||||
|             sx={{  |             sx={{  | ||||||
|  |               ml:3, | ||||||
|               minWidth: 0, |               minWidth: 0, | ||||||
|               width: '32px', |               width: '64px', | ||||||
|               height: '32px', |               height: '38px', | ||||||
|               borderRadius: '50%', |               borderRadius: '5%', | ||||||
|               padding: 0, |               padding: 0, | ||||||
|               overflow: 'hidden', |               overflow: 'hidden', | ||||||
|               backgroundColor: 'primary.main', |               backgroundColor: 'primary.main', | ||||||
| @ -130,10 +165,10 @@ export default function DirectoryPicker({ onSelect }: DirectoryPickerProps) { | |||||||
|               }, |               }, | ||||||
|               '&:hover': { |               '&:hover': { | ||||||
|                 backgroundColor: 'primary.dark', |                 backgroundColor: 'primary.dark', | ||||||
|                 width: '180px', |                 width: '400%', | ||||||
|                 borderRadius: '16px', |                 borderRadius: '5%', | ||||||
|                 '& .buttonText': { |                 '& .buttonText': { | ||||||
|                   width: '110px', |                   width: '150px', | ||||||
|                   marginLeft: '8px', |                   marginLeft: '8px', | ||||||
|                 }, |                 }, | ||||||
|               }, |               }, | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ export function useLLMConfig() { | |||||||
|       }); |       }); | ||||||
|       setConfig(config || { |       setConfig(config || { | ||||||
|         provider: 'ollama', |         provider: 'ollama', | ||||||
|         model: 'phi4', |         model: 'llama2:7b', | ||||||
|         baseUrl: 'http://localhost:11434', |         baseUrl: 'http://localhost:11434', | ||||||
|         temperature: 0.7, |         temperature: 0.7, | ||||||
|         apiKey: undefined |         apiKey: undefined | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user