prepare for google translate
This commit is contained in:
@@ -13,14 +13,15 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Server ServerConfig
|
||||
Database DatabaseConfig
|
||||
Auth AuthConfig
|
||||
OAuth OAuthConfig
|
||||
App AppConfig
|
||||
Email EmailConfig
|
||||
I18n I18n
|
||||
Pdf PdfPrinter
|
||||
Server ServerConfig
|
||||
Database DatabaseConfig
|
||||
Auth AuthConfig
|
||||
OAuth OAuthConfig
|
||||
App AppConfig
|
||||
Email EmailConfig
|
||||
I18n I18n
|
||||
Pdf PdfPrinter
|
||||
GoogleTranslate GoogleTranslateConfig
|
||||
}
|
||||
|
||||
type I18n struct {
|
||||
@@ -82,6 +83,14 @@ type PdfPrinter struct {
|
||||
ServerUrl string `env:"PDF_SERVER_URL,http://localhost:8000"`
|
||||
}
|
||||
|
||||
// GoogleTranslateConfig holds configuration for the Google Cloud Translation API.
|
||||
// CredentialsFile should point to a service account JSON key file.
|
||||
// ProjectID is your Google Cloud project ID (e.g. "my-project-123").
|
||||
type GoogleTranslateConfig struct {
|
||||
CredentialsFile string `env:"GOOGLE_APPLICATION_CREDENTIALS"`
|
||||
ProjectID string `env:"GOOGLE_CLOUD_PROJECT_ID"`
|
||||
}
|
||||
|
||||
var cfg *Config
|
||||
|
||||
func init() {
|
||||
@@ -153,6 +162,11 @@ func load() *Config {
|
||||
slog.Error("not possible to load env variables for email : ", err.Error(), "")
|
||||
}
|
||||
|
||||
err = loadEnv(&cfg.GoogleTranslate)
|
||||
if err != nil {
|
||||
slog.Error("not possible to load env variables for google translate : ", err.Error(), "")
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
|
||||
@@ -5,32 +5,76 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.ma-al.com/goc_daniel/b2b/app/config"
|
||||
"git.ma-al.com/goc_daniel/b2b/app/db"
|
||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||
"git.ma-al.com/goc_daniel/b2b/app/service/langsService"
|
||||
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
||||
"google.golang.org/api/option"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/openai/openai-go/v3"
|
||||
"github.com/openai/openai-go/v3/option"
|
||||
"github.com/openai/openai-go/v3/responses"
|
||||
// [START translate_v3_import_client_library]
|
||||
"cloud.google.com/go/auth/credentials"
|
||||
translate "cloud.google.com/go/translate/apiv3"
|
||||
"cloud.google.com/go/translate/apiv3/translatepb"
|
||||
// [END translate_v3_import_client_library]
|
||||
)
|
||||
|
||||
type ProductDescriptionService struct {
|
||||
db *gorm.DB
|
||||
client openai.Client
|
||||
db *gorm.DB
|
||||
ctx context.Context
|
||||
googleCli translate.TranslationClient
|
||||
// projectID is the Google Cloud project ID used as the "parent" in API calls,
|
||||
// e.g. "projects/my-project-123/locations/global"
|
||||
projectID string
|
||||
}
|
||||
|
||||
// New creates a ProductDescriptionService and authenticates against the
|
||||
// Google Cloud Translation API using a service account key file.
|
||||
//
|
||||
// Required configuration (set in .env or environment):
|
||||
//
|
||||
// GOOGLE_APPLICATION_CREDENTIALS – absolute path to the service account JSON key file
|
||||
// GOOGLE_CLOUD_PROJECT_ID – your Google Cloud project ID
|
||||
//
|
||||
// The service account must have the "Cloud Translation API User" role
|
||||
// (roles/cloudtranslate.user) granted in Google Cloud IAM.
|
||||
func New() *ProductDescriptionService {
|
||||
ctx := context.Background()
|
||||
cfg := config.Get()
|
||||
|
||||
// Read the service account key file whose path comes from config / env.
|
||||
data, err := os.ReadFile(cfg.GoogleTranslate.CredentialsFile)
|
||||
if err != nil {
|
||||
log.Fatalf("productDescriptionService: cannot read credentials file %q: %v",
|
||||
cfg.GoogleTranslate.CredentialsFile, err)
|
||||
}
|
||||
|
||||
// Build OAuth2 credentials scoped to the Cloud Translation API.
|
||||
// The correct scope for Cloud Translation v3 is "cloud-translation".
|
||||
creds, err := credentials.DetectDefault(&credentials.DetectOptions{
|
||||
Scopes: []string{"https://www.googleapis.com/auth/cloud-translation"},
|
||||
CredentialsJSON: data,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("productDescriptionService: cannot build Google credentials: %v", err)
|
||||
}
|
||||
|
||||
googleCli, err := translate.NewTranslationClient(ctx, option.WithAuthCredentials(creds))
|
||||
if err != nil {
|
||||
log.Fatalf("productDescriptionService: cannot create Translation client: %v", err)
|
||||
}
|
||||
|
||||
return &ProductDescriptionService{
|
||||
db: db.Get(),
|
||||
client: openai.NewClient(option.WithAPIKey("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"),
|
||||
option.WithHTTPClient(&http.Client{Timeout: 300 * time.Second})),
|
||||
db: db.Get(),
|
||||
ctx: ctx,
|
||||
googleCli: *googleCli,
|
||||
projectID: cfg.GoogleTranslate.ProjectID,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +146,12 @@ func (s *ProductDescriptionService) SaveProductDescription(userID uint, productI
|
||||
return nil
|
||||
}
|
||||
|
||||
// Updates relevant fields with the "updates" map
|
||||
// TranslateProductDescription fetches the product description for productFromLangID,
|
||||
// translates every text field into productToLangID using the Google Cloud
|
||||
// Translation API (v3 TranslateText), and returns the translated record.
|
||||
//
|
||||
// The Google Cloud project must have the Cloud Translation API enabled and the
|
||||
// service account must hold the "Cloud Translation API User" role.
|
||||
func (s *ProductDescriptionService) TranslateProductDescription(userID uint, productID uint, productShopID uint, productFromLangID uint, productToLangID uint) (*model.ProductDescription, error) {
|
||||
var ProductDescription model.ProductDescription
|
||||
|
||||
@@ -148,21 +197,36 @@ func (s *ProductDescriptionService) TranslateProductDescription(userID uint, pro
|
||||
}
|
||||
request = cleanForPrompt(request)
|
||||
|
||||
openai_response, _ := s.client.Responses.New(context.Background(), responses.ResponseNewParams{
|
||||
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(request)},
|
||||
Model: openai.ChatModelGPT4_1Mini,
|
||||
// Model: openai.ChatModelGPT4_1Nano,
|
||||
})
|
||||
if openai_response.Status != "completed" {
|
||||
return nil, responseErrors.ErrOpenAIResponseFail
|
||||
// TranslateText is the standard Cloud Translation v3 endpoint.
|
||||
// "parent" must be "projects/<PROJECT_ID>/locations/global" (or a specific region).
|
||||
// MimeType "text/plain" is used because cleanForPrompt strips HTML attributes;
|
||||
// switch to "text/html" if you want Google to preserve HTML tags automatically.
|
||||
req := &translatepb.TranslateTextRequest{
|
||||
Parent: fmt.Sprintf("projects/%s/locations/global", s.projectID),
|
||||
TargetLanguageCode: lang.ISOCode,
|
||||
MimeType: "text/plain",
|
||||
Contents: []string{request},
|
||||
}
|
||||
responseGoogle, err := s.googleCli.TranslateText(s.ctx, req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TranslateText returns one Translation per input string.
|
||||
if len(responseGoogle.GetTranslations()) == 0 {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
response := responseGoogle.GetTranslations()[0].GetTranslatedText()
|
||||
|
||||
for i := 0; i < len(keys); i++ {
|
||||
success, resolution := resolveResponse(*fields[i], openai_response.OutputText(), keys[i])
|
||||
success, resolution := resolveResponse(*fields[i], response, keys[i])
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
*fields[i] = resolution
|
||||
|
||||
fmt.Println("resolution: ", resolution)
|
||||
}
|
||||
|
||||
return &ProductDescription, nil
|
||||
|
||||
Reference in New Issue
Block a user