Plugin/merge main to plugin/beta 20250122 (#12962)

Signed-off-by: yihong0618 <zouzou0208@gmail.com>
Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: kurokobo <kuro664@gmail.com>
Co-authored-by: Hiroshi Fujita <fujita-h@users.noreply.github.com>
Co-authored-by: NFish <douxc512@gmail.com>
Co-authored-by: Gen Sato <52241300+halogen22@users.noreply.github.com>
Co-authored-by: eux <euxuuu@gmail.com>
Co-authored-by: huangzhuo1949 <167434202+huangzhuo1949@users.noreply.github.com>
Co-authored-by: huangzhuo <huangzhuo1@xiaomi.com>
Co-authored-by: lotsik <lotsik@mail.ru>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: gakkiyomi <gakkiyomi@aliyun.com>
Co-authored-by: CN-P5 <heibai2006@gmail.com>
Co-authored-by: CN-P5 <heibai2006@qq.com>
Co-authored-by: Chuehnone <1897025+chuehnone@users.noreply.github.com>
Co-authored-by: yihong <zouzou0208@gmail.com>
Co-authored-by: Kevin9703 <51311316+Kevin9703@users.noreply.github.com>
Co-authored-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: Boris Feld <lothiraldan@gmail.com>
Co-authored-by: mbo <himabo@gmail.com>
Co-authored-by: mabo <mabo@aeyes.ai>
Co-authored-by: Warren Chen <warren.chen830@gmail.com>
Co-authored-by: KVOJJJin <jzongcode@gmail.com>
Co-authored-by: JzoNgKVO <27049666+JzoNgKVO@users.noreply.github.com>
Co-authored-by: jiandanfeng <chenjh3@wangsu.com>
Co-authored-by: zhu-an <70234959+xhdd123321@users.noreply.github.com>
Co-authored-by: zhaoqingyu.1075 <zhaoqingyu.1075@bytedance.com>
Co-authored-by: 海狸大師 <86974027+yenslife@users.noreply.github.com>
Co-authored-by: Xu Song <xusong.vip@gmail.com>
Co-authored-by: rayshaw001 <396301947@163.com>
Co-authored-by: Ding Jiatong <dingjiatong@gmail.com>
Co-authored-by: Bowen Liang <liangbowen@gf.com.cn>
Co-authored-by: JasonVV <jasonwangiii@outlook.com>
Co-authored-by: le0zh <newlight@qq.com>
Co-authored-by: zhuxinliang <zhuxinliang@didiglobal.com>
Co-authored-by: k-zaku <zaku99@outlook.jp>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: luckylhb90 <luckylhb90@gmail.com>
Co-authored-by: hobo.l <hobo.l@binance.com>
Co-authored-by: jiangbo721 <365065261@qq.com>
Co-authored-by: 刘江波 <jiangbo721@163.com>
Co-authored-by: Shun Miyazawa <34241526+miya@users.noreply.github.com>
Co-authored-by: EricPan <30651140+Egfly@users.noreply.github.com>
Co-authored-by: crazywoola <427733928@qq.com>
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: sino <sino2322@gmail.com>
Co-authored-by: Jhvcc <37662342+Jhvcc@users.noreply.github.com>
Co-authored-by: lowell <lowell.hu@zkteco.in>
This commit is contained in:
Yeuoly
2025-01-23 14:48:16 +08:00
committed by GitHub
parent 8d8d3e3f2f
commit 899df30bf6
238 changed files with 4121 additions and 890 deletions

View File

@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import TracingIcon from './tracing-icon'
import ProviderPanel from './provider-panel'
import type { LangFuseConfig, LangSmithConfig } from './type'
import type { LangFuseConfig, LangSmithConfig, OpikConfig } from './type'
import { TracingProvider } from './type'
import ProviderConfigModal from './provider-config-modal'
import Indicator from '@/app/components/header/indicator'
@ -25,7 +25,8 @@ export type PopupProps = {
onChooseProvider: (provider: TracingProvider) => void
langSmithConfig: LangSmithConfig | null
langFuseConfig: LangFuseConfig | null
onConfigUpdated: (provider: TracingProvider, payload: LangSmithConfig | LangFuseConfig) => void
opikConfig: OpikConfig | null
onConfigUpdated: (provider: TracingProvider, payload: LangSmithConfig | LangFuseConfig | OpikConfig) => void
onConfigRemoved: (provider: TracingProvider) => void
}
@ -38,6 +39,7 @@ const ConfigPopup: FC<PopupProps> = ({
onChooseProvider,
langSmithConfig,
langFuseConfig,
opikConfig,
onConfigUpdated,
onConfigRemoved,
}) => {
@ -61,7 +63,7 @@ const ConfigPopup: FC<PopupProps> = ({
}
}, [onChooseProvider])
const handleConfigUpdated = useCallback((payload: LangSmithConfig | LangFuseConfig) => {
const handleConfigUpdated = useCallback((payload: LangSmithConfig | LangFuseConfig | OpikConfig) => {
onConfigUpdated(currentProvider!, payload)
hideConfigModal()
}, [currentProvider, hideConfigModal, onConfigUpdated])
@ -71,8 +73,8 @@ const ConfigPopup: FC<PopupProps> = ({
hideConfigModal()
}, [currentProvider, hideConfigModal, onConfigRemoved])
const providerAllConfigured = langSmithConfig && langFuseConfig
const providerAllNotConfigured = !langSmithConfig && !langFuseConfig
const providerAllConfigured = langSmithConfig && langFuseConfig && opikConfig
const providerAllNotConfigured = !langSmithConfig && !langFuseConfig && !opikConfig
const switchContent = (
<Switch
@ -91,6 +93,7 @@ const ConfigPopup: FC<PopupProps> = ({
onConfig={handleOnConfig(TracingProvider.langSmith)}
isChosen={chosenProvider === TracingProvider.langSmith}
onChoose={handleOnChoose(TracingProvider.langSmith)}
key="langSmith-provider-panel"
/>
)
@ -103,9 +106,61 @@ const ConfigPopup: FC<PopupProps> = ({
onConfig={handleOnConfig(TracingProvider.langfuse)}
isChosen={chosenProvider === TracingProvider.langfuse}
onChoose={handleOnChoose(TracingProvider.langfuse)}
key="langfuse-provider-panel"
/>
)
const opikPanel = (
<ProviderPanel
type={TracingProvider.opik}
readOnly={readOnly}
config={opikConfig}
hasConfigured={!!opikConfig}
onConfig={handleOnConfig(TracingProvider.opik)}
isChosen={chosenProvider === TracingProvider.opik}
onChoose={handleOnChoose(TracingProvider.opik)}
key="opik-provider-panel"
/>
)
const configuredProviderPanel = () => {
const configuredPanels: ProviderPanel[] = []
if (langSmithConfig)
configuredPanels.push(langSmithPanel)
if (langFuseConfig)
configuredPanels.push(langfusePanel)
if (opikConfig)
configuredPanels.push(opikPanel)
return configuredPanels
}
const moreProviderPanel = () => {
const notConfiguredPanels: ProviderPanel[] = []
if (!langSmithConfig)
notConfiguredPanels.push(langSmithPanel)
if (!langFuseConfig)
notConfiguredPanels.push(langfusePanel)
if (!opikConfig)
notConfiguredPanels.push(opikPanel)
return notConfiguredPanels
}
const configuredProviderConfig = () => {
if (currentProvider === TracingProvider.langSmith)
return langSmithConfig
if (currentProvider === TracingProvider.langfuse)
return langFuseConfig
return opikConfig
}
return (
<div className='w-[420px] p-4 rounded-2xl bg-components-panel-bg border-[0.5px] border-components-panel-border shadow-xl'>
<div className='flex justify-between items-center'>
@ -146,6 +201,7 @@ const ConfigPopup: FC<PopupProps> = ({
<div className='mt-2 space-y-2'>
{langSmithPanel}
{langfusePanel}
{opikPanel}
</div>
</>
)
@ -167,7 +223,7 @@ const ConfigPopup: FC<PopupProps> = ({
<ProviderConfigModal
appId={appId}
type={currentProvider!}
payload={currentProvider === TracingProvider.langSmith ? langSmithConfig : langFuseConfig}
payload={configuredProviderConfig()}
onCancel={hideConfigModal}
onSaved={handleConfigUpdated}
onChosen={onChooseProvider}

View File

@ -3,4 +3,5 @@ import { TracingProvider } from './type'
export const docURL = {
[TracingProvider.langSmith]: 'https://docs.smith.langchain.com/',
[TracingProvider.langfuse]: 'https://docs.langfuse.com',
[TracingProvider.opik]: 'https://www.comet.com/docs/opik/tracing/integrations/dify#setup-instructions',
}

View File

@ -74,11 +74,20 @@ const Panel: FC = () => {
})
}
const inUseTracingProvider: TracingProvider | null = tracingStatus?.tracing_provider || null
const InUseProviderIcon = inUseTracingProvider === TracingProvider.langSmith ? LangsmithIcon : LangfuseIcon
const InUseProviderIcon
= inUseTracingProvider === TracingProvider.langSmith
? LangsmithIcon
: inUseTracingProvider === TracingProvider.langfuse
? LangfuseIcon
: inUseTracingProvider === TracingProvider.opik
? OpikIcon
: null
const [langSmithConfig, setLangSmithConfig] = useState<LangSmithConfig | null>(null)
const [langFuseConfig, setLangFuseConfig] = useState<LangFuseConfig | null>(null)
const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig)
const [opikConfig, setOpikConfig] = useState<OpikConfig | null>(null)
const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig)
const fetchTracingConfig = async () => {
const { tracing_config: langSmithConfig, has_not_configured: langSmithHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.langSmith })
@ -87,6 +96,9 @@ const Panel: FC = () => {
const { tracing_config: langFuseConfig, has_not_configured: langFuseHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.langfuse })
if (!langFuseHasNotConfig)
setLangFuseConfig(langFuseConfig as LangFuseConfig)
const { tracing_config: opikConfig, has_not_configured: OpikHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.opik })
if (!OpikHasNotConfig)
setOpikConfig(opikConfig as OpikConfig)
}
const handleTracingConfigUpdated = async (provider: TracingProvider) => {
@ -94,15 +106,19 @@ const Panel: FC = () => {
const { tracing_config } = await doFetchTracingConfig({ appId, provider })
if (provider === TracingProvider.langSmith)
setLangSmithConfig(tracing_config as LangSmithConfig)
else
else if (provider === TracingProvider.langSmith)
setLangFuseConfig(tracing_config as LangFuseConfig)
else if (provider === TracingProvider.opik)
setOpikConfig(tracing_config as OpikConfig)
}
const handleTracingConfigRemoved = (provider: TracingProvider) => {
if (provider === TracingProvider.langSmith)
setLangSmithConfig(null)
else
else if (provider === TracingProvider.langSmith)
setLangFuseConfig(null)
else if (provider === TracingProvider.opik)
setOpikConfig(null)
if (provider === inUseTracingProvider) {
handleTracingStatusChange({
enabled: false,
@ -201,6 +217,24 @@ const Panel: FC = () => {
</div>
</>
)}
<div className='flex items-center' onClick={e => e.stopPropagation()}>
<ConfigButton
appId={appId}
readOnly={readOnly}
hasConfigured
className='ml-2'
enabled={enabled}
onStatusChange={handleTracingEnabledChange}
chosenProvider={inUseTracingProvider}
onChooseProvider={handleChooseProvider}
langSmithConfig={langSmithConfig}
langFuseConfig={langFuseConfig}
opikConfig={opikConfig}
onConfigUpdated={handleTracingConfigUpdated}
onConfigRemoved={handleTracingConfigRemoved}
controlShowPopup={controlShowPopup}
/>
</div>
</div>
</div>
)

View File

@ -4,7 +4,7 @@ import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import Field from './field'
import type { LangFuseConfig, LangSmithConfig } from './type'
import type { LangFuseConfig, LangSmithConfig, OpikConfig } from './type'
import { TracingProvider } from './type'
import { docURL } from './config'
import {
@ -22,10 +22,10 @@ import Divider from '@/app/components/base/divider'
type Props = {
appId: string
type: TracingProvider
payload?: LangSmithConfig | LangFuseConfig | null
payload?: LangSmithConfig | LangFuseConfig | OpikConfig | null
onRemoved: () => void
onCancel: () => void
onSaved: (payload: LangSmithConfig | LangFuseConfig) => void
onSaved: (payload: LangSmithConfig | LangFuseConfig | OpikConfig) => void
onChosen: (provider: TracingProvider) => void
}
@ -43,6 +43,13 @@ const langFuseConfigTemplate = {
host: '',
}
const opikConfigTemplate = {
api_key: '',
project: '',
url: '',
workspace: '',
}
const ProviderConfigModal: FC<Props> = ({
appId,
type,
@ -56,14 +63,17 @@ const ProviderConfigModal: FC<Props> = ({
const isEdit = !!payload
const isAdd = !isEdit
const [isSaving, setIsSaving] = useState(false)
const [config, setConfig] = useState<LangSmithConfig | LangFuseConfig>((() => {
const [config, setConfig] = useState<LangSmithConfig | LangFuseConfig | OpikConfig>((() => {
if (isEdit)
return payload
if (type === TracingProvider.langSmith)
return langSmithConfigTemplate
return langFuseConfigTemplate
else if (type === TracingProvider.langfuse)
return langFuseConfigTemplate
return opikConfigTemplate
})())
const [isShowRemoveConfirm, {
setTrue: showRemoveConfirm,
@ -112,6 +122,10 @@ const ProviderConfigModal: FC<Props> = ({
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Host' })
}
if (type === TracingProvider.opik) {
const postData = config as OpikConfig
}
return errorMessage
}, [config, t, type])
const handleSave = useCallback(async () => {
@ -216,6 +230,38 @@ const ProviderConfigModal: FC<Props> = ({
/>
</>
)}
{type === TracingProvider.opik && (
<>
<Field
label='API Key'
labelClassName='!text-sm'
value={(config as OpikConfig).api_key}
onChange={handleConfigChange('api_key')}
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
/>
<Field
label={t(`${I18N_PREFIX}.project`)!}
labelClassName='!text-sm'
value={(config as OpikConfig).project}
onChange={handleConfigChange('project')}
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
/>
<Field
label='Workspace'
labelClassName='!text-sm'
value={(config as OpikConfig).workspace}
onChange={handleConfigChange('workspace')}
placeholder={'default'}
/>
<Field
label='Url'
labelClassName='!text-sm'
value={(config as OpikConfig).url}
onChange={handleConfigChange('url')}
placeholder={'https://www.comet.com/opik/api/'}
/>
</>
)}
</div>
<div className='my-8 flex justify-between items-center h-8'>

View File

@ -7,7 +7,8 @@ import {
import { useTranslation } from 'react-i18next'
import { TracingProvider } from './type'
import cn from '@/utils/classnames'
import { LangfuseIconBig, LangsmithIconBig } from '@/app/components/base/icons/src/public/tracing'
import { LangfuseIconBig, LangsmithIconBig, OpikIconBig } from '@/app/components/base/icons/src/public/tracing'
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general'
const I18N_PREFIX = 'app.tracing'
@ -26,6 +27,7 @@ const getIcon = (type: TracingProvider) => {
return ({
[TracingProvider.langSmith]: LangsmithIconBig,
[TracingProvider.langfuse]: LangfuseIconBig,
[TracingProvider.opik]: OpikIconBig,
})[type]
}
@ -79,7 +81,7 @@ const ProviderPanel: FC<Props> = ({
<div className={'flex justify-between items-center space-x-1'}>
{hasConfigured && (
<div className='flex px-2 items-center h-6 bg-components-button-secondary-bg rounded-md border-[0.5px] border-components-button-secondary-border shadow-xs cursor-pointer text-text-secondary space-x-1' onClick={viewBtnClick} >
<View className='w-3 h-3'/>
<View className='w-3 h-3' />
<div className='text-xs font-medium'>{t(`${I18N_PREFIX}.view`)}</div>
</div>
)}

View File

@ -1,6 +1,7 @@
export enum TracingProvider {
langSmith = 'langsmith',
langfuse = 'langfuse',
opik = 'opik',
}
export type LangSmithConfig = {
@ -14,3 +15,10 @@ export type LangFuseConfig = {
secret_key: string
host: string
}
export type OpikConfig = {
api_key: string
project: string
workspace: string
url: string
}

View File

@ -4,7 +4,8 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { useRouter } from 'next/navigation'
import { useTranslation } from 'react-i18next'
import { useDebounceFn } from 'ahooks'
import { useBoolean, useDebounceFn } from 'ahooks'
import { useQuery } from '@tanstack/react-query'
// Components
import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel'
@ -16,7 +17,9 @@ import TabSliderNew from '@/app/components/base/tab-slider-new'
import TagManagementModal from '@/app/components/base/tag-management'
import TagFilter from '@/app/components/base/tag-management/filter'
import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label'
// Services
import { fetchDatasetApiBaseUrl } from '@/service/datasets'
@ -27,15 +30,13 @@ import { useStore as useTagStore } from '@/app/components/base/tag-management/st
import { useAppContext } from '@/context/app-context'
import { useExternalApiPanel } from '@/context/external-api-panel-context'
import { useQuery } from '@tanstack/react-query'
import Input from '@/app/components/base/input'
const Container = () => {
const { t } = useTranslation()
const router = useRouter()
const { currentWorkspace } = useAppContext()
const { currentWorkspace, isCurrentWorkspaceOwner } = useAppContext()
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
const { showExternalApiPanel, setShowExternalApiPanel } = useExternalApiPanel()
const [includeAll, { toggle: toggleIncludeAll }] = useBoolean(false)
const options = useMemo(() => {
return [
@ -81,7 +82,7 @@ const Container = () => {
}, [currentWorkspace, router])
return (
<div ref={containerRef} className='grow relative flex flex-col bg-background-body overflow-y-auto'>
<div ref={containerRef} className='grow relative flex flex-col bg-background-body overflow-y-auto scroll-container'>
<div className='sticky top-0 flex justify-between pt-4 px-12 pb-2 leading-[56px] bg-background-body z-10 flex-wrap gap-y-2'>
<TabSliderNew
value={activeTab}
@ -90,6 +91,14 @@ const Container = () => {
/>
{activeTab === 'dataset' && (
<div className='flex items-center justify-center gap-2'>
{isCurrentWorkspaceOwner && <CheckboxWithLabel
isChecked={includeAll}
onChange={toggleIncludeAll}
label={t('dataset.allKnowledge')}
labelClassName='system-md-regular text-text-secondary'
className='mr-2'
tooltip={t('dataset.allKnowledgeDescription') as string}
/>}
<TagFilter type='knowledge' value={tagFilterValue} onChange={handleTagsChange} />
<Input
showLeftIcon
@ -113,7 +122,7 @@ const Container = () => {
</div>
{activeTab === 'dataset' && (
<>
<Datasets containerRef={containerRef} tags={tagIDs} keywords={searchKeywords} />
<Datasets containerRef={containerRef} tags={tagIDs} keywords={searchKeywords} includeAll={includeAll} />
<DatasetFooter />
{showTagManagementModal && (
<TagManagementModal type='knowledge' show={showTagManagementModal} />

View File

@ -6,7 +6,7 @@ import { debounce } from 'lodash-es'
import { useTranslation } from 'react-i18next'
import NewDatasetCard from './NewDatasetCard'
import DatasetCard from './DatasetCard'
import type { DataSetListResponse } from '@/models/datasets'
import type { DataSetListResponse, FetchDatasetsParams } from '@/models/datasets'
import { fetchDatasets } from '@/service/datasets'
import { useAppContext } from '@/context/app-context'
@ -15,13 +15,15 @@ const getKey = (
previousPageData: DataSetListResponse,
tags: string[],
keyword: string,
includeAll: boolean,
) => {
if (!pageIndex || previousPageData.has_more) {
const params: any = {
const params: FetchDatasetsParams = {
url: 'datasets',
params: {
page: pageIndex + 1,
limit: 30,
include_all: includeAll,
},
}
if (tags.length)
@ -37,16 +39,18 @@ type Props = {
containerRef: React.RefObject<HTMLDivElement>
tags: string[]
keywords: string
includeAll: boolean
}
const Datasets = ({
containerRef,
tags,
keywords,
includeAll,
}: Props) => {
const { isCurrentWorkspaceEditor } = useAppContext()
const { data, isLoading, setSize, mutate } = useSWRInfinite(
(pageIndex: number, previousPageData: DataSetListResponse) => getKey(pageIndex, previousPageData, tags, keywords),
(pageIndex: number, previousPageData: DataSetListResponse) => getKey(pageIndex, previousPageData, tags, keywords, includeAll),
fetchDatasets,
{ revalidateFirstPage: false, revalidateAll: true },
)

View File

@ -1,7 +1,9 @@
'use client'
import { type FC, useEffect } from 'react'
import { useEffect, useState } from 'react'
import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next'
import { RiListUnordered } from '@remixicon/react'
import TemplateEn from './template/template.en.mdx'
import TemplateZh from './template/template.zh.mdx'
import I18n from '@/context/i18n'
@ -10,25 +12,106 @@ import { LanguagesSupported } from '@/i18n/language'
type DocProps = {
apiBaseUrl: string
}
const Doc: FC<DocProps> = ({
apiBaseUrl,
}) => {
const { locale } = useContext(I18n)
const Doc = ({ apiBaseUrl }: DocProps) => {
const { locale } = useContext(I18n)
const { t } = useTranslation()
const [toc, setToc] = useState<Array<{ href: string; text: string }>>([])
const [isTocExpanded, setIsTocExpanded] = useState(false)
// Set initial TOC expanded state based on screen width
useEffect(() => {
const hash = location.hash
if (hash)
document.querySelector(hash)?.scrollIntoView()
const mediaQuery = window.matchMedia('(min-width: 1280px)')
setIsTocExpanded(mediaQuery.matches)
}, [])
// Extract TOC from article content
useEffect(() => {
const extractTOC = () => {
const article = document.querySelector('article')
if (article) {
const headings = article.querySelectorAll('h2')
const tocItems = Array.from(headings).map((heading) => {
const anchor = heading.querySelector('a')
if (anchor) {
return {
href: anchor.getAttribute('href') || '',
text: anchor.textContent || '',
}
}
return null
}).filter((item): item is { href: string; text: string } => item !== null)
setToc(tocItems)
}
}
setTimeout(extractTOC, 0)
}, [locale])
// Handle TOC item click
const handleTocClick = (e: React.MouseEvent<HTMLAnchorElement>, item: { href: string; text: string }) => {
e.preventDefault()
const targetId = item.href.replace('#', '')
const element = document.getElementById(targetId)
if (element) {
const scrollContainer = document.querySelector('.scroll-container')
if (scrollContainer) {
const headerOffset = -40
const elementTop = element.offsetTop - headerOffset
scrollContainer.scrollTo({
top: elementTop,
behavior: 'smooth',
})
}
}
}
return (
<article className='mx-1 px-4 sm:mx-12 pt-16 bg-white rounded-t-xl prose prose-xl'>
{
locale !== LanguagesSupported[1]
<div className="flex">
<div className={`fixed right-16 top-32 z-10 transition-all ${isTocExpanded ? 'w-64' : 'w-10'}`}>
{isTocExpanded
? (
<nav className="toc w-full bg-gray-50 p-4 rounded-lg shadow-md max-h-[calc(100vh-150px)] overflow-y-auto">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-semibold">{t('appApi.develop.toc')}</h3>
<button
onClick={() => setIsTocExpanded(false)}
className="text-gray-500 hover:text-gray-700"
>
</button>
</div>
<ul className="space-y-2">
{toc.map((item, index) => (
<li key={index}>
<a
href={item.href}
className="text-gray-600 hover:text-gray-900 hover:underline transition-colors duration-200"
onClick={e => handleTocClick(e, item)}
>
{item.text}
</a>
</li>
))}
</ul>
</nav>
)
: (
<button
onClick={() => setIsTocExpanded(true)}
className="w-10 h-10 bg-gray-50 rounded-full shadow-md flex items-center justify-center hover:bg-gray-100 transition-colors duration-200"
>
<RiListUnordered className="w-6 h-6" />
</button>
)}
</div>
<article className='mx-1 px-4 sm:mx-12 pt-16 bg-white rounded-t-xl prose prose-xl'>
{locale !== LanguagesSupported[1]
? <TemplateEn apiBaseUrl={apiBaseUrl} />
: <TemplateZh apiBaseUrl={apiBaseUrl} />
}
</article>
}
</article>
</div>
)
}

View File

@ -1,5 +1,5 @@
import { CodeGroup } from '@/app/components/develop/code.tsx'
import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '@/app/components/develop/md.tsx'
import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx'
# Knowledge API
@ -80,6 +80,27 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- <code>max_tokens</code> The maximum length (tokens) must be validated to be shorter than the length of the parent chunk
- <code>chunk_overlap</code> Define the overlap between adjacent chunks (optional)
</Property>
<PropertyInstruction>When no parameters are set for the knowledge base, the first upload requires the following parameters to be provided; if not provided, the default parameters will be used.</PropertyInstruction>
<Property name='retrieval_model' type='object' key='retrieval_model'>
Retrieval model
- <code>search_method</code> (string) Search method
- <code>hybrid_search</code> Hybrid search
- <code>semantic_search</code> Semantic search
- <code>full_text_search</code> Full-text search
- <code>reranking_enable</code> (bool) Whether to enable reranking
- <code>reranking_mode</code> (object) Rerank model configuration
- <code>reranking_provider_name</code> (string) Rerank model provider
- <code>reranking_model_name</code> (string) Rerank model name
- <code>top_k</code> (int) Number of results to return
- <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
- <code>score_threshold</code> (float) Score threshold
</Property>
<Property name='embedding_model' type='string' key='embedding_model'>
Embedding model name
</Property>
<Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
Embedding model provider
</Property>
</Properties>
</Col>
<Col sticky>
@ -197,6 +218,27 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Property name='file' type='multipart/form-data' key='file'>
Files that need to be uploaded.
</Property>
<PropertyInstruction>When no parameters are set for the knowledge base, the first upload requires the following parameters to be provided; if not provided, the default parameters will be used.</PropertyInstruction>
<Property name='retrieval_model' type='object' key='retrieval_model'>
Retrieval model
- <code>search_method</code> (string) Search method
- <code>hybrid_search</code> Hybrid search
- <code>semantic_search</code> Semantic search
- <code>full_text_search</code> Full-text search
- <code>reranking_enable</code> (bool) Whether to enable reranking
- <code>reranking_mode</code> (object) Rerank model configuration
- <code>reranking_provider_name</code> (string) Rerank model provider
- <code>reranking_model_name</code> (string) Rerank model name
- <code>top_k</code> (int) Number of results to return
- <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
- <code>score_threshold</code> (float) Score threshold
</Property>
<Property name='embedding_model' type='string' key='embedding_model'>
Embedding model name
</Property>
<Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
Embedding model provider
</Property>
</Properties>
</Col>
<Col sticky>
@ -1106,6 +1148,57 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<hr className='ml-0 mr-0' />
<Heading
url='/datasets/{dataset_id}/documents/{document_id}/upload-file'
method='GET'
title='Get Upload File'
name='#get_upload_file'
/>
<Row>
<Col>
### Path
<Properties>
<Property name='dataset_id' type='string' key='dataset_id'>
Knowledge ID
</Property>
<Property name='document_id' type='string' key='document_id'>
Document ID
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup
title="Request"
tag="GET"
label="/datasets/{dataset_id}/documents/{document_id}/upload-file"
targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
>
```bash {{ title: 'cURL' }}
curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: 'Response' }}
{
"id": "file_id",
"name": "file_name",
"size": 1024,
"extension": "txt",
"url": "preview_url",
"download_url": "download_url",
"mime_type": "text/plain",
"created_by": "user_id",
"created_at": 1728734540,
}
```
</CodeGroup>
</Col>
</Row>
<hr className='ml-0 mr-0' />
<Heading
url='/datasets/{dataset_id}/retrieve'
method='POST'
@ -1137,10 +1230,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- <code>reranking_mode</code> (object) Rerank model configuration, required if reranking is enabled
- <code>reranking_provider_name</code> (string) Rerank model provider
- <code>reranking_model_name</code> (string) Rerank model name
- <code>weights</code> (double) Semantic search weight setting in hybrid search mode
- <code>weights</code> (float) Semantic search weight setting in hybrid search mode
- <code>top_k</code> (integer) Number of results to return (optional)
- <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
- <code>score_threshold</code> (double) Score threshold
- <code>score_threshold</code> (float) Score threshold
</Property>
<Property name='external_retrieval_model' type='object' key='external_retrieval_model'>
Unused field

View File

@ -1,5 +1,5 @@
import { CodeGroup } from '@/app/components/develop/code.tsx'
import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '@/app/components/develop/md.tsx'
import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx'
# 知识库 API
@ -80,6 +80,27 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- <code>max_tokens</code> 最大长度 (token) 需要校验小于父级的长度
- <code>chunk_overlap</code> 分段重叠指的是在对数据进行分段时,段与段之间存在一定的重叠部分(选填)
</Property>
<PropertyInstruction>当知识库未设置任何参数的时候,首次上传需要提供以下参数,未提供则使用默认选项:</PropertyInstruction>
<Property name='retrieval_model' type='object' key='retrieval_model'>
检索模式
- <code>search_method</code> (string) 检索方法
- <code>hybrid_search</code> 混合检索
- <code>semantic_search</code> 语义检索
- <code>full_text_search</code> 全文检索
- <code>reranking_enable</code> (bool) 是否开启rerank
- <code>reranking_model</code> (object) Rerank 模型配置
- <code>reranking_provider_name</code> (string) Rerank 模型的提供商
- <code>reranking_model_name</code> (string) Rerank 模型的名称
- <code>top_k</code> (int) 召回条数
- <code>score_threshold_enabled</code> (bool)是否开启召回分数限制
- <code>score_threshold</code> (float) 召回分数限制
</Property>
<Property name='embedding_model' type='string' key='embedding_model'>
Embedding 模型名称
</Property>
<Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
Embedding 模型供应商
</Property>
</Properties>
</Col>
<Col sticky>
@ -197,6 +218,27 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Property name='file' type='multipart/form-data' key='file'>
需要上传的文件。
</Property>
<PropertyInstruction>当知识库未设置任何参数的时候,首次上传需要提供以下参数,未提供则使用默认选项:</PropertyInstruction>
<Property name='retrieval_model' type='object' key='retrieval_model'>
检索模式
- <code>search_method</code> (string) 检索方法
- <code>hybrid_search</code> 混合检索
- <code>semantic_search</code> 语义检索
- <code>full_text_search</code> 全文检索
- <code>reranking_enable</code> (bool) 是否开启rerank
- <code>reranking_model</code> (object) Rerank 模型配置
- <code>reranking_provider_name</code> (string) Rerank 模型的提供商
- <code>reranking_model_name</code> (string) Rerank 模型的名称
- <code>top_k</code> (int) 召回条数
- <code>score_threshold_enabled</code> (bool)是否开启召回分数限制
- <code>score_threshold</code> (float) 召回分数限制
</Property>
<Property name='embedding_model' type='string' key='embedding_model'>
Embedding 模型名称
</Property>
<Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
Embedding 模型供应商
</Property>
</Properties>
</Col>
<Col sticky>
@ -1107,6 +1149,57 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<hr className='ml-0 mr-0' />
<Heading
url='/datasets/{dataset_id}/documents/{document_id}/upload-file'
method='GET'
title='获取上传文件'
name='#get_upload_file'
/>
<Row>
<Col>
### Path
<Properties>
<Property name='dataset_id' type='string' key='dataset_id'>
知识库 ID
</Property>
<Property name='document_id' type='string' key='document_id'>
文档 ID
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup
title="Request"
tag="GET"
label="/datasets/{dataset_id}/documents/{document_id}/upload-file"
targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
>
```bash {{ title: 'cURL' }}
curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: 'Response' }}
{
"id": "file_id",
"name": "file_name",
"size": 1024,
"extension": "txt",
"url": "preview_url",
"download_url": "download_url",
"mime_type": "text/plain",
"created_by": "user_id",
"created_at": 1728734540,
}
```
</CodeGroup>
</Col>
</Row>
<hr className='ml-0 mr-0' />
<Heading
url='/datasets/{dataset_id}/retrieve'
method='POST'
@ -1135,13 +1228,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- <code>full_text_search</code> 全文检索
- <code>hybrid_search</code> 混合检索
- <code>reranking_enable</code> (bool) 是否启用 Reranking非必填如果检索模式为 semantic_search 模式或者 hybrid_search 则传值
- <code>reranking_mode</code> (object) Rerank模型配置非必填如果启用了 reranking 则传值
- <code>reranking_mode</code> (object) Rerank 模型配置,非必填,如果启用了 reranking 则传值
- <code>reranking_provider_name</code> (string) Rerank 模型提供商
- <code>reranking_model_name</code> (string) Rerank 模型名称
- <code>weights</code> (double) 混合检索模式下语意检索的权重设置
- <code>weights</code> (float) 混合检索模式下语意检索的权重设置
- <code>top_k</code> (integer) 返回结果数量,非必填
- <code>score_threshold_enabled</code> (bool) 是否开启 score 阈值
- <code>score_threshold</code> (double) Score 阈值
- <code>score_threshold</code> (float) Score 阈值
</Property>
<Property name='external_retrieval_model' type='object' key='external_retrieval_model'>
未启用字段

View File

@ -1,7 +1,6 @@
import React from 'react'
import type { FC } from 'react'
import type { Metadata } from 'next'
import GA, { GaType } from '@/app/components/base/ga'
export const metadata: Metadata = {
icons: 'data:,', // prevent browser from using default favicon
@ -12,7 +11,6 @@ const Layout: FC<{
}> = ({ children }) => {
return (
<div className="min-w-[300px] h-full pb-[env(safe-area-inset-bottom)]">
<GA gaType={GaType.webapp} />
{children}
</div>
)

View File

@ -0,0 +1,122 @@
'use client'
import type { Area } from 'react-easy-crop'
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { RiPencilLine } from '@remixicon/react'
import { updateUserProfile } from '@/service/common'
import { ToastContext } from '@/app/components/base/toast'
import ImageInput, { type OnImageInput } from '@/app/components/base/app-icon-picker/ImageInput'
import Modal from '@/app/components/base/modal'
import Divider from '@/app/components/base/divider'
import Button from '@/app/components/base/button'
import Avatar, { type AvatarProps } from '@/app/components/base/avatar'
import { useLocalFileUploader } from '@/app/components/base/image-uploader/hooks'
import type { ImageFile } from '@/types/app'
import getCroppedImg from '@/app/components/base/app-icon-picker/utils'
import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config'
type InputImageInfo = { file: File } | { tempUrl: string; croppedAreaPixels: Area; fileName: string }
type AvatarWithEditProps = AvatarProps & { onSave?: () => void }
const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
const [inputImageInfo, setInputImageInfo] = useState<InputImageInfo>()
const [isShowAvatarPicker, setIsShowAvatarPicker] = useState(false)
const [uploading, setUploading] = useState(false)
const handleImageInput: OnImageInput = useCallback(async (isCropped: boolean, fileOrTempUrl: string | File, croppedAreaPixels?: Area, fileName?: string) => {
setInputImageInfo(
isCropped
? { tempUrl: fileOrTempUrl as string, croppedAreaPixels: croppedAreaPixels!, fileName: fileName! }
: { file: fileOrTempUrl as File },
)
}, [setInputImageInfo])
const handleSaveAvatar = useCallback(async (uploadedFileId: string) => {
try {
await updateUserProfile({ url: 'account/avatar', body: { avatar: uploadedFileId } })
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
setIsShowAvatarPicker(false)
onSave?.()
}
catch (e) {
notify({ type: 'error', message: (e as Error).message })
}
}, [notify, onSave, t])
const { handleLocalFileUpload } = useLocalFileUploader({
limit: 3,
disabled: false,
onUpload: (imageFile: ImageFile) => {
if (imageFile.progress === 100) {
setUploading(false)
setInputImageInfo(undefined)
handleSaveAvatar(imageFile.fileId)
}
// Error
if (imageFile.progress === -1)
setUploading(false)
},
})
const handleSelect = useCallback(async () => {
if (!inputImageInfo)
return
setUploading(true)
if ('file' in inputImageInfo) {
handleLocalFileUpload(inputImageInfo.file)
return
}
const blob = await getCroppedImg(inputImageInfo.tempUrl, inputImageInfo.croppedAreaPixels, inputImageInfo.fileName)
const file = new File([blob], inputImageInfo.fileName, { type: blob.type })
handleLocalFileUpload(file)
}, [handleLocalFileUpload, inputImageInfo])
if (DISABLE_UPLOAD_IMAGE_AS_ICON)
return <Avatar {...props} />
return (
<>
<div>
<div className="relative group">
<Avatar {...props} />
<div
onClick={() => { setIsShowAvatarPicker(true) }}
className="absolute inset-0 bg-black bg-opacity-50 rounded-full opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer flex items-center justify-center"
>
<span className="text-white text-xs">
<RiPencilLine />
</span>
</div>
</div>
</div>
<Modal
closable
className="!w-[362px] !p-0"
isShow={isShowAvatarPicker}
onClose={() => setIsShowAvatarPicker(false)}
>
<ImageInput onImageInput={handleImageInput} cropShape='round' />
<Divider className='m-0' />
<div className='w-full flex items-center justify-center p-3 gap-2'>
<Button className='w-full' onClick={() => setIsShowAvatarPicker(false)}>
{t('app.iconPicker.cancel')}
</Button>
<Button variant="primary" className='w-full' disabled={uploading || !inputImageInfo} loading={uploading} onClick={handleSelect}>
{t('app.iconPicker.ok')}
</Button>
</div>
</Modal>
</>
)
}
export default AvatarWithEdit

View File

@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import DeleteAccount from '../delete-account'
import s from './index.module.css'
import AvatarWithEdit from './AvatarWithEdit'
import Collapse from '@/app/components/header/account-setting/collapse'
import type { IItem } from '@/app/components/header/account-setting/collapse'
import Modal from '@/app/components/base/modal'
@ -13,7 +14,6 @@ import { updateUserProfile } from '@/service/common'
import { useAppContext } from '@/context/app-context'
import { ToastContext } from '@/app/components/base/toast'
import AppIcon from '@/app/components/base/app-icon'
import Avatar from '@/app/components/base/avatar'
import { IS_CE_EDITION } from '@/config'
import Input from '@/app/components/base/input'
@ -133,7 +133,7 @@ export default function AccountPage() {
<h4 className='title-2xl-semi-bold text-text-primary'>{t('common.account.myAccount')}</h4>
</div>
<div className='mb-8 p-6 rounded-xl flex items-center bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1'>
<Avatar name={userProfile.name} size={64} />
<AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={ mutateUserProfile } size={64} />
<div className='ml-4'>
<p className='system-xl-semibold text-text-primary'>{userProfile.name}</p>
<p className='system-xs-regular text-text-tertiary'>{userProfile.email}</p>

View File

@ -45,7 +45,7 @@ export default function AppSelector() {
${open && 'bg-components-panel-bg-blur'}
`}
>
<Avatar name={userProfile.name} size={32} />
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={32} />
</Menu.Button>
</div>
<Transition
@ -71,7 +71,7 @@ export default function AppSelector() {
<div className='system-md-medium text-text-primary break-all'>{userProfile.name}</div>
<div className='system-xs-regular text-text-tertiary break-all'>{userProfile.email}</div>
</div>
<Avatar name={userProfile.name} size={32} />
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={32} />
</div>
</div>
</Menu.Item>

View File

@ -12,7 +12,7 @@ import Divider from '@/app/components/base/divider'
import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
import Textarea from '@/app/components/base/textarea'
import { type DataSet } from '@/models/datasets'
import type { DataSet } from '@/models/datasets'
import { useToastContext } from '@/app/components/base/toast'
import { updateDatasetSetting } from '@/service/datasets'
import { useAppContext } from '@/context/app-context'
@ -33,7 +33,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
import { fetchMembers } from '@/service/common'
import type { Member } from '@/models/common'
interface SettingsModalProps {
type SettingsModalProps = {
currentDataset: DataSet
onCancel: () => void
onSave: (newDataset: DataSet) => void

View File

@ -149,7 +149,7 @@ const ChatItem: FC<ChatItemProps> = ({
suggestedQuestions={suggestedQuestions}
onSend={doSend}
showPromptLog
questionIcon={<Avatar name={userProfile.name} size={40} />}
questionIcon={<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={40} />}
allToolIcons={allToolIcons}
hideLogModal
noSpacing

View File

@ -175,7 +175,7 @@ const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSi
onRegenerate={doRegenerate}
onStopResponding={handleStop}
showPromptLog
questionIcon={<Avatar name={userProfile.name} size={40} />}
questionIcon={<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={40} />}
allToolIcons={allToolIcons}
onAnnotationEdited={handleAnnotationEdited}
onAnnotationAdded={handleAnnotationAdded}

View File

@ -39,7 +39,7 @@ const VarPanel: FC<Props> = ({
}
</div>
{!isCollapse && (
<div className='p-3 flex flex-col gap-2'>
<div className='p-3 flex flex-col gap-2 max-h-[500px] overflow-y-auto'>
{varList.map(({ label, value }, index) => (
<div key={index} className='flex py-2 system-xs-medium'>
<div className='shrink-0 w-[128px] flex text-text-accent'>

View File

@ -6,6 +6,7 @@ import type { EChartsOption } from 'echarts'
import useSWR from 'swr'
import dayjs from 'dayjs'
import { get } from 'lodash-es'
import Decimal from 'decimal.js'
import { useTranslation } from 'react-i18next'
import { formatNumber } from '@/utils/format'
import Basic from '@/app/components/app-sidebar/basic'
@ -60,10 +61,8 @@ const CHART_TYPE_CONFIG: Record<string, IChartConfigType> = {
},
}
const sum = (arr: number[]): number => {
return arr.reduce((acr, cur) => {
return acr + cur
})
const sum = (arr: Decimal.Value[]): number => {
return Decimal.sum(...arr).toNumber()
}
const defaultPeriod = {

View File

@ -1,12 +1,12 @@
'use client'
import type { FC } from 'react'
import React, { useEffect, useState } from 'react'
import { ChevronRightIcon } from '@heroicons/react/20/solid'
import React, { useCallback, useEffect, useState } from 'react'
import Link from 'next/link'
import { Trans, useTranslation } from 'react-i18next'
import { useContextSelector } from 'use-context-selector'
import { useContext, useContextSelector } from 'use-context-selector'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import Input from '@/app/components/base/input'
import Textarea from '@/app/components/base/textarea'
import AppIcon from '@/app/components/base/app-icon'
@ -18,10 +18,13 @@ import { useToastContext } from '@/app/components/base/toast'
import { languages } from '@/i18n/language'
import Tooltip from '@/app/components/base/tooltip'
import AppContext, { useAppContext } from '@/context/app-context'
import { useProviderContext } from '@/context/provider-context'
import { useModalContext } from '@/context/modal-context'
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
import AppIconPicker from '@/app/components/base/app-icon-picker'
import Divider from '@/app/components/base/divider'
import I18n from '@/context/i18n'
import cn from '@/utils/classnames'
import { ChevronRightIcon } from '@heroicons/react/24/outline'
export type ISettingsModalProps = {
isChat: boolean
@ -85,6 +88,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
chatColorTheme: chat_color_theme,
chatColorThemeInverted: chat_color_theme_inverted,
copyright,
copyrightSwitchValue: !!copyright,
privacyPolicy: privacy_policy,
customDisclaimer: custom_disclaimer,
show_workflow_steps,
@ -94,6 +98,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
const [language, setLanguage] = useState(default_language)
const [saveLoading, setSaveLoading] = useState(false)
const { t } = useTranslation()
const { locale } = useContext(I18n)
const [showAppIconPicker, setShowAppIconPicker] = useState(false)
const [appIcon, setAppIcon] = useState<AppIconSelection>(
@ -101,7 +106,16 @@ const SettingsModal: FC<ISettingsModalProps> = ({
? { type: 'image', url: icon_url!, fileId: icon }
: { type: 'emoji', icon, background: icon_background! },
)
const isChatBot = appInfo.mode === 'chat' || appInfo.mode === 'advanced-chat' || appInfo.mode === 'agent-chat'
const { enableBilling, plan } = useProviderContext()
const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
const isFreePlan = plan.type === 'sandbox'
const handlePlanClick = useCallback(() => {
if (isFreePlan)
setShowPricingModal()
else
setShowAccountSettingModal({ payload: 'billing' })
}, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
useEffect(() => {
setInputInfo({
@ -110,6 +124,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
chatColorTheme: chat_color_theme,
chatColorThemeInverted: chat_color_theme_inverted,
copyright,
copyrightSwitchValue: !!copyright,
privacyPolicy: privacy_policy,
customDisclaimer: custom_disclaimer,
show_workflow_steps,
@ -159,7 +174,11 @@ const SettingsModal: FC<ISettingsModalProps> = ({
chat_color_theme: inputInfo.chatColorTheme,
chat_color_theme_inverted: inputInfo.chatColorThemeInverted,
prompt_public: false,
copyright: inputInfo.copyright,
copyright: isFreePlan
? ''
: inputInfo.copyrightSwitchValue
? inputInfo.copyright
: '',
privacy_policy: inputInfo.privacyPolicy,
custom_disclaimer: inputInfo.customDisclaimer,
icon_type: appIcon.type,
@ -193,8 +212,8 @@ const SettingsModal: FC<ISettingsModalProps> = ({
return (
<>
<Modal
title={t(`${prefixSettings}.title`)}
isShow={isShow}
closable={false}
onClose={onHide}
className='max-w-[520px]'
>
@ -327,7 +346,9 @@ const SettingsModal: FC<ISettingsModalProps> = ({
<Button className='mr-2' onClick={onHide}>{t('common.operation.cancel')}</Button>
<Button variant='primary' onClick={onClickSave} loading={saveLoading}>{t('common.operation.save')}</Button>
</div>
{showAppIconPicker && <AppIconPicker
</Modal >
{showAppIconPicker && (
<AppIconPicker
onSelect={(payload) => {
setAppIcon(payload)
setShowAppIconPicker(false)
@ -338,8 +359,8 @@ const SettingsModal: FC<ISettingsModalProps> = ({
: { type: 'emoji', icon, background: icon_background! })
setShowAppIconPicker(false)
}}
/>}
</Modal >
/>
)}
</>
)

View File

@ -306,8 +306,14 @@ const GenerationItem: FC<IGenerationItemProps> = ({
}
<div className={`flex ${contentClassName}`}>
<div className='grow w-0'>
{siteInfo && siteInfo.show_workflow_steps && workflowProcessData && (
<WorkflowProcessItem data={workflowProcessData} expand={workflowProcessData.expand} hideProcessDetail={hideProcessDetail} />
{siteInfo && workflowProcessData && (
<WorkflowProcessItem
data={workflowProcessData}
expand={workflowProcessData.expand}
hideProcessDetail={hideProcessDetail}
hideInfo={hideProcessDetail}
readonly={!siteInfo.show_workflow_steps}
/>
)}
{workflowProcessData && !isError && (
<ResultTab data={workflowProcessData} content={content} currentTab={currentTab} onCurrentTabChange={setCurrentTab} />

View File

@ -9,7 +9,7 @@ import {
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import { BubbleTextMod, ChatBot, ListSparkle, Logic } from '@/app/components/base/icons/src/vender/solid/communication'
import { type AppMode } from '@/types/app'
import type { AppMode } from '@/types/app'
export type AppSelectorProps = {
value: Array<AppMode>
onChange: (value: AppSelectorProps['value']) => void

View File

@ -2,8 +2,7 @@
import type { ChangeEvent, FC } from 'react'
import { createRef, useEffect, useState } from 'react'
import type { Area } from 'react-easy-crop'
import Cropper from 'react-easy-crop'
import Cropper, { type Area, type CropperProps } from 'react-easy-crop'
import classNames from 'classnames'
import { ImagePlus } from '../icons/src/vender/line/images'
@ -18,11 +17,13 @@ export type OnImageInput = {
type UploaderProps = {
className?: string
cropShape?: CropperProps['cropShape']
onImageInput?: OnImageInput
}
const ImageInput: FC<UploaderProps> = ({
className,
cropShape,
onImageInput,
}) => {
const [inputImage, setInputImage] = useState<{ file: File; url: string }>()
@ -78,6 +79,7 @@ const ImageInput: FC<UploaderProps> = ({
crop={crop}
zoom={zoom}
aspect={1}
cropShape={cropShape}
onCropChange={setCrop}
onCropComplete={onCropComplete}
onZoomChange={setZoom}

View File

@ -2,9 +2,9 @@
import { useState } from 'react'
import cn from '@/utils/classnames'
type AvatarProps = {
export type AvatarProps = {
name: string
avatar?: string
avatar: string | null
size?: number
className?: string
textClassName?: string

View File

@ -115,9 +115,11 @@ const Sidebar = () => {
)
}
</div>
<div className='px-4 pb-4 text-xs text-gray-400'>
© {appData?.site.copyright || appData?.site.title} {(new Date()).getFullYear()}
</div>
{appData?.site.copyright && (
<div className='px-4 pb-4 text-xs text-gray-400'>
© {(new Date()).getFullYear()} {appData?.site.copyright}
</div>
)}
{!!showConfirm && (
<Confirm
title={t('share.chat.deleteConversation.title')}

View File

@ -13,7 +13,7 @@ import AgentContent from './agent-content'
import BasicContent from './basic-content'
import SuggestedQuestions from './suggested-questions'
import More from './more'
import WorkflowProcess from './workflow-process'
import WorkflowProcessItem from './workflow-process'
import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
import Citation from '@/app/components/base/chat/chat/citation'
import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
@ -133,7 +133,7 @@ const Answer: FC<AnswerProps> = ({
{/** Render the normal steps */}
{
workflowProcess && !hideProcessDetail && (
<WorkflowProcess
<WorkflowProcessItem
data={workflowProcess}
item={item}
hideProcessDetail={hideProcessDetail}
@ -142,11 +142,12 @@ const Answer: FC<AnswerProps> = ({
}
{/** Hide workflow steps by it's settings in siteInfo */}
{
workflowProcess && hideProcessDetail && appData && appData.site.show_workflow_steps && (
<WorkflowProcess
workflowProcess && hideProcessDetail && appData && (
<WorkflowProcessItem
data={workflowProcess}
item={item}
hideProcessDetail={hideProcessDetail}
readonly={!appData.site.show_workflow_steps}
/>
)
}

View File

@ -21,12 +21,14 @@ type WorkflowProcessProps = {
expand?: boolean
hideInfo?: boolean
hideProcessDetail?: boolean
readonly?: boolean
}
const WorkflowProcessItem = ({
data,
expand = false,
hideInfo = false,
hideProcessDetail = false,
readonly = false,
}: WorkflowProcessProps) => {
const { t } = useTranslation()
const [collapse, setCollapse] = useState(!expand)
@ -62,8 +64,8 @@ const WorkflowProcessItem = ({
}}
>
<div
className={cn('flex items-center cursor-pointer', !collapse && 'px-1.5')}
onClick={() => setCollapse(!collapse)}
className={cn('flex items-center cursor-pointer', !collapse && 'px-1.5', readonly && 'cursor-default')}
onClick={() => !readonly && setCollapse(!collapse)}
>
{
running && (
@ -83,10 +85,10 @@ const WorkflowProcessItem = ({
<div className={cn('system-xs-medium text-text-secondary', !collapse && 'grow')}>
{t('workflow.common.workflowProcess')}
</div>
<RiArrowRightSLine className={`'ml-1 w-4 h-4 text-text-tertiary' ${collapse ? '' : 'rotate-90'}`} />
{!readonly && <RiArrowRightSLine className={`'ml-1 w-4 h-4 text-text-tertiary' ${collapse ? '' : 'rotate-90'}`} />}
</div>
{
!collapse && (
!collapse && !readonly && (
<div className='mt-1.5'>
{
<TracingPanel

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="70.700851"
height="24"
viewBox="0 0 70.700851 24"
fill="none"
version="1.1"
id="svg6"
sodipodi:docname="opik-icon-big.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="18.615088"
inkscape:cx="36.314629"
inkscape:cy="18.989972"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<rect
width="70.700851"
height="24"
fill="#ffffff"
id="rect1"
x="0"
y="0"
style="stroke-width:0.0683761;fill:none" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 14.463316,5.8949744 C 11.191179,4.456547 7.3065299,5.9932444 5.8118769,9.3932308 4.3172308,12.793231 5.8113846,16.694496 9.0834872,18.132923 c 1.3197948,0.580171 2.7316238,0.676855 4.0492308,0.364923 0.567179,-0.13429 1.135863,0.216684 1.270085,0.783863 0.134291,0.56718 -0.216615,1.135864 -0.783863,1.270154 C 11.873983,20.964923 9.9916581,20.83788 8.2340513,20.065231 3.8540444,18.139761 1.9338872,12.969778 3.8795692,8.5437949 5.8252581,4.1177778 10.932786,2.0372103 15.312752,3.9626667 c 2.672342,1.1747624 4.432069,3.564376 4.952137,6.2470423 0.110974,0.57224 -0.262974,1.126017 -0.835214,1.236992 -0.572171,0.110906 -1.126017,-0.263043 -1.236923,-0.835282 C 17.796308,8.5668376 16.46359,6.7742906 14.463316,5.8949744 Z M 18.01388,17.557812 c 0.20424,0.856752 -0.324786,1.716786 -1.181538,1.921026 -0.856752,0.204171 -1.716855,-0.324787 -1.921026,-1.181539 -0.204239,-0.856752 0.324787,-1.716855 1.181539,-1.921025 0.856752,-0.20424 1.716854,0.324786 1.921025,1.181538 z m 1.329368,-1.216547 c 1.144615,-0.272821 1.85135,-1.42188 1.57853,-2.566427 -0.272821,-1.144616 -1.421881,-1.851351 -2.566428,-1.57853 -1.144615,0.27282 -1.85135,1.421812 -1.578529,2.566427 0.27282,1.144615 1.42188,1.85135 2.566427,1.57853 z"
fill="url(#paint0_linear_3874_31725)"
id="path1"
style="fill:url(#paint0_linear_3874_31725);stroke-width:0.0683761" />
<path
d="m 31.039658,17.805538 c -1.082803,0 -2.046769,-0.231042 -2.891897,-0.693196 -0.84506,-0.475419 -1.511932,-1.122462 -2.000479,-1.941128 -0.488615,-0.818667 -0.732855,-1.749607 -0.732855,-2.792821 0,-1.056342 0.24424,-1.987282 0.732855,-2.7928204 0.488547,-0.8186666 1.155419,-1.4590769 2.000479,-1.9212991 0.845128,-0.4621538 1.809094,-0.6931966 2.891897,-0.6931966 1.096,0 2.06653,0.2310428 2.911658,0.6931966 0.858257,0.4622222 1.525128,1.096 2.000479,1.9015385 0.488615,0.80547 0.732855,1.742974 0.732855,2.812581 0,1.043214 -0.24424,1.974154 -0.732855,2.792821 -0.475351,0.818666 -1.142222,1.465709 -2.000479,1.941128 -0.845128,0.462154 -1.815658,0.693196 -2.911658,0.693196 z m 0,-2.119316 c 0.607385,0 1.148786,-0.132102 1.624137,-0.396171 0.475419,-0.264068 0.845128,-0.647042 1.109196,-1.148786 0.277334,-0.501812 0.416,-1.089436 0.416,-1.762872 0,-0.686632 -0.138666,-1.274256 -0.416,-1.762803 -0.264068,-0.501812 -0.633777,-0.8847182 -1.109196,-1.148855 -0.475351,-0.2640683 -1.01012,-0.3961025 -1.604376,-0.3961025 -0.607385,0 -1.148787,0.1320342 -1.624137,0.3961025 -0.462222,0.2641368 -0.831932,0.647043 -1.109265,1.148855 -0.277265,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138667,1.26106 0.415932,1.762872 0.277333,0.501744 0.647043,0.884718 1.109265,1.148786 0.47535,0.264069 1.01012,0.396171 1.604376,0.396171 z"
fill="#3a3a3a"
id="path2"
style="stroke-width:0.0683761" />
<path
d="m 44.915145,17.805538 c -0.858256,0 -1.643966,-0.198017 -2.35706,-0.594188 -0.699829,-0.396171 -1.261059,-0.990359 -1.683555,-1.782632 -0.409368,-0.805539 -0.614017,-1.822291 -0.614017,-3.050325 0,-1.241231 0.198017,-2.257983 0.594188,-3.0503246 0.409367,-0.7922735 0.963966,-1.3798975 1.663795,-1.7628034 0.699829,-0.396171 1.498735,-0.5941881 2.396649,-0.5941881 1.043214,0 1.960958,0.2244787 2.753231,0.6734359 0.80547,0.4489573 1.439316,1.076171 1.90147,1.881641 0.475351,0.8055382 0.713026,1.7562392 0.713026,2.8522392 0,1.096 -0.237675,2.053333 -0.713026,2.872069 -0.462154,0.80547 -1.096,1.432683 -1.90147,1.881641 -0.792273,0.448957 -1.710017,0.673435 -2.753231,0.673435 z m -4.714598,3.703932 c -0.634188,0 -1.148308,-0.514051 -1.148308,-1.148239 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.06044 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 1.3474188 l -0.07925,2.8126494 0.198086,2.812581 v 5.150428 c 0,0.634188 -0.51412,1.148239 -1.148308,1.148239 z m 4.437333,-5.823248 c 0.594188,0 1.122394,-0.132102 1.584547,-0.396171 0.475351,-0.264068 0.851693,-0.647042 1.129026,-1.148786 0.277265,-0.501812 0.415932,-1.089436 0.415932,-1.762872 0,-0.686632 -0.138667,-1.274256 -0.415932,-1.762803 C 47.07412,10.113778 46.697778,9.7308718 46.222427,9.466735 45.760274,9.2026667 45.232068,9.0706325 44.63788,9.0706325 c -0.594256,0 -1.129025,0.1320342 -1.604376,0.3961025 -0.475419,0.2641368 -0.85176,0.647043 -1.129025,1.148855 -0.277334,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138598,1.26106 0.415932,1.762872 0.277265,0.501744 0.653606,0.884718 1.129025,1.148786 0.475351,0.264069 1.01012,0.396171 1.604376,0.396171 z"
fill="#3a3a3a"
id="path3"
style="stroke-width:0.0683761" />
<path
d="m 53.779282,17.66694 c -0.634188,0 -1.148308,-0.514119 -1.148308,-1.148308 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.179282 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 8.2804782 c 0,0.634189 -0.51412,1.148308 -1.148308,1.148308 z m 0.09956,-12.3200819 c -0.462154,0 -0.845129,-0.1452513 -1.148855,-0.4357607 -0.290462,-0.2905025 -0.435692,-0.6404307 -0.435692,-1.0497777 0,-0.4225505 0.14523,-0.7724787 0.435692,-1.0497778 0.303726,-0.2905026 0.686701,-0.4357607 1.148855,-0.4357607 0.462153,0 0.838495,0.138653 1.129025,0.4159521 0.303658,0.2640958 0.455522,0.6008205 0.455522,1.0101676 0,0.4357538 -0.145231,0.8054906 -0.435761,1.1091965 -0.290462,0.2905094 -0.673436,0.4357607 -1.148786,0.4357607 z"
fill="#3a3a3a"
id="path4"
style="stroke-width:0.0683761" />
<path
d="m 60.376821,15.30988 0.05942,-3.109743 5.22106,-4.8280344 c 0.196169,-0.1814701 0.453537,-0.2821881 0.72075,-0.2821881 v 0 c 0.944752,0 1.41894,1.141265 0.752274,1.8107351 l -2.891077,2.9033164 -1.307282,1.089436 z m -0.872069,2.35706 c -0.634188,0 -1.148239,-0.514119 -1.148239,-1.148308 V 4.1182838 c 0,-0.6341812 0.514051,-1.1482872 1.148239,-1.1482872 h 0.179351 c 0.634188,0 1.148307,0.514106 1.148307,1.1482872 V 16.518632 c 0,0.634189 -0.514119,1.148308 -1.148307,1.148308 z m 7.382017,0 c -0.346598,0 -0.674666,-0.156581 -0.892718,-0.426051 l -3.517675,-4.347487 1.564786,-1.980718 3.848206,4.89641 c 0.592,0.753368 0.05538,1.857846 -0.902838,1.857846 z"
fill="#3a3a3a"
id="path5"
style="stroke-width:0.0683761" />
<defs
id="defs6">
<linearGradient
id="paint0_linear_3874_31725"
x1="258.13101"
y1="269.78299"
x2="88.645203"
y2="75.4571"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(0.06837607)">
<stop
stop-color="#FB9341"
id="stop5" />
<stop
offset="1"
stop-color="#E30D3E"
id="stop6" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="47.133904"
height="16"
viewBox="0 0 47.133904 16"
fill="none"
version="1.1"
id="svg6"
sodipodi:docname="opik-icon.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview6"
pagecolor="#b95d5d"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="18.615087"
inkscape:cx="34.541874"
inkscape:cy="18.882533"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<rect
width="47.119099"
height="15.98219"
fill="#ffffff"
id="rect1"
x="0"
y="0"
style="stroke-width:0.0455515;fill:none"
inkscape:label="rect1" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 9.6391824,3.9256084 C 7.4584431,2.9677242 4.8694901,3.9910489 3.8733677,6.2551834 2.8772499,8.519327 3.8730396,11.117275 6.0537561,12.075159 c 0.8795869,0.38635 1.8205107,0.450735 2.6986394,0.243012 0.3780009,-0.08943 0.7570043,0.144295 0.8464576,0.521993 0.089499,0.377699 -0.1443649,0.7564 -0.5224113,0.845827 C 7.9135024,13.961058 6.6590133,13.876457 5.4876434,13.361931 2.568556,12.079712 1.2888532,8.636894 2.5855671,5.6895232 3.8822857,2.7421295 7.286235,1.3566284 10.205295,2.6388372 11.986296,3.4211403 13.15908,5.0124429 13.505682,6.7988966 13.579642,7.1799648 13.330421,7.548739 12.949049,7.6226396 12.567721,7.6964947 12.198606,7.447473 12.124692,7.0664048 11.860478,5.7048679 10.972279,4.5111667 9.6391824,3.9256084 Z m 2.3662996,7.7665706 c 0.136116,0.570532 -0.216457,1.14325 -0.787445,1.279258 -0.570989,0.135962 -1.14421,-0.216283 -1.2802814,-0.786816 -0.1361171,-0.570532 0.2164564,-1.143295 0.7874454,-1.279258 0.570987,-0.136008 1.14421,0.216283 1.280281,0.786816 z m 0.885967,-0.810128 c 0.762836,-0.181679 1.233846,-0.9468664 1.052022,-1.7090479 -0.181824,-0.7622275 -0.947622,-1.2328598 -1.710414,-1.0511819 -0.762838,0.1816779 -1.233846,0.9468196 -1.052023,1.7090471 0.181823,0.7622277 0.947623,1.2328597 1.710415,1.0511827 z"
fill="url(#paint0_linear_3874_31725)"
id="path1"
style="fill:url(#paint0_linear_3874_31725);stroke-width:0.0455515" />
<path
d="m 20.686606,11.857146 c -0.721642,0 -1.364084,-0.153857 -1.927326,-0.461616 -0.563197,-0.316594 -1.007638,-0.747475 -1.333234,-1.292646 -0.325641,-0.54517 -0.488416,-1.165106 -0.488416,-1.8598076 0,-0.703444 0.162775,-1.32338 0.488416,-1.8598079 0.325596,-0.5451702 0.770037,-0.9716351 1.333234,-1.2794403 0.563242,-0.3077596 1.205684,-0.4616167 1.927326,-0.4616167 0.730437,0 1.377254,0.1538571 1.940495,0.4616167 0.571992,0.3078052 1.016434,0.7298533 1.333234,1.2662813 0.325641,0.5363823 0.488417,1.1606894 0.488417,1.8729669 0,0.6947016 -0.162776,1.3146376 -0.488417,1.8598076 -0.3168,0.545171 -0.761242,0.976052 -1.333234,1.292646 -0.563241,0.307759 -1.210058,0.461616 -1.940495,0.461616 z m 0,-1.411304 c 0.404796,0 0.765617,-0.08797 1.082418,-0.263821 0.316846,-0.17585 0.563242,-0.4308815 0.739232,-0.7650049 0.184831,-0.3341689 0.277246,-0.7254822 0.277246,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277246,-1.1738941 C 22.332266,6.7350133 22.08587,6.4800268 21.769024,6.3041317 21.452223,6.1282821 21.095822,6.0403572 20.699776,6.0403572 c -0.404796,0 -0.765617,0.087925 -1.082418,0.2637745 -0.308051,0.1758951 -0.554446,0.4308816 -0.739277,0.7650506 -0.184786,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09241,0.8397708 0.277201,1.1739397 0.184831,0.3341234 0.431226,0.5891549 0.739277,0.7650049 0.316801,0.17585 0.673201,0.263821 1.069248,0.263821 z"
fill="#3a3a3a"
id="path2"
style="stroke-width:0.0455515" />
<path
d="m 29.934026,11.857146 c -0.571992,0 -1.095634,-0.131865 -1.57088,-0.395684 -0.466407,-0.26382 -0.840442,-0.659504 -1.122018,-1.1871 -0.272826,-0.5364272 -0.409217,-1.2135074 -0.409217,-2.0312856 0,-0.826566 0.131971,-1.5036463 0.396002,-2.0312862 0.272826,-0.5275944 0.642442,-0.9189077 1.108848,-1.1738942 0.466406,-0.26382 0.998843,-0.3956845 1.597265,-0.3956845 0.695257,0 1.306893,0.1494859 1.83491,0.4484576 0.536811,0.2989717 0.959243,0.7166486 1.267248,1.253031 0.316801,0.5364279 0.475202,1.169523 0.475202,1.8993763 0,0.7298534 -0.158401,1.3673652 -0.475202,1.9125806 -0.308005,0.536383 -0.730437,0.95406 -1.267248,1.253031 -0.528017,0.298972 -1.139653,0.448458 -1.83491,0.448458 z m -3.142079,2.466539 c -0.422659,0 -0.765298,-0.342319 -0.765298,-0.764641 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.04028 c 0.42266,0 0.765299,0.3423195 0.765299,0.7646408 v 0.8972793 l -0.05281,1.8730126 0.132016,1.8729669 v 3.429796 c 0,0.422322 -0.342639,0.764641 -0.765298,0.764641 z m 2.957293,-3.877843 c 0.396001,0 0.748027,-0.08797 1.056033,-0.263821 0.316801,-0.17585 0.567616,-0.4308815 0.752447,-0.7650049 0.184786,-0.3341689 0.277201,-0.7254822 0.277201,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277201,-1.1738941 C 31.372889,6.7350133 31.122074,6.4800268 30.805273,6.3041317 30.497267,6.1282821 30.145241,6.0403572 29.74924,6.0403572 c -0.396046,0 -0.752447,0.087925 -1.069248,0.2637745 -0.316846,0.1758951 -0.567662,0.4308816 -0.752447,0.7650506 -0.184831,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09237,0.8397708 0.277201,1.1739397 0.184785,0.3341234 0.435601,0.5891549 0.752447,0.7650049 0.316801,0.17585 0.673202,0.263821 1.069248,0.263821 z"
fill="#3a3a3a"
id="path3"
style="stroke-width:0.0455515" />
<path
d="m 35.841594,11.76485 c -0.422659,0 -0.765298,-0.342365 -0.765298,-0.764686 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.119484 c 0.422659,0 0.765298,0.3423195 0.765298,0.7646408 v 5.5141748 c 0,0.422321 -0.342639,0.764686 -0.765298,0.764686 z m 0.06635,-8.2042457 c -0.308006,0 -0.563241,-0.096726 -0.765662,-0.2901837 -0.19358,-0.1934528 -0.290371,-0.4264787 -0.290371,-0.6990729 0,-0.2813867 0.0968,-0.5144125 0.290371,-0.6990728 0.202421,-0.1934528 0.457656,-0.2901838 0.765662,-0.2901838 0.308006,0 0.558822,0.092332 0.752448,0.2769928 0.202375,0.1758678 0.303585,0.4001011 0.303585,0.6726954 0,0.2901792 -0.0968,0.536396 -0.290415,0.7386413 -0.19358,0.1934573 -0.448817,0.2901837 -0.765618,0.2901837 z"
fill="#3a3a3a"
id="path4"
style="stroke-width:0.0455515" />
<path
d="m 40.238571,10.195226 0.0396,-2.0708549 3.479613,-3.2151067 c 0.130739,-0.1208454 0.302264,-0.187916 0.480351,-0.187916 v 0 c 0.629636,0 0.945662,0.7599964 0.501357,1.2058131 l -1.926779,1.9333896 -0.871247,0.7254822 z m -0.581195,1.569624 c -0.42266,0 -0.765253,-0.342365 -0.765253,-0.764686 V 2.7424664 c 0,-0.4223168 0.342593,-0.7646726 0.765253,-0.7646726 h 0.119528 c 0.42266,0 0.765298,0.3423558 0.765298,0.7646726 v 8.2576976 c 0,0.422321 -0.342638,0.764686 -0.765298,0.764686 z m 4.919799,0 c -0.230994,0 -0.449637,-0.104271 -0.594959,-0.283718 l -2.34438,-2.8950987 1.042863,-1.3190088 2.564664,3.2606405 c 0.394542,0.501685 0.03692,1.237185 -0.601702,1.237185 z"
fill="#3a3a3a"
id="path5"
style="stroke-width:0.0455515" />
<defs
id="defs6">
<linearGradient
id="paint0_linear_3874_31725"
x1="258.13101"
y1="269.78299"
x2="88.645203"
y2="75.4571"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(0.04556973,0.04553331)">
<stop
stop-color="#FB9341"
id="stop5" />
<stop
offset="1"
stop-color="#E30D3E"
id="stop6" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -0,0 +1,163 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "47.133904",
"height": "16",
"viewBox": "0 0 47.133904 16",
"fill": "none",
"version": "1.1",
"id": "svg6",
"sodipodi:docname": "opik-icon.svg",
"inkscape:version": "1.3.2 (091e20ef0f, 2023-11-25)",
"xmlns:inkscape": "http://www.inkscape.org/namespaces/inkscape",
"xmlns:sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
"xmlns": "http://www.w3.org/2000/svg",
"xmlns:svg": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "sodipodi:namedview",
"attributes": {
"id": "namedview6",
"pagecolor": "#b95d5d",
"bordercolor": "#666666",
"borderopacity": "1.0",
"inkscape:showpageshadow": "2",
"inkscape:pageopacity": "0.0",
"inkscape:pagecheckerboard": "0",
"inkscape:deskcolor": "#d1d1d1",
"inkscape:zoom": "18.615087",
"inkscape:cx": "34.541874",
"inkscape:cy": "18.882533",
"inkscape:window-width": "2560",
"inkscape:window-height": "1371",
"inkscape:window-x": "0",
"inkscape:window-y": "0",
"inkscape:window-maximized": "1",
"inkscape:current-layer": "svg6"
},
"children": []
},
{
"type": "element",
"name": "rect",
"attributes": {
"width": "47.119099",
"height": "15.98219",
"fill": "#ffffff",
"id": "rect1",
"x": "0",
"y": "0",
"style": "stroke-width:0.0455515;fill:none",
"inkscape:label": "rect1"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"fill-rule": "evenodd",
"clip-rule": "evenodd",
"d": "M 9.6391824,3.9256084 C 7.4584431,2.9677242 4.8694901,3.9910489 3.8733677,6.2551834 2.8772499,8.519327 3.8730396,11.117275 6.0537561,12.075159 c 0.8795869,0.38635 1.8205107,0.450735 2.6986394,0.243012 0.3780009,-0.08943 0.7570043,0.144295 0.8464576,0.521993 0.089499,0.377699 -0.1443649,0.7564 -0.5224113,0.845827 C 7.9135024,13.961058 6.6590133,13.876457 5.4876434,13.361931 2.568556,12.079712 1.2888532,8.636894 2.5855671,5.6895232 3.8822857,2.7421295 7.286235,1.3566284 10.205295,2.6388372 11.986296,3.4211403 13.15908,5.0124429 13.505682,6.7988966 13.579642,7.1799648 13.330421,7.548739 12.949049,7.6226396 12.567721,7.6964947 12.198606,7.447473 12.124692,7.0664048 11.860478,5.7048679 10.972279,4.5111667 9.6391824,3.9256084 Z m 2.3662996,7.7665706 c 0.136116,0.570532 -0.216457,1.14325 -0.787445,1.279258 -0.570989,0.135962 -1.14421,-0.216283 -1.2802814,-0.786816 -0.1361171,-0.570532 0.2164564,-1.143295 0.7874454,-1.279258 0.570987,-0.136008 1.14421,0.216283 1.280281,0.786816 z m 0.885967,-0.810128 c 0.762836,-0.181679 1.233846,-0.9468664 1.052022,-1.7090479 -0.181824,-0.7622275 -0.947622,-1.2328598 -1.710414,-1.0511819 -0.762838,0.1816779 -1.233846,0.9468196 -1.052023,1.7090471 0.181823,0.7622277 0.947623,1.2328597 1.710415,1.0511827 z",
"fill": "url(#paint0_linear_3874_31725)",
"id": "path1",
"style": "fill:url(#paint0_linear_3874_31725);stroke-width:0.0455515"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 20.686606,11.857146 c -0.721642,0 -1.364084,-0.153857 -1.927326,-0.461616 -0.563197,-0.316594 -1.007638,-0.747475 -1.333234,-1.292646 -0.325641,-0.54517 -0.488416,-1.165106 -0.488416,-1.8598076 0,-0.703444 0.162775,-1.32338 0.488416,-1.8598079 0.325596,-0.5451702 0.770037,-0.9716351 1.333234,-1.2794403 0.563242,-0.3077596 1.205684,-0.4616167 1.927326,-0.4616167 0.730437,0 1.377254,0.1538571 1.940495,0.4616167 0.571992,0.3078052 1.016434,0.7298533 1.333234,1.2662813 0.325641,0.5363823 0.488417,1.1606894 0.488417,1.8729669 0,0.6947016 -0.162776,1.3146376 -0.488417,1.8598076 -0.3168,0.545171 -0.761242,0.976052 -1.333234,1.292646 -0.563241,0.307759 -1.210058,0.461616 -1.940495,0.461616 z m 0,-1.411304 c 0.404796,0 0.765617,-0.08797 1.082418,-0.263821 0.316846,-0.17585 0.563242,-0.4308815 0.739232,-0.7650049 0.184831,-0.3341689 0.277246,-0.7254822 0.277246,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277246,-1.1738941 C 22.332266,6.7350133 22.08587,6.4800268 21.769024,6.3041317 21.452223,6.1282821 21.095822,6.0403572 20.699776,6.0403572 c -0.404796,0 -0.765617,0.087925 -1.082418,0.2637745 -0.308051,0.1758951 -0.554446,0.4308816 -0.739277,0.7650506 -0.184786,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09241,0.8397708 0.277201,1.1739397 0.184831,0.3341234 0.431226,0.5891549 0.739277,0.7650049 0.316801,0.17585 0.673201,0.263821 1.069248,0.263821 z",
"fill": "#3a3a3a",
"id": "path2",
"style": "stroke-width:0.0455515"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 29.934026,11.857146 c -0.571992,0 -1.095634,-0.131865 -1.57088,-0.395684 -0.466407,-0.26382 -0.840442,-0.659504 -1.122018,-1.1871 -0.272826,-0.5364272 -0.409217,-1.2135074 -0.409217,-2.0312856 0,-0.826566 0.131971,-1.5036463 0.396002,-2.0312862 0.272826,-0.5275944 0.642442,-0.9189077 1.108848,-1.1738942 0.466406,-0.26382 0.998843,-0.3956845 1.597265,-0.3956845 0.695257,0 1.306893,0.1494859 1.83491,0.4484576 0.536811,0.2989717 0.959243,0.7166486 1.267248,1.253031 0.316801,0.5364279 0.475202,1.169523 0.475202,1.8993763 0,0.7298534 -0.158401,1.3673652 -0.475202,1.9125806 -0.308005,0.536383 -0.730437,0.95406 -1.267248,1.253031 -0.528017,0.298972 -1.139653,0.448458 -1.83491,0.448458 z m -3.142079,2.466539 c -0.422659,0 -0.765298,-0.342319 -0.765298,-0.764641 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.04028 c 0.42266,0 0.765299,0.3423195 0.765299,0.7646408 v 0.8972793 l -0.05281,1.8730126 0.132016,1.8729669 v 3.429796 c 0,0.422322 -0.342639,0.764641 -0.765298,0.764641 z m 2.957293,-3.877843 c 0.396001,0 0.748027,-0.08797 1.056033,-0.263821 0.316801,-0.17585 0.567616,-0.4308815 0.752447,-0.7650049 0.184786,-0.3341689 0.277201,-0.7254822 0.277201,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277201,-1.1738941 C 31.372889,6.7350133 31.122074,6.4800268 30.805273,6.3041317 30.497267,6.1282821 30.145241,6.0403572 29.74924,6.0403572 c -0.396046,0 -0.752447,0.087925 -1.069248,0.2637745 -0.316846,0.1758951 -0.567662,0.4308816 -0.752447,0.7650506 -0.184831,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09237,0.8397708 0.277201,1.1739397 0.184785,0.3341234 0.435601,0.5891549 0.752447,0.7650049 0.316801,0.17585 0.673202,0.263821 1.069248,0.263821 z",
"fill": "#3a3a3a",
"id": "path3",
"style": "stroke-width:0.0455515"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 35.841594,11.76485 c -0.422659,0 -0.765298,-0.342365 -0.765298,-0.764686 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.119484 c 0.422659,0 0.765298,0.3423195 0.765298,0.7646408 v 5.5141748 c 0,0.422321 -0.342639,0.764686 -0.765298,0.764686 z m 0.06635,-8.2042457 c -0.308006,0 -0.563241,-0.096726 -0.765662,-0.2901837 -0.19358,-0.1934528 -0.290371,-0.4264787 -0.290371,-0.6990729 0,-0.2813867 0.0968,-0.5144125 0.290371,-0.6990728 0.202421,-0.1934528 0.457656,-0.2901838 0.765662,-0.2901838 0.308006,0 0.558822,0.092332 0.752448,0.2769928 0.202375,0.1758678 0.303585,0.4001011 0.303585,0.6726954 0,0.2901792 -0.0968,0.536396 -0.290415,0.7386413 -0.19358,0.1934573 -0.448817,0.2901837 -0.765618,0.2901837 z",
"fill": "#3a3a3a",
"id": "path4",
"style": "stroke-width:0.0455515"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 40.238571,10.195226 0.0396,-2.0708549 3.479613,-3.2151067 c 0.130739,-0.1208454 0.302264,-0.187916 0.480351,-0.187916 v 0 c 0.629636,0 0.945662,0.7599964 0.501357,1.2058131 l -1.926779,1.9333896 -0.871247,0.7254822 z m -0.581195,1.569624 c -0.42266,0 -0.765253,-0.342365 -0.765253,-0.764686 V 2.7424664 c 0,-0.4223168 0.342593,-0.7646726 0.765253,-0.7646726 h 0.119528 c 0.42266,0 0.765298,0.3423558 0.765298,0.7646726 v 8.2576976 c 0,0.422321 -0.342638,0.764686 -0.765298,0.764686 z m 4.919799,0 c -0.230994,0 -0.449637,-0.104271 -0.594959,-0.283718 l -2.34438,-2.8950987 1.042863,-1.3190088 2.564664,3.2606405 c 0.394542,0.501685 0.03692,1.237185 -0.601702,1.237185 z",
"fill": "#3a3a3a",
"id": "path5",
"style": "stroke-width:0.0455515"
},
"children": []
},
{
"type": "element",
"name": "defs",
"attributes": {
"id": "defs6"
},
"children": [
{
"type": "element",
"name": "linearGradient",
"attributes": {
"id": "paint0_linear_3874_31725",
"x1": "258.13101",
"y1": "269.78299",
"x2": "88.645203",
"y2": "75.4571",
"gradientUnits": "userSpaceOnUse",
"gradientTransform": "scale(0.04556973,0.04553331)"
},
"children": [
{
"type": "element",
"name": "stop",
"attributes": {
"stop-color": "#FB9341",
"id": "stop5"
},
"children": []
},
{
"type": "element",
"name": "stop",
"attributes": {
"offset": "1",
"stop-color": "#E30D3E",
"id": "stop6"
},
"children": []
}
]
}
]
}
]
},
"name": "OpikIcon"
}

View File

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './OpikIcon.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'OpikIcon'
export default Icon

View File

@ -0,0 +1,162 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "70.700851",
"height": "24",
"viewBox": "0 0 70.700851 24",
"fill": "none",
"version": "1.1",
"id": "svg6",
"sodipodi:docname": "opik-icon-big.svg",
"inkscape:version": "1.3.2 (091e20ef0f, 2023-11-25)",
"xmlns:inkscape": "http://www.inkscape.org/namespaces/inkscape",
"xmlns:sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
"xmlns": "http://www.w3.org/2000/svg",
"xmlns:svg": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "sodipodi:namedview",
"attributes": {
"id": "namedview6",
"pagecolor": "#ffffff",
"bordercolor": "#666666",
"borderopacity": "1.0",
"inkscape:showpageshadow": "2",
"inkscape:pageopacity": "0.0",
"inkscape:pagecheckerboard": "0",
"inkscape:deskcolor": "#d1d1d1",
"inkscape:zoom": "18.615088",
"inkscape:cx": "36.314629",
"inkscape:cy": "18.989972",
"inkscape:window-width": "2560",
"inkscape:window-height": "1371",
"inkscape:window-x": "0",
"inkscape:window-y": "0",
"inkscape:window-maximized": "1",
"inkscape:current-layer": "svg6"
},
"children": []
},
{
"type": "element",
"name": "rect",
"attributes": {
"width": "70.700851",
"height": "24",
"fill": "#ffffff",
"id": "rect1",
"x": "0",
"y": "0",
"style": "stroke-width:0.0683761;fill:none"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"fill-rule": "evenodd",
"clip-rule": "evenodd",
"d": "M 14.463316,5.8949744 C 11.191179,4.456547 7.3065299,5.9932444 5.8118769,9.3932308 4.3172308,12.793231 5.8113846,16.694496 9.0834872,18.132923 c 1.3197948,0.580171 2.7316238,0.676855 4.0492308,0.364923 0.567179,-0.13429 1.135863,0.216684 1.270085,0.783863 0.134291,0.56718 -0.216615,1.135864 -0.783863,1.270154 C 11.873983,20.964923 9.9916581,20.83788 8.2340513,20.065231 3.8540444,18.139761 1.9338872,12.969778 3.8795692,8.5437949 5.8252581,4.1177778 10.932786,2.0372103 15.312752,3.9626667 c 2.672342,1.1747624 4.432069,3.564376 4.952137,6.2470423 0.110974,0.57224 -0.262974,1.126017 -0.835214,1.236992 -0.572171,0.110906 -1.126017,-0.263043 -1.236923,-0.835282 C 17.796308,8.5668376 16.46359,6.7742906 14.463316,5.8949744 Z M 18.01388,17.557812 c 0.20424,0.856752 -0.324786,1.716786 -1.181538,1.921026 -0.856752,0.204171 -1.716855,-0.324787 -1.921026,-1.181539 -0.204239,-0.856752 0.324787,-1.716855 1.181539,-1.921025 0.856752,-0.20424 1.716854,0.324786 1.921025,1.181538 z m 1.329368,-1.216547 c 1.144615,-0.272821 1.85135,-1.42188 1.57853,-2.566427 -0.272821,-1.144616 -1.421881,-1.851351 -2.566428,-1.57853 -1.144615,0.27282 -1.85135,1.421812 -1.578529,2.566427 0.27282,1.144615 1.42188,1.85135 2.566427,1.57853 z",
"fill": "url(#paint0_linear_3874_31725)",
"id": "path1",
"style": "fill:url(#paint0_linear_3874_31725);stroke-width:0.0683761"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 31.039658,17.805538 c -1.082803,0 -2.046769,-0.231042 -2.891897,-0.693196 -0.84506,-0.475419 -1.511932,-1.122462 -2.000479,-1.941128 -0.488615,-0.818667 -0.732855,-1.749607 -0.732855,-2.792821 0,-1.056342 0.24424,-1.987282 0.732855,-2.7928204 0.488547,-0.8186666 1.155419,-1.4590769 2.000479,-1.9212991 0.845128,-0.4621538 1.809094,-0.6931966 2.891897,-0.6931966 1.096,0 2.06653,0.2310428 2.911658,0.6931966 0.858257,0.4622222 1.525128,1.096 2.000479,1.9015385 0.488615,0.80547 0.732855,1.742974 0.732855,2.812581 0,1.043214 -0.24424,1.974154 -0.732855,2.792821 -0.475351,0.818666 -1.142222,1.465709 -2.000479,1.941128 -0.845128,0.462154 -1.815658,0.693196 -2.911658,0.693196 z m 0,-2.119316 c 0.607385,0 1.148786,-0.132102 1.624137,-0.396171 0.475419,-0.264068 0.845128,-0.647042 1.109196,-1.148786 0.277334,-0.501812 0.416,-1.089436 0.416,-1.762872 0,-0.686632 -0.138666,-1.274256 -0.416,-1.762803 -0.264068,-0.501812 -0.633777,-0.8847182 -1.109196,-1.148855 -0.475351,-0.2640683 -1.01012,-0.3961025 -1.604376,-0.3961025 -0.607385,0 -1.148787,0.1320342 -1.624137,0.3961025 -0.462222,0.2641368 -0.831932,0.647043 -1.109265,1.148855 -0.277265,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138667,1.26106 0.415932,1.762872 0.277333,0.501744 0.647043,0.884718 1.109265,1.148786 0.47535,0.264069 1.01012,0.396171 1.604376,0.396171 z",
"fill": "#3a3a3a",
"id": "path2",
"style": "stroke-width:0.0683761"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 44.915145,17.805538 c -0.858256,0 -1.643966,-0.198017 -2.35706,-0.594188 -0.699829,-0.396171 -1.261059,-0.990359 -1.683555,-1.782632 -0.409368,-0.805539 -0.614017,-1.822291 -0.614017,-3.050325 0,-1.241231 0.198017,-2.257983 0.594188,-3.0503246 0.409367,-0.7922735 0.963966,-1.3798975 1.663795,-1.7628034 0.699829,-0.396171 1.498735,-0.5941881 2.396649,-0.5941881 1.043214,0 1.960958,0.2244787 2.753231,0.6734359 0.80547,0.4489573 1.439316,1.076171 1.90147,1.881641 0.475351,0.8055382 0.713026,1.7562392 0.713026,2.8522392 0,1.096 -0.237675,2.053333 -0.713026,2.872069 -0.462154,0.80547 -1.096,1.432683 -1.90147,1.881641 -0.792273,0.448957 -1.710017,0.673435 -2.753231,0.673435 z m -4.714598,3.703932 c -0.634188,0 -1.148308,-0.514051 -1.148308,-1.148239 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.06044 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 1.3474188 l -0.07925,2.8126494 0.198086,2.812581 v 5.150428 c 0,0.634188 -0.51412,1.148239 -1.148308,1.148239 z m 4.437333,-5.823248 c 0.594188,0 1.122394,-0.132102 1.584547,-0.396171 0.475351,-0.264068 0.851693,-0.647042 1.129026,-1.148786 0.277265,-0.501812 0.415932,-1.089436 0.415932,-1.762872 0,-0.686632 -0.138667,-1.274256 -0.415932,-1.762803 C 47.07412,10.113778 46.697778,9.7308718 46.222427,9.466735 45.760274,9.2026667 45.232068,9.0706325 44.63788,9.0706325 c -0.594256,0 -1.129025,0.1320342 -1.604376,0.3961025 -0.475419,0.2641368 -0.85176,0.647043 -1.129025,1.148855 -0.277334,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138598,1.26106 0.415932,1.762872 0.277265,0.501744 0.653606,0.884718 1.129025,1.148786 0.475351,0.264069 1.01012,0.396171 1.604376,0.396171 z",
"fill": "#3a3a3a",
"id": "path3",
"style": "stroke-width:0.0683761"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 53.779282,17.66694 c -0.634188,0 -1.148308,-0.514119 -1.148308,-1.148308 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.179282 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 8.2804782 c 0,0.634189 -0.51412,1.148308 -1.148308,1.148308 z m 0.09956,-12.3200819 c -0.462154,0 -0.845129,-0.1452513 -1.148855,-0.4357607 -0.290462,-0.2905025 -0.435692,-0.6404307 -0.435692,-1.0497777 0,-0.4225505 0.14523,-0.7724787 0.435692,-1.0497778 0.303726,-0.2905026 0.686701,-0.4357607 1.148855,-0.4357607 0.462153,0 0.838495,0.138653 1.129025,0.4159521 0.303658,0.2640958 0.455522,0.6008205 0.455522,1.0101676 0,0.4357538 -0.145231,0.8054906 -0.435761,1.1091965 -0.290462,0.2905094 -0.673436,0.4357607 -1.148786,0.4357607 z",
"fill": "#3a3a3a",
"id": "path4",
"style": "stroke-width:0.0683761"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "m 60.376821,15.30988 0.05942,-3.109743 5.22106,-4.8280344 c 0.196169,-0.1814701 0.453537,-0.2821881 0.72075,-0.2821881 v 0 c 0.944752,0 1.41894,1.141265 0.752274,1.8107351 l -2.891077,2.9033164 -1.307282,1.089436 z m -0.872069,2.35706 c -0.634188,0 -1.148239,-0.514119 -1.148239,-1.148308 V 4.1182838 c 0,-0.6341812 0.514051,-1.1482872 1.148239,-1.1482872 h 0.179351 c 0.634188,0 1.148307,0.514106 1.148307,1.1482872 V 16.518632 c 0,0.634189 -0.514119,1.148308 -1.148307,1.148308 z m 7.382017,0 c -0.346598,0 -0.674666,-0.156581 -0.892718,-0.426051 l -3.517675,-4.347487 1.564786,-1.980718 3.848206,4.89641 c 0.592,0.753368 0.05538,1.857846 -0.902838,1.857846 z",
"fill": "#3a3a3a",
"id": "path5",
"style": "stroke-width:0.0683761"
},
"children": []
},
{
"type": "element",
"name": "defs",
"attributes": {
"id": "defs6"
},
"children": [
{
"type": "element",
"name": "linearGradient",
"attributes": {
"id": "paint0_linear_3874_31725",
"x1": "258.13101",
"y1": "269.78299",
"x2": "88.645203",
"y2": "75.4571",
"gradientUnits": "userSpaceOnUse",
"gradientTransform": "scale(0.06837607)"
},
"children": [
{
"type": "element",
"name": "stop",
"attributes": {
"stop-color": "#FB9341",
"id": "stop5"
},
"children": []
},
{
"type": "element",
"name": "stop",
"attributes": {
"offset": "1",
"stop-color": "#E30D3E",
"id": "stop6"
},
"children": []
}
]
}
]
}
]
},
"name": "OpikIconBig"
}

View File

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './OpikIconBig.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'OpikIconBig'
export default Icon

View File

@ -2,4 +2,6 @@ export { default as LangfuseIconBig } from './LangfuseIconBig'
export { default as LangfuseIcon } from './LangfuseIcon'
export { default as LangsmithIconBig } from './LangsmithIconBig'
export { default as LangsmithIcon } from './LangsmithIcon'
export { default as OpikIconBig } from './OpikIconBig'
export { default as OpikIcon } from './OpikIcon'
export { default as TracingIcon } from './TracingIcon'

View File

@ -3,7 +3,7 @@ import React from 'react'
import { type VariantProps, cva } from 'class-variance-authority'
import classNames from '@/utils/classnames'
import './index.css'
import { Highlight } from '../icons/src/public/common'
import { Highlight } from '@/app/components/base/icons/src/public/common'
const PremiumBadgeVariants = cva(
'premium-badge',

View File

@ -11,15 +11,17 @@ export const ChunkLabel: FC<ChunkLabelProps> = (props) => {
const { label, characterCount } = props
return <div className='flex items-center text-text-tertiary text-xs font-medium'>
<SelectionMod className='size-[10px]' />
<p className='flex gap-2 ml-0.5'><span>
{label}
</span>
<span>
<p className='flex gap-2 ml-0.5'>
<span>
{label}
</span>
<span>
·
</span>
<span>
{`${characterCount} characters`}
</span></p>
</span>
<span>
{`${characterCount} characters`}
</span>
</p>
</div>
}

View File

@ -37,7 +37,7 @@ import Button from '@/app/components/base/button'
import FloatRightContainer from '@/app/components/base/float-right-container'
import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
import { type RetrievalConfig } from '@/types/app'
import type { RetrievalConfig } from '@/types/app'
import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
import Toast from '@/app/components/base/toast'
import type { NotionPage } from '@/models/common'
@ -98,6 +98,7 @@ export enum IndexingType {
const DEFAULT_SEGMENT_IDENTIFIER = '\\n\\n'
const DEFAULT_MAXIMUM_CHUNK_LENGTH = 500
const DEFAULT_OVERLAP = 50
const MAXIMUM_CHUNK_TOKEN_LENGTH = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000', 10)
type ParentChildConfig = {
chunkForContext: ParentMode
@ -163,7 +164,7 @@ const StepTwo = ({
doSetSegmentIdentifier(value ? escape(value) : (canEmpty ? '' : DEFAULT_SEGMENT_IDENTIFIER))
}, [])
const [maxChunkLength, setMaxChunkLength] = useState(DEFAULT_MAXIMUM_CHUNK_LENGTH) // default chunk length
const [limitMaxChunkLength, setLimitMaxChunkLength] = useState(4000)
const [limitMaxChunkLength, setLimitMaxChunkLength] = useState(MAXIMUM_CHUNK_TOKEN_LENGTH)
const [overlap, setOverlap] = useState(DEFAULT_OVERLAP)
const [rules, setRules] = useState<PreProcessingRule[]>([])
const [defaultConfig, setDefaultConfig] = useState<Rules>()
@ -205,7 +206,7 @@ const StepTwo = ({
if (value === ChunkingMode.parentChild && indexType === IndexingType.ECONOMICAL)
setIndexType(IndexingType.QUALIFIED)
setDocForm(value)
// eslint-disable-next-line @typescript-eslint/no-use-before-define
// eslint-disable-next-line ts/no-use-before-define
currentEstimateMutation.reset()
}
@ -342,8 +343,8 @@ const StepTwo = ({
}
const updatePreview = () => {
if (segmentationType === ProcessMode.general && maxChunkLength > 4000) {
Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck') })
if (segmentationType === ProcessMode.general && maxChunkLength > MAXIMUM_CHUNK_TOKEN_LENGTH) {
Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck', { limit: MAXIMUM_CHUNK_TOKEN_LENGTH }) })
return
}
fetchEstimate()
@ -393,7 +394,7 @@ const StepTwo = ({
score_threshold_enabled: false,
score_threshold: 0.5,
})
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [rerankDefaultModel, isRerankDefaultModelValid])
const getCreationParams = () => {
@ -575,6 +576,8 @@ const StepTwo = ({
const economyDomRef = useRef<HTMLDivElement>(null)
const isHoveringEconomy = useHover(economyDomRef)
const isModelAndRetrievalConfigDisabled = !!datasetId && !!currentDataset?.data_source_type
return (
<div className='flex w-full h-full'>
<div className={cn('relative h-full w-1/2 py-6 overflow-y-auto', isMobile ? 'px-4' : 'px-12')}>
@ -931,15 +934,15 @@ const StepTwo = ({
<div className='mt-5'>
<div className={cn('system-md-semibold mb-1', datasetId && 'flex justify-between items-center')}>{t('datasetSettings.form.embeddingModel')}</div>
<ModelSelector
readonly={!!datasetId}
triggerClassName={datasetId ? 'opacity-50' : ''}
readonly={isModelAndRetrievalConfigDisabled}
triggerClassName={isModelAndRetrievalConfigDisabled ? 'opacity-50' : ''}
defaultModel={embeddingModel}
modelList={embeddingModelList}
onSelect={(model: DefaultModel) => {
setEmbeddingModel(model)
}}
/>
{!!datasetId && (
{isModelAndRetrievalConfigDisabled && (
<div className='mt-2 system-xs-medium'>
{t('datasetCreation.stepTwo.indexSettingTip')}
<Link className='text-text-accent' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link>
@ -950,7 +953,7 @@ const StepTwo = ({
<Divider className='my-5' />
{/* Retrieval Method Config */}
<div>
{!datasetId
{!isModelAndRetrievalConfigDisabled
? (
<div className={'mb-1'}>
<div className='system-md-semibold mb-0.5'>{t('datasetSettings.form.retrievalSetting.title')}</div>
@ -971,14 +974,14 @@ const StepTwo = ({
getIndexing_technique() === IndexingType.QUALIFIED
? (
<RetrievalMethodConfig
disabled={!!datasetId}
disabled={isModelAndRetrievalConfigDisabled}
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
)
: (
<EconomicalRetrievalMethodConfig
disabled={!!datasetId}
disabled={isModelAndRetrievalConfigDisabled}
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
@ -999,7 +1002,7 @@ const StepTwo = ({
)
: (
<div className='flex items-center mt-8 py-2'>
{!datasetId && <Button loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.save')}</Button>}
<Button loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.save')}</Button>
<Button className='ml-2' onClick={onCancel}>{t('datasetCreation.stepTwo.cancel')}</Button>
</div>
)}
@ -1070,10 +1073,9 @@ const StepTwo = ({
}
{
currentDocForm !== ChunkingMode.qa
&& <Badge text={t(
'datasetCreation.stepTwo.previewChunkCount', {
count: estimate?.total_segments || 0,
}) as string}
&& <Badge text={t('datasetCreation.stepTwo.previewChunkCount', {
count: estimate?.total_segments || 0,
}) as string}
/>
}
</div>

View File

@ -39,6 +39,8 @@ export const DelimiterInput: FC<InputProps & { tooltip?: string }> = (props) =>
}
export const MaxLengthInput: FC<InputNumberProps> = (props) => {
const maxValue = parseInt(globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000', 10)
const { t } = useTranslation()
return <FormField label={<div className='system-sm-semibold mb-1'>
{t('datasetCreation.stepTwo.maxLength')}
@ -46,8 +48,8 @@ export const MaxLengthInput: FC<InputNumberProps> = (props) => {
<InputNumber
type="number"
className='h-9'
placeholder={'≤ 4000'}
max={4000}
placeholder={`${maxValue}`}
max={maxValue}
min={1}
{...props}
/>

View File

@ -4,6 +4,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useDebounceFn } from 'ahooks'
import { useTranslation } from 'react-i18next'
import { createContext, useContext, useContextSelector } from 'use-context-selector'
import { usePathname } from 'next/navigation'
import { useDocumentContext } from '../index'
import { ProcessStatus } from '../segment-add'
import s from './style.module.css'
@ -99,6 +100,7 @@ const Completed: FC<ICompletedProps> = ({
}) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
const pathname = usePathname()
const datasetId = useDocumentContext(s => s.datasetId) || ''
const documentId = useDocumentContext(s => s.documentId) || ''
const docForm = useDocumentContext(s => s.docForm)
@ -374,6 +376,10 @@ const Completed: FC<ICompletedProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [segments, datasetId, documentId])
useEffect(() => {
resetList()
}, [pathname])
useEffect(() => {
if (importStatus === ProcessStatus.COMPLETED)
resetList()

View File

@ -17,7 +17,7 @@ const FullDocListSkeleton = () => {
return (
<div className='w-full grow flex flex-col gap-y-3 relative z-10 overflow-y-hidden'>
<div className='absolute top-0 left-0 bottom-14 w-full h-full bg-dataset-chunk-list-mask-bg z-20' />
{[...Array(15)].map((_, index) => <Slice key={index} />)}
{[...Array.from({ length: 15 })].map((_, index) => <Slice key={index} />)}
</div>
)
}

View File

@ -50,7 +50,7 @@ const GeneralListSkeleton = () => {
return (
<div className='relative flex flex-col grow overflow-y-hidden z-10'>
<div className='absolute top-0 left-0 w-full h-full bg-dataset-chunk-list-mask-bg z-20' />
{[...Array(10)].map((_, index) => {
{[...Array.from({ length: 10 })].map((_, index) => {
return (
<div key={index} className='flex items-start gap-x-2'>
<Checkbox

View File

@ -52,7 +52,7 @@ const ParagraphListSkeleton = () => {
return (
<div className='relative flex flex-col h-full overflow-y-hidden z-10'>
<div className='absolute top-0 left-0 w-full h-full bg-dataset-chunk-list-mask-bg z-20' />
{[...Array(10)].map((_, index) => {
{[...Array.from({ length: 10 })].map((_, index) => {
return (
<div key={index} className='flex items-start gap-x-2'>
<Checkbox

View File

@ -49,7 +49,7 @@ const EmbeddingSkeleton = () => {
return (
<div className='relative flex flex-col grow overflow-y-hidden z-10'>
<div className='absolute top-0 left-0 w-full h-full bg-dataset-chunk-list-mask-bg z-20' />
{[...Array(5)].map((_, index) => {
{[...Array.from({ length: 5 })].map((_, index) => {
return (
<div key={index} className='w-full px-11'>
<CardSkelton />

View File

@ -0,0 +1,60 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import ResultItemMeta from './result-item-meta'
import ResultItemFooter from './result-item-footer'
import type { ExternalKnowledgeBaseHitTesting } from '@/models/datasets'
import cn from '@/utils/classnames'
import Modal from '@/app/components/base/modal'
import { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
const i18nPrefix = 'datasetHitTesting'
type Props = {
payload: ExternalKnowledgeBaseHitTesting
positionId: number
}
const ResultItemExternal: FC<Props> = ({ payload, positionId }) => {
const { t } = useTranslation()
const { content, title, score } = payload
const [
isShowDetailModal,
{ setTrue: showDetailModal, setFalse: hideDetailModal },
] = useBoolean(false)
return (
<div className={cn('pt-3 bg-chat-bubble-bg rounded-xl hover:shadow-lg cursor-pointer')} onClick={showDetailModal}>
{/* Meta info */}
<ResultItemMeta className='px-3' labelPrefix={'Chunk'} positionId={positionId} wordCount={content.length} score={score} />
{/* Main */}
<div className='mt-1 px-3'>
<div className='line-clamp-2 body-md-regular break-all'>{content}</div>
</div>
{/* Foot */}
<ResultItemFooter docType={FileAppearanceTypeEnum.custom} docTitle={title} showDetailModal={showDetailModal} />
{isShowDetailModal && (
<Modal
title={t(`${i18nPrefix}.chunkDetail`)}
className={'!min-w-[800px]'}
closable
onClose={hideDetailModal}
isShow={isShowDetailModal}
>
<div className='mt-4 flex-1'>
<ResultItemMeta labelPrefix={'Chunk'} positionId={positionId} wordCount={content.length} score={score} />
<div className={cn('mt-2 body-md-regular text-text-secondary break-all', 'h-[min(539px,_80vh)] overflow-y-auto')}>
{content}
</div>
</div>
</Modal>
)}
</div>
)
}
export default React.memo(ResultItemExternal)

View File

@ -0,0 +1,42 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { RiArrowRightUpLine } from '@remixicon/react'
import FileIcon from '@/app/components/base/file-uploader/file-type-icon'
import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
type Props = {
docType: FileAppearanceTypeEnum
docTitle: string
showDetailModal: () => void
}
const i18nPrefix = 'datasetHitTesting'
const ResultItemFooter: FC<Props> = ({
docType,
docTitle,
showDetailModal,
}) => {
const { t } = useTranslation()
return (
<div className="mt-3 flex justify-between items-center h-10 pl-3 pr-2 border-t border-divider-subtle">
<div className="grow flex items-center space-x-1">
<FileIcon type={docType} size="sm" />
<span className="grow w-0 truncate text-text-secondary text-[13px] font-normal">
{docTitle}
</span>
</div>
<div
className="flex items-center space-x-1 cursor-pointer text-text-tertiary"
onClick={showDetailModal}
>
<div className="text-xs uppercase">{t(`${i18nPrefix}.open`)}</div>
<RiArrowRightUpLine className="size-3.5" />
</div>
</div>
)
}
export default React.memo(ResultItemFooter)

View File

@ -0,0 +1,45 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { SegmentIndexTag } from '../../documents/detail/completed/common/segment-index-tag'
import Dot from '../../documents/detail/completed/common/dot'
import Score from './score'
import cn from '@/utils/classnames'
type Props = {
labelPrefix: string
positionId: number
wordCount: number
score: number
className?: string
}
const ResultItemMeta: FC<Props> = ({
labelPrefix,
positionId,
wordCount,
score,
className,
}) => {
const { t } = useTranslation()
return (
<div className={cn('flex justify-between items-center', className)}>
<div className="flex items-center space-x-2">
<SegmentIndexTag
labelPrefix={labelPrefix}
positionId={positionId}
className={cn('w-fit group-hover:opacity-100')}
/>
<Dot />
<div className="system-xs-medium text-text-tertiary">
{wordCount} {t('datasetDocuments.segment.characters', { count: wordCount })}
</div>
</div>
<Score value={score} />
</div>
)
}
export default React.memo(ResultItemMeta)

View File

@ -2,33 +2,29 @@
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { RiArrowDownSLine, RiArrowRightSLine, RiArrowRightUpLine } from '@remixicon/react'
import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
import { useBoolean } from 'ahooks'
import { SegmentIndexTag } from '../../documents/detail/completed/common/segment-index-tag'
import Dot from '../../documents/detail/completed/common/dot'
import Score from './score'
import ChildChunkItem from './child-chunks-item'
import ChunkDetailModal from './chunk-detail-modal'
import ResultItemMeta from './result-item-meta'
import ResultItemFooter from './result-item-footer'
import type { HitTesting } from '@/models/datasets'
import cn from '@/utils/classnames'
import FileIcon from '@/app/components/base/file-uploader/file-type-icon'
import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
import Tag from '@/app/components/datasets/documents/detail/completed/common/tag'
import { extensionToFileType } from '@/app/components/datasets/hit-testing/utils/extension-to-file-type'
const i18nPrefix = 'datasetHitTesting'
type Props = {
isExternal: boolean
payload: HitTesting
}
const ResultItem: FC<Props> = ({
isExternal,
payload,
}) => {
const { t } = useTranslation()
const { segment, content: externalContent, score, child_chunks } = payload
const data = isExternal ? externalContent : segment
const { segment, score, child_chunks } = payload
const data = segment
const { position, word_count, content, keywords, document } = data
const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0)
const extension = document.name.split('.').slice(-1)[0] as FileAppearanceTypeEnum
@ -46,18 +42,7 @@ const ResultItem: FC<Props> = ({
return (
<div className={cn('pt-3 bg-chat-bubble-bg rounded-xl hover:shadow-lg cursor-pointer')} onClick={showDetailModal}>
{/* Meta info */}
<div className='flex justify-between items-center px-3'>
<div className='flex items-center space-x-2'>
<SegmentIndexTag
labelPrefix={`${isParentChildRetrieval ? 'Parent-' : ''}Chunk`}
positionId={position}
className={cn('w-fit group-hover:opacity-100')}
/>
<Dot />
<div className='system-xs-medium text-text-tertiary'>{word_count} {t('datasetDocuments.segment.characters', { count: word_count })}</div>
</div>
<Score value={score} />
</div>
<ResultItemMeta className='px-3' labelPrefix={`${isParentChildRetrieval ? 'Parent-' : ''}Chunk`} positionId={position} wordCount={word_count} score={score} />
{/* Main */}
<div className='mt-1 px-3'>
@ -88,19 +73,7 @@ const ResultItem: FC<Props> = ({
)}
</div>
{/* Foot */}
<div className='mt-3 flex justify-between items-center h-10 pl-3 pr-2 border-t border-divider-subtle'>
<div className='grow flex items-center space-x-1'>
<FileIcon type={fileType} size='sm' />
<span className='grow w-0 truncate text-text-secondary text-[13px] font-normal'>{document.name}</span>
</div>
<div
className='flex items-center space-x-1 cursor-pointer text-text-tertiary'
onClick={showDetailModal}
>
<div className='text-xs uppercase'>{t(`${i18nPrefix}.open`)}</div>
<RiArrowRightUpLine className='size-3.5' />
</div>
</div>
<ResultItemFooter docType={fileType} docTitle={document.name} showDetailModal={showDetailModal} />
{
isShowDetailModal && (

View File

@ -12,8 +12,9 @@ import Textarea from './textarea'
import s from './style.module.css'
import ModifyRetrievalModal from './modify-retrieval-modal'
import ResultItem from './components/result-item'
import ResultItemExternal from './components/result-item-external'
import cn from '@/utils/classnames'
import type { ExternalKnowledgeBaseHitTestingResponse, HitTestingResponse } from '@/models/datasets'
import type { ExternalKnowledgeBaseHitTesting, ExternalKnowledgeBaseHitTestingResponse, HitTesting, HitTestingResponse } from '@/models/datasets'
import Loading from '@/app/components/base/loading'
import Drawer from '@/app/components/base/drawer'
import Pagination from '@/app/components/base/pagination'
@ -41,7 +42,7 @@ const RecordsEmpty: FC = () => {
</div>
}
const HitTesting: FC<Props> = ({ datasetId }: Props) => {
const HitTestingPage: FC<Props> = ({ datasetId }: Props) => {
const { t } = useTranslation()
const { formatTime } = useTimestamp()
@ -68,19 +69,25 @@ const HitTesting: FC<Props> = ({ datasetId }: Props) => {
const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict as RetrievalConfig)
const [isShowModifyRetrievalModal, setIsShowModifyRetrievalModal] = useState(false)
const [isShowRightPanel, { setTrue: showRightPanel, setFalse: hideRightPanel, set: setShowRightPanel }] = useBoolean(!isMobile)
const renderHitResults = (results: any[]) => (
const renderHitResults = (results: HitTesting[] | ExternalKnowledgeBaseHitTesting[]) => (
<div className='h-full flex flex-col py-3 px-4 rounded-t-2xl bg-background-body'>
<div className='shrink-0 pl-2 text-text-primary font-semibold leading-6 mb-2'>
{t('datasetHitTesting.hit.title', { num: results.length })}
</div>
<div className='grow overflow-y-auto space-y-2'>
{results.map((record, idx) => (
<ResultItem
key={idx}
payload={record}
isExternal={isExternal}
/>
))}
{results.map((record, idx) =>
isExternal
? (
<ResultItemExternal
key={idx}
positionId={idx + 1}
payload={record as ExternalKnowledgeBaseHitTesting}
/>
)
: (
<ResultItem key={idx} payload={record as HitTesting} />
),
)}
</div>
</div>
)
@ -130,7 +137,7 @@ const HitTesting: FC<Props> = ({ datasetId }: Props) => {
<>
<div className='grow overflow-y-auto'>
<table className={'w-full border-collapse border-0 text-[13px] leading-4 text-text-secondary '}>
<thead className="sticky top-0 h-7 leading-7 text-xs text-text-tertiary font-medium uppercase">
<thead className='sticky top-0 h-7 leading-7 text-xs text-text-tertiary font-medium uppercase'>
<tr>
<td className='pl-3 w-[128px] rounded-l-lg bg-background-section-burn'>{t('datasetHitTesting.table.header.source')}</td>
<td className='bg-background-section-burn'>{t('datasetHitTesting.table.header.text')}</td>
@ -208,4 +215,4 @@ const HitTesting: FC<Props> = ({ datasetId }: Props) => {
)
}
export default HitTesting
export default HitTestingPage

View File

@ -84,6 +84,7 @@ const TextAreaWithButton = ({
}
const externalRetrievalTestingOnSubmit = async () => {
setLoading(true)
const [e, res] = await asyncRunSafe<ExternalKnowledgeBaseHitTestingResponse>(
externalKnowledgeBaseHitTesting({
datasetId,

View File

@ -17,7 +17,7 @@ import Input from '@/app/components/base/input'
import Textarea from '@/app/components/base/textarea'
import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
import { updateDatasetSetting } from '@/service/datasets'
import { type DataSetListResponse } from '@/models/datasets'
import type { DataSetListResponse } from '@/models/datasets'
import DatasetDetailContext from '@/context/dataset-detail'
import type { RetrievalConfig } from '@/types/app'
import { useAppContext } from '@/context/app-context'
@ -223,7 +223,7 @@ const Form = () => {
<IndexMethodRadio
disable={!currentDataset?.embedding_available}
value={indexMethod}
onChange={v => setIndexMethod(v)}
onChange={v => setIndexMethod(v!)}
docForm={currentDataset.doc_form}
currentValue={currentDataset.indexing_technique}
/>
@ -300,35 +300,37 @@ const Form = () => {
</div>
</div>
</>
: <>
<div className='w-full h-0 border-b border-divider-subtle my-1' />
<div className={rowClass}>
<div className={labelClass}>
<div>
<div className='text-text-secondary system-sm-semibold'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='body-xs-regular text-text-tertiary'>
<a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
{t('datasetSettings.form.retrievalSetting.description')}
: indexMethod
? <>
<div className='w-full h-0 border-b border-divider-subtle my-1' />
<div className={rowClass}>
<div className={labelClass}>
<div>
<div className='text-text-secondary system-sm-semibold'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='body-xs-regular text-text-tertiary'>
<a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
{t('datasetSettings.form.retrievalSetting.description')}
</div>
</div>
</div>
<div className='grow'>
{indexMethod === IndexingType.QUALIFIED
? (
<RetrievalMethodConfig
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
)
: (
<EconomicalRetrievalMethodConfig
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
)}
</div>
</div>
<div className='grow'>
{indexMethod === 'high_quality'
? (
<RetrievalMethodConfig
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
)
: (
<EconomicalRetrievalMethodConfig
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
)}
</div>
</div>
</>
</>
: null
}
<div className='w-full h-0 border-b border-divider-subtle my-1' />
<div className={rowClass}>

View File

@ -74,7 +74,7 @@ const PermissionSelector = ({ disabled, permission, value, memberList, onChange,
>
{permission === 'only_me' && (
<div className={cn('flex items-center px-3 py-[6px] rounded-lg bg-gray-100 cursor-pointer hover:bg-gray-200', open && 'bg-gray-200', disabled && 'hover:!bg-gray-100 !cursor-default')}>
<Avatar name={userProfile.name} className='shrink-0 mr-2' size={24} />
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='shrink-0 mr-2' size={24} />
<div className='grow mr-2 text-gray-900 text-sm leading-5'>{t('datasetSettings.form.permissionsOnlyMe')}</div>
{!disabled && <RiArrowDownSLine className='shrink-0 w-4 h-4 text-gray-700' />}
</div>
@ -106,7 +106,7 @@ const PermissionSelector = ({ disabled, permission, value, memberList, onChange,
setOpen(false)
}}>
<div className='flex items-center gap-2'>
<Avatar name={userProfile.name} className='shrink-0 mr-2' size={24} />
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='shrink-0 mr-2' size={24} />
<div className='grow mr-2 text-gray-900 text-sm leading-5'>{t('datasetSettings.form.permissionsOnlyMe')}</div>
{permission === 'only_me' && <Check className='w-4 h-4 text-primary-600' />}
</div>
@ -149,7 +149,7 @@ const PermissionSelector = ({ disabled, permission, value, memberList, onChange,
</div>
{showMe && (
<div className='pl-3 pr-[10px] py-1 flex gap-2 items-center rounded-lg'>
<Avatar name={userProfile.name} className='shrink-0' size={24} />
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='shrink-0' size={24} />
<div className='grow'>
<div className='text-[13px] text-gray-700 font-medium leading-[18px] truncate'>
{userProfile.name}
@ -162,7 +162,7 @@ const PermissionSelector = ({ disabled, permission, value, memberList, onChange,
)}
{filteredMemberList.map(member => (
<div key={member.id} className='pl-3 pr-[10px] py-1 flex gap-2 items-center rounded-lg hover:bg-gray-100 cursor-pointer' onClick={() => selectMember(member)}>
<Avatar name={member.name} className='shrink-0' size={24} />
<Avatar avatar={userProfile.avatar_url} name={member.name} className='shrink-0' size={24} />
<div className='grow'>
<div className='text-[13px] text-gray-700 font-medium leading-[18px] truncate'>{member.name}</div>
<div className='text-xs text-gray-500 leading-[18px] truncate'>{member.email}</div>

View File

@ -10,6 +10,7 @@ import {
import { Tab } from '@headlessui/react'
import { Tag } from './tag'
import classNames from '@/utils/classnames'
import { writeTextToClipboard } from '@/utils/clipboard'
const languageNames = {
js: 'JavaScript',
@ -71,7 +72,7 @@ function CopyButton({ code }: { code: string }) {
: 'bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5',
)}
onClick={() => {
window.navigator.clipboard.writeText(code).then(() => {
writeTextToClipboard(code).then(() => {
setCopyCount(count => count + 1)
})
}}

View File

@ -1,4 +1,5 @@
'use client'
import type { PropsWithChildren } from 'react'
import classNames from '@/utils/classnames'
type IChildrenProps = {
@ -139,3 +140,9 @@ export function SubProperty({ name, type, children }: ISubProperty) {
</li>
)
}
export function PropertyInstruction({ children }: PropsWithChildren<{}>) {
return (
<li className="m-0 px-0 py-4 first:pt-0 italic">{children}</li>
)
}

View File

@ -67,7 +67,7 @@ export default function AppSelector({ isMobile }: IAppSelector) {
${open && 'bg-gray-200'}
`}
>
<Avatar name={userProfile.name} className='sm:mr-2 mr-0' size={32} />
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='sm:mr-2 mr-0' size={32} />
{!isMobile && <>
{userProfile.name}
<RiArrowDownSLine className="w-3 h-3 ml-1 text-gray-700" />
@ -91,7 +91,7 @@ export default function AppSelector({ isMobile }: IAppSelector) {
>
<Menu.Item disabled>
<div className='flex flex-nowrap items-center px-4 py-[13px]'>
<Avatar name={userProfile.name} size={36} className='mr-3' />
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={36} className='mr-3' />
<div className='grow'>
<div className='system-md-medium text-text-primary break-all'>{userProfile.name}</div>
<div className='system-xs-regular text-text-tertiary break-all'>{userProfile.email}</div>

View File

@ -95,7 +95,7 @@ const MembersPage = () => {
accounts.map(account => (
<div key={account.id} className='flex border-b border-divider-subtle'>
<div className='grow flex items-center py-2 px-3'>
<Avatar size={24} className='mr-2' name={account.name} />
<Avatar avatar={account.avatar_url} size={24} className='mr-2' name={account.name} />
<div className=''>
<div className='text-text-secondary system-sm-medium'>
{account.name}

View File

@ -647,10 +647,12 @@ const TextGeneration: FC<IMainProps> = ({
isInstalledApp ? 'left-[248px]' : 'left-8',
'fixed bottom-4 flex space-x-2 text-gray-400 font-normal text-xs',
)}>
<div className="">© {siteInfo.copyright || siteInfo.title} {(new Date()).getFullYear()}</div>
{siteInfo.copyright && (
<div className="">© {(new Date()).getFullYear()} {siteInfo.copyright}</div>
)}
{siteInfo.privacy_policy && (
<>
<div>·</div>
{siteInfo.copyright && <div>·</div>}
<div>{t('share.chat.privacyPolicyLeft')}
<a
className='text-gray-500 px-1'

View File

@ -48,7 +48,7 @@ const ProviderList = () => {
if (tagFilterValue.length > 0 && (!collection.labels || collection.labels.every(label => !tagFilterValue.includes(label))))
return false
if (keywords)
return collection.name.toLowerCase().includes(keywords.toLowerCase())
return Object.values(collection.label).some(value => value.toLowerCase().includes(keywords.toLowerCase()))
return true
})
}, [activeTab, tagFilterValue, keywords, collectionList])

View File

@ -277,7 +277,21 @@ export const useWorkflowRun = () => {
edges,
viewport,
})
featuresStore?.setState({ features: publishedWorkflow.features })
const mappedFeatures = {
opening: {
enabled: !!publishedWorkflow.features.opening_statement || !!publishedWorkflow.features.suggested_questions.length,
opening_statement: publishedWorkflow.features.opening_statement,
suggested_questions: publishedWorkflow.features.suggested_questions,
},
suggested: publishedWorkflow.features.suggested_questions_after_answer,
text2speech: publishedWorkflow.features.text_to_speech,
speech2text: publishedWorkflow.features.speech_to_text,
citation: publishedWorkflow.features.retriever_resource,
moderation: publishedWorkflow.features.sensitive_word_avoidance,
file: publishedWorkflow.features.file_upload,
}
featuresStore?.setState({ features: mappedFeatures })
workflowStore.getState().setPublishedAt(publishedWorkflow.created_at)
workflowStore.getState().setEnvironmentVariables(publishedWorkflow.environment_variables || [])
}, [featuresStore, handleUpdateWorkflowCanvas, workflowStore])

View File

@ -167,6 +167,9 @@ export const getMultipleRetrievalConfig = (
}
}
}
else {
result.reranking_enable = true
}
}
if (allHighQuality && !inconsistentEmbeddingModel && allInternal) {
@ -205,13 +208,6 @@ export const getMultipleRetrievalConfig = (
result.reranking_mode = RerankingModeEnum.WeightedScore
setDefaultWeights()
}
if (reranking_mode === RerankingModeEnum.RerankingModel && rerankModelIsValid) {
result.reranking_enable = true
result.reranking_model = {
provider: validRerankModel.provider || '',
model: validRerankModel.model || '',
}
}
}
return result

View File

@ -4,39 +4,39 @@ export const CUSTOM_NOTE_NODE = 'custom-note'
export const THEME_MAP: Record<string, { outer: string; title: string; bg: string; border: string }> = {
[NoteTheme.blue]: {
outer: '#2E90FA',
title: '#D1E9FF',
bg: '#EFF8FF',
border: '#84CAFF',
outer: 'border-util-colors-blue-blue-500',
title: 'bg-util-colors-blue-blue-100',
bg: 'bg-util-colors-blue-blue-50',
border: 'border-util-colors-blue-blue-300',
},
[NoteTheme.cyan]: {
outer: '#06AED4',
title: '#CFF9FE',
bg: '#ECFDFF',
border: '#67E3F9',
outer: 'border-util-colors-cyan-cyan-500',
title: 'bg-util-colors-cyan-cyan-100',
bg: 'bg-util-colors-cyan-cyan-50',
border: 'border-util-colors-cyan-cyan-300',
},
[NoteTheme.green]: {
outer: '#16B364',
title: '#D3F8DF',
bg: '#EDFCF2',
border: '#73E2A3',
outer: 'border-util-colors-green-green-500',
title: 'bg-util-colors-green-green-100',
bg: 'bg-util-colors-green-green-50',
border: 'border-util-colors-green-green-300',
},
[NoteTheme.yellow]: {
outer: '#EAAA08',
title: '#FEF7C3',
bg: '#FEFBE8',
border: '#FDE272',
outer: 'border-util-colors-yellow-yellow-500',
title: 'bg-util-colors-yellow-yellow-100',
bg: 'bg-util-colors-yellow-yellow-50',
border: 'border-util-colors-yellow-yellow-300',
},
[NoteTheme.pink]: {
outer: '#EE46BC',
title: '#FCE7F6',
bg: '#FDF2FA',
border: '#FAA7E0',
outer: 'border-util-colors-pink-pink-500',
title: 'bg-util-colors-pink-pink-100',
bg: 'bg-util-colors-pink-pink-50',
border: 'border-util-colors-pink-pink-300',
},
[NoteTheme.violet]: {
outer: '#875BF7',
title: '#ECE9FE',
bg: '#F5F3FF',
border: '#C3B5FD',
outer: 'border-util-colors-violet-violet-500',
title: 'bg-util-colors-violet-violet-100',
bg: 'bg-util-colors-violet-violet-100',
border: 'border-util-colors-violet-violet-300',
},
}

View File

@ -62,10 +62,10 @@ const NoteNode = ({
<div
className={cn(
'flex flex-col relative rounded-md shadow-xs border hover:shadow-md',
THEME_MAP[theme].bg,
data.selected ? THEME_MAP[theme].border : 'border-black/5',
)}
style={{
background: THEME_MAP[theme].bg,
borderColor: data.selected ? THEME_MAP[theme].border : 'rgba(0, 0, 0, 0.05)',
width: data.width,
height: data.height,
}}
@ -83,7 +83,11 @@ const NoteNode = ({
minWidth={240}
minHeight={88}
/>
<div className='shrink-0 h-2 opacity-50 rounded-t-md' style={{ background: THEME_MAP[theme].title }}></div>
<div
className={cn(
'shrink-0 h-2 opacity-50 rounded-t-md',
THEME_MAP[theme].title,
)}></div>
{
data.selected && (
<div className='absolute -top-[41px] left-1/2 -translate-x-1/2'>
@ -112,7 +116,7 @@ const NoteNode = ({
</div>
{
data.showAuthor && (
<div className='p-3 pt-0 text-xs text-black/[0.32]'>
<div className='p-3 pt-0 text-xs text-text-tertiary'>
{data.author}
</div>
)

View File

@ -44,7 +44,7 @@ const Editor = ({
onFocus={() => setShortcutsEnabled(false)}
onBlur={() => setShortcutsEnabled(true)}
spellCheck={false}
className='w-full h-full outline-none caret-primary-600'
className='w-full h-full outline-none text-text-secondary caret-primary-600'
placeholder={placeholder}
/>
</div>

View File

@ -69,9 +69,9 @@ const LinkEditorComponent = ({
<FloatingPortal root={containerElement}>
<div
className={cn(
'nodrag nopan inline-flex items-center w-max rounded-md border-[0.5px] border-black/5 bg-white z-10',
'nodrag nopan inline-flex items-center w-max rounded-md border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg z-10',
!linkOperatorShow && 'p-1 shadow-md',
linkOperatorShow && 'p-0.5 shadow-sm text-xs text-gray-500 font-medium',
linkOperatorShow && 'p-0.5 shadow-sm system-xs-medium text-text-tertiary',
)}
style={floatingStyles}
ref={refs.setFloating}
@ -80,7 +80,7 @@ const LinkEditorComponent = ({
!linkOperatorShow && (
<>
<input
className='mr-0.5 p-1 w-[196px] h-6 rounded-sm text-[13px] appearance-none outline-none'
className='mr-0.5 p-1 w-[196px] h-6 rounded-sm text-[13px] appearance-none outline-none bg-transparent text-components-input-text-filled'
value={url}
onChange={e => setUrl(e.target.value)}
placeholder={t('workflow.nodes.note.editor.enterUrl') || ''}
@ -101,7 +101,7 @@ const LinkEditorComponent = ({
linkOperatorShow && (
<>
<a
className='flex items-center px-2 h-6 rounded-md hover:bg-gray-50'
className='flex items-center px-2 h-6 rounded-md hover:bg-state-base-hover'
href={escape(url)}
target='_blank'
rel='noreferrer'
@ -112,14 +112,14 @@ const LinkEditorComponent = ({
</div>
<div
title={escape(url)}
className='text-primary-600 max-w-[140px] truncate'
className='text-text-accent max-w-[140px] truncate'
>
{escape(url)}
</div>
</a>
<div className='mx-1 w-[1px] h-3.5 bg-gray-100'></div>
<div className='mx-1 w-[1px] h-3.5 bg-divider-regular'></div>
<div
className='flex items-center mr-0.5 px-2 h-6 rounded-md cursor-pointer hover:bg-gray-50'
className='flex items-center mr-0.5 px-2 h-6 rounded-md cursor-pointer hover:bg-state-base-hover'
onClick={(e) => {
e.stopPropagation()
setLinkOperatorShow(false)
@ -129,7 +129,7 @@ const LinkEditorComponent = ({
{t('common.operation.edit')}
</div>
<div
className='flex items-center px-2 h-6 rounded-md cursor-pointer hover:bg-gray-50'
className='flex items-center px-2 h-6 rounded-md cursor-pointer hover:bg-state-base-hover'
onClick={handleUnlink}
>
<RiLinkUnlinkM className='mr-1 w-3 h-3' />

View File

@ -16,7 +16,7 @@
.note-editor-theme_link {
cursor: pointer;
color: #155eef;
color: var(--text-text-selected);
}
.note-editor-theme_link:hover {

View File

@ -67,13 +67,15 @@ const ColorPicker = ({
open && 'bg-black/5',
)}>
<div
className='w-4 h-4 rounded-full border border-black/5'
style={{ backgroundColor: THEME_MAP[theme].title }}
className={cn(
'w-4 h-4 rounded-full border border-black/5',
THEME_MAP[theme].title,
)}
></div>
</div>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent>
<div className='grid grid-cols-3 grid-rows-2 gap-0.5 p-0.5 rounded-lg border-[0.5px] border-black/8 bg-white shadow-lg'>
<div className='grid grid-cols-3 grid-rows-2 gap-0.5 p-0.5 rounded-lg border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg shadow-lg'>
{
COLOR_LIST.map(color => (
<div
@ -86,12 +88,16 @@ const ColorPicker = ({
}}
>
<div
className='hidden group-hover:block absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-5 h-5 rounded-full border-[1.5px]'
style={{ borderColor: color.outer }}
className={cn(
'hidden group-hover:block absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-5 h-5 rounded-full border-[1.5px]',
color.outer,
)}
></div>
<div
className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-4 h-4 rounded-full border border-black/5'
style={{ backgroundColor: color.inner }}
className={cn(
'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-4 h-4 rounded-full border border-black/5',
color.inner,
)}
></div>
</div>
))

View File

@ -65,12 +65,12 @@ const Command = ({
>
<div
className={cn(
'flex items-center justify-center w-8 h-8 cursor-pointer rounded-md text-gray-500 hover:text-gray-800 hover:bg-black/5',
type === 'bold' && selectedIsBold && 'bg-primary-50',
type === 'italic' && selectedIsItalic && 'bg-primary-50',
type === 'strikethrough' && selectedIsStrikeThrough && 'bg-primary-50',
type === 'link' && selectedIsLink && 'bg-primary-50',
type === 'bullet' && selectedIsBullet && 'bg-primary-50',
'flex items-center justify-center w-8 h-8 cursor-pointer rounded-md text-text-tertiary hover:text-text-accent hover:bg-state-accent-active',
type === 'bold' && selectedIsBold && 'bg-state-accent-active',
type === 'italic' && selectedIsItalic && 'bg-state-accent-active',
type === 'strikethrough' && selectedIsStrikeThrough && 'bg-state-accent-active',
type === 'link' && selectedIsLink && 'bg-state-accent-active',
type === 'bullet' && selectedIsBullet && 'bg-state-accent-active',
)}
onClick={() => handleCommand(type)}
>

View File

@ -1,6 +1,6 @@
const Divider = () => {
return (
<div className='mx-1 w-[1px] h-3.5 bg-gray-200'></div>
<div className='mx-1 w-[1px] h-3.5 bg-divider-regular'></div>
)
}

View File

@ -42,20 +42,20 @@ const FontSizeSelector = () => {
>
<PortalToFollowElemTrigger onClick={() => handleOpenFontSizeSelector(!fontSizeSelectorShow)}>
<div className={cn(
'flex items-center pl-2 pr-1.5 h-8 rounded-md text-[13px] font-medium text-gray-700 cursor-pointer hover:bg-gray-50',
fontSizeSelectorShow && 'bg-gray-50',
'flex items-center pl-2 pr-1.5 h-8 rounded-md text-[13px] font-medium text-text-tertiary hover:text-text-secondary cursor-pointer hover:bg-state-base-hover',
fontSizeSelectorShow && 'bg-state-base-hover text-text-secondary',
)}>
<RiFontSize className='mr-1 w-4 h-4' />
{FONT_SIZE_LIST.find(font => font.key === fontSize)?.value || t('workflow.nodes.note.editor.small')}
</div>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent>
<div className='p-1 w-[120px] bg-white border-[0.5px] border-gray-200 rounded-md shadow-xl text-gray-700'>
<div className='p-1 w-[120px] bg-components-panel-bg-blur border-[0.5px] border-components-panel-border rounded-md shadow-xl text-text-secondary'>
{
FONT_SIZE_LIST.map(font => (
<div
key={font.key}
className='flex items-center justify-between pl-3 pr-2 h-8 rounded-md cursor-pointer hover:bg-gray-50'
className='flex items-center justify-between pl-3 pr-2 h-8 rounded-md cursor-pointer hover:bg-state-base-hover'
onClick={(e) => {
e.stopPropagation()
handleFontSize(font.key)
@ -69,7 +69,7 @@ const FontSizeSelector = () => {
</div>
{
fontSize === font.key && (
<Check className='w-4 h-4 text-primary-500' />
<Check className='w-4 h-4 text-text-accent' />
)
}
</div>

View File

@ -18,7 +18,7 @@ const Toolbar = ({
onShowAuthorChange,
}: ToolbarProps) => {
return (
<div className='inline-flex items-center p-0.5 bg-white rounded-lg border-[0.5px] border-black/5 shadow-sm'>
<div className='inline-flex items-center p-0.5 bg-components-actionbar-bg rounded-lg border-[0.5px] border-components-actionbar-border shadow-sm'>
<ColorPicker
theme={theme}
onThemeChange={onThemeChange}

View File

@ -40,18 +40,18 @@ const Operator = ({
<PortalToFollowElemTrigger onClick={() => setOpen(!open)}>
<div
className={cn(
'flex items-center justify-center w-8 h-8 cursor-pointer rounded-lg hover:bg-black/5',
open && 'bg-black/5',
'flex items-center justify-center w-8 h-8 cursor-pointer rounded-lg text-text-tertiary hover:text-text-secondary hover:bg-state-base-hover',
open && 'bg-state-base-hover text-text-secondary',
)}
>
<RiMoreFill className='w-4 h-4 text-gray-500' />
<RiMoreFill className='w-4 h-4' />
</div>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent>
<div className='min-w-[192px] bg-white rounded-md border-[0.5px] border-gray-200 shadow-xl'>
<div className='min-w-[192px] bg-components-panel-bg-blur rounded-md border-[0.5px] border-components-panel-border shadow-xl'>
<div className='p-1'>
<div
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:bg-black/5'
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-text-secondary hover:bg-state-base-hover'
onClick={() => {
onCopy()
setOpen(false)
@ -61,7 +61,7 @@ const Operator = ({
<ShortcutsName keys={['ctrl', 'c']} />
</div>
<div
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:bg-black/5'
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-text-secondary hover:bg-state-base-hover'
onClick={() => {
onDuplicate()
setOpen(false)
@ -71,10 +71,10 @@ const Operator = ({
<ShortcutsName keys={['ctrl', 'd']} />
</div>
</div>
<div className='h-[1px] bg-gray-100'></div>
<div className='h-[1px] bg-divider-subtle'></div>
<div className='p-1'>
<div
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:bg-black/5'
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-text-secondary hover:bg-state-base-hover'
onClick={e => e.stopPropagation()}
>
<div>{t('workflow.nodes.note.editor.showAuthor')}</div>
@ -85,10 +85,10 @@ const Operator = ({
/>
</div>
</div>
<div className='h-[1px] bg-gray-100'></div>
<div className='h-[1px] bg-divider-subtle'></div>
<div className='p-1'>
<div
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:text-[#D92D20] hover:bg-[#FEF3F2]'
className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-text-secondary hover:text-text-destructive hover:bg-state-destructive-hover'
onClick={() => {
onDelete()
setOpen(false)

View File

@ -1,6 +1,5 @@
import exp from 'constants'
import format from '.'
import { agentNodeData, oneStepCircle, multiStepsCircle } from './data'
import { agentNodeData, multiStepsCircle, oneStepCircle } from './data'
describe('agent', () => {
test('list should transform to tree', () => {

View File

@ -47,6 +47,7 @@ const LocaleLayout = ({
data-public-site-about={process.env.NEXT_PUBLIC_SITE_ABOUT}
data-public-text-generation-timeout-ms={process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS}
data-public-top-k-max-value={process.env.NEXT_PUBLIC_TOP_K_MAX_VALUE}
data-public-indexing-max-segmentation-tokens-length={process.env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH}
>
<BrowserInitor>
<SentryInitor>