mirror of https://github.com/langgenius/dify.git
chore: support Zendesk widget (#25517)
This commit is contained in:
parent
af7f67dc9c
commit
07d067d828
|
|
@ -24,7 +24,7 @@ const GA: FC<IGAProps> = ({
|
||||||
if (IS_CE_EDITION)
|
if (IS_CE_EDITION)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
const nonce = process.env.NODE_ENV === 'production' ? (headers() as unknown as UnsafeUnwrappedHeaders).get('x-nonce') : ''
|
const nonce = process.env.NODE_ENV === 'production' ? (headers() as unknown as UnsafeUnwrappedHeaders).get('x-nonce') ?? '' : ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -32,7 +32,7 @@ const GA: FC<IGAProps> = ({
|
||||||
strategy="beforeInteractive"
|
strategy="beforeInteractive"
|
||||||
async
|
async
|
||||||
src={`https://www.googletagmanager.com/gtag/js?id=${gaIdMaps[gaType]}`}
|
src={`https://www.googletagmanager.com/gtag/js?id=${gaIdMaps[gaType]}`}
|
||||||
nonce={nonce!}
|
nonce={nonce ?? undefined}
|
||||||
></Script>
|
></Script>
|
||||||
<Script
|
<Script
|
||||||
id="ga-init"
|
id="ga-init"
|
||||||
|
|
@ -44,14 +44,14 @@ gtag('js', new Date());
|
||||||
gtag('config', '${gaIdMaps[gaType]}');
|
gtag('config', '${gaIdMaps[gaType]}');
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
nonce={nonce!}
|
nonce={nonce ?? undefined}
|
||||||
>
|
>
|
||||||
</Script>
|
</Script>
|
||||||
{/* Cookie banner */}
|
{/* Cookie banner */}
|
||||||
<Script
|
<Script
|
||||||
id="cookieyes"
|
id="cookieyes"
|
||||||
src='https://cdn-cookieyes.com/client_data/2a645945fcae53f8e025a2b1/script.js'
|
src='https://cdn-cookieyes.com/client_data/2a645945fcae53f8e025a2b1/script.js'
|
||||||
nonce={nonce!}
|
nonce={nonce ?? undefined}
|
||||||
></Script>
|
></Script>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { memo } from 'react'
|
||||||
|
import { type UnsafeUnwrappedHeaders, headers } from 'next/headers'
|
||||||
|
import Script from 'next/script'
|
||||||
|
import { IS_CE_EDITION, ZENDESK_WIDGET_KEY } from '@/config'
|
||||||
|
|
||||||
|
const Zendesk = () => {
|
||||||
|
if (IS_CE_EDITION || !ZENDESK_WIDGET_KEY)
|
||||||
|
return null
|
||||||
|
|
||||||
|
const nonce = process.env.NODE_ENV === 'production' ? (headers() as unknown as UnsafeUnwrappedHeaders).get('x-nonce') ?? '' : ''
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Script
|
||||||
|
nonce={nonce ?? undefined}
|
||||||
|
id="ze-snippet"
|
||||||
|
src={`https://static.zdassets.com/ekr/snippet.js?key=${ZENDESK_WIDGET_KEY}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(Zendesk)
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { IS_CE_EDITION } from '@/config'
|
||||||
|
|
||||||
|
export type ConversationField = {
|
||||||
|
id: string,
|
||||||
|
value: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line ts/consistent-type-definitions
|
||||||
|
interface Window {
|
||||||
|
zE?: (
|
||||||
|
command: string,
|
||||||
|
value: string,
|
||||||
|
payload?: ConversationField[] | string | string[] | (() => any),
|
||||||
|
callback?: () => any,
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setZendeskConversationFields = (fields: ConversationField[], callback?: () => any) => {
|
||||||
|
if (!IS_CE_EDITION && window.zE)
|
||||||
|
window.zE('messenger:set', 'conversationFields', fields, callback)
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ import type { Viewport } from 'next'
|
||||||
import I18nServer from './components/i18n-server'
|
import I18nServer from './components/i18n-server'
|
||||||
import BrowserInitializer from './components/browser-initializer'
|
import BrowserInitializer from './components/browser-initializer'
|
||||||
import SentryInitializer from './components/sentry-initializer'
|
import SentryInitializer from './components/sentry-initializer'
|
||||||
|
import Zendesk from './components/base/zendesk'
|
||||||
import { getLocaleOnServer } from '@/i18n-config/server'
|
import { getLocaleOnServer } from '@/i18n-config/server'
|
||||||
import { TanstackQueryInitializer } from '@/context/query-client'
|
import { TanstackQueryInitializer } from '@/context/query-client'
|
||||||
import { ThemeProvider } from 'next-themes'
|
import { ThemeProvider } from 'next-themes'
|
||||||
|
|
@ -48,6 +49,12 @@ const LocaleLayout = async ({
|
||||||
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER,
|
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER,
|
||||||
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL,
|
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL,
|
||||||
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL,
|
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL,
|
||||||
|
[DatasetAttr.NEXT_PUBLIC_ZENDESK_WIDGET_KEY]: process.env.NEXT_PUBLIC_ZENDESK_WIDGET_KEY,
|
||||||
|
[DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT]: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT,
|
||||||
|
[DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION]: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION,
|
||||||
|
[DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL]: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL,
|
||||||
|
[DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID]: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID,
|
||||||
|
[DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN]: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -89,6 +96,7 @@ const LocaleLayout = async ({
|
||||||
</BrowserInitializer>
|
</BrowserInitializer>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
<RoutePrefixHandle />
|
<RoutePrefixHandle />
|
||||||
|
<Zendesk />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -173,46 +173,46 @@ export const DEFAULT_AGENT_SETTING = {
|
||||||
export const DEFAULT_AGENT_PROMPT = {
|
export const DEFAULT_AGENT_PROMPT = {
|
||||||
chat: `Respond to the human as helpfully and accurately as possible.
|
chat: `Respond to the human as helpfully and accurately as possible.
|
||||||
|
|
||||||
{{instruction}}
|
{{instruction}}
|
||||||
|
|
||||||
You have access to the following tools:
|
You have access to the following tools:
|
||||||
|
|
||||||
{{tools}}
|
{{tools}}
|
||||||
|
|
||||||
Use a json blob to specify a tool by providing an {{TOOL_NAME_KEY}} key (tool name) and an {{ACTION_INPUT_KEY}} key (tool input).
|
Use a json blob to specify a tool by providing an {{TOOL_NAME_KEY}} key (tool name) and an {{ACTION_INPUT_KEY}} key (tool input).
|
||||||
Valid "{{TOOL_NAME_KEY}}" values: "Final Answer" or {{tool_names}}
|
Valid "{{TOOL_NAME_KEY}}" values: "Final Answer" or {{tool_names}}
|
||||||
|
|
||||||
Provide only ONE action per $JSON_BLOB, as shown:
|
Provide only ONE action per $JSON_BLOB, as shown:
|
||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
{
|
{
|
||||||
"{{TOOL_NAME_KEY}}": $TOOL_NAME,
|
"{{TOOL_NAME_KEY}}": $TOOL_NAME,
|
||||||
"{{ACTION_INPUT_KEY}}": $ACTION_INPUT
|
"{{ACTION_INPUT_KEY}}": $ACTION_INPUT
|
||||||
}
|
}
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
Follow this format:
|
Follow this format:
|
||||||
|
|
||||||
Question: input question to answer
|
Question: input question to answer
|
||||||
Thought: consider previous and subsequent steps
|
Thought: consider previous and subsequent steps
|
||||||
Action:
|
Action:
|
||||||
\`\`\`
|
\`\`\`
|
||||||
$JSON_BLOB
|
$JSON_BLOB
|
||||||
\`\`\`
|
\`\`\`
|
||||||
Observation: action result
|
Observation: action result
|
||||||
... (repeat Thought/Action/Observation N times)
|
... (repeat Thought/Action/Observation N times)
|
||||||
Thought: I know what to respond
|
Thought: I know what to respond
|
||||||
Action:
|
Action:
|
||||||
\`\`\`
|
\`\`\`
|
||||||
{
|
{
|
||||||
"{{TOOL_NAME_KEY}}": "Final Answer",
|
"{{TOOL_NAME_KEY}}": "Final Answer",
|
||||||
"{{ACTION_INPUT_KEY}}": "Final response to human"
|
"{{ACTION_INPUT_KEY}}": "Final response to human"
|
||||||
}
|
}
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
Begin! Reminder to ALWAYS respond with a valid json blob of a single action. Use tools if necessary. Respond directly if appropriate. Format is Action:\`\`\`$JSON_BLOB\`\`\`then Observation:.`,
|
Begin! Reminder to ALWAYS respond with a valid json blob of a single action. Use tools if necessary. Respond directly if appropriate. Format is Action:\`\`\`$JSON_BLOB\`\`\`then Observation:.`,
|
||||||
completion: `
|
completion: `
|
||||||
Respond to the human as helpfully and accurately as possible.
|
Respond to the human as helpfully and accurately as possible.
|
||||||
|
|
||||||
{{instruction}}
|
{{instruction}}
|
||||||
|
|
||||||
|
|
@ -285,3 +285,12 @@ export const ENABLE_WEBSITE_WATERCRAWL = getBooleanConfig(process.env.NEXT_PUBLI
|
||||||
export const VALUE_SELECTOR_DELIMITER = '@@@'
|
export const VALUE_SELECTOR_DELIMITER = '@@@'
|
||||||
|
|
||||||
export const validPassword = /^(?=.*[a-zA-Z])(?=.*\d)\S{8,}$/
|
export const validPassword = /^(?=.*[a-zA-Z])(?=.*\d)\S{8,}$/
|
||||||
|
|
||||||
|
export const ZENDESK_WIDGET_KEY = getStringConfig(process.env.NEXT_PUBLIC_ZENDESK_WIDGET_KEY, DatasetAttr.NEXT_PUBLIC_ZENDESK_WIDGET_KEY, '')
|
||||||
|
export const ZENDESK_FIELD_IDS = {
|
||||||
|
ENVIRONMENT: getStringConfig(process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT, DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT, ''),
|
||||||
|
VERSION: getStringConfig(process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION, DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION, ''),
|
||||||
|
EMAIL: getStringConfig(process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL, DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL, ''),
|
||||||
|
WORKSPACE_ID: getStringConfig(process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID, DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID, ''),
|
||||||
|
PLAN: getStringConfig(process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN, DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN, ''),
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import { fetchCurrentWorkspace, fetchLangGeniusVersion, fetchUserProfile } from
|
||||||
import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
|
import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
|
||||||
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
|
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
|
||||||
import { noop } from 'lodash-es'
|
import { noop } from 'lodash-es'
|
||||||
|
import { setZendeskConversationFields } from '@/app/components/base/zendesk/utils'
|
||||||
|
import { ZENDESK_FIELD_IDS } from '@/config'
|
||||||
|
|
||||||
export type AppContextValue = {
|
export type AppContextValue = {
|
||||||
userProfile: UserProfileResponse
|
userProfile: UserProfileResponse
|
||||||
|
|
@ -115,6 +117,44 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
||||||
setCurrentWorkspace(currentWorkspaceResponse)
|
setCurrentWorkspace(currentWorkspaceResponse)
|
||||||
}, [currentWorkspaceResponse])
|
}, [currentWorkspaceResponse])
|
||||||
|
|
||||||
|
// #region Zendesk conversation fields
|
||||||
|
useEffect(() => {
|
||||||
|
if (ZENDESK_FIELD_IDS.ENVIRONMENT && langGeniusVersionInfo?.current_env) {
|
||||||
|
setZendeskConversationFields([{
|
||||||
|
id: ZENDESK_FIELD_IDS.ENVIRONMENT,
|
||||||
|
value: langGeniusVersionInfo.current_env.toLowerCase(),
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}, [langGeniusVersionInfo?.current_env])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ZENDESK_FIELD_IDS.VERSION && langGeniusVersionInfo?.version) {
|
||||||
|
setZendeskConversationFields([{
|
||||||
|
id: ZENDESK_FIELD_IDS.VERSION,
|
||||||
|
value: langGeniusVersionInfo.version,
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}, [langGeniusVersionInfo?.version])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ZENDESK_FIELD_IDS.EMAIL && userProfile?.email) {
|
||||||
|
setZendeskConversationFields([{
|
||||||
|
id: ZENDESK_FIELD_IDS.EMAIL,
|
||||||
|
value: userProfile.email,
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}, [userProfile?.email])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ZENDESK_FIELD_IDS.WORKSPACE_ID && currentWorkspace?.id) {
|
||||||
|
setZendeskConversationFields([{
|
||||||
|
id: ZENDESK_FIELD_IDS.WORKSPACE_ID,
|
||||||
|
value: currentWorkspace.id,
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}, [currentWorkspace?.id])
|
||||||
|
// #endregion Zendesk conversation fields
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext.Provider value={{
|
<AppContext.Provider value={{
|
||||||
userProfile,
|
userProfile,
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import {
|
||||||
useEducationStatus,
|
useEducationStatus,
|
||||||
} from '@/service/use-education'
|
} from '@/service/use-education'
|
||||||
import { noop } from 'lodash-es'
|
import { noop } from 'lodash-es'
|
||||||
|
import { setZendeskConversationFields } from '@/app/components/base/zendesk/utils'
|
||||||
|
import { ZENDESK_FIELD_IDS } from '@/config'
|
||||||
|
|
||||||
type ProviderContextState = {
|
type ProviderContextState = {
|
||||||
modelProviders: ModelProvider[]
|
modelProviders: ModelProvider[]
|
||||||
|
|
@ -189,6 +191,17 @@ export const ProviderContextProvider = ({
|
||||||
fetchPlan()
|
fetchPlan()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// #region Zendesk conversation fields
|
||||||
|
useEffect(() => {
|
||||||
|
if (ZENDESK_FIELD_IDS.PLAN && plan.type) {
|
||||||
|
setZendeskConversationFields([{
|
||||||
|
id: ZENDESK_FIELD_IDS.PLAN,
|
||||||
|
value: `${plan.type}-plan`,
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}, [plan.type])
|
||||||
|
// #endregion Zendesk conversation fields
|
||||||
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem('anthropic_quota_notice') === 'true')
|
if (localStorage.getItem('anthropic_quota_notice') === 'true')
|
||||||
|
|
|
||||||
|
|
@ -122,4 +122,10 @@ export enum DatasetAttr {
|
||||||
DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER = 'data-public-enable-website-jinareader',
|
DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER = 'data-public-enable-website-jinareader',
|
||||||
DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL = 'data-public-enable-website-firecrawl',
|
DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL = 'data-public-enable-website-firecrawl',
|
||||||
DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL = 'data-public-enable-website-watercrawl',
|
DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL = 'data-public-enable-website-watercrawl',
|
||||||
|
NEXT_PUBLIC_ZENDESK_WIDGET_KEY = 'next-public-zendesk-widget-key',
|
||||||
|
NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT = 'next-public-zendesk-field-id-environment',
|
||||||
|
NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION = 'next-public-zendesk-field-id-version',
|
||||||
|
NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL = 'next-public-zendesk-field-id-email',
|
||||||
|
NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID = 'next-public-zendesk-field-id-workspace-id',
|
||||||
|
NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN = 'next-public-zendesk-field-id-plan',
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue