using System.Net.Http.Json; using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; namespace SynorCompute; /// /// Synor Compute SDK - C# Client /// /// Access distributed heterogeneous compute resources (CPU, GPU, TPU, NPU, LPU, FPGA, DSP) /// for AI/ML workloads at 90% cost reduction compared to traditional cloud. /// /// /// /// // Create client /// using var client = new SynorComputeClient("your-api-key"); /// /// // Matrix multiplication on GPU /// var a = Tensor.Rand(512, 512); /// var b = Tensor.Rand(512, 512); /// var result = await client.MatMulAsync(a, b, new MatMulOptions /// { /// Processor = ProcessorType.Gpu, /// Precision = Precision.Fp16 /// }); /// /// if (result.IsSuccess) /// { /// Console.WriteLine($"Time: {result.ExecutionTimeMs}ms"); /// } /// /// // LLM inference /// var response = await client.InferenceAsync("llama-3-70b", "Explain quantum computing"); /// Console.WriteLine(response.Result); /// /// // Streaming inference /// await foreach (var token in client.InferenceStreamAsync("llama-3-70b", "Write a poem")) /// { /// Console.Write(token); /// } /// /// public sealed class SynorComputeClient : IDisposable { public const string Version = "0.1.0"; private readonly SynorConfig _config; private readonly HttpClient _httpClient; private readonly JsonSerializerOptions _jsonOptions; private bool _disposed; public SynorComputeClient(string apiKey) : this(new SynorConfig { ApiKey = apiKey }) { } public SynorComputeClient(SynorConfig config) { _config = config; _httpClient = new HttpClient { BaseAddress = new Uri(config.BaseUrl), Timeout = TimeSpan.FromMilliseconds(config.TimeoutMs) }; _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {config.ApiKey}"); _httpClient.DefaultRequestHeaders.Add("X-SDK-Version", $"csharp/{Version}"); _jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, PropertyNameCaseInsensitive = true }; } // ==================== Matrix Operations ==================== public Task> MatMulAsync(Tensor a, Tensor b, CancellationToken ct = default) => MatMulAsync(a, b, new MatMulOptions(), ct); public async Task> MatMulAsync( Tensor a, Tensor b, MatMulOptions options, CancellationToken ct = default) { CheckDisposed(); var body = new { operation = "matmul", a = TensorToDict(a), b = TensorToDict(b), precision = options.Precision.ToString().ToLower(), processor = options.Processor.ToString().ToLower(), priority = options.Priority.ToString().ToLower() }; return await PostAsync>("/compute", body, ct); } public async Task> Conv2dAsync( Tensor input, Tensor kernel, Conv2dOptions? options = null, CancellationToken ct = default) { CheckDisposed(); options ??= new Conv2dOptions(); var body = new { operation = "conv2d", input = TensorToDict(input), kernel = TensorToDict(kernel), stride = new[] { options.Stride.Item1, options.Stride.Item2 }, padding = new[] { options.Padding.Item1, options.Padding.Item2 }, precision = options.Precision.ToString().ToLower() }; return await PostAsync>("/compute", body, ct); } public async Task> AttentionAsync( Tensor query, Tensor key, Tensor value, AttentionOptions? options = null, CancellationToken ct = default) { CheckDisposed(); options ??= new AttentionOptions(); var body = new { operation = "attention", query = TensorToDict(query), key = TensorToDict(key), value = TensorToDict(value), num_heads = options.NumHeads, flash = options.Flash, precision = options.Precision.ToString().ToLower() }; return await PostAsync>("/compute", body, ct); } // ==================== LLM Inference ==================== public Task> InferenceAsync(string model, string prompt, CancellationToken ct = default) => InferenceAsync(model, prompt, new InferenceOptions(), ct); public async Task> InferenceAsync( string model, string prompt, InferenceOptions options, CancellationToken ct = default) { CheckDisposed(); var body = new Dictionary { ["operation"] = "inference", ["model"] = model, ["prompt"] = prompt, ["max_tokens"] = options.MaxTokens, ["temperature"] = options.Temperature, ["top_p"] = options.TopP, ["top_k"] = options.TopK }; if (options.Processor.HasValue) { body["processor"] = options.Processor.Value.ToString().ToLower(); } return await PostAsync>("/inference", body, ct); } public async IAsyncEnumerable InferenceStreamAsync( string model, string prompt, InferenceOptions? options = null, [EnumeratorCancellation] CancellationToken ct = default) { CheckDisposed(); options ??= new InferenceOptions(); var body = new Dictionary { ["operation"] = "inference", ["model"] = model, ["prompt"] = prompt, ["max_tokens"] = options.MaxTokens, ["temperature"] = options.Temperature, ["stream"] = true }; var request = new HttpRequestMessage(HttpMethod.Post, "/inference/stream") { Content = JsonContent.Create(body, options: _jsonOptions) }; using var response = await _httpClient.SendAsync( request, HttpCompletionOption.ResponseHeadersRead, ct); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(ct); using var reader = new StreamReader(stream); while (!reader.EndOfStream && !ct.IsCancellationRequested) { var line = await reader.ReadLineAsync(ct); if (line == null) break; if (line.StartsWith("data: ")) { var data = line[6..]; if (data == "[DONE]") yield break; try { var json = JsonSerializer.Deserialize>(data, _jsonOptions); if (json?.TryGetValue("token", out var token) == true) { yield return token.GetString() ?? ""; } } catch (JsonException) { // Skip malformed JSON } } } } // ==================== Model Registry ==================== public async Task> ListModelsAsync( ModelCategory? category = null, CancellationToken ct = default) { CheckDisposed(); var url = category.HasValue ? $"/models?category={category.Value.ToString().ToLower()}" : "/models"; var response = await GetAsync(url, ct); var models = response.GetProperty("models"); return models.Deserialize>(_jsonOptions) ?? new List(); } public async Task GetModelAsync(string modelId, CancellationToken ct = default) { CheckDisposed(); return await GetAsync($"/models/{modelId}", ct); } public async Task> SearchModelsAsync(string query, CancellationToken ct = default) { CheckDisposed(); var response = await GetAsync($"/models/search?q={Uri.EscapeDataString(query)}", ct); var models = response.GetProperty("models"); return models.Deserialize>(_jsonOptions) ?? new List(); } // ==================== Pricing & Usage ==================== public async Task> GetPricingAsync(CancellationToken ct = default) { CheckDisposed(); var response = await GetAsync("/pricing", ct); var pricing = response.GetProperty("pricing"); return pricing.Deserialize>(_jsonOptions) ?? new List(); } public async Task GetUsageAsync(CancellationToken ct = default) { CheckDisposed(); return await GetAsync("/usage", ct); } // ==================== Health Check ==================== public async Task HealthCheckAsync(CancellationToken ct = default) { try { var response = await GetAsync("/health", ct); return response.GetProperty("status").GetString() == "healthy"; } catch { return false; } } // ==================== Internal Methods ==================== private async Task GetAsync(string path, CancellationToken ct) { var response = await _httpClient.GetAsync(path, ct); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync(_jsonOptions, ct) ?? throw new SynorException("Failed to deserialize response"); } private async Task PostAsync(string path, object body, CancellationToken ct) { var response = await _httpClient.PostAsJsonAsync(path, body, _jsonOptions, ct); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync(_jsonOptions, ct) ?? throw new SynorException("Failed to deserialize response"); } private static object TensorToDict(Tensor tensor) => new { shape = tensor.Shape, data = tensor.Data, dtype = tensor.Dtype.ToString().ToLower() }; private void CheckDisposed() { ObjectDisposedException.ThrowIf(_disposed, this); } public void Dispose() { if (!_disposed) { _disposed = true; _httpClient.Dispose(); } } }