188 lines
3.9 KiB
Go
188 lines
3.9 KiB
Go
package service
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"database/sql"
|
||
|
|
"encoding/json/v2"
|
||
|
|
"errors"
|
||
|
|
"log/slog"
|
||
|
|
"net/http"
|
||
|
|
)
|
||
|
|
|
||
|
|
func (svc *Service) listConversations(w http.ResponseWriter, r *http.Request) {
|
||
|
|
var (
|
||
|
|
ctx = r.Context()
|
||
|
|
log = ctx.Value(logKey).(*slog.Logger)
|
||
|
|
)
|
||
|
|
|
||
|
|
rows, err := svc.dbr.SelectConversationsUserId(ctx, "default")
|
||
|
|
if err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to list conversations",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
http.Error(
|
||
|
|
w,
|
||
|
|
http.StatusText(http.StatusInternalServerError),
|
||
|
|
http.StatusInternalServerError,
|
||
|
|
)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
w.Header().Set("Content-Type", "application/json")
|
||
|
|
if err := json.MarshalWrite(w, rows); err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to encode conversations response",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (svc *Service) createConversation(w http.ResponseWriter, r *http.Request) {
|
||
|
|
var (
|
||
|
|
ctx = r.Context()
|
||
|
|
log = ctx.Value(logKey).(*slog.Logger)
|
||
|
|
req struct {
|
||
|
|
Title *string `json:"title"`
|
||
|
|
SystemMessage *string `json:"system_message"`
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
r.Body = http.MaxBytesReader(w, r.Body, 32<<20)
|
||
|
|
if err := json.UnmarshalRead(r.Body, &req); err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to decode request",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
http.Error(w, "invalid request", http.StatusBadRequest)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
system := svc.cfg.SystemMessage
|
||
|
|
if req.SystemMessage != nil {
|
||
|
|
system = *req.SystemMessage
|
||
|
|
}
|
||
|
|
saved, _, err := svc.newConversation(
|
||
|
|
ctx, "default", req.Title, system,
|
||
|
|
)
|
||
|
|
if err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to create conversation",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
http.Error(
|
||
|
|
w,
|
||
|
|
http.StatusText(http.StatusInternalServerError),
|
||
|
|
http.StatusInternalServerError,
|
||
|
|
)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
w.Header().Set("Content-Type", "application/json")
|
||
|
|
w.WriteHeader(http.StatusCreated)
|
||
|
|
if err := json.MarshalWrite(w, saved); err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to encode conversation response",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (svc *Service) getConversationHandler(
|
||
|
|
w http.ResponseWriter,
|
||
|
|
r *http.Request,
|
||
|
|
) {
|
||
|
|
var (
|
||
|
|
ctx = r.Context()
|
||
|
|
log = ctx.Value(logKey).(*slog.Logger)
|
||
|
|
)
|
||
|
|
|
||
|
|
saved, err := svc.dbr.SelectConversationIdUserId(
|
||
|
|
ctx, r.PathValue("id"), "default",
|
||
|
|
)
|
||
|
|
if errors.Is(err, sql.ErrNoRows) {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to load conversation",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
http.Error(
|
||
|
|
w,
|
||
|
|
http.StatusText(http.StatusInternalServerError),
|
||
|
|
http.StatusInternalServerError,
|
||
|
|
)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
w.Header().Set("Content-Type", "application/json")
|
||
|
|
if err := json.MarshalWrite(w, saved); err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to encode conversation response",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (svc *Service) deleteConversation(w http.ResponseWriter, r *http.Request) {
|
||
|
|
var (
|
||
|
|
ctx = r.Context()
|
||
|
|
log = ctx.Value(logKey).(*slog.Logger)
|
||
|
|
id = r.PathValue("id")
|
||
|
|
)
|
||
|
|
|
||
|
|
if _, err := svc.dbr.SelectConversationIdUserId(
|
||
|
|
ctx, id, "default",
|
||
|
|
); err != nil {
|
||
|
|
if errors.Is(err, sql.ErrNoRows) {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to load conversation",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
http.Error(
|
||
|
|
w,
|
||
|
|
http.StatusText(http.StatusInternalServerError),
|
||
|
|
http.StatusInternalServerError,
|
||
|
|
)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
c, err := svc.getConversation(ctx, id)
|
||
|
|
if errors.Is(err, sql.ErrNoRows) {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to get conversation handle",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
http.Error(
|
||
|
|
w,
|
||
|
|
http.StatusText(http.StatusInternalServerError),
|
||
|
|
http.StatusInternalServerError,
|
||
|
|
)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err := c.Delete(ctx); err != nil {
|
||
|
|
log.ErrorContext(
|
||
|
|
ctx, "failed to delete conversation",
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
http.Error(
|
||
|
|
w,
|
||
|
|
http.StatusText(http.StatusInternalServerError),
|
||
|
|
http.StatusInternalServerError,
|
||
|
|
)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
svc.mu.Lock()
|
||
|
|
delete(svc.conversations, id)
|
||
|
|
svc.mu.Unlock()
|
||
|
|
w.WriteHeader(http.StatusNoContent)
|
||
|
|
}
|