-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Expand file tree
/
Copy pathchat.py
More file actions
275 lines (240 loc) · 11.1 KB
/
Copy pathchat.py
File metadata and controls
275 lines (240 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: chat.py
@date:2025/6/6 11:18
@desc:
"""
import requests
from django.http import HttpResponse, StreamingHttpResponse
from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema
from rest_framework.parsers import MultiPartParser
from rest_framework.request import Request
from rest_framework.views import APIView
from application.api.application_api import SpeechToTextAPI, TextToSpeechAPI
from application.models import ChatUserType, ChatSourceChoices
from chat.api.chat_api import ChatAPI
from chat.api.chat_authentication_api import ChatAuthenticationAPI, ChatAuthenticationProfileAPI, ChatOpenAPI, OpenAIAPI
from chat.serializers.chat import OpenChatSerializers, ChatSerializers, SpeechToTextSerializers, \
TextToSpeechSerializers, OpenAIChatSerializer
from chat.serializers.chat_authentication import AnonymousAuthenticationSerializer, ApplicationProfileSerializer, \
AuthProfileSerializer
from common.auth import ChatTokenAuth
from common.constants.permission_constants import ChatAuth
from common.exception.app_exception import AppAuthenticationFailed
from common.log.log import _get_ip_address
from common.result import result
from knowledge.models import FileSourceType
from oss.serializers.file import FileSerializer
from users.api import CaptchaAPI
from users.serializers.login import CaptchaSerializer
def stream_image(response):
"""生成器函数,用于流式传输图片数据"""
for chunk in response.iter_content(chunk_size=4096):
if chunk: # 过滤掉保持连接的空块
yield chunk
class ResourceProxy(APIView):
def get(self, request: Request):
image_url = request.query_params.get("url")
if not image_url:
return result.error("Missing 'url' parameter")
try:
# 发送GET请求,流式获取图片内容
response = requests.get(
image_url,
stream=True, # 启用流式响应
allow_redirects=True,
timeout=10
)
response.raise_for_status()
content_type = response.headers.get('Content-Type', '').split(';')[0]
# 创建Django流式响应
django_response = StreamingHttpResponse(
stream_image(response), # 使用生成器
content_type=content_type
)
return django_response
except Exception as e:
return result.error(f"Image request failed: {str(e)}")
class OpenAIView(APIView):
authentication_classes = [ChatTokenAuth]
@extend_schema(
methods=['POST'],
description=_('OpenAI Interface Dialogue'),
summary=_('OpenAI Interface Dialogue'),
operation_id=_('OpenAI Interface Dialogue'), # type: ignore
request=OpenAIAPI.get_request(),
responses=None,
tags=[_('Chat')] # type: ignore
)
def post(self, request: Request, application_id: str):
ip_address = _get_ip_address(request)
if application_id != str(request.auth.application_id):
raise AppAuthenticationFailed(500, _('Secret key is invalid'))
return OpenAIChatSerializer(
data={'application_id': application_id, 'chat_user_id': request.auth.chat_user_id,
'chat_user_type': request.auth.chat_user_type,
'ip_address': ip_address,
'source': {"type": ChatSourceChoices.API_CALL.value}}).chat(request.data)
class AnonymousAuthentication(APIView):
def options(self, request, *args, **kwargs):
return HttpResponse(
headers={"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Methods": "POST",
"Access-Control-Allow-Headers": "Origin,Content-Type,Cookie,Accept,Token"}, )
@extend_schema(
methods=['POST'],
description=_('Application Anonymous Certification'),
summary=_('Application Anonymous Certification'),
operation_id=_('Application Anonymous Certification'), # type: ignore
request=ChatAuthenticationAPI.get_request(),
responses=None,
tags=[_('Chat')] # type: ignore
)
def post(self, request: Request):
return result.success(
AnonymousAuthenticationSerializer(data={'access_token': request.data.get("access_token")}).auth(
request),
headers={"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Methods": "POST",
"Access-Control-Allow-Headers": "Origin,Content-Type,Cookie,Accept,Token"}
)
class ApplicationProfile(APIView):
authentication_classes = [ChatTokenAuth]
@extend_schema(
methods=['GET'],
description=_("Get application related information"),
summary=_("Get application related information"),
operation_id=_("Get application related information"), # type: ignore
request=None,
responses=None,
tags=[_('Chat')] # type: ignore
)
def get(self, request: Request):
if isinstance(request.auth, ChatAuth):
return result.success(ApplicationProfileSerializer(
data={'application_id': request.auth.application_id}).profile())
raise AppAuthenticationFailed(401, "身份异常")
class AuthProfile(APIView):
@extend_schema(
methods=['GET'],
description=_("Get application authentication information"),
summary=_("Get application authentication information"),
operation_id=_("Get application authentication information"), # type: ignore
parameters=ChatAuthenticationProfileAPI.get_parameters(),
responses=None,
tags=[_('Chat')] # type: ignore
)
def get(self, request: Request):
return result.success(
AuthProfileSerializer(data={'access_token': request.query_params.get("access_token")}).profile())
class ChatView(APIView):
authentication_classes = [ChatTokenAuth]
@extend_schema(
methods=['POST'],
description=_("dialogue"),
summary=_("dialogue"),
operation_id=_("dialogue"), # type: ignore
request=ChatAPI.get_request(),
parameters=ChatAPI.get_parameters(),
responses=None,
tags=[_('Chat')] # type: ignore
)
def post(self, request: Request, chat_id: str):
ip_address = _get_ip_address(request)
return ChatSerializers(data={'chat_id': chat_id,
'chat_user_id': request.auth.chat_user_id,
'chat_user_type': request.auth.chat_user_type,
'application_id': request.auth.application_id,
'debug': False,
'ip_address': ip_address,
'source': {
'type': ChatSourceChoices.API_CALL.value if request.auth.chat_user_type == ChatUserType.APPLICATION_API_KEY.value else ChatSourceChoices.ONLINE.value}
}
).chat(request.data)
class OpenView(APIView):
authentication_classes = [ChatTokenAuth]
@extend_schema(
methods=['GET'],
description=_("Get the session id according to the application id"),
summary=_("Get the session id according to the application id"),
operation_id=_("Get the session id according to the application id"), # type: ignore
parameters=ChatOpenAPI.get_parameters(),
responses=None,
tags=[_('Chat')] # type: ignore
)
def get(self, request: Request):
ip_address = _get_ip_address(request)
return result.success(OpenChatSerializers(
data={'application_id': request.auth.application_id,
'chat_user_id': request.auth.chat_user_id, 'chat_user_type': request.auth.chat_user_type,
'ip_address': ip_address,
'source': {
'type': ChatSourceChoices.API_CALL.value if request.auth.chat_user_type == ChatUserType.APPLICATION_API_KEY.value else ChatSourceChoices.ONLINE.value},
'debug': False}).open())
class CaptchaView(APIView):
@extend_schema(methods=['GET'],
summary=_("Get Chat captcha"),
description=_("Get Chat captcha"),
operation_id=_("Get Chat captcha"), # type: ignore
tags=[_("Chat")], # type: ignore
responses=CaptchaAPI.get_response())
def get(self, request: Request):
username = request.query_params.get('username', None)
accessToken = request.query_params.get('accessToken', None)
return result.success(CaptchaSerializer().chat_generate(username, 'chat', accessToken))
class SpeechToText(APIView):
authentication_classes = [ChatTokenAuth]
@extend_schema(
methods=['POST'],
description=_("speech to text"),
summary=_("speech to text"),
operation_id=_("speech to text"), # type: ignore
request=SpeechToTextAPI.get_request(),
responses=SpeechToTextAPI.get_response(),
tags=[_('Chat')] # type: ignore
)
def post(self, request: Request):
return result.success(
SpeechToTextSerializers(
data={'application_id': request.auth.application_id})
.speech_to_text({'file': request.FILES.get('file')}))
class TextToSpeech(APIView):
authentication_classes = [ChatTokenAuth]
@extend_schema(
methods=['POST'],
description=_("text to speech"),
summary=_("text to speech"),
operation_id=_("text to speech"), # type: ignore
request=TextToSpeechAPI.get_request(),
responses=TextToSpeechAPI.get_response(),
tags=[_('Chat')] # type: ignore
)
def post(self, request: Request):
byte_data = TextToSpeechSerializers(
data={'application_id': request.auth.application_id}).text_to_speech(request.data)
return HttpResponse(byte_data, status=200, headers={'Content-Type': 'audio/mp3',
'Content-Disposition': 'attachment; filename="abc.mp3"'})
class UploadFile(APIView):
authentication_classes = [ChatTokenAuth]
parser_classes = [MultiPartParser]
@extend_schema(
methods=['POST'],
description=_("Upload files"),
summary=_("Upload files"),
operation_id=_("Upload files"), # type: ignore
request=TextToSpeechAPI.get_request(),
responses=TextToSpeechAPI.get_response(),
tags=[_('Application')] # type: ignore
)
def post(self, request: Request, chat_id: str):
files = request.FILES.getlist('file')
file_ids = []
meta = {}
for file in files:
file_url = FileSerializer(
data={'file': file, 'meta': meta, 'source_id': chat_id, 'source_type': FileSourceType.CHAT, }).upload()
file_ids.append({'name': file.name, 'url': file_url, 'file_id': file_url.split('/')[-1]})
return result.success(file_ids)