maui 调用文心一言开发的聊天APP 3

主要是对代码进行了优化

  1. 上一个版本写死了帐号跟密码 ,这一个帐本有户可以直接设置
  2. 对相关的key以及secret如果设置错时,在聊天中也会返回提示。
  3. 注册帐号时同时也设置了key及secrete
  4. 升级到了net.8.0
  5. 导出APK,上一个版本是导出abb.
  6. 解决了变型问题,现在生成桌面系统也能正常显示。

注册界面

在这里插入图片描述

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="AiChat.Views.RegPage"
             Shell.NavBarIsVisible="True"
             xmlns:mct="clr-namespace:CommunityToolkit.Maui.Behaviors;assembly=CommunityToolkit.Maui"
             xmlns:local="clr-namespace:AiChat.Views;assembly=AiChat"
             Title="注册">
    <Grid RowDefinitions="Auto,*" Margin="0,10,0,0">
        <VerticalStackLayout Padding="10" VerticalOptions="Center" HorizontalOptions="FillAndExpand">

            <Frame BorderColor="White"
                   CornerRadius="10"
                   HasShadow="True"
                   Margin="0,20,0,0"
                   ZIndex="0"
                   Padding="8">
                <Frame.Shadow>
                    <Shadow Brush="Black"
                            Offset="20,20"
                            Radius="10"
                            Opacity="0.9" />
                </Frame.Shadow>
                <StackLayout Padding="10">
                    <VerticalStackLayout Padding="10" BackgroundColor="{StaticResource White}">
                    
                        <Label Text="AI CHAT"
                               FontSize="30"
                               FontAttributes="Bold"
                               TextColor="{StaticResource Cyan100Accent}"
                               FontFamily="Consolas"
                               Padding="5"/>
                        <Label Text="to continue!" TextColor="{StaticResource Cyan100Accent}"
                               FontSize="14" Padding="5"
                               FontAttributes="Bold" />
                    </VerticalStackLayout>
                    <VerticalStackLayout Padding="10">
                        <Label FontFamily="Consolas" Text="手机号" TextColor="{StaticResource Cyan100Accent}" />
                        <Frame CornerRadius="10" Padding="3" Margin="0,10,0,0">
                            <VerticalStackLayout>
                                <Entry x:Name="Phone" Text="{Binding Phone,Mode=TwoWay}" Margin="5,0,0,0" Placeholder="手机" FontSize="14">
                                    <Entry.Behaviors>
                                        <local:PhoneNumberValidatorBehavior />
                                    </Entry.Behaviors>
                                </Entry>

                            </VerticalStackLayout>
                        </Frame>
                        <VerticalStackLayout Padding="0" Margin="0,5,0,0">
                            <Label FontFamily="Consolas" Text="密码" TextColor="{StaticResource Cyan100Accent}"  />
                            <Frame CornerRadius="10" Padding="3" Margin="0,10,0,0">
                                <Entry x:Name="Password" Text="{Binding Password,Mode=TwoWay}" Margin="5,0,0,0" Placeholder="密码6位数字" IsPassword="True" FontSize="14">
                                    <Entry.Behaviors>
                                        <local:PasswordValidatorBehavior />
                                    </Entry.Behaviors>
                                </Entry>
                            </Frame>
                        </VerticalStackLayout>
                        <Label FontFamily="Consolas" Text="文心一言API_KEY" TextColor="{StaticResource Cyan100Accent}" />
                        <Frame CornerRadius="10" Padding="3" Margin="0,10,0,0">
                            <VerticalStackLayout>
                                <Entry x:Name="API_KEY" Text="{Binding API_KEY,Mode=TwoWay}" Margin="5,0,0,0" Placeholder="API_KEY" FontSize="14" />
                            </VerticalStackLayout>
                        </Frame>
                        <Label FontFamily="Consolas" Text="文心一言SECRET_KEY" TextColor="{StaticResource Cyan100Accent}" />
                        <Frame CornerRadius="10" Padding="3" Margin="0,10,0,0">
                            <VerticalStackLayout>
                                <Entry x:Name="SECRET_KEY" Text="{Binding SECRET_KEY,Mode=TwoWay}" Margin="5,0,0,0" Placeholder="SECRET_KEY" FontSize="14" />
                            </VerticalStackLayout>
                        </Frame>
                        <Button Margin="0,20,0,0"
                                x:Name="RegButton"
                                Clicked="RegButton_Clicked"
                                Text="确定注册" VerticalOptions="CenterAndExpand" BackgroundColor="{StaticResource Cyan100Accent}" 
                                HorizontalOptions="FillAndExpand"/>

                        <BoxView Color="{StaticResource Cyan100Accent}"
                                 Margin="0,20,0,0"
                                 HeightRequest="2"
                                 HorizontalOptions="Fill" />
                        <Grid Padding="10" Margin="0,10,0,0" InputTransparent="False">

                            <Label FontFamily="Consolas"  InputTransparent="False">
                                <Label.FormattedText>
                                    <FormattedString>
                                        <Span Text="返回 " TextColor="{StaticResource Cyan100Accent}" />
                                        <Span Text="登陆" TextColor="{StaticResource Cyan100Accent}" />
                                    </FormattedString>
                                </Label.FormattedText>
                                <Label.GestureRecognizers>
                                    <TapGestureRecognizer Tapped="OnLoginLabelTapped" />
                                </Label.GestureRecognizers>
                            </Label>
                            
                            
                        </Grid>
                        <Grid Padding="10" Margin="0,10,0,0" InputTransparent="False">

                            <Label FontFamily="Consolas"  InputTransparent="False">
                                <Label.FormattedText>
                                    <FormattedString>
                                        <Span Text="百度文言一心登陆获取 API_KEY SECRET_KEY" TextColor="Red" />
                                   
                                    </FormattedString>
                                </Label.FormattedText>
                                <Label.GestureRecognizers>
                                    <TapGestureRecognizer Tapped="OnBaiduLabelTapped" />
                                </Label.GestureRecognizers>
                            </Label>


                        </Grid>
                    </VerticalStackLayout>
                </StackLayout>
            </Frame>
        </VerticalStackLayout>
    </Grid>
</ContentPage>

using System.Text.RegularExpressions;
using System.Windows.Input;
using static Microsoft.Maui.ApplicationModel.Permissions;
namespace AiChat.Views
{
    public class PhoneNumberValidatorBehavior : Behavior<Entry>
    {
        protected override void OnAttachedTo(Entry entry)
        {
            entry.TextChanged += OnEntryTextChanged;
            base.OnAttachedTo(entry);
        }
        protected override void OnDetachingFrom(Entry entry)
        {
            entry.TextChanged -= OnEntryTextChanged;
            base.OnDetachingFrom(entry);
        }
        private void OnEntryTextChanged(object sender, TextChangedEventArgs args)
        {
            if (!(sender is Entry entry))
                return;

            string phoneNumber = args.NewTextValue;
            bool isValid = Regex.IsMatch(phoneNumber, @"^\d{11}$");

            // Set IsValid property on the associated entry
            entry.SetValue(IsValidProperty, isValid);
        }

        public static readonly BindableProperty IsValidProperty =
            BindableProperty.CreateAttached("IsValid", typeof(bool), typeof(PhoneNumberValidatorBehavior), false);
    }

    public class PasswordValidatorBehavior : Behavior<Entry>
    {
        protected override void OnAttachedTo(Entry entry)
        {
            entry.TextChanged += OnEntryTextChanged;
            base.OnAttachedTo(entry);
        }
        protected override void OnDetachingFrom(Entry entry)
        {
            entry.TextChanged -= OnEntryTextChanged;
            base.OnDetachingFrom(entry);
        }
        private void OnEntryTextChanged(object sender, TextChangedEventArgs args)
        {
            if (!(sender is Entry entry))
                return;

            string password = args.NewTextValue;
            bool isValid = Regex.IsMatch(password, @"^\d{6}$");

            // Set IsValid property on the associated entry
            entry.SetValue(IsValidProperty, isValid);
        }

        public static readonly BindableProperty IsValidProperty =
            BindableProperty.CreateAttached("IsValid", typeof(bool), typeof(PasswordValidatorBehavior), false);
    }
    public partial class RegPage : ContentPage
    {
        public RegPage()
        {
            InitializeComponent();
            BindingContext = this;
        }
        private async void OnLoginLabelTapped(object sender, EventArgs e)
        {
            var nextPage = new LoginPage();
            var navigation = Application.Current.MainPage.Navigation;
            await navigation.PushAsync(nextPage);
        }

        private async void OnBaiduLabelTapped(object sender, EventArgs e)
        {
            await Launcher.TryOpenAsync(new Uri("https://login.bce.baidu.com/"));
        }
        protected override bool OnBackButtonPressed()
        {
            Application.Current.Quit();
            return true;
        }
        private async void RegButton_Clicked(object sender, EventArgs e)
        {
            bool isPhoneValid = (bool)Phone.GetValue(PhoneNumberValidatorBehavior.IsValidProperty);
            bool isPasswordValid = (bool)Password.GetValue(PasswordValidatorBehavior.IsValidProperty);
            if (isPhoneValid && isPasswordValid)
            {
                if (string.IsNullOrEmpty(API_KEY.Text) || string.IsNullOrEmpty(SECRET_KEY.Text))
                {
                    await DisplayAlert("确定", "API_KEY  SECRET_KEY 不能为空?", "确定"); // 修改按钮标签为 "确定"
                    return;
                }

                if (await DisplayAlert("确定", "确定增加吗?", "确定", "取消")) // 修改按钮标签为 "确定" 和 "取消"
                {

                    await SecureStorage.SetAsync("PHONE", Phone.Text);
                    await SecureStorage.SetAsync("PASSWORD", Password.Text);
                    await SecureStorage.SetAsync("API_KEY", API_KEY.Text);
                    await SecureStorage.SetAsync("SECRET_KEY", SECRET_KEY.Text);
                    await DisplayAlert("成功", "注册成功", "OK");
                }

            }
            else
            {
                await DisplayAlert("验证失改", "手机号密码错", "OK");
              
            }
        }


    }
}

加入了手机号密码的验证,同时要求加入API_KEY,SECRET_KEY。

聊天代码

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace AiChat.Views
{
    // 用于将文本颜色转换为视图颜色的转换器
    public class MessageColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // 根据“IsUser”的值确定文本颜色的逻辑
            bool isUser = (bool)value;

            if (isUser)
            {
                // 返回用户的文本颜色
                return Color.FromHex("#0000FF"); // 更改为所需的颜色
            }
            else
            {
                // 返回其他情况的文本颜色
                return Color.FromHex("#000000");// 更改为所需的颜色
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // 如果需要双向绑定,请实现此方法进行转换
            throw new NotImplementedException();
        }
    }

    // 聊天页面类
    public partial class Chat : ContentPage
    {
        // 定义表示聊天消息的类
        public class ChatMessage
        {
            public string Text { get; set; }
            public bool IsUser { get; set; }
            public DateTime Timestamp { get; set; }
        }
        static string sAPI_KEY = "";
        static string sSECRET_KEY = "";
  
        // 用于存储聊天消息的集合
        private ObservableCollection<ChatMessage> chatMessages = new ObservableCollection<ChatMessage>();

        // 构造函数
        public Chat()
        {
            InitializeComponent();
            // 将chatMessages集合绑定到CollectionView的ItemsSource
            collectionView.ItemsSource = chatMessages;
            SetStoredValues();
        }
        // 获取 API_KEY SECRET_KEY
        private async void SetStoredValues()
        {
            var storedKey = await SecureStorage.GetAsync("API_KEY");
      
            if (!string.IsNullOrEmpty(storedKey))
            {
                sAPI_KEY = storedKey;

            }

            var storedSecret = await SecureStorage.GetAsync("SECRET_KEY");
            if (!string.IsNullOrEmpty(storedSecret))
            {
                sSECRET_KEY = storedSecret;
            }
            entryUserMessage.Text = "";
        }
        // 发送消息按钮点击事件处理程序
        private async void SendMessage_Clicked(object sender, EventArgs e)
        {
          
            try
            {
                sendmessageButton.IsEnabled = false;
                loadingIndicator.IsVisible = true;
                // 从Entry中获取用户的消息
                string userMessage = entryUserMessage.Text;
            if (string.IsNullOrEmpty(userMessage) )
            { return;   }

            // 将用户的消息添加到chatMessages集合,并添加时间戳
            chatMessages.Add(new ChatMessage
            {
                Text = $"您:{userMessage}",
                IsUser = true,
                Timestamp = DateTime.Now
            });

            // 模拟对方的响应
            string response = await getAnswer(userMessage);
            response = response != null ? response : "请配置好文心一言的API_KEY SECRET_KEY";

                // 将对方的响应添加到chatMessages集合,并添加时间戳
                chatMessages.Add(new ChatMessage
                {

                Text = $"AI:{response}",
                    IsUser = false,
                    Timestamp = DateTime.Now
                }); 

            // 可选:滚动到底部以显示最新的消息
            collectionView.ScrollTo(chatMessages[chatMessages.Count - 1], ScrollToPosition.End);
            // 发送后清除用户的输入
            entryUserMessage.Text = string.Empty;

            }
       
            finally
            {
                // Hide the loading indicator when the operation is complete
                loadingIndicator.IsVisible = false;
                sendmessageButton.IsEnabled = true;
            }
        }

        public static async Task<string> getAnswer(string question)
        {
            var url = $"https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/aquilachat_7b?access_token={await GetAccessToken()}";

            var payload = JsonConvert.SerializeObject(new
            {
                messages = new[]
                {
                    new { role = "user", content = question }
                }
            });

            using (var client = new HttpClient())
            {
                var content = new StringContent(payload, Encoding.UTF8, "application/json");
                var response = await client.PostAsync(url, content);

                if (response.IsSuccessStatusCode)
                {
                    var responseContent = await response.Content.ReadAsStringAsync();
                    var dictObj = JsonConvert.DeserializeObject<dynamic>(responseContent);
                    return dictObj.result;
                }
                else
                {
                    Console.WriteLine($"HTTP请求失败: {response.StatusCode}");
                    return "请配置好文心一言的API_KEY SECRET_KEY";
                }
            }
        }

        private static async Task<string> GetAccessToken()
        {
            var url = "https://aip.baidubce.com/oauth/2.0/token";
            using (var client = new HttpClient())
            {
                var parameters = new FormUrlEncodedContent(new[]
                {
                            new KeyValuePair<string, string>("grant_type", "client_credentials"),
                            new KeyValuePair<string, string>("client_id", sAPI_KEY),
                            new KeyValuePair<string, string>("client_secret", sSECRET_KEY)
                        });
                var response = await client.PostAsync(url, parameters);
                if (response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();
                    var result = JsonConvert.DeserializeObject<dynamic>(content);
                    return result.access_token;
                }
                else
                {
                    Console.WriteLine($"HTTP请求失败: {response.StatusCode}");
                    return "wrong";
                }
            }
        }
    }
}

桌面界面:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/243667.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

动物姿态估计:微调 YOLOv8 姿态模型

动物姿态估计是计算机视觉的一个研究领域&#xff0c;是人工智能的一个子领域&#xff0c;专注于自动检测和分析图像或视频片段中动物的姿势和位置。目标是确定一种或多种动物的身体部位&#xff08;例如头部、四肢和尾巴&#xff09;的空间排列。这项技术具有广泛的应用&#…

一起学习生成式人工智能(四)|用低代码实现人工智能应用

点击蓝字 关注我们 编辑&#xff1a;Alan Wang 排版&#xff1a;Rani Sun 微软 Reactor 为帮助广开发者&#xff0c;技术爱好者&#xff0c;更好的学习 .NET Core, C#, Python&#xff0c;数据科学&#xff0c;机器学习&#xff0c;AI&#xff0c;区块链, IoT 等技术&#xff0…

EasyRecovery(数据恢复软件) 2024中文绿色无需激活版下载

EasyRecovery是一款功能强大且专业的数据恢复软件&#xff0c;软件能够对电脑误删的文件进行恢复&#xff0c;包括格式化硬盘是数据恢复、手机U盘数据恢复等&#xff0c;小编今天给大家带来的是根据官软件解压后直接使用。感兴趣的朋友快来下载使用吧。 EasyRecovery-2024mac最…

Java数据结构篇——实现顺序表的增删查改

文章目录 1.线性表2. 顺序表2.1 顺序表结构2.2 实现顺序表接口2.3 打印顺序表2.2 实现新增元素2.3 实现查找元素2.3 获取pos位置的值2.4 删除元素2.5 获取顺序表的长度2.6 清空顺序表 3.代码在这 1.线性表 定义&#xff1a;线性表是 n 个具有相同特性的数据元素的有序序列。线…

数据库性能优化八大方案

毫不夸张的说咱们后端工程师&#xff0c;无论在哪家公司&#xff0c;呆在哪个团队&#xff0c;做哪个系统&#xff0c;遇到的第一个让人头疼的问题绝对是数据库性能问题。如果我们有一套成熟的方法论&#xff0c;能让大家快速、准确的去选择出合适的优化方案&#xff0c;我相信…

Unity之OpenXR+XR Interaction Toolkit接入Meta Quest3

前言 随着备受期待的Meta Quest 3与今年10月10日发布,这款来自Meta的下一代VR游戏头戴设备承诺将彻底改变您的游戏方式。 Meta Quest 3,玩家只需轻松一触即可在虚拟现实和真实世界之间无缝切换,无需摘下头戴设备进行快速现实检查。 Meta Quest 3最引人注目的特点之一是其能…

【知识积累】深度度量学习综述

原文指路&#xff1a;https://hav4ik.github.io/articles/deep-metric-learning-survey Problem Setting of Supervised Metric Learning 深度度量学习是一组旨在衡量数据样本之间相似性的技术。 Contrastive Approaches 对比方法的主要思想是设计一个损失函数&#xff0c;直…

pytorch中的归一化:BatchNorm、LayerNorm 和 GroupNorm

1 归一化概述 训练深度神经网络是一项具有挑战性的任务。 多年来&#xff0c;研究人员提出了不同的方法来加速和稳定学习过程。 归一化是一种被证明在这方面非常有效的技术。 1.1 为什么要归一化 数据的归一化操作是数据处理的一项基础性工作&#xff0c;在一些实际问题中&am…

六.聚合函数

聚合函数 1.什么是聚合函数1.1AVG和SUM函数1.2MIN和MAX函数1.3COUNT函数 2.GROUP BY2.1基本使用2.2使用多个列分组2.3GROUP BY中使用WITH ROLLUP 3.HAVING3.1基本使用3.2WHERE和HAVING的区别 4.SELECT的执行过程4.1查询的结构4.2SELECT执行顺序4.3SQL执行原理 1.什么是聚合函数…

JOSEF约瑟快速跳闸继电器RXMS1RK216063 DC220V

系列型号 RXMS1 RK 216 437快速跳闸继电器&#xff1b;RXMS1 RK 216 237快速跳闸继电器&#xff1b; RXMS1 RK 216 449快速跳闸继电器&#xff1b;RXMS1 RK 216 249快速跳闸继电器&#xff1b; RXMS1 RK 216 450快速跳闸继电器&#xff1b;RXMS1 RK 216 250快速跳闸继电器&a…

HarmonyOS使用Web组件

Web组件的使用 1 概述 相信大家都遇到过这样的场景&#xff0c;有时候我们点击应用的页面&#xff0c;会跳转到一个类似浏览器加载的页面&#xff0c;加载完成后&#xff0c;才显示这个页面的具体内容&#xff0c;这个加载和显示网页的过程通常都是浏览器的任务。 ArkUI为我…

C语言实现贪吃蛇【完整版】

贪吃蛇 文章目录 贪吃蛇使用到的WIN32一些接口简单介绍控制台窗口大小隐藏光标控制光标的位置获取键盘的值的情况字符问题 游戏逻辑开始游戏打印地图初始化贪吃蛇创建食物 运行游戏控制蛇的移动 运行结束 贪吃蛇实现出来的效果如下&#xff1a; 贪吃蛇小游戏录屏 完整代码&…

【Spark精讲】Spark存储原理

目录 类比HDFS的存储架构 Spark的存储架构 存储级别 RDD的持久化机制 RDD缓存的过程 Block淘汰和落盘 类比HDFS的存储架构 HDFS集群有两类节点以管理节点-工作节点模式运行&#xff0c;即一个NameNode(管理节点)和多个DataNode(工作节点)。 Namenode管理文件系统的命名空…

销售技巧培训之如何提升金融销售技巧

销售技巧培训之如何提升金融销售技巧 在金融行业&#xff0c;销售技巧是决定业绩成败的关键因素之一。无论是销售保险、股票、债券&#xff0c;还是提供投资咨询服务&#xff0c;都需要掌握一定的销售技巧。本文将探讨如何提升金融销售技巧&#xff0c;通过案例分析&#xff0…

如何提升网络安全技术【蓝队】?在职学长告诉你

网络安全的防守技术是网络安全工程师必备技能&#xff0c;只有攻防兼备的白帽子&#xff0c;才算是真正的网安精英。 网络安全的攻击技术在前面我已经讲过了&#xff0c;感兴趣的可以去看看&#xff1a; 90%的人都不算会网络安全&#xff0c;这才是真正的白帽子技术【红队】 . …

GitHub帐户管理更改电子邮件

登录到您的 GitHub 帐户&#xff1a; 前往 GitHub 网站并使用您的凭据登录。 访问个人设置&#xff1a; 单击右上角的您的头像&#xff0c;然后选择“Settings”&#xff08;设置&#xff09;。 选择电子邮件选项卡&#xff1a; 在左侧边栏中选择“Emails”&#xff08;电子邮…

单片稳压集成电路78LXX系列——固定的电压输出,适用于需100mA电源供给的应用场合(网络产品,声卡和电脑主板等产品)

78LXX系列是一款单片稳压集成电路&#xff0c;它们有一系列固定的电压输出&#xff0c;适用于需100mA电源供给的应用场合。78LXX系列采用T0-92和SOT-89-3L的封装形式。 主要特点&#xff1a; ● 最大输出电流为100mA ● 输出电压为3.3V. 5V. 6V. 8V、9V、10V、 12V和15V ● 热…

深入理解 Go Channel:解密并发编程中的通信机制

一、Channel管道 1、Channel说明 共享内存交互数据弊端 单纯地将函数并发执行是没有意义的。函数与函数间需要交互数据才能体现编发执行函数的意义虽然可以使用共享内存进行数据交换&#xff0c;但是共享内存在不同的goroutine中容易发送静态问题为了保证数据交换的正确性&am…

HTTP、HTTPS、SSL协议以及相关报文讲解

目录 HTTP/HTTPS介绍 HTTP/HTTPS基本信息 HTTP如何实现有状态 HTTP请求与应答报文 HTTP请求报文 HTTP响应报文 SSL协议 SSL单向认证 SSL双向认证 HTTP连接建立与传输步骤 HTTP访问全过程相关报文&#xff08;以访问www.download.cucdccom为例子&#xff09; DNS报文…

什么是SEO优化

什么是SEO&#xff0c;百度其实就有答案&#xff0c;只是回答的很基础&#xff0c;说的都是基础概念&#xff0c;没有具体的体现在里面&#xff0c;SEO除了基础概念&#xff0c;还要有相应的构架&#xff0c;不然怎么弄都是一场空而已。 关于什么是SEO的文章导读&#xff1f; 1…