18
18
import queue
19
19
import threading
20
20
import time
21
+ import uuid
21
22
22
23
import openai
23
24
24
25
import Authenticator
25
26
import RequestResponseContainer
27
+ from JSONReaderWriter import load_json , save_json
26
28
27
29
EMPTY_RESPONSE_ERROR_MESSAGE = 'Empty response or unhandled error!'
28
30
ERROR_CHATGPT_DISABLED = 'ChatGPT module is disabled in settings.json'
29
31
ERROR_DALLE_DISABLED = 'DALL-E module is disabled in settings.json'
30
32
31
33
32
34
class AIHandler :
33
- def __init__ (self , settings , authenticator ):
35
+ def __init__ (self , settings , chats_file , authenticator ):
34
36
self .settings = settings
37
+ self .chats_file = chats_file
35
38
self .authenticator = authenticator
36
39
37
40
# Loop running flag
@@ -46,10 +49,6 @@ def __init__(self, settings, authenticator):
46
49
# Requests queue
47
50
self .requests_queue = None
48
51
49
- # Conversation id and parent id to continue dialog
50
- self .conversation_id = None
51
- self .parent_id = None
52
-
53
52
# Check settings
54
53
if self .settings is not None :
55
54
# Initialize queue
@@ -68,6 +67,63 @@ def thread_start(self):
68
67
thread .start ()
69
68
logging .info ('AIHandler thread: ' + thread .name )
70
69
70
+ def get_chat (self , chat_id : int ):
71
+ """
72
+ Retrieves conversation_id and parent_id for given chat_id or None if not exists
73
+ :param chat_id:
74
+ :return: (conversation_id, parent_id)
75
+ """
76
+ logging .info ('Loading conversation_id for chat_id ' + str (chat_id ))
77
+ chats = load_json (self .chats_file )
78
+ if chats is not None and str (chat_id ) in chats :
79
+ chat = chats [str (chat_id )]
80
+ conversation_id = None
81
+ parent_id = None
82
+ if 'conversation_id' in chat :
83
+ conversation_id = chat ['conversation_id' ]
84
+ if 'parent_id' in chat :
85
+ parent_id = chat ['parent_id' ]
86
+
87
+ return conversation_id , parent_id
88
+ else :
89
+ return None , None
90
+
91
+ def set_chat (self , chat_id : int , conversation_id = None , parent_id = None ):
92
+ """
93
+ Saves conversation ID and parent ID or Nones to remove it
94
+ :param chat_id:
95
+ :param conversation_id:
96
+ :param parent_id:
97
+ :return:
98
+ """
99
+ logging .info ('Saving conversation_id ' + str (conversation_id ) + ' and parent_id '
100
+ + str (parent_id ) + ' for chat_id ' + str (chat_id ))
101
+ chats = load_json (self .chats_file )
102
+ if chats is not None :
103
+ if str (chat_id ) in chats :
104
+ # Save or delete conversation_id
105
+ if conversation_id is not None and len (conversation_id ) > 0 :
106
+ chats [str (chat_id )]['conversation_id' ] = conversation_id
107
+ elif 'conversation_id' in chats [str (chat_id )]:
108
+ del chats [str (chat_id )]['conversation_id' ]
109
+
110
+ # Save or delete parent_id
111
+ if parent_id is not None and len (parent_id ) > 0 :
112
+ chats [str (chat_id )]['parent_id' ] = parent_id
113
+ elif 'parent_id' in chats [str (chat_id )]:
114
+ del chats [str (chat_id )]['parent_id' ]
115
+
116
+ # New chat
117
+ else :
118
+ chats [str (chat_id )] = {}
119
+ if conversation_id is not None and len (conversation_id ) > 0 :
120
+ chats [str (chat_id )]['conversation_id' ] = conversation_id
121
+ if parent_id is not None and len (parent_id ) > 0 :
122
+ chats [str (chat_id )]['parent_id' ] = parent_id
123
+ else :
124
+ chats = {}
125
+ save_json (self .chats_file , chats )
126
+
71
127
def gpt_loop (self ):
72
128
"""
73
129
Background loop for handling requests
@@ -99,25 +155,33 @@ def gpt_loop(self):
99
155
100
156
# API type 0
101
157
if self .authenticator .api_type == 0 :
102
- # Initialize conversation id
103
- if len (str (self .settings ['chatgpt_api_0' ]['existing_conversation_id' ])) > 0 :
104
- self .conversation_id = str (self .settings ['chatgpt_api_0' ]['existing_conversation_id' ])
105
- logging .info ('Conversation id: ' + str (self .conversation_id ))
106
- else :
107
- self .conversation_id = None
158
+ # Get conversation_id
159
+ conversation_id , parent_id = self .get_chat (container .chat_id )
108
160
109
161
# Get chatbot from Authenticator class
110
162
chatbot = self .authenticator .chatbot
111
163
164
+ # Reset chat
165
+ chatbot .reset ()
166
+
112
167
# Ask
113
- for data in chatbot .ask_stream (str (container .request ), conversation_id = self . conversation_id ):
168
+ for data in chatbot .ask_stream (str (container .request ), conversation_id = conversation_id ):
114
169
# Initialize response
115
170
if api_response is None :
116
171
api_response = ''
117
172
118
173
# Append response
119
174
api_response += str (data )
120
175
176
+ # Generate and save conversation ID
177
+ try :
178
+ if conversation_id is None :
179
+ conversation_id = str (uuid .uuid4 ())
180
+ chatbot .save_conversation (conversation_id )
181
+ self .set_chat (container .chat_id , conversation_id , parent_id )
182
+ except Exception as e :
183
+ logging .warning ('Error saving conversation! ' + str (e ))
184
+
121
185
# Remove tags
122
186
api_response = api_response .replace ('<|im_end|>' , '' ).replace ('<|im_start|>' , '' )
123
187
@@ -140,34 +204,36 @@ def gpt_loop(self):
140
204
# Lock chatbot
141
205
self .authenticator .chatbot_locked = True
142
206
207
+ # Get conversation_id and parent_id
208
+ conversation_id , parent_id = self .get_chat (container .chat_id )
209
+
143
210
# Log request
144
- logging .info ('Asking: ' + str (container .request ))
145
-
146
- # Initialize conversation_id and parent_id
147
- if self .conversation_id is None :
148
- if len (str (self .settings ['chatgpt_api_1' ]['chatgpt_dialog' ]['conversation_id' ])) > 0 :
149
- self .conversation_id \
150
- = str (self .settings ['chatgpt_api_1' ]['chatgpt_dialog' ]['conversation_id' ])
151
- logging .info ('Initial conversation id: ' + str (self .conversation_id ))
152
- if self .parent_id is None :
153
- if len (str (self .settings ['chatgpt_api_1' ]['chatgpt_dialog' ]['parent_id' ])) > 0 :
154
- self .parent_id = str (self .settings ['chatgpt_api_1' ]['chatgpt_dialog' ]['parent_id' ])
155
- logging .info ('Initial parent id: ' + str (self .parent_id ))
211
+ logging .info ('Asking: ' + str (container .request )
212
+ + ', conversation_id: ' + str (conversation_id ) + ', parent_id: ' + str (parent_id ))
213
+
214
+ # Reset chat
215
+ chatbot .reset_chat ()
156
216
157
217
# Ask
158
218
for data in chatbot .ask (str (container .request ),
159
- conversation_id = self . conversation_id ,
160
- parent_id = self . parent_id ):
219
+ conversation_id = conversation_id ,
220
+ parent_id = parent_id ):
161
221
# Get last response
162
222
api_response = data ['message' ]
163
223
164
224
# Store conversation_id
165
- if data ['conversation_id' ] is not None :
166
- self .conversation_id = data ['conversation_id' ]
225
+ if 'conversation_id' in data and data ['conversation_id' ] is not None :
226
+ conversation_id = data ['conversation_id' ]
227
+
228
+ # Store parent_id
229
+ if 'parent_id' in data and data ['parent_id' ] is not None :
230
+ parent_id = data ['parent_id' ]
167
231
168
232
# Log conversation id and parent id
169
- logging .info ('Current conversation id: ' + str (self .conversation_id )
170
- + '\t Parent id: ' + str (self .parent_id ))
233
+ logging .info ('Current conversation_id: ' + conversation_id + ', parent_id: ' + parent_id )
234
+
235
+ # Save conversation id
236
+ self .set_chat (container .chat_id , conversation_id , parent_id )
171
237
172
238
# Wrong api type
173
239
else :
0 commit comments