55
66UPDATE_INTERVAL_SECONDS = 1
77DISCORD_CHAR_LIMIT = 4000
8- SAFE_SPLIT_LIMIT = 3980
8+ SAFE_SPLIT_LIMIT = 3900
99
1010
1111class LLMView (discord .ui .LayoutView ):
1212 def __init__ (self , model : str ):
13- super ().__init__ ()
13+ super ().__init__ (timeout = 300 )
1414 self .last_update_time = time .time ()
1515 self .start_time , self .first_token_time , self .end_time = time .time (), None , None
1616
1717 self .response_messages = []
1818 self .current_message_content = ""
1919 self .full_response = ""
2020 self .model = model
21+ self .current_page = 1
22+ self .message : discord .WebhookMessage | None = None
2123
2224 self .usage = None
2325 self .ttft , self .tps , self .completion_tokens = 0.0 , 0.0 , 0
@@ -57,23 +59,84 @@ def find_best_split_position(self, text: str, max_len: int) -> int:
5759 # 4. If all else fails, force a hard cut at the safe limit
5860 return max_len
5961
60- async def update_view (self , message : discord .WebhookMessage ):
61- self .clear_items ()
62- container = discord .ui .Container ()
62+ def refresh_item (self , old_item : discord .ui .Item , new_item : discord .ui .Item ):
63+ new_item ._update_view (self )
64+ self ._swap_item (old_item , new_item , "" )
65+ del old_item
66+
67+ def pagination_callback (self , current_page : int = 1 ):
68+ async def _callback (interaction : discord .Interaction ):
69+ total_pages = len (self .response_messages )
70+ new_page = current_page
71+
72+ if interaction .data ["custom_id" ] == "next" :
73+ new_page = min (current_page + 1 , total_pages )
74+ elif interaction .data ["custom_id" ] == "previous" :
75+ new_page = max (current_page - 1 , 1 )
76+
77+ self .current_page = new_page
78+ new_container = self .construct_container (new_page )
79+ self .refresh_item (self .container , new_container )
80+ self .container = new_container
81+
82+ await interaction .response .edit_message (view = self )
6383
64- for response in self .response_messages :
65- container .add_item (discord .ui .TextDisplay (response ))
84+ return _callback
6685
67- if not self .end_time :
86+ def construct_container (self , page : int = - 1 ):
87+ container = discord .ui .Container ()
88+ total_pages = len (self .response_messages )
89+
90+ # page -1 means show current streaming content only
91+ if page == - 1 :
6892 current_message = self .current_message_content + " █"
6993 container .add_item (discord .ui .TextDisplay (current_message ))
70- else :
94+ elif total_pages > 0 and 1 <= page <= total_pages :
95+ # Show only the specified page's content (1 response message per page)
96+ page_content = self .response_messages [page - 1 ]
97+ container .add_item (discord .ui .TextDisplay (page_content ))
98+
99+ # Footer with stats (only when finished)
100+ if self .end_time :
101+ container .add_item (
102+ discord .ui .Separator (spacing = discord .enums .SeparatorSpacing .small )
103+ )
71104 container .add_item (
72105 discord .ui .TextDisplay (
73106 f"-# { self .model } • { self .tps :.2f} tps • TTFT: { self .ttft :.2f} s • Tokens: { self .completion_tokens } "
74107 )
75108 )
76- self .add_item (container )
109+
110+ # Pagination controls (only when there are multiple pages and streaming is done)
111+ if self .end_time and total_pages > 1 :
112+ container .add_item (
113+ discord .ui .Separator (spacing = discord .enums .SeparatorSpacing .small )
114+ )
115+ footer = discord .ui .TextDisplay (f"-# Page { self .current_page } /{ total_pages } " )
116+ container .add_item (footer )
117+
118+ actionrow = discord .ui .ActionRow ()
119+ previous_button = discord .ui .Button (
120+ label = "Previous" , custom_id = "previous" , disabled = self .current_page <= 1
121+ )
122+ previous_button .callback = self .pagination_callback (self .current_page )
123+ actionrow .add_item (previous_button )
124+
125+ next_button = discord .ui .Button (
126+ label = "Next" , custom_id = "next" , disabled = self .current_page >= total_pages
127+ )
128+ next_button .callback = self .pagination_callback (self .current_page )
129+ actionrow .add_item (next_button )
130+
131+ container .add_item (actionrow )
132+
133+ return container
134+
135+ async def update_view (self , message : discord .WebhookMessage , page : int = - 1 ):
136+ self .message = message
137+ self .clear_items ()
138+ self .container = self .construct_container (page )
139+ self .add_item (self .container )
77140
78141 await message .edit (view = self )
79142
@@ -107,6 +170,7 @@ async def update_chunk(
107170 async def end_chunk (self , message : discord .WebhookMessage ):
108171 self .end_time = time .time ()
109172 self .response_messages .append (self .current_message_content )
173+ self .current_page = len (self .response_messages ) # Go to the last page
110174
111175 if self .usage :
112176 self .completion_tokens = self .usage .completion_tokens
@@ -117,4 +181,4 @@ async def end_chunk(self, message: discord.WebhookMessage):
117181 if generation_time > 0 and self .completion_tokens > 1 :
118182 self .tps = (self .completion_tokens - 1 ) / generation_time
119183
120- await self .update_view (message )
184+ await self .update_view (message , self . current_page )
0 commit comments