Skip to content

Commit 8f69c9b

Browse files
committed
feat: chat message ui
1 parent 11dfcd4 commit 8f69c9b

File tree

15 files changed

+268
-143
lines changed

15 files changed

+268
-143
lines changed

apps/chat/serializers/chat.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ def re_open_chat_work_flow(self, chat_id, application):
315315

316316

317317
class OpenChatSerializers(serializers.Serializer):
318-
workspace_id = serializers.CharField(required=True)
318+
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
319319
application_id = serializers.UUIDField(required=True)
320320
chat_user_id = serializers.CharField(required=True, label=_("Client id"))
321321
chat_user_type = serializers.CharField(required=True, label=_("Client Type"))
@@ -325,7 +325,10 @@ def is_valid(self, *, raise_exception=False):
325325
super().is_valid(raise_exception=True)
326326
workspace_id = self.data.get('workspace_id')
327327
application_id = self.data.get('application_id')
328-
if not QuerySet(Application).filter(id=application_id, workspace_id=workspace_id).exists():
328+
query_set = QuerySet(Application).filter(id=application_id)
329+
if workspace_id:
330+
query_set = query_set.filter(workspace_id=workspace_id)
331+
if not query_set.exists():
329332
raise AppApiException(500, gettext('Application does not exist'))
330333

331334
def open(self):

apps/chat/serializers/chat_authentication.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ def profile(self, with_valid=True):
126126
'user_avatar': application_setting.user_avatar,
127127
'show_user_avatar': application_setting.show_user_avatar,
128128
'float_location': application_setting.float_location}
129+
base_node = [node for node in ((application.work_flow or {}).get('nodes', []) or []) if
130+
node.get('id') == 'base-node']
129131
return {**ApplicationSerializerModel(application).data,
130132
'stt_model_id': application.stt_model_id,
131133
'tts_model_id': application.tts_model_id,
@@ -136,8 +138,7 @@ def profile(self, with_valid=True):
136138
'stt_autosend': application.stt_autosend,
137139
'file_upload_enable': application.file_upload_enable,
138140
'file_upload_setting': application.file_upload_setting,
139-
'work_flow': {'nodes': [node for node in ((application.work_flow or {}).get('nodes', []) or []) if
140-
node.get('id') == 'base-node']},
141+
'work_flow': {'nodes': base_node} if base_node else None,
141142
'show_source': application_access_token.show_source,
142143
'language': application_access_token.language,
143144
**application_setting_dict}

apps/chat/urls.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
app_name = 'chat'
66

77
urlpatterns = [
8-
path('chat/embed', views.ChatEmbedView.as_view()),
9-
path('application/anonymous_authentication', views.AnonymousAuthentication.as_view()),
10-
path('auth/profile', views.AuthProfile.as_view()),
11-
path('profile', views.ApplicationProfile.as_view()),
8+
path('embed', views.ChatEmbedView.as_view()),
9+
path('auth/anonymous', views.AnonymousAuthentication.as_view()),
10+
path('profile', views.AuthProfile.as_view()),
11+
path('application/profile', views.ApplicationProfile.as_view()),
1212
path('chat_message/<str:chat_id>', views.ChatView.as_view()),
13-
path('workspace/<str:workspace_id>/application/<str:application_id>/open', views.OpenView.as_view())
13+
path('open', views.OpenView.as_view())
1414
]

apps/chat/views/chat.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ def post(self, request: Request, chat_id: str):
100100
return ChatSerializers(data={'chat_id': chat_id,
101101
'chat_user_id': request.auth.chat_user_id,
102102
'chat_user_type': request.auth.chat_user_type,
103-
'application_id': request.auth.application_id}
103+
'application_id': request.auth.application_id,
104+
'debug': False}
104105
).chat(request.data)
105106

106107

@@ -116,7 +117,8 @@ class OpenView(APIView):
116117
responses=None,
117118
tags=[_('Chat')] # type: ignore
118119
)
119-
def get(self, request: Request, workspace_id: str, application_id: str):
120+
def get(self, request: Request):
120121
return result.success(OpenChatSerializers(
121-
data={'workspace_id': workspace_id, 'application_id': application_id,
122-
'chat_user_id': request.auth.chat_user_id, 'chat_user_type': request.auth.chat_user_type}).open())
122+
data={'application_id': request.auth.application_id,
123+
'chat_user_id': request.auth.chat_user_id, 'chat_user_type': request.auth.chat_user_type,
124+
'debug': False}).open())

ui/src/api/chat/chat.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
download,
1010
exportFile,
1111
} from '@/request/chat/index'
12-
12+
import { type ChatProfile } from '@/api/type/chat'
1313
import { type Ref } from 'vue'
1414

1515
const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/application'
@@ -20,11 +20,8 @@ const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/applicat
2020
* @param loading 加载器
2121
* @returns
2222
*/
23-
const open: (application_id: string, loading?: Ref<boolean>) => Promise<Result<string>> = (
24-
application_id,
25-
loading,
26-
) => {
27-
return get(`${prefix}/${application_id}/open`, {}, loading)
23+
const open: (loading?: Ref<boolean>) => Promise<Result<string>> = (loading) => {
24+
return get('/open', {}, loading)
2825
}
2926
/**
3027
* 对话
@@ -33,22 +30,38 @@ const open: (application_id: string, loading?: Ref<boolean>) => Promise<Result<s
3330
* data
3431
*/
3532
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
36-
return postStream(`/api/chat_message/${chat_id}`, data)
33+
return postStream(`/chat/api/chat_message/${chat_id}`, data)
3734
}
38-
const chatProfile: (assessToken: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
35+
const chatProfile: (assessToken: string, loading?: Ref<boolean>) => Promise<Result<ChatProfile>> = (
3936
assessToken,
4037
loading,
4138
) => {
42-
return get('/auth/profile', { access_token: assessToken }, loading)
39+
return get('/profile', { access_token: assessToken }, loading)
4340
}
44-
const applicationProfile: (assessToken: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
45-
assessToken,
46-
loading,
47-
) => {
48-
return get('/chat/api/profile')
41+
/**
42+
* 匿名认证
43+
* @param assessToken
44+
* @param loading
45+
* @returns
46+
*/
47+
const anonymousAuthentication: (
48+
assessToken: string,
49+
loading?: Ref<boolean>,
50+
) => Promise<Result<any>> = (assessToken, loading) => {
51+
return post('/auth/anonymous', { access_token: assessToken }, {}, loading)
52+
}
53+
/**
54+
* 获取应用相关信息
55+
* @param loading
56+
* @returns
57+
*/
58+
const applicationProfile: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => {
59+
return get('/application/profile', {}, loading)
4960
}
5061
export default {
5162
open,
5263
chat,
5364
chatProfile,
65+
anonymousAuthentication,
66+
applicationProfile,
5467
}

ui/src/api/type/chat.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
interface ChatProfile {
2+
// 是否开启认证
3+
authentication: boolean
4+
// icon
5+
icon?: string
6+
// 应用名称
7+
application_name?: string
8+
// 背景图
9+
bg_icon?: string
10+
// 认证类型
11+
authentication_type?: 'password' | 'login'
12+
// 登录类型
13+
login_value?: Array<string>
14+
}
15+
export { type ChatProfile }

ui/src/components/ai-chat/index.vue

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@
8585
</div>
8686
</template>
8787
<script setup lang="ts">
88-
import { ref, nextTick, computed, watch, reactive, onMounted, onBeforeUnmount } from 'vue'
88+
import { type Ref, ref, nextTick, computed, watch, reactive, onMounted, onBeforeUnmount } from 'vue'
8989
import { useRoute } from 'vue-router'
9090
import applicationApi from '@/api/application/application'
91+
import chatAPI from '@/api/chat/chat'
9192
import chatLogApi from '@/api/application/chat-log'
9293
import { ChatManagement, type chatType } from '@/api/type/application'
9394
import { randomId } from '@/utils/utils'
@@ -280,23 +281,35 @@ const handleDebounceClick = debounce((val, other_params_data?: any, chat?: chatT
280281
*/
281282
const openChatId: () => Promise<string> = () => {
282283
const obj = props.applicationDetails
284+
return getOpenChatAPI()(obj.id)
285+
.then((res) => {
286+
chartOpenId.value = res.data
287+
return res.data
288+
})
289+
.catch((res) => {
290+
if (res.response.status === 403) {
291+
return application.asyncAppAuthentication(accessToken).then(() => {
292+
return openChatId()
293+
})
294+
}
295+
return Promise.reject(res)
296+
})
297+
}
298+
299+
const getChatMessageAPI = () => {
283300
if (props.type === 'debug-ai-chat') {
284-
return applicationApi
285-
.open(obj.id)
286-
.then((res) => {
287-
chartOpenId.value = res.data
288-
return res.data
289-
})
290-
.catch((res) => {
291-
if (res.response.status === 403) {
292-
return application.asyncAppAuthentication(accessToken).then(() => {
293-
return openChatId()
294-
})
295-
}
296-
return Promise.reject(res)
297-
})
301+
return applicationApi.chat
302+
} else {
303+
return chatAPI.chat
304+
}
305+
}
306+
const getOpenChatAPI = () => {
307+
if (props.type === 'debug-ai-chat') {
308+
return applicationApi.open
298309
} else {
299-
return Promise.reject('暂不支持')
310+
return (a?: string, loading?: Ref<boolean>) => {
311+
return chatAPI.open(loading)
312+
}
300313
}
301314
}
302315
/**
@@ -453,8 +466,7 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
453466
},
454467
}
455468
// 对话
456-
applicationApi
457-
.chat(chartOpenId.value, obj)
469+
getChatMessageAPI()(chartOpenId.value, obj)
458470
.then((response) => {
459471
if (response.status === 401) {
460472
application

ui/src/request/chat/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ instance.interceptors.request.use(
2323
if (config.headers === undefined) {
2424
config.headers = new AxiosHeaders()
2525
}
26-
const { user, login } = useStore()
27-
const token = login.getToken()
28-
const language = user.getLanguage()
29-
config.headers['Accept-Language'] = `${language}`
26+
const { chatUser } = useStore()
27+
const token = chatUser.getToken()
28+
// const language = chatUser.getLanguage()
29+
// config.headers['Accept-Language'] = `${language}`
3030
if (token) {
3131
config.headers['AUTHORIZATION'] = `Bearer ${token}`
3232
}
@@ -203,14 +203,14 @@ export const postStream: (url: string, data?: unknown) => Promise<Result<any> |
203203
url,
204204
data,
205205
) => {
206-
const { user, login } = useStore()
207-
const token = login.getToken()
208-
const language = user.getLanguage()
206+
const { chatUser } = useStore()
207+
const token = chatUser.getToken()
208+
// const language = user.getLanguage()
209209
const headers: HeadersInit = { 'Content-Type': 'application/json' }
210210
if (token) {
211211
headers['AUTHORIZATION'] = `Bearer ${token}`
212212
}
213-
headers['Accept-Language'] = `${language}`
213+
// headers['Accept-Language'] = `${language}`
214214
return fetch(url, {
215215
method: 'POST',
216216
body: data ? JSON.stringify(data) : undefined,

ui/src/router/chat/index.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,39 @@ const router = createRouter({
2020
router.beforeEach(
2121
async (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
2222
NProgress.start()
23-
if (to.name === '404') {
23+
if (to.path === '/404') {
2424
next()
2525
return
2626
}
27-
const { user, login } = useStore()
28-
29-
const notAuthRouteNameList = ['login', 'ForgotPassword', 'ResetPassword', 'Chat', 'UserLogin']
27+
const { chatUser } = useStore()
28+
const notAuthRouteNameList = ['UserLogin']
3029
if (!notAuthRouteNameList.includes(to.name ? to.name.toString() : '')) {
31-
if (to.query && to.query.token) {
32-
localStorage.setItem('token', to.query.token.toString())
33-
}
34-
const token = login.getToken()
35-
if (!token) {
30+
if (to.params && to.params.accessToken) {
31+
chatUser.setAccessToken(to.params.accessToken.toString())
32+
} else {
3633
next({
37-
path: '/login',
34+
path: '/404',
3835
})
3936
return
4037
}
41-
if (!user.userInfo) {
42-
await user.profile()
38+
const token = chatUser.getToken()
39+
const authentication = await chatUser.isAuthentication()
40+
if (authentication) {
41+
if (!token) {
42+
next({
43+
name: 'UserLogin',
44+
params: {
45+
accessToken: to.params.accessToken,
46+
},
47+
})
48+
return
49+
}
50+
} else {
51+
await chatUser.anonymousAuthentication()
52+
}
53+
54+
if (!chatUser.application) {
55+
await chatUser.applicationProfile()
4356
}
4457
}
4558
// 判断是否有菜单权限

ui/src/router/chat/routes.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ export const routes: Array<RouteRecordRaw> = [
44
// 对话
55
{
66
path: '/:accessToken',
7-
name: 'Chat',
7+
name: 'chat',
88
component: () => import('@/views/chat/index.vue'),
99
},
1010
// 对话用户登录
1111
{
1212
path: '/user-login/:accessToken',
13-
name: 'UserLogin',
13+
name: 'user_login',
1414
component: () => import('@/views/chat/user-login/index.vue'),
1515
},
16+
// 对话用户登录
17+
{
18+
path: '/404',
19+
name: '404',
20+
component: () => import('@/views/404/index.vue'),
21+
},
1622
]

ui/src/stores/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import useParagraphStore from './modules/paragraph'
1111
import useDocumentStore from './modules/document'
1212
import useApplicationStore from './modules/application'
1313
import useChatLogStore from './modules/chat-log'
14+
import useChatUserStore from './modules/chat-user'
1415
const useStore = () => ({
1516
common: useCommonStore(),
1617
login: useLoginStore(),
@@ -25,6 +26,7 @@ const useStore = () => ({
2526
document: useDocumentStore(),
2627
application: useApplicationStore(),
2728
chatLog: useChatLogStore(),
29+
chatUser: useChatUserStore(),
2830
})
2931

3032
export default useStore

0 commit comments

Comments
 (0)