增强 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:
lihanbo 2025-02-28 16:34:55 +08:00
parent 78d65a6aff
commit 8f42b5e5a7
8 changed files with 121 additions and 162 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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. 12Excel公式
4. 4.
5. 使 5. 使
6.
{DateTime.Now} {DateTime.Now}
@ -26,6 +27,5 @@ namespace ExcelHelper.AI
{msg} {msg}
"; ";
}
} }
} }

View File

@ -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();
}
}

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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.
****
```
![img-name](img-url)
```
****
![logo](https://news.cnblogs.com/images/logo.gif)
# 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]