增强 Markdown 渲染和 AI 交互功能
- 修改 `MarkdownWpfRenderer.RenderHtmlBlock` 方法,支持 `<think>` 标签并使用 `Expander` 控件展示内容。 - 更新 `AiHelper` 类,添加新的 API_KEY 注释。 - 调整 `PromptUtil.UsePrompt` 方法的注释,增加思考过程的要求。 - 新增 `StringEmptyToBoolConverter` 类,用于处理字符串空状态。 - 在 `MainWindow.xaml` 中注释掉部分 `SideMenu` 内容。 - 在 `AiMessageControll.xaml` 中集成 `StringEmptyToBoolConverter`,优化内容显示逻辑。 - 修改 `ImportExcelPage.xaml` 的文本绑定属性。 - 更新 `ImportViewModel.cs` 中 `AiHelper` 的实例化方式和变量声明,提升代码清晰度。 - 更新 `TEST_AI_CONTENT`,添加 `<think>` 标签示例。
This commit is contained in:
parent
78d65a6aff
commit
8f42b5e5a7
|
|
@ -362,9 +362,19 @@ public class MarkdownWpfRenderer
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
return new FrameworkElement();
|
return new FrameworkElement();
|
||||||
|
var text = htmlBlock.Lines.ToString();
|
||||||
|
if (text.StartsWith("<think>"))
|
||||||
|
{
|
||||||
|
text = text.Replace("<think>", "").Replace("</think>", "");
|
||||||
|
}
|
||||||
var htmlText = new SelectableTextBlock();
|
var htmlText = new SelectableTextBlock();
|
||||||
htmlText.Text = htmlBlock.Lines.ToString();
|
htmlText.Text = text;
|
||||||
return htmlText;
|
var expander = new Expander();
|
||||||
|
var header = new StackPanel();
|
||||||
|
header.Children.Add(new ProgressBar() { IsIndeterminate = true,Width = 30 });
|
||||||
|
expander.Header = header;
|
||||||
|
expander.Content = htmlText;
|
||||||
|
return expander;
|
||||||
|
|
||||||
}
|
}
|
||||||
public FrameworkElement RenderMathBlock(MathBlock mathBlock, CancellationToken cancellationToken)
|
public FrameworkElement RenderMathBlock(MathBlock mathBlock, CancellationToken cancellationToken)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,12 @@ class AiHelper
|
||||||
/// 火山引擎
|
/// 火山引擎
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const string API_KEY = "58e5c6fd-a5da-400e-b889-715febce478f";
|
private const string API_KEY = "58e5c6fd-a5da-400e-b889-715febce478f";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 硅基流动
|
||||||
|
/// </summary>
|
||||||
|
//private const string API_KEY = "sk-anocoxlcvabejwwzzfsozibmrhzygyedjxdbjpmzfwauwtnx";
|
||||||
|
//private const string API_ENDPOINT = "https://api.siliconflow.cn/";
|
||||||
private const string API_ENDPOINT = "https://ark.cn-beijing.volces.com/api/v3/";
|
private const string API_ENDPOINT = "https://ark.cn-beijing.volces.com/api/v3/";
|
||||||
|
|
||||||
private readonly IChatClient _client;
|
private readonly IChatClient _client;
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,22 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ExcelHelper.AI
|
namespace ExcelHelper.AI;
|
||||||
|
|
||||||
|
class PromptUtil
|
||||||
{
|
{
|
||||||
class PromptUtil
|
public static string UsePrompt(string msg,string excelPrompt)
|
||||||
{
|
{
|
||||||
public static string UsePrompt(string msg,string excelPrompt)
|
return $@"
|
||||||
{
|
|
||||||
return $@"
|
|
||||||
你是一个Excel公式大师,你需要帮助用户解答Excel公式相关的问题。
|
你是一个Excel公式大师,你需要帮助用户解答Excel公式相关的问题。
|
||||||
|
|
||||||
你在回复用户的问题时,需要遵守以下规则:
|
你在回复用户的问题时,需要遵守以下规则:
|
||||||
1. 优先保证答案的准确性,其次是简洁明了。
|
1. 优先保证答案的准确性,其次是简洁明了。
|
||||||
2. 需要保证你的回答是有逻辑性的,不要让用户感到困惑。
|
2. 需要保证你的回答是有逻辑性的,不要让用户感到困惑。
|
||||||
3. 可以例举2~3个例子来帮助用户更好地理解你的回答。
|
3. 可以例举1到2个例子来帮助用户更好地理解你的回答中的Excel公式。
|
||||||
4. 一定要保证文档格式的正确性,避免出现无法显示的内容。
|
4. 一定要保证文档格式的正确性,避免出现无法显示的内容。
|
||||||
5. 尽量使用比较简短与易懂的公式来回答用户的问题,避免用户无法理解。
|
5. 尽量使用比较简短与易懂的公式来回答用户的问题,避免用户无法理解。
|
||||||
|
6. 你不能跳过你的思考过程。
|
||||||
|
|
||||||
现在的时间是{DateTime.Now}。
|
现在的时间是{DateTime.Now}。
|
||||||
|
|
||||||
|
|
@ -26,6 +27,5 @@ namespace ExcelHelper.AI
|
||||||
|
|
||||||
用户的问题是:{msg}
|
用户的问题是:{msg}
|
||||||
";
|
";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace ExcelHelper.Converter;
|
||||||
|
|
||||||
|
public class StringEmptyToBoolConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
var str = value as string;
|
||||||
|
var isEmpty = string.IsNullOrEmpty(str);
|
||||||
|
|
||||||
|
// 如果参数是"invert",则反转结果
|
||||||
|
if (parameter != null && parameter.ToString() == "invert")
|
||||||
|
{
|
||||||
|
isEmpty = !isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isEmpty ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,16 +15,16 @@
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" MinWidth="100" />
|
<!--<ColumnDefinition Width="Auto" MinWidth="100" />-->
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<hc:SideMenu Grid.Column="0" AutoSelect="True">
|
<!--<hc:SideMenu Grid.Column="0" AutoSelect="True">
|
||||||
<hc:SideMenuItem
|
<hc:SideMenuItem
|
||||||
Command="{Binding SideMenuSelectCommand}"
|
Command="{Binding SideMenuSelectCommand}"
|
||||||
CommandParameter="ImportExcelPage"
|
CommandParameter="ImportExcelPage"
|
||||||
Header="导入"
|
Header="导入"
|
||||||
IsSelected="True" />
|
IsSelected="True" />
|
||||||
</hc:SideMenu>
|
</hc:SideMenu>-->
|
||||||
<Frame
|
<Frame
|
||||||
x:Name="MainFrame"
|
x:Name="MainFrame"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@
|
||||||
|
|
||||||
<!-- 布尔值到可见性转换器 -->
|
<!-- 布尔值到可见性转换器 -->
|
||||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||||
|
<!-- 字符串空判断转换器 -->
|
||||||
|
<local1:StringEmptyToBoolConverter x:Key="StringEmptyToBoolConverter" />
|
||||||
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
|
@ -52,16 +55,50 @@
|
||||||
Padding="5"
|
Padding="5"
|
||||||
HorizontalAlignment="{Binding IsUser, Converter={StaticResource BoolToAlignmentConverter}}"
|
HorizontalAlignment="{Binding IsUser, Converter={StaticResource BoolToAlignmentConverter}}"
|
||||||
Background="{Binding IsUser, Converter={StaticResource BoolToColorConverter}}"
|
Background="{Binding IsUser, Converter={StaticResource BoolToColorConverter}}"
|
||||||
CornerRadius="10">
|
CornerRadius="3">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<md:MarkdownViewer x:Name="MdViewer" Content="{Binding Content}" />
|
<!-- 当Content为空时显示进度条 -->
|
||||||
|
<ProgressBar
|
||||||
|
Height="5"
|
||||||
|
Margin="5"
|
||||||
|
IsIndeterminate="True"
|
||||||
|
Visibility="{Binding Content, Converter={StaticResource StringEmptyToBoolConverter}}" />
|
||||||
|
|
||||||
<TextBlock
|
<!-- 当Content不为空时显示内容 -->
|
||||||
Margin="0,5,0,0"
|
<TabControl
|
||||||
HorizontalAlignment="Right"
|
Background="Transparent"
|
||||||
FontSize="10"
|
BorderThickness="0"
|
||||||
Foreground="#99000000"
|
Visibility="{Binding Content, Converter={StaticResource StringEmptyToBoolConverter}, ConverterParameter=invert}">
|
||||||
Text="{Binding Timestamp, StringFormat='{}{0:HH:mm}'}" />
|
<TabItem Background="Transparent" Header="文档">
|
||||||
|
<md:MarkdownViewer
|
||||||
|
x:Name="MdViewer"
|
||||||
|
Margin="10"
|
||||||
|
Padding="10"
|
||||||
|
Content="{Binding Content}" />
|
||||||
|
</TabItem>
|
||||||
|
<TabItem Background="Transparent" Header="文本">
|
||||||
|
<TextBox
|
||||||
|
Margin="5"
|
||||||
|
Padding="5"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderBrush="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
Text="{Binding Content}" />
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
|
||||||
|
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,5,5,0"
|
||||||
|
FontSize="10"
|
||||||
|
Foreground="#99000000"
|
||||||
|
Text="{Binding Content.Length, StringFormat='字数: {0}'}" />
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,5,0,0"
|
||||||
|
FontSize="10"
|
||||||
|
Foreground="#99000000"
|
||||||
|
Text="{Binding Timestamp, StringFormat='{}{0:HH:mm}'}" />
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
@ -101,8 +138,12 @@
|
||||||
Height="40"
|
Height="40"
|
||||||
Margin="5,0,0,0"
|
Margin="5,0,0,0"
|
||||||
Padding="15,0"
|
Padding="15,0"
|
||||||
|
Background="#000"
|
||||||
|
BorderBrush="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
Click="SendButton_Click"
|
Click="SendButton_Click"
|
||||||
Content="发送"
|
Content="发送"
|
||||||
|
Foreground="White"
|
||||||
IsEnabled="{Binding IsWaiting, Converter={StaticResource InverseBoolConverter}, UpdateSourceTrigger=PropertyChanged, ElementName=userControl}" />
|
IsEnabled="{Binding IsWaiting, Converter={StaticResource InverseBoolConverter}, UpdateSourceTrigger=PropertyChanged, ElementName=userControl}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
@ -117,7 +158,7 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center" Text="AI正在思考中..." />
|
<TextBlock VerticalAlignment="Center" Text="正在思考中..." />
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
Width="100"
|
Width="100"
|
||||||
Height="15"
|
Height="15"
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@
|
||||||
Padding="5"
|
Padding="5"
|
||||||
VerticalContentAlignment="Top"
|
VerticalContentAlignment="Top"
|
||||||
AcceptsReturn="True"
|
AcceptsReturn="True"
|
||||||
Text="{Binding PromptString}"
|
Text="{Binding ExcelPromptString}"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
VerticalScrollBarVisibility="Auto" />
|
VerticalScrollBarVisibility="Auto" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace ExcelHelper.Views.ViewModels;
|
||||||
public partial class ImportViewModel : ObservableRecipient, IViewModel
|
public partial class ImportViewModel : ObservableRecipient, IViewModel
|
||||||
{
|
{
|
||||||
|
|
||||||
private AiHelper AiHelper = new AiHelper("deepseek-v3-241226", false);
|
private readonly AiHelper AiHelper = new("deepseek-r1-250120", false);
|
||||||
|
|
||||||
public Task FileDrop(string[] files)
|
public Task FileDrop(string[] files)
|
||||||
{
|
{
|
||||||
|
|
@ -46,7 +46,11 @@ public partial class ImportViewModel : ObservableRecipient, IViewModel
|
||||||
IsLoading = false;
|
IsLoading = false;
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 读取excel
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path"></param>
|
||||||
|
/// <param name="isReload"></param>
|
||||||
public async void ReadForExcel(string path, bool isReload = false)
|
public async void ReadForExcel(string path, bool isReload = false)
|
||||||
{
|
{
|
||||||
IsLoading = true;
|
IsLoading = true;
|
||||||
|
|
@ -135,7 +139,7 @@ public partial class ImportViewModel : ObservableRecipient, IViewModel
|
||||||
ExcelColumns.Add(column);
|
ExcelColumns.Add(column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int columnsSeq = 0;
|
var columnsSeq = 0;
|
||||||
foreach (var item in ExcelColumns)
|
foreach (var item in ExcelColumns)
|
||||||
{
|
{
|
||||||
TableColumns.Add(new TableColumnModel
|
TableColumns.Add(new TableColumnModel
|
||||||
|
|
@ -308,143 +312,9 @@ public partial class ImportViewModel : ObservableRecipient, IViewModel
|
||||||
|
|
||||||
|
|
||||||
private const string TEST_AI_CONTENT = @"
|
private const string TEST_AI_CONTENT = @"
|
||||||
这篇文章包含markdown语法基本的内容, 目的是放在自己的博客园上, 通过开发者控制台快速选中,
|
<think>
|
||||||
从而自定义自己博客园markdown样式.当然本文也可以当markdown语法学习之用.
|
1231231
|
||||||
|
</think>
|
||||||
在markdown里强制换行是在末尾添加2个空格+1个回车.
|
|
||||||
在markdown里可以使用 \ 对特殊符号进行转义.
|
|
||||||
|
|
||||||
# 1. 标题
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
```
|
|
||||||
# This is an <h1> tag
|
|
||||||
## This is an <h2> tag
|
|
||||||
### This is an <h3> tag
|
|
||||||
#### This is an <h4> tag
|
|
||||||
```
|
|
||||||
|
|
||||||
**实例**
|
|
||||||
|
|
||||||
# This is an h1 tag
|
|
||||||
## This is an h2 tag
|
|
||||||
### This is an h3 tag
|
|
||||||
#### This is an h4 tag
|
|
||||||
|
|
||||||
# 2. 强调和斜体
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
```
|
|
||||||
*This text will be italic*
|
|
||||||
_This will also be italic_
|
|
||||||
|
|
||||||
**This text will be bold**
|
|
||||||
__This will also be bold__
|
|
||||||
```
|
|
||||||
(个人不喜欢2个下划线中间包含的内容被斜体, 会和网址冲突, 我会在自定义博客园样式中去除这个样式.)
|
|
||||||
|
|
||||||
**实例**
|
|
||||||
|
|
||||||
*This text will be italic*
|
|
||||||
_This will also be italic_
|
|
||||||
|
|
||||||
**This text will be bold**
|
|
||||||
__This will also be bold__
|
|
||||||
|
|
||||||
# 3. 有序列表和无序列表
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
```
|
|
||||||
* Item 1
|
|
||||||
* Item 2
|
|
||||||
* Item 3
|
|
||||||
|
|
||||||
1. Item 1
|
|
||||||
2. Item 2
|
|
||||||
3. Item 3
|
|
||||||
```
|
|
||||||
|
|
||||||
**实例**
|
|
||||||
* Item 1
|
|
||||||
* Item 2
|
|
||||||
* Item 3
|
|
||||||
|
|
||||||
1. Item 1
|
|
||||||
2. Item 2
|
|
||||||
3. Item 3
|
|
||||||
|
|
||||||
# 4. 图片
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
```
|
|
||||||

|
|
||||||
```
|
|
||||||
|
|
||||||
**实例**
|
|
||||||

|
|
||||||
|
|
||||||
# 5. 超链接
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
```
|
|
||||||
[link-name](link-url)
|
|
||||||
```
|
|
||||||
|
|
||||||
**实例**
|
|
||||||
|
|
||||||
[阿胜4K](http://www.cnblogs.com/asheng2016/)
|
|
||||||
|
|
||||||
# 6. 引用
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
```
|
|
||||||
> 引用本意是引用别人的话之类
|
|
||||||
> 但我个人喜欢把引用当成""注意""使用
|
|
||||||
```
|
|
||||||
|
|
||||||
**实例**
|
|
||||||
|
|
||||||
> If you please draw me a sheep!
|
|
||||||
> 不想当将军的士兵, 不是好士兵.
|
|
||||||
|
|
||||||
# 7. 单行代码
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
```
|
|
||||||
`This is an inline code.`
|
|
||||||
```
|
|
||||||
|
|
||||||
**实例**
|
|
||||||
|
|
||||||
`同样的单行代码, 我经常用来显示特殊名词`
|
|
||||||
|
|
||||||
# 8. 多行代码
|
|
||||||
|
|
||||||
**语法**
|
|
||||||
````
|
|
||||||
```javascript
|
|
||||||
for (var i=0; i<100; i++) {
|
|
||||||
console.log(""hello world"" + i);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
````
|
|
||||||
|
|
||||||
**实例**
|
|
||||||
|
|
||||||
```js
|
|
||||||
for (var i=0; i<100; i++) {
|
|
||||||
console.log(""hello world"" + i);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
也可以通过缩进来显示代码, 下面是示例:
|
|
||||||
|
|
||||||
console.loe(""Hello_World"");
|
|
||||||
|
|
||||||
# 参考链接
|
|
||||||
|
|
||||||
https://guides.github.com/features/mastering-markdown/
|
|
||||||
https://help.github.com/articles/basic-writing-and-formatting-syntax/
|
|
||||||
";
|
";
|
||||||
#region Props
|
#region Props
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue