@@ -103,65 +103,103 @@ async def output(self):
103
103
return await self .output_queue .async_q .get ()
104
104
105
105
def respond (self , run_code = None ):
106
- try :
107
- if run_code == None :
108
- run_code = self .auto_run
109
-
110
- for chunk_og in self ._respond_and_store ():
111
- chunk = (
112
- chunk_og .copy ()
113
- ) # This fixes weird double token chunks. Probably a deeper problem?
114
-
115
- if chunk ["type" ] == "confirmation" :
116
- if run_code :
117
- run_code = False
118
- continue
119
- else :
120
- break
121
-
122
- if self .stop_event .is_set ():
123
- return
106
+ for attempt in range (5 ): # 5 attempts
107
+ try :
108
+ if run_code == None :
109
+ run_code = self .auto_run
124
110
125
- if self .print :
126
- if "start" in chunk :
127
- print ("\n " )
128
- if chunk ["type" ] in ["code" , "console" ] and "format" in chunk :
129
- if "start" in chunk :
130
- print ("\n ------------\n \n ```" + chunk ["format" ], flush = True )
131
- if "end" in chunk :
132
- print ("\n ```\n \n ------------\n \n " , flush = True )
133
- if chunk .get ("format" ) != "active_line" :
134
- if "format" in chunk and "base64" in chunk ["format" ]:
135
- print ("\n [An image was produced]" )
136
- else :
137
- content = chunk .get ("content" , "" )
138
- content = (
139
- str (content ).encode ("ascii" , "ignore" ).decode ("ascii" )
140
- )
141
- print (content , end = "" , flush = True )
111
+ sent_chunks = False
142
112
143
- if self .debug :
144
- print ("Interpreter produced this chunk:" , chunk )
113
+ for chunk_og in self ._respond_and_store ():
114
+ chunk = (
115
+ chunk_og .copy ()
116
+ ) # This fixes weird double token chunks. Probably a deeper problem?
145
117
146
- self .output_queue .sync_q .put (chunk )
118
+ if chunk ["type" ] == "confirmation" :
119
+ if run_code :
120
+ run_code = False
121
+ continue
122
+ else :
123
+ break
147
124
148
- self .output_queue .sync_q .put (complete_message )
125
+ if self .stop_event .is_set ():
126
+ return
149
127
150
- if self .print or self .debug :
151
- print ("\n Server response complete.\n " )
128
+ if self .print :
129
+ if "start" in chunk :
130
+ print ("\n " )
131
+ if chunk ["type" ] in ["code" , "console" ] and "format" in chunk :
132
+ if "start" in chunk :
133
+ print (
134
+ "\n ------------\n \n ```" + chunk ["format" ],
135
+ flush = True ,
136
+ )
137
+ if "end" in chunk :
138
+ print ("\n ```\n \n ------------\n \n " , flush = True )
139
+ if chunk .get ("format" ) != "active_line" :
140
+ if "format" in chunk and "base64" in chunk ["format" ]:
141
+ print ("\n [An image was produced]" )
142
+ else :
143
+ content = chunk .get ("content" , "" )
144
+ content = (
145
+ str (content )
146
+ .encode ("ascii" , "ignore" )
147
+ .decode ("ascii" )
148
+ )
149
+ print (content , end = "" , flush = True )
150
+
151
+ if self .debug :
152
+ print ("Interpreter produced this chunk:" , chunk )
153
+
154
+ self .output_queue .sync_q .put (chunk )
155
+ sent_chunks = True
156
+
157
+ if not sent_chunks :
158
+ print ("ERROR. NO CHUNKS SENT. TRYING AGAIN." )
159
+ print ("Messages:" , self .messages )
160
+ messages = [
161
+ "Hello? Answer please." ,
162
+ "Just say something, anything." ,
163
+ "Are you there?" ,
164
+ "Can you respond?" ,
165
+ "Please reply." ,
166
+ ]
167
+ self .messages .append (
168
+ {
169
+ "role" : "user" ,
170
+ "type" : "message" ,
171
+ "content" : messages [attempt % len (messages )],
172
+ }
173
+ )
174
+ time .sleep (1 )
175
+ else :
176
+ self .output_queue .sync_q .put (complete_message )
177
+ if self .debug :
178
+ print ("\n Server response complete.\n " )
179
+ return
152
180
153
- except Exception as e :
154
- error = traceback .format_exc () + "\n " + str (e )
155
- error_message = {
156
- "role" : "server" ,
157
- "type" : "error" ,
158
- "content" : traceback .format_exc () + "\n " + str (e ),
159
- }
160
- self .output_queue .sync_q .put (error_message )
161
- self .output_queue .sync_q .put (complete_message )
162
- print ("\n \n --- SENT ERROR: ---\n \n " )
163
- print (error )
164
- print ("\n \n --- (ERROR ABOVE WAS SENT) ---\n \n " )
181
+ except Exception as e :
182
+ error = traceback .format_exc () + "\n " + str (e )
183
+ error_message = {
184
+ "role" : "server" ,
185
+ "type" : "error" ,
186
+ "content" : traceback .format_exc () + "\n " + str (e ),
187
+ }
188
+ self .output_queue .sync_q .put (error_message )
189
+ self .output_queue .sync_q .put (complete_message )
190
+ print ("\n \n --- SENT ERROR: ---\n \n " )
191
+ print (error )
192
+ print ("\n \n --- (ERROR ABOVE WAS SENT) ---\n \n " )
193
+ return
194
+
195
+ error_message = {
196
+ "role" : "server" ,
197
+ "type" : "error" ,
198
+ "content" : "No chunks sent or unknown error." ,
199
+ }
200
+ self .output_queue .sync_q .put (error_message )
201
+ self .output_queue .sync_q .put (complete_message )
202
+ raise Exception ("No chunks sent or unknown error." )
165
203
166
204
def accumulate (self , chunk ):
167
205
"""
@@ -678,29 +716,51 @@ class ChatCompletionRequest(BaseModel):
678
716
stream : Optional [bool ] = False
679
717
680
718
async def openai_compatible_generator ():
681
- for i , chunk in enumerate (async_interpreter ._respond_and_store ()):
682
- output_content = None
683
-
684
- if chunk ["type" ] == "message" and "content" in chunk :
685
- output_content = chunk ["content" ]
686
- if chunk ["type" ] == "code" and "start" in chunk :
687
- output_content = " "
688
-
689
- if output_content :
690
- await asyncio .sleep (0 )
691
- output_chunk = {
692
- "id" : i ,
693
- "object" : "chat.completion.chunk" ,
694
- "created" : time .time (),
695
- "model" : "open-interpreter" ,
696
- "choices" : [{"delta" : {"content" : output_content }}],
697
- }
698
- yield f"data: { json .dumps (output_chunk )} \n \n "
719
+ made_chunk = False
720
+
721
+ for message in [
722
+ "." ,
723
+ "Just say something, anything." ,
724
+ "Hello? Answer please." ,
725
+ "Are you there?" ,
726
+ "Can you respond?" ,
727
+ "Please reply." ,
728
+ ]:
729
+ for i , chunk in enumerate (
730
+ async_interpreter .chat (message = message , stream = True , display = True )
731
+ ):
732
+ made_chunk = True
733
+
734
+ if async_interpreter .stop_event .is_set ():
735
+ break
736
+
737
+ output_content = None
738
+
739
+ if chunk ["type" ] == "message" and "content" in chunk :
740
+ output_content = chunk ["content" ]
741
+ if chunk ["type" ] == "code" and "start" in chunk :
742
+ output_content = " "
743
+
744
+ if output_content :
745
+ await asyncio .sleep (0 )
746
+ output_chunk = {
747
+ "id" : i ,
748
+ "object" : "chat.completion.chunk" ,
749
+ "created" : time .time (),
750
+ "model" : "open-interpreter" ,
751
+ "choices" : [{"delta" : {"content" : output_content }}],
752
+ }
753
+ yield f"data: { json .dumps (output_chunk )} \n \n "
754
+
755
+ if made_chunk :
756
+ break
699
757
700
758
@router .post ("/openai/chat/completions" )
701
759
async def chat_completion (request : ChatCompletionRequest ):
702
760
# Convert to LMC
703
761
762
+ async_interpreter .stop_event .set ()
763
+
704
764
last_message = request .messages [- 1 ]
705
765
706
766
if last_message .role != "user" :
@@ -711,18 +771,26 @@ async def chat_completion(request: ChatCompletionRequest):
711
771
return
712
772
713
773
if type (last_message .content ) == str :
714
- async_interpreter .messages .append (last_message )
715
- if type (last_message .content ) == list :
774
+ async_interpreter .messages .append (
775
+ {
776
+ "role" : "user" ,
777
+ "type" : "message" ,
778
+ "content" : last_message .content ,
779
+ }
780
+ )
781
+ print (">" , last_message .content )
782
+ elif type (last_message .content ) == list :
716
783
for content in last_message .content :
717
784
if content ["type" ] == "text" :
718
785
async_interpreter .messages .append (
719
- {"role" : "user" , "type" : "message" , "content" : content }
786
+ {"role" : "user" , "type" : "message" , "content" : str ( content ) }
720
787
)
788
+ print (">" , content )
721
789
elif content ["type" ] == "image_url" :
722
790
if "url" not in content ["image_url" ]:
723
791
raise Exception ("`url` must be in `image_url`." )
724
792
url = content ["image_url" ]["url" ]
725
- print (url [:100 ])
793
+ print ("> [user sent an image]" , url [:100 ])
726
794
if "base64," not in url :
727
795
raise Exception (
728
796
'''Image must be in the format: "data:image/jpeg;base64,{base64_image}"'''
@@ -741,12 +809,21 @@ async def chat_completion(request: ChatCompletionRequest):
741
809
}
742
810
)
743
811
812
+ if os .getenv ("INTERPRETER_SERVER_REQUIRE_START" , False ):
813
+ if last_message .content != "{START}" :
814
+ return
815
+ if async_interpreter .messages [- 1 ]["content" ] == "{START}" :
816
+ # Remove that {START} message that would have just been added
817
+ async_interpreter .messages = async_interpreter .messages [:- 1 ]
818
+
819
+ async_interpreter .stop_event .clear ()
820
+
744
821
if request .stream :
745
822
return StreamingResponse (
746
823
openai_compatible_generator (), media_type = "application/x-ndjson"
747
824
)
748
825
else :
749
- messages = async_interpreter .chat (message = "" , stream = False , display = True )
826
+ messages = async_interpreter .chat (message = ". " , stream = False , display = True )
750
827
content = messages [- 1 ]["content" ]
751
828
return {
752
829
"id" : "200" ,
0 commit comments