using Dpz.Core.Entity.Base;
using Markdig;
using Markdig.Syntax;
namespace Dpz.Core.Service.Network.Models;
/// <summary>
/// Chat Completion API 响应
/// </summary>
[Obsolete("use IOpenAiService")]
public class ChatCompletionResponse
{
[JsonPropertyName("id")]
public string Id { get; set; } = string.Empty;
[JsonPropertyName("object")]
public string Object { get; set; } = string.Empty;
[JsonPropertyName("created")]
public long Created { get; set; }
[JsonPropertyName("model")]
public string Model { get; set; } = string.Empty;
[JsonPropertyName("provider")]
public string? Provider { get; set; }
[JsonPropertyName("choices")]
public List<CompletionChoice> Choices { get; set; } = [];
[JsonPropertyName("usage")]
public Usage? Usage { get; set; }
public ResponseResult<T?> Analyze<T>()
where T : new()
{
var result = new ResponseResult<T?>();
T? t;
var content = Choices.Count > 0 ? Choices[0].Message.Content : "";
try
{
var pipeline = new MarkdownPipelineBuilder()
.UseAutoLinks()
.UsePipeTables()
.UseTaskLists()
.UseEmphasisExtras()
.UseAutoIdentifiers()
.Build();
var document = Markdown.Parse(content, pipeline);
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var codeBlocks = document.Descendants<CodeBlock>().ToList();
var jsonText = ExtractJsonFromCodeBlocks(codeBlocks);
jsonText ??= ExtractFirstJsonPayload(content);
jsonText ??= content;
t = JsonSerializer.Deserialize<T>(jsonText, options);
}
catch (Exception e)
{
result.Arguments = [content];
return result.WithFail(e.Message);
}
return result.WithOk(t);
}
private static string? ExtractJsonFromCodeBlocks(IEnumerable<CodeBlock> codeBlocks)
{
var blocks = codeBlocks.ToList();
if (blocks.Count == 0)
{
return null;
}
foreach (var codeBlock in blocks)
{
var fenced = codeBlock as FencedCodeBlock;
var info = fenced?.Info ?? string.Empty;
if (info.Trim().Equals("json", StringComparison.OrdinalIgnoreCase))
{
var text = codeBlock.Lines.ToString();
if (!string.IsNullOrWhiteSpace(text))
{
return text;
}
}
}
foreach (var codeBlock in blocks)
{
var text = codeBlock.Lines.ToString();
if (!string.IsNullOrWhiteSpace(text))
{
return text;
}
}
return null;
}
private static string? ExtractFirstJsonPayload(string content)
{
if (string.IsNullOrWhiteSpace(content))
{
return null;
}
var trimmed = content.Trim();
var objectIndex = trimmed.IndexOf('{');
var arrayIndex = trimmed.IndexOf('[');
var startIndex = -1;
if (objectIndex >= 0 && arrayIndex >= 0)
{
startIndex = Math.Min(objectIndex, arrayIndex);
}
else if (objectIndex >= 0)
{
startIndex = objectIndex;
}
else if (arrayIndex >= 0)
{
startIndex = arrayIndex;
}
if (startIndex < 0)
{
return null;
}
var candidate = trimmed[startIndex..];
for (var length = candidate.Length; length > 0; length--)
{
var slice = candidate[..length];
try
{
JsonDocument.Parse(slice);
return slice;
}
catch (JsonException)
{
// ignore
}
}
return null;
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个用于处理 OpenAI Chat Completion API 响应的 C# 模型类,主要功能是解析 API 响应并从中提取结构化数据。
主要组成部分
1. 类定义与属性
[Obsolete("use IOpenAiService")]
public class ChatCompletionResponse
- 标记为已过时,建议使用
IOpenAiService - 包含 Chat Completion API 的标准响应字段:
Id: 响应唯一标识Object: 对象类型Created: 创建时间戳Model: 使用的模型名称Provider: 提供商(可选)Choices: 生成的回复选项列表Usage: 使用情况统计
2. 核心方法:Analyze<T>()
这是类的核心功能,用于从 AI 响应中提取并反序列化 JSON 数据:
工作流程:
- 获取第一个选项的消息内容
- 使用 Markdig 解析 Markdown 格式
- 按优先级尝试提取 JSON:
- 首先从代码块(code blocks)中提取
- 如果失败,尝试从原始内容中提取 JSON
- 最后使用完整内容
- 将提取的 JSON 反序列化为泛型类型
T - 返回
ResponseResult<T?>包装的结果
3. 辅助方法:ExtractJsonFromCodeBlocks()
从 Markdown 代码块中提取 JSON:
- 优先查找标记为
json的代码块 - 如果没有,返回第一个非空代码块内容
- 如果都没有,返回
null
4. 辅助方法:ExtractFirstJsonPayload()
从普通文本中智能提取 JSON 数据:
- 查找第一个
{或[字符的位置 - 从该位置开始,逐步尝试解析不同长度的子串
- 使用
JsonDocument.Parse()验证 JSON 有效性 - 返回第一个有效的 JSON 字符串
使用场景
这个类特别适用于处理 AI 返回的非结构化文本,例如:
这是一些解释文字...
```json
{
"name": "John",
"age": 30
}
更多说明...
能够智能提取其中的 JSON 数据并转换为强类型对象,增强了与 AI API 交互的健壮性。
AI 正在分析代码…
评论加载中...