# #region preview_response_parser [C:3] [TYPE Module] [SEMANTICS llm, parse, json, superset, hash] # @BRIEF Parse LLM JSON responses and Superset data; compute config/dict hashes for preview. # @RELATION DEPENDS_ON -> [TranslationJob] # @RELATION DEPENDS_ON -> [TranslationJobDictionary] import hashlib import json import re from typing import Any from sqlalchemy.orm import Session from ...models.translate import TranslationJob, TranslationJobDictionary # #region parse_llm_response [C:3] [TYPE Function] [SEMANTICS llm, parse, json, translate] # @BRIEF Parse LLM JSON response into structured translations dict with per-language support. # @PRE response_text is a valid JSON string (possibly wrapped in markdown code block). # @POST Returns dict mapping row_id -> {detected_source_language, lang_code: translation, ...}. def parse_llm_response( response_text: str, expected_count: int, target_languages: list[str] | None = None, finish_reason: str | None = None, ) -> dict[str, dict[str, str]]: """Parse LLM JSON response into structured translations dict.""" try: data = json.loads(response_text) except json.JSONDecodeError: data = None match = re.search(r'```(?:json)?\s*\n?(.*?)\n?```', response_text, re.DOTALL) if match: try: data = json.loads(match.group(1)) except json.JSONDecodeError: pass if data is None: rows_match = re.findall(r'\{\s*"row_id"\s*:\s*(?:\d+|"\d+").*?\}\s*', response_text, re.DOTALL) if rows_match: partial_rows = [] for row_text in rows_match: try: partial_rows.append(json.loads(row_text)) except json.JSONDecodeError: continue if partial_rows: data = {"rows": partial_rows} if data is None: raise ValueError("LLM response was not valid JSON") rows = data.get("rows", []) if not isinstance(rows, list): raise ValueError("LLM response missing 'rows' array") translations: dict[str, dict[str, str]] = {} for item in rows: row_id = str(item.get("row_id", "")) if not row_id: continue detected_lang = str(item.get("detected_source_language", "und")) if item.get("detected_source_language") else "und" result: dict[str, str] = {"detected_source_language": detected_lang} has_language_data = False if target_languages: for lang_code in target_languages: lang_val = item.get(lang_code) if lang_val is not None and str(lang_val).strip(): result[lang_code] = str(lang_val) has_language_data = True if not has_language_data: translation = item.get("translation") if translation is not None: result["translation"] = str(translation) else: continue translations[row_id] = result return translations # #endregion parse_llm_response # #region extract_data_rows [C:1] [TYPE Function] [SEMANTICS superset, data, extraction] # @BRIEF Extract data rows from Superset chart data API response. def extract_data_rows(response: dict[str, Any]) -> list[dict[str, Any]]: """Extract data rows from Superset chart data API response.""" result = response.get("result") if isinstance(result, list): for item in result: if isinstance(item, dict): data = item.get("data") if isinstance(data, list) and data: return data if isinstance(result, dict): data = result.get("data") if isinstance(data, list) and data: return data data = response.get("data") if isinstance(data, list) and data: return data if isinstance(result, list): return result return [] # #endregion extract_data_rows # #region compute_config_hash [C:1] [TYPE Function] [SEMANTICS config, hash, deterministic] # @BRIEF Compute a deterministic hash of job configuration for snapshot comparison. def compute_config_hash(job: TranslationJob) -> str: """Compute a deterministic hash of job configuration for snapshot comparison.""" config_str = json.dumps({ "source_dialect": job.source_dialect, "target_dialect": job.target_dialect, "source_datasource_id": job.source_datasource_id, "translation_column": job.translation_column, "context_columns": job.context_columns, "provider_id": job.provider_id, "batch_size": job.batch_size, "upsert_strategy": job.upsert_strategy, }, sort_keys=True) return hashlib.sha256(config_str.encode()).hexdigest()[:16] # #endregion compute_config_hash # #region compute_dict_snapshot_hash [C:2] [TYPE Function] [SEMANTICS dictionary, hash, snapshot] # @BRIEF Compute a hash of dictionary state for snapshot comparison. def compute_dict_snapshot_hash(db: Session, job_id: str) -> str: """Compute a hash of dictionary state for snapshot comparison.""" dict_links = ( db.query(TranslationJobDictionary) .filter(TranslationJobDictionary.job_id == job_id) .all() ) dict_ids = sorted([dl.dictionary_id for dl in dict_links]) hash_input = ",".join(dict_ids) return hashlib.sha256(hash_input.encode()).hexdigest()[:16] # #endregion compute_dict_snapshot_hash # #endregion preview_response_parser