"mapping": {
"<node-id>": {
"id": "<node-id>",
"message": { … } // nebo null pro kořen
"parent": "<parent-node-id>" // nebo null
"children": ["<child-id-1>", …]
},
…
}
Zcela klíčové pro orientaci ve stromu mapping
jsou tyto identifikátory:
-
id
(uzlu / node-id)-
Unikátní řetězec (většinou UUID), který označuje právě tento uzel ve slovníku
mapping
. -
Používá se jako klíč i v
node["id"]
.
-
-
parent
(ve slovníkumapping
)-
Hodnota je
id
nadřazeného uzlu. -
Každý uzel (kromě „root“) má jednoho
parent
, tedy uzel, ze kterého tato zpráva/podstrom logicky vychází. -
Uzel s
parent: null
(většinou"client-created-root"
) je počáteční „kořen“ sezení.
-
-
children
-
Pole
["id1", "id2", …]
– seznamid
všech potomků (uzly, které navazují na daný uzel). -
V jednoduchém lineárním chatu bude každé pole
children
obsahovat právě jeden další uzel, u vícevětvených scénářů jich může být víc.
-
-
message.id
-
Stejné jako uzlové
id
, ale uvnitř objektumessage
. -
Slouží k unitárnímu mapování mezi uzlem a jeho
message
.
-
-
metadata.parent_id
(uvnitřmessage.metadata
)-
Duplicitně ukládá
parent
i přímo v metadatech té zprávy. -
Může se hodit pro rychlé filtrování přímo na úrovni
message
, aniž bys musel prolézatmapping
.
-
-
metadata.request_id
-
Identifikátor konkrétního API požadavku / uživatelského promptu, ze kterého tah vznikl.
-
Pokud jde o uživatelský vstup,
request_id
jej spojuje s interním zpracováním.
-
-
async_task_id
/async_task_title
-
Pokud
is_async_task_result_message: true
, máte tu ještěasync_task_id
(interní značka dlouhé operace) a human-readableasync_task_title
.
-
-
mapping
vs.jsonData
-
jsonData
je pole sezení (chat sessions). Každý prvek pole je jedno celé sezení/chat (má svůjtitle
,create_time
apod.). -
Uvnitř každé session se zcela odděleně nachází
mapping
, tedy strukturální strom všech uzlů ve vlastním rozhovoru.
-
Jak je to navázané:
-
Top-level:
[ { // session #1 "title": "...", "mapping": { ... } }, { // session #2 ... } ]
-
V každé session:
-
mapping["node-id"]
→ uzel, který má:-
id
(shodné s klíčem), -
parent
(id nadřazeného), -
children
(pole id potomků), -
message
(objekt).
-
-
-
V objektu
message
najdeš:-
message.id
(jaký uzel to je), -
message.metadata.parent_id
(pro rychlé rozpoznání rodiče), -
message.metadata.request_id
(který uživatelský dotaz to vyvolal), -
někdy i
async_task_id
a další příznaky režie.
-
Zjednodušené schéma
jsonData: [
session₁ {
mapping: {
node₁ {
id: node₁
parent: null
children: [node₂]
message: null ← virtuální root
}
node₂ {
id: node₂
parent: node₁
children: [node₃]
message: {
id: node₂
author: { role: user }
metadata: {
parent_id: node₁
request_id: abc-123
is_async_task_result_message: false
}
}
}
node₃ {
id: node₃
parent: node₂
children: []
message: {
…
metadata: {
parent_id: node₂
request_id: abc-123
async_task_id: long-job-456
async_task_title: "…"
}
}
}
}
},
session₂ { … }
]
-
parent
/parent_id
udávají, „ze kterého kroku/vstupu“ daná zpráva vzešla. -
children
: na co navazuje dál. -
request_id
: váže to k tomu, co jsi skutečně poslal „ven“ jako svůj prompt. -
async_task_*
: značí, že odpověď vznikla vícefázově (nejen bezprostředně po promptu).
* * *
* * *
Ta pole start_ix
a end_ix
udávají přesné pozice (offsety) v textovém řetězci, kde v dané zprávě citace začíná a končí. V praxi to znamená:
-
Odkazují na znaky v té samé proměnné
msg["content"]["parts"][0]
nebo vmsg["content"]["parts"]
po sloučení. -
Jsou to 0-based indexy znaků (v JavaScriptu se to obvykle měří jako UTF-16 code units, v Pythonu jako Unicode code points).
Co to znamená pro převod \uXXXX
→ skutečné diakritické znaky
-
Pokud JSON načteš a necháš Python či JavaScript automaticky dekódovat ty unicode escape sekvence (
\u00fd
→ý
apod.), pakparts[0]
uloží v paměti skutečné znaky. -
Potom
start_ix
aend_ix
odpovídají právě těmto dekódovaným znakům.text = msg["content"]["parts"][0] # text už obsahuje např. 'TJV má velmi nízkou...' citace = text[start_ix:end_ix]
-
Nezmění se ti tedy offsety, pokud je dekóduješ před použitím těch indexů.
Kdy nastává problém?
-
Pokud bys nejprve počítal znaky nad původním JSON řetězcem se
\uXXXX
(tj. escape syntaxí), a pak nahradil\u00fd
znakemý
, pak by se ti indexy posouvaly (protože\u00fd
je 6 znaků, aleý
je jen 1 znak). -
Správný postup je:
-
Načíst JSON a nechat ho plně dekódovat (
json.loads
v Pythonu, neboJSON.parse
v JS). -
Teprve na dekódovaném
text = parts[0]
pak aplikovatstart_ix:end_ix
.
-
To zajistí, že offsety sedí na finální podobu řetězce s diakritikou a emoji. Pokud bys ale nejprve dekódovaný text znovu kódoval zpátky do \uXXXX
, nebo manipuloval s řetězcem jiným způsobem (vkládal/odstraňoval znaky), tak bys ty indexy samozřejmě rozházel.
Závěr:
-
start_ix
/end_ix
jsou offsety v již dekódovaném textu zprávy. -
Dekódování
\uXXXX
→UTF-8 (= skutečné diakritické znaky) proto nezmění jejich význam, pokud proběhne před jejich aplikací. -
Pokud ale unicode escapes převádíš početně nevhodným krokem (např. ve zdrojovém JSONu), pak ano, indexy by neseděly. Proto:
-
zavolej
data = json.loads(raw)
-
text = data[…]["content"]["parts"][0]
-
substring = text[start_ix:end_ix]
a budeš mít přesně tu část zprávy, kterou citace popisuje.
-
* * *
V metadata zpráv se kromě textových částí (content.parts
) nachází ještě pole citations
(případně citations
+ další typy poznámek) s těmito nejčastějšími formáty:
1. "type": "webpage"
Objekt popisuje základní citaci zdroje – má:
-
start_ix
/end_ix
Pozice v dekódovaném textu (parts[0]
) od – do (UTF-8 znaky), kde se citace nachází. -
metadata
podklíč s těmito poli:-
type: "webpage"
-
title
– titul stránky -
url
– odkaz -
text
– vypíchnutý úsek původního textu (short snippet) -
cited_message_id
/cited_message_idx
– na kterou předchozí zprávu se citace odkazuje -
evidence_text
– další poznámka (často prázdné)
-
Struktura:
{
"start_ix": 423,
"end_ix": 435,
"citation_format_type": "tether_v4",
"metadata": {
"type": "webpage",
"title": "Mapování psychologických tendencí…",
"url": "https://…",
"text": "Uživatel TJV ve svých příspěvcích…",
"cited_message_id": "cc5d078c-…",
"evidence_text": ""
}
}
2. "type": "webpage_extended"
Rozšířená citace, přidává další kontext a ověřené údaje:
-
matched_text
Přesná sekvence z originálního textu, kterou citace popisuje (např.“[28]L49-L52”
). -
snippet
Kratší úryvek z cílové webové stránky (nemusí být totožné smetadata.text
). -
attribution
Zdroj domény (např.zpovednica.blogspot.com
). -
icon_type
Ikonka zdroje (většinounull
). -
pub_date
Datum publikace zdroje (častonull
). -
alt
Alternativní popisek (většinounull
).
Struktura:
{
"matched_text": "“[28]L49-L52”",
"start_idx": 3505,
"end_idx": 3517,
"type": "webpage_extended",
"title": "Mapování psychologických tendencí…",
"url": "https://…",
"pub_date": null,
"snippet": "sarkasticky, její tón je převážně kritický…",
"attribution": "zpovednica.blogspot.com",
"icon_type": null
}
3. is_async_task_result_message
Když vidíš v message.metadata
klíč
"is_async_task_result_message": true,
"async_task_id": "...",
"async_task_title": "Psychologická a behaviorální analýza…"
znamená to, že tato zpráva je výsledkem asynchronní úlohy (např. delšího API volání / batchového procesu).
-
async_task_id
– interní ID úlohy -
async_task_title
– popisek, co se zpracovávalo
Jak to celé použít
-
Rozdělení obsahu
-
Vypíšeš text z
message.content.parts[0]
. -
Citace vkládáš pomocí
metadata.citations
(pro základní linky) a/nebometadata.citations
obsahujícíchtype: "webpage_extended"
.
-
-
Správné offsety
-
Vždy pracuj na dekódovaném textu (
json.loads
), pakstart_ix:end_ix
ukazují přímo na české znaky.
-
-
Asynchronní zprávy
-
Pokud
is_async_task_result_message
jetrue
, můžeš je vyfiltrovat nebo označit jako odpovědi generované dávkovou úlohou – mají k sobě vlastníasync_task_title
.
-
Tím máš kompletní přehled, jak v datech najít samotný text, veškeré citace a jak rozpoznat, že zpráva vznikla v rámci asynchronní operace.
* * *
V tomhle úseku jsi narazil na několik nových polí a formátů, které obohacují chování a metadata jednotlivých uzlů – pojďme si je rychle projít:
… "content": {
"content_type": "text",
"parts": ["… ;\n</html>"]
},
"status": "finished_successfully",
"end_turn": true,
"weight": 1.0,
"metadata": {
"citations": [],
"content_references": [], ← nově vidíš tohle pole
"message_type": null,
"model_slug": "o4-mini",
"default_model_slug": "auto",
"parent_id": "7d32f62e-…",
"request_id": "94829d82bd8f8033-MXP",
"timestamp_": "absolute",
"is_async_task_result_message": true, ← a i tohle
"b1de6e2_rm": true,
"async_task_id": "deepresch_683a…",
"async_task_title": "Psychologická a behaviorální analýza…"
},
"recipient": "all",
"channel": "final"
…
1. content_references
– Prázdné pole tady, ale obecně by mohlo obsahovat odkazy na externí entity, obrázky, nebo další assety, které se v textu objevují. Pokud bys měl např. vestavěné grafy, videa apod., sem by se zapsal jejich popis/odkaz.
2. status
, end_turn
, weight
– status
: stav vykonání (např. "finished_successfully"
znamená, že celý backend proces doběhl ok).
– end_turn
: zda tah končí (pokud true
, uživatel má možnost vložit nový vstup).
– weight
: interní váha nebo priorita v stromu — obvykle všechny outputy mají 1.0
.
3. model_slug
/ default_model_slug
– Označují, který model odpověď generoval ("o4-mini"
). Pokud se měnil model, default_model_slug
to může zaznamenat.
4. timestamp_
– Zde "absolute"
znamená, že create_time
v tomto message je absolutní Unix timestamp (nikoli relativní).
5. Asynchronní tasky:
-
is_async_task_result_message: true
říká, že tah vznikl jako výsledek dlouhé asynchronní operace (např. batchové zpracování, složitější analýza). -
async_task_id
/async_task_title
ukládají interní ID a popisek té úlohy („Psychologická a behaviorální analýza TJV…“). -
A
b1de6e2_rm
je jen interní flag, že se jedná orebase_developer_message
nebo podobné značení uvnitř systému.
6. channel
– Hodnota "final"
značí, že tohle je konečné zpracování odpovědi asistenta.
– Kromě něj můžou být i jiné kanály (např. "analysis"
, "thoughts"
, apod.), ale konečný výstup vždy jde na "final"
.
Celkově to znamená, že:
-
Nejsou to už jen tvoje požadavky a odpovědi, ale v datech vidíš úplnou historii celého procesu generování:
-
request (uživatel)
-
system mezikroky (
thoughts
,reasoning_recap
) -
asynchronní výpočty (dlouhé úlohy)
-
finální output (
channel: "final"
)
-
-
Metadata ti tím dávají detailní auditní stopu:
-
Který model to vypočítal,
-
zda to byla asynchronní taska,
-
jestli to ukončilo turn,
-
jaké externí assety by se mohly objevit (
content_references
).
-
To ti umožňuje přesně rekonstruovat, jak a odkud každá část odpovědi vznikla.
Žádné komentáře:
Okomentovat