mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
code highlighting in progress
This commit is contained in:
parent
187f7b5b03
commit
e95e22de15
10 changed files with 169 additions and 18 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
|
@ -2,7 +2,7 @@
|
|||
"editor.lightbulb.enabled": false,
|
||||
"editor.parameterHints.enabled": false,
|
||||
"editor.renderWhitespace": "all",
|
||||
"editor.snippetSuggestions": "none",
|
||||
// "editor.snippetSuggestions": "none",
|
||||
"editor.tabSize": 2,
|
||||
"editor.wordWrap": "on",
|
||||
"emmet.showExpandedAbbreviation": "never",
|
||||
|
|
|
|||
46
package-lock.json
generated
46
package-lock.json
generated
|
|
@ -20,6 +20,7 @@
|
|||
"cors": "^2.8.5",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"highlight.js": "^11.7.0",
|
||||
"keyv": "^4.5.2",
|
||||
"keyv-file": "^0.2.0",
|
||||
"lucide-react": "^0.113.0",
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
"openai": "^3.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-highlight": "^0.15.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-textarea-autosize": "^8.4.0",
|
||||
"react-transition-group": "^4.4.5",
|
||||
|
|
@ -8722,6 +8724,14 @@
|
|||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/highlight.js": {
|
||||
"version": "11.7.0",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
|
||||
"integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
|
|
@ -12211,6 +12221,22 @@
|
|||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-highlight": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.15.0.tgz",
|
||||
"integrity": "sha512-5uV/b/N4Z421GSVVe05fz+OfTsJtFzx/fJBdafZyw4LS70XjIZwgEx3Lrkfc01W/RzZ2Dtfb0DApoaJFAIKBtA==",
|
||||
"dependencies": {
|
||||
"highlight.js": "^10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-highlight/node_modules/highlight.js": {
|
||||
"version": "10.7.3",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
|
|
@ -21488,6 +21514,11 @@
|
|||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"highlight.js": {
|
||||
"version": "11.7.0",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
|
||||
"integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ=="
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
|
|
@ -23885,6 +23916,21 @@
|
|||
"scheduler": "^0.23.0"
|
||||
}
|
||||
},
|
||||
"react-highlight": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.15.0.tgz",
|
||||
"integrity": "sha512-5uV/b/N4Z421GSVVe05fz+OfTsJtFzx/fJBdafZyw4LS70XjIZwgEx3Lrkfc01W/RzZ2Dtfb0DApoaJFAIKBtA==",
|
||||
"requires": {
|
||||
"highlight.js": "^10.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"highlight.js": {
|
||||
"version": "10.7.3",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
"cors": "^2.8.5",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"highlight.js": "^11.7.0",
|
||||
"keyv": "^4.5.2",
|
||||
"keyv-file": "^0.2.0",
|
||||
"lucide-react": "^0.113.0",
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
"openai": "^3.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-highlight": "^0.15.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-textarea-autosize": "^8.4.0",
|
||||
"react-transition-group": "^4.4.5",
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ router.post('/', async (req, res) => {
|
|||
}
|
||||
|
||||
if (!parentMessageId) {
|
||||
gptResponse.title = await titleConvo(text, gptResponse.text, model);
|
||||
gptResponse.title = await titleConvo(text, JSON.stringify(gptResponse.text), model);
|
||||
}
|
||||
gptResponse.sender = model;
|
||||
gptResponse.final = true;
|
||||
|
|
|
|||
1
src/atom-one-dark.css
Normal file
1
src/atom-one-dark.css
Normal file
|
|
@ -0,0 +1 @@
|
|||
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
|
||||
|
|
@ -1,18 +1,55 @@
|
|||
import React from 'react';
|
||||
import Embed from './Embed';
|
||||
import hljs from 'highlight.js';
|
||||
import Highlight from 'react-highlight';
|
||||
|
||||
export default function CodeWrapper({ text }) {
|
||||
const matchRegex = /(`[^`]+?`)/g;
|
||||
const parts = text.split(matchRegex);
|
||||
// console.log('parts', parts);
|
||||
if (text.includes('```')) {
|
||||
const codeRegex = /(```[^`]+?```)/g;
|
||||
const inLineRegex = /(`[^`]+?`)/g;
|
||||
const parts = text.split(codeRegex);
|
||||
// console.log(parts);
|
||||
const codeParts = parts.map((part, i) => {
|
||||
if (part.match(codeRegex)) {
|
||||
return (
|
||||
<Embed
|
||||
key={i}
|
||||
language="javascript"
|
||||
>
|
||||
{hljs.highlightAuto(part.slice(1, -1)).value}
|
||||
{/* <Highlight className="!whitespace-pre">{part.slice(1, -1)}</Highlight> */}
|
||||
|
||||
// map over the parts and wrap any text between tildes with <code> tags
|
||||
const codeParts = parts.map((part, index) => {
|
||||
if (part.match(matchRegex)) {
|
||||
return <code key={index}>{part.slice(1, -1)}</code>;
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
</Embed>
|
||||
);
|
||||
} else if (part.match(inLineRegex)) {
|
||||
const innerParts = part.split(inLineRegex);
|
||||
return innerParts.map((part, i) => {
|
||||
if (part.match(inLineRegex)) {
|
||||
return <code key={i}>{part.slice(1, -1)}</code>;
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
|
||||
return <>{codeParts}</>; // return the wrapped text
|
||||
}
|
||||
return <>{codeParts}</>; // return the wrapped text
|
||||
} else {
|
||||
const matchRegex = /(`[^`]+?`)/g;
|
||||
const parts = text.split(matchRegex);
|
||||
// console.log('parts', parts);
|
||||
|
||||
// map over the parts and wrap any text between tildes with <code> tags
|
||||
const codeParts = parts.map((part, i) => {
|
||||
if (part.match(matchRegex)) {
|
||||
return <code key={i}>{part.slice(1, -1)}</code>;
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
|
||||
return <>{codeParts}</>; // return the wrapped text
|
||||
}
|
||||
}
|
||||
|
|
|
|||
62
src/components/Messages/Embed.jsx
Normal file
62
src/components/Messages/Embed.jsx
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import React from 'react';
|
||||
// import '~/atom-one-dark.css';
|
||||
|
||||
export default function Embed({ children, language = ''}) {
|
||||
return (
|
||||
<pre>
|
||||
<div className="mb-4 rounded-md bg-black">
|
||||
<div className="relative flex items-center bg-gray-800 px-4 py-2 font-sans text-xs text-gray-200">
|
||||
<span className="">{ language }</span>
|
||||
<button className="ml-auto flex gap-2">
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path>
|
||||
<rect
|
||||
x="8"
|
||||
y="2"
|
||||
width="8"
|
||||
height="4"
|
||||
rx="1"
|
||||
ry="1"
|
||||
></rect>
|
||||
</svg>
|
||||
Copy code
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-y-auto p-4">
|
||||
{ children }
|
||||
{/* <span className="hljs-keyword">export</span> <span className="hljs-keyword">default</span> <span className="hljs-keyword">function</span> <span className="hljs-title function_">CodeWrapper</span>(<span className="hljs-params">{ text }</span>) {
|
||||
<span className="hljs-keyword">const</span> matchRegex = <span className="hljs-regexp">/(`[^`]+?`)/g</span>; <span className="hljs-comment">// regex to match backticks and text between them</span>
|
||||
<span className="hljs-keyword">const</span> parts = text.<span className="hljs-title function_">split</span>(matchRegex);
|
||||
<span className="hljs-variable language_">console</span>.<span className="hljs-title function_">log</span>(<span className="hljs-string">'parts'</span>, parts);
|
||||
|
||||
<span className="hljs-comment">// map over the parts and wrap any backticked text with <code> tags</span>
|
||||
<span className="hljs-keyword">const</span> codeParts = parts.<span className="hljs-title function_">map</span>(<span className="hljs-function">(<span className="hljs-params">part, index</span>) =></span> {
|
||||
<span className="hljs-keyword">if</span> (part.<span className="hljs-title function_">match</span>(matchRegex)) {
|
||||
<>
|
||||
<span className="hljs-keyword">return</span> <span className="xml"><span className="hljs-tag"><<span className="hljs-name">code</span> <span className="hljs-attr">key</span>=<span className="hljs-string">{index}</span>></span>{part}<span className="hljs-tag"></<span className="hljs-name">code</span>></span></span>;
|
||||
</>
|
||||
} <span className="hljs-keyword">else</span> {
|
||||
<>
|
||||
<span className="hljs-keyword">return</span> part.<span className="hljs-title function_">trim</span>(); <span className="hljs-comment">// remove leading/trailing whitespace from non-backticked text</span>
|
||||
</>
|
||||
}
|
||||
});
|
||||
|
||||
<span className="hljs-keyword">return</span> <span className="xml"><span className="hljs-tag"><></span>{codeParts}<span className="hljs-tag"></></span></span>; <span className="hljs-comment">// return the wrapped text</span>
|
||||
} */}
|
||||
</div>
|
||||
</div>
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ export default function Nav() {
|
|||
onMouseLeave={() => setIsHovering(false)}
|
||||
>
|
||||
<div className="flex flex-col gap-2 text-sm text-gray-100">
|
||||
{!!isLoading ? <Spinner /> : <Conversations conversations={data} conversationId={conversationId}/>}
|
||||
{isLoading ? <Spinner /> : <Conversations conversations={data} conversationId={conversationId}/>}
|
||||
</div>
|
||||
</div>
|
||||
<NavLinks />
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export default function TextChat({ messages }) {
|
|||
};
|
||||
const convoHandler = (data) => {
|
||||
console.log('in convo handler');
|
||||
if (model !== 'bingai' && convo.conversationId && convo.parentMessageId === null) {
|
||||
if (model !== 'bingai' && convo.conversationId === null && convo.parentMessageId === null) {
|
||||
const { title, conversationId, id } = data;
|
||||
console.log('parentMessageId is null');
|
||||
console.log('title, convoId, id', title, conversationId, id);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { SSE } from '../../app/sse';
|
||||
const endpoint = 'http://localhost:3050/ask';
|
||||
// const newLineRegex = /^\n+/;
|
||||
|
||||
export default function handleSubmit({
|
||||
model,
|
||||
|
|
@ -40,8 +41,10 @@ export default function handleSubmit({
|
|||
|
||||
events.onmessage = function (e) {
|
||||
const data = JSON.parse(e.data);
|
||||
const text = data.text || data.response;
|
||||
let text = data.text || data.response;
|
||||
if (data.message) {
|
||||
// text = text.match(newLineRegex) ? text.replace(newLineRegex, '') : text;
|
||||
// console.log(data);
|
||||
messageHandler(text);
|
||||
} else if (data.final) {
|
||||
console.log(data);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue