Skip to content

Commit

Permalink
Add scheduled debate summary generation
Browse files Browse the repository at this point in the history
  • Loading branch information
limdingwen committed Jul 28, 2024
1 parent 5f69268 commit 556dae0
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 0 deletions.
11 changes: 11 additions & 0 deletions scripts/deploy-and-run/generate-debate-summary.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
set -e

source ../.env
source ../lib/functions/deploy.sh
source ../lib/functions/run.sh

FUNCTION_NAME="generate-debate-summary"

deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME"
run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}"
5 changes: 5 additions & 0 deletions supabase/functions/generate-debate-summary/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts";
import proxyToResponseWrapper from "../lib/utils/proxy-to-response-wrapper.ts";
import generateDebateSummary from "../lib/shared-functions/generate-debate-summary.ts";

Deno.serve(proxyToResponseWrapper(generateDebateSummary));
104 changes: 104 additions & 0 deletions supabase/functions/lib/shared-functions/generate-debate-summary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { createSupabase } from "../utils/create-supabase.ts";
import createOpenAi from "../utils/create-openai.ts";
import { isAdmin } from "../utils/check-admin.ts";
import buildResponseProxy from "../utils/build-response-proxy.ts";
import { TextContentBlock } from "https://deno.land/x/[email protected]/resources/beta/threads/messages.ts";
import { SupabaseClient } from "https://esm.sh/v135/@supabase/[email protected]/dist/module/index.d.ts";

function restrictInputLength(input: string, length: number) {
return input.length <= length ? input : input.substring(0, length);
}

async function getDebateNeedingSummary(supabase: SupabaseClient) {
// Generate the summary for the most recent debates first because we assume they are the most important
const { data, error } = await supabase
.from("debate")
.select("id, order_no, summary, sitting ( sitting_date ( sitting_date ) )")
.is("summary", null)
.order("sitting_date", {
ascending: false,
referencedTable: "sitting.sitting_date",
})
.order("order_no", { ascending: false })
.limit(1)
.maybeSingle();
if (error) throw error;
return data;
}

async function getDebateSpeechInputForAi(
supabase: SupabaseClient,
debateId: number,
) {
const { data, error } = await supabase
.from("debate_speech")
.select("speaker_name, content")
.eq("debate_id", debateId)
.order("order_no", { ascending: true });
if (error) throw error;
return data
.map((speech) => `${speech.speaker_name}: ${speech.content}`)
.join("\n\n");
}

export default async function generateDebateSummary(req: Request) {
const supabase = createSupabase();
const openai = createOpenAi();

if (!isAdmin(req)) {
return buildResponseProxy({ message: "Unauthorised." }, 401);
}

const debate = await getDebateNeedingSummary(supabase);
if (!debate) {
return buildResponseProxy({
message: "No debates need summary generation.",
});
}

console.log(`Creating AI-friendly input of debate speeches...`);
const debateSpeechInput = await getDebateSpeechInputForAi(
supabase,
debate.id,
);
console.log(`AI-friendly input created: ${debateSpeechInput}`);

console.log(
`Attempting to generate summary for debate from row ID ${debate.id}...`,
);
const run = await openai.beta.threads.createAndRunPoll({
assistant_id: Deno.env.get("OPENAI_DEBATE_SUMMARY_ASSISTANT_ID")!,
thread: {
messages: [
{
role: "user",
// The input length limit is 256,000 characters for GPT 4o mini, independent of the token limit
content: restrictInputLength(debateSpeechInput, 256000),
},
],
},
});

if (run.status == "completed") {
const responses = await openai.beta.threads.messages.list(run.thread_id, {
run_id: run.id,
});
const summary = (responses.data[0].content[0] as TextContentBlock).text
.value;
console.log(`Summary generated: ${summary}`);

const { error: updateError } = await supabase
.from("debate")
.update({ summary })
.eq("id", debate.id);
if (updateError) throw updateError;

return buildResponseProxy({
message: `Added generated summary to row ID ${debate.id}.`,
});
} else {
throw new Error(
`Summary generation failed. The run dump is as follows: ${JSON.stringify(run)}`,
);
}
}
2 changes: 2 additions & 0 deletions supabase/functions/per-10-min/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import scrapeBillsPdf from "../lib/shared-functions/scrape-bills-pdf.ts";
import generateBillsSummary from "../lib/shared-functions/generate-bills-summary.ts";
import { buildResponse } from "../lib/utils/build-response.ts";
import fillDebateSpeakerIds from "../lib/shared-functions/fill-debate-speaker-ids.ts";
import generateDebateSummary from "../lib/shared-functions/generate-debate-summary.ts";

Deno.serve(async (req) => {
return buildResponse([
await fillDebateSpeakerIds(req),
await scrapeBillsPdf(req),
await generateBillsSummary(req),
await generateDebateSummary(req),
]);
});

0 comments on commit 556dae0

Please sign in to comment.