1function cleanText(value) { 2 return String(value || "").trim(); 3} 4 5function eventTime(value) { 6 const time = Date.parse(cleanText(value)); 7 return Number.isFinite(time) ? time : 0; 8} 9 10const SIMPLE_CHAT_HELP = "NapiÅ¡te mi, co mám s touto datovou zprávou udÄlat. Můžu ji archivovat, oznaÄit jako vyÅÃzenou, odeslat odpovÄÄ nebo pÅedat kolegovi."; 11const DRAFT_READY_NOTICE = "Návrh odpovÄdi je pÅipravený. Nic nebylo odesláno."; 12 13export function dataBoxPlusVisibleDraftText(draftText = "") { 14 const draft = cleanText(draftText); 15 return draft ? `${DRAFT_READY_NOTICE}\n\n${draft}` : DRAFT_READY_NOTICE; 16} 17 18function simpleChatWords(value) { 19 return cleanText(value) 20 .toLocaleLowerCase("cs-CZ") 21 .normalize("NFD") 22 .replace(/[\u0300-\u036f]/g, "") 23 .replace(/[^a-z0-9]+/g, " ") 24 .trim(); 25} 26 27function isUnclearChatInstruction(value) { 28 const words = simpleChatWords(value); 29 return !words 30 || ["ahoj", "co", "test", "zkouska", "ano", "souhlasim", "souhlas", "proved", "potvrzuji"].includes(words) 31 || words.includes("tvoje poslani") 32 || words.includes("jake je tvoje poslani") 33 || words.includes("co umis"); 34} 35 36function humanAssistantText(event, payload, instruction) { 37 const outcome = cleanText(payload.outcome || event?.result).toLowerCase(); 38 const explicitAssistantText = cleanText(payload.assistantText); 39 if (isUnclearChatInstruction(instruction) 40 && (!explicitAssistantText || !["done", "cancelled", "expired", "failed", "waiting_confirmation"].includes(outcome))) { 41 return SIMPLE_CHAT_HELP; 42 } 43 if (outcome === "draft_ready") { 44 return dataBoxPlusVisibleDraftText(payload.draftText || payload.plan?.draftText); 45 } 46 const raw = cleanText(payload.assistantText || event?.assistantText || event?.auditNote || payload.performedAction); 47 if (outcome === "needs_input" && explicitAssistantText) { 48 return raw.replace(/^Hotovo\.\s*/i, "") || "PotÅebuji doplnit chybÄjÃcà údaj."; 49 } 50 const performed = raw.match(/Systém provedl:\s*(.+?)(?:\.\s*Nový stav:|$)/i)?.[1]; 51 const missingWords = simpleChatWords(performed || raw); 52 const missingRecipient = missingWords.includes("chybi adresat") || missingWords.includes("adresat chybi"); 53 if (missingRecipient) { 54 return "Chybà adresát. Komu to mám pÅedat nebo pÅeposlat?"; 55 } 56 if (outcome === "needs_input") { 57 return raw.replace(/^Hotovo\.\s*/i, "") || "PotÅebuji doplnit chybÄjÃcà údaj."; 58 } 59 if (missingWords.includes("chybi")) { 60 const missingDetail = cleanText(performed || raw).replace(/[.\s]+$/, ""); 61 return `${missingDetail}. PotÅebuji doplnit chybÄjÃcà údaj.`; 62 } 63 if (performed) return `Hotovo. ${performed.replace(/[.\s]+$/, "")}.`; 64 if (/^(intent|result|no_action|changedstate)\b/i.test(raw)) return SIMPLE_CHAT_HELP; 65 return raw || SIMPLE_CHAT_HELP; 66} 67 68export function dataBoxPlusHistoryChatEntries(history = []) { 69 return (Array.isArray(history) ? history : []) 70 .filter((event) => cleanText(event?.actionType).toLocaleLowerCase("cs-CZ") === "chatový pokyn") 71 .sort((left, right) => eventTime(left?.createdAt) - eventTime(right?.createdAt)) 72 .flatMap((event) => { 73 const payload = event?.payload && typeof event.payload === "object" ? event.payload : {}; 74 const instruction = cleanText(payload.originalInstruction || payload.userInstruction); 75 if (!instruction) return []; 76 const assistantText = humanAssistantText(event, payload, instruction); 77 const auditId = cleanText(event.id); 78 const createdAt = cleanText(event.createdAt); 79 const eventResult = cleanText(event.result); 80 const payloadOutcome = cleanText(payload.outcome); 81 const activeConfirmation = eventResult === "waiting_confirmation"; 82 const outcome = payloadOutcome === "waiting_confirmation" && eventResult && !activeConfirmation 83 ? eventResult 84 : payloadOutcome || eventResult; 85 return [ 86 { 87 id: `${auditId || createdAt}-user`, 88 auditId, 89 role: "user", 90 text: instruction, 91 createdAt 92 }, 93 ...(assistantText ? [{ 94 id: `${auditId || createdAt}-assistant`, 95 auditId, 96 role: "assistant", 97 text: assistantText, 98 createdAt, 99 outcome, 100 intent: cleanText(payload.intent), 101 statusLabel: cleanText(payload.statusLabel), 102 confirmationId: activeConfirmation ? cleanText(payload.proposedAction?.confirmationId || payload.confirmationId) : "", 103 proposedAction: activeConfirmation && payload.proposedAction && typeof payload.proposedAction === "object" 104 ? payload.proposedAction 105 : undefined 106 }] : []) 107 ]; 108 }); 109} 110 111export function dataBoxPlusConversationEntries(history = [], localEntries = []) { 112 const persisted = dataBoxPlusHistoryChatEntries(history); 113 const persistedAuditIds = new Set(persisted.map((entry) =>
113 entry.auditId).filter(Boolean)); 114 const local = (Array.isArray(localEntries) ? localEntries : []) 115 .filter((entry) => cleanText(entry?.text)) 116 .filter((entry) => !entry.auditId || !persistedAuditIds.has(cleanText(entry.auditId))); 117 return [...persisted, ...local]; 118} 119 120export function dataBoxPlusPendingChatEntries(localEntries = [], instruction = "", requestId = "") { 121 const text = cleanText(instruction); 122 const id = cleanText(requestId) || `ds-plus-chat-${Date.now()}`; 123 if (!text) return Array.isArray(localEntries) ? [...localEntries] : []; 124 return [ 125 ...(Array.isArray(localEntries) ? localEntries : []), 126 { 127 id: `${id}-user`, 128 requestId: id, 129 role: "user", 130 text, 131 createdAt: new Date().toISOString() 132 }, 133 { 134 id: `${id}-assistant`, 135 requestId: id, 136 role: "assistant", 137 text: "Autopilot pracuje...", 138 pending: true, 139 createdAt: new Date().toISOString() 140 } 141 ]; 142} 143 144export function dataBoxPlusResolvePendingChatEntries(localEntries = [], requestId = "", assistantText = "", auditId = "", error = false, details = {}) { 145 const id = cleanText(requestId); 146 const reply = cleanText(assistantText) || "Zprávu se nepodaÅilo zpracovat."; 147 return (Array.isArray(localEntries) ? localEntries : []).map((entry) => { 148 if (cleanText(entry?.requestId) !== id) return entry; 149 if (entry.role === "assistant") { 150 return { 151 ...entry, 152 text: reply, 153 pending: false, 154 error: Boolean(error), 155 auditId: cleanText(auditId), 156 createdAt: cleanText(details.createdAt) || entry.createdAt, 157 outcome: cleanText(details.outcome) || (error ? "failed" : cleanText(entry.outcome)), 158 intent: cleanText(details.intent), 159 statusLabel: cleanText(details.statusLabel), 160 understoodAs: cleanText(details.understoodAs), 161 performedAction: cleanText(details.performedAction), 162 proposedAction: details.proposedAction && typeof details.proposedAction === "object" ? details.proposedAction : undefined 163 }; 164 } 165 return { ...entry, auditId: cleanText(auditId) }; 166 }); 167} 168 169export function dataBoxPlusResolveConfirmationEntries(localEntries = [], confirmationId = "", outcome = "confirmed") { 170 const id = cleanText(confirmationId); 171 if (!id) return Array.isArray(localEntries) ? [...localEntries] : []; 172 return (Array.isArray(localEntries) ? localEntries : []).map((entry) => { 173 const entryConfirmationId = cleanText(entry?.proposedAction?.confirmationId || entry?.confirmationId); 174 if (entryConfirmationId !== id) return entry; 175 return { 176 ...entry, 177 outcome: cleanText(outcome) || "confirmed", 178 confirmationId: "", 179 proposedAction: undefined 180 }; 181 }); 182}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.