| @@ -24,7 +24,7 @@ const GA: FC<IGAProps> = ({ | |||
| if (IS_CE_EDITION) | |||
| 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 ( | |||
| <> | |||
| @@ -32,7 +32,7 @@ const GA: FC<IGAProps> = ({ | |||
| strategy="beforeInteractive" | |||
| async | |||
| src={`https://www.googletagmanager.com/gtag/js?id=${gaIdMaps[gaType]}`} | |||
| nonce={nonce!} | |||
| nonce={nonce ?? undefined} | |||
| ></Script> | |||
| <Script | |||
| id="ga-init" | |||
| @@ -44,14 +44,14 @@ gtag('js', new Date()); | |||
| gtag('config', '${gaIdMaps[gaType]}'); | |||
| `, | |||
| }} | |||
| nonce={nonce!} | |||
| nonce={nonce ?? undefined} | |||
| > | |||
| </Script> | |||
| {/* Cookie banner */} | |||
| <Script | |||
| id="cookieyes" | |||
| src='https://cdn-cookieyes.com/client_data/2a645945fcae53f8e025a2b1/script.js' | |||
| nonce={nonce!} | |||
| nonce={nonce ?? undefined} | |||
| ></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 BrowserInitializer from './components/browser-initializer' | |||
| import SentryInitializer from './components/sentry-initializer' | |||
| import Zendesk from './components/base/zendesk' | |||
| import { getLocaleOnServer } from '@/i18n-config/server' | |||
| import { TanstackQueryInitializer } from '@/context/query-client' | |||
| 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_FIRECRAWL]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL, | |||
| [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 ( | |||
| @@ -89,6 +96,7 @@ const LocaleLayout = async ({ | |||
| </BrowserInitializer> | |||
| </ThemeProvider> | |||
| <RoutePrefixHandle /> | |||
| <Zendesk /> | |||
| </body> | |||
| </html> | |||
| ) | |||
| @@ -173,46 +173,46 @@ export const DEFAULT_AGENT_SETTING = { | |||
| export const DEFAULT_AGENT_PROMPT = { | |||
| 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). | |||
| Valid "{{TOOL_NAME_KEY}}" values: "Final Answer" or {{tool_names}} | |||
| 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}} | |||
| Provide only ONE action per $JSON_BLOB, as shown: | |||
| Provide only ONE action per $JSON_BLOB, as shown: | |||
| \`\`\` | |||
| { | |||
| "{{TOOL_NAME_KEY}}": $TOOL_NAME, | |||
| "{{ACTION_INPUT_KEY}}": $ACTION_INPUT | |||
| } | |||
| \`\`\` | |||
| Follow this format: | |||
| Question: input question to answer | |||
| Thought: consider previous and subsequent steps | |||
| Action: | |||
| \`\`\` | |||
| $JSON_BLOB | |||
| \`\`\` | |||
| Observation: action result | |||
| ... (repeat Thought/Action/Observation N times) | |||
| Thought: I know what to respond | |||
| Action: | |||
| \`\`\` | |||
| { | |||
| "{{TOOL_NAME_KEY}}": "Final Answer", | |||
| "{{ACTION_INPUT_KEY}}": "Final response to human" | |||
| } | |||
| \`\`\` | |||
| \`\`\` | |||
| { | |||
| "{{TOOL_NAME_KEY}}": $TOOL_NAME, | |||
| "{{ACTION_INPUT_KEY}}": $ACTION_INPUT | |||
| } | |||
| \`\`\` | |||
| Follow this format: | |||
| 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:.`, | |||
| Question: input question to answer | |||
| Thought: consider previous and subsequent steps | |||
| Action: | |||
| \`\`\` | |||
| $JSON_BLOB | |||
| \`\`\` | |||
| Observation: action result | |||
| ... (repeat Thought/Action/Observation N times) | |||
| Thought: I know what to respond | |||
| Action: | |||
| \`\`\` | |||
| { | |||
| "{{TOOL_NAME_KEY}}": "Final Answer", | |||
| "{{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:.`, | |||
| completion: ` | |||
| Respond to the human as helpfully and accurately as possible. | |||
| Respond to the human as helpfully and accurately as possible. | |||
| {{instruction}} | |||
| @@ -285,3 +285,12 @@ export const ENABLE_WEBSITE_WATERCRAWL = getBooleanConfig(process.env.NEXT_PUBLI | |||
| export const VALUE_SELECTOR_DELIMITER = '@@@' | |||
| 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 MaintenanceNotice from '@/app/components/header/maintenance-notice' | |||
| import { noop } from 'lodash-es' | |||
| import { setZendeskConversationFields } from '@/app/components/base/zendesk/utils' | |||
| import { ZENDESK_FIELD_IDS } from '@/config' | |||
| export type AppContextValue = { | |||
| userProfile: UserProfileResponse | |||
| @@ -115,6 +117,44 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) => | |||
| setCurrentWorkspace(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 ( | |||
| <AppContext.Provider value={{ | |||
| userProfile, | |||
| @@ -27,6 +27,8 @@ import { | |||
| useEducationStatus, | |||
| } from '@/service/use-education' | |||
| import { noop } from 'lodash-es' | |||
| import { setZendeskConversationFields } from '@/app/components/base/zendesk/utils' | |||
| import { ZENDESK_FIELD_IDS } from '@/config' | |||
| type ProviderContextState = { | |||
| modelProviders: ModelProvider[] | |||
| @@ -189,6 +191,17 @@ export const ProviderContextProvider = ({ | |||
| 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() | |||
| useEffect(() => { | |||
| 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_FIRECRAWL = 'data-public-enable-website-firecrawl', | |||
| 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', | |||
| } | |||