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 之前我们课程中有提到当前最为主流的开发模式:前后端分离 在这种模式下,前端技术人员基于"接口文档",开发前端程序&…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...
