basic llm request stream

This commit is contained in:
fabien committed 2026-09-22 21:15:23 +02:00
1 parent f74e4d1043
commit a92cc76a9a
66 files changed
+1496 -158

No files matched your search

+7 -7
View File
@@ -42,7 +42,7 @@ func (h *AgentHandler) ListAgents(c *echo.Context) error {
teamID := c.Param("space")
agents, err := h.agentService.ListAgents(userID, teamID)
if err != nil {
c.Logger().Error("error listing agents", err)
c.Logger().Error("error listing agents", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error listing agents")
}
return c.JSON(http.StatusOK, agents)
@@ -54,7 +54,7 @@ func (h *AgentHandler) GetAgent(c *echo.Context) error {
agentID := c.Param("agent")
agent, err := h.agentService.GetAgent(userID, teamID, agentID)
if err != nil {
c.Logger().Error("error getting agent: %s", err)
c.Logger().Error("error getting agent", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error getting agent")
}
return c.JSON(http.StatusOK, agent)
@@ -66,13 +66,13 @@ func (h *AgentHandler) CreateAgent(c *echo.Context) error {
var agent domain.Agent
err := c.Bind(&agent)
if err != nil {
c.Logger().Error("error binding agent : %s", err)
c.Logger().Error("error binding agent", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error binding agent")
}
agent.TeamID = teamID
updagent, err := h.agentService.CreateAgent(userID, &agent)
if err != nil {
c.Logger().Error("error creating agent: %s", err)
c.Logger().Error("error creating agent", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error creating agent")
}
return c.JSON(http.StatusOK, updagent)
@@ -84,13 +84,13 @@ func (h *AgentHandler) UpdateAgent(c *echo.Context) error {
var agent domain.Agent
err := c.Bind(&agent)
if err != nil {
c.Logger().Error("error binding agent : %s", err)
c.Logger().Error("error binding agent", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error binding agent")
}
agent.TeamID = teamID
updagent, err := h.agentService.UpdateAgent(userID, &agent)
if err != nil {
c.Logger().Error("error updating agent: %s", err)
c.Logger().Error("error updating agent", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error updating agent")
}
return c.JSON(http.StatusOK, updagent)
@@ -102,7 +102,7 @@ func (h *AgentHandler) DeleteAgent(c *echo.Context) error {
agentID := c.Param("agent")
err := h.agentService.DeleteAgent(userID, teamID, agentID)
if err != nil {
c.Logger().Error("error creating agent: %s", err)
c.Logger().Error("error creating agent", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error creating agent")
}
return c.JSON(http.StatusOK, agentID)
+182
View File
@@ -0,0 +1,182 @@
package handlers
import (
"encoding/json"
"log/slog"
"net/http"
"strconv"
"github.com/labstack/echo/v5"
"trankilou.fr/lassistanoque/backend/internal/domain"
"trankilou.fr/lassistanoque/backend/internal/service/auth"
"trankilou.fr/lassistanoque/backend/internal/service/chat"
)
func NewChatGroup(prefix string, e *echo.Group, service *chat.Service, middlewares ...echo.MiddlewareFunc) *echo.Group {
chatHandler := &ChatHandler{
chatService: service,
}
auth := e.Group(prefix, middlewares...)
auth.POST("/:space", chatHandler.NewChat)
auth.POST("/:space/:id", chatHandler.NewChatMessage)
auth.GET("/:space/all/:page", chatHandler.List)
auth.GET("/:space/:id", chatHandler.Get)
auth.GET("/:space/:id/subscribe", chatHandler.Subscribe)
auth.DELETE("/:space/:id", chatHandler.Delete)
return auth
}
type ChatHandler struct {
chatService *chat.Service
}
type ChatRequest struct {
Prompt string `json:"prompt"`
AgentID string `json:"agentID"`
ProviderID string `json:"providerID"`
ModelID string `json:"modelID"`
ReasoningLevel string `json:"reasoningLevel"`
}
func (h *ChatHandler) NewChat(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
var request ChatRequest
err := c.Bind(&request)
if err != nil {
c.Logger().Error("error binding request", "error", err.Error())
return echo.NewHTTPError(http.StatusBadRequest, "error binding request")
}
chat, err := h.chatService.NewChat(
userID,
teamID,
request.AgentID,
)
if err != nil {
c.Logger().Error("error creating chat", "error", err.Error())
return echo.NewHTTPError(http.StatusBadRequest, "error creating chat")
}
return c.JSON(http.StatusOK, chat)
}
func (h *ChatHandler) NewChatMessage(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
chatID := c.Param("id")
var request ChatRequest
err := c.Bind(&request)
if err != nil {
c.Logger().Error("error binding request", "error", err.Error())
return echo.NewHTTPError(http.StatusBadRequest, "error binding request")
}
enc := json.NewEncoder(c.Response())
chunkChan := make(chan *domain.Chunk)
_, err = h.chatService.AddChatMessage(
c.Request().Context(),
userID,
teamID,
chatID,
request.AgentID,
request.Prompt,
&domain.ChatParams{
OnChunk: func(chunk *domain.Chunk) {
chunkChan <- chunk
},
},
)
if err != nil {
c.Logger().Error("error creating chat message", "error", err.Error())
return echo.NewHTTPError(http.StatusBadRequest, "error creating chat message")
}
enc.Encode(&domain.Chunk{
Done: false,
Role: string(domain.RoleUser),
Content: request.Prompt,
})
http.NewResponseController(c.Response()).Flush()
for {
chunk := <-chunkChan
slog.Info("Chunk", "role", chunk.Role, "content", chunk.Content, "reasoning", chunk.Reasoning)
if chunk.Done {
return nil
}
enc.Encode(chunk)
http.NewResponseController(c.Response()).Flush()
}
}
func (h *ChatHandler) List(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
page := c.Param("page")
pageInt, _ := strconv.Atoi(page)
chats, err := h.chatService.ListChats(userID, teamID, pageInt)
if err != nil {
c.Logger().Error("error listing chats", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error listing chats")
}
return c.JSON(http.StatusOK, chats)
}
func (h *ChatHandler) Get(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
chatID := c.Param("id")
chatWithMessages, err := h.chatService.GetChatWithMessages(userID, teamID, chatID)
if err != nil {
c.Logger().Error("error getting chat with messages", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error getting chat")
}
return c.JSON(http.StatusOK, chatWithMessages)
}
func (h *ChatHandler) Delete(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
chatID := c.Param("id")
err := h.chatService.DeleteChat(userID, teamID, chatID)
if err != nil {
c.Logger().Error("error deleting chat", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error deleting chat")
}
return c.JSON(http.StatusOK, "chat deleted")
}
func (h *ChatHandler) Subscribe(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
chatID := c.Param("id")
enc := json.NewEncoder(c.Response())
chunkChan := make(chan *domain.Chunk)
err := h.chatService.Subscribe(
userID,
teamID,
chatID,
func(chunk *domain.Chunk) {
chunkChan <- chunk
},
)
if err != nil {
c.Logger().Error("error subscribing to chat", "error", err.Error())
return echo.NewHTTPError(http.StatusBadRequest, "error creating chat")
}
for {
chunk := <-chunkChan
if chunk.Done {
return nil
}
enc.Encode(chunk)
http.NewResponseController(c.Response()).Flush()
}
}
+10 -10
View File
@@ -40,7 +40,7 @@ func (h *ModelHandler) ListProviders(c *echo.Context) error {
teamID := c.Param("space")
providers, err := h.providerService.ListProviders(userID, teamID)
if err != nil {
c.Logger().Error("error listing providers: %s", err)
c.Logger().Error("error listing providers", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error listing providers")
}
return c.JSON(http.StatusOK, providers)
@@ -52,7 +52,7 @@ func (h *ModelHandler) GetProvider(c *echo.Context) error {
providerID := c.Param("provider")
provider, err := h.providerService.GetProvider(userID, teamID, providerID)
if err != nil {
c.Logger().Error("error getting provider: %s", err)
c.Logger().Error("error getting provider", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error getting provider")
}
return c.JSON(http.StatusOK, provider)
@@ -64,13 +64,13 @@ func (h *ModelHandler) CreateProvider(c *echo.Context) error {
var provider domain.Provider
err := c.Bind(&provider)
if err != nil {
c.Logger().Error("error binding provider: %s", err)
c.Logger().Error("error binding provider", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error binding provider")
}
provider.TeamID = teamID
updprovider, err := h.providerService.CreateProvider(userID, &provider)
if err != nil {
c.Logger().Error("error creating provider: %s", err)
c.Logger().Error("error creating provider", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error creating provider")
}
return c.JSON(http.StatusOK, updprovider)
@@ -82,13 +82,13 @@ func (h *ModelHandler) UpdateProvider(c *echo.Context) error {
var provider domain.Provider
err := c.Bind(&provider)
if err != nil {
c.Logger().Error("error binding provider: %s", err)
c.Logger().Error("error binding provider", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error binding provider")
}
provider.TeamID = teamID
updprovider, err := h.providerService.UpdateProvider(userID, &provider)
if err != nil {
c.Logger().Error("error updating provider: %s", err)
c.Logger().Error("error updating provider", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error creating provider")
}
return c.JSON(http.StatusOK, updprovider)
@@ -100,7 +100,7 @@ func (h *ModelHandler) DeleteProvider(c *echo.Context) error {
providerID := c.Param("provider")
err := h.providerService.DeleteProvider(userID, teamID, providerID)
if err != nil {
c.Logger().Error("error creating provider: %s", err)
c.Logger().Error("error creating provider", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error creating provider")
}
return c.JSON(http.StatusOK, providerID)
@@ -111,13 +111,13 @@ func (h *ModelHandler) ListAvailableModels(c *echo.Context) error {
var provider domain.Provider
err := c.Bind(&provider)
if err != nil {
c.Logger().Error("error binding provider: %s", err)
c.Logger().Error("error binding provider", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error binding provider")
}
provider.TeamID = teamID
list, err := h.providerService.ListAvailableModels(c.Request().Context(), &provider)
if err != nil {
c.Logger().Error("error listing available models: %s", err)
c.Logger().Error("error listing available models", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error listing available models")
}
return c.JSON(http.StatusOK, list)
@@ -128,7 +128,7 @@ func (h *ModelHandler) ListProvidersModels(c *echo.Context) error {
teamID := c.Param("space")
list, err := h.providerService.ListProvidersModels(userID, teamID)
if err != nil {
c.Logger().Error("error listing providers models: %s", err)
c.Logger().Error("error listing providers models", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error listing providers models")
}
return c.JSON(http.StatusOK, list)