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

news2024/11/18 4:47:58

主要是对代码进行了优化

  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";
                }
            }
        }
    }
}

桌面界面:

在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis新数据类型-Bitmaps

目录 Bitmaps 简介 命令 1. setbit (1) 格式 (2) 实例 2. getbit (1) 格式 (2) 实例 3. bitcount (1) 格式 (2) 实例 4. bitop (1) 格式 (2) 实例 我的其他博客 Bitmaps 简介 Bitmaps 是 Redis 的一种新数据类型&#xff0c;它是一种用于存储位信息的数据结构&…

Netty详细文档

Netty教程 文章目录 Netty教程 Netty简介Netty 的介绍Netty 的应用场景互联网行业游戏行业大数据领域其它开源项目使用到 Netty Netty 的学习资料参考 Java BIO编程I/O 模型BIO、NIO、AIO 使用场景分析Java BIO 基本介绍Java BIO 工作机制Java BIO 应用实例问题分析 Java NIO编…

腾讯云Elasticsearch Service产品体验

基本介绍 产品概述 腾讯云 Elasticsearch Service&#xff08;ES&#xff09;是云端全托管海量数据检索分析服务&#xff0c;拥有高性能自研内核&#xff0c;集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群&#xff0c;也支持免运维、自动弹性、按需…

iOS使用CoreText完成txt阅读器

CoreText是一个高效处理字符和字形转换和进行文字排版的框架&#xff0c;API基于C语言。 常见的CoreText类介绍 &#xff08;1&#xff09;、CFAttributedStringRef 属性字符串&#xff0c;用于存储需要绘制的文字字符和字符属性 &#xff08;2&#xff09;、CTFramesetterR…

Layui实现自定义的table列悬停事件并气泡提示信息

1、概要 使用layui组件实现table的指定列悬停时提示信息&#xff0c;因为layui组件中没有鼠标悬停事件支持&#xff0c;所以需要结合js原生事件来实现这个功能&#xff0c;并结合layui的tips和列的templte属性气泡提示实现效果。 2、效果图 3、代码案例 <!DOCTYPE html&g…

Spark编程入门

1.8 Spark编程入门 1.8.1 通过IDEA创建Spark工程 ps:工程创建之前步骤省略,在scala中已经讲解,直接默认是创建好工程的 导入Pom文件依赖 <!-- 声明公有的属性 --><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler…

企业电子招投标采购系统源码之鸿鹄电子招投标系统+电子招投标的组成

招投标管理系统是一款适用于招标代理、政府采购、企业采购和工程交易等领域的企业级应用平台。该平台以项目为主线&#xff0c;从项目立项到项目归档&#xff0c;实现了全流程的高效沟通和协作。通过该平台&#xff0c;用户可以实时共享项目数据信息&#xff0c;实现规范化管理…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十四:系统设置模块相关功能实现

一、本章内容 本章使用已实现的公共组件实现系统管理中的系统设置模块相关功能,包括菜单管理、角色管理、日志管理、用户管理、系统配置、数据字典等。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 3.1 B站视频地址:

Duplicate keys detected: This may cause an update error.【Vue遍历渲染报错的解决】

今天在写项目时&#xff0c;写到一个嵌套评论的遍历时&#xff0c;控制台出现了一个报错信息&#xff0c;但是并不影响页面的渲染&#xff0c;然后一看这个错的原因是 key值重复&#xff0c;那么问题的解决方式就很简单了。&#xff08;vue for循环读取key值时&#xff0c; key…

docker 安装keepalive

docker 安装keepalive 1.Keepalived 简介 Keepalived 是 Linux 下一个轻量级别的高可用解决方案。高可用(High Avalilability,HA)&#xff0c;其实两种不同的含义&#xff1a;广义来讲&#xff0c;是指整个系统的高可用行&#xff0c;狭义的来讲就是之主机的冗余和接管&#…

stateflow之广播时间及案例分析

目录 前言 1.何谓广播事件&#xff1f;作用是啥&#xff1f; 2.本地广播事件 3.直接广播事件 前言 虽然广播时间官方文档以及好多博主已经做出介绍&#xff0c;但个人在阅读的时候总是觉得费解&#xff0c;要么直接按官方内容陈述&#xff0c;要么缺少案例分析讲解&#xf…

节流防抖:提升前端性能的秘密武器(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

flex布局,flex-direction, justify content, align-content

目录 flex-direction justify content&#xff1a; flex-wrap align-items align-content flex-flow flex:1 align-self order属性定义项目排列顺序 已知html文件为&#xff1a; <div class"given"><span>1</span><span>2</span…

大数据云计算——Docker环境下部署Hadoop集群及运行集群案列

大数据云计算——Docker环境下部署Hadoop集群及运行集群案列 本文着重介绍了在Docker环境下部署Hadoop集群以及实际案例中的集群运行。首先&#xff0c;文章详细解释了Hadoop的基本概念和其在大数据处理中的重要性&#xff0c;以及为何选择在Docker环境下部署Hadoop集群。接着&…

Ps:认识 RGB 曲线

曲线 Curves本质上是用于调整通道的命令&#xff0c;因此在不同的颜色模式&#xff08;比如&#xff0c;RGB、CMYK、Lab、灰度、双色调等&#xff09;下有着不同的表现和操作方式。颜色模式的不同影响了曲线的坐标系、可调整的通道以及可实现的效果。 在 RGB 颜色模式下的曲线&…

Vue之Computed(计算属性)

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

IDEA之设置项目包的结构层级为eclipse默认样式

idea默认项目包的结构层级如下: 想修改成eclipse默认的那种样式&#xff0c;设置步骤如下: 1.点击下图中红框图标进行设置 2.选择 Tree Appearance&#xff0c;取消勾选 Compact Middle Packages 3.勾选红框里的两个选项&#xff0c;Flatten Packages 和 Hide Empty Middle Pa…

Python数据科学视频讲解:Python序列的概念及通用操作

2.10 Python序列的概念及通用操作 视频为《Python数据科学应用从入门到精通》张甜 杨维忠 清华大学出版社一书的随书赠送视频讲解2.10节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。内容涵盖数据科学应用的全流程&#xff0c;…

机器学习算法新手入门指南

AI算法的种类在人工智能领域中非常丰富&#xff0c;而且多样化&#xff0c;AI算法利用数学、统计学和计算机科学等领域的原理和方法&#xff0c;通过模拟人类智能和学习能力来解决各种复杂的问题。 在监督学习领域&#xff0c;我们有经典的线性回归和逻辑回归算法&#xff0c;…

YOLOv8算法改进【NO.93】使用resnet18网络作为主干特征提取网络

前 言 YOLO算法改进系列出到这&#xff0c;很多朋友问改进如何选择是最佳的&#xff0c;下面我就根据个人多年的写作发文章以及指导发文章的经验来看&#xff0c;按照优先顺序进行排序讲解YOLO算法改进方法的顺序选择。具体有需求的同学可以私信我沟通&#xff1a; 第一…