Files
enkly-ai/services/conversation/internal/interfaces/grpc/server.go
enkly 79ce8dc4c0
Some checks failed
Go CI Pipeline / build_and_test (push) Failing after 22m0s
Init Project
2026-10-30 18:06:55 +01:00

180 lines
5.8 KiB
Go

package grpc
import (
"context"
"errors"
"google.golang.org/protobuf/types/known/timestamppb"
conversationv1 "enkly/gen/conversation/v1"
"enkly/pkg/grpcerr"
"enkly/services/conversation/internal/application"
"enkly/services/conversation/internal/domain"
)
type Server struct {
conversationv1.UnimplementedConversationServiceServer
Svc *application.Service
}
func New(svc *application.Service) *Server { return &Server{Svc: svc} }
func toProtoRole(r domain.Role) conversationv1.Role {
switch r {
case domain.RoleUser:
return conversationv1.Role_ROLE_USER
case domain.RoleAssistant:
return conversationv1.Role_ROLE_ASSISTANT
case domain.RoleSystem:
return conversationv1.Role_ROLE_SYSTEM
case domain.RoleTool:
return conversationv1.Role_ROLE_TOOL
default:
return conversationv1.Role_ROLE_UNSPECIFIED
}
}
func fromProtoRole(r conversationv1.Role) domain.Role {
switch r {
case conversationv1.Role_ROLE_USER:
return domain.RoleUser
case conversationv1.Role_ROLE_ASSISTANT:
return domain.RoleAssistant
case conversationv1.Role_ROLE_SYSTEM:
return domain.RoleSystem
case conversationv1.Role_ROLE_TOOL:
return domain.RoleTool
default:
return domain.RoleUser
}
}
func toProtoConversation(c *domain.Conversation) *conversationv1.Conversation {
return &conversationv1.Conversation{
Id: c.ID,
UserId: c.UserID,
Title: c.Title,
CreatedAt: timestamppb.New(c.CreatedAt),
LastMessageAt: timestamppb.New(c.LastMessageAt),
}
}
func toProtoMessage(m *domain.Message) *conversationv1.Message {
return &conversationv1.Message{
Id: m.ID,
ConversationId: m.ConversationID,
Role: toProtoRole(m.Role),
Content: m.Content,
ToolName: m.ToolName,
CreatedAt: timestamppb.New(m.CreatedAt),
}
}
func mapErr(err error) error {
if errors.Is(err, domain.ErrNotFound) {
return grpcerr.NotFound("conversation")
}
return grpcerr.Internal(err)
}
func (s *Server) CreateConversation(ctx context.Context, req *conversationv1.CreateConversationRequest) (*conversationv1.Conversation, error) {
c, err := s.Svc.CreateConversation(ctx, req.GetUserId(), req.GetTitle())
if err != nil {
return nil, mapErr(err)
}
return toProtoConversation(c), nil
}
func (s *Server) GetConversation(ctx context.Context, req *conversationv1.GetConversationRequest) (*conversationv1.Conversation, error) {
c, err := s.Svc.GetConversation(ctx, req.GetUserId(), req.GetConversationId())
if err != nil {
return nil, mapErr(err)
}
return toProtoConversation(c), nil
}
func (s *Server) ListConversations(ctx context.Context, req *conversationv1.ListConversationsRequest) (*conversationv1.ListConversationsResponse, error) {
list, err := s.Svc.ListConversations(ctx, req.GetUserId())
if err != nil {
return nil, grpcerr.Internal(err)
}
resp := &conversationv1.ListConversationsResponse{}
for _, c := range list {
resp.Conversations = append(resp.Conversations, toProtoConversation(c))
}
return resp, nil
}
func (s *Server) MostRecentConversation(ctx context.Context, req *conversationv1.MostRecentConversationRequest) (*conversationv1.Conversation, error) {
c, err := s.Svc.MostRecentConversation(ctx, req.GetUserId())
if err != nil {
return nil, mapErr(err)
}
return toProtoConversation(c), nil
}
func (s *Server) RenameConversation(ctx context.Context, req *conversationv1.RenameConversationRequest) (*conversationv1.Conversation, error) {
c, err := s.Svc.RenameConversation(ctx, req.GetUserId(), req.GetConversationId(), req.GetTitle())
if err != nil {
return nil, mapErr(err)
}
return toProtoConversation(c), nil
}
func (s *Server) AutoTitleConversation(ctx context.Context, req *conversationv1.AutoTitleConversationRequest) (*conversationv1.AutoTitleConversationResponse, error) {
changed, err := s.Svc.AutoTitleConversation(ctx, req.GetUserId(), req.GetConversationId(), req.GetTitle())
if err != nil {
return nil, grpcerr.Internal(err)
}
return &conversationv1.AutoTitleConversationResponse{Retitled: changed}, nil
}
func (s *Server) DeleteConversation(ctx context.Context, req *conversationv1.DeleteConversationRequest) (*conversationv1.DeleteConversationResponse, error) {
if err := s.Svc.DeleteConversation(ctx, req.GetUserId(), req.GetConversationId()); err != nil {
return nil, mapErr(err)
}
return &conversationv1.DeleteConversationResponse{}, nil
}
func (s *Server) CountMessages(ctx context.Context, req *conversationv1.CountMessagesRequest) (*conversationv1.CountMessagesResponse, error) {
n, err := s.Svc.CountMessages(ctx, req.GetConversationId())
if err != nil {
return nil, grpcerr.Internal(err)
}
return &conversationv1.CountMessagesResponse{Count: int32(n)}, nil
}
func (s *Server) AddMessage(ctx context.Context, req *conversationv1.AddMessageRequest) (*conversationv1.Message, error) {
m, err := s.Svc.AddMessage(ctx, req.GetConversationId(), fromProtoRole(req.GetRole()), req.GetContent(), req.GetToolName())
if err != nil {
return nil, grpcerr.Internal(err)
}
return toProtoMessage(m), nil
}
func (s *Server) ListMessages(ctx context.Context, req *conversationv1.ListMessagesRequest) (*conversationv1.ListMessagesResponse, error) {
list, err := s.Svc.ListMessages(ctx, req.GetConversationId())
if err != nil {
return nil, grpcerr.Internal(err)
}
resp := &conversationv1.ListMessagesResponse{}
for _, m := range list {
resp.Messages = append(resp.Messages, toProtoMessage(m))
}
return resp, nil
}
func (s *Server) AddToolCall(ctx context.Context, req *conversationv1.AddToolCallRequest) (*conversationv1.AddToolCallResponse, error) {
err := s.Svc.AddToolCall(ctx, domain.ToolCall{
MessageID: req.GetMessageId(),
ToolName: req.GetToolName(),
ArgumentsJSON: req.GetArgumentsJson(),
Result: req.GetResult(),
IsError: req.GetIsError(),
})
if err != nil {
return nil, grpcerr.Internal(err)
}
return &conversationv1.AddToolCallResponse{}, nil
}