@@ -832,7 +832,80 @@ async def disconnect(sid):
832832 # print(f"Unknown session ID {sid} disconnected")
833833
834834
835+ async def _make_channel_emitter (request_info ):
836+ """Event emitter that routes pipeline output to a channel message.
837+
838+ Translates chat:completion events into channel message:update socket
839+ emissions, throttled to avoid flooding with per-token updates.
840+ """
841+ channel_id = request_info ['chat_id' ].removeprefix ('channel:' )
842+ message_id = request_info ['message_id' ]
843+
844+ state = {'last_emit_at' : 0.0 }
845+ THROTTLE_INTERVAL = 0.15 # ~6 updates/sec
846+
847+ async def _emit_channel_update (content : str , done : bool = False ):
848+ from open_webui .models .messages import Messages , MessageForm
849+
850+ update_form = MessageForm (content = content )
851+ if done :
852+ # Merge done flag into existing meta (preserve model_id etc.)
853+ msg = await Messages .get_message_by_id (message_id )
854+ existing_meta = (msg .meta or {}) if msg else {}
855+ update_form = MessageForm (
856+ content = content ,
857+ meta = {** existing_meta , 'done' : True },
858+ )
859+
860+ await Messages .update_message_by_id (message_id , update_form )
861+ message = await Messages .get_message_by_id (message_id )
862+ if message :
863+ await sio .emit (
864+ 'events:channel' ,
865+ {
866+ 'channel_id' : channel_id ,
867+ 'message_id' : message_id ,
868+ 'data' : {
869+ 'type' : 'message:update' ,
870+ 'data' : message .model_dump (),
871+ },
872+ },
873+ to = f'channel:{ channel_id } ' ,
874+ )
875+
876+ async def __channel_emitter__ (event_data ):
877+ event_type = event_data .get ('type' )
878+
879+ if event_type == 'chat:completion' :
880+ data = event_data .get ('data' , {})
881+ content = data .get ('content' , '' )
882+ done = data .get ('done' , False )
883+
884+ if not content and not done :
885+ return
886+
887+ now = __import__ ('time' ).time ()
888+ if done or (now - state ['last_emit_at' ]) >= THROTTLE_INTERVAL :
889+ state ['last_emit_at' ] = now
890+ await _emit_channel_update (content , done )
891+
892+ elif event_type == 'chat:message:error' :
893+ error = event_data .get ('data' , {}).get ('error' , {})
894+ error_content = (
895+ error .get ('content' , 'An error occurred' )
896+ if isinstance (error , dict )
897+ else str (error )
898+ )
899+ await _emit_channel_update (f'Error: { error_content } ' , done = True )
900+
901+ return __channel_emitter__
902+
903+
835904async def get_event_emitter (request_info , update_db = True ):
905+ # Channel mode: route pipeline output to channel message updates
906+ if request_info .get ('chat_id' , '' ).startswith ('channel:' ):
907+ return await _make_channel_emitter (request_info )
908+
836909 async def __event_emitter__ (event_data ):
837910 user_id = request_info ['user_id' ]
838911 chat_id = request_info ['chat_id' ]
0 commit comments