From be5ac2dc40f3b6648d1e671bfbfbe1426eeb701b Mon Sep 17 00:00:00 2001 From: Kaien Date: Thu, 7 May 2026 13:00:55 +0300 Subject: [PATCH] feat: add StatelessMessage, StatelessRequest and GenerateStateless RPC --- ai.pb.go | 175 ++++++++++++++++++++++++++++++++++++++++++-------- ai.proto | 21 +++++- ai_grpc.pb.go | 48 ++++++++++++-- 3 files changed, 209 insertions(+), 35 deletions(-) diff --git a/ai.pb.go b/ai.pb.go index a1be444..0aaa097 100644 --- a/ai.pb.go +++ b/ai.pb.go @@ -512,6 +512,112 @@ func (x *SessionStatusResponse) GetReasoningContent() string { return "" } +// StatelessMessage одно сообщение для stateless запроса (role + content) +type StatelessMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` // "system", "user", "assistant" + Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` // Текст сообщения + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StatelessMessage) Reset() { + *x = StatelessMessage{} + mi := &file_ai_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatelessMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatelessMessage) ProtoMessage() {} + +func (x *StatelessMessage) ProtoReflect() protoreflect.Message { + mi := &file_ai_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatelessMessage.ProtoReflect.Descriptor instead. +func (*StatelessMessage) Descriptor() ([]byte, []int) { + return file_ai_proto_rawDescGZIP(), []int{7} +} + +func (x *StatelessMessage) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +func (x *StatelessMessage) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +// StatelessRequest для stateless генерации с полным контролем над messages +type StatelessRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Messages []*StatelessMessage `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` // Массив сообщений (system + history + user) + ModelName string `protobuf:"bytes,2,opt,name=model_name,json=modelName,proto3" json:"model_name,omitempty"` // Название модели (по умолчанию "venice-uncensored") + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StatelessRequest) Reset() { + *x = StatelessRequest{} + mi := &file_ai_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatelessRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatelessRequest) ProtoMessage() {} + +func (x *StatelessRequest) ProtoReflect() protoreflect.Message { + mi := &file_ai_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatelessRequest.ProtoReflect.Descriptor instead. +func (*StatelessRequest) Descriptor() ([]byte, []int) { + return file_ai_proto_rawDescGZIP(), []int{8} +} + +func (x *StatelessRequest) GetMessages() []*StatelessMessage { + if x != nil { + return x.Messages + } + return nil +} + +func (x *StatelessRequest) GetModelName() string { + if x != nil { + return x.ModelName + } + return "" +} + // HealthCheckRequest для проверки здоровья сервиса type HealthCheckRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -521,7 +627,7 @@ type HealthCheckRequest struct { func (x *HealthCheckRequest) Reset() { *x = HealthCheckRequest{} - mi := &file_ai_proto_msgTypes[7] + mi := &file_ai_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -533,7 +639,7 @@ func (x *HealthCheckRequest) String() string { func (*HealthCheckRequest) ProtoMessage() {} func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[7] + mi := &file_ai_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -546,7 +652,7 @@ func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{7} + return file_ai_proto_rawDescGZIP(), []int{9} } // HealthCheckResponse для ответа на проверку здоровья @@ -560,7 +666,7 @@ type HealthCheckResponse struct { func (x *HealthCheckResponse) Reset() { *x = HealthCheckResponse{} - mi := &file_ai_proto_msgTypes[8] + mi := &file_ai_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -572,7 +678,7 @@ func (x *HealthCheckResponse) String() string { func (*HealthCheckResponse) ProtoMessage() {} func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[8] + mi := &file_ai_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -585,7 +691,7 @@ func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{8} + return file_ai_proto_rawDescGZIP(), []int{10} } func (x *HealthCheckResponse) GetServing() bool { @@ -651,13 +757,21 @@ const file_ai_proto_rawDesc = "" + "\x05error\x18\x04 \x01(\tR\x05error\x12\x1f\n" + "\vduration_ms\x18\x05 \x01(\x01R\n" + "durationMs\x12+\n" + - "\x11reasoning_content\x18\x06 \x01(\tR\x10reasoningContent\"\x14\n" + + "\x11reasoning_content\x18\x06 \x01(\tR\x10reasoningContent\"@\n" + + "\x10StatelessMessage\x12\x12\n" + + "\x04role\x18\x01 \x01(\tR\x04role\x12\x18\n" + + "\acontent\x18\x02 \x01(\tR\acontent\"c\n" + + "\x10StatelessRequest\x120\n" + + "\bmessages\x18\x01 \x03(\v2\x14.ai.StatelessMessageR\bmessages\x12\x1d\n" + + "\n" + + "model_name\x18\x02 \x01(\tR\tmodelName\"\x14\n" + "\x12HealthCheckRequest\"I\n" + "\x13HealthCheckResponse\x12\x18\n" + "\aserving\x18\x01 \x01(\bR\aserving\x12\x18\n" + - "\aversion\x18\x02 \x01(\tR\aversion2\x86\x02\n" + + "\aversion\x18\x02 \x01(\tR\aversion2\xc1\x02\n" + "\tAIService\x12/\n" + - "\x0eGenerateAnswer\x12\r.ai.AIRequest\x1a\x0e.ai.AIResponse\x12>\n" + + "\x0eGenerateAnswer\x12\r.ai.AIRequest\x1a\x0e.ai.AIResponse\x129\n" + + "\x11GenerateStateless\x12\x14.ai.StatelessRequest\x1a\x0e.ai.AIResponse\x12>\n" + "\vHealthCheck\x12\x16.ai.HealthCheckRequest\x1a\x17.ai.HealthCheckResponse\x12D\n" + "\rCreateSession\x12\x18.ai.CreateSessionRequest\x1a\x19.ai.CreateSessionResponse\x12B\n" + "\fAskInSession\x12\x17.ai.AskInSessionRequest\x1a\x19.ai.SessionStatusResponseB,Z*git.be.kaien.ru/l-ai/l-ai-core-proto/protob\x06proto3" @@ -674,7 +788,7 @@ func file_ai_proto_rawDescGZIP() []byte { return file_ai_proto_rawDescData } -var file_ai_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_ai_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_ai_proto_goTypes = []any{ (*AIRequest)(nil), // 0: ai.AIRequest (*AnswerGenerationOptions)(nil), // 1: ai.AnswerGenerationOptions @@ -683,25 +797,30 @@ var file_ai_proto_goTypes = []any{ (*CreateSessionResponse)(nil), // 4: ai.CreateSessionResponse (*AskInSessionRequest)(nil), // 5: ai.AskInSessionRequest (*SessionStatusResponse)(nil), // 6: ai.SessionStatusResponse - (*HealthCheckRequest)(nil), // 7: ai.HealthCheckRequest - (*HealthCheckResponse)(nil), // 8: ai.HealthCheckResponse + (*StatelessMessage)(nil), // 7: ai.StatelessMessage + (*StatelessRequest)(nil), // 8: ai.StatelessRequest + (*HealthCheckRequest)(nil), // 9: ai.HealthCheckRequest + (*HealthCheckResponse)(nil), // 10: ai.HealthCheckResponse } var file_ai_proto_depIdxs = []int32{ - 1, // 0: ai.AIRequest.options:type_name -> ai.AnswerGenerationOptions - 1, // 1: ai.AskInSessionRequest.options:type_name -> ai.AnswerGenerationOptions - 0, // 2: ai.AIService.GenerateAnswer:input_type -> ai.AIRequest - 7, // 3: ai.AIService.HealthCheck:input_type -> ai.HealthCheckRequest - 3, // 4: ai.AIService.CreateSession:input_type -> ai.CreateSessionRequest - 5, // 5: ai.AIService.AskInSession:input_type -> ai.AskInSessionRequest - 2, // 6: ai.AIService.GenerateAnswer:output_type -> ai.AIResponse - 8, // 7: ai.AIService.HealthCheck:output_type -> ai.HealthCheckResponse - 4, // 8: ai.AIService.CreateSession:output_type -> ai.CreateSessionResponse - 6, // 9: ai.AIService.AskInSession:output_type -> ai.SessionStatusResponse - 6, // [6:10] is the sub-list for method output_type - 2, // [2:6] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 1, // 0: ai.AIRequest.options:type_name -> ai.AnswerGenerationOptions + 1, // 1: ai.AskInSessionRequest.options:type_name -> ai.AnswerGenerationOptions + 7, // 2: ai.StatelessRequest.messages:type_name -> ai.StatelessMessage + 0, // 3: ai.AIService.GenerateAnswer:input_type -> ai.AIRequest + 8, // 4: ai.AIService.GenerateStateless:input_type -> ai.StatelessRequest + 9, // 5: ai.AIService.HealthCheck:input_type -> ai.HealthCheckRequest + 3, // 6: ai.AIService.CreateSession:input_type -> ai.CreateSessionRequest + 5, // 7: ai.AIService.AskInSession:input_type -> ai.AskInSessionRequest + 2, // 8: ai.AIService.GenerateAnswer:output_type -> ai.AIResponse + 2, // 9: ai.AIService.GenerateStateless:output_type -> ai.AIResponse + 10, // 10: ai.AIService.HealthCheck:output_type -> ai.HealthCheckResponse + 4, // 11: ai.AIService.CreateSession:output_type -> ai.CreateSessionResponse + 6, // 12: ai.AIService.AskInSession:output_type -> ai.SessionStatusResponse + 8, // [8:13] is the sub-list for method output_type + 3, // [3:8] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_ai_proto_init() } @@ -715,7 +834,7 @@ func file_ai_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_ai_proto_rawDesc), len(file_ai_proto_rawDesc)), NumEnums: 0, - NumMessages: 9, + NumMessages: 11, NumExtensions: 0, NumServices: 1, }, diff --git a/ai.proto b/ai.proto index d258947..301473b 100644 --- a/ai.proto +++ b/ai.proto @@ -61,6 +61,18 @@ message SessionStatusResponse { string reasoning_content = 6; // Текст рассуждений (если включён режим reasoning) } +// StatelessMessage одно сообщение для stateless запроса (role + content) +message StatelessMessage { + string role = 1; // "system", "user", "assistant" + string content = 2; // Текст сообщения +} + +// StatelessRequest для stateless генерации с полным контролем над messages +message StatelessRequest { + repeated StatelessMessage messages = 1; // Массив сообщений (system + history + user) + string model_name = 2; // Название модели (по умолчанию "venice-uncensored") +} + // HealthCheckRequest для проверки здоровья сервиса message HealthCheckRequest {} @@ -74,13 +86,16 @@ message HealthCheckResponse { service AIService { // GenerateAnswer генерирует ответ на запрос rpc GenerateAnswer(AIRequest) returns (AIResponse); - + + // GenerateStateless генерирует ответ из массива messages (system+history+user) + rpc GenerateStateless(StatelessRequest) returns (AIResponse); + // HealthCheck проверяет здоровье сервиса rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse); - + // CreateSession созда новую AI сессию rpc CreateSession(CreateSessionRequest) returns (CreateSessionResponse); - + // AskInSession отправляет запрос в рамках существующей сессии rpc AskInSession(AskInSessionRequest) returns (SessionStatusResponse); } diff --git a/ai_grpc.pb.go b/ai_grpc.pb.go index 824b2fb..631f165 100644 --- a/ai_grpc.pb.go +++ b/ai_grpc.pb.go @@ -19,10 +19,11 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - AIService_GenerateAnswer_FullMethodName = "/ai.AIService/GenerateAnswer" - AIService_HealthCheck_FullMethodName = "/ai.AIService/HealthCheck" - AIService_CreateSession_FullMethodName = "/ai.AIService/CreateSession" - AIService_AskInSession_FullMethodName = "/ai.AIService/AskInSession" + AIService_GenerateAnswer_FullMethodName = "/ai.AIService/GenerateAnswer" + AIService_GenerateStateless_FullMethodName = "/ai.AIService/GenerateStateless" + AIService_HealthCheck_FullMethodName = "/ai.AIService/HealthCheck" + AIService_CreateSession_FullMethodName = "/ai.AIService/CreateSession" + AIService_AskInSession_FullMethodName = "/ai.AIService/AskInSession" ) // AIServiceClient is the client API for AIService service. @@ -33,6 +34,8 @@ const ( type AIServiceClient interface { // GenerateAnswer генерирует ответ на запрос GenerateAnswer(ctx context.Context, in *AIRequest, opts ...grpc.CallOption) (*AIResponse, error) + // GenerateStateless генерирует ответ из массива messages (system+history+user) + GenerateStateless(ctx context.Context, in *StatelessRequest, opts ...grpc.CallOption) (*AIResponse, error) // HealthCheck проверяет здоровье сервиса HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) // CreateSession созда новую AI сессию @@ -59,6 +62,16 @@ func (c *aIServiceClient) GenerateAnswer(ctx context.Context, in *AIRequest, opt return out, nil } +func (c *aIServiceClient) GenerateStateless(ctx context.Context, in *StatelessRequest, opts ...grpc.CallOption) (*AIResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AIResponse) + err := c.cc.Invoke(ctx, AIService_GenerateStateless_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *aIServiceClient) HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(HealthCheckResponse) @@ -97,6 +110,8 @@ func (c *aIServiceClient) AskInSession(ctx context.Context, in *AskInSessionRequ type AIServiceServer interface { // GenerateAnswer генерирует ответ на запрос GenerateAnswer(context.Context, *AIRequest) (*AIResponse, error) + // GenerateStateless генерирует ответ из массива messages (system+history+user) + GenerateStateless(context.Context, *StatelessRequest) (*AIResponse, error) // HealthCheck проверяет здоровье сервиса HealthCheck(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) // CreateSession созда новую AI сессию @@ -116,6 +131,9 @@ type UnimplementedAIServiceServer struct{} func (UnimplementedAIServiceServer) GenerateAnswer(context.Context, *AIRequest) (*AIResponse, error) { return nil, status.Error(codes.Unimplemented, "method GenerateAnswer not implemented") } +func (UnimplementedAIServiceServer) GenerateStateless(context.Context, *StatelessRequest) (*AIResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GenerateStateless not implemented") +} func (UnimplementedAIServiceServer) HealthCheck(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) { return nil, status.Error(codes.Unimplemented, "method HealthCheck not implemented") } @@ -164,6 +182,24 @@ func _AIService_GenerateAnswer_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _AIService_GenerateStateless_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatelessRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AIServiceServer).GenerateStateless(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AIService_GenerateStateless_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AIServiceServer).GenerateStateless(ctx, req.(*StatelessRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AIService_HealthCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(HealthCheckRequest) if err := dec(in); err != nil { @@ -229,6 +265,10 @@ var AIService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GenerateAnswer", Handler: _AIService_GenerateAnswer_Handler, }, + { + MethodName: "GenerateStateless", + Handler: _AIService_GenerateStateless_Handler, + }, { MethodName: "HealthCheck", Handler: _AIService_HealthCheck_Handler,