translation endpoint!
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package productDescriptionService
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -9,17 +10,24 @@ import (
|
||||
|
||||
"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"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/openai/openai-go/v3"
|
||||
"github.com/openai/openai-go/v3/option"
|
||||
"github.com/openai/openai-go/v3/responses"
|
||||
)
|
||||
|
||||
type ProductDescriptionService struct {
|
||||
db *gorm.DB
|
||||
db *gorm.DB
|
||||
client openai.Client
|
||||
}
|
||||
|
||||
func New() *ProductDescriptionService {
|
||||
return &ProductDescriptionService{
|
||||
db: db.Get(),
|
||||
db: db.Get(),
|
||||
client: openai.NewClient(option.WithAPIKey("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")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,185 +118,148 @@ func (s *ProductDescriptionService) SaveProductDescription(userID uint, productI
|
||||
return nil
|
||||
}
|
||||
|
||||
// func (s *ProductDescriptionService) GetRepositoriesForUser(userID uint) ([]uint, error) {
|
||||
// var repoIDs []uint
|
||||
// Updates relevant fields with the "updates" map
|
||||
func (s *ProductDescriptionService) TranslateProductDescription(userID uint, productID uint, productShopID uint, productFromLangID uint, productToLangID uint) (*model.ProductDescription, error) {
|
||||
var ProductDescription model.ProductDescription
|
||||
|
||||
// err := s.db.
|
||||
// Table("customer_repo_accesses").
|
||||
// Where("user_id = ?", userID).
|
||||
// Pluck("repo_id", &repoIDs).Error
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("database error: %w", err)
|
||||
// }
|
||||
err := s.db.
|
||||
Table("ps_product_lang").
|
||||
Where("id_product = ? AND id_shop = ? AND id_lang = ?", productID, productShopID, productFromLangID).
|
||||
First(&ProductDescription).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("database error: %w", err)
|
||||
}
|
||||
|
||||
// return repoIDs, nil
|
||||
// }
|
||||
// we translate all changeable fields, and we keep the exact same HTML structure in relevant fields.
|
||||
lang, err := langsService.LangSrv.GetLanguageById(productToLangID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// func (s *RepoService) UserHasAccessToRepo(userID uint, repoID uint) (bool, error) {
|
||||
// var repositories []uint
|
||||
// var err error
|
||||
request := "Translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website.\n\n"
|
||||
request += "\n"
|
||||
request += "<translation_of_product_description>"
|
||||
request += ProductDescription.Description
|
||||
request += "</translation_of_product_description>"
|
||||
request += "\n"
|
||||
request += "Remember: translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website."
|
||||
request += "\n"
|
||||
request += "<translation_of_product_short_description>"
|
||||
request += ProductDescription.DescriptionShort
|
||||
request += "</translation_of_product_short_description>"
|
||||
request += "\n"
|
||||
request += "Remember: translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website."
|
||||
request += "\n"
|
||||
request += "<translation_of_product_meta_description>"
|
||||
request += ProductDescription.MetaDescription
|
||||
request += "</translation_of_product_meta_description>"
|
||||
request += "\n"
|
||||
request += "Remember: translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website."
|
||||
request += "\n"
|
||||
request += "<translation_of_product_meta_title>"
|
||||
request += ProductDescription.MetaTitle
|
||||
request += "</translation_of_product_meta_title>"
|
||||
request += "\n"
|
||||
request += "Remember: translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website."
|
||||
request += "\n"
|
||||
request += "<translation_of_product_name>"
|
||||
request += ProductDescription.Name
|
||||
request += "</translation_of_product_name>"
|
||||
request += "\n"
|
||||
request += "Remember: translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website."
|
||||
request += "\n"
|
||||
request += "<translation_of_display_text_available_now>"
|
||||
request += ProductDescription.AvailableNow
|
||||
request += "</translation_of_display_text_available_now>"
|
||||
request += "\n"
|
||||
request += "Remember: translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website."
|
||||
request += "\n"
|
||||
request += "<translation_of_display_text_available_later>"
|
||||
request += ProductDescription.AvailableLater
|
||||
request += "</translation_of_display_text_available_later>"
|
||||
request += "\n"
|
||||
request += "Remember: translate to " + lang.ISOCode + " without changing the html structure. You must only translate text visible on website."
|
||||
request += "\n"
|
||||
request += "<translation_of_product_usage>"
|
||||
request += ProductDescription.Usage
|
||||
request += "</translation_of_product_usage>"
|
||||
|
||||
// if repositories, err = s.GetRepositoriesForUser(userID); err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
openai_response, err := 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
|
||||
}
|
||||
output := openai_response.OutputText()
|
||||
|
||||
// if !slices.Contains(repositories, repoID) {
|
||||
// return false, responseErrors.ErrInvalidRepoID
|
||||
// }
|
||||
// for debugging purposes
|
||||
// fi, err := os.ReadFile("/home/daniel/coding/work/b2b/app/service/productDescriptionService/test.txt") // just pass the file name
|
||||
// output := string(fi)
|
||||
|
||||
// return true, nil
|
||||
// }
|
||||
success, match := GetStringInBetween(output, "<translation_of_product_description>", "</translation_of_product_description>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.Description = match
|
||||
|
||||
// // Extract all repositories assigned to user with specific id
|
||||
// func (s *RepoService) GetYearsForUser(userID uint, repoID uint) ([]uint, error) {
|
||||
// if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok {
|
||||
// return nil, err
|
||||
// }
|
||||
success, match = GetStringInBetween(output, "<translation_of_product_short_description>", "</translation_of_product_short_description>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.DescriptionShort = match
|
||||
|
||||
// years, err := s.GetYears(repoID)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("database error: %w", err)
|
||||
// }
|
||||
success, match = GetStringInBetween(output, "<translation_of_product_meta_description>", "</translation_of_product_meta_description>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.MetaDescription = match
|
||||
|
||||
// return years, nil
|
||||
// }
|
||||
success, match = GetStringInBetween(output, "<translation_of_product_meta_title>", "</translation_of_product_meta_title>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.MetaTitle = match
|
||||
|
||||
// func (s *RepoService) GetYears(repo uint) ([]uint, error) {
|
||||
success, match = GetStringInBetween(output, "<translation_of_product_name>", "</translation_of_product_name>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.Name = match
|
||||
|
||||
// var years []uint
|
||||
success, match = GetStringInBetween(output, "<translation_of_display_text_available_now>", "</translation_of_display_text_available_now>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.AvailableNow = match
|
||||
|
||||
// query := `
|
||||
// WITH bounds AS (
|
||||
// SELECT
|
||||
// MIN(to_timestamp(tt.created_unix)) AS min_ts,
|
||||
// MAX(to_timestamp(tt.created_unix)) AS max_ts
|
||||
// FROM tracked_time tt
|
||||
// JOIN issue i ON i.id = tt.issue_id
|
||||
// WHERE i.repo_id = ?
|
||||
// AND tt.deleted = false
|
||||
// )
|
||||
// SELECT
|
||||
// EXTRACT(YEAR FROM y.year_start)::int AS year
|
||||
// FROM bounds
|
||||
// CROSS JOIN LATERAL generate_series(
|
||||
// date_trunc('year', min_ts),
|
||||
// date_trunc('year', max_ts),
|
||||
// interval '1 year'
|
||||
// ) AS y(year_start)
|
||||
// ORDER BY year
|
||||
// `
|
||||
success, match = GetStringInBetween(output, "<translation_of_display_text_available_later>", "</translation_of_display_text_available_later>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.AvailableLater = match
|
||||
|
||||
// err := db.Get().Raw(query, repo).Find(&years).Error
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return years, nil
|
||||
// }
|
||||
success, match = GetStringInBetween(output, "<translation_of_product_usage>", "</translation_of_product_usage>")
|
||||
if !success {
|
||||
return nil, responseErrors.ErrOpenAIBadOutput
|
||||
}
|
||||
ProductDescription.Usage = match
|
||||
|
||||
// // Extract all repositories assigned to user with specific id
|
||||
// func (s *RepoService) GetQuartersForUser(userID uint, repoID uint, year uint) ([]model.QuarterData, error) {
|
||||
// if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok {
|
||||
// return nil, err
|
||||
// }
|
||||
return &ProductDescription, nil
|
||||
}
|
||||
|
||||
// response, err := s.GetQuarters(repoID, year)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("database error: %w", err)
|
||||
// }
|
||||
// GetStringInBetween returns empty string if no start or end string found
|
||||
func GetStringInBetween(str string, start string, end string) (success bool, result string) {
|
||||
s := strings.Index(str, start)
|
||||
if s == -1 {
|
||||
return false, ""
|
||||
}
|
||||
s += len(start)
|
||||
e := strings.Index(str[s:], end)
|
||||
if e == -1 {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// return response, nil
|
||||
// }
|
||||
|
||||
// func (s *RepoService) GetQuarters(repo uint, year uint) ([]model.QuarterData, error) {
|
||||
// var quarters []model.QuarterData
|
||||
|
||||
// query := `
|
||||
// WITH quarters AS (
|
||||
// SELECT
|
||||
// make_date(?::int, 1, 1) + (q * interval '3 months') AS quarter_start,
|
||||
// q + 1 AS quarter
|
||||
// FROM generate_series(0, 3) AS q
|
||||
// ),
|
||||
// data AS (
|
||||
// SELECT
|
||||
// EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) AS quarter,
|
||||
// SUM(tt.time) / 3600 AS time
|
||||
// FROM tracked_time tt
|
||||
// JOIN issue i ON i.id = tt.issue_id
|
||||
// JOIN repository r ON i.repo_id = r.id
|
||||
// WHERE
|
||||
// EXTRACT(YEAR FROM to_timestamp(tt.created_unix)) = ?
|
||||
// AND r.id = ?
|
||||
// AND tt.deleted = false
|
||||
// GROUP BY EXTRACT(QUARTER FROM to_timestamp(tt.created_unix))
|
||||
// )
|
||||
// SELECT
|
||||
// COALESCE(d.time, 0) AS time,
|
||||
// CONCAT(EXTRACT(YEAR FROM q.quarter_start)::int, '_Q', q.quarter) AS quarter
|
||||
// FROM quarters q
|
||||
// LEFT JOIN data d ON d.quarter = q.quarter
|
||||
// ORDER BY q.quarter
|
||||
// `
|
||||
|
||||
// err := db.Get().
|
||||
// Raw(query, year, year, repo).
|
||||
// Find(&quarters).
|
||||
// Error
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// return quarters, nil
|
||||
// }
|
||||
|
||||
// func (s *RepoService) GetIssuesForUser(
|
||||
// userID uint,
|
||||
// repoID uint,
|
||||
// year uint,
|
||||
// quarter uint,
|
||||
// p pagination.Paging,
|
||||
// ) (*pagination.Found[model.IssueTimeSummary], error) {
|
||||
// if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// return s.GetIssues(repoID, year, quarter, p)
|
||||
// }
|
||||
|
||||
// func (s *RepoService) GetIssues(
|
||||
// repoId uint,
|
||||
// year uint,
|
||||
// quarter uint,
|
||||
// p pagination.Paging,
|
||||
// ) (*pagination.Found[model.IssueTimeSummary], error) {
|
||||
|
||||
// query := db.Get().
|
||||
// Table("issue i").
|
||||
// Select(`
|
||||
// i.id AS issue_id,
|
||||
// i.name AS issue_name,
|
||||
// to_timestamp(i.created_unix) AS issue_created_at,
|
||||
// ROUND(SUM(tt.time) / 3600.0, 2) AS total_hours_spent
|
||||
// `).
|
||||
// Joins(`JOIN tracked_time tt ON tt.issue_id = i.id`).
|
||||
// Joins(`JOIN "user" u ON u.id = tt.user_id`).
|
||||
// Where("i.repo_id = ?", repoId).
|
||||
// Where(`
|
||||
// EXTRACT(YEAR FROM to_timestamp(tt.created_unix)) = ?
|
||||
// AND EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) = ?
|
||||
// `, year, quarter).
|
||||
// Group(`
|
||||
// i.id,
|
||||
// i.name,
|
||||
// u.id,
|
||||
// u.full_name
|
||||
// `).
|
||||
// Order("i.created_unix")
|
||||
|
||||
// result, err := pagination.Paginate[model.IssueTimeSummary](p, query)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// return &result, nil
|
||||
// }
|
||||
return true, str[s : s+e]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user