uncloseai.com/languages/vbnet/UncloseAI.vb
Russell Ballestrini 9e3eccb1b9 modified: .gitignore
modified:   CLAUDE.md
	modified:   Makefile
	new file:   languages/awk/Dockerfile
	new file:   languages/awk/uncloseai.awk
	modified:   languages/bash/Dockerfile
	deleted:    languages/bash/examples.sh
	new file:   languages/bash/uncloseai.sh
	new file:   languages/c/curl/Dockerfile
	new file:   languages/c/curl/Makefile
	new file:   languages/c/curl/index.html
	new file:   languages/c/curl/uncloseai.c
	new file:   languages/c/libh2o/Dockerfile
	new file:   languages/c/libh2o/Makefile
	new file:   languages/c/libh2o/uncloseai.c
	new file:   languages/c/nghttp2/Dockerfile
	new file:   languages/c/nghttp2/Makefile
	new file:   languages/c/nghttp2/uncloseai.c
	new file:   languages/clojure/Dockerfile
	new file:   languages/clojure/deps.edn
	new file:   languages/clojure/uncloseai.clj
	new file:   languages/cobol/Dockerfile
	new file:   languages/cobol/discover.sh
	new file:   languages/cobol/hermes.sh
	new file:   languages/cobol/qwen.sh
	new file:   languages/cobol/tts.sh
	new file:   languages/cobol/uncloseai.cob
	new file:   languages/cpp/boost-beast/Dockerfile
	new file:   languages/cpp/boost-beast/Makefile
	new file:   languages/cpp/boost-beast/uncloseai.cpp
	new file:   languages/cpp/cpp-httplib/Dockerfile
	new file:   languages/cpp/cpp-httplib/Makefile
	new file:   languages/cpp/cpp-httplib/uncloseai.cpp
	new file:   languages/cpp/libcurl/Dockerfile
	new file:   languages/cpp/libcurl/Makefile
	new file:   languages/cpp/libcurl/uncloseai.cpp
	new file:   languages/crystal/Dockerfile
	new file:   languages/crystal/uncloseai.cr
	new file:   languages/csharp/Dockerfile
	new file:   languages/csharp/Uncloseai.cs
	new file:   languages/csharp/csharp.csproj
	new file:   languages/dart/Dockerfile
	new file:   languages/dart/bin/uncloseai.dart
	new file:   languages/dart/pubspec.yaml
	new file:   languages/deno/Dockerfile
	new file:   languages/deno/uncloseai.ts
	new file:   languages/elixir/Dockerfile
	new file:   languages/elixir/lib/uncloseai.ex
	new file:   languages/elixir/mix.exs
	new file:   languages/elixir/run.exs
	new file:   languages/erlang/Dockerfile
	new file:   languages/erlang/rebar.config
	new file:   languages/erlang/src/uncloseai.app.src
	new file:   languages/erlang/src/uncloseai.erl
	new file:   languages/fortran/Dockerfile
	new file:   languages/fortran/uncloseai.f90
	new file:   languages/fsharp/Dockerfile
	new file:   languages/fsharp/Uncloseai.fs
	new file:   languages/fsharp/fsharp.fsproj
	new file:   languages/go/Dockerfile
	new file:   languages/go/README.md
	new file:   languages/go/examples/basic.go
	new file:   languages/go/go.mod
	new file:   languages/go/uncloseai.go
	new file:   languages/go/uncloseai/uncloseai.go
	new file:   languages/haskell/Dockerfile
	new file:   languages/haskell/UncloseAI.hs
	new file:   languages/haskell/uncloseai.cabal
	new file:   languages/java/Dockerfile
	new file:   languages/java/UncloseAI.java
	new file:   languages/javascript/bun/Dockerfile
	new file:   languages/javascript/bun/uncloseai.ts
	new file:   languages/javascript/nodejs/Dockerfile
	new file:   languages/javascript/nodejs/README.md
	new file:   languages/javascript/nodejs/package.json
	new file:   languages/javascript/nodejs/uncloseai.js
	new file:   languages/javascript/typescript/Dockerfile
	new file:   languages/javascript/typescript/package.json
	new file:   languages/javascript/typescript/tsconfig.json
	new file:   languages/javascript/typescript/uncloseai.ts
	new file:   languages/javascript/vanilla/Dockerfile
	new file:   languages/javascript/vanilla/uncloseai.html
	new file:   languages/julia/Dockerfile
	new file:   languages/julia/Project.toml
	new file:   languages/julia/src/uncloseai.jl
	new file:   languages/kotlin/Dockerfile
	new file:   languages/kotlin/build.gradle.kts
	new file:   languages/kotlin/src/main/kotlin/UncloseAI.kt
	new file:   languages/kotlin/uncloseai.kt
	new file:   languages/lua/Dockerfile
	new file:   languages/lua/uncloseai.lua
	new file:   languages/nim/Dockerfile
	new file:   languages/nim/uncloseai.nim
	new file:   languages/ocaml/Dockerfile
	new file:   languages/ocaml/dune
	new file:   languages/ocaml/dune-project
	new file:   languages/ocaml/uncloseai.ml
	new file:   languages/odin/Dockerfile
	new file:   languages/odin/uncloseai.odin
	new file:   languages/perl/Dockerfile
	new file:   languages/perl/uncloseai.pl
	new file:   languages/php/Dockerfile
	new file:   languages/php/uncloseai.php
	new file:   languages/powershell/Dockerfile
	new file:   languages/powershell/uncloseai.ps1
	new file:   languages/prolog/Dockerfile
	new file:   languages/prolog/uncloseai.pl
	new file:   languages/python/aiohttp/Dockerfile
	new file:   languages/python/aiohttp/requirements.txt
	new file:   languages/python/aiohttp/uncloseai.py
	modified:   languages/python/httpx-async/Dockerfile
	deleted:    languages/python/httpx-async/examples.py
	new file:   languages/python/httpx-async/uncloseai.py
	modified:   languages/python/openai-client/Dockerfile
	deleted:    languages/python/openai-client/examples.py
	new file:   languages/python/openai-client/uncloseai.py
	modified:   languages/python/requests/Dockerfile
	deleted:    languages/python/requests/examples.py
	new file:   languages/python/requests/uncloseai.py
	new file:   languages/r/Dockerfile
	new file:   languages/r/uncloseai.R
	new file:   languages/ruby/Dockerfile
	new file:   languages/ruby/README.md
	new file:   languages/ruby/uncloseai.rb
	new file:   languages/rust/Cargo.toml
	new file:   languages/rust/Dockerfile
	new file:   languages/rust/README.md
	new file:   languages/rust/examples/basic.rs
	new file:   languages/rust/src/lib.rs
	new file:   languages/rust/src/uncloseai.rs
	new file:   languages/scala/Dockerfile
	new file:   languages/scala/build.sbt
	new file:   languages/scala/project/build.properties
	new file:   languages/scala/project/plugins.sbt
	new file:   languages/scala/src/main/scala/UncloseAI.scala
	new file:   languages/tcl/Dockerfile
	new file:   languages/tcl/uncloseai.tcl
	new file:   languages/v/Dockerfile
	new file:   languages/v/uncloseai.v
	new file:   languages/v/v.mod
	new file:   languages/vbnet/Dockerfile
	new file:   languages/vbnet/UncloseAI.vb
	new file:   languages/vbnet/UncloseAI.vbproj
	modified:   languages/zig/Dockerfile
	modified:   languages/zig/build.zig
	deleted:    languages/zig/src/main.zig
	new file:   languages/zig/src/uncloseai.zig
2025-10-14 10:24:16 -04:00

336 lines
13 KiB
VB.net

' UncloseAI - VB.NET client for OpenAI-compatible APIs with streaming support
Imports System
Imports System.Net.Http
Imports System.Text
Imports System.Threading.Tasks
Imports System.Text.Json
Imports System.IO
Imports System.Collections.Generic
Imports System.Linq
Public Class ChatMessage
Public Property Role As String
Public Property Content As String
End Class
Public Class ModelInfo
Public Property Id As String
Public Property Endpoint As String
Public Property MaxTokens As Integer
End Class
Public Class UncloseAI
Private ReadOnly models As List(Of ModelInfo)
Private ReadOnly ttsEndpoints As List(Of String)
Private ReadOnly apiKey As String
Private ReadOnly timeout As Integer
Private ReadOnly debug As Boolean
Private ReadOnly httpClient As HttpClient
Public Sub New(Optional endpoints As List(Of String) = Nothing,
Optional ttsEps As List(Of String) = Nothing,
Optional key As String = "",
Optional tm As Integer = 30,
Optional dbg As Boolean = False)
Me.apiKey = key
Me.timeout = tm
Me.debug = dbg
Me.httpClient = New HttpClient()
Me.httpClient.Timeout = TimeSpan.FromSeconds(tm)
' Discover endpoints from environment if not provided
Dim modelEnds = If(endpoints Is Nothing OrElse endpoints.Count = 0,
DiscoverEnvEndpoints("MODEL_ENDPOINT"),
endpoints)
Dim ttsEnds = If(ttsEps Is Nothing OrElse ttsEps.Count = 0,
DiscoverEnvEndpoints("TTS_ENDPOINT"),
ttsEps)
If debug Then
Console.WriteLine($"[DEBUG] Initialized with {modelEnds.Count} endpoint(s)")
End If
Me.models = DiscoverModels(modelEnds).GetAwaiter().GetResult()
Me.ttsEndpoints = ttsEnds
End Sub
Private Shared Function DiscoverEnvEndpoints(prefix As String) As List(Of String)
Dim endpoints As New List(Of String)()
For i As Integer = 1 To 9999
Dim endpoint = Environment.GetEnvironmentVariable($"{prefix}_{i}")
If String.IsNullOrEmpty(endpoint) Then Exit For
endpoints.Add(endpoint)
Next
Return endpoints
End Function
Private Async Function DiscoverModels(endpoints As List(Of String)) As Task(Of List(Of ModelInfo))
Dim modelList As New List(Of ModelInfo)()
For Each endpoint In endpoints
If debug Then
Console.WriteLine($"[DEBUG] Discovering from: {endpoint}")
End If
Try
Dim response = Await httpClient.GetAsync($"{endpoint}/models")
Dim json = Await response.Content.ReadAsStringAsync()
' Parse JSON to find models
Dim doc = JsonDocument.Parse(json)
Dim data = doc.RootElement.GetProperty("data")
For Each model In data.EnumerateArray()
Dim modelId = model.GetProperty("id").GetString()
' Skip permission entries
If Not modelId.StartsWith("modelperm-") AndAlso Not modelId.StartsWith("chatcmpl-") Then
Dim maxTokens = 8192
Dim maxTokensProp As JsonElement
If model.TryGetProperty("max_model_len", maxTokensProp) Then
maxTokens = maxTokensProp.GetInt32()
End If
modelList.Add(New ModelInfo With {
.Id = modelId,
.Endpoint = endpoint,
.MaxTokens = maxTokens
})
If debug Then
Console.WriteLine($"[DEBUG] Discovered: {modelId}")
End If
End If
Next
Catch ex As Exception
If debug Then
Console.WriteLine($"[DEBUG] Error: {ex.Message}")
End If
End Try
Next
Return modelList
End Function
Public Function ListModels() As List(Of ModelInfo)
Return models
End Function
Private Function ResolveModel(modelId As String) As ModelInfo
If models.Count = 0 Then
Throw New Exception("No models available")
End If
If String.IsNullOrEmpty(modelId) Then
Return models(0)
End If
For Each model In models
If model.Id = modelId Then
Return model
End If
Next
Throw New Exception($"Model '{modelId}' not found")
End Function
Public Async Function Chat(messages As List(Of ChatMessage),
Optional modelId As String = "",
Optional maxTokens As Integer = 100,
Optional temperature As Double = 0.7) As Task(Of String)
Dim model = ResolveModel(modelId)
Dim request = New With {
.model = model.Id,
.messages = messages.Select(Function(m) New With {.role = m.Role, .content = m.Content}).ToArray(),
.max_tokens = maxTokens,
.temperature = temperature,
.stream = False
}
Dim jsonRequest = JsonSerializer.Serialize(request)
Dim content = New StringContent(jsonRequest, Encoding.UTF8, "application/json")
If Not String.IsNullOrEmpty(apiKey) Then
httpClient.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Bearer", apiKey)
End If
Dim response = Await httpClient.PostAsync($"{model.Endpoint}/chat/completions", content)
Dim result = Await response.Content.ReadAsStringAsync()
Return result
End Function
Public Async Function ChatStream(messages As List(Of ChatMessage),
callback As Action(Of String),
Optional modelId As String = "",
Optional maxTokens As Integer = 500,
Optional temperature As Double = 0.7) As Task
Dim model = ResolveModel(modelId)
Dim request = New With {
.model = model.Id,
.messages = messages.Select(Function(m) New With {.role = m.Role, .content = m.Content}).ToArray(),
.max_tokens = maxTokens,
.temperature = temperature,
.stream = True
}
Dim jsonRequest = JsonSerializer.Serialize(request)
Dim content = New StringContent(jsonRequest, Encoding.UTF8, "application/json")
If Not String.IsNullOrEmpty(apiKey) Then
httpClient.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Bearer", apiKey)
End If
Try
Dim httpRequest = New HttpRequestMessage(HttpMethod.Post, $"{model.Endpoint}/chat/completions")
httpRequest.Content = content
Using response = Await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead)
Using stream = Await response.Content.ReadAsStreamAsync()
Using reader = New StreamReader(stream)
While Not reader.EndOfStream
Dim line = Await reader.ReadLineAsync()
If Not String.IsNullOrEmpty(line) AndAlso line.StartsWith("data: ") Then
Dim data = line.Substring(6).Trim()
If data = "[DONE]" Then Exit While
Try
Dim doc = JsonDocument.Parse(data)
Dim choices = doc.RootElement.GetProperty("choices")
If choices.GetArrayLength() > 0 Then
Dim choice = choices(0)
If choice.TryGetProperty("delta", Nothing) Then
Dim delta = choice.GetProperty("delta")
If delta.TryGetProperty("content", Nothing) Then
Dim contentText = delta.GetProperty("content").GetString()
If Not String.IsNullOrEmpty(contentText) Then
callback(contentText)
End If
End If
End If
End If
Catch
' Ignore parse errors
End Try
End If
End While
End Using
End Using
End Using
Catch ex As Exception
If debug Then
Console.WriteLine($"[DEBUG] Stream error: {ex.Message}")
End If
End Try
End Function
Public Async Function Tts(text As String,
Optional voice As String = "alloy",
Optional model As String = "tts-1",
Optional format As String = "mp3") As Task(Of Byte())
If ttsEndpoints.Count = 0 Then
Throw New Exception("No TTS endpoints available")
End If
Dim endpoint = ttsEndpoints(0)
Dim request = New With {
.model = model,
.voice = voice,
.input = text,
.response_format = format
}
Dim jsonRequest = JsonSerializer.Serialize(request)
Dim content = New StringContent(jsonRequest, Encoding.UTF8, "application/json")
If Not String.IsNullOrEmpty(apiKey) Then
httpClient.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Bearer", apiKey)
End If
Dim response = Await httpClient.PostAsync($"{endpoint}/audio/speech", content)
Dim audioBytes = Await response.Content.ReadAsByteArrayAsync()
Return audioBytes
End Function
End Class
' Demo when run as application
Module Program
Sub Main(args As String())
MainAsync(args).GetAwaiter().GetResult()
End Sub
Private Async Function MainAsync(args As String()) As Task
Console.WriteLine("=== UncloseAI VB.NET Client (with Streaming) ===")
Console.WriteLine()
Dim client = New UncloseAI(dbg:=True)
If client.ListModels().Count = 0 Then
Console.WriteLine("ERROR: No models discovered. Set environment variables:")
Console.WriteLine(" MODEL_ENDPOINT_1, MODEL_ENDPOINT_2, etc.")
Return
End If
Console.WriteLine()
Console.WriteLine($"Discovered {client.ListModels().Count} model(s):")
For Each model In client.ListModels()
Console.WriteLine($" - {model.Id} (max_tokens: {model.MaxTokens})")
Next
Console.WriteLine()
' Non-streaming chat
Console.WriteLine("=== Non-Streaming Chat ===")
Try
Dim messages = New List(Of ChatMessage) From {
New ChatMessage With {.Role = "system", .Content = "You are a helpful AI assistant."},
New ChatMessage With {.Role = "user", .Content = "Explain quantum computing in one sentence."}
}
Dim response = Await client.Chat(messages)
Dim doc = JsonDocument.Parse(response)
Dim content = doc.RootElement.GetProperty("choices")(0).GetProperty("message").GetProperty("content").GetString()
Console.WriteLine($"Response: {content}")
Console.WriteLine()
Catch ex As Exception
Console.WriteLine($"Error: {ex.Message}")
Console.WriteLine()
End Try
' Streaming chat
Console.WriteLine("=== Streaming Chat ===")
Dim modelId = If(client.ListModels().Count > 1, client.ListModels()(1).Id, "")
Dim modelName = If(String.IsNullOrEmpty(modelId), client.ListModels()(0).Id, modelId)
Console.WriteLine($"Model: {modelName}")
Console.Write("Response: ")
Dim streamMessages = New List(Of ChatMessage) From {
New ChatMessage With {.Role = "system", .Content = "You are a coding assistant."},
New ChatMessage With {.Role = "user", .Content = "Write a VB.NET function to check if a number is prime"}
}
Await client.ChatStream(streamMessages, Sub(content) Console.Write(content), modelId, 200)
Console.WriteLine()
Console.WriteLine()
' TTS
Console.WriteLine("=== TTS Speech Generation ===")
Try
Dim audioData = Await client.Tts("Hello from UncloseAI VB.NET client! This demonstrates streaming support.")
File.WriteAllBytes("speech.mp3", audioData)
Console.WriteLine($"✓ Speech file created: speech.mp3 ({audioData.Length} bytes)")
Console.WriteLine()
Catch ex As Exception
Console.WriteLine($"✗ TTS Error: {ex.Message}")
Console.WriteLine()
End Try
Console.WriteLine("=== Examples Complete ===")
End Function
End Module