mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat: micro go cli
This commit is contained in:
@@ -8,8 +8,17 @@ export interface ErrorResponse {
|
||||
}
|
||||
|
||||
export const errorMiddleware = new Elysia({ name: 'error' })
|
||||
.onError(({ code, error, set }) => {
|
||||
console.error('[Error]', code, error)
|
||||
.onError(({ code, error, set, request }) => {
|
||||
const url = new URL(request.url)
|
||||
const status = set.status ?? 500
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error('[Error]', {
|
||||
method: request.method,
|
||||
path: url.pathname,
|
||||
code,
|
||||
status,
|
||||
message,
|
||||
})
|
||||
|
||||
switch (code) {
|
||||
case 'VALIDATION':
|
||||
|
||||
+57
-20
@@ -37,6 +37,12 @@ const ScheduleBody = z.object({
|
||||
|
||||
export const chatModule = new Elysia({ prefix: '/chat' })
|
||||
.post('/', async ({ body }) => {
|
||||
console.log('[Chat] request', {
|
||||
type: 'chat',
|
||||
clientType: body.clientType,
|
||||
model: body.model,
|
||||
baseUrl: body.baseUrl,
|
||||
})
|
||||
const { ask } = createAgent({
|
||||
apiKey: body.apiKey,
|
||||
baseUrl: body.baseUrl,
|
||||
@@ -49,14 +55,33 @@ export const chatModule = new Elysia({ prefix: '/chat' })
|
||||
platforms: body.platforms,
|
||||
currentPlatform: body.currentPlatform,
|
||||
})
|
||||
return await ask({
|
||||
messages: body.messages as unknown as ModelMessage[],
|
||||
query: body.query,
|
||||
})
|
||||
try {
|
||||
const result = await ask({
|
||||
messages: body.messages as unknown as ModelMessage[],
|
||||
query: body.query,
|
||||
})
|
||||
console.log('[Chat] response', { type: 'chat', messages: result.messages?.length ?? 0 })
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('[Chat] error', {
|
||||
type: 'chat',
|
||||
clientType: body.clientType,
|
||||
model: body.model,
|
||||
baseUrl: body.baseUrl,
|
||||
error,
|
||||
})
|
||||
throw error
|
||||
}
|
||||
}, {
|
||||
body: ChatBody,
|
||||
})
|
||||
.post('/stream', async function* ({ body }) {
|
||||
console.log('[Chat] request', {
|
||||
type: 'stream',
|
||||
clientType: body.clientType,
|
||||
model: body.model,
|
||||
baseUrl: body.baseUrl,
|
||||
})
|
||||
const { stream } = createAgent({
|
||||
apiKey: body.apiKey,
|
||||
baseUrl: body.baseUrl,
|
||||
@@ -69,23 +94,35 @@ export const chatModule = new Elysia({ prefix: '/chat' })
|
||||
platforms: body.platforms,
|
||||
currentPlatform: body.currentPlatform,
|
||||
})
|
||||
const streanGenerator = stream({
|
||||
messages: body.messages as unknown as ModelMessage[],
|
||||
query: body.query,
|
||||
})
|
||||
while (true) {
|
||||
const chunk = await streanGenerator.next()
|
||||
if (chunk.done) {
|
||||
yield sse({
|
||||
type: 'done',
|
||||
data: chunk.value,
|
||||
})
|
||||
break
|
||||
}
|
||||
yield sse({
|
||||
type: 'delta',
|
||||
data: chunk.value
|
||||
try {
|
||||
const streanGenerator = stream({
|
||||
messages: body.messages as unknown as ModelMessage[],
|
||||
query: body.query,
|
||||
})
|
||||
while (true) {
|
||||
const chunk = await streanGenerator.next()
|
||||
if (chunk.done) {
|
||||
console.log('[Chat] response', { type: 'stream', messages: chunk.value?.messages?.length ?? 0 })
|
||||
yield sse({
|
||||
type: 'done',
|
||||
data: chunk.value,
|
||||
})
|
||||
break
|
||||
}
|
||||
yield sse({
|
||||
type: 'delta',
|
||||
data: chunk.value
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Chat] error', {
|
||||
type: 'stream',
|
||||
clientType: body.clientType,
|
||||
model: body.model,
|
||||
baseUrl: body.baseUrl,
|
||||
error,
|
||||
})
|
||||
throw error
|
||||
}
|
||||
}, {
|
||||
body: ChatBody,
|
||||
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/memohai/memoh/internal/chat"
|
||||
"github.com/memohai/memoh/internal/config"
|
||||
)
|
||||
|
||||
type cliOptions struct {
|
||||
configPath string
|
||||
username string
|
||||
password string
|
||||
timeout time.Duration
|
||||
apiBaseURL string
|
||||
jwtToken string
|
||||
}
|
||||
|
||||
func main() {
|
||||
opts := parseFlags()
|
||||
ctx := context.Background()
|
||||
|
||||
cfg, err := config.Load(opts.configPath)
|
||||
if err != nil {
|
||||
log.Fatalf("load config: %v", err)
|
||||
}
|
||||
if strings.TrimSpace(opts.apiBaseURL) == "" {
|
||||
opts.apiBaseURL = defaultAPIBaseURL(cfg.Server.Addr)
|
||||
}
|
||||
if strings.TrimSpace(opts.apiBaseURL) == "" {
|
||||
log.Fatalf("api url is required")
|
||||
}
|
||||
opts.apiBaseURL = normalizeBaseURL(opts.apiBaseURL)
|
||||
|
||||
jwtToken := strings.TrimSpace(opts.jwtToken)
|
||||
client := &http.Client{Timeout: opts.timeout}
|
||||
if jwtToken == "" {
|
||||
username, password, err := resolveLoginCredentials(opts, cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("resolve login: %v", err)
|
||||
}
|
||||
loginCtx := ctx
|
||||
if opts.timeout > 0 {
|
||||
var cancel context.CancelFunc
|
||||
loginCtx, cancel = context.WithTimeout(ctx, opts.timeout)
|
||||
defer cancel()
|
||||
}
|
||||
jwtToken, err = resolveJWTToken(loginCtx, client, opts.apiBaseURL, username, password)
|
||||
if err != nil {
|
||||
log.Fatalf("resolve jwt: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
query := strings.TrimSpace(strings.Join(flag.Args(), " "))
|
||||
if query != "" {
|
||||
if err := sendChat(ctx, client, opts.apiBaseURL, jwtToken, query); err != nil {
|
||||
log.Fatalf("chat failed: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err := runInteractive(ctx, client, opts.apiBaseURL, jwtToken); err != nil {
|
||||
log.Fatalf("chat failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func parseFlags() cliOptions {
|
||||
var opts cliOptions
|
||||
defaultConfig := os.Getenv("CONFIG_PATH")
|
||||
if strings.TrimSpace(defaultConfig) == "" {
|
||||
defaultConfig = config.DefaultConfigPath
|
||||
}
|
||||
|
||||
flag.StringVar(&opts.configPath, "config", defaultConfig, "Path to config.toml")
|
||||
flag.StringVar(&opts.username, "username", "", "Username for login")
|
||||
flag.StringVar(&opts.password, "password", "", "Password for login (or set MEMOH_PASSWORD)")
|
||||
flag.StringVar(&opts.jwtToken, "jwt", "", "JWT token (optional)")
|
||||
flag.StringVar(&opts.apiBaseURL, "api-url", "", "API server base URL (e.g. http://127.0.0.1:8080)")
|
||||
flag.DurationVar(&opts.timeout, "timeout", 30*time.Second, "Request timeout")
|
||||
flag.Parse()
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func normalizeBaseURL(value string) string {
|
||||
return strings.TrimRight(strings.TrimSpace(value), "/")
|
||||
}
|
||||
|
||||
func defaultAPIBaseURL(addr string) string {
|
||||
trimmed := strings.TrimSpace(addr)
|
||||
if trimmed == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.HasPrefix(trimmed, "http://") || strings.HasPrefix(trimmed, "https://") {
|
||||
return normalizeBaseURL(trimmed)
|
||||
}
|
||||
if strings.HasPrefix(trimmed, ":") {
|
||||
return "http://127.0.0.1" + trimmed
|
||||
}
|
||||
return "http://" + trimmed
|
||||
}
|
||||
|
||||
func resolveLoginCredentials(opts cliOptions, cfg config.Config) (string, string, error) {
|
||||
username := strings.TrimSpace(opts.username)
|
||||
if username == "" {
|
||||
username = strings.TrimSpace(cfg.Admin.Username)
|
||||
}
|
||||
if username == "" {
|
||||
return "", "", fmt.Errorf("username is required for login")
|
||||
}
|
||||
|
||||
password := strings.TrimSpace(opts.password)
|
||||
if password == "" {
|
||||
password = strings.TrimSpace(os.Getenv("MEMOH_PASSWORD"))
|
||||
}
|
||||
if password == "" {
|
||||
if candidate := strings.TrimSpace(cfg.Admin.Password); candidate != "" && candidate != "change-your-password-here" {
|
||||
password = candidate
|
||||
}
|
||||
}
|
||||
if password == "" {
|
||||
return "", "", fmt.Errorf("password is required; pass --password or set MEMOH_PASSWORD")
|
||||
}
|
||||
return username, password, nil
|
||||
}
|
||||
|
||||
func resolveJWTToken(ctx context.Context, client *http.Client, baseURL, username, password string) (string, error) {
|
||||
resp, err := loginForToken(ctx, client, baseURL, username, password)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if strings.TrimSpace(resp.AccessToken) == "" {
|
||||
return "", fmt.Errorf("login succeeded but token missing")
|
||||
}
|
||||
return resp.AccessToken, nil
|
||||
}
|
||||
|
||||
type loginRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type loginResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
UserID string `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
func loginForToken(ctx context.Context, client *http.Client, baseURL, username, password string) (loginResponse, error) {
|
||||
body, err := json.Marshal(loginRequest{
|
||||
Username: username,
|
||||
Password: password,
|
||||
})
|
||||
if err != nil {
|
||||
return loginResponse{}, err
|
||||
}
|
||||
url := normalizeBaseURL(baseURL) + "/auth/login"
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return loginResponse{}, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return loginResponse{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
payload, _ := io.ReadAll(resp.Body)
|
||||
return loginResponse{}, fmt.Errorf("login failed: %s", strings.TrimSpace(string(payload)))
|
||||
}
|
||||
|
||||
var parsed loginResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil {
|
||||
return loginResponse{}, err
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func runInteractive(ctx context.Context, client *http.Client, baseURL, jwtToken string) error {
|
||||
reader := bufio.NewScanner(os.Stdin)
|
||||
reader.Buffer(make([]byte, 0, 64*1024), 2*1024*1024)
|
||||
|
||||
fmt.Fprint(os.Stdout, "You: ")
|
||||
for reader.Scan() {
|
||||
line := strings.TrimSpace(reader.Text())
|
||||
if line == "" {
|
||||
fmt.Fprint(os.Stdout, "You: ")
|
||||
continue
|
||||
}
|
||||
lower := strings.ToLower(line)
|
||||
if lower == "exit" || lower == "quit" {
|
||||
return nil
|
||||
}
|
||||
if err := sendChat(ctx, client, baseURL, jwtToken, line); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(os.Stdout, "You: ")
|
||||
}
|
||||
return reader.Err()
|
||||
}
|
||||
|
||||
func sendChat(ctx context.Context, client *http.Client, baseURL, jwtToken, query string) error {
|
||||
return streamAPIChat(ctx, client, baseURL, jwtToken, chat.ChatRequest{Query: query})
|
||||
}
|
||||
|
||||
func streamAPIChat(ctx context.Context, client *http.Client, baseURL, jwtToken string, req chat.ChatRequest) error {
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url := baseURL + "/chat/stream"
|
||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
httpReq.Header.Set("Accept", "text/event-stream")
|
||||
httpReq.Header.Set("Authorization", "Bearer "+jwtToken)
|
||||
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
payload, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("api server error: %s", strings.TrimSpace(string(payload)))
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
scanner.Buffer(make([]byte, 0, 64*1024), 2*1024*1024)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "event:") {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(line, "data:") {
|
||||
continue
|
||||
}
|
||||
data := strings.TrimSpace(strings.TrimPrefix(line, "data:"))
|
||||
if data == "" || data == "[DONE]" {
|
||||
break
|
||||
}
|
||||
if text, ok := extractStreamText([]byte(data)); ok {
|
||||
fmt.Fprint(os.Stdout, text)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(os.Stdout)
|
||||
return nil
|
||||
}
|
||||
|
||||
func renderMessageContent(raw interface{}) (string, bool) {
|
||||
switch v := raw.(type) {
|
||||
case string:
|
||||
return v, true
|
||||
case []interface{}:
|
||||
parts := make([]string, 0, len(v))
|
||||
for _, item := range v {
|
||||
if text, ok := renderMessageContent(item); ok && strings.TrimSpace(text) != "" {
|
||||
parts = append(parts, text)
|
||||
}
|
||||
}
|
||||
if len(parts) > 0 {
|
||||
return strings.Join(parts, ""), true
|
||||
}
|
||||
case map[string]interface{}:
|
||||
if text, ok := v["text"].(string); ok && strings.TrimSpace(text) != "" {
|
||||
return text, true
|
||||
}
|
||||
if text, ok := v["content"].(string); ok && strings.TrimSpace(text) != "" {
|
||||
return text, true
|
||||
}
|
||||
if kind, ok := v["type"].(string); ok && kind == "text" {
|
||||
if text, ok := v["text"].(string); ok {
|
||||
return text, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func extractStreamText(raw []byte) (string, bool) {
|
||||
var payload interface{}
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
return "", false
|
||||
}
|
||||
return extractTextFromPayload(payload)
|
||||
}
|
||||
|
||||
func extractTextFromPayload(payload interface{}) (string, bool) {
|
||||
switch v := payload.(type) {
|
||||
case string:
|
||||
if strings.TrimSpace(v) == "" {
|
||||
return "", false
|
||||
}
|
||||
return v, true
|
||||
case []interface{}:
|
||||
parts := make([]string, 0, len(v))
|
||||
for _, item := range v {
|
||||
if text, ok := extractTextFromPayload(item); ok && strings.TrimSpace(text) != "" {
|
||||
parts = append(parts, text)
|
||||
}
|
||||
}
|
||||
if len(parts) > 0 {
|
||||
return strings.Join(parts, ""), true
|
||||
}
|
||||
case map[string]interface{}:
|
||||
if text, ok := v["textDelta"].(string); ok && strings.TrimSpace(text) != "" {
|
||||
return text, true
|
||||
}
|
||||
if text, ok := v["text"].(string); ok && strings.TrimSpace(text) != "" {
|
||||
return text, true
|
||||
}
|
||||
if content, ok := v["content"]; ok {
|
||||
if text, ok := renderMessageContent(content); ok {
|
||||
return text, true
|
||||
}
|
||||
}
|
||||
if delta, ok := v["delta"]; ok {
|
||||
if text, ok := extractTextFromPayload(delta); ok {
|
||||
return text, true
|
||||
}
|
||||
}
|
||||
if data, ok := v["data"]; ok {
|
||||
if text, ok := extractTextFromPayload(data); ok {
|
||||
return text, true
|
||||
}
|
||||
}
|
||||
if msg, ok := v["message"]; ok {
|
||||
if text, ok := extractTextFromPayload(msg); ok {
|
||||
return text, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
+4
-12
@@ -959,20 +959,12 @@ const docTemplate = `{
|
||||
},
|
||||
"/models/enable-as/{enableAs}": {
|
||||
"get": {
|
||||
"description": "Get the model that is enabled for a specific purpose (chat, memory, embedding)\nGet the default model configured for a specific purpose (chat, memory, or embedding)",
|
||||
"description": "Get the model that is enabled for a specific purpose (chat, memory, embedding)",
|
||||
"tags": [
|
||||
"models",
|
||||
"models"
|
||||
],
|
||||
"summary": "Get default model by enable_as",
|
||||
"summary": "Get model by enable_as",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Enable as value (chat, memory, embedding)",
|
||||
"name": "enableAs",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Enable as value (chat, memory, embedding)",
|
||||
@@ -2499,11 +2491,11 @@ const docTemplate = `{
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "",
|
||||
Version: "1.0.0",
|
||||
Host: "",
|
||||
BasePath: "",
|
||||
Schemes: []string{},
|
||||
Title: "",
|
||||
Title: "Memoh API",
|
||||
Description: "",
|
||||
InfoInstanceName: "swagger",
|
||||
SwaggerTemplate: docTemplate,
|
||||
|
||||
+5
-11
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"contact": {}
|
||||
"title": "Memoh API",
|
||||
"contact": {},
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/auth/login": {
|
||||
@@ -948,20 +950,12 @@
|
||||
},
|
||||
"/models/enable-as/{enableAs}": {
|
||||
"get": {
|
||||
"description": "Get the model that is enabled for a specific purpose (chat, memory, embedding)\nGet the default model configured for a specific purpose (chat, memory, or embedding)",
|
||||
"description": "Get the model that is enabled for a specific purpose (chat, memory, embedding)",
|
||||
"tags": [
|
||||
"models",
|
||||
"models"
|
||||
],
|
||||
"summary": "Get default model by enable_as",
|
||||
"summary": "Get model by enable_as",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Enable as value (chat, memory, embedding)",
|
||||
"name": "enableAs",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Enable as value (chat, memory, embedding)",
|
||||
|
||||
+5
-10
@@ -499,6 +499,8 @@ definitions:
|
||||
type: object
|
||||
info:
|
||||
contact: {}
|
||||
title: Memoh API
|
||||
version: 1.0.0
|
||||
paths:
|
||||
/auth/login:
|
||||
post:
|
||||
@@ -1210,15 +1212,9 @@ paths:
|
||||
- models
|
||||
/models/enable-as/{enableAs}:
|
||||
get:
|
||||
description: |-
|
||||
Get the model that is enabled for a specific purpose (chat, memory, embedding)
|
||||
Get the default model configured for a specific purpose (chat, memory, or embedding)
|
||||
description: Get the model that is enabled for a specific purpose (chat, memory,
|
||||
embedding)
|
||||
parameters:
|
||||
- description: Enable as value (chat, memory, embedding)
|
||||
in: path
|
||||
name: enableAs
|
||||
required: true
|
||||
type: string
|
||||
- description: Enable as value (chat, memory, embedding)
|
||||
in: path
|
||||
name: enableAs
|
||||
@@ -1241,10 +1237,9 @@ paths:
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.ErrorResponse'
|
||||
summary: Get default model by enable_as
|
||||
summary: Get model by enable_as
|
||||
tags:
|
||||
- models
|
||||
- models
|
||||
/models/model/{modelId}:
|
||||
delete:
|
||||
description: Delete a model configuration by its model_id field (e.g., gpt-4)
|
||||
|
||||
@@ -7,7 +7,6 @@ require (
|
||||
github.com/containerd/containerd/api v1.10.0
|
||||
github.com/containerd/containerd/v2 v2.2.1
|
||||
github.com/containerd/errdefs v1.0.0
|
||||
github.com/firebase/genkit/go v1.4.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jackc/pgx/v5 v5.8.0
|
||||
@@ -25,8 +24,6 @@ require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.14.0-rc.1 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.1.2 // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
@@ -53,22 +50,17 @@ require (
|
||||
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
|
||||
github.com/goccy/go-yaml v1.17.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/dotprompt/go v0.0.0-20251014011017-8d056e027254 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/jsonschema-go v0.3.0 // indirect
|
||||
github.com/invopop/jsonschema v0.13.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/klauspost/compress v1.18.3 // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
@@ -83,17 +75,12 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect
|
||||
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.39.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/mod v0.32.0 // indirect
|
||||
|
||||
@@ -10,10 +10,6 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/Microsoft/hcsshim v0.14.0-rc.1 h1:qAPXKwGOkVn8LlqgBN8GS0bxZ83hOJpcjxzmlQKxKsQ=
|
||||
github.com/Microsoft/hcsshim v0.14.0-rc.1/go.mod h1:hTKFGbnDtQb1wHiOWv4v0eN+7boSWAHyK/tNAaYZL0c=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -57,8 +53,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/firebase/genkit/go v1.4.0 h1:CP1hNWk7z0hosyY53zMH6MFKFO1fMLtj58jGPllQo6I=
|
||||
github.com/firebase/genkit/go v1.4.0/go.mod h1:HX6m7QOaGc3MDNr/DrpQZrzPLzxeuLxrkTvfFtCYlGw=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -70,7 +64,7 @@ github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmG
|
||||
github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
|
||||
github.com/go-openapi/spec v0.22.3 h1:qRSmj6Smz2rEBxMnLRBMeBWxbbOvuOoElvSvObIgwQc=
|
||||
github.com/go-openapi/spec v0.22.3/go.mod h1:iIImLODL2loCh3Vnox8TY2YWYJZjMAKYyLH2Mu8lOZs=
|
||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
|
||||
github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
|
||||
github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
|
||||
@@ -91,8 +85,6 @@ github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxE
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
|
||||
github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
|
||||
github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
@@ -113,8 +105,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/dotprompt/go v0.0.0-20251014011017-8d056e027254 h1:okN800+zMJOGHLJCgry+OGzhhtH6YrjQh1rluHmOacE=
|
||||
github.com/google/dotprompt/go v0.0.0-20251014011017-8d056e027254/go.mod h1:k8cjJAQWc//ac/bMnzItyOFbfT01tgRTZGgxELCuxEQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@@ -128,8 +118,6 @@ github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
@@ -152,14 +140,10 @@ github.com/labstack/echo/v4 v4.15.0 h1:hoRTKWcnR5STXZFe9BmYun9AMTNeSbjHi2vtDuADJ
|
||||
github.com/labstack/echo/v4 v4.15.0/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
|
||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a h1:v2cBA3xWKv2cIOVhnzX/gNgkNXqiHfUgJtA3r61Hf7A=
|
||||
github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a/go.mod h1:Y6ghKH+ZijXn5d9E7qGGZBmjitx7iitZdQiIW97EpTU=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||
@@ -212,15 +196,6 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -241,8 +216,6 @@ go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2W
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
||||
@@ -62,6 +62,7 @@ func (r *Resolver) Chat(ctx context.Context, req ChatRequest) (ChatResponse, err
|
||||
if strings.TrimSpace(req.UserID) == "" {
|
||||
return ChatResponse{}, fmt.Errorf("user id is required")
|
||||
}
|
||||
skipHistory := req.MaxContextLoadTime < 0
|
||||
|
||||
chatModel, provider, err := r.selectChatModel(ctx, req)
|
||||
if err != nil {
|
||||
@@ -83,9 +84,12 @@ func (r *Resolver) Chat(ctx context.Context, req ChatRequest) (ChatResponse, err
|
||||
language = req.Language
|
||||
}
|
||||
|
||||
messages, err := r.loadHistoryMessages(ctx, req.UserID, maxContextLoadTime)
|
||||
if err != nil {
|
||||
return ChatResponse{}, err
|
||||
var messages []GatewayMessage
|
||||
if !skipHistory {
|
||||
messages, err = r.loadHistoryMessages(ctx, req.UserID, maxContextLoadTime)
|
||||
if err != nil {
|
||||
return ChatResponse{}, err
|
||||
}
|
||||
}
|
||||
if len(req.Messages) > 0 {
|
||||
messages = append(messages, req.Messages...)
|
||||
@@ -142,6 +146,7 @@ func (r *Resolver) StreamChat(ctx context.Context, req ChatRequest) (<-chan Stre
|
||||
errChan <- fmt.Errorf("user id is required")
|
||||
return
|
||||
}
|
||||
skipHistory := req.MaxContextLoadTime < 0
|
||||
|
||||
chatModel, provider, err := r.selectChatModel(ctx, req)
|
||||
if err != nil {
|
||||
@@ -166,10 +171,13 @@ func (r *Resolver) StreamChat(ctx context.Context, req ChatRequest) (<-chan Stre
|
||||
language = req.Language
|
||||
}
|
||||
|
||||
messages, err := r.loadHistoryMessages(ctx, req.UserID, maxContextLoadTime)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
var messages []GatewayMessage
|
||||
if !skipHistory {
|
||||
messages, err = r.loadHistoryMessages(ctx, req.UserID, maxContextLoadTime)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(req.Messages) > 0 {
|
||||
messages = append(messages, req.Messages...)
|
||||
@@ -225,6 +233,7 @@ func (r *Resolver) postChat(ctx context.Context, payload agentGatewayRequest) (a
|
||||
return agentGatewayResponse{}, err
|
||||
}
|
||||
url := r.gatewayBaseURL + "/chat"
|
||||
fmt.Println("url", url)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return agentGatewayResponse{}, err
|
||||
|
||||
@@ -257,15 +257,6 @@ func (h *ModelsHandler) DeleteByModelID(c echo.Context) error {
|
||||
// @Failure 404 {object} ErrorResponse
|
||||
// @Failure 500 {object} ErrorResponse
|
||||
// @Router /models/enable-as/{enableAs} [get]
|
||||
// GetByEnableAs godoc
|
||||
// @Summary Get default model by enable_as
|
||||
// @Description Get the default model configured for a specific purpose (chat, memory, or embedding)
|
||||
// @Tags models
|
||||
// @Param enableAs path string true "Enable as value (chat, memory, embedding)"
|
||||
// @Success 200 {object} models.GetResponse
|
||||
// @Failure 400 {object} ErrorResponse
|
||||
// @Failure 404 {object} ErrorResponse
|
||||
// @Router /models/enable-as/{enableAs} [get]
|
||||
func (h *ModelsHandler) GetByEnableAs(c echo.Context) error {
|
||||
enableAs := c.Param("enableAs")
|
||||
if enableAs == "" {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package handlers
|
||||
|
||||
// @title Memoh API
|
||||
// @version 1.0.0
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@elysiajs/eden": "^1.4.6",
|
||||
"@memoh/api": "workspace:*",
|
||||
"@memoh/shared": "workspace:*",
|
||||
"elysia": "latest",
|
||||
"commander": "^12.1.0",
|
||||
|
||||
Generated
+16
-3290
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user