mirror of
https://github.com/langgenius/webapp-conversation.git
synced 2025-12-08 17:32:27 +08:00
chore: enchance app config
This commit is contained in:
19
README.md
19
README.md
@ -1,11 +1,24 @@
|
||||
# Conversion Web App Template
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Set App Info
|
||||
Set app info in `config/index.ts`. Includes:
|
||||
## Config App
|
||||
Config app in `config/index.ts`.Please config:
|
||||
- APP_ID
|
||||
- API_KEY
|
||||
- APP_INFO
|
||||
|
||||
More config:
|
||||
```js
|
||||
export const APP_INFO: AppInfo = {
|
||||
"title": 'Chat APP',
|
||||
"description": '',
|
||||
"copyright": '',
|
||||
"privacy_policy": '',
|
||||
"default_language": 'zh-Hans'
|
||||
}
|
||||
|
||||
export const isShowPrompt = true
|
||||
export const promptTemplate = ''
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
First, install dependencies:
|
||||
|
||||
@ -9,26 +9,18 @@ import Toast from '@/app/components/base/toast'
|
||||
import Sidebar from '@/app/components/sidebar'
|
||||
import ConfigSence from '@/app/components/config-scence'
|
||||
import Header from '@/app/components/header'
|
||||
import { fetchAppInfo, fetchAppParams, fetchChatList, fetchConversations, sendChatMessage, updateFeedback } from '@/service'
|
||||
import type { ConversationItem, Feedbacktype, IChatItem, PromptConfig, SiteInfo } from '@/types/app'
|
||||
import { fetchAppParams, fetchChatList, fetchConversations, sendChatMessage, updateFeedback } from '@/service'
|
||||
import type { ConversationItem, Feedbacktype, IChatItem, PromptConfig, AppInfo } from '@/types/app'
|
||||
import Chat from '@/app/components/chat'
|
||||
import { setLocaleOnClient } from '@/i18n/client'
|
||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { replaceVarWithValues } from '@/utils/prompt'
|
||||
import AppUnavailable from '@/app/components/app-unavailable'
|
||||
import { APP_ID, API_KEY } from '@/config'
|
||||
import { APP_ID, API_KEY, APP_INFO, isShowPrompt, promptTemplate } from '@/config'
|
||||
|
||||
export type IMainProps = {
|
||||
params: {
|
||||
locale: string
|
||||
appId: string
|
||||
conversationId: string
|
||||
token: string
|
||||
}
|
||||
}
|
||||
|
||||
const Main: FC<IMainProps> = () => {
|
||||
const Main: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
@ -39,23 +31,16 @@ const Main: FC<IMainProps> = () => {
|
||||
*/
|
||||
const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
|
||||
const [isUnknwonReason, setIsUnknwonReason] = useState<boolean>(false)
|
||||
const [appId, setAppId] = useState<string>('')
|
||||
const [isPublicVersion, setIsPublicVersion] = useState<boolean>(true)
|
||||
const [siteInfo, setSiteInfo] = useState<SiteInfo | null>()
|
||||
const [promptConfig, setPromptConfig] = useState<PromptConfig | null>(null)
|
||||
const [inited, setInited] = useState<boolean>(false)
|
||||
const [plan, setPlan] = useState<string>('basic') // basic/plus/pro
|
||||
// in mobile, show sidebar by click button
|
||||
const [isShowSidebar, { setTrue: showSidebar, setFalse: hideSidebar }] = useBoolean(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (siteInfo?.title) {
|
||||
if (plan !== 'basic')
|
||||
document.title = `${siteInfo.title}`
|
||||
else
|
||||
document.title = `${siteInfo.title} - Powered by LangGenius`
|
||||
if (APP_INFO?.title) {
|
||||
document.title = `${APP_INFO.title} - Powered by LangGenius`
|
||||
}
|
||||
}, [siteInfo?.title, plan])
|
||||
}, [APP_INFO?.title])
|
||||
|
||||
/*
|
||||
* conversation info
|
||||
@ -97,11 +82,6 @@ const Main: FC<IMainProps> = () => {
|
||||
const handleConversationSwitch = () => {
|
||||
if (!inited)
|
||||
return
|
||||
if (!appId) {
|
||||
// wait for appId
|
||||
setTimeout(handleConversationSwitch, 100)
|
||||
return
|
||||
}
|
||||
|
||||
// update inputs of current conversation
|
||||
let notSyncToStateIntroduction = ''
|
||||
@ -160,7 +140,7 @@ const Main: FC<IMainProps> = () => {
|
||||
setConversationIdChangeBecauseOfNew(false)
|
||||
}
|
||||
// trigger handleConversationSwitch
|
||||
setCurrConversationId(id, appId)
|
||||
setCurrConversationId(id, APP_ID)
|
||||
hideSidebar()
|
||||
}
|
||||
|
||||
@ -203,7 +183,7 @@ const Main: FC<IMainProps> = () => {
|
||||
content: caculatedIntroduction,
|
||||
isAnswer: true,
|
||||
feedbackDisabled: true,
|
||||
isOpeningStatement: isPublicVersion,
|
||||
isOpeningStatement: isShowPrompt,
|
||||
}
|
||||
if (caculatedIntroduction)
|
||||
return [openstatement]
|
||||
@ -219,37 +199,30 @@ const Main: FC<IMainProps> = () => {
|
||||
}
|
||||
(async () => {
|
||||
try {
|
||||
const [appData, conversationData, appParams] = await Promise.all([fetchAppInfo(), fetchConversations(), fetchAppParams()])
|
||||
const { app_id: appId, site: siteInfo, prompt_config, plan }: any = appData
|
||||
setAppId(appId)
|
||||
setPlan(plan)
|
||||
const tempIsPublicVersion = !!prompt_config
|
||||
setIsPublicVersion(tempIsPublicVersion)
|
||||
const prompt_template = tempIsPublicVersion ? prompt_config.prompt_template : ''
|
||||
const [conversationData, appParams] = await Promise.all([fetchConversations(), fetchAppParams()])
|
||||
|
||||
// handle current conversation id
|
||||
const { data: conversations } = conversationData as { data: ConversationItem[] }
|
||||
const _conversationId = getConversationIdFromStorage(appId)
|
||||
const _conversationId = getConversationIdFromStorage(APP_ID)
|
||||
const isNotNewConversation = conversations.some(item => item.id === _conversationId)
|
||||
|
||||
// fetch new conversation info
|
||||
const { variables: prompt_variables, introduction }: any = appParams
|
||||
|
||||
setLocaleOnClient(siteInfo.default_language, true)
|
||||
setLocaleOnClient(APP_INFO.default_language, true)
|
||||
setNewConversationInfo({
|
||||
name: t('app.chat.newChatDefaultName'),
|
||||
introduction,
|
||||
})
|
||||
setSiteInfo(siteInfo as SiteInfo)
|
||||
setPromptConfig({
|
||||
prompt_template,
|
||||
prompt_template: promptTemplate,
|
||||
prompt_variables,
|
||||
} as PromptConfig)
|
||||
|
||||
setConversationList(conversations as ConversationItem[])
|
||||
|
||||
if (isNotNewConversation)
|
||||
setCurrConversationId(_conversationId, appId, false)
|
||||
setCurrConversationId(_conversationId, APP_ID, false)
|
||||
|
||||
setInited(true)
|
||||
}
|
||||
@ -355,7 +328,7 @@ const Main: FC<IMainProps> = () => {
|
||||
setConversationIdChangeBecauseOfNew(false)
|
||||
resetNewConversationInputs()
|
||||
setChatNotStarted()
|
||||
setCurrConversationId(tempNewConversationId, appId, true)
|
||||
setCurrConversationId(tempNewConversationId, APP_ID, true)
|
||||
},
|
||||
onError() {
|
||||
setResponsingFalse()
|
||||
@ -383,28 +356,28 @@ const Main: FC<IMainProps> = () => {
|
||||
}
|
||||
|
||||
const renderSidebar = () => {
|
||||
if (!appId || !siteInfo || !promptConfig)
|
||||
if (!APP_ID || !APP_INFO || !promptConfig)
|
||||
return null
|
||||
return (
|
||||
<Sidebar
|
||||
list={conversationList}
|
||||
onCurrentIdChange={handleConversationIdChange}
|
||||
currentId={currConversationId}
|
||||
copyRight={siteInfo.copyright || siteInfo.title}
|
||||
copyRight={APP_INFO.copyright || APP_INFO.title}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (appUnavailable)
|
||||
return <AppUnavailable isUnknwonReason={isUnknwonReason} errMessage={!hasSetAppConfig && 'Please set APP_ID and API_KEY in config/index.tsx'} />
|
||||
return <AppUnavailable isUnknwonReason={isUnknwonReason} errMessage={!hasSetAppConfig ? 'Please set APP_ID and API_KEY in config/index.tsx' : ''} />
|
||||
|
||||
if (!appId || !siteInfo || !promptConfig)
|
||||
if (!APP_ID || !APP_INFO || !promptConfig)
|
||||
return <Loading type='app' />
|
||||
|
||||
return (
|
||||
<div className='bg-gray-100'>
|
||||
<Header
|
||||
title={siteInfo.title}
|
||||
title={APP_INFO.title}
|
||||
isMobile={isMobile}
|
||||
onShowSideBar={showSidebar}
|
||||
onCreateNewChat={() => handleConversationIdChange('-1')}
|
||||
@ -427,14 +400,13 @@ const Main: FC<IMainProps> = () => {
|
||||
<ConfigSence
|
||||
conversationName={conversationName}
|
||||
hasSetInputs={hasSetInputs}
|
||||
isPublicVersion={isPublicVersion}
|
||||
siteInfo={siteInfo}
|
||||
isPublicVersion={isShowPrompt}
|
||||
siteInfo={APP_INFO}
|
||||
promptConfig={promptConfig}
|
||||
onStartChat={handleStartChat}
|
||||
canEidtInpus={canEditInpus}
|
||||
savedInputs={currInputs as Record<string, any>}
|
||||
onInputsChange={setCurrInputs}
|
||||
plan={plan}
|
||||
></ConfigSence>
|
||||
|
||||
{
|
||||
|
||||
@ -4,8 +4,8 @@ import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import TemplateVarPanel, { PanelTitle, VarOpBtnGroup } from '../value-panel'
|
||||
import s from './style.module.css'
|
||||
import { AppInfo, ChatBtn, EditBtn, FootLogo, PromptTemplate } from './massive-component'
|
||||
import type { PromptConfig, SiteInfo } from '@/types/app'
|
||||
import { AppInfoComp, ChatBtn, EditBtn, FootLogo, PromptTemplate } from './massive-component'
|
||||
import type { PromptConfig, AppInfo } from '@/types/app'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import Select from '@/app/components/base/select'
|
||||
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
||||
@ -17,13 +17,12 @@ export type IWelcomeProps = {
|
||||
conversationName: string
|
||||
hasSetInputs: boolean
|
||||
isPublicVersion: boolean
|
||||
siteInfo: SiteInfo
|
||||
siteInfo: AppInfo
|
||||
promptConfig: PromptConfig
|
||||
onStartChat: (inputs: Record<string, any>) => void
|
||||
canEidtInpus: boolean
|
||||
savedInputs: Record<string, any>
|
||||
onInputsChange: (inputs: Record<string, any>) => void
|
||||
plan: string
|
||||
}
|
||||
|
||||
const Welcome: FC<IWelcomeProps> = ({
|
||||
@ -31,7 +30,6 @@ const Welcome: FC<IWelcomeProps> = ({
|
||||
hasSetInputs,
|
||||
isPublicVersion,
|
||||
siteInfo,
|
||||
plan,
|
||||
promptConfig,
|
||||
onStartChat,
|
||||
canEidtInpus,
|
||||
@ -144,7 +142,7 @@ const Welcome: FC<IWelcomeProps> = ({
|
||||
if (isPublicVersion) {
|
||||
return (
|
||||
<div>
|
||||
<AppInfo siteInfo={siteInfo} />
|
||||
<AppInfoComp siteInfo={siteInfo} />
|
||||
<TemplateVarPanel
|
||||
isFold={false}
|
||||
header={
|
||||
@ -167,7 +165,7 @@ const Welcome: FC<IWelcomeProps> = ({
|
||||
<TemplateVarPanel
|
||||
isFold={false}
|
||||
header={
|
||||
<AppInfo siteInfo={siteInfo} />
|
||||
<AppInfoComp siteInfo={siteInfo} />
|
||||
}
|
||||
>
|
||||
<ChatBtn onClick={handleChat} />
|
||||
@ -180,7 +178,7 @@ const Welcome: FC<IWelcomeProps> = ({
|
||||
<TemplateVarPanel
|
||||
isFold={false}
|
||||
header={
|
||||
<AppInfo siteInfo={siteInfo} />
|
||||
<AppInfoComp siteInfo={siteInfo} />
|
||||
}
|
||||
>
|
||||
{renderInputs()}
|
||||
@ -325,10 +323,10 @@ const Welcome: FC<IWelcomeProps> = ({
|
||||
</div>
|
||||
: <div>
|
||||
</div>}
|
||||
{plan === 'basic' && <a className='flex items-center pr-3 space-x-3' href="https://langgenius.ai/" target="_blank">
|
||||
<a className='flex items-center pr-3 space-x-3' href="https://langgenius.ai/" target="_blank">
|
||||
<span className='uppercase'>{t('app.chat.powerBy')}</span>
|
||||
<FootLogo />
|
||||
</a>}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -7,10 +7,10 @@ import {
|
||||
PencilIcon,
|
||||
} from '@heroicons/react/24/solid'
|
||||
import s from './style.module.css'
|
||||
import type { SiteInfo } from '@/types/app'
|
||||
import type { AppInfo } from '@/types/app'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
export const AppInfo: FC<{ siteInfo: SiteInfo }> = ({ siteInfo }) => {
|
||||
export const AppInfoComp: FC<{ siteInfo: AppInfo }> = ({ siteInfo }) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
import { AppInfo } from "@/types/app"
|
||||
export const APP_ID = ''
|
||||
export const API_KEY = ''
|
||||
export const APP_INFO = {
|
||||
"app_id": APP_ID,
|
||||
"site": {
|
||||
"title": "Chat APP",
|
||||
"description": null,
|
||||
"copyright": null,
|
||||
"privacy_policy": null,
|
||||
"default_language": "zh-Hans",
|
||||
"prompt_public": true
|
||||
},
|
||||
"prompt_config": {
|
||||
"introduction": "Chat APP",
|
||||
"prompt_template": "{{a}}", "prompt_variables": [{ "key": "a", "name": "a", "type": "string", "max_length": 48 }], "completion_params": { "max_token": 256, "temperature": 1, "top_p": 1, "presence_penalty": 0, "frequency_penalty": 0 }
|
||||
}
|
||||
|
||||
export const APP_INFO: AppInfo = {
|
||||
"title": 'Chat APP',
|
||||
"description": '',
|
||||
"copyright": '',
|
||||
"privacy_policy": '',
|
||||
"default_language": 'zh-Hans'
|
||||
}
|
||||
|
||||
|
||||
export const isShowPrompt = false
|
||||
export const promptTemplate = 'I want you to act as a javascript console.'
|
||||
|
||||
export const API_PREFIX = '/api';
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ export type ConversationItem = {
|
||||
introduction: string,
|
||||
}
|
||||
|
||||
export type SiteInfo = {
|
||||
export type AppInfo = {
|
||||
title: string
|
||||
description: string
|
||||
default_language: Locale
|
||||
|
||||
Reference in New Issue
Block a user