2026-06-08 10:39:11 -05:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Net.Http.Json;
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
|
|
2026-06-08 15:18:19 -05:00
|
|
|
namespace finder2e_foundry_converter.Services
|
2026-06-08 10:39:11 -05:00
|
|
|
{
|
2026-06-08 15:53:40 -05:00
|
|
|
public class LmStudioService : ILlmService
|
2026-06-08 10:39:11 -05:00
|
|
|
{
|
|
|
|
|
private readonly HttpClient _httpClient = new HttpClient();
|
|
|
|
|
|
|
|
|
|
public async Task<List<string>> GetModelsAsync(string baseUrl)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var response = await _httpClient.GetFromJsonAsync<ModelsResponse>($"{baseUrl.TrimEnd('/')}/v1/models");
|
|
|
|
|
if (response?.Data == null) return new List<string>();
|
|
|
|
|
|
|
|
|
|
var models = new List<string>();
|
|
|
|
|
foreach (var model in response.Data)
|
|
|
|
|
{
|
|
|
|
|
models.Add(model.Id);
|
|
|
|
|
}
|
|
|
|
|
return models;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return new List<string> { "Error: LM Studio not found" };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<string> GenerateResponseAsync(string baseUrl, string model, string text, List<string> imagePaths)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var contents = new List<object>
|
|
|
|
|
{
|
|
|
|
|
new { type = "text", text = text }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
foreach (var path in imagePaths)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(path)) continue;
|
|
|
|
|
|
|
|
|
|
var bytes = await System.IO.File.ReadAllBytesAsync(path);
|
|
|
|
|
var base64 = Convert.ToBase64String(bytes);
|
|
|
|
|
var extension = System.IO.Path.GetExtension(path).ToLower();
|
|
|
|
|
var mimeType = extension switch
|
|
|
|
|
{
|
|
|
|
|
".jpg" or ".jpeg" => "image/jpeg",
|
|
|
|
|
".webp" => "image/webp",
|
|
|
|
|
_ => "image/png"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
contents.Add(new
|
|
|
|
|
{
|
|
|
|
|
type = "image_url",
|
|
|
|
|
image_url = new { url = $"data:{mimeType};base64,{base64}" }
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var requestBody = new
|
|
|
|
|
{
|
|
|
|
|
model = model,
|
|
|
|
|
messages = new[]
|
|
|
|
|
{
|
|
|
|
|
new { role = "user", content = contents }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var response = await _httpClient.PostAsJsonAsync($"{baseUrl.TrimEnd('/')}/v1/chat/completions", requestBody);
|
|
|
|
|
var body = await response.Content.ReadAsStringAsync();
|
|
|
|
|
|
|
|
|
|
using var doc = JsonDocument.Parse(body);
|
|
|
|
|
if (doc.RootElement.TryGetProperty("error", out var error))
|
|
|
|
|
{
|
|
|
|
|
return $"Error: {error.GetProperty("message").GetString()}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doc.RootElement.TryGetProperty("choices", out var choices) && choices.GetArrayLength() > 0)
|
|
|
|
|
{
|
|
|
|
|
return choices[0].GetProperty("message").GetProperty("content").GetString() ?? "No content returned";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "No response choices returned.";
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return $"Error: {ex.Message}";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class ModelsResponse
|
|
|
|
|
{
|
|
|
|
|
[JsonPropertyName("data")]
|
|
|
|
|
public List<ModelData>? Data { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class ModelData
|
|
|
|
|
{
|
|
|
|
|
[JsonPropertyName("id")]
|
|
|
|
|
public string Id { get; set; } = string.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|