首頁  >  文章  >  後端開發  >  Go 和 Python 之間的 gRPC 通信

Go 和 Python 之間的 gRPC 通信

WBOY
WBOY原創
2024-08-22 19:02:33707瀏覽

gRPC Communication Between Go and Python

gRPC 是一個強大、高效能的遠端過程呼叫 (RPC) 框架,儘管不如 REST 常用,但在某些場景下具有顯著的優勢。

此外,它與語言無關,可以在任何環境中運行,使其成為伺服器到伺服器通訊的理想選擇。

我不會深入研究它的完整解釋,但這裡是 gRPC 的一般連結。我將提供實作教學

Go 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 等等。


讓我們從安裝 gRPC 開始,最好是在您的 virtualenv .venv 中

$ 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"

接下來你應該在你的作業系統中安裝protocol buffer,可以按照這裡進行操作。
讓我們創建一個 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,vscode-proto3 是一個很好的擴展,值得下載。

完成所有這些之後,您可以生成原型文件,我更喜歡它與 prot 目錄處於同一級別,為此運行以下命令:

協定--go_out=. --go_opt=paths=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
}

我們建立一個連線來監聽 50051,它將成為我們的 Python 伺服器, &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 伺服器

由於 python 將充當伺服器,因此方法會略有不同,但本質上不需要套件欄位中的相同原型檔案。讓我們先建立一個沒有 gRPC 的基礎 main.py,只是為了看一下 GPT 如何在 excel 中填充問題。

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 發送給我們的問題,但由於專用的 openai 庫,LOC 較少,這使得它變得更容易。


我們首先新增具有與上面相同的檔案的原始目錄,可以按照討論刪除選項部分。最好在您的 virtualenv 中安裝 gRPC,然後按照我運行的原型生成安裝“

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

與我的原始目錄處於相同的lvl記得添加__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()

我們定義伺服器並新增 ExcelService 類,其中包含 proto 檔案產生的方法。因為我們按位元組接收文件,所以必須使用 io 位元組讀取器並開始進一步處理文件並填充第二列。

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

最後我們將返回 ☝️ 供 Go 客戶端接收。

為了能夠在Python中找到proto文件,但你應該定義一個導出路徑

導出 PYTHONPATH=$PYTHONPATH:mnt/c/own_dev/gRPC/server/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,我們建立了一種無縫方式,將 Excel 文件從 Go 應用程式傳送到 Python 伺服器,使用 OpenAI 的 GPT API 處理文件,並將修改後的文件傳回 Go 用戶端。

以上是Go 和 Python 之間的 gRPC 通信的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn