maui 调用文心一言开发的聊天APP 3
主要是对代码进行了优化
- 上一个版本写死了帐号跟密码 ,这一个帐本有户可以直接设置
- 对相关的key以及secret如果设置错时,在聊天中也会返回提示。
- 注册帐号时同时也设置了key及secrete
- 升级到了net.8.0
- 导出APK,上一个版本是导出abb.
- 解决了变型问题,现在生成桌面系统也能正常显示。
注册界面

<?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 entryentry.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 entryentry.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的ItemsSourcecollectionView.ItemsSource = chatMessages;SetStoredValues();}// 获取 API_KEY SECRET_KEYprivate 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 completeloadingIndicator.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";}}}}
}
桌面界面:



相关文章:
maui 调用文心一言开发的聊天APP 3
主要是对代码进行了优化 上一个版本写死了帐号跟密码 ,这一个帐本有户可以直接设置对相关的key以及secret如果设置错时,在聊天中也会返回提示。注册帐号时同时也设置了key及secrete升级到了net.8.0导出APK,上一个版本是导出abb.解决了变型问…...
鸿蒙开发 - ohpm安装第三方库
前端开发难免使用第三方库,鸿蒙亦是如此,在使用 DevEco Studio 开发工具时,如何引入第三方库呢?操作步骤如下,假设你使用的是MacOS,假设你已经创建了了一个项目: 一、配置 HTTP Proxy 在打开了…...
[C++] new和delete
使用new时调用构造函数使用delete时调用析构函数 构造函数 使用new动态分配内存时,如果分配的是基本类型的内存,则不会调用构造函数。如果分配的是自定义类型的内存,则会调用构造函数进行对象的初始化。 例如: int* pInt new…...
OpenVINS学习2——VIRAL数据集eee01.bag运行
前言 周末休息了两天,接着做上周五那个VIRAL数据集没有运行成功的工作。现在的最新OpenVINS需要重新写配置文件,不像之前那样都写在launch里,因此需要根据数据集情况配置好estimator_config.yaml还有两个标定参数文件。 VIRAL数据集 VIRAL…...
jemeter,断言:响应断言、Json断言
一、响应断言 接口A请求正常返回值如下: {"status": 10013, "message": "user sign timeout"} 在该接口下创建【响应断言】元件,配置如下: 若断言成功,则查看结果树的接口显示绿色,若…...
【vue实战项目】通用管理系统:信息列表,信息的编辑和删除
本文为博主的vue实战小项目系列中的第七篇,很适合后端或者才入门的小伙伴看,一个前端项目从0到1的保姆级教学。前面的内容: 【vue实战项目】通用管理系统:登录页-CSDN博客 【vue实战项目】通用管理系统:封装token操作…...
基于FPGA的视频接口之高速IO(光纤)
简介 对于高速IO口配置光纤,现在目前大部分开发板都有配置,且也有说明,在此根据自己的工作经验以及对于各开发板的说明归纳 通过高速IO接口,以及硬件配置,可以实现对于光纤的收发功能,由于GTX的速率在500Mbs到10Gbps之间,但通道高速io可配置光纤10G硬件,物理通完成,则…...
HTML实现页面
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>工商银行电子汇款单</title> </head> &…...
回归预测 | MATLAB实现IWOA-LSTM改进鲸鱼算法算法优化长短期记忆神经网络的数据回归预测(多指标,多图)
回归预测 | MATLAB实现IWOA-LSTM改进鲸鱼算法算法优化长短期记忆神经网络的数据回归预测(多指标,多图) 目录 回归预测 | MATLAB实现IWOA-LSTM改进鲸鱼算法算法优化长短期记忆神经网络的数据回归预测(多指标,多图&#…...
鸿蒙开发之状态管理@State
1、视图数据双向绑定 鸿蒙开发采用的声明式UI,利用状态驱动UI的更新。其中State被称作装饰器,是一种状态管理的方式。 状态:指的是被装饰器装饰的驱动视图更新的数据。 视图:是指用户看到的UI渲染出来的界面。 之所以成为双向…...
redis基本用法学习(主要数据类型)
redis官网教程中介绍有三种方式连接redis:命令行、gui工具和编程连接: 命令行方式主要是在命令行中输入redis-cli后,通过命令方式与redis服务进行交互,支持两种模式:REPL模式(简单的交互式的编程环境&a…...
低代码:美味膳食或垃圾食品
低代码开发是近年来迅速崛起的软件开发方法,让编写应用程序变得更快、更简单。有人说它是美味的膳食,让开发过程高效而满足,但也有人质疑它是垃圾食品,缺乏定制性与深度。你认为低代码到底是美味的膳食还是垃圾食品呢,…...
设计模式—观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。 在观察者模式中,有两个核心角色…...
Java_EasyExcel_导入_导出Java-js
easyExcel导入 从easyexcel官网中拷贝过来,使用到的,这是使用监听器的方法。 EasyExcel.read(file.getInputStream(), BaseStoreDataExcelVo.class, new ReadListener<BaseStoreDataExcelVo>() {/*** 单次缓存的数据量*/public static final int…...
循环神经网络-RNN记忆能力实验 [HBU]
目录 一、循环神经网络 二、循环神经网络的记忆能力实验 三、数据集构建 数据集的构建函数 加载数据并进行数据划分 构造Dataset类 四、模型构建 嵌入层 SRN层 五、模型训练 训练指定长度的数字预测模型 多组训练 损失曲线展示 六、模型评价 参考《神经网络与深度…...
P1044 [NOIP2003 普及组] 栈——卡特兰数
传送门: P1044 [NOIP2003 普及组] 栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1044 公式一:递推式(注意开 long long ,然后 先乘完再除,防止下取整) typedef long long ll;…...
9:00面试,9:06就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到12月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40…...
ets:tab2list的不足之处与替代方法,以及gen_server中使用ets的优缺点
ets:tab2list 是 Erlang/OTP 中的一个函数,用于将 ETS(Erlang Term Storage)表转换为列表。ETS 是 Erlang 中的一个内建数据库,允许开发者在内存中存储大量数据。 一、ets:tab2list 的不足之处: 性能问题:…...
软件测试之压力测试详解
一、什么是压力测试 软件测试中:压力测试(Stress Test),也称为强度测试、负载测试。压力测试是模拟实际应用的软硬件环境及用户使用过程的系统负荷,长时间或超大负荷地运行测试软件,来测试被测系统的性能、…...
SpringBoot之请求的详细解析
1. 请求 在本章节呢,我们主要讲解,如何接收页面传递过来的请求数据。 1.1 Postman 之前我们课程中有提到当前最为主流的开发模式:前后端分离 在这种模式下,前端技术人员基于"接口文档",开发前端程序&…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
