Discord C# + API OpenAI - c#

using Discord;
using Discord.WebSocket;
using RestSharp;
using Newtonsoft.Json;
using System.Net;
namespace DiscordBot.Service;
public class OpenAiService
{
private const string OpenAiApiKey = "OPENAIKEY";
private const string ChatGptApiUrl = "https://api.openai.com/v1/completions";
private const string DalleApiUrl = "https://api.openai.com/v1/images/generations";
/// <param name="message"></param>
internal static async Task<Tuple<bool, string>> ChatGpt(SocketMessage message)
{
try
{
if (string.IsNullOrWhiteSpace(message.Content.Substring(5)))
{
await message.Channel.SendMessageAsync("The message content is empty. Please provide a prompt for the ChatGPT API.");
return new Tuple<bool, string>(false, "The message content is empty.");
}
// Create a new RestClient instance
var client = new RestClient(ChatGptApiUrl);
// Create a new RestRequest instance
var request = new RestSharp.RestRequest("", Method.Post);
// Set the request headers
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", $"Bearer {OpenAiApiKey}");
// Create the request data
var data = new
{
// The prompt is everything after the !chat command
model = "text-davinci-003",
prompt = message.Content.Substring(5),
max_tokens = 256
};
var jsonData = JsonConvert.SerializeObject(data);
// Add the request data to the request body
request.AddJsonBody(jsonData);
// Send the request and get the response
var response = await client.ExecuteAsync(request);
// Holds the response from the API.
string responseText;
var success = true;
// Check the status code of the response
if (response.Content != null && response.StatusCode == HttpStatusCode.OK)
{
// Get the response text from the API
responseText = JsonConvert.DeserializeObject<dynamic>(response.Content)?["choices"][0]["text"] ??
"Could not deserialize response from ChatGPT Api!";
}
else
{
// Get the ErrorMessage from the API
responseText = response.ErrorMessage ?? string.Empty;
success = false;
}
// Send the response to the Discord chat
await message.Channel.SendMessageAsync(responseText);
return new Tuple<bool, string>(success, responseText);
}
catch (Exception ex)
{
// Log the exception or handle it in another way
Console.WriteLine(ex.Message);
return new Tuple<bool, string>(false, "An error occurred while sending the request to the ChatGPT API");
}
}
/// <summary>
/// The method uses the RestClient class to send a request to the Dall-E API, passing the user's message as the
/// prompt and sends an image to the Chat
/// </summary>
/// <param name="message"></param>
/// <returns>Boolean indicating whether the request was successful</returns>
internal static async Task<Tuple<bool, string>> DallE(SocketMessage message)
{
try
{
if (string.IsNullOrWhiteSpace(message.Content.Substring(5)))
{
await message.Channel.SendMessageAsync("The message content is empty. Please provide a prompt for the ChatGPT API.");
return new Tuple<bool, string>(false, "The message content is empty.");
}
// Create a new RestClient instance
var client = new RestClient(DalleApiUrl);
// Create a new RestRequest instance
var request = new RestSharp.RestRequest("", Method.Post);
// Set the request headers
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", $"Bearer {OpenAiApiKey}");
// Create the request data
var data = new
{
// The prompt is everything after the !image command
model = "image-alpha-001",
prompt = message.Content.Substring(6),
n = 1,
size = "1024x1024"
};
var jsonData = JsonConvert.SerializeObject(data);
// Add the request data to the request body
request.AddJsonBody(jsonData);
// Send the request and get the response
var response = await client.ExecuteAsync(request);
// Holds the response from the API.
string responseText;
var success = false;
// Check the status code of the response
if (response.Content != null && response.StatusCode == HttpStatusCode.OK)
{
// Get the image URL from the API response
var imageUrl = JsonConvert.DeserializeObject<dynamic>(response.Content)?["data"][0]["url"];
responseText = $"Here is the generated image: {imageUrl}";
success = true;
}
else
{
// Get the ErrorMessage from the API
responseText = response.ErrorMessage ?? string.Empty;
}
// Send the response to the Discord chat
await message.Channel.SendMessageAsync(responseText);
return new Tuple<bool, string>(success, responseText);
}
catch (Exception ex)
{
// Log the exception or handle it in another way
Console.WriteLine(ex.Message);
return new Tuple<bool, string>(false, "An error occurred while sending the request to the Dall-e API");
}
}
}
public class Program
{
private const string DiscordToken = "BOTTOKEN";
private static void Main()
{
MainAsync().GetAwaiter().GetResult();
}
public static async Task MainAsync()
{
//Creates a config with specified gateway intents
var config = new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent
};
// Create a new Discord client
var client = new DiscordSocketClient(config);
// Log messages to the console
client.Log += Log;
// Handle messages received
client.MessageReceived += HandleCommand;
// Login to Discord
await client.LoginAsync(TokenType.Bot, DiscordToken);
// Start the client
await client.StartAsync();
// Block this program until it is closed
await Task.Delay(-1);
}
/// <summary>
/// This method is called whenever a message is received
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
private static async Task HandleCommand(SocketMessage message)
{
var success = true;
var responseText = string.Empty;
await Log(new LogMessage(LogSeverity.Info, nameof(HandleCommand),
"New Message incoming..."));
// Check if the message starts with one of these commands
switch (message.Content)
{
case { } chat when chat.StartsWith("!chat"):
await Log(new LogMessage(LogSeverity.Info, nameof(HandleCommand),
"Recived !chat command: " + message.Content));
(success, responseText) = await OpenAiService.ChatGpt(message);
break;
case { } image when image.StartsWith("!image"):
await Log(new LogMessage(LogSeverity.Info, nameof(HandleCommand),
"Recived !image command: " + message.Content));
(success, responseText) = await OpenAiService.DallE(message);
break;
default:
await Log(new LogMessage(LogSeverity.Info, nameof(HandleCommand),
"No command found, normal message"));
break;
}
if (!success)
await Log(new LogMessage(LogSeverity.Warning, nameof(HandleCommand),
"Error with one of the request to the Apis!"));
if (!string.IsNullOrEmpty(responseText))
await Log(new LogMessage(LogSeverity.Info, nameof(HandleCommand),
"Respone: " + responseText));
}
/// <summary>
/// This method logs messages to the console
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
private static Task Log(LogMessage msg)
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}
}
Here is my code that does not contain errors according to the compiler but causes errors in the console:
15:58:09 Discord Discord.Net v3.9.0 (API v10)
15:58:09 Gateway Connecting
15:58:11 Gateway You're using the GuildScheduledEvents gateway intent without listening to any events related to that intent, consider removing the intent from your config.
15:58:11 Gateway You're using the GuildInvites gateway intent without listening to any events related to that intent, consider removing the intent from your config.
15:58:11 Gateway Connected
15:58:11 Gateway Ready
15:58:36 HandleComma New Message incoming...
15:58:36 HandleComma No command found, normal message
15:58:55 HandleComma New Message incoming...
15:58:55 HandleComma Recived !chat command: !chat explain me quantum physic in simple terms
Argument cannot be blank. (Parameter 'Content')
15:58:55 HandleComma Error with one of the request to the Apis!
15:58:55 HandleComma Respone: An error occurred while sending the request to the ChatGPT API
So I asked ChatGPT, who returned my code without modification.
Then I looked for help on this:
You're using the GuildScheduledEvents gateway intent without listening to any events related to that intent, consider removing the intent from your config. You're using the GuildInvites gateway intent without listening to any events related to that intent, consider removing the intent from your config.
I couldn't find anything except this: Events in Discord.Net
I would need help and am at your disposal for any further information

Related

Why RestAPI occasionally returns 429 TooManyRequest response?

I send a request to the API and sometimes receive the response with an HTTP 429 status code (TooManyRequests).
On average, for 10 requests, 2 will return 429 response and the remaining 8 return the correct value.
It also happened to me that when it was the first request (so there is no option for TooManyRequests)
public static List<ResponseObject> GetProductsFromRestAPI(int[] ProductIdArray )
{
List<ResponseObject> products = new List<ResponseObject>();
string action;
for (int i = 0; i < ProductIdArray.Length; i++)
{
action = "products/" + ProductIdArray[i].ToString();
client = AddHeadersToClient(action, new RestClient("https://api.usedbythiscode.com/")); //required by this API.
var currentProduct = RequestsLib.GetProduct(client, action);
products.Add(currentProduct);
}
return products;
}
public static Product GetProduct(RestClient restClient, string action) //todo test this for bugs
{
var result = new Product();
var request = new RestRequest(action, Method.GET);
var response = SendRequest(restClient, request);//Here I sometimes get response with 429.
//.. Other code
return result;
}
public static async Task<IRestResponse> SendRequest(RestClient restClient, RestRequest request)
{
return await restClient.ExecuteGetAsync(request);
}
Temporarily resolved it by sending another request with do while loop and usually second request return right answer.
do
{
SendRequest(restClient, request);
}
while (StatusCode != 200);
Where could the cause of the error lie?
Is it possible that I have unclosed requests?
Is creating multiple RestSharp clients a good practice?
EDIT:
The problem was on the server side. All I had to do was report the bug to the admins who provided the API. Thank you for help.
429 is Too Many Requests. Most APIs have some kind of rate-limiting in place so that a single client can't take down their server with too many requests.
The proper response for 429 is to retry. I recommend using Polly for retry logic, but be aware that HandleTransientHttpError doesn't consider 429 a transient error.
I agree with #mason, you should use async method with Task<> and await response Here is the part of login side of my mobileApp-project in Xamarin. You may want to see how to use async with Task<> easily.
public async Task<BSUser> ValidateUser(string userName, string password)
{
string url = Xamarin.Essentials.Preferences.Get(Constants.URL_KEY, "") + "/api/Validateuser";
HttpClient _Client = new HttpClient();
var data = new Dictionary<string, string>
{
{"userName", userName},
{"password", password}
};
string jsonData = JsonConvert.SerializeObject(data);
HttpContent content = new StringContent(jsonData, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage httpResponse = await _Client.PostAsync(url, content);
if (httpResponse.IsSuccessStatusCode)
{
try {
var responseData = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
var result = JsonConvert.DeserializeObject(responseData).ToString();
UserInfo userInfo = JsonConvert.DeserializeObject<UserInfo>(result);
BSUser value = new BSUser();
value.UserName = userInfo.userCode;
return value;
}
catch (Java.Net.SocketException e)
{
Console.WriteLine("Hata", e);
return null;
}
}
else
{
return null;
}
}
catch (SystemException)
{
return null;
}
}

Why doesn't IServerStreamWriter send notification responses?

I work on a cross-platform application. For connection between them, I use gRPC technology. When a client connects to server, it is added to an observers list located in server implementation. When a client connects, I want to send a message to the rest of connected clients telling them that a new client connected. The problem is that when I want to send a response to clients that a new client connected, using the observers from my list, I get the following exception:
Grpc.Core.RpcException: 'Status(StatusCode=Unknown, Detail="Exception was thrown by handler.")'
This is my proto file where I declared my server:
syntax = "proto3";
package com.example.grpc.chat;
message ChatMessage {
string from = 1;
string message = 2;
}
message ChatMessageFromServer {
ChatMessage message = 2;
}
service ChatService {
rpc Login(ChatMessage ) returns (stream ChatMessageFromServer);
}
The server code :
public class ChatServiceImpl : ChatService.ChatServiceBase
{
private static HashSet<IServerStreamWriter<ChatMessageFromServer>> responseStreams = new HashSet<IServerStreamWriter<ChatMessageFromServer>>();
/*
* if the stream object (from "for" statement inside this method) isn't the responseStream object given in the list with parameters,
* the rest of clients aren't notified when a new login request is pushed.
*/
public override async Task Login(global::Com.Example.Grpc.Chat.ChatMessage request,
IServerStreamWriter<global::Com.Example.Grpc.Chat.ChatMessageFromServer> responseStream,
ServerCallContext context)
{
Console.WriteLine("Login method from server");
responseStreams.Add(responseStream);
// Create a server message that wraps the client message
var message = new ChatMessageFromServer
{
Message = new ChatMessage
{
From = "login",
Message = "hello"
}
};
// If stream variable isn't equal to responseStream from list of parameters, the client corresponding to that stream isn't notified and it's thrown the above exception
foreach (var stream in responseStreams)
{
await stream.WriteAsync(message);
}
}
}
The client code where the client send a login request:
public partial class ChatForm : Form
{
private const string Host = "localhost";
private const int Port = 9090;
private ChatService.ChatServiceClient _chatService;
public ChatForm()
{
//InitializeComponent();
InitializeGrpc();
}
private void InitializeGrpc()
{
// Create a channel
var channel = new Channel(Host + ":" + Port, ChannelCredentials.Insecure);
// Create a client with the channel
_chatService = new ChatService.ChatServiceClient(channel);
}
private async void ChatForm_Load(object sender, EventArgs e)
{
var message = new ChatMessage
{
From = "Unknown",
Message = "Login text"
};
// Open a connection to the server
try
{
using (var call = _chatService.Login(message))
{
// Read messages from the response stream
while (await call.ResponseStream.MoveNext(CancellationToken.None))
{
var serverMessage = call.ResponseStream.Current;
var otherClientMessage = serverMessage.Message;
var displayMessage = string.Format("{0}:{1}{2}", otherClientMessage.From, otherClientMessage.Message, Environment.NewLine);
chatTextBox.Text += displayMessage;
}
}
}
catch (RpcException )
{
throw;
}
}
}
Your notifyObservers method is asynchronous but has a void return type, which means you can't await it. You're effectively starting the method, and returning as soon as you hit the first await operator that uses an incomplete awaitable (the first WriteAsync call, probably).
You then return the task with a ReservationResponse, and the operation completes.
When that first awaitable call completes, notifyObservers will continue, but at that point the operation has already completed, so when you try to write to the response stream, the system will throw the error you're seeing.
I strongly suspect you should return a Task from notifyObservers and await that from your main entry method:
// Names changed to be conventional C#
public override async Task<ReservationResponse> SaveReservation(
global::Res.Protocol.ReservationRequest request, ServerCallContext context)
{
// some code for saving my reservation in repository database
ReservationResponse response = new Res.Protocol.ReservationResponse
{
Type = ReservationResponse.Types.Type.Savereservation,
Journey = GetProtoJourney(journey)
};
await NotifyObserversAsync(response);
// Note: no Task.FromResult, as you're in an async method. The response
// will already be wrapped in a task.
return new ReservationResponse
{
Type = ReservationResponse.Types.Type.Savereservation
};
}
public async Task NotifyObserversAsync(Res.Protocol.ReservationResponse response)
{
foreach (var ob in responseStreams)
{
await ob.WriteAsync(response);
}
}

Async calls get stuck at HttpClient.SendAsync()

I am using Microsoft Bot framework (SDK v3) to create a QnA bot. While calling the QnAMaker API, the execution gets stuck at HttpCleint.SendAsync.
I have tried calling ConfigureAwait(false) on all the async calls.
I have tried adding .Result at end of function calls.
Both doesn't seem to work.
[Serializable]
public class QnAMakerService
{
private string qnaServiceHostName;
private string knowledgeBaseId;
private string endpointKey;
public QnAMakerService()
{
qnaServiceHostName = "foo";
knowledgeBaseId = "bar";
endpointKey = "foo";
}
async Task<string> Post(string uri, string body)
{
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(uri);
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
request.Headers.Add("Authorization", "EndpointKey " + endpointKey);
var response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> GetAnswer(string question)
{
string uri = qnaServiceHostName + "/qnamaker/knowledgebases/" + knowledgeBaseId + "/generateAnswer";
string questionJSON = #"{'question': '" + question + "'}";
var response = await Post(uri, questionJSON);
var answers = JsonConvert.DeserializeObject<QnAAnswer>(response);
if (answers.answers.Count > 0)
{
return answers.answers[0].answer;
}
else
{
return "No good match found.";
}
}
}
[BotAuthentication]
public class MessagesController : ApiController
{
/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
///
QnAMakerService qna = new QnAMakerService();
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var q = await qna.GetAnswer(activity.Text);
// return our reply to the user
Activity reply = activity.CreateReply($"{q}");
connector.Conversations.ReplyToActivity(reply);
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
}
The execution stops after the SendAsync call with a 500 internal server error excception.
I think the asynchonous code is getting blocked somewhere, but I don't know where.
EDIT : The same block of code(to call the API) works if I try it in a console application.

In Dynamics CRM Plugin: How to force the code not to wait for async response

So here is my scenario. I have to call an Azure Function through Dynamics CRM plugin code (C#) asynchronously, that is fine. But I don't want the code to wait for Azure Function's response. I just want to complete the code execution and exit.
The Azure Function will take care of the updates back in the CRM if necessary.
The reason why I don't want to wait is there is a 2 minutes time limit for plugin execution to complete in CRM Online. However, Azure Function could take several minutes to complete the process.
Here is my plugin class code that is making a synchronous call to Azure Function. (I can convert the call to async following this document, but following that approach my code will still be waiting for the response).
public class CallAzureFunc : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an entity type you are expecting.
if (entity.LogicalName != "account")
return;
// Obtain the organization service reference which you will need web service calls.
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
try
{
// Plug-in business logic goes here.
Data data = new Data
{
name = entity.Attributes["name"].ToString()
};
string result = CallFunction(tracer, data);
tracer.Trace($#"result: {result}");
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in MyPlug-in.", ex);
}
catch (Exception ex)
{
tracer.Trace("MyPlugin: {0}", ex.ToString());
throw;
}
}
}
private string CallFunction(ITracingService tracer, Data data)
{
string json = JsonConvert.SerializeObject(data);
string apiUrl = "https://<AzureFunctionName>.azurewebsites.net/api/";
string token = "<token>";
string content = null;
string apiMethod = "CreateContactFromLead";
string inputJson = json;
string result = ApiHelper.ExecuteApiRequest(apiUrl, token, content, apiMethod, inputJson, tracer);
return result;
}
}
And here are the helper methods to make an API call.
internal static string ExecuteApiRequest(string apiUrl, string token, string content, string apiMethod, string inputJson, ITracingService tracer)
{
try
{
var data = Encoding.ASCII.GetBytes(inputJson);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Format(apiUrl + apiMethod));
request.Method = "POST";
request.ContentLength = inputJson.Length;
request.ContentType = "application/json";
request.ContentLength = data.Length;
request.Headers.Add("x-functions-key", token);
request.Accept = "application/json";
// Send the data
Stream newStream = request.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
// Get the resposne
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response != null)
{
tracer.Trace("ApiHelper > ExecuteApiRequest > response.StatusCode: " + response.StatusCode);
tracer.Trace("ApiHelper > ExecuteApiRequest > response.StatusDescription: " + response.StatusDescription);
}
if (response.StatusCode == HttpStatusCode.OK || response.StatusDescription == "OK" || response.StatusDescription == "200")
{
content = ReadStream(response, tracer);
}
else if (response.StatusCode == HttpStatusCode.NoContent || response.StatusDescription == "No Content" || response.StatusDescription == "204")
{
content = null;
}
else
{
if (response != null)
{
throw new Exception(String.Format("Status Code: {0}, Status Description: {1}",
response.StatusCode,
response.StatusDescription));
}
}
return content;
}
catch (Exception ex)
{
tracer.Trace("ApiHelper > ExecuteApiRequest > error: " + ex.Message);
throw;
}
}
private static string ReadStream(HttpWebResponse response, ITracingService tracer)
{
try
{
var responseJson = string.Empty;
if (response != null)
{
Stream dataStream = response.GetResponseStream();
if (dataStream != null)
{
using (StreamReader reader = new StreamReader(dataStream))
{
while (!reader.EndOfStream)
{
responseJson = reader.ReadToEnd();
}
}
}
}
return responseJson;
}
catch (Exception ex)
{
tracer.Trace("ApiHelper > ReadStream > error: " + ex.Message);
throw ex;
}
}
You need two functions.
Function #1 will be called by your plugin (essentially what you are doing now.) It will validate the inputs. If the inputs are successful it will place a message (presumably that includes the relative data from the caller) in an Azure Service Bus Queue. After placing a message on the service bus queue it will terminate and return a success message to the caller (i.e., the plugin code.)
Function # 2 will be triggered by an Azure Service Bus Queue message. This function will handle the long-running code based on the message content (from Function # 1.)
Example of Azure Service triggered Azure Function:
[FunctionName("ServiceBusQueueTriggerCSharp")]
public static void Run(
[ServiceBusTrigger("myqueue", AccessRights.Manage, Connection = "ServiceBusConnection")]
string myQueueItem,
Int32 deliveryCount,
DateTime enqueuedTimeUtc,
string messageId,
TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
log.Info($"EnqueuedTimeUtc={enqueuedTimeUtc}");
log.Info($"DeliveryCount={deliveryCount}");
log.Info($"MessageId={messageId}");
}
This pattern is commonly used because it provides transaction execution safety. If you only had the one function, as described above, and the Function failed the call would be lost since there was no listener for completion.
Using two functions we have safety. If Function # 1 fails (either validation or placing a message on the queue) it will fail to the caller, and your plugin code can handle as appropriate. If Function # 2 fails it will fail back to the Service Bus and be queued for retry (by default it is retried up to 5 times and then written to a poison queue.)

Calling FB Greeting from Bot Framework

I was trying to create FB Gretting using C# SDK and sending the curl request according to FB documentation here : https://developers.facebook.com/docs/messenger-platform/thread-settings/greeting-text
However, seems that there is no response from FB. Any pointers would be appreciated. Thanks
public class MessagesController : ApiController
{
int i = 0;
/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
//await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
await Conversation.SendAsync(activity, () => new Dialogs.TheQnAMakerDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
private Activity HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.DeleteUserData)
{
// Implement user deletion here
// If we handle user deletion, return a real message
}
else if (message.Type == ActivityTypes.ConversationUpdate)
{
// Handle conversation state changes, like members being added and removed
// Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
// Not available in all channels
var callFB=SendFBGreeting();
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
// Handle add/remove from contact lists
// Activity.From + Activity.Action represent what happened
}
else if (message.Type == ActivityTypes.Typing)
{
// Handle knowing tha the user is typing
}
else if (message.Type == ActivityTypes.Ping)
{
}
return null;
}
private async Task<HttpResponseMessage> SendFBGreeting()
{
var payload = #"{
""setting_type"": ""greeting"",
""greeting"": {
""text"": ""Timeless apparel for the masses.""
}
}";
var stringPayload = await Task.Run(() => JsonConvert.SerializeObject(payload));
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
using (var client = new HttpClient())
{
// Do the actual request and await the response
var httpResponse = await client.PostAsync("https://graph.facebook.com/v2.6/me/thread_settings?access_token=xxx", httpContent);
// If the response contains content we want to read it!
if (httpResponse.Content != null)
{
var responseContent = await httpResponse.Content.ReadAsStringAsync();
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
}
}
Facebook does not return a ConversationUpdate event. Try to call SendFBGreeting() elsewhere.
Keep in mind greeting text will be shown before the user Get Started, So even if you do get ConversationUpdate event, it won't matter in this case.

Categories

Resources