Merge branch 'dev' into patch-1
This commit is contained in:
commit
c3096d9574
@ -123,10 +123,10 @@ export class CortexAPI implements ICortexAPI {
|
|||||||
* @param model
|
* @param model
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
updateModel(model: object): Promise<void> {
|
updateModel(model: Partial<Model>): Promise<void> {
|
||||||
return this.queue.add(() =>
|
return this.queue.add(() =>
|
||||||
ky
|
ky
|
||||||
.patch(`${API_URL}/v1/models/${model}`, { json: { model } })
|
.patch(`${API_URL}/v1/models/${model.id}`, { json: { ...model } })
|
||||||
.json()
|
.json()
|
||||||
.then()
|
.then()
|
||||||
)
|
)
|
||||||
|
|||||||
@ -193,7 +193,13 @@ export default class JanModelExtension extends ModelExtension {
|
|||||||
]) // Copied models
|
]) // Copied models
|
||||||
: model.sources[0].url, // Symlink models,
|
: model.sources[0].url, // Symlink models,
|
||||||
model.name
|
model.name
|
||||||
)
|
).then((e) => {
|
||||||
|
this.updateModel({
|
||||||
|
id: model.id,
|
||||||
|
...model.settings,
|
||||||
|
...model.parameters,
|
||||||
|
} as Partial<Model>)
|
||||||
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,17 @@ import { PropsWithChildren, useCallback, useEffect } from 'react'
|
|||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { DownloadEvent, events, DownloadState, ModelEvent } from '@janhq/core'
|
import {
|
||||||
|
DownloadEvent,
|
||||||
|
events,
|
||||||
|
DownloadState,
|
||||||
|
ModelEvent,
|
||||||
|
ExtensionTypeEnum,
|
||||||
|
ModelExtension,
|
||||||
|
ModelManager,
|
||||||
|
Model,
|
||||||
|
} from '@janhq/core'
|
||||||
|
|
||||||
import { useSetAtom } from 'jotai'
|
import { useSetAtom } from 'jotai'
|
||||||
|
|
||||||
import { setDownloadStateAtom } from '@/hooks/useDownloadState'
|
import { setDownloadStateAtom } from '@/hooks/useDownloadState'
|
||||||
@ -18,6 +28,7 @@ import EventHandler from './EventHandler'
|
|||||||
import ModelImportListener from './ModelImportListener'
|
import ModelImportListener from './ModelImportListener'
|
||||||
import QuickAskListener from './QuickAskListener'
|
import QuickAskListener from './QuickAskListener'
|
||||||
|
|
||||||
|
import { extensionManager } from '@/extension'
|
||||||
import {
|
import {
|
||||||
InstallingExtensionState,
|
InstallingExtensionState,
|
||||||
removeInstallingExtensionAtom,
|
removeInstallingExtensionAtom,
|
||||||
@ -83,12 +94,24 @@ const EventListenerWrapper = ({ children }: PropsWithChildren) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const onFileDownloadSuccess = useCallback(
|
const onFileDownloadSuccess = useCallback(
|
||||||
(state: DownloadState) => {
|
async (state: DownloadState) => {
|
||||||
console.debug('onFileDownloadSuccess', state)
|
console.debug('onFileDownloadSuccess', state)
|
||||||
if (state.downloadType !== 'extension') {
|
if (state.downloadType !== 'extension') {
|
||||||
|
// Update model metadata accordingly
|
||||||
|
const model = ModelManager.instance().models.get(state.modelId)
|
||||||
|
if (model) {
|
||||||
|
await extensionManager
|
||||||
|
.get<ModelExtension>(ExtensionTypeEnum.Model)
|
||||||
|
?.updateModel({
|
||||||
|
id: model.id,
|
||||||
|
...model.settings,
|
||||||
|
...model.parameters,
|
||||||
|
} as Partial<Model>)
|
||||||
|
.catch((e) => console.debug(e))
|
||||||
|
}
|
||||||
state.downloadState = 'end'
|
state.downloadState = 'end'
|
||||||
setDownloadState(state)
|
setDownloadState(state)
|
||||||
if (state.percent !== 0) removeDownloadingModel(state.modelId)
|
removeDownloadingModel(state.modelId)
|
||||||
}
|
}
|
||||||
events.emit(ModelEvent.OnModelsUpdate, {})
|
events.emit(ModelEvent.OnModelsUpdate, {})
|
||||||
},
|
},
|
||||||
|
|||||||
@ -35,10 +35,6 @@ const useModels = () => {
|
|||||||
const localModels = (await getModels()).map((e) => ({
|
const localModels = (await getModels()).map((e) => ({
|
||||||
...e,
|
...e,
|
||||||
name: ModelManager.instance().models.get(e.id)?.name ?? e.id,
|
name: ModelManager.instance().models.get(e.id)?.name ?? e.id,
|
||||||
settings:
|
|
||||||
ModelManager.instance().models.get(e.id)?.settings ?? e.settings,
|
|
||||||
parameters:
|
|
||||||
ModelManager.instance().models.get(e.id)?.parameters ?? e.parameters,
|
|
||||||
metadata:
|
metadata:
|
||||||
ModelManager.instance().models.get(e.id)?.metadata ?? e.metadata,
|
ModelManager.instance().models.get(e.id)?.metadata ?? e.metadata,
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -69,6 +69,9 @@ const RichTextEditor = ({
|
|||||||
}: RichTextEditorProps) => {
|
}: RichTextEditorProps) => {
|
||||||
const [editor] = useState(() => withHistory(withReact(createEditor())))
|
const [editor] = useState(() => withHistory(withReact(createEditor())))
|
||||||
const currentLanguage = useRef<string>('plaintext')
|
const currentLanguage = useRef<string>('plaintext')
|
||||||
|
const hasStartBackticks = useRef<boolean>(false)
|
||||||
|
const hasEndBackticks = useRef<boolean>(false)
|
||||||
|
|
||||||
const [currentPrompt, setCurrentPrompt] = useAtom(currentPromptAtom)
|
const [currentPrompt, setCurrentPrompt] = useAtom(currentPromptAtom)
|
||||||
const textareaRef = useRef<HTMLDivElement>(null)
|
const textareaRef = useRef<HTMLDivElement>(null)
|
||||||
const activeThreadId = useAtomValue(getActiveThreadIdAtom)
|
const activeThreadId = useAtomValue(getActiveThreadIdAtom)
|
||||||
@ -133,20 +136,31 @@ const RichTextEditor = ({
|
|||||||
node.children.forEach((child: { text: any }, childIndex: number) => {
|
node.children.forEach((child: { text: any }, childIndex: number) => {
|
||||||
const text = child.text
|
const text = child.text
|
||||||
|
|
||||||
|
const codeBlockStartRegex = /```(\w*)/g
|
||||||
|
const matches = [...currentPrompt.matchAll(codeBlockStartRegex)]
|
||||||
|
|
||||||
|
if (matches.length % 2 !== 0) {
|
||||||
|
hasEndBackticks.current = false
|
||||||
|
}
|
||||||
|
|
||||||
// Match code block start and end
|
// Match code block start and end
|
||||||
const startMatch = text.match(/^```(\w*)$/)
|
const lang = text.match(/^```(\w*)$/)
|
||||||
const endMatch = text.match(/^```$/)
|
const endMatch = text.match(/^```$/)
|
||||||
|
|
||||||
if (startMatch) {
|
if (lang) {
|
||||||
// If it's the start of a code block, store the language
|
// If it's the start of a code block, store the language
|
||||||
currentLanguage.current = startMatch[1] || 'plaintext'
|
currentLanguage.current = lang[1] || 'plaintext'
|
||||||
} else if (endMatch) {
|
} else if (endMatch) {
|
||||||
// Reset language when code block ends
|
// Reset language when code block ends
|
||||||
currentLanguage.current = 'plaintext'
|
currentLanguage.current = 'plaintext'
|
||||||
} else if (currentLanguage.current !== 'plaintext') {
|
} else if (
|
||||||
|
hasStartBackticks.current &&
|
||||||
|
hasEndBackticks.current &&
|
||||||
|
currentLanguage.current !== 'plaintext'
|
||||||
|
) {
|
||||||
// Highlight entire code line if in a code block
|
// Highlight entire code line if in a code block
|
||||||
const leadingSpaces = text.match(/^\s*/)?.[0] ?? '' // Capture leading spaces
|
|
||||||
const codeContent = text.trimStart() // Remove leading spaces for highlighting
|
const codeContent = text.trim() // Remove leading spaces for highlighting
|
||||||
|
|
||||||
let highlighted = ''
|
let highlighted = ''
|
||||||
highlighted = hljs.highlightAuto(codeContent).value
|
highlighted = hljs.highlightAuto(codeContent).value
|
||||||
@ -168,21 +182,9 @@ const RichTextEditor = ({
|
|||||||
|
|
||||||
let slateTextIndex = 0
|
let slateTextIndex = 0
|
||||||
|
|
||||||
// Adjust to include leading spaces in the ranges and preserve formatting
|
|
||||||
ranges.push({
|
|
||||||
anchor: { path: [...path, childIndex], offset: 0 },
|
|
||||||
focus: {
|
|
||||||
path: [...path, childIndex],
|
|
||||||
offset: slateTextIndex,
|
|
||||||
},
|
|
||||||
type: 'code',
|
|
||||||
code: true,
|
|
||||||
language: currentLanguage.current,
|
|
||||||
className: '', // No class for leading spaces
|
|
||||||
})
|
|
||||||
|
|
||||||
doc.body.childNodes.forEach((childNode) => {
|
doc.body.childNodes.forEach((childNode) => {
|
||||||
const childText = childNode.textContent || ''
|
const childText = childNode.textContent || ''
|
||||||
|
|
||||||
const length = childText.length
|
const length = childText.length
|
||||||
const className =
|
const className =
|
||||||
childNode.nodeType === Node.ELEMENT_NODE
|
childNode.nodeType === Node.ELEMENT_NODE
|
||||||
@ -192,11 +194,11 @@ const RichTextEditor = ({
|
|||||||
ranges.push({
|
ranges.push({
|
||||||
anchor: {
|
anchor: {
|
||||||
path: [...path, childIndex],
|
path: [...path, childIndex],
|
||||||
offset: slateTextIndex + leadingSpaces.length,
|
offset: slateTextIndex,
|
||||||
},
|
},
|
||||||
focus: {
|
focus: {
|
||||||
path: [...path, childIndex],
|
path: [...path, childIndex],
|
||||||
offset: slateTextIndex + leadingSpaces.length + length,
|
offset: slateTextIndex + length,
|
||||||
},
|
},
|
||||||
type: 'code',
|
type: 'code',
|
||||||
code: true,
|
code: true,
|
||||||
@ -220,7 +222,7 @@ const RichTextEditor = ({
|
|||||||
|
|
||||||
return ranges
|
return ranges
|
||||||
},
|
},
|
||||||
[editor]
|
[currentPrompt, editor]
|
||||||
)
|
)
|
||||||
|
|
||||||
// RenderLeaf applies the decoration styles
|
// RenderLeaf applies the decoration styles
|
||||||
@ -340,9 +342,20 @@ const RichTextEditor = ({
|
|||||||
currentLanguage.current = 'plaintext'
|
currentLanguage.current = 'plaintext'
|
||||||
}
|
}
|
||||||
const hasCodeBlockStart = combinedText.match(/^```(\w*)/m)
|
const hasCodeBlockStart = combinedText.match(/^```(\w*)/m)
|
||||||
|
const hasCodeBlockEnd = combinedText.match(/^```$/m)
|
||||||
|
|
||||||
// Set language to plaintext if no code block with language identifier is found
|
// Set language to plaintext if no code block with language identifier is found
|
||||||
if (!hasCodeBlockStart) {
|
if (!hasCodeBlockStart) {
|
||||||
currentLanguage.current = 'plaintext'
|
currentLanguage.current = 'plaintext'
|
||||||
|
hasStartBackticks.current = false
|
||||||
|
} else {
|
||||||
|
hasStartBackticks.current = true
|
||||||
|
}
|
||||||
|
if (!hasCodeBlockEnd) {
|
||||||
|
currentLanguage.current = 'plaintext'
|
||||||
|
hasEndBackticks.current = false
|
||||||
|
} else {
|
||||||
|
hasEndBackticks.current = true
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user