nsarrazin HF staff victor HF staff commited on
Commit
af58e08
1 Parent(s): 7e685c3

Store preprompt in conversation (#422) (#470)

Browse files

* Store preprompt in conversation (#422)

* display preprompt at the top

* system prompt modal

* tweaks

---------

Co-authored-by: Victor Mustar <victor.mustar@gmail.com>

src/lib/components/SystemPromptModal.svelte ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import Modal from "./Modal.svelte";
3
+ import CarbonClose from "~icons/carbon/close";
4
+ import CarbonBlockchain from "~icons/carbon/blockchain";
5
+
6
+ export let preprompt: string;
7
+
8
+ let isOpen = false;
9
+ </script>
10
+
11
+ <button
12
+ type="button"
13
+ class="mx-auto flex items-center gap-1.5 rounded-full border border-gray-100 bg-gray-50 px-3 py-1 text-xs text-gray-500 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700"
14
+ on:click={() => (isOpen = !isOpen)}
15
+ on:keypress={(e) => e.key === "Enter" && (isOpen = !isOpen)}
16
+ >
17
+ <CarbonBlockchain class="text-xxs" /> Using Custom System Prompt
18
+ </button>
19
+
20
+ {#if isOpen}
21
+ <Modal on:close={() => (isOpen = false)} width="w-full max-w-2xl">
22
+ <div class="flex w-full flex-col gap-5 p-6">
23
+ <div class="flex items-start justify-between text-xl font-semibold text-gray-800">
24
+ <h2>System Prompt</h2>
25
+ <button type="button" class="group" on:click={() => (isOpen = false)}>
26
+ <CarbonClose class="mt-auto text-gray-900 group-hover:text-gray-500" />
27
+ </button>
28
+ </div>
29
+ <textarea
30
+ disabled
31
+ value={preprompt}
32
+ class="min-h-[420px] w-full resize-none rounded-lg border bg-gray-50 p-2.5 text-gray-600 max-sm:text-sm"
33
+ />
34
+ </div>
35
+ </Modal>
36
+ {/if}
src/lib/components/chat/ChatMessages.svelte CHANGED
@@ -10,6 +10,7 @@
10
  import ChatMessage from "./ChatMessage.svelte";
11
  import type { WebSearchUpdate } from "$lib/types/MessageUpdate";
12
  import { browser } from "$app/environment";
 
13
 
14
  export let messages: Message[];
15
  export let loading: boolean;
@@ -18,6 +19,7 @@
18
  export let currentModel: Model;
19
  export let settings: LayoutData["settings"];
20
  export let models: Model[];
 
21
  export let readOnly: boolean;
22
 
23
  let chatContainer: HTMLElement;
@@ -42,6 +44,9 @@
42
  >
43
  <div class="mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl">
44
  {#each messages as message, i}
 
 
 
45
  <ChatMessage
46
  loading={loading && i === messages.length - 1}
47
  {message}
 
10
  import ChatMessage from "./ChatMessage.svelte";
11
  import type { WebSearchUpdate } from "$lib/types/MessageUpdate";
12
  import { browser } from "$app/environment";
13
+ import SystemPromptModal from "../SystemPromptModal.svelte";
14
 
15
  export let messages: Message[];
16
  export let loading: boolean;
 
19
  export let currentModel: Model;
20
  export let settings: LayoutData["settings"];
21
  export let models: Model[];
22
+ export let preprompt: string | undefined;
23
  export let readOnly: boolean;
24
 
25
  let chatContainer: HTMLElement;
 
44
  >
45
  <div class="mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl">
46
  {#each messages as message, i}
47
+ {#if i === 0 && preprompt}
48
+ <SystemPromptModal {preprompt} />
49
+ {/if}
50
  <ChatMessage
51
  loading={loading && i === messages.length - 1}
52
  {message}
src/lib/components/chat/ChatWindow.svelte CHANGED
@@ -24,6 +24,7 @@
24
  export let models: Model[];
25
  export let settings: LayoutData["settings"];
26
  export let webSearchMessages: WebSearchUpdate[] = [];
 
27
 
28
  export let loginRequired = false;
29
  $: isReadOnly = !models.some((model) => model.id === currentModel.id);
@@ -59,6 +60,7 @@
59
  readOnly={isReadOnly}
60
  isAuthor={!shared}
61
  {webSearchMessages}
 
62
  on:message
63
  on:vote
64
  on:retry={(ev) => {
 
24
  export let models: Model[];
25
  export let settings: LayoutData["settings"];
26
  export let webSearchMessages: WebSearchUpdate[] = [];
27
+ export let preprompt: string | undefined = undefined;
28
 
29
  export let loginRequired = false;
30
  $: isReadOnly = !models.some((model) => model.id === currentModel.id);
 
60
  readOnly={isReadOnly}
61
  isAuthor={!shared}
62
  {webSearchMessages}
63
+ {preprompt}
64
  on:message
65
  on:vote
66
  on:retry={(ev) => {
src/lib/types/Conversation.ts CHANGED
@@ -17,4 +17,6 @@ export interface Conversation extends Timestamps {
17
  meta?: {
18
  fromShareId?: string;
19
  };
 
 
20
  }
 
17
  meta?: {
18
  fromShareId?: string;
19
  };
20
+
21
+ preprompt?: string;
22
  }
src/lib/types/SharedConversation.ts CHANGED
@@ -9,4 +9,5 @@ export interface SharedConversation extends Timestamps {
9
  model: string;
10
  title: string;
11
  messages: Message[];
 
12
  }
 
9
  model: string;
10
  title: string;
11
  messages: Message[];
12
+ preprompt?: string;
13
  }
src/routes/+page.svelte CHANGED
@@ -17,7 +17,10 @@
17
  headers: {
18
  "Content-Type": "application/json",
19
  },
20
- body: JSON.stringify({ model: data.settings.activeModel }),
 
 
 
21
  });
22
 
23
  if (!res.ok) {
 
17
  headers: {
18
  "Content-Type": "application/json",
19
  },
20
+ body: JSON.stringify({
21
+ model: data.settings.activeModel,
22
+ preprompt: data.settings.customPrompts[data.settings.activeModel],
23
+ }),
24
  });
25
 
26
  if (!res.ok) {
src/routes/conversation/+server.ts CHANGED
@@ -18,9 +18,12 @@ export const POST: RequestHandler = async ({ locals, request }) => {
18
  .object({
19
  fromShare: z.string().optional(),
20
  model: validateModel(models),
 
21
  })
22
  .parse(JSON.parse(body));
23
 
 
 
24
  if (values.fromShare) {
25
  const conversation = await collections.sharedConversations.findOne({
26
  _id: values.fromShare,
@@ -33,8 +36,11 @@ export const POST: RequestHandler = async ({ locals, request }) => {
33
  title = conversation.title;
34
  messages = conversation.messages;
35
  values.model = conversation.model;
 
36
  }
37
 
 
 
38
  const res = await collections.conversations.insertOne({
39
  _id: new ObjectId(),
40
  title:
@@ -42,6 +48,7 @@ export const POST: RequestHandler = async ({ locals, request }) => {
42
  "Untitled " + ((await collections.conversations.countDocuments(authCondition(locals))) + 1),
43
  messages,
44
  model: values.model,
 
45
  createdAt: new Date(),
46
  updatedAt: new Date(),
47
  ...(locals.user ? { userId: locals.user._id } : { sessionId: locals.sessionId }),
 
18
  .object({
19
  fromShare: z.string().optional(),
20
  model: validateModel(models),
21
+ preprompt: z.string().optional(),
22
  })
23
  .parse(JSON.parse(body));
24
 
25
+ let preprompt = values.preprompt;
26
+
27
  if (values.fromShare) {
28
  const conversation = await collections.sharedConversations.findOne({
29
  _id: values.fromShare,
 
36
  title = conversation.title;
37
  messages = conversation.messages;
38
  values.model = conversation.model;
39
+ preprompt = conversation.preprompt;
40
  }
41
 
42
+ const model = models.find((m) => m.name === values.model);
43
+
44
  const res = await collections.conversations.insertOne({
45
  _id: new ObjectId(),
46
  title:
 
48
  "Untitled " + ((await collections.conversations.countDocuments(authCondition(locals))) + 1),
49
  messages,
50
  model: values.model,
51
+ preprompt: preprompt === model?.preprompt ? undefined : preprompt,
52
  createdAt: new Date(),
53
  updatedAt: new Date(),
54
  ...(locals.user ? { userId: locals.user._id } : { sessionId: locals.sessionId }),
src/routes/conversation/[id]/+page.server.ts CHANGED
@@ -33,5 +33,6 @@ export const load = async ({ params, depends, locals }) => {
33
  messages: conversation.messages,
34
  title: conversation.title,
35
  model: conversation.model,
 
36
  };
37
  };
 
33
  messages: conversation.messages,
34
  title: conversation.title,
35
  model: conversation.model,
36
+ preprompt: conversation.preprompt,
37
  };
38
  };
src/routes/conversation/[id]/+page.svelte CHANGED
@@ -218,6 +218,7 @@
218
  {loading}
219
  {pending}
220
  {messages}
 
221
  bind:webSearchMessages
222
  on:message={(event) => writeMessage(event.detail)}
223
  on:retry={(event) => writeMessage(event.detail.content, event.detail.id)}
 
218
  {loading}
219
  {pending}
220
  {messages}
221
+ preprompt={data.preprompt}
222
  bind:webSearchMessages
223
  on:message={(event) => writeMessage(event.detail)}
224
  on:retry={(event) => writeMessage(event.detail.content, event.detail.id)}
src/routes/conversation/[id]/+server.ts CHANGED
@@ -70,7 +70,6 @@ export async function POST({ request, fetch, locals, params, getClientAddress })
70
 
71
  // fetch the model
72
  const model = models.find((m) => m.id === conv.model);
73
- const settings = await collections.settings.findOne(authCondition(locals));
74
 
75
  if (!model) {
76
  throw error(410, "Model not available anymore");
@@ -155,7 +154,7 @@ export async function POST({ request, fetch, locals, params, getClientAddress })
155
  messages,
156
  model,
157
  webSearch: webSearchResults,
158
- preprompt: settings?.customPrompts?.[model.id] ?? model.preprompt,
159
  locals: locals,
160
  });
161
 
 
70
 
71
  // fetch the model
72
  const model = models.find((m) => m.id === conv.model);
 
73
 
74
  if (!model) {
75
  throw error(410, "Model not available anymore");
 
154
  messages,
155
  model,
156
  webSearch: webSearchResults,
157
+ preprompt: conv.preprompt ?? model.preprompt,
158
  locals: locals,
159
  });
160
 
src/routes/conversation/[id]/share/+server.ts CHANGED
@@ -39,6 +39,7 @@ export async function POST({ params, url, locals }) {
39
  updatedAt: new Date(),
40
  title: conversation.title,
41
  model: conversation.model,
 
42
  };
43
 
44
  await collections.sharedConversations.insertOne(shared);
 
39
  updatedAt: new Date(),
40
  title: conversation.title,
41
  model: conversation.model,
42
+ preprompt: conversation.preprompt,
43
  };
44
 
45
  await collections.sharedConversations.insertOne(shared);
src/routes/r/[id]/+page.server.ts CHANGED
@@ -12,6 +12,7 @@ export const load: PageServerLoad = async ({ params }) => {
12
  }
13
 
14
  return {
 
15
  messages: conversation.messages,
16
  title: conversation.title,
17
  model: conversation.model,
 
12
  }
13
 
14
  return {
15
+ preprompt: conversation.preprompt,
16
  messages: conversation.messages,
17
  title: conversation.title,
18
  model: conversation.model,
src/routes/r/[id]/+page.svelte CHANGED
@@ -60,6 +60,7 @@
60
  {loading}
61
  shared={true}
62
  messages={data.messages}
 
63
  on:message={(ev) =>
64
  createConversation()
65
  .then((convId) => {
 
60
  {loading}
61
  shared={true}
62
  messages={data.messages}
63
+ preprompt={data.preprompt}
64
  on:message={(ev) =>
65
  createConversation()
66
  .then((convId) => {