@@ -34,17 +34,68 @@ function wrapPromise<T>(func: promiseFunc<T>, time = 1000) {
3434 */
3535async function markdownToHtml ( s : string ) : Promise < string > {
3636 marked . setOptions ( marked . getDefaults ( ) ) ;
37- const parsed = await marked . parse ( s ) as string | { toString ( ) : string } ;
37+ const parsed = ( await marked . parse ( s ) ) as string | { toString ( ) : string } ;
3838 const parsedString = typeof parsed === 'string' ? parsed : parsed . toString ( ) ;
3939 const tagsToRemove = [ 'p' , 'ol' , 'ul' , 'li' , 'h1' , 'h2' , 'h3' ] ;
4040 const tagPattern = new RegExp ( tagsToRemove . map ( ( tag ) => `<${ tag } >|</${ tag } >` ) . join ( '|' ) , 'g' ) ;
4141 return parsedString . replace ( tagPattern , '' ) ;
4242}
4343
44+ /**
45+ * Stream AI response and send periodic updates via bot.streamReply
46+ * @param bot - the telegram execution context
47+ * @param env - the environment
48+ * @param model - the AI model to use
49+ * @param messages - the messages to send
50+ * @returns the full response string
51+ */
52+ async function streamAiResponse (
53+ bot : TelegramExecutionContext ,
54+ env : Environment ,
55+ model : string ,
56+ messages : { role : string ; content : string } [ ] ,
57+ ) : Promise < string > {
58+ // @ts -expect-error broken bindings
59+ const response = ( await env . AI . run ( model , {
60+ messages,
61+ stream : true ,
62+ } ) ) as ReadableStream ;
63+
64+ const reader = response . getReader ( ) ;
65+ const decoder = new TextDecoder ( ) ;
66+ let fullResponse = '' ;
67+ let lastUpdate = Date . now ( ) ;
68+
69+ while ( true ) {
70+ const { done, value } = await reader . read ( ) ;
71+ if ( done ) break ;
72+
73+ const chunk = decoder . decode ( value ) ;
74+ const lines = chunk . split ( '\n' ) ;
75+
76+ for ( const line of lines ) {
77+ if ( line . startsWith ( 'data: ' ) && line !== 'data: [DONE]' ) {
78+ try {
79+ const data = JSON . parse ( line . slice ( 6 ) ) as { response : string } ;
80+ fullResponse += data . response ;
81+
82+ if ( Date . now ( ) - lastUpdate > 5000 ) {
83+ await bot . streamReply ( await markdownToHtml ( fullResponse ) , 'HTML' ) ;
84+ lastUpdate = Date . now ( ) ;
85+ }
86+ } catch ( e ) {
87+ console . error ( 'Error parsing AI stream:' , e ) ;
88+ }
89+ }
90+ }
91+ }
92+ return fullResponse ;
93+ }
94+
4495// Constants for system prompts
4596const SYSTEM_PROMPTS = {
4697 TUX_ROBOT : 'You are a friendly assistant named TuxRobot. Use lots of emojis in your responses.' ,
47- SEAN : 'You are a friendly person named Sean. Sometimes just acknowledge messages with okay. You are working on coding a cool telegram bot. You are 26 years old and from Toronto, Canada. ' ,
98+ SEAN : 'You are a friendly person named Sean. Sometimes just acknowledge messages with okay. You are working on coding a cool telegram bot.' ,
4899} ;
49100
50101// AI model constants
@@ -122,7 +173,7 @@ export default {
122173 . on ( ':message' , async ( bot : TelegramExecutionContext ) => {
123174 switch ( bot . update_type ) {
124175 case 'message' : {
125- await bot . sendTyping ( ) ;
176+ // await bot.sendTyping();
126177 const prompt = bot . update . message ?. text ?. toString ( ) ?? '' ;
127178
128179 const { results } = await env . DB . prepare ( 'SELECT * FROM Messages WHERE userId=?' )
@@ -138,25 +189,13 @@ export default {
138189
139190 try {
140191 console . log ( 'Processing text message:' , prompt ) ;
141- // @ts -expect-error broken bindings
142- const response = await env . AI . run ( AI_MODELS . LLAMA , { messages } ) ;
192+ const response = await streamAiResponse ( bot , env , AI_MODELS . LLAMA , messages ) ;
143193
144- if ( 'response' in response && response . response ) {
145- await bot . reply (
146- await markdownToHtml (
147- typeof response . response === 'string'
148- ? response . response
149- : JSON . stringify ( response . response )
150- ) ,
151- 'HTML'
152- ) ;
194+ if ( response ) {
195+ await bot . reply ( await markdownToHtml ( response ) , 'HTML' ) ;
153196
154197 await env . DB . prepare ( 'INSERT INTO Messages (id, userId, content) VALUES (?, ?, ?)' )
155- . bind (
156- crypto . randomUUID ( ) ,
157- bot . update . message ?. from . id ,
158- `'[INST] ${ prompt } [/INST] \n ${ typeof response . response === 'string' ? response . response : JSON . stringify ( response . response ) } '`
159- )
198+ . bind ( crypto . randomUUID ( ) , bot . update . message ?. from . id , `'[INST] ${ prompt } [/INST] \n ${ response } '` )
160199 . run ( ) ;
161200 }
162201 } catch ( e ) {
0 commit comments