>  기사  >  백엔드 개발  >  Go와 Python 간의 gRPC 통신

Go와 Python 간의 gRPC 통신

WBOY
WBOY원래의
2024-08-22 19:02:33590검색

gRPC Communication Between Go and Python

gRPC는 REST보다 덜 일반적으로 사용되지만 특정 시나리오에서 상당한 이점을 제공하는 강력한 고성능 원격 프로시저 호출(RPC) 프레임워크입니다.

또한 언어에 구애받지 않고 모든 환경에서 실행될 수 있으므로 서버 간 통신에 이상적인 선택입니다.

전체적으로 설명하지는 않겠지만 gRPC의 일반적인 링크는 다음과 같습니다. 실습 튜토리얼을 제공해 드리겠습니다

gRPC 클라이언트로 이동 

Go는 클라이언트이지만 프런트엔드 앱인 React, Svelte 등의 서버임을 상상해 보세요.

func getFirstArg() (string, error) {
    if len(os.Args) < 2 {
        return "", fmt.Errorf("expected 1 argument, but got none")
    }
    return os.Args[1], nil
}

func main() {
    filePath, err := getFirstArg()
    if err != nil {
        log.Fatalf("Failed to get file path from arguments: %v", err)
    }

    fileData, err := ioutil.ReadFile(filePath)
    if err != nil {
        log.Fatalf("Failed to read file: %v", err)
    }

 ...
}

gRPC Communication Between Go and Python


예를 들어 React 프론트엔드가 파일을 업로드하고 Go가 이를 처리하지만 Excel의 답변이 필요하므로 GPT API를 사용하겠습니다. Go로도 가능하지만 Python에는 langchan_openai, pandas for excel 등과 같이 우리의 삶을 편하게 해주는 더 많은 패키지가 있습니다.


가급적이면 virtualenv .venv에 gRPC를 설치하는 것부터 시작하겠습니다

$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
$ export PATH="$PATH:$(go env GOPATH)/bin"

다음으로 OS에 프로토콜 버퍼를 설치해야 합니다.
프로토콜 버퍼 파일을 저장할 proto 디렉토리를 생성해 보겠습니다. 이름을 excel.proto로 지정하고 다음을 붙여넣습니다.

syntax = "proto3";
option go_package = "client-gRPC/proto";
service ExcelService {
    rpc UploadFile(FileRequest) returns (FileResponse);
}
message FileRequest {
    string file_name = 1;
    bytes file_content = 2;
}
message FileResponse {
    bytes file_content = 1;
}

이 gRPC 서비스인 ExcelService를 사용하면 클라이언트가 이름과 내용을 전송하여 파일을 업로드할 수 있습니다. 서버는 동일한 파일 내용으로 응답합니다. 

Go의 경우 Python에서 go_package를 전달하는 것이 필수적입니다.

vscode-proto3은 VSCode를 사용하는 경우 다운로드하기에 좋은 확장 프로그램입니다.

이 모든 작업을 마친 후 prot 파일을 생성할 수 있습니다. 저는 prot 디렉터리와 동일한 수준에서 이를 선호합니다. 그러려면 다음 명령을 실행하세요.

protoc --go_out=. --go_opt=경로=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/excel.proto

두 개의 파일이 성공적으로 생성되어야 하는 경우 선택적으로 조정이 많이 필요한 경우 Makefile을 추가하고 proto + upper 명령으로 정의합니다.

import (
    ....

    "google.golang.org/grpc"
    pb "client-gRPC/proto"
    "github.com/xuri/excelize/v2"
)

func main() {
    ....

    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("Failed to connect to gRPC server: %v", err)
    }
    defer conn.Close()

    client := pb.NewExcelServiceClient(conn)

    req := &pb.FileRequest{
        FileName:    filePath,
        FileContent: fileData,
    }

    res, err := client.UploadFile(context.Background(), req)
    if err != nil {
        log.Fatalf("Failed to upload file: %v", err)
    }

    outputFile := "output.xlsx"
    err = saveBytesAsExcel(outputFile, res.FileContent)
    if err != nil {
        log.Fatalf("Failed to save bytes as Excel file: %v", err)
    }

    fmt.Printf("Excel file saved as: %s\n", outputFile)
}

func saveBytesAsExcel(filePath string, fileContent []byte) error {
    f, err := excelize.OpenReader(bytes.NewReader(fileContent))
    if err != nil {
        return fmt.Errorf("failed to open Excel file: %v", err)
    }

    if err := f.SaveAs(filePath); err != nil {
        return fmt.Errorf("failed to save Excel file: %v", err)
    }
    return nil
}

Python 서버가 될 50051을 수신하기 위해 연결합니다. &pb.FileRequest는 proto 명령을 사용하여 이전에 생성되었으며 이제 메서드를 가져오는 중입니다. 달리면 받을 수 있나요? Python 서버가 아직 구축되지 않았기 때문입니다.

Failed to upload file: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp 127.0.0.1:50051: connect: connection refused"

Python gRPC 서버

파이썬이 서버 역할을 하기 때문에 접근 방식은 약간 다르지만 본질적으로 패키지 필드의 동일한 프로토 파일 구성은 필요하지 않습니다. GPT가 Excel에서 질문을 어떻게 채우는지 살펴보기 위해 gRPC 없이 기본 main.py를 만드는 것부터 시작해 보겠습니다.

import os
import openai
import pandas as pd
from dotenv import load_dotenv

def get_answer_from_gpt(apikey: str, question: str):
    openai.api_key = apikey
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": question}
        ]
    )
    return response['choices'][0]['message']['content'].strip()

def answer_questions_df(df: pd.DataFrame, apikey: str):
    answers = []

    for question in df.iloc[:, 0]: 
        answer = get_answer_from_gpt(apikey, question)
        answers.append(answer)
    return answers

if __name__ == "__main__":
    load_dotenv()

    openai_api_key = os.getenv("OPENAI_API_KEY", "OpenAI API key hasn't been set.")

    df = pd.read_excel('Book1.xlsx')

    df['Answer'] = answer_questions_df(df, openai_api_key

Go가 우리에게 보내는 질문에 답하는 간단한 스크립트이지만 LOC는 전용 openai 라이브러리 덕분에 더 쉬워집니다.


위와 동일한 파일로 proto 디렉토리를 추가하는 것부터 시작합니다. 옵션 섹션은 논의된 대로 제거될 수 있습니다. 가급적이면 virtualenv에 gRPC를 설치하고 여기에서 제가 실행한 proto 생성 설치를 따르세요."

python3 -m grpc_tools.protoc --proto_path=proto --python_out=proto --grpc_python_out=proto proto/excel.proto

내 proto 디렉토리와 동일한 레벨에 있으려면 __init.py를 추가하는 것을 잊지 마세요!

파일이 생성되었으면 계속 진행하세요.

import io
import grpc
from proto import excel_pb2_grpc as excel_grpc
from proto import excel_pb2

class ExcelService(excel_grpc.ExcelServiceServicer):
    def UploadFile(self, request, context):
        try:
            # Convert bytes to a file-like object
            file_like_object = io.BytesIO(request.file_content)

            # Load the workbook from the file-like object
            workbook = openpyxl.load_workbook(file_like_object)

            # Access the first sheet (or use appropriate logic to get the sheet you need)
            sheet = workbook.active

            # Convert the sheet to a DataFrame
            data = sheet.values
            columns = next(data)  # Get the header row
            df = pd.DataFrame(data, columns=columns)

            print("Loaded DataFrame:")
            print(df.head())

            # Ensure that the DataFrame is not empty and has questions
            if df.empty or df.shape[1] < 1:
                print("DataFrame is empty or does not have the expected columns.")
                return excel_pb2.FileResponse(file_content=b'')

            # Get answers and add them to the DataFrame
            answers = answer_questions_df(df, openai_api_key)
            df['Answer'] = answers

            # Write the updated DataFrame back to a BytesIO object
            output = io.BytesIO()
            with pd.ExcelWriter(output, engine='openpyxl') as writer:
                df.to_excel(writer, index=False, sheet_name='Sheet1')

            # Reset the buffer's position to the beginning
            output.seek(0)

            # Return the modified file content
            response = excel_pb2.FileResponse(file_content=output.read())
            return response
        except Exception as e:
            print(f"Error processing file: {e}")
            return excel_pb2.FileResponse(file_content=b'')

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    excel_grpc.add_ExcelServiceServicer_to_server(ExcelService(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    print("Server running on port 50051.")
    server.wait_for_termination()

if __name__ == "__main__":
    load_dotenv()

    openai_api_key = os.getenv("OPENAI_API_KEY", "OpenAI API key hasn't been set.")

    serve()

서버를 정의하고 proto 파일에서 생성된 메소드가 포함된 ExcelService 클래스를 추가합니다. 바이트 단위로 파일을 수신하기 때문에 io 바이트 리더를 사용하고 파일의 추가 처리를 시작하고 두 번째 열을 채워야 합니다.

response = excel_pb2.FileResponse(file_content=output.read())

마지막에 Go 클라이언트가 받을 수 있도록 ☝️로 돌아갑니다.

Python에서 proto 파일을 찾으려면 내보내기 경로를 정의해야 합니다

PYTHONPATH=$PYTHONPATH:mnt/c/own_dev/gRPC/서버/proto 내보내기

클라이언트 및 서버 실행

If all is good you can run

#First comes server

python3 -m main

#Then client

go run client.go Book1.xlsx

Go 클라이언트 측에서 업데이트된 .xlsx 파일을 받아야 합니다.

결론

이 기사에서는 Python 서버와 Go 클라이언트 간의 gRPC 통신 설정의 기본 사항을 살펴보았습니다. gRPC를 활용하여 Go 애플리케이션에서 Python 서버로 Excel 파일을 보내고, OpenAI의 GPT API를 사용하여 파일을 처리하고, 수정된 파일을 Go 클라이언트로 다시 반환하는 원활한 방법을 확립했습니다.

위 내용은 Go와 Python 간의 gRPC 통신의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.