Skip to content

Commit

Permalink
release(1.4.0): wasm embedding & vector store in Browser memory, cach…
Browse files Browse the repository at this point in the history
…e in disk.

1. add langchain support
2. add knowledge storage for document embedding.
3. memory support for ville or document.
4. web preview can edit.
5. all in web(embedding use wasm embedding in browser, vector store use Browser memory, cache in disk)
  • Loading branch information
10cl committed Jan 15, 2024
1 parent d157cea commit 9aec3c2
Show file tree
Hide file tree
Showing 17 changed files with 691 additions and 790 deletions.
5 changes: 4 additions & 1 deletion manifest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default defineManifest(async (env) => {
name: '__MSG_appName__',
description: '__MSG_appDesc__',
default_locale: 'en',
version: '1.3.2',
version: '1.4.0',
icons: {
'16': 'src/assets/icon.png',
'32': 'src/assets/icon.png',
Expand All @@ -28,6 +28,9 @@ export default defineManifest(async (env) => {
'https://*.anthropic.com/',
'https://*.claude.ai/',
],
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
},
optional_host_permissions: ['https://*/*', 'wss://*/*'],
permissions: ['storage', 'unlimitedStorage', 'sidePanel', 'declarativeNetRequestWithHostAccess'],
content_scripts: [
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
"@sentry/integrations": "^7.54.0",
"@sentry/react": "^7.54.0",
"@tanstack/react-router": "^0.0.1-beta.83",
"@tensorflow-models/universal-sentence-encoder": "1.3.3",
"@tensorflow/tfjs-backend-webgl": "^4.15.0",
"@tensorflow/tfjs-converter": "3.6.0",
"@tensorflow/tfjs-core": "3.6.0",
"@xenova/transformers": "^2.5.4",
"ace-builds": "^1.26.0",
"browser-fs-access": "^0.34.1",
Expand Down
260 changes: 141 additions & 119 deletions src/app/components/Agent/AgentCommunity.tsx
Original file line number Diff line number Diff line change
@@ -1,143 +1,165 @@
import {Suspense, useCallback, useEffect, useMemo, useState} from 'react'
import {FC, Suspense, useCallback, useContext, useEffect, useMemo, useState} from 'react'
import {useTranslation} from 'react-i18next'
import {BeatLoader} from 'react-spinners'
import useSWR from 'swr'
import {getStore, loadRemotePrompts, loadYaml, PromptLab, setStore} from '~services/prompts'
import {loadRemotePrompts, loadYaml, PromptLab} from '~services/prompts'
import {GoBook} from "react-icons/go";
import {importFromText} from "~app/utils/export";
import {useAtom} from "jotai/index";
import Tabs, {Tab} from '../Tabs'
import {Toaster, toast} from "react-hot-toast";

import {
editorPromptAtom,
editorPromptTimesAtom,
editorYamlTimesAtom,
seminarDisableAtom, showEditorAtom, showGptsDialogAtom,
sidebarCollapsedAtom,
workFlowingDisableAtom
editorPromptAtom,
editorPromptTimesAtom,
editorYamlTimesAtom, gameModeEnable,
seminarDisableAtom, showEditorAtom, showGptsDialogAtom,
workFlowingDisableAtom
} from "~app/state";
import {trackEvent} from "~app/plausible";
import {getStore, setRealYamlKey, setStore} from "~services/storage/memory-store";
import {BotId} from "~app/bots";
import {ChatMessageModel} from "~types";
import {ConversationContext} from "~app/context";

const ActionButton = (props: { text: string; onClick: () => void }) => {
return (
<a
className="inline-flex items-center rounded-full bg-white px-2.5 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 cursor-pointer"
onClick={props.onClick}
>
{props.text}
</a>
)
return (
<a
className="inline-flex items-center rounded-full bg-white px-2.5 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 cursor-pointer"
onClick={props.onClick}
>
{props.text}
</a>
)
}

const PromptLabItem = (props: {
title: string
intro: string
author: string
share: string
title: string
intro: string
author: string
share: string
}) => {
const {t} = useTranslation()
const [seminarDisable, setSeminarDisable] = useAtom(seminarDisableAtom)
const [workFlowingDisable, setWorkFlowingDisable] = useAtom(workFlowingDisableAtom)
const [editorPromptTimes, setEditorPromptTimes] = useAtom(editorPromptTimesAtom)
const [editorYamlTimes, setEditorYamlTimes] = useAtom(editorYamlTimesAtom)
const [showAssistant, setShowAssistant] = useAtom(showGptsDialogAtom)
const confirmTips = t('Are you sure you want to import the Agent?')
const successTips = t('Imported Agent successfully')
const successEditTips = t('Import succeeded. Do you need to edit?')
const [showEditor, setShowEditor] = useAtom(showEditorAtom)
const [editorPrompt, setEditorPrompt] = useAtom(editorPromptAtom)

const importToFlowYaml = useCallback(() => {
if (!window.confirm(confirmTips)) {
return
const {t} = useTranslation()
const [seminarDisable, setSeminarDisable] = useAtom(seminarDisableAtom)
const [workFlowingDisable, setWorkFlowingDisable] = useAtom(workFlowingDisableAtom)
const [editorPromptTimes, setEditorPromptTimes] = useAtom(editorPromptTimesAtom)
const [editorYamlTimes, setEditorYamlTimes] = useAtom(editorYamlTimesAtom)
const [showAssistant, setShowAssistant] = useAtom(showGptsDialogAtom)
const confirmTips = t('Are you sure you want to import the Agent?')
const successTips = t('Imported Agent successfully')
const successEditTips = t('Import succeeded. Do you need to edit?')
const [showEditor, setShowEditor] = useAtom(showEditorAtom)
const [editorPrompt, setEditorPrompt] = useAtom(editorPromptAtom)
const [isGameMode, setGameModeEnable] = useAtom(gameModeEnable)
const conversation = useContext(ConversationContext)

const importToFlowYaml = useCallback(() => {
/* if (!window.confirm(confirmTips)) {
return
}*/
setShowAssistant(false)
setSeminarDisable(false)
setWorkFlowingDisable(false)
setShowEditor(false)

setGameModeEnable(false)
setStore("gameModeEnable", false)

setRealYamlKey("Default_Flow_Dag_Yaml")

toast.promise(
loadYaml(props.share).then(promptYaml => {
try {
importFromText(JSON.parse(promptYaml.yaml))
} catch (e) {
alert(e)
}
loadYaml(props.share).then(promptYaml => {
try {
importFromText(JSON.parse(promptYaml.yaml)).then(() => {
setShowAssistant(false)
setSeminarDisable(false)
setWorkFlowingDisable(false)

const editorYamlTimes = getStore("editorYamlTimes", 0) + 1
setEditorYamlTimes(editorYamlTimes)
setStore("editorYamlTimes", editorYamlTimes)

if (!window.confirm(successEditTips)) {
return
}

// setEditorPrompt("Flow_Dag_Yaml")
const isGameMode = getStore("gameModeEnable", true)
setStore("real_yaml", getStore(isGameMode?"editor_yaml":"real_yaml", "Default_Flow_Dag_Yaml"))
if (getStore("prompts")[getStore("real_yaml", "Default_Flow_Dag_Yaml")] == undefined) {
getStore("prompts")[getStore("real_yaml", "Default_Flow_Dag_Yaml")] = getStore("prompts")["Action_YAML_Template"]
}
setEditorPrompt("Action_Prompt_Template");

setEditorPromptTimes(editorPromptTimes + 1)
setShowEditor(true)
setStore("editor_show", true)

setShowAssistant(false)
})
}catch (e) {
alert(e)
}
})
}, [props])

const detailShow = useCallback(() => {

}, [props])

return (
<div
className="group relative flex items-center space-x-3 rounded-lg border border-primary-border bg-primary-background px-5 py-4 shadow-sm hover:border-gray-400">
<div className="min-w-0 flex-1">
<p title={props.title}
className="truncate text-sm font-semibold text-primary-text italic pl-1">{props.title}</p>
<div title={props.intro} className="text-primary-text line-clamp-1 prompt-intro">{props.intro}</div>
</div>
<div className="flex flex-row gap-1">
<a target="_blank" href={"https://chatdev.toscl.com/s/" + props.share} rel="noreferrer">
<ActionButton text={t('detail')} onClick={detailShow}/>
</a>
</div>
<div className="flex flex-row gap-1">
<ActionButton text={t('Import')} onClick={importToFlowYaml}/>
</div>
</div>
)
}),
{
loading: t('Load Agent...'),
success: <b>{t('Load success.')}</b>,
error: <b>{t('Load failed.')}</b>,
}, {
position: "top-center"
}
);
conversation?.reset()
}, [props])

const detailShow = useCallback(() => {
trackEvent("detail_show")
}, [props])

return (
<div /*onClick={importToFlowYaml}*/
className="group relative flex items-center space-x-3 rounded-lg border border-primary-border bg-primary-background px-5 py-4 shadow-sm hover:border-gray-400">
<div className="min-w-0 flex-1">
<p title={props.title}
className="truncate text-sm font-semibold text-primary-text italic pl-1">{props.title}</p>
<div title={props.intro} className="text-primary-text line-clamp-1 prompt-intro">{props.intro}</div>
</div>
<div className="flex flex-row gap-1">
<a target="_blank" href={"https://chatdev.toscl.com/s/" + props.share} rel="noreferrer">
<ActionButton text={t('detail')} onClick={detailShow}/>
</a>
</div>
<div className="flex flex-row gap-1">
<ActionButton text={t('Use')} onClick={importToFlowYaml}/>
</div>
</div>
)
}

function CommunityPrompts() {
const promptsQuery = useSWR('community-prompts', () => loadRemotePrompts(), {suspense: true})

return (
<>{promptsQuery.data.length > 0 && promptsQuery.data[0] && promptsQuery.data[0].title ? (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 pt-2">
{promptsQuery.data.map((promptLab, index) => (
<PromptLabItem
key={index}
title={promptLab.title}
intro={promptLab.intro}
author={promptLab.author}
share={promptLab.share}
/>
))}
</div>): (
<div className="relative block w-full rounded-lg border-2 border-dashed border-gray-300 p-3 text-center text-sm mt-5 text-primary-text">
You have no prompts.
</div>
)}
</>
)
interface Props {
tab: string
}
const CommunityPrompts: FC<Props> = (props) => {
const promptsQuery = useSWR('community-prompts', () => loadRemotePrompts(props.tab), {suspense: true})

return (
<>{promptsQuery.data.length > 0 && promptsQuery.data[0] && promptsQuery.data[0].title ? (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 pt-2">
{promptsQuery.data.map((promptLab, index) => (
<PromptLabItem
key={index}
title={promptLab.title}
intro={promptLab.intro}
author={promptLab.author}
share={promptLab.share}
/>
))}
</div>) : (
<div
className="relative block w-full rounded-lg border-2 border-dashed border-gray-300 p-3 text-center text-sm mt-5 text-primary-text">
There is no agent.
</div>
)}
</>
)
}

const AgentCommunity = () => {

const {t} = useTranslation()

const tabs = useMemo<Tab[]>(
() => [
{name: t('All'), value: ''},
// {name: t('Tools'), value: 'tools'},
// {name: t('Learning'), value: 'learning'},
// {name: t('Advice'), value: 'advice'},
// {name: t('NPC'), value: 'npc'},
],
[t],
)

return (<Tabs tabs={tabs} renderTab={(tab: (typeof tabs)[0]['value']) => {
return (
<Suspense fallback={<BeatLoader size={10} className="mt-5" color="rgb(var(--primary-text))"/>}>
<CommunityPrompts/>
</Suspense>
<Suspense fallback={<BeatLoader size={10} className="mt-5" color="rgb(var(--primary-text))"/>}>
<CommunityPrompts tab={tab}/>
</Suspense>
)
}}
/>
)
}

export default AgentCommunity
Loading

0 comments on commit 9aec3c2

Please sign in to comment.