mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-15 18:30:39 +09:00
Add feedback voting and thumbs capture flow
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
3db6bdfc3c
commit
c0d0d03bce
66 changed files with 18988 additions and 78 deletions
54
server/src/services/feedback-share-client.ts
Normal file
54
server/src/services/feedback-share-client.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import type { FeedbackTraceBundle } from "@paperclipai/shared";
|
||||
import type { Config } from "../config.js";
|
||||
|
||||
function buildFeedbackShareObjectKey(bundle: FeedbackTraceBundle, exportedAt: Date) {
|
||||
const year = String(exportedAt.getUTCFullYear());
|
||||
const month = String(exportedAt.getUTCMonth() + 1).padStart(2, "0");
|
||||
const day = String(exportedAt.getUTCDate()).padStart(2, "0");
|
||||
return `feedback-traces/${bundle.companyId}/${year}/${month}/${day}/${bundle.exportId ?? bundle.traceId}.json`;
|
||||
}
|
||||
|
||||
export interface FeedbackTraceShareClient {
|
||||
uploadTraceBundle(bundle: FeedbackTraceBundle): Promise<{ objectKey: string }>;
|
||||
}
|
||||
|
||||
export function createFeedbackTraceShareClientFromConfig(
|
||||
config: Pick<Config, "feedbackExportBackendUrl" | "feedbackExportBackendToken">,
|
||||
): FeedbackTraceShareClient | null {
|
||||
const baseUrl = config.feedbackExportBackendUrl?.trim();
|
||||
if (!baseUrl) return null;
|
||||
|
||||
const token = config.feedbackExportBackendToken?.trim();
|
||||
const endpoint = new URL("/feedback-traces", baseUrl).toString();
|
||||
|
||||
return {
|
||||
async uploadTraceBundle(bundle) {
|
||||
const exportedAt = new Date();
|
||||
const objectKey = buildFeedbackShareObjectKey(bundle, exportedAt);
|
||||
const response = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
...(token ? { authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
objectKey,
|
||||
exportedAt: exportedAt.toISOString(),
|
||||
bundle,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const detail = await response.text().catch(() => "");
|
||||
throw new Error(detail.trim() || `Feedback trace upload failed with HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const payload = await response.json().catch(() => null) as { objectKey?: unknown } | null;
|
||||
return {
|
||||
objectKey: typeof payload?.objectKey === "string" && payload.objectKey.trim().length > 0
|
||||
? payload.objectKey
|
||||
: objectKey,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue