added support for non-default lm studio api addresses

This commit is contained in:
grimsace
2026-06-03 13:22:44 -05:00
parent 82f30fe812
commit 00c32d5cbe
2 changed files with 123 additions and 39 deletions
+1
View File
@@ -34,3 +34,4 @@ go.work.sum
TODO
/binaries/
converter
+122 -39
View File
@@ -4,14 +4,17 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"image/color"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/driver/desktop"
@@ -20,27 +23,81 @@ import (
)
func main() {
myApp := app.New()
myApp := app.NewWithID("finder2e_foundry_converter")
myWindow := myApp.NewWindow("Finder2e Foundry Converter")
// LLM Provider Selection
providerSelect := widget.NewSelect([]string{"LM Studio"}, func(s string) {
fmt.Printf("Provider changed to: %s\n", s)
})
providerSelect.SetSelected("LM Studio")
prefs := myApp.Preferences()
// LM Studio Integration
modelSelect := widget.NewSelect([]string{"Loading models..."}, nil)
savedAddr := prefs.StringWithFallback("LMStudioAddress", "http://localhost:1234")
addrEntry := widget.NewEntry()
addrEntry.SetText(savedAddr)
addrEntry.SetPlaceHolder("LM Studio URL (e.g. http://192.168.1.10:1234)")
addrEntry.OnChanged = func(s string) {
prefs.SetString("LMStudioAddress", s)
}
addrContainer := container.NewVBox(
widget.NewLabel("LM Studio Address:"),
addrEntry,
)
addrContainer.Hide()
// LLM Provider Selection
var toggleAddrBtn *widget.Button
savedProvider := prefs.StringWithFallback("SelectedProvider", "LM Studio")
providerSelect := widget.NewSelect([]string{"LM Studio"}, func(s string) {
fmt.Printf("Provider changed to: %s\n", s)
prefs.SetString("SelectedProvider", s)
if s == "LM Studio" {
toggleAddrBtn.Show()
} else {
toggleAddrBtn.Hide()
addrContainer.Hide()
}
})
addrManuallyOpened := false
toggleAddrBtn = widget.NewButton("Address", func() {
if addrContainer.Visible() {
addrContainer.Hide()
addrManuallyOpened = false
} else {
addrContainer.Show()
addrManuallyOpened = true
}
})
providerSelect.SetSelected(savedProvider)
errorLabel := canvas.NewText("Error: LM Studio not found. Retrying...", color.NRGBA{R: 255, G: 0, B: 0, A: 255})
errorLabel.Alignment = fyne.TextAlignCenter
errorLabel.Hide()
modelSelect := widget.NewSelect([]string{"Loading models..."}, func(s string) {
if s != "" && !strings.HasPrefix(s, "Loading") && !strings.HasPrefix(s, "Error") && !strings.HasPrefix(s, "No models") {
prefs.SetString("LastSelectedModel", s)
}
})
modelSelect.PlaceHolder = "Select Model"
refreshModels := func() {
if providerSelect.Selected != "LM Studio" {
fyne.Do(func() {
errorLabel.Hide()
})
return
}
resp, err := http.Get("http://localhost:1234/v1/models")
currentAddr := strings.TrimSuffix(addrEntry.Text, "/")
resp, err := http.Get(fmt.Sprintf("%s/v1/models", currentAddr))
if err != nil {
modelSelect.Options = []string{"Error: LM Studio not found"}
modelSelect.Refresh()
fyne.Do(func() {
modelSelect.Options = []string{"Error: LM Studio not found"}
modelSelect.Refresh()
errorLabel.Show()
errorLabel.Refresh()
addrContainer.Show() // Auto-show on failure
})
return
}
defer resp.Body.Close()
@@ -51,8 +108,10 @@ func main() {
} `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
modelSelect.Options = []string{"Error decoding models"}
modelSelect.Refresh()
fyne.Do(func() {
modelSelect.Options = []string{"Error decoding models"}
modelSelect.Refresh()
})
return
}
@@ -63,12 +122,46 @@ func main() {
if len(models) == 0 {
models = []string{"No models loaded in LM Studio"}
}
modelSelect.Options = models
modelSelect.Refresh()
fyne.Do(func() {
errorLabel.Hide()
errorLabel.Refresh()
modelSelect.Options = models
modelSelect.Refresh()
lastModel := prefs.String("LastSelectedModel")
if lastModel != "" && (modelSelect.Selected == "" || modelSelect.Selected == "Loading models...") {
for _, m := range models {
if m == lastModel {
modelSelect.SetSelected(m)
break
}
}
}
if !addrManuallyOpened {
addrContainer.Hide()
}
})
}
// Initial fetch
go refreshModels()
// Retry logic: Refresh models every 3 seconds with countdown
go func() {
for {
refreshModels()
if errorLabel.Visible() {
for i := 3; i > 0; i-- {
fyne.Do(func() {
errorLabel.Text = fmt.Sprintf("Error: LM Studio not found. Retrying in %d...", i)
errorLabel.Refresh()
})
time.Sleep(1 * time.Second)
}
} else {
time.Sleep(3 * time.Second)
}
}
}()
textEntry := widget.NewMultiLineEntry()
textEntry.SetPlaceHolder("Enter description here...")
@@ -76,10 +169,12 @@ func main() {
imagePathsContainer := container.NewVBox()
addImageEntry := func(path string) {
newEntry := widget.NewEntry()
newEntry.SetText(path)
imagePathsContainer.Add(newEntry)
imagePathsContainer.Refresh()
fyne.Do(func() {
newEntry := widget.NewEntry()
newEntry.SetText(path)
imagePathsContainer.Add(newEntry)
imagePathsContainer.Refresh()
})
}
isImage := func(ext string) bool {
@@ -134,22 +229,7 @@ func main() {
}
})
generateButton := widget.NewButton("Generate", func() {
if modelSelect.Selected == "" {
dialog.ShowInformation("Selection Required", "Please select a model first.", myWindow)
return
}
if providerSelect.Selected == "LM Studio" {
fmt.Printf("Sending request to LM Studio (%s)...\n", modelSelect.Selected)
// ... (rest of the existing LM Studio generation logic remains below)
}
})
// (I'll keep the actual generation logic block to keep the edit clean)
// Actually, I should include it to ensure the code is complete.
// RE-IMPLEMENTING the generate button with provider check:
generateButton := widget.NewButton("Generate", nil)
generateButton.OnTapped = func() {
if modelSelect.Selected == "" {
dialog.ShowInformation("Selection Required", "Please select a model first.", myWindow)
@@ -157,7 +237,8 @@ func main() {
}
if providerSelect.Selected == "LM Studio" {
fmt.Printf("Sending request to LM Studio (%s)...\n", modelSelect.Selected)
currentAddr := strings.TrimSuffix(addrEntry.Text, "/")
fmt.Printf("Sending request to LM Studio at %s (%s)...\n", currentAddr, modelSelect.Selected)
// Prepare messages
type MessageContent struct {
@@ -202,7 +283,7 @@ func main() {
"messages": []interface{}{map[string]interface{}{"role": "user", "content": content}},
})
resp, err := http.Post("http://localhost:1234/v1/chat/completions", "application/json", strings.NewReader(string(requestBody)))
resp, err := http.Post(fmt.Sprintf("%s/v1/chat/completions", currentAddr), "application/json", strings.NewReader(string(requestBody)))
if err != nil {
fmt.Printf("Error calling LM Studio: %v\n", err)
return
@@ -246,7 +327,9 @@ func main() {
content := container.NewVBox(
widget.NewLabel("Provider:"),
providerSelect,
container.NewBorder(nil, nil, nil, toggleAddrBtn, providerSelect),
errorLabel,
addrContainer,
widget.NewLabel("Model:"),
container.NewBorder(nil, nil, nil, widget.NewButton("Refresh", refreshModels), modelSelect),
widget.NewLabel("Description:"),