1import * as GCP from "@/GCP";
2import { GcpEnvironment } from "@/GCP/Environment";
3import * as Output from "@/Output";
4import * as Effect from "effect/Effect";
5import * as Redacted from "effect/Redacted";
6
7export const CHAT_TRANSCRIPT = JSON.stringify({
8 entries: [
9 {
10 start_timestamp_usec: 1_000_000,
11 text: "Hello, how can I help you today?",
12 role: "AGENT",
13 user_id: 1,
14 },
15 {
16 start_timestamp_usec: 5_000_000,
17 text: "I want to check my billing.",
18 role: "CUSTOMER",
19 user_id: 2,
20 },
21 ],
22});
23
24export const uploadChatTranscript = (bucketName: string) =>
25 Effect.gen(function* () {
26 const env = yield* GcpEnvironment.current;
27 const token = Redacted.value(env.accessToken);
28 const project = env.project;
29 yield* Effect.tryPromise({
30 try: () =>
31 fetch(
32 `https://storage.googleapis.com/storage/v1/b?project=${encodeURIComponent(project)}`,
33 {
34 method: "POST",
35 headers: {
36 Authorization: `Bearer ${token}`,
37 "Content-Type": "application/json",
38 },
39 body: JSON.stringify({
40 name: bucketName,
41 location: "US-CENTRAL1",
42 }),
43 },
44 ),
45 catch: (error) =>
46 new Error(`transcript bucket create failed: ${String(error)}`),
47 });
48 const response = yield* Effect.tryPromise({
49 try: () =>
50 fetch(
51 `https://storage.googleapis.com/upload/storage/v1/b/${bucketName}/o?uploadType=media&name=transcript.json`,
52 {
53 method: "POST",
54 headers: {
55 Authorization: `Bearer ${token}`,
56 "Content-Type": "application/json",
57 },
58 body: CHAT_TRANSCRIPT,
59 },
60 ),
61 catch: (error) => new Error(`transcript upload failed: ${String(error)}`),
62 });
63 if (!response.ok) {
64 return yield* Effect.die(
65 new Error(`transcript upload failed with HTTP ${response.status}`),
66 );
67 }
68 });
69
70/**
71 * A bucket holding {@link CHAT_TRANSCRIPT}, declared as stack resources.
72 * Conversations must name a GCS transcript as their data source.
73 */
74export const ChatTranscript = Effect.gen(function* () {
75 const bucket = yield* GCP.Storage.Bucket("Transcripts", {
76 location: "US-CENTRAL1",
77 forceDestroy: true,
78 });
79 const object = yield* GCP.Storage.Object("Transcript", {
80 bucketName: bucket.bucketName,
81 key: "transcript.json",
82 content: CHAT_TRANSCRIPT,
83 contentType: "application/json",
84 });
85 return {
86 gcsSource: {
87 transcriptUri: Output.interpolate`gs://${bucket.bucketName}/${object.key}`,
88 },
89 };
90});