Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d02e16a

Browse files
committed
a bit more tidying up
1 parent 5784820 commit d02e16a

File tree

4 files changed

+325
-306
lines changed

4 files changed

+325
-306
lines changed

packages/shared/scripts/seeder/seed-postgres.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ async function main() {
110110
},
111111
});
112112

113-
// Ensure a dedicated support chat session exists (ClickHouse traces are seeded elsewhere)
114-
await upsertSupportChatSession(project1);
113+
// Realistic support chat scenario
114+
await createSupportChatSession(project1);
115115

116116
await prisma.organizationMembership.upsert({
117117
where: {
@@ -774,7 +774,7 @@ async function createTraceSessions(project1: Project, project2: Project) {
774774
}
775775
}
776776

777-
async function upsertSupportChatSession(project: Project) {
777+
async function createSupportChatSession(project: Project) {
778778
const sessionId = "support-chat-session";
779779
await prisma.traceSession.upsert({
780780
where: {

packages/shared/scripts/seeder/utils/data-generators.ts

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,310 @@ export class DataGenerator {
898898
: JSON.stringify(this.fileContent.chatMlJson);
899899
}
900900

901+
/**
902+
* Creates realistic support chat session data with conversational flow.
903+
* Use for: Demonstrating session-based conversations with tool calls and scoring.
904+
*/
905+
generateSupportChatSessionData(projectId: string): {
906+
traces: TraceRecordInsertType[];
907+
observations: ObservationRecordInsertType[];
908+
scores: ScoreRecordInsertType[];
909+
} {
910+
// Domain: Art museum membership support (non-tech)
911+
const dialogues = [
912+
{
913+
user: "Hi—my family membership at the City Art Museum was charged twice this month.",
914+
assistant:
915+
"Sorry about that. I can help. Could you share your membership ID and the last 4 digits of the card?",
916+
},
917+
{
918+
user: "Membership ID is CAM-48291, card ending 4417.",
919+
assistant: "Thanks. I'll check your billing records now.",
920+
tool: {
921+
name: "billing.lookup",
922+
input: { membershipId: "CAM-48291", last4: "4417" },
923+
output: {
924+
duplicateCharge: true,
925+
amounts: [95.0, 95.0],
926+
date: "2025-08-28",
927+
},
928+
},
929+
},
930+
{
931+
user: "Okay.",
932+
assistant:
933+
"I found a duplicate charge on 2025-08-28 for $95. I can issue a refund to the original payment method. Shall I proceed?",
934+
},
935+
{
936+
user: "Yes, please issue the refund.",
937+
assistant: "Processing your refund now. One moment.",
938+
tool: {
939+
name: "billing.refund",
940+
input: { membershipId: "CAM-48291", amount: 95.0 },
941+
output: { status: "success", refundId: "RFND-20931" },
942+
},
943+
},
944+
{
945+
user: "Thank you!",
946+
assistant:
947+
"Refund RFND-20931 has been issued. You'll see it on your statement within 3–5 business days.",
948+
},
949+
{
950+
user: "No, that's all. Appreciate the quick help!",
951+
assistant: "Happy to help. Enjoy your next visit to the museum!",
952+
},
953+
// a couple more lightweight turns for scrolling realism
954+
{
955+
user: "Oh, and do members get early access to exhibitions?",
956+
assistant:
957+
"Yes—members get a 48-hour early booking window and a preview evening invite.",
958+
},
959+
{
960+
user: "Perfect.",
961+
assistant: "You're all set. Have a great day!",
962+
},
963+
];
964+
965+
const now = Date.now();
966+
const traces: TraceRecordInsertType[] = dialogues.map((d, index) => ({
967+
id: `support-chat-${index}-${projectId.slice(-8)}`,
968+
timestamp: now + index * 1000,
969+
name: "SupportChatSession",
970+
user_id: null,
971+
metadata: { scenario: "support-chat" },
972+
release: null,
973+
version: null,
974+
project_id: projectId,
975+
environment: "default",
976+
public: false,
977+
bookmarked: false,
978+
tags: ["support", "chat", "session"],
979+
input: JSON.stringify(
980+
d.tool
981+
? {
982+
messages: [
983+
{ role: "user", content: d.user },
984+
{ role: "assistant", content: d.assistant },
985+
{
986+
role: "tool",
987+
name: d.tool.name,
988+
content: d.tool.output,
989+
},
990+
],
991+
}
992+
: { messages: [{ role: "user", content: d.user }] },
993+
),
994+
output: JSON.stringify({ role: "assistant", content: d.assistant }),
995+
session_id: "support-chat-session",
996+
created_at: now + index * 1000,
997+
updated_at: now + index * 1000 + 500,
998+
event_ts: now + index * 1000,
999+
is_deleted: 0,
1000+
}));
1001+
1002+
// Create one GENERATION observation per trace
1003+
const observations: ObservationRecordInsertType[] = dialogues
1004+
.map((d, index) => {
1005+
const start = now + index * 1000 + 50;
1006+
const end = start + 400 + Math.floor(Math.random() * 400);
1007+
const inputTokens = 80 + Math.floor(Math.random() * 60);
1008+
const outputTokens = 60 + Math.floor(Math.random() * 60);
1009+
const totalTokens = inputTokens + outputTokens;
1010+
1011+
const baseGen: ObservationRecordInsertType = {
1012+
id: `support-chat-${index}-${projectId.slice(-8)}-gen`,
1013+
trace_id: `support-chat-${index}-${projectId.slice(-8)}`,
1014+
project_id: projectId,
1015+
type: "GENERATION",
1016+
parent_observation_id: null,
1017+
environment: "default",
1018+
start_time: start,
1019+
end_time: end,
1020+
name: "llm-generation",
1021+
metadata: {},
1022+
level: "DEFAULT",
1023+
status_message: null,
1024+
version: null,
1025+
input: JSON.stringify({
1026+
messages: [
1027+
{ role: "user", content: d.user },
1028+
d.tool
1029+
? {
1030+
role: "tool",
1031+
name: d.tool.name,
1032+
content: d.tool.output,
1033+
}
1034+
: undefined,
1035+
].filter(Boolean),
1036+
}),
1037+
output: JSON.stringify({ role: "assistant", content: d.assistant }),
1038+
provided_model_name: "gpt-4o",
1039+
internal_model_id: null,
1040+
model_parameters: JSON.stringify({ temperature: 0.2 }),
1041+
provided_usage_details: {
1042+
input: inputTokens,
1043+
output: outputTokens,
1044+
total: totalTokens,
1045+
},
1046+
usage_details: {
1047+
input: inputTokens,
1048+
output: outputTokens,
1049+
total: totalTokens,
1050+
},
1051+
provided_cost_details: {
1052+
input: Math.round(inputTokens * 2) / 1_000_000,
1053+
output: Math.round(outputTokens * 3) / 1_000_000,
1054+
total: Math.round(totalTokens * 5) / 1_000_000,
1055+
},
1056+
cost_details: {
1057+
input: Math.round(inputTokens * 2) / 1_000_000,
1058+
output: Math.round(outputTokens * 3) / 1_000_000,
1059+
total: Math.round(totalTokens * 5) / 1_000_000,
1060+
},
1061+
total_cost: Math.round(totalTokens * 5) / 1_000_000,
1062+
completion_start_time: start + 120,
1063+
prompt_id: null,
1064+
prompt_name: null,
1065+
prompt_version: null,
1066+
created_at: start,
1067+
updated_at: end,
1068+
event_ts: start,
1069+
is_deleted: 0,
1070+
};
1071+
1072+
if (!d.tool) return [baseGen];
1073+
1074+
const toolObs: ObservationRecordInsertType = {
1075+
id: `support-chat-${index}-${projectId.slice(-8)}-tool`,
1076+
trace_id: `support-chat-${index}-${projectId.slice(-8)}`,
1077+
project_id: projectId,
1078+
type: "TOOL",
1079+
parent_observation_id: null,
1080+
environment: "default",
1081+
start_time: start - 40,
1082+
end_time: start - 5,
1083+
name: d.tool.name,
1084+
metadata: {},
1085+
level: "DEFAULT",
1086+
status_message: null,
1087+
version: null,
1088+
input: JSON.stringify(d.tool.input),
1089+
output: JSON.stringify(d.tool.output),
1090+
provided_model_name: null,
1091+
internal_model_id: null,
1092+
model_parameters: null,
1093+
provided_usage_details: {},
1094+
usage_details: {},
1095+
provided_cost_details: {},
1096+
cost_details: {},
1097+
total_cost: null,
1098+
completion_start_time: null,
1099+
prompt_id: null,
1100+
prompt_name: null,
1101+
prompt_version: null,
1102+
created_at: start - 40,
1103+
updated_at: start - 5,
1104+
event_ts: start - 40,
1105+
is_deleted: 0,
1106+
};
1107+
1108+
return [toolObs, baseGen];
1109+
})
1110+
.flat();
1111+
1112+
// Create a couple of scores per trace
1113+
const scores: ScoreRecordInsertType[] = dialogues
1114+
.map((_, index) => {
1115+
const baseTs = now + index * 1000 + 600;
1116+
const helpfulness: ScoreRecordInsertType = {
1117+
id: `support-chat-${index}-${projectId.slice(-8)}-score-helpfulness`,
1118+
project_id: projectId,
1119+
trace_id: `support-chat-${index}-${projectId.slice(-8)}`,
1120+
session_id: null,
1121+
dataset_run_id: null,
1122+
observation_id: null,
1123+
environment: "default",
1124+
name: "helpfulness",
1125+
value: 70 + Math.random() * 25,
1126+
source: "API",
1127+
comment: "Heuristic helpfulness score",
1128+
metadata: {},
1129+
author_user_id: null,
1130+
config_id: null,
1131+
data_type: "NUMERIC",
1132+
string_value: null,
1133+
queue_id: null,
1134+
created_at: baseTs,
1135+
updated_at: baseTs,
1136+
timestamp: baseTs,
1137+
event_ts: baseTs,
1138+
is_deleted: 0,
1139+
};
1140+
1141+
const safeVal = Math.random() > 0.1 ? 1 : 0;
1142+
const safety: ScoreRecordInsertType = {
1143+
id: `support-chat-${index}-${projectId.slice(-8)}-score-safety`,
1144+
project_id: projectId,
1145+
trace_id: `support-chat-${index}-${projectId.slice(-8)}`,
1146+
session_id: null,
1147+
dataset_run_id: null,
1148+
observation_id: null,
1149+
environment: "default",
1150+
name: "safe",
1151+
value: safeVal,
1152+
source: "API",
1153+
comment: "Content safety",
1154+
metadata: {},
1155+
author_user_id: null,
1156+
config_id: null,
1157+
data_type: "BOOLEAN",
1158+
string_value: safeVal === 1 ? "true" : "false",
1159+
queue_id: null,
1160+
created_at: baseTs + 10,
1161+
updated_at: baseTs + 10,
1162+
timestamp: baseTs + 10,
1163+
event_ts: baseTs + 10,
1164+
is_deleted: 0,
1165+
};
1166+
1167+
// Optional: resolution score on last turn
1168+
const isFinal = index === dialogues.length - 1;
1169+
const resolved: ScoreRecordInsertType | null = isFinal
1170+
? {
1171+
id: `support-chat-${index}-${projectId.slice(-8)}-score-resolved`,
1172+
project_id: projectId,
1173+
trace_id: `support-chat-${index}-${projectId.slice(-8)}`,
1174+
session_id: null,
1175+
dataset_run_id: null,
1176+
observation_id: null,
1177+
environment: "default",
1178+
name: "resolved",
1179+
value: 1,
1180+
source: "API",
1181+
comment: "Conversation resolved",
1182+
metadata: {},
1183+
author_user_id: null,
1184+
config_id: null,
1185+
data_type: "BOOLEAN",
1186+
string_value: "true",
1187+
queue_id: null,
1188+
created_at: baseTs + 20,
1189+
updated_at: baseTs + 20,
1190+
timestamp: baseTs + 20,
1191+
event_ts: baseTs + 20,
1192+
is_deleted: 0,
1193+
}
1194+
: null;
1195+
1196+
return [helpfulness, safety, resolved].filter(
1197+
Boolean,
1198+
) as ScoreRecordInsertType[];
1199+
})
1200+
.flat();
1201+
1202+
return { traces, observations, scores };
1203+
}
1204+
9011205
/**
9021206
* Creates exactly one score per evaluation trace with prefixed IDs.
9031207
* Use for: Evaluation traces that need score validation, evaluator testing.

0 commit comments

Comments
 (0)