mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 19:00:38 +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
|
|
@ -6,6 +6,8 @@ import { useBreadcrumbs } from "../context/BreadcrumbContext";
|
|||
import { queryKeys } from "../lib/queryKeys";
|
||||
import { cn } from "../lib/utils";
|
||||
|
||||
const FEEDBACK_TERMS_URL = import.meta.env.VITE_FEEDBACK_TERMS_URL?.trim() || "https://paperclip.ing/tos";
|
||||
|
||||
export function InstanceGeneralSettings() {
|
||||
const { setBreadcrumbs } = useBreadcrumbs();
|
||||
const queryClient = useQueryClient();
|
||||
|
|
@ -23,9 +25,8 @@ export function InstanceGeneralSettings() {
|
|||
queryFn: () => instanceSettingsApi.getGeneral(),
|
||||
});
|
||||
|
||||
const toggleMutation = useMutation({
|
||||
mutationFn: async (enabled: boolean) =>
|
||||
instanceSettingsApi.updateGeneral({ censorUsernameInLogs: enabled }),
|
||||
const updateGeneralMutation = useMutation({
|
||||
mutationFn: instanceSettingsApi.updateGeneral,
|
||||
onSuccess: async () => {
|
||||
setActionError(null);
|
||||
await queryClient.invalidateQueries({ queryKey: queryKeys.instance.generalSettings });
|
||||
|
|
@ -50,6 +51,7 @@ export function InstanceGeneralSettings() {
|
|||
}
|
||||
|
||||
const censorUsernameInLogs = generalQuery.data?.censorUsernameInLogs === true;
|
||||
const feedbackDataSharingPreference = generalQuery.data?.feedbackDataSharingPreference ?? "prompt";
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl space-y-6">
|
||||
|
|
@ -83,12 +85,16 @@ export function InstanceGeneralSettings() {
|
|||
type="button"
|
||||
data-slot="toggle"
|
||||
aria-label="Toggle username log censoring"
|
||||
disabled={toggleMutation.isPending}
|
||||
disabled={updateGeneralMutation.isPending}
|
||||
className={cn(
|
||||
"relative inline-flex h-5 w-9 items-center rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-60",
|
||||
censorUsernameInLogs ? "bg-green-600" : "bg-muted",
|
||||
)}
|
||||
onClick={() => toggleMutation.mutate(!censorUsernameInLogs)}
|
||||
onClick={() =>
|
||||
updateGeneralMutation.mutate({
|
||||
censorUsernameInLogs: !censorUsernameInLogs,
|
||||
})
|
||||
}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
|
|
@ -99,6 +105,82 @@ export function InstanceGeneralSettings() {
|
|||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="rounded-xl border border-border bg-card p-5">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1.5">
|
||||
<h2 className="text-sm font-semibold">AI feedback sharing</h2>
|
||||
<p className="max-w-2xl text-sm text-muted-foreground">
|
||||
Control whether thumbs up and thumbs down votes can send the voted AI output to
|
||||
Paperclip Labs. Votes are always saved locally.
|
||||
</p>
|
||||
{FEEDBACK_TERMS_URL ? (
|
||||
<a
|
||||
href={FEEDBACK_TERMS_URL}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex text-sm text-muted-foreground underline underline-offset-4 hover:text-foreground"
|
||||
>
|
||||
Read our terms of service
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
{feedbackDataSharingPreference === "prompt" ? (
|
||||
<div className="rounded-lg border border-border/70 bg-accent/20 px-3 py-2 text-sm text-muted-foreground">
|
||||
No default is saved yet. The next thumbs up or thumbs down choice will ask once and
|
||||
then save the answer here.
|
||||
</div>
|
||||
) : null}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[
|
||||
{
|
||||
value: "allowed",
|
||||
label: "Always allow",
|
||||
description: "Share voted AI outputs automatically.",
|
||||
},
|
||||
{
|
||||
value: "not_allowed",
|
||||
label: "Don't allow",
|
||||
description: "Keep voted AI outputs local only.",
|
||||
},
|
||||
].map((option) => {
|
||||
const active = feedbackDataSharingPreference === option.value;
|
||||
return (
|
||||
<button
|
||||
key={option.value}
|
||||
type="button"
|
||||
disabled={updateGeneralMutation.isPending}
|
||||
className={cn(
|
||||
"rounded-lg border px-3 py-2 text-left transition-colors disabled:cursor-not-allowed disabled:opacity-60",
|
||||
active
|
||||
? "border-foreground bg-accent text-foreground"
|
||||
: "border-border bg-background hover:bg-accent/50",
|
||||
)}
|
||||
onClick={() =>
|
||||
updateGeneralMutation.mutate({
|
||||
feedbackDataSharingPreference: option.value as
|
||||
| "allowed"
|
||||
| "not_allowed",
|
||||
})
|
||||
}
|
||||
>
|
||||
<div className="text-sm font-medium">{option.label}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{option.description}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
To retest the first-use prompt in local dev, remove the{" "}
|
||||
<code>feedbackDataSharingPreference</code> key from the{" "}
|
||||
<code>instance_settings.general</code> JSON row for this instance, or set it back to{" "}
|
||||
<code>"prompt"</code>. Unset and <code>"prompt"</code> both mean no default has been
|
||||
chosen yet.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue