Read game conversations through GraphQL
Build and publish frontend / publish (push) Failing after 3s
Build and publish frontend / publish (push) Failing after 3s
This commit is contained in:
+63
-6
@@ -184,6 +184,22 @@
|
||||
if (!response.ok) throw new Error(body?.error || `HTTP ${response.status}`);
|
||||
return body;
|
||||
}
|
||||
async function graphqlQuery(query, variables = {}) {
|
||||
const response = await request('/graphql', {
|
||||
method: 'POST',
|
||||
headers: {'content-type': 'application/json'},
|
||||
body: JSON.stringify({query, variables}),
|
||||
});
|
||||
if (response.errors?.length) throw new Error(response.errors[0].message || 'GraphQL-förfrågan misslyckades');
|
||||
return response.data;
|
||||
}
|
||||
async function getAdminTrace(accountId = null, limit = 200, offset = 0) {
|
||||
const data = await graphqlQuery(
|
||||
'query AdminPlayerTrace($accountId: String, $limit: Int!, $offset: Int!) { adminPlayerTrace(accountId: $accountId, limit: $limit, offset: $offset) }',
|
||||
{accountId, limit, offset},
|
||||
);
|
||||
return data.adminPlayerTrace;
|
||||
}
|
||||
function appendLine(role, content, options = {}) {
|
||||
const line = document.createElement('li');
|
||||
line.dataset.role = role;
|
||||
@@ -659,7 +675,7 @@
|
||||
adminJson(`${profile.username} · profil och biografi`, profile);
|
||||
adminTraceOffset = 0;
|
||||
adminSimpleConversation = false;
|
||||
const trace = await request(`/api/admin/players/${encodeURIComponent(accountId)}/trace?limit=200&offset=0`);
|
||||
const trace = await getAdminTrace(accountId, 200, 0);
|
||||
renderAdminConversations(trace, accountId);
|
||||
}
|
||||
function renderAdminConversations(trace, accountId, existingRoot, hasMoreOverride) {
|
||||
@@ -748,7 +764,7 @@
|
||||
older.disabled = true;
|
||||
older.textContent = 'Hämtar äldre samtal…';
|
||||
adminTraceOffset += trace.limit || 200;
|
||||
const next = await request(`/api/admin/players/${encodeURIComponent(accountId)}/trace?limit=${trace.limit || 200}&offset=${adminTraceOffset}`);
|
||||
const next = await getAdminTrace(accountId, trace.limit || 200, adminTraceOffset);
|
||||
const merge = (key, idKey) => [...(trace[key] || []), ...(next[key] || [])].filter((item, index, all) => all.findIndex(candidate => candidate[idKey] === item[idKey]) === index);
|
||||
renderAdminConversations({events: merge('events', 'event_id'), ai_interactions: merge('ai_interactions', 'id'), player_messages: merge('player_messages', 'id'), limit: next.limit, offset: next.offset}, accountId, root, next.has_more);
|
||||
});
|
||||
@@ -1000,12 +1016,53 @@
|
||||
messageField.disabled = false;
|
||||
messageField.focus();
|
||||
}
|
||||
function savedDialogueLine(line) {
|
||||
const element = document.createElement('li');
|
||||
element.dataset.role = line.role === 'user' ? 'user' : line.role === 'system' ? 'system' : 'assistant';
|
||||
element.textContent = `${line.speaker || (line.role === 'user' ? 'Du' : 'Berättelsen')}: ${line.content}`;
|
||||
return element;
|
||||
}
|
||||
function dialogueLinesFromPage(page) {
|
||||
return page.edges.flatMap(edge => edge.node.lines);
|
||||
}
|
||||
function addOlderDialogueControl(cursor) {
|
||||
const item = document.createElement('li');
|
||||
item.dataset.role = 'system';
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.textContent = 'Hämta äldre konversation';
|
||||
button.addEventListener('click', async () => {
|
||||
button.disabled = true;
|
||||
button.textContent = 'Hämtar äldre konversation…';
|
||||
try {
|
||||
const page = (await graphqlQuery(
|
||||
'query OlderDialogue($before: String!) { dialogue(first: 50, before: $before) { edges { cursor node { lines { role content speaker } } } pageInfo { hasPreviousPage startCursor } } }',
|
||||
{before: cursor},
|
||||
)).dialogue;
|
||||
const oldLines = dialogueLinesFromPage(page);
|
||||
const fragment = document.createDocumentFragment();
|
||||
for (const line of oldLines) fragment.append(savedDialogueLine(line));
|
||||
item.remove();
|
||||
transcript.prepend(fragment);
|
||||
if (page.pageInfo.hasPreviousPage && page.pageInfo.startCursor) addOlderDialogueControl(page.pageInfo.startCursor);
|
||||
} catch (error) {
|
||||
button.disabled = false;
|
||||
button.textContent = `Kunde inte hämta äldre repliker: ${error.message}. Försök igen`;
|
||||
}
|
||||
});
|
||||
item.append(button);
|
||||
transcript.prepend(item);
|
||||
}
|
||||
async function loadSavedDialogue() {
|
||||
const lines = await request('/api/dialogue');
|
||||
const page = (await graphqlQuery(
|
||||
'query CurrentDialogue { dialogue(first: 100) { edges { cursor node { lines { role content speaker } } } pageInfo { hasPreviousPage startCursor } } }',
|
||||
)).dialogue;
|
||||
const lines = dialogueLinesFromPage(page);
|
||||
transcript.replaceChildren();
|
||||
latestAssistantText = '';
|
||||
latestAssistantText = [...lines].reverse().find(line => line.role === 'assistant')?.content || '';
|
||||
latestPlayerAction = [...lines].reverse().find(line => line.role === 'user')?.content || '';
|
||||
for (const line of lines) appendLine(line.role === 'user' ? 'user' : line.role === 'system' ? 'system' : 'assistant', line.content, {speaker: line.speaker, speak: false});
|
||||
for (const line of lines) transcript.append(savedDialogueLine(line));
|
||||
if (page.pageInfo.hasPreviousPage && page.pageInfo.startCursor) addOlderDialogueControl(page.pageInfo.startCursor);
|
||||
refreshActionTools();
|
||||
if (lines.length > 0 && latestAssistantText && location.pathname !== '/admin') {
|
||||
voiceController?.speak(latestAssistantText, {role: 'narrator', voiceIdentity: 'neutral'});
|
||||
@@ -1166,7 +1223,7 @@
|
||||
debugRefreshBusy = true;
|
||||
debugStatus.textContent = 'Hämtar revisionsloggad spårning…';
|
||||
try {
|
||||
const trace = await request('/api/admin/self/trace?limit=200');
|
||||
const trace = await getAdminTrace(null, 200, 0);
|
||||
renderDecisionTrace(trace);
|
||||
debugStatus.textContent = `Visar ${debugTrace.childElementCount} korrelerade händelsegrupper. Uppdaterad ${new Date().toLocaleTimeString('sv-SE')}.`;
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user