Skip to content

Commit

Permalink
feat: Custom user prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
motform committed Oct 5, 2024
1 parent 0035b73 commit e7a59de
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 82 deletions.
38 changes: 28 additions & 10 deletions resources/public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ textarea:focus {
}

.textarea-large {
height: 125px;
width: 100%;
overflow: scroll;
}
Expand Down Expand Up @@ -407,13 +406,10 @@ textarea:focus {
}

.tab-label {
font-weight: 700;
align-self: center;
margin-top: -5px;
color: var(--fg);
margin-top: -1px;
}

.tab-label {
.floating-tab-label {
font-weight: 700;
align-self: center;
margin-top: -5px;
Expand Down Expand Up @@ -591,6 +587,7 @@ textarea:focus {
align-items: center;
transform: scale(110%);
border: 1px solid transparent;
user-select: none;
}

.template-toggle:hover {
Expand All @@ -614,14 +611,31 @@ textarea:focus {

.template-tip {
width: 100%;
margin-top: -20px;
margin-bottom: 8px;
margin-inline: 16px;
font-size: 12px;
white-space: pre;
}

/* new-story */

.new-story {
align-items: center;
max-width: 700px;
padding-block-start: 40px;
}

.prompt {
padding-block-start: 24px;
}

.prompt-label {
font:
12px/1 "Obviously",
sans-serif;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--accent-30);
}

.prompt-background {
Expand Down Expand Up @@ -664,16 +678,20 @@ textarea:focus {
color: var(--accent-20);
}

#prompt-textarea {
.prompt-textarea {
border-color: var(--blurred-0);
}

#prompt-textarea:hover {
.prompt-textarea:disabled {
color: var(--accent-30);
}

.prompt-textarea:hover {
background-color: var(--blurred-1);
border-color: var(--blurred-1);
}

#prompt-textarea:focus {
.prompt-textarea:focus {
background-color: var(--blurred-2);
border-color: var(--blurred-2);
}
Expand Down
6 changes: 3 additions & 3 deletions src/org/motform/multiverse/components/header.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
label]
(when (and (= type :new-story)
(or @*visible? active?))
[:label.tab-label
[:label.floating-tab-label
{:class (when (and @*visible? (not active?)) "tab-label-inactive")}
"Add new story"])]))))

Expand All @@ -34,7 +34,7 @@
(rf/dispatch [:page/active :page/story])
(. (.-history js/window) pushState #js {} "" (routes/url-for :page/story)))}
[:<>
[:p title]
[:p.tab-label title]
(when (= id @(rf/subscribe [:tab/highlight]))
[:div.tab-map.rounded.shadow-large
[map/RadialMap :source/header id {} {:w 400 :h 250}]])]])
Expand All @@ -53,4 +53,4 @@
[:section.header-content.h-stack.gap-half
[Tabs]
[Item :page/new-story active-page :new-story icon/plus]]
[Item :page/library active-page :library (count @(rf/subscribe [:story/recent]))]]))
[Item :page/library active-page :library "Library"]]))
59 changes: 43 additions & 16 deletions src/org/motform/multiverse/components/new_story.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@
(defn PromptVersions []
(let [active @(rf/subscribe [:new-story/prompt-version])
Toggle (partial Toggle active :new-story/prompt-version)]
[:section.v-stack.gap-quarter
[:span.toggle-label "Prompt"]
[:section.template-toggles.h-stack.gap-quarter
[Toggle :prompt/v1 "v1"]
[Toggle :prompt/v2 "v2"]]]))
[:section.template-toggles.h-stack.gap-quarter
[Toggle :prompt/v1 "v1"]
[Toggle :prompt/v2 "v2"]]))

(defn submit-story []
(rf/dispatch [:new-story/submit])
Expand All @@ -39,19 +37,48 @@

(defn Prompt []
(let [prompt @(rf/subscribe [:new-story/prompt])
system-message @(rf/subscribe [:new-story/system-message])
user-message @(rf/subscribe [:new-story/user-message])
promt-version @(rf/subscribe [:new-story/prompt-version])
blank? (str/blank? prompt)]
[:section.prompt.prompt-background.v-stack.gap-half.rounded-large.shadow-large.pad-half
[:textarea#prompt-textarea.textarea-large.rounded.shadow-large.pad-half
{:value prompt
:auto-focus true
:on-change #(rf/dispatch [:new-story/update-prompt (.. % -target -value)])
:on-key-down #(when (and (or (.-metaKey %) (.-ctrlKey %))
(= (.-key %) "Enter"))
(submit-story))}]
[:section.prompt.prompt-background.v-stack.gap-full.rounded-large.shadow-large.pad-half

[:section.v-stack.gap-half
[:span.prompt-label "System Message"]
[:section.v-stack.gap-quarter
[:textarea#system-prompt.prompt-textarea.textarea-large.rounded.shadow-large.pad-half
{:value system-message
:rows 10
:disabled (= promt-version :prompt/v1)
:on-change #(rf/dispatch [:new-story/update :new-story/system-message (.. % -target -value)])}]
[:p.template-tip "The system message is the message that the AI will see before generating the story.\nOpenAI claims it is weighted more heavily than the user message."]]

[:span.prompt-label "User Message"]
[:section.v-stack.gap-quarter
[:textarea#system-prompt.prompt-textarea.textarea-large.rounded.shadow-large.pad-half
{:value user-message
:rows 4
:disabled (= promt-version :prompt/v1)
:on-change #(rf/dispatch [:new-story/update :new-story/user-message (.. % -target -value)])}]
[:p.template-tip "The user message is the last message the AI sees, after having been given the entire story up to this point."]]


[PromptVersions]]

[:section.v-stack.gap-half
[:span.prompt-label "Story Prompt"]
[:textarea#story-prompt.prompt-textarea.textarea-large.rounded.shadow-large.pad-half
{:value prompt
:rows 3
:auto-focus true
:on-change #(rf/dispatch [:new-story/update :new-story/prompt (.. % -target -value)])
:on-key-down #(when (and (or (.-metaKey %) (.-ctrlKey %))
(= (.-key %) "Enter"))
(submit-story))}]]


[:section.h-stack.spaced {:style {:align-items "flex-end"}}
[:section.h-stack.gap-half
[Models]
[PromptVersions]]
[Models]
[:button.rounded.shadow-medium.tab.prompt-button-submit.blurred
{:disabled blank?
:on-pointer-down #(when-not blank? (submit-story))}
Expand Down
14 changes: 10 additions & 4 deletions src/org/motform/multiverse/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
(:require
[cljs.reader :as reader]
[org.motform.multiverse.open-ai :as-alias open-ai]
[org.motform.multiverse.prompts :refer [prompts]]
[re-frame.core :as rf]))

;; We store sentences as tree implemented by as an indexed map.
Expand All @@ -22,8 +23,10 @@
{:db/stories {}
:db/state
{:page/active :page/landing
:new-story/prompt ""
:new-story/prompt "" ; the initial sentence
:new-story/prompt-version :prompt/v1 ; :prompt/v1, :prompt/v2
:new-story/system-message (get-in prompts [:prompt/v1 :system])
:new-story/user-message (get-in prompts [:prompt/v1 :user])
:new-story/model ::open-ai/gpt-3.5-turbo ; ::open-ai/gpt-4o
:story/active nil
:story/recent []
Expand Down Expand Up @@ -55,11 +58,14 @@
(get-in db [:db/stories story-id :story/sentences parent-id :sentence/children])))))

(defn request-data [db]
(let [story-id (get-in db [:db/state :story/active])]
(let [story-id (get-in db [:db/state :story/active])
story-meta #(conj [:db/stories story-id :story/meta] %)]
{:story-id story-id
:parent-id (get-in db [:db/stories story-id :story/meta :sentence/active])
:api-key (get-in db [:db/state :open-ai/key :open-ai/api-key])
:model (get-in db [:db/stories story-id :story/meta :story/model])}))
:parent-id (get-in db (story-meta :sentence/active))
:model (get-in db (story-meta :story/model))
:system-message (get-in db (story-meta :story/system-message))
:user-message (get-in db (story-meta :story/user-message))}))

(defn paragraph [db story-id sentence-id]
(reduce
Expand Down
46 changes: 32 additions & 14 deletions src/org/motform/multiverse/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[nano-id.core :refer [nano-id]]
[org.motform.multiverse.db :as db]
[org.motform.multiverse.open-ai :as open-ai]
[org.motform.multiverse.prompts :refer [prompts]]
[org.motform.multiverse.routes :as routes]
[org.motform.multiverse.story :as story]
[re-frame.core :as rf :refer [reg-event-db reg-event-fx reg-fx inject-cofx after]]))
Expand Down Expand Up @@ -100,37 +101,50 @@
(reg-event-db
:new-story/prompt-version
(fn [db [_ version]]
(assoc-in db [:db/state :new-story/prompt-version] version)))
(-> db
(assoc-in [:db/state :new-story/prompt-version] version)
(assoc-in [:db/state :new-story/system-message] (get-in prompts [version :system] ""))
(assoc-in [:db/state :new-story/user-message] (get-in prompts [version :user] "")))))

(reg-event-db
:new-story/update
(fn [db [_ k v]]
{:pre [(#{:new-story/prompt :new-story/system-message :new-story/user-message} k)
(string? v)]}
(assoc-in db [:db/state k] v)))

(reg-event-fx
:new-story/submit
(fn [{:keys [db]} _]
(let [prompt (get-in db [:db/state :new-story/prompt])
model (get-in db [:db/state :new-story/model])
version (get-in db [:db/state :new-story/prompt-version])]
version (get-in db [:db/state :new-story/prompt-version])
system-message (get-in db [:db/state :new-story/system-message])
user-message (get-in db [:db/state :new-story/user-message])]
{:db (assoc-in db [:db/state :new-story/prompt] "")
:dispatch [:story/new prompt model version]})))
:dispatch [:story/new prompt model version system-message user-message]})))

(reg-event-fx
:story/new
[local-storage-interceptor]
(fn [{:keys [db]} [_ prompt model version]]
(fn [{:keys [db]} [_ prompt model version system-message user-message]]
(let [story-id (nano-id 10)
sentence-id (nano-id 10)]
sentence-id (nano-id 10)
story (story/->story prompt
:id story-id
:sentence-id sentence-id
:model model
:version version
:system-message system-message
:user-message user-message)]
{:db (-> db
(assoc-in [:db/stories story-id]
(story/->story prompt :id story-id :sentence-id sentence-id :model model :version version))
(assoc-in [:db/stories story-id] story)
(assoc-in [:db/state :story/active] story-id)
(assoc-in [:db/state :sentence/active] sentence-id)
(assoc-in [:db/state :sentence/highlight] {:id sentence-id :source :page/new-story})
(update-in [:db/state :story/recent] conj story-id))
:dispatch [:open-ai/title]})))

(reg-event-db
:new-story/update-prompt
(fn [db [_ prompt]]
(assoc-in db [:db/state :new-story/prompt] prompt)))

;; Library

(reg-event-db
Expand Down Expand Up @@ -200,8 +214,12 @@
(reg-event-fx
:open-ai/completions
(fn [{:keys [db]} [_ parent-id prompt]]
(let [{:keys [story-id api-key model]} (db/request-data db)
params (open-ai/request-next-sentence model prompt)]
(let [{:keys [story-id api-key model system-message user-message]} (db/request-data db)
params (open-ai/request-next-sentence
:model model
:paragraphs prompt
:system-message system-message
:user-message user-message)]
{:db (assoc-in db [:db/state :open-ai/pending-request?] true)
:http-xhrio
{:method :post
Expand Down
40 changes: 7 additions & 33 deletions src/org/motform/multiverse/open_ai.cljs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
(ns org.motform.multiverse.open-ai)
(ns org.motform.multiverse.open-ai
(:require
[org.motform.multiverse.prompts :as prompts]))

(defn auth [api-key]
{"Authorization" (str "Bearer " api-key)})
Expand All @@ -25,49 +27,21 @@

;; Chat

(def system-message
(->message ::system
"You are an award winning AUTHOR writing an experimental, hypertext story.
Your work is boundary pushing and the stories you write are often nonlinear.
Twists and turns are your specialty. Characters meander through your stories,
often in a postmodern fashion. You are a master of the craft. You are a genius.
The story is written in a contemporary, neutral style.
BE CONCISE. Be creative. Be weird. Be yourself. Write like your life depends on it.
Your response should ONLY BE THE THE NEXT SENTENCE OF THE STORY.
It is very important that you only respond WITH A SINGLE SENTENCE, or else the game will break.
NEVER include your prompt, or any other texts other than THE NEXT SENTENCE ONLY."))

(def next-sentence
(->message ::user
"Now it is your time to write the next sentence.
It is VERY important that respond in the style you were ask to emulate.
As a reminder, your style is: The story is written in a contemporary, neutral style.
The next sentence is:"))


(defn request-next-sentence [model paragraphs]
(defn request-next-sentence [& {:keys [model paragraphs system-message user-message]}]
{:pre [(valid-model? model)]}
{:n 3
:model model
:messages (flatten
[system-message
[(->message ::system system-message)
(map #(->message ::assistant (:sentence/text %)) paragraphs)
next-sentence])})
(->message ::user user-message)])})

;; Title

(def title-prompt
"You are an award winning AUTHOR writing an experimental, hypertext story.
Your work is boundary pushing and your titles are witty, smart and experimental. You will be provided with a short story.
Your task is to SUGGEST A TITLE FOR IT. The title should give the reader a good idea of the story, in a clever, funny way.
Respond ONLY with the title and no other content.
NEVER repeat anything from your prompt.
DO NOT ENCLOSE THE TITLE IN QUOTATION MARKS.")

(defn request-title [model paragraphs]
{:pre [(valid-model? model)]}
(let [sentences (map :sentence/text paragraphs)]
{:n 1
:model model
:messages [(->message ::system title-prompt)
:messages [(->message ::system prompts/title)
(->message ::user (apply str "Here is the short story:\n" sentences))]}))
Loading

0 comments on commit e7a59de

Please sign in to comment.