Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into test
This commit is contained in:
@@ -32,8 +32,7 @@ func ProductDescriptionHandlerRoutes(r fiber.Router) fiber.Router {
|
||||
|
||||
r.Get("/get-product-description", handler.GetProductDescription)
|
||||
r.Post("/save-product-description", handler.SaveProductDescription)
|
||||
// r.Get("/get-quarters", handler.GetQuarters)
|
||||
// r.Get("/get-issues", handler.GetIssues)
|
||||
r.Get("/translate-product-description", handler.TranslateProductDescription)
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -132,3 +131,54 @@ func (h *ProductDescriptionHandler) SaveProductDescription(c fiber.Ctx) error {
|
||||
"message": i18n.T_(c, "product_description.successfully_updated_fields"),
|
||||
})
|
||||
}
|
||||
|
||||
// GetProductDescription returns the product description for a given product ID
|
||||
func (h *ProductDescriptionHandler) TranslateProductDescription(c fiber.Ctx) error {
|
||||
userID, ok := c.Locals("userID").(uint)
|
||||
if !ok {
|
||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).JSON(fiber.Map{
|
||||
"error": responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody), // possibly could return a different error
|
||||
})
|
||||
}
|
||||
|
||||
productID_attribute := c.Query("productID")
|
||||
productID, err := strconv.Atoi(productID_attribute)
|
||||
if err != nil {
|
||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).JSON(fiber.Map{
|
||||
"error": responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute),
|
||||
})
|
||||
}
|
||||
|
||||
productShopID_attribute := c.Query("productShopID")
|
||||
productShopID, err := strconv.Atoi(productShopID_attribute)
|
||||
if err != nil {
|
||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).JSON(fiber.Map{
|
||||
"error": responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute),
|
||||
})
|
||||
}
|
||||
|
||||
productFromLangID_attribute := c.Query("productFromLangID")
|
||||
productFromLangID, err := strconv.Atoi(productFromLangID_attribute)
|
||||
if err != nil {
|
||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).JSON(fiber.Map{
|
||||
"error": responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute),
|
||||
})
|
||||
}
|
||||
|
||||
productToLangID_attribute := c.Query("productToLangID")
|
||||
productToLangID, err := strconv.Atoi(productToLangID_attribute)
|
||||
if err != nil {
|
||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).JSON(fiber.Map{
|
||||
"error": responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute),
|
||||
})
|
||||
}
|
||||
|
||||
response, err := h.productDescriptionService.TranslateProductDescription(userID, uint(productID), uint(productShopID), uint(productFromLangID), uint(productToLangID))
|
||||
if err != nil {
|
||||
return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{
|
||||
"error": responseErrors.GetErrorCode(c, err),
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(response)
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ func (s *LangService) GetLanguageByISOCode(isoCode string) (*view.Language, erro
|
||||
return s.repo.GetByISOCode(isoCode)
|
||||
}
|
||||
|
||||
// GetLanguageByISOCode returns a language by its ISO code
|
||||
// GetLanguageByISOCode returns a language by its id
|
||||
func (s *LangService) GetLanguageById(id uint) (*view.Language, error) {
|
||||
return s.repo.GetById(id)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
client openai.Client
|
||||
}
|
||||
|
||||
func New() *ProductDescriptionService {
|
||||
return &ProductDescriptionService{
|
||||
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]
|
||||
}
|
||||
|
||||
158
app/service/productDescriptionService/test.txt
Normal file
158
app/service/productDescriptionService/test.txt
Normal file
@@ -0,0 +1,158 @@
|
||||
<translation_of_product_description><p>The use of rehabilitation rollers in various exercises and treatments positively affects the alleviation of injuries and increases the chances of the patient returning to full physical fitness. They are used in motor rehabilitation, during corrective gymnastics, traditional and sports massages, as they are ideal for lifting and separating limbs. They can also be used to support knees, feet, arms, and the patient’s shoulders. Rehabilitation rollers are also recommended for children; using them during play greatly supports the development of gross motor skills.</p>
|
||||
<p>Thanks to a wide color range and varied sizes, it is possible to compose an exercise set necessary in every physiotherapy office, massage room, as well as in schools and kindergartens.</p>
|
||||
<p>The rehabilitation roller is a medical device in accordance with the essential requirements for medical devices and the understanding of the Medical Devices Act, registered in the Medical Devices Register maintained by the Office for Registration of Medicinal Products, Medical Devices and Biocidal Products, equipped with the manufacturer's declaration of conformity and marked with the CE mark.</p>
|
||||
<p></p>
|
||||
<p><img src="https://www.naluconcept.com/img/cms/Logotypy/images.jpg" alt="Medical device" style="margin-left:auto;margin-right:auto;" width="253" height="86" /></p>
|
||||
<h4><strong>Recommended uses:</strong></h4>
|
||||
<ul style="list-style-type:circle;">
|
||||
<li>in rehabilitation</li>
|
||||
<li>during massages (traditional, sports)</li>
|
||||
<li>in corrective gymnastics (especially for children)</li>
|
||||
<li>in alleviating injuries to specific parts of the body</li>
|
||||
<li>for supporting: knees, ankles, the patient’s head</li>
|
||||
<li>in exercises developing children’s motor skills</li>
|
||||
<li>in beauty salons</li>
|
||||
<li>in children’s playrooms</li>
|
||||
</ul>
|
||||
<p></p>
|
||||
<h4><strong>Material specification:</strong></h4>
|
||||
<p><strong>Cover:</strong> material with a PVC coating intended for medical devices, making it very easy to clean and disinfect:</p>
|
||||
<ul style="list-style-type:circle;">
|
||||
<li>material compliant with REACH regulation, certified STANDARD 100 by OEKO-TEX ®</li>
|
||||
<li>phthalate-free</li>
|
||||
<li>fire-resistant</li>
|
||||
<li>resistant to physiological fluids (blood, urine, sweat) and alcohol</li>
|
||||
<li>UV resistant, so it can also be used outdoors</li>
|
||||
<li>scratch-resistant</li>
|
||||
<li>oil-resistant</li>
|
||||
</ul>
|
||||
<p><img src="https://www.naluconcept.com/img/cms/Logotypy/reach.jpg" alt="REACH" width="115" height="115" /><img src="https://www.naluconcept.com/img/cms/Logotypy/oeko-tex.jpg" alt="OEKO-TEX Standard 100 Certificate" width="116" height="114" /><img src="https://www.naluconcept.com/img/cms/Logotypy/phthalate-free.jpg" alt="Phthalate-free" width="112" height="111" /><img src="https://www.naluconcept.com/img/cms/Logotypy/fireresistant.jpg" alt="Fire-resistant" width="114" height="113" /><img src="https://www.naluconcept.com/img/cms/Logotypy/odporny-na-alkohol.jpg" alt="Alcohol-resistant" width="114" height="114" /><img src="https://www.naluconcept.com/img/cms/Logotypy/odporny-na-uv.jpg" alt="UV-resistant" width="117" height="116" /><img src="https://www.naluconcept.com/img/cms/Logotypy/outdoor.jpg" alt="Suitable for outdoor use" width="116" height="116" /><img src="https://www.naluconcept.com/img/cms/Logotypy/odporny-na-zadrapania.jpg" alt="Scratch-resistant" width="97" height="96" /><img src="https://www.naluconcept.com/img/cms/Logotypy/olejoodporny.jpg" alt="Oil-resistant" width="99" height="98" /></p>
|
||||
<p><strong>Filling:</strong> medium-hard polyurethane foam with increased resistance to deformation:</p>
|
||||
<ul style="list-style-type:circle;">
|
||||
<li>has a HYGIENIC CERTIFICATE issued by the Institute of Maritime and Tropical Medicine in Gdynia</li>
|
||||
<li>has a STANDARD 100 by OEKO-TEX ® certificate – product class I, issued by the Textile Institute in Łódź</li>
|
||||
<li>produced from high-quality raw materials that do not cause depletion of the ozone layer</li>
|
||||
</ul>
|
||||
<p><img src="https://www.naluconcept.com/img/cms/Logotypy/oeko-tex.jpg" alt="OEKO-TEX Standard 100 Certificate" width="95" height="95" /><img src="https://www.naluconcept.com/img/cms/Logotypy/Logo_GUMed_kolor-180x180.jpg" alt="Hygienic certificate" width="94" height="94" /><img src="https://www.naluconcept.com/img/cms/Logotypy/atest_higieniczny_kolor.jpg" alt="Hygienic certificate" width="79" height="94" /></p>
|
||||
<p></p>
|
||||
<p></p></translation_of_product_description>
|
||||
<translation_of_product_short_description><p>Rehabilitation rollers are used in various types of exercises. They are used in motor rehabilitation, during corrective gymnastics, traditional and sports massages, as they are ideal for lifting and separating limbs. They can also be used to support knees, feet, arms, and the patient’s shoulders. Rehabilitation rollers are also recommended for children; using them during play significantly supports the development of gross motor skills. The product is certified as a medical device.</p></translation_of_product_short_description>
|
||||
<translation_of_product_meta_description></translation_of_product_meta_description>
|
||||
<translation_of_product_meta_title></translation_of_product_meta_title>
|
||||
<translation_of_product_name>Rehabilitation roller 10 x 30 cm</translation_of_product_name>
|
||||
<translation_of_display_text_available_now>available</translation_of_display_text_available_now>
|
||||
<translation_of_display_text_available_later>on order</translation_of_display_text_available_later>
|
||||
<translation_of_product_usage><p>I. Cleaning and maintenance</p>
|
||||
<p>The upholstery should be cleaned superficially using permitted agents:</p>
|
||||
<table class="MsoNormalTable" style="margin-left: -5.4pt; border-collapse: collapse; mso-table-layout-alt: fixed; border: none; mso-border-alt: solid #1F3864 .5pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid #1F3864; mso-border-insideh-themecolor: accent5; mso-border-insideh-themeshade: 128; mso-border-insidev: .5pt solid #1F3864; mso-border-insidev-themecolor: accent5; mso-border-insidev-themeshade: 128;" width="764" cellspacing="0" cellpadding="0" border="1">
|
||||
<tbody>
|
||||
<tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; height: 36.5pt;">
|
||||
<td style="width: 111.5pt; border: solid #1F3864 1.0pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.5pt;" width="186" valign="top">
|
||||
<p class="Default"><span color="#002e59" face="Verdana, sans-serif" style="color: #002e59; font-family: Verdana, sans-serif;"><span style="font-size: 11.3333px;"><b>Type of dirt</b></span></span></p>
|
||||
</td>
|
||||
<td style="width: 155.4pt; border: solid #1F3864 1.0pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; border-left: none; mso-border-left-alt: solid #1F3864 .5pt; mso-border-left-themecolor: accent5; mso-border-left-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.5pt;" width="259" valign="top">
|
||||
<p class="Default"><span color="#002e59" face="Verdana, sans-serif" style="color: #002e59; font-family: Verdana, sans-serif;"><span style="font-size: 11.3333px;"><b>Permitted agents</b></span></span></p>
|
||||
</td>
|
||||
<td style="width: 191.35pt; border: solid #1F3864 1.0pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; border-left: none; mso-border-left-alt: solid #1F3864 .5pt; mso-border-left-themecolor: accent5; mso-border-left-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.5pt;" width="319" valign="top">
|
||||
<p class="Default"><span color="#002e59" face="Verdana, sans-serif" style="color: #002e59; font-family: Verdana, sans-serif;"><span style="font-size: 11.3333px;"><b>Procedure</b></span></span></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="mso-yfti-irow: 1; height: 36.5pt;">
|
||||
<td style="width: 111.5pt; border: solid #1F3864 1.0pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; border-top: none; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.5pt;" width="186" valign="top">
|
||||
<p class="Default"><span style="color: #002e59;"><b><span style="font-size: 8.5pt; font-family: Verdana, sans-serif;">Everyday dirt<o:p></o:p></span></b></span></p>
|
||||
<p class="Default"><span style="font-size: 8.5pt; font-family: Verdana, sans-serif; color: #002e59;"> </span></p>
|
||||
</td>
|
||||
<td style="width: 155.4pt; border-top: none; border-left: none; border-bottom: solid #1F3864 1.0pt; mso-border-bottom-themecolor: accent5; mso-border-bottom-themeshade: 128; border-right: solid #1F3864 1.0pt; mso-border-right-themecolor: accent5; mso-border-right-themeshade: 128; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-left-alt: solid #1F3864 .5pt; mso-border-left-themecolor: accent5; mso-border-left-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.5pt;" width="259" valign="top">
|
||||
<p class="Default"><span style="font-size: 8.5pt; font-family: Verdana, sans-serif; color: #002e59;">Mild detergent, preferably a solution of gray soap<o:p></o:p></span></p>
|
||||
</td>
|
||||
<td style="width: 191.35pt; border-top: none; border-left: none; border-bottom: solid #1F3864 1.0pt; mso-border-bottom-themecolor: accent5; mso-border-bottom-themeshade: 128; border-right: solid #1F3864 1.0pt; mso-border-right-themecolor: accent5; mso-border-right-themeshade: 128; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-left-alt: solid #1F3864 .5pt; mso-border-left-themecolor: accent5; mso-border-left-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.5pt;" width="319" valign="top">
|
||||
<p class="Default"><span style="font-size: 8.5pt; font-family: Verdana, sans-serif; color: #002e59;">Clean regularly using a sponge or soft brush. Finally, wipe the cleaned area with a damp cloth and then dry it (to remove detergent residues).<o:p></o:p></span></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="mso-yfti-irow: 2; height: 40.65pt;">
|
||||
<td style="width: 111.5pt; border: solid #1F3864 1.0pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; border-top: none; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 40.65pt;" width="186" valign="top">
|
||||
<p class="Default"><span style="color: #002e59;"><b><span style="font-size: 8.5pt; font-family: Verdana, sans-serif;">Local, stronger dirt<o:p></o:p></span></b></span></p>
|
||||
</td>
|
||||
<td style="width: 155.4pt; border-top: none; border-left: none; border-bottom: solid #1F3864 1.0pt; mso-border-bottom-themecolor: accent5; mso-border-bottom-themeshade: 128; border-right: solid #1F3864 1.0pt; mso-border-right-themecolor: accent5; mso-border-right-themeshade: 128; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-left-alt: solid #1F3864 .5pt; mso-border-left-themecolor: accent5; mso-border-left-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; padding: 0cm 5.4pt 0cm 5.4pt; height: 40.65pt;" width="259" valign="top">
|
||||
<p class="Default"><span style="font-size: 8.5pt; font-family: Verdana, sans-serif; color: #002e59;">25% ethyl alcohol solution<o:p></o:p></span></p>
|
||||
</td>
|
||||
<td style="width: 191.35pt; border-top: none; border-left: none; border-bottom: solid #1F3864 1.0pt; mso-border-bottom-themecolor: accent5; mso-border-bottom-themeshade: 128; border-right: solid #1F3864 1.0pt; mso-border-right-themecolor: accent5; mso-border-right-themeshade: 128; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-left-alt: solid #1F3864 .5pt; mso-border-left-themecolor: accent5; mso-border-left-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; padding: 0cm 5.4pt 0cm 5.4pt; height: 40.65pt;" width="319" valign="top">
|
||||
<p class="Default"><span style="font-size: 8.5pt; font-family: Verdana, sans-serif; color: #002e59;">Gently wipe with a gauze tampon soaked with the solution. Finally, wipe the cleaned area with a damp cloth and then dry it (to remove detergent residues).<o:p></o:p></span></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="mso-yfti-irow: 3; height: 36.35pt;">
|
||||
<td style="width: 111.5pt; border: solid #1F3864 1.0pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; border-top: none; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.35pt;" width="186" valign="top">
|
||||
<p class="Default"><span style="color: #002e59;"><b><span style="font-size: 8.5pt; font-family: Verdana, sans-serif;">Disinfection<o:p></o:p></span></b></span></p>
|
||||
</td>
|
||||
<td style="width: 155.4pt; border-top: none; border-left: none; border-bottom: solid #1F3864 1.0pt; mso-border-bottom-themecolor: accent5; mso-border-bottom-themeshade: 128; border-right: solid #1F3864 1.0pt; mso-border-right-themecolor: accent5; mso-border-right-themeshade: 128; mso-border-top-alt: solid #1F3864 .5pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.35pt;" width="259" valign="top">
|
||||
<p class="Default"><span style="font-size: 8.5pt; font-family: Verdana, sans-serif; color: #002e59;">Commercially available disinfectants containing:</span></p>
|
||||
<p class="Default"><span style="color: #002e59;">- active chlorine – sodium dichloroisocyanurate, max concentration 10000 ppm </span></p>
|
||||
<p><span style="color: #002e59;">- active chlorine - chlorine dioxide in a solution up to 20000 ppm </span></p>
|
||||
<p><span style="color: #002e59;">- isopropyl alcohol max concentration 70%</span> </p>
|
||||
<p></p>
|
||||
</td>
|
||||
<td style="width: 191.35pt; border-top: none; border-left: none; border-bottom: solid #1F3864 1.0pt; mso-border-bottom-themecolor: accent5; mso-border-bottom-themeshade: 128; border-right: solid #1F3864 1.0pt; mso-border-right-themecolor: accent5; mso-border-right-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; padding: 0cm 5.4pt 0cm 5.4pt; height: 36.35pt;" width="319" valign="top">
|
||||
<p class="Default"><span style="font-size: 8.5pt; font-family: Verdana, sans-serif; color: #002e59;">Disinfect according to the recommendations of the product manufacturer.<o:p></o:p></span></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="mso-yfti-irow: 4; mso-yfti-lastrow: yes; height: 11.05pt;">
|
||||
<td colspan="3" style="width: 458.25pt; border: solid #1F3864 1.0pt; mso-border-themecolor: accent5; mso-border-themeshade: 128; border-top: none; mso-border-top-alt: solid #1F3864 .5pt; mso-border-top-themecolor: accent5; mso-border-top-themeshade: 128; mso-border-alt: solid #1F3864 .5pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 11.05pt;" width="764" valign="top">
|
||||
<p class="Default"><span style="color: #002e59;"><b><span style="font-size: 8.5pt; font-family: 'Verdana',sans-serif;">Before using any agent other than a mild detergent, test the effect in an inconspicuous area, and perform cleaning very carefully.</span></b></span><span style="font-size: 8.5pt; font-family: 'Verdana',sans-serif;"><o:p></o:p></span></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><br />II. Information</p>
|
||||
<p></p>
|
||||
<table class="MsoTableGrid" style="width: 767px; margin-left: -7.35pt; border-collapse: collapse; border: none;" width="768" height="156" cellspacing="0" cellpadding="0" border="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 113.45pt; border: solid windowtext 1.0pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="189" valign="top"><img src="https://www.naluconcept.com/img/cms/Konserwacja/2.jpg" alt="" width="74" height="37" /></td>
|
||||
<td style="width: 347.25pt; border: solid windowtext 1.0pt; border-left: none; mso-border-left-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="579" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Shampoo using a sponge<o:p></o:p></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 113.45pt; border: solid windowtext 1.0pt; border-top: none; mso-border-top-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="189" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;"><o:p> <img src="https://www.naluconcept.com/img/cms/Konserwacja/3.jpg" alt="" width="68" height="43" /></o:p></p>
|
||||
</td>
|
||||
<td style="width: 347.25pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; mso-border-top-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="579" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Do not wash!!! (delicate products) <o:p></o:p></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 113.45pt; border: solid windowtext 1.0pt; border-top: none; mso-border-top-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="189" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal; text-align: left;"><o:p><img src="https://www.naluconcept.com/img/cms/Konserwacja/1.jpg" width="68" height="50" /></o:p></p>
|
||||
</td>
|
||||
<td style="width: 347.25pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; mso-border-top-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="579" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Do not bleach!!! (do not use bleaching agents that release free chlorine)<o:p></o:p></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 113.45pt; border: solid windowtext 1.0pt; border-top: none; mso-border-top-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="189" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;"><o:p> <img src="https://www.naluconcept.com/img/cms/Konserwacja/4.jpg" alt="" width="67" height="46" /></o:p></p>
|
||||
</td>
|
||||
<td style="width: 347.25pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; mso-border-top-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="579" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Do not iron!!! (avoid contact with hot surfaces such as radiators)<o:p></o:p></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 113.45pt; border: solid windowtext 1.0pt; border-top: none; mso-border-top-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="189" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;"><o:p> <img src="https://www.naluconcept.com/img/cms/Konserwacja/5.jpg" alt="" width="63" height="50" /></o:p></p>
|
||||
</td>
|
||||
<td style="width: 347.25pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; mso-border-top-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-alt: solid windowtext .5pt; padding: 0cm 5.4pt 0cm 5.4pt;" width="579" valign="top">
|
||||
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Do not dry clean!!!<o:p></o:p></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p></p>
|
||||
<p>III. Warranty conditions</p>
|
||||
<p>The warranty does not cover:</p>
|
||||
<ul style="list-style-type: circle;">
|
||||
<li>Permanent discoloration caused by contact with clothing containing active, migrating dyes (e.g., jeans, suede, etc.)</li>
|
||||
<li>Marks from pens, ink, markers, etc., containing active dyes</li>
|
||||
<li>Damage caused by high temperature, corrosive liquids, fire</li>
|
||||
<li>Mechanical damage caused by pets and other users</li>
|
||||
<li>Defects caused by improper maintenance</li>
|
||||
</ul></translation_of_product_usage>
|
||||
17
app/service/productDescriptionService/test2.txt
Normal file
17
app/service/productDescriptionService/test2.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -41,6 +41,8 @@ var (
|
||||
ErrBadAttribute = errors.New("bad attribute")
|
||||
ErrBadField = errors.New("this field can not be updated")
|
||||
ErrInvalidHTML = errors.New("text is not in html format")
|
||||
ErrOpenAIResponseFail = errors.New("OpenAI responded with failure")
|
||||
ErrOpenAIBadOutput = errors.New("OpenAI response does not obey the format")
|
||||
)
|
||||
|
||||
// Error represents an error with HTTP status code
|
||||
@@ -116,6 +118,10 @@ func GetErrorCode(c fiber.Ctx, err error) string {
|
||||
return i18n.T_(c, "error.err_bad_field")
|
||||
case errors.Is(err, ErrInvalidHTML):
|
||||
return i18n.T_(c, "error.err_invalid_html")
|
||||
case errors.Is(err, ErrOpenAIResponseFail):
|
||||
return i18n.T_(c, "error.err_openai_response_fail")
|
||||
case errors.Is(err, ErrOpenAIBadOutput):
|
||||
return i18n.T_(c, "error.err_openai_bad_output")
|
||||
|
||||
default:
|
||||
return i18n.T_(c, "error.err_internal_server_error")
|
||||
@@ -152,6 +158,9 @@ func GetErrorStatus(err error) int {
|
||||
return fiber.StatusBadRequest
|
||||
case errors.Is(err, ErrEmailExists):
|
||||
return fiber.StatusConflict
|
||||
case errors.Is(err, ErrOpenAIResponseFail),
|
||||
errors.Is(err, ErrOpenAIBadOutput):
|
||||
return fiber.StatusServiceUnavailable
|
||||
default:
|
||||
return fiber.StatusInternalServerError
|
||||
}
|
||||
|
||||
8
go.mod
8
go.mod
@@ -14,6 +14,13 @@ require (
|
||||
gorm.io/gorm v1.31.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
@@ -46,6 +53,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/onsi/gomega v1.39.1 // indirect
|
||||
github.com/openai/openai-go/v3 v3.26.0
|
||||
github.com/philhofer/fwd v1.2.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -94,6 +94,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
|
||||
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
|
||||
github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE=
|
||||
github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
|
||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
|
||||
@@ -119,6 +121,16 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s=
|
||||
github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
|
||||
@@ -1 +1 @@
|
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
|
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
|
||||
Reference in New Issue
Block a user