@@ -24,11 +24,11 @@ namespace Microsoft.BotBuilderSamples
2424{
2525 public class AssistantBot < T > : StateManagementBot < T > where T : Dialog
2626 {
27- private string _aoaiModel ;
2827 private string _aoaiAssistant ;
2928 private readonly AOAIClient _aoaiClient ;
3029 private readonly string _welcomeMessage ;
3130 private readonly List < string > _suggestedQuestions ;
31+ private readonly string _appUrl ;
3232 private HttpClient client = new HttpClient ( ) ;
3333
3434 public AssistantBot (
@@ -39,12 +39,12 @@ public AssistantBot(
3939 T dialog ) :
4040 base ( config , conversationState , userState , dialog )
4141 {
42- _aoaiModel = config . GetValue < string > ( "AOAI_GPT_MODEL" ) ;
4342 _aoaiAssistant = config . GetValue < string > ( "AOAI_ASSISTANT_ID" ) ;
4443 _welcomeMessage = config . GetValue < string > ( "PROMPT_WELCOME_MESSAGE" ) ;
4544 _systemMessage = config . GetValue < string > ( "PROMPT_SYSTEM_MESSAGE" ) ;
46- _suggestedQuestions = System . Text . Json . JsonSerializer . Deserialize < List < string > > ( config . GetValue < string > ( "PROMPT_SUGGESTED_QUESTIONS" ) ) ;
45+ _suggestedQuestions = JsonSerializer . Deserialize < List < string > > ( config . GetValue < string > ( "PROMPT_SUGGESTED_QUESTIONS" ) ) ;
4746 _aoaiClient = aoaiClient ;
47+ _appUrl = config . GetValue ( "APP_URL" , "http://localhost:3978" ) ;
4848 }
4949
5050 protected override async Task OnMembersAddedAsync ( IList < ChannelAccount > membersAdded , ITurnContext < IConversationUpdateActivity > turnContext , CancellationToken cancellationToken )
@@ -62,7 +62,7 @@ await turnContext.SendActivityAsync(new Activity()
6262 } ) ;
6363 }
6464
65- public override async Task < string > ProcessMessage ( ConversationData conversationData , ITurnContext < IMessageActivity > turnContext )
65+ public override async Task < List < string > > ProcessMessage ( ConversationData conversationData , ITurnContext < IMessageActivity > turnContext )
6666 {
6767 await turnContext . SendActivityAsync ( new Activity ( type : "typing" ) ) ;
6868 if ( conversationData . ThreadId . IsNullOrEmpty ( ) )
@@ -83,7 +83,7 @@ public override async Task<string> ProcessMessage(ConversationData conversationD
8383 conversationData . ThreadId = null ;
8484 conversationData . History . Clear ( ) ;
8585 conversationData . Attachments . Clear ( ) ;
86- return $ "Thread { thread . Id } deleted.";
86+ return new List < string > { $ "Thread { thread . Id } deleted." } ;
8787 }
8888
8989 // Add user message to thread
@@ -101,134 +101,57 @@ public override async Task<string> ProcessMessage(ConversationData conversationD
101101 } ) ;
102102
103103 // Wait until run completes
104- while ( run . Status != "completed" )
104+ while ( run . Status != "completed" && run . Status != "failed" )
105105 {
106- Console . WriteLine ( JsonSerializer . Serialize ( run ) ) ;
107106 if ( run . Status == "requires_action" )
108107 {
109- var submitData = new ToolOutputData ( )
110- {
111- ToolOutputs = new ( )
112- } ;
113- foreach ( ToolCall toolcall in run . RequiredAction . SubmitToolOutputs . ToolCalls )
114- {
115- var arguments = System . Text . Json . JsonSerializer . Deserialize < Dictionary < string , object > > ( toolcall . Function . Arguments ) ;
116- string output = "" ;
117- switch ( toolcall . Function . Name )
118- {
119- case "get_wikipedia_content" :
120- output = await GetWikipediaContent ( conversationData , turnContext , arguments [ "page_title" ] . ToString ( ) ) ;
121- break ;
122- case "query_wikipedia" :
123- output = await QueryWikipedia ( conversationData , turnContext , arguments [ "query" ] . ToString ( ) ) ;
124- break ;
125- case "mslearn_query_articles" :
126- output = await MslearnQueryArticles ( conversationData , turnContext , arguments [ "query" ] . ToString ( ) ) ;
127- break ;
128- case "mslearn_get_article" :
129- output = await MslearnGetArticle ( conversationData , turnContext , arguments [ "page_url" ] . ToString ( ) ) ;
130- break ;
131- case "bot_show_image" :
132- output = await BotShowImage ( conversationData , turnContext , arguments [ "image_url" ] . ToString ( ) ) ;
133- break ;
134- default :
135- output = "Function not found" ;
136- break ;
137- }
138- var toolOutput = new ToolOutput
139- {
140- ToolCallId = toolcall . Id ,
141- Output = output
142- } ;
143- submitData . ToolOutputs . Add ( toolOutput ) ;
144- }
145-
108+ var tools = new Tools ( conversationData , turnContext ) ;
109+ var submitData = await tools . RunRequestedTools ( run ) ;
146110 await _aoaiClient . SubmitToolOutputs ( conversationData . ThreadId , run . Id , submitData ) ;
147111 }
148112 // await turnContext.SendActivityAsync($"The assistant is running...");
149113 System . Threading . Thread . Sleep ( 10000 ) ;
150114 run = await _aoaiClient . GetThreadRun ( conversationData . ThreadId , run . Id ) ;
151115 }
116+ if ( run . Status == "failed" ) {
117+ await turnContext . SendActivityAsync ( "Something went wrong when running the assistant." ) ;
118+ }
152119
153- // Send back first message
120+ // Send back all messages written by the assistant since the last user message
121+ var responses = new List < string > ( ) ;
154122 var messages = await _aoaiClient . ListThreadMessages ( conversationData . ThreadId ) ;
123+ var firstAssistantMessageIndex = messages . FindIndex ( x => x . Role == "user" ) - 1 ;
155124
156- return messages . First ( ) . Content . First ( ) . Text . Value ;
157- }
158- public async Task < string > BotShowImage ( ConversationData conversationData , ITurnContext < IMessageActivity > turnContext , string imageUrl )
159- {
160- List < object > images = new ( ) ;
161- images . Add ( new { type = "Image" , url = imageUrl } ) ;
162- object adaptiveCardJson = new
125+ for ( var i = firstAssistantMessageIndex ; i >= 0 ; i -- )
163126 {
164- type = "AdaptiveCard" ,
165- version = "1.0" ,
166- body = images
167- } ;
168-
169- var adaptiveCardAttachment = new Microsoft . Bot . Schema . Attachment ( )
170- {
171- ContentType = "application/vnd.microsoft.card.adaptive" ,
172- Content = adaptiveCardJson ,
173- } ;
174- await turnContext . SendActivityAsync ( MessageFactory . Attachment ( adaptiveCardAttachment ) ) ;
175- return "IMAGE SENT TO USER SUCCESSFULLY. DO NOT EMBED IT INTO YOUR RESPONSE." ;
176- }
177- public async Task < string > MslearnQueryArticles ( ConversationData conversationData , ITurnContext < IMessageActivity > turnContext , string query )
178- {
179- await turnContext . SendActivityAsync ( $ "Searching MS Learn for \" { query } \" ...") ;
180- HttpResponseMessage response = await client . GetAsync (
181- $ "https://learn.microsoft.com/api/search?search={ UrlEncoder . Default . Encode ( query ) } &locale=en-us&$top=3"
182- ) ;
183- if ( response . IsSuccessStatusCode )
184- return await response . Content . ReadAsStringAsync ( ) ;
185- else
186- return $ "FAILED TO FETCH DATA FROM API. STATUS CODE { response . StatusCode } ";
187- }
188- public async Task < string > MslearnGetArticle ( ConversationData conversationData , ITurnContext < IMessageActivity > turnContext , string pageUrl )
189- {
190- if ( ! pageUrl . StartsWith ( "https://learn.microsoft.com/" ) )
191- return "NOT ALLOWED TO FETCH DATA FROM API OUTSIDE OF LEARN.MICROSOFT.COM" ;
192- await turnContext . SendActivityAsync ( $ "Getting docs page \" { pageUrl } \" ...") ;
193-
194- var web = new HtmlWeb ( ) ;
195- var doc = web . Load ( pageUrl ) ;
196-
197- return doc . GetElementbyId ( "main-column" ) . InnerText ;
198- }
199- public async Task < string > QueryWikipedia ( ConversationData conversationData , ITurnContext < IMessageActivity > turnContext , string query )
200- {
201- await turnContext . SendActivityAsync ( $ "Searching Wikipedia for \" { query } \" ...") ;
202- HttpResponseMessage response = await client . GetAsync (
203- $ "https://en.wikipedia.org/w/api.php?action=opensearch&search={ UrlEncoder . Default . Encode ( query ) } &limit=1"
204- ) ;
205- if ( response . IsSuccessStatusCode )
206- return await response . Content . ReadAsStringAsync ( ) ;
207- else
208- return $ "FAILED TO FETCH DATA FROM API. STATUS CODE { response . StatusCode } ";
209- }
210- public async Task < string > GetWikipediaContent ( ConversationData conversationData , ITurnContext < IMessageActivity > turnContext , string pageTitle )
211- {
212- await turnContext . SendActivityAsync ( $ "Getting article \" { pageTitle } \" ...") ;
213- HttpResponseMessage response = await client . GetAsync (
214- $ "https://en.wikipedia.org/w/api.php?action=query&format=json&titles={ UrlEncoder . Default . Encode ( pageTitle ) } &prop=extracts&explaintext"
215- ) ;
216- if ( response . IsSuccessStatusCode )
217- return await response . Content . ReadAsStringAsync ( ) ;
218- else
219- return $ "FAILED TO FETCH DATA FROM API. STATUS CODE { response . StatusCode } ";
220-
221- }
127+ for ( var j = messages [ i ] . Content . Count ( ) - 1 ; j >= 0 ; j -- )
128+ {
129+ if ( messages [ i ] . Content [ j ] . Type == "text" )
130+ {
131+ responses . Add ( messages [ i ] . Content [ j ] . Text . Value ) ;
132+ await turnContext . SendActivityAsync ( messages [ i ] . Content [ j ] . Text . Value ) ;
133+ }
134+ if ( messages [ i ] . Content [ j ] . Type == "image_file" )
135+ {
136+ responses . Add ( $ "Image (ID: { messages [ i ] . Content [ j ] . ImageFile . FileId } )") ;
137+ List < object > images = [ new { type = "Image" , url = $ "{ _appUrl } /openai/files/{ messages [ i ] . Content [ j ] . ImageFile . FileId } /content" } ] ;
138+ object adaptiveCardJson = new
139+ {
140+ type = "AdaptiveCard" ,
141+ version = "1.0" ,
142+ body = images
143+ } ;
222144
223- class QueryWikipediaArguments
224- {
225- [ JsonPropertyName ( "query" ) ]
226- public string Query { get ; set ; }
227- }
228- class GetWikipediaContentArguments
229- {
230- [ JsonPropertyName ( "page_title" ) ]
231- public string PageTitle { get ; set ; }
145+ var adaptiveCardAttachment = new Bot . Schema . Attachment ( )
146+ {
147+ ContentType = "application/vnd.microsoft.card.adaptive" ,
148+ Content = adaptiveCardJson ,
149+ } ;
150+ await turnContext . SendActivityAsync ( MessageFactory . Attachment ( adaptiveCardAttachment ) ) ;
151+ }
152+ }
153+ }
154+ return responses ;
232155 }
233156 }
234157}
0 commit comments