Class: Packages::AiTranslationService
- Inherits:
-
Object
- Object
- Packages::AiTranslationService
- Includes:
- ElasticAPM::SpanHelpers
- Defined in:
- app/services/packages/ai_translation_service.rb
Overview
Service for synchronous AI translation of package fields Uses OpenRouter API with Claude for high-quality translations Handles all package types: Ayce, PartyPack, BuffetExtra, HungryAtHome, SetMenu, Xperience, Diy
Instance Attribute Summary collapse
-
#only_blank_fields ⇒ Object
readonly
Returns the value of attribute only_blank_fields.
-
#only_blank_languages ⇒ Object
readonly
Returns the value of attribute only_blank_languages.
-
#package ⇒ Object
readonly
Returns the value of attribute package.
-
#source_language ⇒ Object
readonly
Returns the value of attribute source_language.
-
#target_fields ⇒ Object
readonly
Returns the value of attribute target_fields.
-
#target_languages ⇒ Object
readonly
Returns the value of attribute target_languages.
Instance Method Summary collapse
- #call ⇒ Object
-
#initialize(package, source_language: 'en', target_languages: [], target_fields: [], only_blank_languages: false, only_blank_fields: false) ⇒ AiTranslationService
constructor
A new instance of AiTranslationService.
Constructor Details
#initialize(package, source_language: 'en', target_languages: [], target_fields: [], only_blank_languages: false, only_blank_fields: false) ⇒ AiTranslationService
Returns a new instance of AiTranslationService.
14 15 16 17 18 19 20 21 |
# File 'app/services/packages/ai_translation_service.rb', line 14 def initialize(package, source_language: 'en', target_languages: [], target_fields: [], only_blank_languages: false, only_blank_fields: false) @package = package @source_language = source_language @target_languages = target_languages @target_fields = target_fields @only_blank_languages = only_blank_languages @only_blank_fields = only_blank_fields end |
Instance Attribute Details
#only_blank_fields ⇒ Object (readonly)
Returns the value of attribute only_blank_fields.
11 12 13 |
# File 'app/services/packages/ai_translation_service.rb', line 11 def only_blank_fields @only_blank_fields end |
#only_blank_languages ⇒ Object (readonly)
Returns the value of attribute only_blank_languages.
11 12 13 |
# File 'app/services/packages/ai_translation_service.rb', line 11 def only_blank_languages @only_blank_languages end |
#package ⇒ Object (readonly)
Returns the value of attribute package.
11 12 13 |
# File 'app/services/packages/ai_translation_service.rb', line 11 def package @package end |
#source_language ⇒ Object (readonly)
Returns the value of attribute source_language.
11 12 13 |
# File 'app/services/packages/ai_translation_service.rb', line 11 def source_language @source_language end |
#target_fields ⇒ Object (readonly)
Returns the value of attribute target_fields.
11 12 13 |
# File 'app/services/packages/ai_translation_service.rb', line 11 def target_fields @target_fields end |
#target_languages ⇒ Object (readonly)
Returns the value of attribute target_languages.
11 12 13 |
# File 'app/services/packages/ai_translation_service.rb', line 11 def target_languages @target_languages end |
Instance Method Details
#call ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'app/services/packages/ai_translation_service.rb', line 23 def call validate_inputs! # Determine actual languages and fields to translate actual_languages = determine_target_languages actual_fields = determine_target_fields return failure_result('No languages to translate') if actual_languages.blank? return failure_result('No fields to translate') if actual_fields.blank? # Filter out language-field combinations that already have content languages_needing_translation, fields_needing_translation = filter_existing_translations(actual_languages, actual_fields) if languages_needing_translation.blank? || fields_needing_translation.blank? skipped_count = (actual_languages.size * actual_fields.size) - (languages_needing_translation.size * fields_needing_translation.size) return success_result({}, message: "All selected translations already exist (#{skipped_count} skipped)") end source_texts = extract_source_texts(fields_needing_translation) return failure_result('No source text found for translation') if source_texts.blank? # Batch translations to avoid timeout: max 6 languages or 4 fields per batch all_translations = {} failed_batches = [] # Strategy: If too many languages, batch by language groups # If too many fields, batch by field groups if languages_needing_translation.size > 6 languages_needing_translation.each_slice(6) do |lang_batch| result = execute_single_batch(source_texts, lang_batch, fields_needing_translation) if result[:success] all_translations.deep_merge!(result[:translations]) else failed_batches << { languages: lang_batch, error: result[:message] } end end elsif fields_needing_translation.size > 4 fields_needing_translation.each_slice(4) do |field_batch| batch_source_texts = source_texts.slice(*field_batch) result = execute_single_batch(batch_source_texts, languages_needing_translation, field_batch) if result[:success] all_translations.deep_merge!(result[:translations]) else failed_batches << { fields: field_batch, error: result[:message] } end end else result = execute_single_batch(source_texts, languages_needing_translation, fields_needing_translation) if result[:success] all_translations = result[:translations] else failed_batches << { all: true, error: result[:message] } end end # If all batches failed, return error if all_translations.blank? && failed_batches.present? error_msg = failed_batches.pluck(:error).join('; ') return failure_result("All translation batches failed: #{error_msg}") end # If some batches failed, log warning but continue log_partial_success(failed_batches, all_translations.keys) if failed_batches.present? # Update package fields with translations update_package_fields(all_translations, languages_needing_translation, fields_needing_translation) skipped_count = (actual_languages.size * actual_fields.size) - (languages_needing_translation.size * fields_needing_translation.size) = "Successfully translated #{languages_needing_translation.size} language(s) for #{fields_needing_translation.size} field(s)" += " (#{skipped_count} already existed)" if skipped_count > 0 success_result(all_translations, message: ) rescue StandardError => e handle_error(e) end |