Skip to content

Commit

Permalink
improve streaming and UX
Browse files Browse the repository at this point in the history
  • Loading branch information
tevko committed Dec 11, 2024
1 parent c3aa8dc commit 818da1c
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 73 deletions.
13 changes: 6 additions & 7 deletions client-report/src/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class App extends React.Component {
disagree: globals.brandColors.disagree,
pass: globals.brandColors.pass,
},
narrative: {
},
};
}

Expand Down Expand Up @@ -121,7 +123,6 @@ class App extends React.Component {
}

async getNarrative(report_id) {
let narrativeData = "";
const urlPrefix = URLs.urlPrefix;
const response = await fetch(`${urlPrefix}api/v3/reportNarrative?report_id=${report_id}`, {
credentials: "include",
Expand All @@ -139,17 +140,15 @@ class App extends React.Component {
const decoder = new TextDecoder();
const loopRunner = true;

while (loopRunner) {
while (loopRunner) { // streaming response - the loop will run indefinetly until the response ends - this is a streaming function to improve UX and prevent cloud runners (like heroku) from terminating a long running http request
const { value, done } = await reader.read();
if (done) {
break;
}
const decodedChunk = decoder.decode(value, { stream: true });

if (!decodedChunk.includes('POLIS-PING:')) narrativeData += decodedChunk;
if (!decodedChunk.includes('POLIS-PING:')) this.setState(state => ({ narrative: Object.assign(state.narrative, JSON.parse(decodedChunk)) }))
}

return JSON.parse(narrativeData);
}

getReport(report_id) {
Expand Down Expand Up @@ -245,7 +244,7 @@ class App extends React.Component {
});

const narrativePromise = reportPromise.then((report) => {
return this.state.isNarrativeReport ? this.getNarrative(report.report_id) : Promise.resolve();
if (this.state.isNarrativeReport) this.getNarrative(report.report_id);
});

Promise.all([
Expand Down Expand Up @@ -436,7 +435,7 @@ class App extends React.Component {
repfulDisageeTidsByGroup: repfulDisageeTidsByGroup,
formatTid: formatTid,
report: report,
narrative: this.state.isNarrativeReport ? narrative : undefined,
// narrative: this.state.isNarrativeReport ? narrative : undefined,
//conversationStats: conversationstats,
computedStats: computedStats,
nothingToShow: !comments.length || !groupDemographics.length,
Expand Down
2 changes: 1 addition & 1 deletion client-report/src/components/lists/consensusNarrative.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const ConsensusNarrative = ({
model
}) => {
if (!narrative?.group_informed_consensus) {
return null;
return <div>Loading Consensus...</div>;
}
const txt = model === "claude" ? narrative.group_informed_consensus.responseClaude.content[0].text : narrative.group_informed_consensus.responseGemini;

Expand Down
2 changes: 1 addition & 1 deletion client-report/src/components/lists/uncertaintyNarrative.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const UncertaintyNarrative = ({
narrative,
model
}) => {
if (!conversation || !narrative) {
if (!conversation || !narrative || !narrative?.uncertainty?.responseClaude) {
return <div>Loading Uncertainty...</div>;
}

Expand Down
179 changes: 115 additions & 64 deletions server/src/routes/reportNarrative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,75 +195,126 @@ export async function handle_GET_reportNarrative(

// @ts-expect-error flush - calling due to use of compression
res.flush();


// Process each section
const sectionResults = await Promise.all(
reportSections.map(async (section) => {
const fileContents = await fs.readFile(section.templatePath, "utf8");
const json = await convertXML(fileContents);
const structured_comments = await getCommentsAsXML(zid, section.filter);

json.polisAnalysisPrompt.children[
json.polisAnalysisPrompt.children.length - 1
].data.content = { structured_comments };

const prompt_xml = js2xmlparser.parse(
"polis-comments-and-group-demographics",
json
);

const responseClaude = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
temperature: 0,
system: system_lore,
messages: [
{
role: "user",
content: [{ type: "text", text: prompt_xml }],
},
{
role: "assistant",
content: [{ type: "text", text: "{" }],
},
],
});
for (const section of reportSections) {
const fileContents = await fs.readFile(section.templatePath, "utf8");
const json = await convertXML(fileContents);
const structured_comments = await getCommentsAsXML(zid, section.filter);

json.polisAnalysisPrompt.children[
json.polisAnalysisPrompt.children.length - 1
].data.content = { structured_comments };

const prompt_xml = js2xmlparser.parse(
"polis-comments-and-group-demographics",
json
);

const responseClaude = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
temperature: 0,
system: system_lore,
messages: [
{
role: "user",
content: [{ type: "text", text: prompt_xml }],
},
{
role: "assistant",
content: [{ type: "text", text: "{" }],
},
],
});

const gemeniModelprompt: GenerateContentRequest = {
contents: [
{
parts: [{
text: prompt_xml,
}],
role: "user"
},
// {
// parts: [{
// text: prompt_xml,
// }],
// role: "user"
// }
],
systemInstruction: system_lore,
};

const respGem = await gemeniModel.generateContent(gemeniModelprompt);
const responseGemini = await respGem.response.text();

return {
[section.name]: {
responseClaude,
responseGemini,
const gemeniModelprompt: GenerateContentRequest = {
contents: [
{
parts: [{
text: prompt_xml,
}],
role: "user"
},
};
})
);
],
systemInstruction: system_lore,
};

// Combine all section results
const combinedResults = Object.assign({}, ...sectionResults);
const respGem = await gemeniModel.generateContent(gemeniModelprompt);
const responseGemini = await respGem.response.text();

res.write(JSON.stringify({ narrative: "A narrative report summarizing a polis conversation, Nov 26.", ...combinedResults }));
res.write(JSON.stringify({ [section.name]: { responseGemini, responseClaude } }));
// @ts-expect-error flush - calling due to use of compression
res.flush();
}


// Process each section
// const sectionResults = await Promise.all(
// reportSections.map(async (section) => {
// const fileContents = await fs.readFile(section.templatePath, "utf8");
// const json = await convertXML(fileContents);
// const structured_comments = await getCommentsAsXML(zid, section.filter);

// json.polisAnalysisPrompt.children[
// json.polisAnalysisPrompt.children.length - 1
// ].data.content = { structured_comments };

// const prompt_xml = js2xmlparser.parse(
// "polis-comments-and-group-demographics",
// json
// );

// const responseClaude = await anthropic.messages.create({
// model: "claude-3-5-sonnet-20241022",
// max_tokens: 1000,
// temperature: 0,
// system: system_lore,
// messages: [
// {
// role: "user",
// content: [{ type: "text", text: prompt_xml }],
// },
// {
// role: "assistant",
// content: [{ type: "text", text: "{" }],
// },
// ],
// });

// const gemeniModelprompt: GenerateContentRequest = {
// contents: [
// {
// parts: [{
// text: prompt_xml,
// }],
// role: "user"
// },
// // {
// // parts: [{
// // text: prompt_xml,
// // }],
// // role: "user"
// // }
// ],
// systemInstruction: system_lore,
// };

// const respGem = await gemeniModel.generateContent(gemeniModelprompt);
// const responseGemini = await respGem.response.text();

// return {
// [section.name]: {
// responseClaude,
// responseGemini,
// },
// };
// })
// );

// // Combine all section results
// const combinedResults = Object.assign({}, ...sectionResults);

// res.write(JSON.stringify({ narrative: "A narrative report summarizing a polis conversation, Nov 26.", ...combinedResults }));

res.end();

Expand Down

0 comments on commit 818da1c

Please sign in to comment.