Browse Source

first commit

lijunliang 1 năm trước cách đây
commit
d130d7adf2

+ 117 - 0
README.md

@@ -0,0 +1,117 @@
+## **a2s服务的python工具包,更容易大规模应用**
+
+
+## *启动服务*
+```python
+from a2s_server import watch, simple_params
+
+#方式一 使用简单方式启动   .py文件命令行参数   python server.py --h
+@simple_params
+@watch
+def main(data: bytes, *args, **kwargs) -> bytes:
+    '''
+
+    :param data: 固定格式
+    :param args: 固定格式
+    :param kwargs: 固定格式
+    :return:
+    '''
+    # 内部处理程序
+    data = data.decode("utf-8")
+    data += "服务端处理过了数据"
+    return data.encode("utf-8")
+
+main()
+
+# 方式二 自定义启动方式
+@watch
+def main(data: bytes, *args, **kwargs) -> bytes:
+    '''
+
+    :param data: 固定格式
+    :param args: 固定格式
+    :param kwargs: 固定格式
+    :return:
+    '''
+    # 内部处理程序
+    data = data.decode("utf-8")
+    data += "服务端处理过了数据"
+    return data.encode("utf-8")
+
+main(nats_host="192.168.3.240",nats_port=19090,subject="test",queue="main")
+```
+#### 方式一 更简单方式启动
+#### 方法二 灵活性更高
+#### 推荐使用 *方法一*
+
+## *调用服务*
+
+a2s_client # 简化a2s客户端调用
+
+```python
+
+from a2s_client import a2s_execute
+
+if __name__ == '__main__':
+    result = a2s_execute(a2s_ip="192.168.3.240:19094", topic="test", timeout=10, bytes_data=b"hello")
+    print(result.decode("utf-8"))
+
+```
+
+## *工具*
+
+dict(字典) 序列化反序列化
+
+grpc 序列化反序列化
+```python
+
+import json
+
+
+def grpc_serialize(resp):
+    """
+    grpc对象序列化
+    :param resp:resp = Text2VectorReq(text=data)
+    :return:
+    """
+    return resp.SerializeToString()
+
+
+def grpc_deserialize(req, data):
+    """
+    grpc对象反序列化
+    :param req: req = Text2VectorResp()
+    :param data: req的序列化对象
+    :return:
+    """
+    return req.ParseFromString(data)
+
+
+def json_serialize(dict_data):
+    """
+    json对象序列化
+    :param resp: 字典
+    :return:
+    """
+    # 将字典转换为 JSON 格式的字符串
+    json_data = json.dumps(dict_data)
+
+    # 将 JSON 字符串转换为字节流
+    bytes_data = json_data.encode('utf-8')
+    return bytes_data
+
+
+def json_deserialize(bytes_data):
+    """
+    grpc对象反序列化
+    :param bytes_data:
+    :return:
+    """
+    # 将字节流转换为 JSON 字符串
+    json_data = bytes_data.decode('utf-8')
+
+    # 将 JSON 字符串转换为字典对象
+    dict_data = json.loads(json_data)
+    return dict_data
+
+```

BIN
__pycache__/a2s_client.cpython-37.pyc


BIN
__pycache__/a2s_server.cpython-37.pyc


+ 31 - 0
a2s_client.py

@@ -0,0 +1,31 @@
+# coding:utf-8
+
+import grpc
+from proto import service_pb2, service_pb2_grpc
+
+
+def a2s_execute(a2s_ip: str, topic: str, timeout: int, bytes_data: bytes):
+    """
+    a2e服务调用
+    :param a2s_ip: 192.168.3.240:9090  #  服务地址
+    :param topic: t2v   主体
+    :param timeout: 60  超时时间
+    :param bytes_data: 请求字段
+    :return: bytes or None
+    """
+    try:
+        if not (a2s_ip and topic):
+            raise IOError("参数错误:a2s_ip和topic不能为空!")
+        with grpc.insecure_channel(a2s_ip) as channel:
+            # 客户端实例
+            stub = service_pb2_grpc.CallerStub(channel)
+            print(topic,timeout,bytes_data)
+            # 调用服务端方法
+            response = stub.Call(service_pb2.Request(topic=topic, timeout=timeout, data=bytes_data))
+            print("==>",response)
+            # 获取结果
+            data = response.data
+            return data
+    except Exception as e:
+        print(e)
+        return None

+ 71 - 0
a2s_server.py

@@ -0,0 +1,71 @@
+# coding:utf-8
+import argparse
+from functools import wraps
+from pynats import NATSClient
+from proto.service_pb2 import NatsRequest, NatsResponse
+import time
+import logging
+
+
+def simple_params(func):
+    @wraps(func)
+    def wrapper():
+        parser = argparse.ArgumentParser()
+        parser.add_argument('-host', '--nats_host', type=str, default="192.168.3.240", help='nats主机')
+        parser.add_argument('-port', '--nats_port', type=int, default=19090, help='nats端口')
+        parser.add_argument('-subject', '--subject', type=str, default="test", help='监听主题名称')
+        parser.add_argument('-queue', '--queue', type=str, default="main", help='监听主题名称')
+        args = parser.parse_args()
+        params = dict(args._get_kwargs())
+        return func(**params)
+
+    return wrapper
+
+
+def watch(func):
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        nats_host = kwargs.get("nats_host")
+        nats_port = kwargs.get("nats_port")
+        subject = kwargs.get("subject")
+        queue = kwargs.get("queue")
+        if not (nats_host and nats_port and subject and queue):
+            raise Exception("""请检查参数,使用举例:
+1、使用方法            
+@watch
+def say_hello(nats_host="192.168.3.109", nats_port=800, subject="text2vec", queue="main",data):
+    print(data)
+    
+2、建议使用:
+@simple_params
+@watch
+def main(data: bytes, *args, **kwargs) -> bytes:
+    """)
+        NatsIp = f"nats://{nats_host}:{nats_port}"
+        ListenSubject = subject + "_req"
+        PublishSubject = subject + "_resp"
+        logging.warning(f"服务启动中>>>>listen::{ListenSubject}:,,publish:{PublishSubject}")
+        with NATSClient(NatsIp, name=subject) as nc:
+            nc.connect()
+
+            def message_handler(msg):
+                try:
+                    nats_req = NatsRequest()
+                    nats_req.ParseFromString(msg.payload)
+                    # TODO 检查消息是否超时
+                    t = int(time.time())
+                    if t - nats_req.timestamp > nats_req.timeout:
+                        logging.debug("%s 这条消息超时了,舍弃" % (nats_req.msgId))
+                        return
+                    kwargs["data"] = nats_req.data
+                    bytes_result = func(*args, **kwargs)
+                    nats_resp = NatsResponse(msgId=nats_req.msgId, data=bytes_result)
+                    nc.publish(subject=PublishSubject, payload=nats_resp.SerializeToString())
+                except Exception as e:
+                    logging.warning(e)
+
+            logging.warning(f"服务启动成功......")
+            nc.subscribe(subject=ListenSubject, callback=message_handler, queue=queue)
+            nc.wait()
+
+    return wrapper

+ 6 - 0
demo/client.py

@@ -0,0 +1,6 @@
+# coding:utf-8
+from a2s_client import a2s_execute
+
+if __name__ == '__main__':
+    result = a2s_execute(a2s_ip="192.168.3.240:19094", topic="test", timeout=10, bytes_data=b"hello")
+    print(result.decode("utf-8"))

+ 40 - 0
demo/server.py

@@ -0,0 +1,40 @@
+from a2s_server import watch, simple_params
+
+#方式一 使用简单方式启动   .py文件命令行参数   python server.py --h
+@simple_params
+@watch
+def main(data: bytes, *args, **kwargs) -> bytes:
+    '''
+
+    :param data: 固定格式
+    :param args: 固定格式
+    :param kwargs: 固定格式
+    :return:
+    '''
+    # 内部处理程序
+    data = data.decode("utf-8")
+    data += "服务端处理过了数据"
+    return data.encode("utf-8")
+
+main()
+# 方式二 使用简单方式启动   .py文件命令行参数   python server.py --h
+
+@watch
+def main(data: bytes, *args, **kwargs) -> bytes:
+    '''
+
+    :param data: 固定格式
+    :param args: 固定格式
+    :param kwargs: 固定格式
+    :return:
+    '''
+    # 内部处理程序
+    data = data.decode("utf-8")
+    data += "服务端处理过了数据"
+    return data.encode("utf-8")
+
+main(nats_host="192.168.3.240",nats_port=19090,subject="test",queue="main")
+
+方式一,更简单方式启动
+方法二,灵活性更高
+推荐使用方法一

BIN
proto/__pycache__/service_pb2.cpython-37.pyc


BIN
proto/__pycache__/service_pb2_grpc.cpython-37.pyc


+ 43 - 0
proto/service.proto

@@ -0,0 +1,43 @@
+syntax = "proto3";
+package main;
+option go_package = ".;a2s";
+
+service Caller {
+  //远程调用
+  rpc Call (Request) returns (Response) {}
+  //状态查看
+  rpc ViewState(Empty)returns(State){}
+}
+//请求
+message Request {
+  string topic = 1;//主题
+  int64 timeout = 2;//超时设定
+  bytes data =3;//数据序列化
+}
+//回应
+message Response {
+  int32 code =1;//返回码
+  string msg = 2;//
+  bytes data =3;//结构数据
+}
+//空消息体
+message Empty{
+	
+}
+//状态消息体
+message State{
+  int32 currentRequest =1 ; //当前处理的请求数
+}
+
+//发送给nats的消息体
+message NatsRequest{
+	string msgId =1;
+	int64 timestamp = 2;
+	int64  timeout =3;
+	bytes data=4;
+}
+//回应给nats的消息体
+message NatsResponse{
+	string msgId =1;
+	bytes data=4;
+}

+ 346 - 0
proto/service_pb2.py

@@ -0,0 +1,346 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: service.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='service.proto',
+  package='main',
+  syntax='proto3',
+  serialized_options=b'Z\005.;a2s',
+  serialized_pb=b'\n\rservice.proto\x12\x04main\"7\n\x07Request\x12\r\n\x05topic\x18\x01 \x01(\t\x12\x0f\n\x07timeout\x18\x02 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"3\n\x08Response\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0b\n\x03msg\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\x07\n\x05\x45mpty\"\x1f\n\x05State\x12\x16\n\x0e\x63urrentRequest\x18\x01 \x01(\x05\"N\n\x0bNatsRequest\x12\r\n\x05msgId\x18\x01 \x01(\t\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\x12\x0f\n\x07timeout\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\"+\n\x0cNatsResponse\x12\r\n\x05msgId\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x32Z\n\x06\x43\x61ller\x12\'\n\x04\x43\x61ll\x12\r.main.Request\x1a\x0e.main.Response\"\x00\x12\'\n\tViewState\x12\x0b.main.Empty\x1a\x0b.main.State\"\x00\x42\x07Z\x05.;a2sb\x06proto3'
+)
+
+
+
+
+_REQUEST = _descriptor.Descriptor(
+  name='Request',
+  full_name='main.Request',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='topic', full_name='main.Request.topic', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='timeout', full_name='main.Request.timeout', index=1,
+      number=2, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='data', full_name='main.Request.data', index=2,
+      number=3, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=23,
+  serialized_end=78,
+)
+
+
+_RESPONSE = _descriptor.Descriptor(
+  name='Response',
+  full_name='main.Response',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='code', full_name='main.Response.code', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='msg', full_name='main.Response.msg', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='data', full_name='main.Response.data', index=2,
+      number=3, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=80,
+  serialized_end=131,
+)
+
+
+_EMPTY = _descriptor.Descriptor(
+  name='Empty',
+  full_name='main.Empty',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=133,
+  serialized_end=140,
+)
+
+
+_STATE = _descriptor.Descriptor(
+  name='State',
+  full_name='main.State',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='currentRequest', full_name='main.State.currentRequest', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=142,
+  serialized_end=173,
+)
+
+
+_NATSREQUEST = _descriptor.Descriptor(
+  name='NatsRequest',
+  full_name='main.NatsRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='msgId', full_name='main.NatsRequest.msgId', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='timestamp', full_name='main.NatsRequest.timestamp', index=1,
+      number=2, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='timeout', full_name='main.NatsRequest.timeout', index=2,
+      number=3, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='data', full_name='main.NatsRequest.data', index=3,
+      number=4, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=175,
+  serialized_end=253,
+)
+
+
+_NATSRESPONSE = _descriptor.Descriptor(
+  name='NatsResponse',
+  full_name='main.NatsResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='msgId', full_name='main.NatsResponse.msgId', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='data', full_name='main.NatsResponse.data', index=1,
+      number=4, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=255,
+  serialized_end=298,
+)
+
+DESCRIPTOR.message_types_by_name['Request'] = _REQUEST
+DESCRIPTOR.message_types_by_name['Response'] = _RESPONSE
+DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
+DESCRIPTOR.message_types_by_name['State'] = _STATE
+DESCRIPTOR.message_types_by_name['NatsRequest'] = _NATSREQUEST
+DESCRIPTOR.message_types_by_name['NatsResponse'] = _NATSRESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Request = _reflection.GeneratedProtocolMessageType('Request', (_message.Message,), {
+  'DESCRIPTOR' : _REQUEST,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:main.Request)
+  })
+_sym_db.RegisterMessage(Request)
+
+Response = _reflection.GeneratedProtocolMessageType('Response', (_message.Message,), {
+  'DESCRIPTOR' : _RESPONSE,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:main.Response)
+  })
+_sym_db.RegisterMessage(Response)
+
+Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), {
+  'DESCRIPTOR' : _EMPTY,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:main.Empty)
+  })
+_sym_db.RegisterMessage(Empty)
+
+State = _reflection.GeneratedProtocolMessageType('State', (_message.Message,), {
+  'DESCRIPTOR' : _STATE,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:main.State)
+  })
+_sym_db.RegisterMessage(State)
+
+NatsRequest = _reflection.GeneratedProtocolMessageType('NatsRequest', (_message.Message,), {
+  'DESCRIPTOR' : _NATSREQUEST,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:main.NatsRequest)
+  })
+_sym_db.RegisterMessage(NatsRequest)
+
+NatsResponse = _reflection.GeneratedProtocolMessageType('NatsResponse', (_message.Message,), {
+  'DESCRIPTOR' : _NATSRESPONSE,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:main.NatsResponse)
+  })
+_sym_db.RegisterMessage(NatsResponse)
+
+
+DESCRIPTOR._options = None
+
+_CALLER = _descriptor.ServiceDescriptor(
+  name='Caller',
+  full_name='main.Caller',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  serialized_start=300,
+  serialized_end=390,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='Call',
+    full_name='main.Caller.Call',
+    index=0,
+    containing_service=None,
+    input_type=_REQUEST,
+    output_type=_RESPONSE,
+    serialized_options=None,
+  ),
+  _descriptor.MethodDescriptor(
+    name='ViewState',
+    full_name='main.Caller.ViewState',
+    index=1,
+    containing_service=None,
+    input_type=_EMPTY,
+    output_type=_STATE,
+    serialized_options=None,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_CALLER)
+
+DESCRIPTOR.services_by_name['Caller'] = _CALLER
+
+# @@protoc_insertion_point(module_scope)

+ 98 - 0
proto/service_pb2_grpc.py

@@ -0,0 +1,98 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+import grpc
+
+import proto.service_pb2 as service__pb2
+
+
+class CallerStub(object):
+    """Missing associated documentation comment in .proto file"""
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.Call = channel.unary_unary(
+                '/main.Caller/Call',
+                request_serializer=service__pb2.Request.SerializeToString,
+                response_deserializer=service__pb2.Response.FromString,
+                )
+        self.ViewState = channel.unary_unary(
+                '/main.Caller/ViewState',
+                request_serializer=service__pb2.Empty.SerializeToString,
+                response_deserializer=service__pb2.State.FromString,
+                )
+
+
+class CallerServicer(object):
+    """Missing associated documentation comment in .proto file"""
+
+    def Call(self, request, context):
+        """远程调用
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def ViewState(self, request, context):
+        """状态查看
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_CallerServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'Call': grpc.unary_unary_rpc_method_handler(
+                    servicer.Call,
+                    request_deserializer=service__pb2.Request.FromString,
+                    response_serializer=service__pb2.Response.SerializeToString,
+            ),
+            'ViewState': grpc.unary_unary_rpc_method_handler(
+                    servicer.ViewState,
+                    request_deserializer=service__pb2.Empty.FromString,
+                    response_serializer=service__pb2.State.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'main.Caller', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class Caller(object):
+    """Missing associated documentation comment in .proto file"""
+
+    @staticmethod
+    def Call(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/main.Caller/Call',
+            service__pb2.Request.SerializeToString,
+            service__pb2.Response.FromString,
+            options, channel_credentials,
+            call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def ViewState(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/main.Caller/ViewState',
+            service__pb2.Empty.SerializeToString,
+            service__pb2.State.FromString,
+            options, channel_credentials,
+            call_credentials, compression, wait_for_ready, timeout, metadata)

+ 12 - 0
proto/text2vector.proto

@@ -0,0 +1,12 @@
+syntax = "proto3";
+package proto;
+
+//请求
+message Text2VectorReq{
+    string text = 1;
+}
+
+//响应
+message Text2VectorResp{
+  repeated float vector = 1;
+}

+ 107 - 0
proto/text2vector_pb2.py

@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: text2vector.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='text2vector.proto',
+  package='proto',
+  syntax='proto3',
+  serialized_options=None,
+  serialized_pb=b'\n\x11text2vector.proto\x12\x05proto\"\x1e\n\x0eText2VectorReq\x12\x0c\n\x04text\x18\x01 \x01(\t\"!\n\x0fText2VectorResp\x12\x0e\n\x06vector\x18\x01 \x03(\x02\x62\x06proto3'
+)
+
+
+
+
+_TEXT2VECTORREQ = _descriptor.Descriptor(
+  name='Text2VectorReq',
+  full_name='proto.Text2VectorReq',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='text', full_name='proto.Text2VectorReq.text', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=28,
+  serialized_end=58,
+)
+
+
+_TEXT2VECTORRESP = _descriptor.Descriptor(
+  name='Text2VectorResp',
+  full_name='proto.Text2VectorResp',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='vector', full_name='proto.Text2VectorResp.vector', index=0,
+      number=1, type=2, cpp_type=6, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=60,
+  serialized_end=93,
+)
+
+DESCRIPTOR.message_types_by_name['Text2VectorReq'] = _TEXT2VECTORREQ
+DESCRIPTOR.message_types_by_name['Text2VectorResp'] = _TEXT2VECTORRESP
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Text2VectorReq = _reflection.GeneratedProtocolMessageType('Text2VectorReq', (_message.Message,), {
+  'DESCRIPTOR' : _TEXT2VECTORREQ,
+  '__module__' : 'text2vector_pb2'
+  # @@protoc_insertion_point(class_scope:proto.Text2VectorReq)
+  })
+_sym_db.RegisterMessage(Text2VectorReq)
+
+Text2VectorResp = _reflection.GeneratedProtocolMessageType('Text2VectorResp', (_message.Message,), {
+  'DESCRIPTOR' : _TEXT2VECTORRESP,
+  '__module__' : 'text2vector_pb2'
+  # @@protoc_insertion_point(class_scope:proto.Text2VectorResp)
+  })
+_sym_db.RegisterMessage(Text2VectorResp)
+
+
+# @@protoc_insertion_point(module_scope)

+ 3 - 0
proto/text2vector_pb2_grpc.py

@@ -0,0 +1,3 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+import grpc
+

+ 4 - 0
requirement.txt

@@ -0,0 +1,4 @@
+grpcio==1.28.1
+grpcio-tools==1.28.1
+nats-python==0.8.0
+protobuf==4.24.3

+ 49 - 0
tools.py

@@ -0,0 +1,49 @@
+# coding:utf-8
+import json
+
+
+def grpc_serialize(resp):
+    """
+    grpc对象序列化
+    :param resp:resp = Text2VectorReq(text=data)
+    :return:
+    """
+    return resp.SerializeToString()
+
+
+def grpc_deserialize(req, data):
+    """
+    grpc对象反序列化
+    :param req: req = Text2VectorResp()
+    :param data: req的序列化对象
+    :return:
+    """
+    return req.ParseFromString(data)
+
+
+def json_serialize(dict_data):
+    """
+    json对象序列化
+    :param resp: 字典
+    :return:
+    """
+    # 将字典转换为 JSON 格式的字符串
+    json_data = json.dumps(dict_data)
+
+    # 将 JSON 字符串转换为字节流
+    bytes_data = json_data.encode('utf-8')
+    return bytes_data
+
+
+def json_deserialize(bytes_data):
+    """
+    grpc对象反序列化
+    :param bytes_data:
+    :return:
+    """
+    # 将字节流转换为 JSON 字符串
+    json_data = bytes_data.decode('utf-8')
+
+    # 将 JSON 字符串转换为字典对象
+    dict_data = json.loads(json_data)
+    return dict_data