feat(httpapi): 添加模型名称字段并创建查询模型命令工具
- 在 modelResponse 结构体中添加 Name 字段用于返回模型名称 - 实现 handleModels 接口返回模型的名称信息 - 创建 query-models 命令行工具用于查询和展示模型列表 - 实现 IPC 连接和模型数据提取功能 - 添加模型 ID 和场景键识别逻辑 - 支持多种模型字段映射和遍历解析
This commit is contained in:
151
cmd/query-models/main.go
Normal file
151
cmd/query-models/main.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"lingma-ipc-proxy/internal/lingmaipc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// 使用自动发现的传输方式
|
||||
opts, err := lingmaipc.ResolveDialOptions(lingmaipc.TransportAuto, "", "")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to resolve dial options: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Connecting to Lingma IPC...\n")
|
||||
fmt.Printf("Transport: %s\n", opts.Transport)
|
||||
fmt.Printf("PipePath: %s\n", opts.PipePath)
|
||||
fmt.Printf("WebSocketURL: %s\n", opts.WebSocketURL)
|
||||
fmt.Println()
|
||||
|
||||
client, err := lingmaipc.Connect(ctx, opts)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// 初始化
|
||||
if err := client.Request(ctx, "initialize", map[string]any{
|
||||
"protocolVersion": 1,
|
||||
"clientCapabilities": map[string]any{},
|
||||
"timestamp": time.Now().UnixMilli(),
|
||||
}, nil); err != nil {
|
||||
log.Fatalf("Failed to initialize: %v", err)
|
||||
}
|
||||
fmt.Println("Initialized successfully")
|
||||
fmt.Println()
|
||||
|
||||
// 查询模型
|
||||
var raw any
|
||||
if err := client.Request(ctx, "config/queryModels", map[string]any{}, &raw); err != nil {
|
||||
log.Fatalf("Failed to query models: %v", err)
|
||||
}
|
||||
|
||||
// 打印原始结果
|
||||
fmt.Println("=== Raw IPC Response ===")
|
||||
rawJSON, _ := json.MarshalIndent(raw, "", " ")
|
||||
fmt.Println(string(rawJSON))
|
||||
fmt.Println()
|
||||
|
||||
// 提取并打印模型列表
|
||||
fmt.Println("=== Extracted Models ===")
|
||||
models := extractModels(raw)
|
||||
for _, m := range models {
|
||||
fmt.Printf("ID: %s, Name: %s, Scene: %s\n", m.ID, m.Name, m.Scene)
|
||||
}
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
ID string
|
||||
Name string
|
||||
Scene string
|
||||
}
|
||||
|
||||
func extractModels(raw any) []Model {
|
||||
seen := make(map[string]Model)
|
||||
var walk func(scene string, value any)
|
||||
walk = func(scene string, value any) {
|
||||
switch typed := value.(type) {
|
||||
case map[string]any:
|
||||
id := firstString(typed, "id", "modelId", "key")
|
||||
name := firstString(typed, "name", "label", "displayName", "title")
|
||||
currentScene := scene
|
||||
if currentScene == "" {
|
||||
currentScene = firstString(typed, "scene", "sceneId", "category")
|
||||
}
|
||||
if id != "" && (name != "" || likelyModelID(id)) {
|
||||
if name == "" {
|
||||
name = id
|
||||
}
|
||||
seen[id] = Model{ID: id, Name: name, Scene: currentScene}
|
||||
}
|
||||
for key, child := range typed {
|
||||
nextScene := currentScene
|
||||
if nextScene == "" || isSceneKey(key) {
|
||||
nextScene = key
|
||||
}
|
||||
walk(nextScene, child)
|
||||
}
|
||||
case []any:
|
||||
for _, item := range typed {
|
||||
walk(scene, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk("", raw)
|
||||
|
||||
models := make([]Model, 0, len(seen))
|
||||
for _, model := range seen {
|
||||
models = append(models, model)
|
||||
}
|
||||
return models
|
||||
}
|
||||
|
||||
func likelyModelID(id string) bool {
|
||||
lowered := id
|
||||
return contains(lowered, "qwen") || contains(lowered, "model") || contains(lowered, "auto") || contains(lowered, "coder")
|
||||
}
|
||||
|
||||
func isSceneKey(key string) bool {
|
||||
switch key {
|
||||
case "assistant", "chat", "developer", "inline", "quest":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func firstString(m map[string]any, keys ...string) string {
|
||||
for _, key := range keys {
|
||||
if value, ok := m[key]; ok {
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
if typed != "" {
|
||||
return typed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
|
||||
}
|
||||
|
||||
func containsHelper(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -43,6 +43,7 @@ type modelResponse struct {
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
OwnedBy string `json:"owned_by"`
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func NewServer(addr string, svc *service.Service) *Server {
|
||||
@@ -122,6 +123,7 @@ func (s *Server) handleModels(w http.ResponseWriter, r *http.Request) {
|
||||
Object: "model",
|
||||
Created: created,
|
||||
OwnedBy: "lingma",
|
||||
Name: model.Name,
|
||||
})
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
|
||||
Reference in New Issue
Block a user