I am currently calling a HTTP service and getting data returned. The query is the result of calling the chat completions API of Azure Open AI.
我目前正在调用一个HTTP服务并获取返回的数据。该查询是调用Azure Open AI的聊天完成API的结果。
For reference
以供参考
[webappurl]/openai/deployments/gpt35turbo/extensions/chat/completions?api-version=2023-06-01-preview
The reason I'm using the HTTP client approach is that I am connecting to my own datasources rather than everything. The current implementation of Azure.AI.OpenAI
(0.7 Beta) doesn't appear to have properties for Datasources yet even though it is mentioned in the preview documentation.
我使用HTTP客户端方法的原因是我连接到我自己的数据源,而不是连接到所有数据源。Azure.AI.OpenAI(0.7Beta)的当前实现似乎还没有数据源的属性,尽管在预览文档中提到了它。
Some of the response is pasted below (obtained using Fiddler) that I'm getting back from the HTTP request has the following format.
下面粘贴了我从HTTP请求得到的一些响应(使用Fiddler获得),格式如下。
data: {
"id": "**removed**",
"model": "gpt-35-turbo",
"created": 1694376472,
"object": "chat.completion.chunk",
"choices": [
{
"index": 0,
"messages": [
{
"delta": {
"role": "tool",
"content": "{\"citations\": [{\"content\": \"** removed ** "
},
"index": 0,
"end_turn": false
}
],
"finish_reason": null
}
]
}
data: {
"id": "**removed**",
"model": "gpt-35-turbo",
"created": 1694376472,
"object": "chat.completion.chunk",
"choices": [
{
"index": 0,
"messages": [
{
"delta": {
"role": "assistant"
},
"index": 1,
"end_turn": false
}
],
"finish_reason": null
}
]
}
data: {
"id": "**removed**",
"model": "gpt-35-turbo",
"created": 1694376472,
"object": "chat.completion.chunk",
"choices": [
{
"index": 0,
"messages": [
{
"delta": {
"content": ""
},
"index": 1,
"end_turn": false
}
],
"finish_reason": null
}
]
}
I then have the following code to make the request and deal with the response.
然后,我有以下代码来发出请求并处理响应。
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);
var content = new StringContent(body, Encoding.UTF8, "application/json");
request.Content = content;
var response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
CompletionResponse completionResponse = new CompletionResponse();
completionResponse = JsonSerializer.Deserialize<CompletionResponse>(responseBody);
My class file for my model contains the following
我的模型的类文件包含以下内容
public class CompletionResponse
{
[JsonPropertyName("choices")]
public List<ChatGPTChoice>? Choices
{
get;
set;
}
[JsonPropertyName("usage")]
public ChatGPTUsage? Usage
{
get;
set;
}
}
public class ChatGPTUsage
{
[JsonPropertyName("prompt_tokens")]
public int PromptTokens
{
get;
set;
}
[JsonPropertyName("completion_token")]
public int CompletionTokens
{
get;
set;
}
[JsonPropertyName("total_tokens")]
public int TotalTokens
{
get;
set;
}
}
[DebuggerDisplay("Text = {Text}")]
public class ChatGPTChoice
{
[JsonPropertyName("text")]
public string? Text
{
get;
set;
}
}
When I run the app I get to the final line above and get:
当我运行这个应用程序时,我转到上面的最后一行并得到:
System.Text.Json.JsonException: 'd' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
System.Text.Json.JsonReaderException: 'd' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
If I take the response and paste it into a JSON document I get the following expected a JSON object, array or literal.json. It looks to me like the response doesn't contain JSON but I don't understand what is has given me (I'm no expert).
如果我获取响应并将其粘贴到JSON文档中,我会得到以下预期的JSON对象、数组或equal.json。在我看来,响应不包含JSON,但我不明白它给了我什么(我不是专家)。
It will probably be a daft mistake but any pointers greatly appreciate.
这可能是一个愚蠢的错误,但任何指导者都会非常感激。
I've referenced this video:
我参考了这段视频:
https://www.youtube.com/watch?v=Bfls6P7IaDE
Https://www.youtube.com/watch?v=Bfls6P7IaDE
更多回答
If the response body really starts with data:
like that, then it's not valid JSON.
如果响应主体真的以数据开头:就像这样,那么它就不是有效的JSON。
优秀答案推荐
The JSON contains a "data" element. Your class doesn't have that.
JSON包含一个“data”元素。你的班级没有这个。
You can create a new class like
您可以像这样创建一个新类
public class CompletionResponseRoot // awful name, but whatever
{
public CompletionResponse Data { get; set; }
}
Used with the existing type CompletionResponse
, this can deserialize an object with a Data
property that contains the rest of the data you want.
与现有类型CompletionResponse配合使用,可以反序列化具有Data属性的对象,该属性包含所需的其余数据。
There are other properties in your classes that I don't see in the JSON, so I'm not sure what those are for.
您的类中还有其他我在JSON中看不到的属性,所以我不确定这些属性是用来做什么的。
There are also easier ways to generate the C# models for JSON. Visual Studio 2022 has functionality for this
If you Google "paste JSON as code" along with the name of your preferred editor you'll find other options and extensions.
还有一些更简单的方法可以为JSON生成C#模型。如果您在Google上搜索“Paste JSON as code”以及您首选的编辑器的名称,您会发现其他选项和扩展。
You can also use a website like Json2CSharp. If that link goes out of date, just google JSON to CSharp. There are other sites. Paste in your JSON, including the outer brackets, like
你也可以使用像Json2CSharp这样的网站。如果该链接过期,只需谷歌JSON到CSharp。还有其他网站。粘贴到您的JSON中,包括外括号,如
{
data {
// etc
}
}
All of these will produce C# classes you can use to deserialize your JSON. They might not be perfect because they're inferred from the exact JSON you pasted, but they're usually close and often just right. In this case that produces
所有这些都将生成可用于反序列化JSON的C#类。它们可能不是完美的,因为它们是从您粘贴的JSON中推断出来的,但它们通常很接近,而且往往恰到好处。在这种情况下,它产生了
public class Choice
{
public int index { get; set; }
public List<Message> messages { get; set; }
public object finish_reason { get; set; }
}
public class Data
{
public string id { get; set; }
public string model { get; set; }
public int created { get; set; }
public string @object { get; set; }
public List<Choice> choices { get; set; }
}
public class Delta
{
public string role { get; set; }
public string content { get; set; }
}
public class Message
{
public Delta delta { get; set; }
public int index { get; set; }
public bool end_turn { get; set; }
}
public class Root
{
public Data data { get; set; }
}
You can rename the classes and delete parts you don't care about. Deserialize the JSON as type Root
and the rest is magic.
您可以重命名类并删除您不关心的部分。将JSON反序列化为Root类型,剩下的就是魔术了。
JSON syntax requires that all property names be quoted string. The response begins with data:
which is not valid JSON. Everything after that, from the first {
onwards, appears to be valid JSON that should match your DTO.
JSON语法要求所有属性名称都用引号引起来。响应以data:开头,这不是有效的JSON。之后的所有内容,从第一个{开始,似乎都是有效的JSON,应该与您的DTO匹配。
The simple solution is to skip that initial tag and deserialize the rest:
简单解决方案是跳过初始标记并反序列化其余标记:
if (responseBody.StartsWith("data:"))
responseBody = responseBody[5..].TrimStart();
Next, your DTO doesn't match the actual JSON format from the examples. You'll need to fix up the ChatGPTChoice
class to better reflect the structure, with a class each for the messages
array items and the delta
record for each message. What you have at the moment will never capture the details.
接下来,您的DTO与示例中的实际JSON格式不匹配。您需要修复ChatGPTChoice类以更好地反映结构,每个类分别用于消息数组项和每条消息的增量记录。你目前所拥有的永远不会捕捉到细节。
更多回答
我是一名优秀的程序员,十分优秀!