Supports chat, tools, streaming, audio, and image inputs with flexible request extensions.
$ dotnet add package ChatGPTSharpModern C# client for chat, tools, streaming, and multimodal messages (image/audio). It supports ConversationId-based continuity, flexible request extensions, and manual control when you need it.
IAsyncEnumerableExtraBody dotnet add package ChatGPTSharp
using ChatGPTSharp;
using ChatGPTSharp.Model;
var settings = new ChatGPTClientSettings
{
OpenAIKey = File.ReadAllText("KEY.txt"),
ModelName = "gpt-4o-mini"
};
var client = new ChatGPTClient(settings);
var result = await client.SendMessage(new List<MessageContent>
{
MessageContent.FromText("Hello!")
});
Console.WriteLine(result.Response);
Use SendMessageWithConversation to record history and return ConversationId + MessageId.
var first = await client.SendMessageWithConversation(new List<MessageContent>
{
MessageContent.FromText("Hello!")
});
var second = await client.SendMessageWithConversation(
new List<MessageContent> { MessageContent.FromText("Continue the conversation") },
conversationId: first.ConversationId ?? "",
parentMessageId: first.MessageId ?? "");
Console.WriteLine(second.Response);
Use CreateSession to keep state without manually passing ConversationId and MessageId.
It also supports a simplified content call without building List<MessageContent>.
var session = client.CreateSession(systemPrompt: "You are a concise assistant.");
var first = await session.SendAsync("Hello!");
var second = await session.SendAsync("Continue the conversation.");
var multimodal = await session.SendAsync(
"Describe this image.",
MessageContent.FromImageUrl("https://example.com/demo.png"));
Console.WriteLine(second.Response);
var result = await client.SendMessage(
new List<MessageContent> { MessageContent.FromText("Summarize this in one sentence.") },
systemPrompt: "You are a concise assistant.");
var contents = new List<MessageContent>
{
MessageContent.FromText("Describe these images"),
MessageContent.FromImageFile(@"C:\Images\demo.jpg", ImageDetailMode.Low),
MessageContent.FromImageUrl("https://example.com/demo.png", ImageDetailMode.Auto)
};
var result = await client.SendMessage(contents);
var contents = new List<MessageContent>
{
MessageContent.FromText("Transcribe this audio"),
MessageContent.FromAudioUrl("https://example.com/sample.mp3"),
MessageContent.FromAudioFile(@"C:\Audio\sample.mp3", "audio/mpeg")
};
var result = await client.SendMessage(contents);
await foreach (var evt in client.SendMessageStream(new List<MessageContent>
{
MessageContent.FromText("Tell me a story")
}))
{
if (evt.IsDone)
{
Console.WriteLine("\n[done]");
break;
}
if (!string.IsNullOrEmpty(evt.DeltaText))
{
Console.Write(evt.DeltaText);
}
}
Define a tool schema, send a request, then execute the tool and return its result.
using System.Text.Json.Nodes;
var weatherSchema = JsonNode.Parse(@"{
\"type\": \"object\",
\"properties\": {
\"city\": { \"type\": \"string\" }
},
\"required\": [\"city\"]
}") as JsonObject;
var tools = new List<ToolDefinition>
{
ToolDefinition.CreateFunction(new ToolFunctionDefinition(
"get_weather",
"Get current weather",
weatherSchema))
};
var toolResult = await client.SendMessage(
new List<MessageContent> { MessageContent.FromText("What's the weather in Paris?") },
tools: tools);
if (toolResult.ToolCalls?.Count > 0)
{
var call = toolResult.ToolCalls[0];
var args = JsonNode.Parse(call.Function.Arguments) as JsonObject;
var city = args?["city"]?.GetValue<string>();
// Your tool execution
var weather = new JsonObject
{
["city"] = city,
["tempC"] = 18
};
// Continue with manual message list
var messages = new List<ChatMessage>
{
new ChatMessage
{
Role = RoleType.User,
Contents = new List<MessageContent> { MessageContent.FromText("What's the weather in Paris?") }
},
new ChatMessage { Role = RoleType.Assistant, ToolCalls = toolResult.ToolCalls },
new ChatMessage
{
Role = RoleType.Tool,
ToolCallId = call.Id,
Contents = new List<MessageContent> { MessageContent.FromText(weather.ToString()) }
}
};
var followup = await client.SendAsync(new ChatRequest
{
Messages = messages,
Tools = tools
});
Console.WriteLine(followup.Message?.GetTextContent());
}
The Responses API supports server-side state via conversation or previous_response_id, and built-in tools.
using System.Text.Json.Nodes;
var response = await client.CreateResponseAsync(new ResponseRequest
{
Instructions = "You are concise.",
Input = MessageContent.BuildResponseInput(RoleType.User, new List<MessageContent>
{
MessageContent.FromText("Summarize this in one sentence.")
}),
Store = true,
Tools = new List<ResponseTool>
{
ResponseTool.BuiltIn("web_search")
}
});
Console.WriteLine(response.GetOutputText());
Create a conversation on the server and keep adding items:
var convo = await client.CreateConversationAsync();
var items = MessageContent.BuildResponseInput(RoleType.User, new List<MessageContent>
{
MessageContent.FromText("Remember this preference: I like short answers.")
});
await client.AddConversationItemsAsync(convo.Id ?? "", items);
var followup = await client.CreateResponseAsync(new ResponseRequest
{
ConversationId = convo.Id,
Input = MessageContent.BuildResponseInput(RoleType.User, new List<MessageContent>
{
MessageContent.FromText("What should you remember?")
})
});
Console.WriteLine(followup.GetOutputText());
var extra = new Dictionary<string, object?>
{
["response_format"] = new { type = "json_object" }
};
var result = await client.SendMessage(
new List<MessageContent> { MessageContent.FromText("Return JSON with fields a and b") },
extraBody: extra);
You can also set defaults:
settings.ExtraBody = new Dictionary<string, object?>
{
["response_format"] = new { type = "json_object" }
};
Use SendAsync and StreamAsync with a ChatRequest when you want full control over messages.
var request = new ChatRequest
{
Model = "gpt-4o-mini",
Messages = new List<ChatMessage>
{
new ChatMessage
{
Role = RoleType.System,
Contents = new List<MessageContent> { MessageContent.FromText("You are concise.") }
},
new ChatMessage
{
Role = RoleType.User,
Contents = new List<MessageContent> { MessageContent.FromText("Explain async streams.") }
}
}
};
var response = await client.SendAsync(request);
Console.WriteLine(response.Message?.GetTextContent());
var settings = new ChatGPTClientSettings
{
OpenAIKey = File.ReadAllText("KEY.txt"),
ModelName = "gpt-4o-mini",
BaseUrl = "https://api.openai.com/",
ProxyUri = "http://127.0.0.1:1080",
TimeoutSeconds = 60
};
Notes:
BaseUrl and ProxyUri can be used to route requests. BaseUrl may include /v1 and will still resolve correctly.This code base references node-chatgpt-api.