{"id":18292528,"url":"https://github.com/tinode/csharpbot","last_synced_at":"2025-04-05T10:31:16.189Z","repository":{"id":33287511,"uuid":"151221110","full_name":"tinode/csharpbot","owner":"tinode","description":"Chatbot in C#","archived":false,"fork":false,"pushed_at":"2022-02-23T03:10:50.000Z","size":935,"stargazers_count":26,"open_issues_count":0,"forks_count":8,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-04-28T18:05:29.671Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-02T08:07:01.000Z","updated_at":"2024-02-18T08:05:39.000Z","dependencies_parsed_at":"2022-08-07T20:30:20.658Z","dependency_job_id":null,"html_url":"https://github.com/tinode/csharpbot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinode%2Fcsharpbot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinode%2Fcsharpbot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinode%2Fcsharpbot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinode%2Fcsharpbot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinode","download_url":"https://codeload.github.com/tinode/csharpbot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247324647,"owners_count":20920692,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T14:18:24.699Z","updated_at":"2025-04-05T10:31:15.071Z","avatar_url":"https://github.com/tinode.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tinode Chatbot Example for .Net or .NetCore\n\nThis is a rudimentary chatbot for Tinode using [gRPC API](../../pbx/). It's written in C# as a demonstration\nthat the API is language-independent.\n\nThe chat bot subscribes to events stream using Plugin API and logs in as a regular user. The event stream API is used to listen for creation of new accounts. When a new account is created, the bot initiates a p2p topic with the new user. Then it listens for messages sent to the topic and responds to each with a random quote from `quotes.txt` file.\n\n\n#### Nuget: [Tinode.ChatBot](https://www.nuget.org/packages/Tinode.ChatBot/)\n\nGenerated files are provided for convenience in a [separate folder](./Tinode.ChatBot). You may re-generate them if needed:\n### for Windows\n```\ngenerate_proto.bat\n```\n\n### for Linux/Mac\n```\ngenerate_proto.sh\n```\n\nThere is already a .net standard library implement for chatbot as \"Tinode.ChatBot\", and there are two applicaion implentat for .net framework4.6.1 and .net core2.0\nthey are \"Tinode.ChatBot.DemoNet46\" and \"Tinode.ChatBot.DemoNetCore\".\n\n#### you can use VistualStudio2017 to open it : [ChatBot.sln](./ChatBot.sln)\n\n#### if you want define your own bot, Just follow these steps:\n* Implement your own `IBotResponse` interface,such as :\n\n```C#\n    /// \u003csummary\u003e\n    /// ChatBot reply interface, you can define your own chat reply logic.\n    /// \u003c/summary\u003e\n    public interface IBotResponse\n    {\n        /// \u003csummary\u003e\n        /// ChatBot Accept Message, and give a resonable reply.\n        /// \u003c/summary\u003e\n        /// \u003cparam name=\"message\"\u003emessage to chatbot\u003c/param\u003e\n        /// \u003creturns\u003emessage reply by chatbot\u003c/returns\u003e\n        Task\u003cChatMessage\u003e ThinkAndReply(ServerData message);\n    }\n```\n\n#### API useage:\n\n1. New a bot instance:\n\n```C#\nChatBot bot = new ChatBot(serverHost: host, listen: listen, schema: schemaArg, secret: secretArg);\n//Event handlers\nbot.ServerDataEvent += Bot_ServerDataEvent; //ServerData Event, message comming\nbot.ServerMetaEvent += Bot_ServerMetaEvent; //ServerMeta Event, friend list message etc.\nbot.ServerPresEvent += Bot_ServerPresEvent; //ServerPres Event, someone is begion typing message\nbot.CtrlMessageEvent += Bot_CtrlMessageEvent; //CtrlMessage Event, every acton with server will response a ctrl message\nbot.LoginSuccessEvent += Bot_LoginSuccessEvent; //LoginSuccess Event, when login success\nbot.LoginFailedEvent += Bot_LoginFailedEvent;  //LoginFailed Event, when login failed\nbot.DisconnectedEvent += Bot_DisconnectedEvent;  //when disconnected with the server, the bot will reconnect automatically.\n//your should set your chatserver's http base url and api access key to handle larget file upload\nbot.SetHttpApi(\"your chat server http base url\", \"your api key\");\nbot.BotResponse = new BotReponse(bot);  //your response implement with IBotResponse\nbot.Start().Wait();  //start your bot\n```\n\n2. handle new message, use `MsgBuilder`, new message comes with ServerData, so you need to is just parse it to `ChatMessage`, to do it is simple as below:\n\n```C#\n var msg = MsgBuilder.Parse(message);\n```\n\n3. get chatbot chat/friend list, you can access it with `bot.Subscribers`\n\n4. build your response message, such as formatted text, image, file etc. you can use `MsgBuilder`  to do that just like `StringBuilder`:\n\n```C#\nMsgBuilder builder = new MsgBuilder();\n//add text with bold\nbuilder.AppendText(\"Hi,this is bold\\n\", isBold: true);\n//add text with italic\nbuilder.AppendText(\"Hi,this is italic\\n\", isItalic: true);\n//add text with deleted\nbuilder.AppendText(\"Hi,this is deleted\\n\", isDeleted: true);\n\n//add text with code style\nbuilder.AppendText(\"int a=100;\\nint b=a*100-90;\\n\", isCode: true);\n//add link\nbuilder.AppendText(\"https://google.com\\n\", isLink: true);\n//add domain\nbuilder.AppendText(\"baidu.com\\n\", isLink: true);\n//add mention message\nbuilder.AppendText(\"@tinode\\n\", isMention: true);\n//add hashtags\nbuilder.AppendText(\"#Tinode\\n\", isHashTag: true);\nbuilder.AppendText(\"\\n\\nnext is image\\n\");\n//add image message\nbuilder.AppendImage(\"a.png\", \"image/png\", 0, 0, \"iamge with base64 value\");\nbuilder.AppendText(\"\\n\\nnext is file\\n\");\n//add file message\nbuilder.AppendFile(\"a.txt\", \"text/plain\", \"file with base64 value\");\n//add attachment file message\nbuilder.AppendAttachment(attachmentInfo);\n\n//Send form with button\nMsgBuilder builder = new MsgBuilder();\nbuilder.AppendText(\"What's your gender?\", isBold: true, isForm: true);\nbuilder.AppendText(\"Male\", isButton: true, buttonDataName: \"male\", buttonDataVal: \"user click male\");\nbuilder.AppendText(\"Female\", isButton: true, buttonDataName: \"female\", buttonDataVal: \"user click female\");\nbuilder.AppendText(\"Not Sure\", isButton: true, buttonDataName: \"NA\", buttonDataVal: \"user click NA\");\n\n\nresponseMsg = builder.Message;\n\n```\n\nyou can also build simple message with static methods of `MsgBuilder`:\n\n```C#\n//Send Image File\nresponseMsg = MsgBuilder.BuildImageMessage(\"a.png\", \"image/png\", 47, 48, \"image with base64 value\", \"this is a image by chatbot\");\n\n//Send file\nresponseMsg = MsgBuilder.BuildFileMessage(\"a.txt\", \"text/plain\", \"file with base64 value\", \"this is a file by chatbot\");\n\n//Send text\nresponseMsg = MsgBuilder.BuildFileMessage(\"this your text message with line break\\n this is new line.\");\n\n//Send attachment file\n//upload a test file as attachment first\nvar uploadInfo=await bot.Upload(\"./libgrpc_csharp_ext.x64.so\");\nif (uploadInfo!=null)\n{\n    //then build a attachment message with attchment success\n    responseMsg = MsgBuilder.BuildAttachmentMessage(uploadInfo, \"This is a larget attachment file\");\n}\n```\n\n\n#### build your chatbot,a complete example:\n\n```C#\nclass Program\n    {\n        public class CmdOptions\n        {\n            [Option('C', \"login-cookie\", Required = false, Default = \".tn-cookie\", HelpText = \"read credentials from the provided cookie file\")]\n            public string CookieFile { get; set; }\n            [Option('T', \"login-token\", Required = false, HelpText = \"login using token authentication\")]\n            public string Token { get; set; }\n            [Option('B', \"login-basic\", Required = false, HelpText = \"login using basic authentication username:password\")]\n            public string Basic { get; set; }\n            [Option('L', \"listen\", Required = false, Default = \"0.0.0.0:40051\", HelpText = \"address to listen on for incoming Plugin API calls\")]\n            public string Listen { get; set; }\n            [Option('S', \"server\", Required = false, Default = \"localhost:16060\", HelpText = \"address of Tinode server gRPC endpoint\")]\n            public string Host { get; set; }\n        }\n\n        /// \u003csummary\u003e\n        /// ChatBot auto reply implement\n        /// \u003c/summary\u003e\n        public class BotReponse : IBotResponse\n        {\n            ChatBot bot;\n            public BotReponse(ChatBot bot)\n            {\n                this.bot = bot;\n            }\n            public async Task\u003cChatMessage\u003e ThinkAndReply(ServerData message)\n            {\n                foreach (var sub in bot.Subscribers)\n                {\n                    //Current account friends info\n                }\n                ChatMessage responseMsg;\n                var msgText = message.Content.ToStringUtf8();\n                var msg = MsgBuilder.Parse(message);\n                if (msg.IsPlainText)\n                {\n                    if (msg.Text == \"image\")\n                    {\n                        //Send Image File\n                        responseMsg = MsgBuilder.BuildImageMessage(\"a.png\", \"image/png\", 47, 48, \"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ACV0RVh0ZGF0ZTptb2RpZnkAMjAxMS0wNS0xOFQyMzo1NDowMCswODowMDef1rEAAABDdEVYdHNvZnR3YXJlAC91c3IvbG9jYWwvaW1hZ2VtYWdpY2svc2hhcmUvZG9jL0ltYWdlTWFnaWNrLTcvL2luZGV4Lmh0bWy9tXkKAAAAGHRFWHRUaHVtYjo6RG9jdW1lbnQ6OlBhZ2VzADGn/7svAAAAF3RFWHRUaHVtYjo6SW1hZ2U6OkhlaWdodAA2MLuNbZ0AAAAWdEVYdFRodW1iOjpJbWFnZTo6V2lkdGgANTkR00Z3AAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADEzMDU3MzQwNDCrCw2wAAAAEXRFWHRUaHVtYjo6U2l6ZQA1OTQzQjpo3pUAAABgdEVYdFRodW1iOjpVUkkAZmlsZTovLy9ob21lL3d3d3Jvb3QvbmV3c2l0ZS93d3cuZWFzeWljb24ubmV0L2Nkbi1pbWcuZWFzeWljb24uY24vc3JjLzUwOTIvNTA5Mjg0LnBuZ91LspIAAAAASUVORK5CYII=\", \"this is a image by chatbot\");\n                    }\n                    else if (msg.Text == \"file\")\n                    {\n                        //Send file\n                        responseMsg = MsgBuilder.BuildFileMessage(\"a.txt\", \"text/plain\", \"ZHNmZHMKZmRzZmRzZnNkZgpm5Y+N5YCS5piv56a75byA5oi/6Ze055qE5LiK6K++5LqGCg==\", \"this is a file by chatbot\");\n                    }\n                    else if (msg.Text == \"more\")\n                    {\n                        MsgBuilder builder = new MsgBuilder();\n                        //add text with bold\n                        builder.AppendText(\"Hi,this is bold\\n\", isBold: true);\n                        //add text with italic\n                        builder.AppendText(\"Hi,this is italic\\n\", isItalic: true);\n                        //add text with deleted\n                        builder.AppendText(\"Hi,this is deleted\\n\", isDeleted: true);\n\n                        //add text with code style\n                        builder.AppendText(\"int a=100;\\nint b=a*100-90;\\n\", isCode: true);\n                        //add link\n                        builder.AppendText(\"https://google.com\\n\", isLink: true);\n                        //add domain\n                        builder.AppendText(\"baidu.com\\n\", isLink: true);\n                        //add mention message\n                        builder.AppendText(\"@tinode\\n\", isMention: true);\n                        //add hashtags\n                        builder.AppendText(\"#Tinode\\n\", isHashTag: true);\n                        builder.AppendText(\"\\n\\nnext is image\\n\");\n                        //add image message\n                        builder.AppendImage(\"a.png\", \"image/png\", 0, 0, \"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ACV0RVh0ZGF0ZTptb2RpZnkAMjAxMS0wNS0xOFQyMzo1NDowMCswODowMDef1rEAAABDdEVYdHNvZnR3YXJlAC91c3IvbG9jYWwvaW1hZ2VtYWdpY2svc2hhcmUvZG9jL0ltYWdlTWFnaWNrLTcvL2luZGV4Lmh0bWy9tXkKAAAAGHRFWHRUaHVtYjo6RG9jdW1lbnQ6OlBhZ2VzADGn/7svAAAAF3RFWHRUaHVtYjo6SW1hZ2U6OkhlaWdodAA2MLuNbZ0AAAAWdEVYdFRodW1iOjpJbWFnZTo6V2lkdGgANTkR00Z3AAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADEzMDU3MzQwNDCrCw2wAAAAEXRFWHRUaHVtYjo6U2l6ZQA1OTQzQjpo3pUAAABgdEVYdFRodW1iOjpVUkkAZmlsZTovLy9ob21lL3d3d3Jvb3QvbmV3c2l0ZS93d3cuZWFzeWljb24ubmV0L2Nkbi1pbWcuZWFzeWljb24uY24vc3JjLzUwOTIvNTA5Mjg0LnBuZ91LspIAAAAASUVORK5CYII=\");\n                        builder.AppendText(\"\\n\\nnext is file\\n\");\n                        //add file message\n                        builder.AppendFile(\"a.txt\", \"text/plain\", \"ZHNmZHMKZmRzZmRzZnNkZgpm5Y+N5YCS5piv56a75byA5oi/6Ze055qE5LiK6K++5LqGCg==\");\n                        responseMsg = builder.Message;\n                    }\n                    else if (msg.Text == \"attach\")\n                    {\n                        //upload a test file as attachment\n                        var uploadInfo = await bot.Upload(\"./libgrpc_csharp_ext.x64.so\");\n                        if (uploadInfo != null)\n                        {\n                            responseMsg = MsgBuilder.BuildAttachmentMessage(uploadInfo, \"This is a larget attachment file\");\n                        }\n                        else\n                        {\n                            responseMsg = MsgBuilder.BuildTextMessage(\"I try to send you a larget attach file, but I am sorry I failed...\");\n                        }\n\n                    }\n                    else if (msg.Text == \"form\")\n                    {\n                        //send a form with button\n                        MsgBuilder builder = new MsgBuilder();\n                        builder.AppendText(\"What's your gender?\", isBold: true, isForm: true);\n                        builder.AppendText(\"Male\", isButton: true, buttonDataName: \"male\", buttonDataVal: \"user click male\");\n                        builder.AppendText(\"Female\", isButton: true, buttonDataName: \"female\", buttonDataVal: \"user click female\");\n                        builder.AppendText(\"Not Sure\", isButton: true, buttonDataName: \"NA\", buttonDataVal: \"user click NA\");\n                        responseMsg = builder.Message;\n                    }\n                    else\n                    {\n                        responseMsg = msg;\n                    }\n\n                }\n                else\n                {\n                    responseMsg = msg;\n                    //Extract more information\n                    var mentions = msg.GetMentions();\n                    foreach (var m in mentions)\n                    {\n                        Console.WriteLine($\"Mentions:{m.Val}\");\n                    }\n\n                    var images = msg.GetImages();\n                    foreach (var image in images)\n                    {\n                        Console.WriteLine($\"Image:Name={image.Name} Mime={image.Mime}\");\n                    }\n\n                    var hashTags = msg.GetHashTags();\n                    foreach (var hash in hashTags)\n                    {\n                        Console.WriteLine($\"HashTags:{hash.Val}\");\n                    }\n\n                    var links = msg.GetLinks();\n                    foreach (var link in links)\n                    {\n                        Console.WriteLine($\"Links:{link.Url}\");\n                    }\n\n                    var files = msg.GetGenericAttachment();\n                    foreach (var f in files)\n                    {\n                        Console.WriteLine($\"Image:Name={f.Name} Mime={f.Mime}\");\n                    }\n\n                }\n                return responseMsg;\n            }\n\n        }\n\n        static ChatBot bot;\n        static void Main(string[] args)\n        {\n            Console.CancelKeyPress += Console_CancelKeyPress;\n            string schemaArg = string.Empty;\n            string secretArg = string.Empty;\n            string cookieFile = string.Empty;\n            string host = string.Empty;\n            string listen = string.Empty;\n            Parser.Default.ParseArguments\u003cCmdOptions\u003e(args)\n                   .WithParsed\u003cCmdOptions\u003e(o =\u003e\n                   {\n                       if (!string.IsNullOrEmpty(o.Host))\n                       {\n                           host = o.Host;\n                           Console.WriteLine($\"gRPC server:{host}\");\n                       }\n                       if (!string.IsNullOrEmpty(o.Listen))\n                       {\n                           listen = o.Listen;\n                           Console.WriteLine($\"Plugin API calls Listen server:{listen}\");\n                       }\n                       if (!string.IsNullOrEmpty(o.Token))\n                       {\n                           schemaArg = \"token\";\n                           secretArg = Encoding.ASCII.GetString(Encoding.Default.GetBytes(o.Token));\n                           Console.WriteLine($\"Login in with token {o.Token}\");\n                           bot = new ChatBot(serverHost: host, listen: listen, schema: schemaArg, secret: secretArg);\n                       }\n                       else if (!string.IsNullOrEmpty(o.Basic))\n                       {\n                           schemaArg = \"basic\";\n                           secretArg = Encoding.UTF8.GetString(Encoding.Default.GetBytes(o.Basic));\n                           Console.WriteLine($\"Login in with login:password {o.Basic}\");\n                           bot = new ChatBot(serverHost: host, listen: listen, schema: schemaArg, secret: secretArg);\n                       }\n                       else\n                       {\n                           cookieFile = o.CookieFile;\n                           Console.WriteLine($\"Login in with cookie file {o.CookieFile}\");\n                           bot = new ChatBot(serverHost: host, listen: listen, cookie: cookieFile, schema: string.Empty, secret: string.Empty);\n                           if (bot.ReadAuthCookie(out var schem, out var secret))\n                           {\n                               bot.Schema = schem;\n                               bot.Secret = secret;\n                           }\n                           else\n                           {\n                               Console.WriteLine(\"Login in with cookie file failed, please check your credentials and try again... Press any key to exit.\");\n                               Console.ReadKey();\n                               return;\n                           }\n                       }\n                       bot.ServerDataEvent += Bot_ServerDataEvent;\n                       bot.ServerMetaEvent += Bot_ServerMetaEvent;\n                       bot.ServerPresEvent += Bot_ServerPresEvent;\n                       bot.CtrlMessageEvent += Bot_CtrlMessageEvent;\n                       bot.LoginSuccessEvent += Bot_LoginSuccessEvent;\n                       bot.LoginFailedEvent += Bot_LoginFailedEvent;\n                       bot.DisconnectedEvent += Bot_DisconnectedEvent;\n                       //your should set your chatserver's http base url and api access key to handle larget file upload\n                       bot.SetHttpApi(\"http://localhost:6660\", \"AQAAAAABAABtfBKva9nJN3ykjBi0feyL\");\n                       bot.BotResponse = new BotReponse(bot);\n                       bot.Start().Wait();\n\n                       Console.WriteLine(\"[Bye Bye] ChatBot Stopped\");\n                   });\n\n        }\n\n        private static void Bot_DisconnectedEvent(object sender, EventArgs e)\n        {\n            Console.WriteLine(\"[!!!Disconnected!!!]\");\n        }\n\n        private static void Bot_LoginFailedEvent(object sender, EventArgs e)\n        {\n            Console.WriteLine(\"[!!!Login Failed!!!]\");\n        }\n\n        private static void Bot_LoginSuccessEvent(object sender, EventArgs e)\n        {\n            Console.WriteLine(\"[!!!Login Success!!!]\");\n        }\n\n        private static void Bot_CtrlMessageEvent(object sender, ChatBot.CtrlMessageEventArgs e)\n        {\n            //Console.WriteLine($\"[Ctrl Message] {e.Code} {e.Id}  {e.Topic}  {e.Text}  {e.Params}  {e.Type}  {e.HasError}\");\n        }\n\n        private static void Bot_ServerPresEvent(object sender, ChatBot.ServerPresEventArgs e)\n        {\n            //Console.WriteLine($\"[Pres Message] {e.Pres.ToString()}\");\n        }\n\n        private static void Bot_ServerMetaEvent(object sender, ChatBot.ServerMetaEventArgs e)\n        {\n            //Console.WriteLine($\"[Meta Message] {e.Meta.ToString()}\");\n        }\n\n        private static void Bot_ServerDataEvent(object sender, ChatBot.ServerDataEventArgs e)\n        {\n            //Console.WriteLine($\"[Data Message] {e.Data.ToString()}\");\n        }\n\n        private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)\n        {\n            bot.Stop();\n        }\n    }\n```\n\n#### example screenshot\n![image](./screenshots/1.png)\n![image](./screenshots/2.png)\n![image](./screenshots/3.PNG)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinode%2Fcsharpbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinode%2Fcsharpbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinode%2Fcsharpbot/lists"}