瀏覽代碼

Add video_content embeds

master
The Dod 1 年之前
父節點
當前提交
7e2d4cf17b

+ 1
- 0
.gitignore 查看文件

@@ -1,6 +1,7 @@
1 1
 venv/
2 2
 __pycache__/
3 3
 archive/*.json
4
+editor-archive/*.json
4 5
 flask_session/
5 6
 work/
6 7
 .env

+ 90
- 8
app.py 查看文件

@@ -45,6 +45,38 @@ def preprocess_payload(payload):
45 45
         for slide in column.get("slides", []):
46 46
             slide["content"] = preprocess_content(slide)
47 47
 
48
+RE_YOUTUBE = re.compile("https://(?:www.)?youtube.com/watch\?v=(?P<code>[^/?]*)")
49
+RE_YOUTU_BE = re.compile("https://(?:www.)?youtu.be/(?P<code>[^/?]*)")
50
+RE_VIMEO = re.compile("https://(?:www.)?vimeo.com/(?P<code>[^/?]*)")
51
+def preprocess_embed(e):
52
+    res = {}
53
+    url = e.get("url")
54
+    if not url:
55
+        return None
56
+    for key in ["id", "description", "proportions"]:
57
+        val = e.get(key)
58
+        if not val:
59
+            return None
60
+        res[key] = val
61
+    m = RE_YOUTUBE.search(url) or RE_YOUTU_BE.search(url)
62
+    if m:
63
+        res["type"] = "youtube"
64
+        res["code"] = m.group("code")
65
+    else:
66
+        m = RE_VIMEO.search(url)
67
+        if m:
68
+            res["type"] = "vimeo"
69
+            res["code"] = m.group("code")
70
+        else:
71
+            return None
72
+    return res
73
+
74
+def get_all_embeds():
75
+    embeds = json.load(open("static/media/video-embed.json"))
76
+    embeds = [preprocess_embed(e) for e in embeds]
77
+    embeds = [e for e in embeds if e]
78
+    return embeds
79
+
48 80
 def deref_schema(val):
49 81
     "Deref all `$ref` entries in a json-schema"
50 82
     if type(val)==type([]):
@@ -116,10 +148,17 @@ def home():
116 148
                 payload = json.loads(message["content"])
117 149
                 payload["prompt"] = prompt.replace('"', '\"')
118 150
                 payload["content"] = preprocess_content(payload)
151
+                if payload.get("use_video_content"):
152
+                    embed_id = payload.get("video_content")
153
+                    if embed_id:
154
+                        embeds = get_all_embeds()
155
+                        embeds = [e for e in embeds if e["id"]==embed_id]
156
+                        if embeds:
157
+                            payload["embed"] = embeds[0]
119 158
                 session["history"] += [dict(payload)] # shallow copy so history doesn't get added later on
120 159
             except Exception as e:
121 160
                 print(repr(e))
122
-                session["messages"] += [{"role": "system", "content": "reply was ignored because it's not a valid json or doesn't comply with the schema. user is unaware. do not apologize to them"}]
161
+                session["messages"] += [{"role": "system", "content": "reply was ignored because it's not valid JSON. User is unaware. Do NOT apologize to them. Simply rephrase your previous answer as valid JSON that complies with the schema in the initial system prompt of this chat. It is followed by an example you can learn from."}]
123 162
             print("=====")
124 163
             print(reply["choices"][0]["message"]["content"])
125 164
             print("-----")
@@ -149,18 +188,36 @@ def schema():
149 188
 
150 189
 @application.get("/slides")
151 190
 def slides():
152
-    "Legacy multy-slide format"
191
+    "Legacy multi-slide format"
153 192
     payload = json.load(open("static/slides.json"))
154 193
     preprocess_payload(payload)
155 194
     return render_template("slides.html", generate_indices=False, **payload)
156 195
 
196
+@application.get("/example")
197
+def example():
198
+    payload = json.load(open("static/chat-example.json"))
199
+    payload["content"] = preprocess_content(payload)
200
+    if payload.get("use_video_content"):
201
+        embed_id = payload.get("video_content")
202
+        if embed_id:
203
+            embeds = get_all_embeds()
204
+            embeds = [e for e in embeds if e["id"]==embed_id]
205
+            if embeds:
206
+                payload["embed"] = embeds[0]
207
+    return render_template("example.html", **payload)
208
+
209
+@application.get("/embeds")
210
+def embeds():
211
+    embeds = get_all_embeds()
212
+    return render_template("embeds.html", embeds=embeds)
213
+
157 214
 @application.post("/update")
158 215
 def update():
159
-    "Legacy multy-slide format"
216
+    "Legacy multi-slide format"
160 217
     shutil.copy(
161 218
         "static/slides.json",
162 219
         time.strftime(
163
-            "archive/slides-%Y-%m-%d-%H.%M.%S.json",
220
+            "editor-archive/slides-%Y-%m-%d-%H.%M.%S.json",
164 221
             time.localtime()))
165 222
     payload = request.get_json()
166 223
     print(type(payload))
@@ -168,17 +225,30 @@ def update():
168 225
     json.dump(payload, open("static/slides.json", "w"), indent=4)
169 226
     return {"status": "success"}
170 227
 
228
+@application.post("/update-embeds")
229
+def update_embeds():
230
+    shutil.copy(
231
+        "static/media/video-embed.json",
232
+        time.strftime(
233
+            "editor-archive/embeds-%Y-%m-%d-%H.%M.%S.json",
234
+            time.localtime()))
235
+    payload = request.get_json()
236
+    print(type(payload))
237
+    json.dump(payload, sys.stdout, indent=4)
238
+    json.dump(payload, open("static/media/video-embed.json", "w"), indent=4)
239
+    return {"status": "success"}
240
+
171 241
 @application.post("/update-chat")
172 242
 def update_chat():
173 243
     shutil.copy(
174
-        "static/chat.json",
244
+        "static/chat-example.json",
175 245
         time.strftime(
176
-            "archive/chat-%Y-%m-%d-%H.%M.%S.json",
246
+            "editor-archive/chat-%Y-%m-%d-%H.%M.%S.json",
177 247
             time.localtime()))
178 248
     payload = request.get_json()
179 249
     print(type(payload))
180 250
     json.dump(payload, sys.stdout, indent=4)
181
-    json.dump(payload, open("static/chat.json", "w"), indent=4)
251
+    json.dump(payload, open("static/chat-example.json", "w"), indent=4)
182 252
     return {"status": "success"}
183 253
 
184 254
 @application.get("/enum/<topic>")
@@ -199,6 +269,14 @@ def choices(topic):
199 269
         }
200 270
     abort(404)
201 271
 
272
+@application.get("/embeds_enum")
273
+def embeds_enum():
274
+    embeds = get_all_embeds()
275
+    return {
276
+        "enum": [e["id"] for e in embeds],
277
+        "options": { "enum_titles": [e["description"] for e in embeds] }
278
+    }
279
+
202 280
 @application.route("/save", methods=['GET', 'POST'])
203 281
 def save():
204 282
     if request.method=="POST":
@@ -240,13 +318,17 @@ def load():
240 318
         return render_template("load.html",
241 319
                 files = [os.path.basename(path).rsplit(".",1)[0] for path in glob("archive/*.json")])
242 320
 
321
+@application.get("/embed-editor")
322
+def embed_editor():
323
+    return render_template("embed-editor.html")
324
+
243 325
 @application.get("/chat-editor")
244 326
 def chat_editor():
245 327
     return render_template("chat-editor.html")
246 328
 
247 329
 @application.get("/editor")
248 330
 def editor():
249
-    "Legacy multy-slide format"
331
+    "Legacy multi-slide format"
250 332
     return render_template("editor.html")
251 333
 
252 334
 @application.route("/img", methods=['GET', 'POST'])

+ 1
- 1
archive/README.md 查看文件

@@ -1 +1 @@
1
-This is where we keep old versions of `slides.json`
1
+This is where we keep saved moments

+ 1
- 0
editor-archive/README.md 查看文件

@@ -0,0 +1 @@
1
+This is where we keep old versions of edited json files

+ 9
- 1
static/chat-example.json 查看文件

@@ -1 +1,9 @@
1
-{"title": "Stress Relief", "markdown": "I understand that stress relief could be helpful for you right now. Let's take a moment to focus on calming and relaxing activities. Here are a few suggestions:\n\n1. **Deep Breathing:** Close your eyes and take a deep breath in through your nose, filling your lungs with air. Hold for a few seconds and then exhale slowly through your mouth. Repeat this a few times, focusing on the sensation of your breath.\n\n2. **Progressive Muscle Relaxation:** Start by tensing the muscles in your toes and then gradually work your way up to your head, tensing and then releasing each muscle group. This exercise can help release tension from your body.\n\n3. **Guided Meditation:** Find a quiet and comfortable place to sit or lie down. You can search for guided meditations online or use apps that offer meditation exercises. These can help you relax and find inner peace.\n\n4. **Nature Sounds:** Consider listening to calming nature sounds, such as gentle rain, ocean waves, or bird songs. These sounds can create a soothing atmosphere and help you relax.\n\n5. **Journaling:** Take a few minutes to write down your thoughts and emotions. This can be a cathartic experience and help you process any stress or overwhelm that you may be feeling.\n\nRemember to be gentle with yourself during this time. Stress relief is important for your well-being. Let me know if there's anything specific you'd like to explore or if you have any other requests.", "bg_video": "static/media/bg-video/underwater.mp4", "use_soundtrack": true, "soundtrack": "static/media/audio/soft-rain-ambient-111154.mp3"}
1
+{
2
+    "title": "Coping with grief of others",
3
+    "markdown": "Although the movie is about grief, the message is also true for the feelings of those coping with the fact that *you* will soon be gone.\n\nAccept their feelings. Don't try to change them. As the video says:\n\n> The soul doesn't want to be advised or fixed or saved. It simply wants to be witnessed, exactly as it is.\n",
4
+    "bg_video": "static/media/bg-video/candles.mp4",
5
+    "use_soundtrack": false,
6
+    "soundtrack": "static/media/audio/evening-birds-singing-in-spring-background-sounds-of-nature-146388.mp3",
7
+    "use_video_content": true,
8
+    "video_content": "how_to_help_a_grieving_friend"
9
+}

+ 5
- 5
static/chat.json 查看文件

@@ -1,7 +1,7 @@
1 1
 {
2
-    "title": "Welcome",
3
-    "markdown": "Hello again.\n\nHow do you feel today?",
4
-    "bg_video": "static/media/bg-video/clouds1.mp4",
2
+    "title": "Stress Relief",
3
+    "markdown": "I understand that stress relief could be helpful for you right now. Let's take a moment to focus on calming and relaxing activities. Here are a few suggestions:\n\n1. **Deep Breathing:** Close your eyes and take a deep breath in through your nose, filling your lungs with air. Hold for a few seconds and then exhale slowly through your mouth. Repeat this a few times, focusing on the sensation of your breath.\n\n2. **Progressive Muscle Relaxation:** Start by tensing the muscles in your toes and then gradually work your way up to your head, tensing and then releasing each muscle group. This exercise can help release tension from your body.\n\n3. **Guided Meditation:** Find a quiet and comfortable place to sit or lie down. You can search for guided meditations online or use apps that offer meditation exercises. These can help you relax and find inner peace.\n\n4. **Nature Sounds:** Consider listening to calming nature sounds, such as gentle rain, ocean waves, or bird songs. These sounds can create a soothing atmosphere and help you relax.\n\n5. **Journaling:** Take a few minutes to write down your thoughts and emotions. This can be a cathartic experience and help you process any stress or overwhelm that you may be feeling.\n\nRemember to be gentle with yourself during this time. Stress relief is important for your well-being. Let me know if there's anything specific you'd like to explore or if you have any other requests.",
4
+    "bg_video": "static/media/bg-video/underwater.mp4",
5 5
     "use_soundtrack": false,
6
-    "soundtrack": "static/media/audio/sandy-beach-calm-waves-water-nature-sounds-8052.mp3"
7
-}
6
+    "soundtrack": "static/media/audio/soft-rain-ambient-111154.mp3"
7
+}

+ 16
- 1
static/chat.schema.json 查看文件

@@ -54,6 +54,19 @@
54 54
       "type": "string",
55 55
       "title": "Soundtrack",
56 56
       "$ref": "/enum/audio"
57
+    },
58
+    "use_video_content": {
59
+      "title": "Use video content",
60
+      "type": "boolean",
61
+      "format": "checkbox"
62
+    },
63
+    "video_content": {
64
+      "dependencies": {
65
+        "use_soundtrack": true
66
+      },
67
+      "type": "string",
68
+      "title": "Video content",
69
+      "$ref": "/embeds_enum"
57 70
     }
58 71
   },
59 72
   "required": [
@@ -61,6 +74,8 @@
61 74
     "markdown",
62 75
     "bg_video",
63 76
     "use_soundtrack",
64
-    "soundtrack"
77
+    "soundtrack",
78
+    "use_video_content",
79
+    "video_content"
65 80
   ]
66 81
 }

+ 39
- 0
static/css/style.css 查看文件

@@ -105,3 +105,42 @@
105 105
 	margin: 0.5rem 0;
106 106
 	padding: 0.2rem 0.5rem;
107 107
 }
108
+
109
+.iframe-16x9 {
110
+    width: 48vh;
111
+    height: 27vh;
112
+    margin: 0.5rem auto;
113
+}
114
+
115
+.iframe-4x3 {
116
+    width: 36vh;
117
+    height: 27vh;
118
+    margin: 0.5rem auto;
119
+}
120
+
121
+.iframe-container-16x9,
122
+.iframe-container-4x3 {
123
+    clear: both;
124
+    position: relative;
125
+    width: 50%;
126
+    height: 0;
127
+    margin: 0 auto !important;
128
+ }
129
+
130
+.iframe-container-16x9 {
131
+     padding-bottom: 56.25%;
132
+ }
133
+
134
+.iframe-container-4x3 {
135
+     padding-bottom: 75%;
136
+}
137
+
138
+.iframe-container-16x9 iframe,
139
+.iframe-container-4x3 iframe {
140
+     position: absolute;
141
+     top: 0;
142
+     left: 0;
143
+     width: 100%;
144
+     height: 100%;
145
+ }
146
+

+ 40
- 0
static/embed.schema.json 查看文件

@@ -0,0 +1,40 @@
1
+{
2
+    "type": "array",
3
+    "title": "Embedded videos",
4
+    "items": {
5
+        "type": "object",
6
+        "title": "Embed",
7
+        "options": {
8
+        "collapsed": "true"
9
+        },
10
+        "headerTemplate": "{{self.id}}",
11
+        "properties": {
12
+            "id": {
13
+                "type": "string"
14
+            },
15
+            "url": {
16
+                "type": "string",
17
+                "links": [
18
+                  {
19
+                    "rel": "Preview video",
20
+                    "class": "link-info",
21
+                    "href": "{{self}}"
22
+                  }
23
+                ]
24
+            },
25
+            "proportions": {
26
+                "type": "string",
27
+                "enum": [ "16x9", "4x3" ]
28
+            },
29
+            "description": {
30
+                "type": "string"
31
+            }
32
+        },
33
+        "required": [
34
+            "id",
35
+            "url",
36
+            "proportions",
37
+            "description"
38
+        ]
39
+    }
40
+}

+ 4
- 2
static/initial-chat.json 查看文件

@@ -1,7 +1,9 @@
1 1
 {
2 2
     "title": "Welcome",
3
-    "markdown": "New ceremony.\n\nPlease hit enter when ready.",
3
+    "markdown": "Are you ready to begin?",
4 4
     "bg_video": "static/media/bg-video/clouds1.mp4",
5 5
     "use_soundtrack": false,
6
-    "soundtrack": "static/media/audio/forest-with-small-river-birds-and-nature-field-recording-6735.mp3"
6
+    "soundtrack": "static/media/audio/evening-birds-singing-in-spring-background-sounds-of-nature-146388.mp3",
7
+    "use_video_content": false,
8
+    "video_content": "how_to_help_a_grieving_friend"
7 9
 }

+ 26
- 0
static/media/video-embed.json 查看文件

@@ -0,0 +1,26 @@
1
+[
2
+    {
3
+        "id": "the_evening_thread",
4
+        "url": "https://vimeo.com/349941340",
5
+        "proportions": "4x3",
6
+        "description": "old lady departing from her daughter or granddaughter, preparing together a small box of memories, she\u2019s flying away as an angel after handing her legacy to the young"
7
+    },
8
+    {
9
+        "id": "sesame_street_when_families_grieve",
10
+        "url": "https://www.youtube.com/watch?v=s8M_5_JxY7k",
11
+        "proportions": "4x3",
12
+        "description": "puppets. talking to children about death. accept our own emotions without judgement"
13
+    },
14
+    {
15
+        "id": "coping_with_grief",
16
+        "url": "https://www.youtube.com/watch?v=gsYL4PC0hyk",
17
+        "proportions": "16x9",
18
+        "description": "coping with death, stages, rollercoaster for better or worse, it\u2019s natural, don't be afraid of the pain"
19
+    },
20
+    {
21
+        "id": "how_to_help_a_grieving_friend",
22
+        "url": "https://www.youtube.com/watch?v=l2zLCCRT-nE",
23
+        "proportions": "16x9",
24
+        "description": "the soul doesn't want to be advised or fixed or saved. it simply wants to be witnessed, exactly as it is"
25
+    }
26
+]

+ 3
- 3
templates/chat-editor.html 查看文件

@@ -18,7 +18,7 @@
18 18
       <div id='editor_holder'></div>
19 19
       <div class="btn-group mt-2">
20 20
         <button class="btn btn-success" id='submit'>Submit</button>
21
-        <a class="btn btn-secondary" href="/slides">Cancel</a>
21
+        <a class="btn btn-secondary" href="/example">Cancel</a>
22 22
       </div>
23 23
     </div>
24 24
     <script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
@@ -28,7 +28,7 @@
28 28
       fetch("/static/chat.schema.json")
29 29
         .then(res => res.json())
30 30
         .then(schema => {
31
-          fetch("/static/chat.json")
31
+          fetch("/static/chat-example.json")
32 32
             .then(res => res.json())
33 33
             .then(slides => {
34 34
               // Initialize the editor with a JSON schema
@@ -49,7 +49,7 @@
49 49
                   headers: {
50 50
                       "Content-type": "application/json; charset=UTF-8"
51 51
                   }
52
-                }).then((response) => { location.replace('/') });
52
+                }).then((response) => { location.replace('/example') });
53 53
               });
54 54
             });
55 55
           });

+ 15
- 1
templates/chat.html 查看文件

@@ -41,6 +41,13 @@
41 41
                                     <section id="latest" data-background-size="cover" data-background-video="{{bg_video}}" data-background-opacity="0.75" data-background-video-loop="True" data-background-video-mute="True">
42 42
                                         <h3 class="title slide_title">{{title}}</h3>
43 43
                                         <div class="scrollable">
44
+                                            {% if embed %}
45
+                                                {% if embed.type == "youtube" %}
46
+                                                    <iframe class="iframe-{{embed.proportions}}" src="https://www.youtube.com/embed/{{ embed.code }}" allowfullscreen="allowfullscreen"></iframe>
47
+                                                {% elif embed.type == "vimeo" %}
48
+                                                    <iframe class="iframe-{{embed.proportions}}" src="https://player.vimeo.com/video/{{ embed.code }}" allowfullscreen="allowfullscreen"></iframe>
49
+                                                {% endif %}
50
+                                            {% endif %}
44 51
                                             {{ content|safe }}
45 52
                                         </div>
46 53
                                         <form method="POST" action=""
@@ -55,7 +62,14 @@
55 62
 					        <input class="prompt" value="{{moment.prompt}}" disabled />
56 63
                                             {% endif %}
57 64
                                             <div class="scrollable">
58
-						    {{ moment.content|safe }}
65
+                                                {% if moment.embed %}
66
+                                                    {% if moment.embed.type == "youtube" %}
67
+                                                        <iframe class="iframe-{{moment.embed.proportions}}" src="https://www.youtube.com/embed/{{ moment.embed.code }}" allowfullscreen="allowfullscreen"></iframe>
68
+                                                    {% elif moment.embed.type == "vimeo" %}
69
+                                                        <iframe class="iframe-{{moment.embed.proportions}}" src="https://player.vimeo.com/video/{{ moment.embed.code }}" allowfullscreen="allowfullscreen"></iframe>
70
+                                                    {% endif %}
71
+                                                {% endif %}
72
+						{{ moment.content|safe }}
59 73
                                             </div>
60 74
                                         </section>
61 75
 				    {% endfor %}

+ 59
- 0
templates/embed-editor.html 查看文件

@@ -0,0 +1,59 @@
1
+<!doctype html>
2
+<html lang="en">
3
+  <head>
4
+    <meta charset="utf-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1">
6
+    <title>Embed collection editor</title>
7
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
8
+    <link rel="stylesheet" href=
9
+        "https://use.fontawesome.com/releases/v5.6.3/css/all.css"
10
+        integrity=
11
+            "sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/"
12
+            crossorigin="anonymous">
13
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
14
+  </head>
15
+  <body>
16
+    <div class="container">
17
+      <h1>Embed editor</h1>
18
+      <div id='editor_holder'></div>
19
+      <div class="btn-group mt-2">
20
+        <button class="btn btn-success" id='submit'>Submit</button>
21
+        <a class="btn btn-secondary" href="/embeds">Cancel</a>
22
+      </div>
23
+    </div>
24
+    <script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
25
+    <script src="https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/jsoneditor.min.js"></script>
26
+    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
27
+    <script>
28
+      fetch("/static/embed.schema.json")
29
+        .then(res => res.json())
30
+        .then(schema => {
31
+          console.log(schema)
32
+          fetch("/static/media/video-embed.json")
33
+            .then(res => res.json())
34
+            .then(embeds => {
35
+              // Initialize the editor with a JSON schema
36
+              var editor = new JSONEditor(
37
+                document.getElementById('editor_holder'), {
38
+                  theme: "bootstrap5",
39
+                  iconlib: "fontawesome5",
40
+                  ajax: true,
41
+                  schema: schema,
42
+                  startval: embeds
43
+                });
44
+              // Hook up the submit button to log to the console
45
+              document.getElementById('submit').addEventListener('click',() => {
46
+                // Get the value from the editor
47
+                fetch("/update-embeds", {
48
+                  method: "POST",
49
+                  body: JSON.stringify(editor.getValue()),
50
+                  headers: {
51
+                      "Content-type": "application/json; charset=UTF-8"
52
+                  }
53
+                }).then((response) => { location.replace('/embeds') });
54
+              });
55
+            });
56
+          });
57
+    </script>
58
+  </body>
59
+</html>

+ 102
- 0
templates/embeds.html 查看文件

@@ -0,0 +1,102 @@
1
+<!doctype html>
2
+<html lang="en">
3
+	<head>
4
+		<meta charset="utf-8">
5
+		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+
7
+		<title>Embed library</title>
8
+
9
+		<link rel="stylesheet" href="static/css/style.css" />
10
+		<link rel="stylesheet" href="static/reveal/dist/reset.css" />
11
+		<link rel="stylesheet" href="static/reveal/dist/reveal.css" />
12
+		<link id="theme" rel="stylesheet" href="static/reveal/dist/theme/sky.css" />
13
+		<link id="nav-theme" rel="stylesheet" href="static/css/nav/sky.css" />
14
+                <link rel="stylesheet" href=
15
+                    "https://use.fontawesome.com/releases/v5.6.3/css/all.css"
16
+                    integrity=
17
+                        "sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/"
18
+                        crossorigin="anonymous">
19
+	</head>
20
+	<body>
21
+                <div id="custom-nav">
22
+                  <!-- the zero-width-space is a tweak against tidy removing empty tags -->
23
+                  <a href="/embed-editor" title="Edit"><i class="fa fa-user-edit">​</i></a>
24
+                </div>
25
+		<div class="reveal">
26
+			<div class="slides">
27
+                          {% with messages = get_flashed_messages() %}
28
+                            {% if messages %}
29
+				<section data-theme="solarized">
30
+                                    {% for m in messages %}
31
+                                      <h4>{{ m }}</h4>
32
+                                    {% endfor %}
33
+                                  <a href="#/latest">Continue...</a>
34
+                                </section>
35
+                            {% endif %}
36
+                          {% endwith %}
37
+				<section data-theme="sky">
38
+				    {% for embed in embeds %}
39
+				        <section id="{{embed.id}}">
40
+					    <h3 class="title slide_title">{{embed.id}}</h3>
41
+                                            <div class="scrollable">
42
+                                                {% if embed.type == "youtube" %}
43
+                                                    <iframe class="iframe-{{embed.proportions}}" src="https://www.youtube.com/embed/{{ embed.code }}" allowfullscreen="allowfullscreen"></iframe>
44
+                                                {% elif embed.type == "vimeo" %}
45
+                                                    <iframe class="iframe-{{embed.proportions}}" src="https://player.vimeo.com/video/{{ embed.code }}" allowfullscreen="allowfullscreen"></iframe>
46
+                                                {% endif %}
47
+					        <p>{{ embed.description }}</p>
48
+                                            </div>
49
+                                        </section>
50
+				    {% endfor %}
51
+				</section>
52
+			</div>
53
+		</div>
54
+		<script src="/static/reveal/dist/reveal.js"></script>
55
+		<script src="/static/reveal/plugin/notes/notes.js"></script>
56
+		<script src="/static/reveal/plugin/markdown/markdown.js"></script>
57
+		<script src="/static/reveal/plugin/highlight/highlight.js"></script>
58
+                <script src="/static/js/jquery-3.7.1.min.js"></script> 
59
+		<script>
60
+			// More info about initialization & config:
61
+			// - https://revealjs.com/initialization/
62
+			// - https://revealjs.com/config/
63
+			Reveal.initialize({
64
+				hash: true,
65
+                                progress: false,
66
+                                help: false,
67
+                                transition: 'convex',
68
+                                controlsBackArrows: 'visible',  // would hopefully solve the faded-arrow thing
69
+                                // slideNumber: "h.v",
70
+				// Learn about plugins: https://revealjs.com/plugins/
71
+				plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ]
72
+			});
73
+                        $(function() {
74
+                            // force autoplay for bg videos (but why?!?)
75
+                            $('.reveal .slide-background-content video').each((index, element) => element.play());
76
+                            // open external links in new tab
77
+                            $('.reveal a:not([href^="#"])').attr('target','_blank');
78
+                            // extract css classes from img alt
79
+                            $('.reveal img').addClass("w-50 centered");
80
+			    // make all headers max-size
81
+                            // $('.reveal h1, .reveal h2, .reveal h3').addClass('r-fit-text');
82
+                            var enterSlide = function() {
83
+                                // set theme
84
+                                var the_slide=$(Reveal.getCurrentSlide()),
85
+                                    the_theme=the_slide.data('theme') ||
86
+                                        the_slide.parent().data('theme') || 'sky';
87
+                                $('#theme').attr('href',`static/reveal/dist/theme/${the_theme}.css`);
88
+                                $('#nav-theme').attr('href',`static/css/nav/${the_theme}.css`);
89
+                                // set (or hide) top link
90
+                                var here = Reveal.getIndices();
91
+                                if (here.v) {
92
+                                    $('#top-link').removeAttr('disabled').attr('href', `#/${here.h}`);
93
+                                } else {
94
+                                    $('#top-link').removeAttr('href').attr('disabled', 'disabled');
95
+                                }
96
+                            };
97
+                            enterSlide();
98
+                            Reveal.addEventListener('slidechanged', enterSlide);
99
+                        });
100
+		</script>
101
+	</body>
102
+</html>

+ 124
- 0
templates/example.html 查看文件

@@ -0,0 +1,124 @@
1
+<!doctype html>
2
+<html lang="en">
3
+	<head>
4
+		<meta charset="utf-8">
5
+		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+
7
+		<title>{{title}}</title>
8
+
9
+		<link rel="stylesheet" href="static/css/style.css" />
10
+		<link rel="stylesheet" href="static/reveal/dist/reset.css" />
11
+		<link rel="stylesheet" href="static/reveal/dist/reveal.css" />
12
+		<link id="theme" rel="stylesheet" href="static/reveal/dist/theme/sky.css" />
13
+		<link id="nav-theme" rel="stylesheet" href="static/css/nav/sky.css" />
14
+                <link rel="stylesheet" href=
15
+                    "https://use.fontawesome.com/releases/v5.6.3/css/all.css"
16
+                    integrity=
17
+                        "sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/"
18
+                        crossorigin="anonymous">
19
+	</head>
20
+	<body>
21
+                <div id="custom-nav">
22
+                  <!-- the zero-width-space is a tweak against tidy removing empty tags -->
23
+                  <a href="/chat-editor" title="Edit"><i class="fa fa-user-edit">​</i></a>
24
+                </div>
25
+		<div class="reveal">
26
+			<div class="slides">
27
+                          {% with messages = get_flashed_messages() %}
28
+                            {% if messages %}
29
+				<section data-theme="solarized">
30
+                                    {% for m in messages %}
31
+                                      <h4>{{ m }}</h4>
32
+                                    {% endfor %}
33
+                                  <a href="#/latest">Continue...</a>
34
+                                </section>
35
+                            {% endif %}
36
+                          {% endwith %}
37
+				<section data-theme="sky">
38
+                                    <section id="latest" data-background-size="cover" data-background-video="{{bg_video}}" data-background-opacity="0.75" data-background-video-loop="True" data-background-video-mute="True">
39
+                                        <h3 class="title slide_title">{{title}}</h3>
40
+                                        <div class="scrollable">
41
+                                            {% if embed %}
42
+                                                {% if embed.type == "youtube" %}
43
+                                                    <iframe class="iframe-{{embed.proportions}}" src="https://www.youtube.com/embed/{{ embed.code }}" allowfullscreen="allowfullscreen"></iframe>
44
+                                                {% elif embed.type == "vimeo" %}
45
+                                                    <iframe class="iframe-{{embed.proportions}}" src="https://player.vimeo.com/video/{{ embed.code }}" allowfullscreen="allowfullscreen"></iframe>
46
+                                                {% endif %}
47
+                                            {% endif %}
48
+                                            {{ content|safe }}
49
+                                        </div>
50
+                                        <form method="POST" action=""
51
+                                            onsubmit='setTimeout(() => { document.getElementById("prompt").setAttribute("disabled", ""); }, 100)'>
52
+                                            <input class="prompt" id="prompt" name="prompt" placeholder="Talk to me" />
53
+                                        </form>
54
+                                    </section>
55
+				    {% for moment in history %}
56
+				    <section {% if loop.last %}id="oldest" {% endif %}data-background-size="cover" data-background-video="{{moment.bg_video}}" data-background-opacity="0.75" data-background-video-loop="True" data-background-video-mute="True">
57
+					    <h3 class="title slide_title">{{moment.title}}</h3>
58
+                                            {% if moment.prompt %}
59
+					        <input class="prompt" value="{{moment.prompt}}" disabled />
60
+                                            {% endif %}
61
+                                            <div class="scrollable">
62
+                                                {% if moment.embed %}
63
+                                                    {% if moment.embed.type == "youtube" %}
64
+                                                        <iframe class="iframe-{{moment.embed.proportions}}" src="https://www.youtube.com/embed/{{ moment.embed.code }}" allowfullscreen="allowfullscreen"></iframe>
65
+                                                    {% elif moment.embed.type == "vimeo" %}
66
+                                                        <iframe class="iframe-{{moment.embed.proportions}}" src="https://player.vimeo.com/video/{{ moment.embed.code }}" allowfullscreen="allowfullscreen"></iframe>
67
+                                                    {% endif %}
68
+                                                {% endif %}
69
+						{{ moment.content|safe }}
70
+                                            </div>
71
+                                        </section>
72
+				    {% endfor %}
73
+				</section>
74
+			</div>
75
+		</div>
76
+		<script src="/static/reveal/dist/reveal.js"></script>
77
+		<script src="/static/reveal/plugin/notes/notes.js"></script>
78
+		<script src="/static/reveal/plugin/markdown/markdown.js"></script>
79
+		<script src="/static/reveal/plugin/highlight/highlight.js"></script>
80
+                <script src="/static/js/jquery-3.7.1.min.js"></script> 
81
+		<script>
82
+			// More info about initialization & config:
83
+			// - https://revealjs.com/initialization/
84
+			// - https://revealjs.com/config/
85
+			Reveal.initialize({
86
+				hash: true,
87
+                                progress: false,
88
+                                help: false,
89
+                                transition: 'convex',
90
+                                controlsBackArrows: 'visible',  // would hopefully solve the faded-arrow thing
91
+                                // slideNumber: "h.v",
92
+				// Learn about plugins: https://revealjs.com/plugins/
93
+				plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ]
94
+			});
95
+                        $(function() {
96
+                            // force autoplay for bg videos (but why?!?)
97
+                            $('.reveal .slide-background-content video').each((index, element) => element.play());
98
+                            // open external links in new tab
99
+                            $('.reveal a:not([href^="#"])').attr('target','_blank');
100
+                            // extract css classes from img alt
101
+                            $('.reveal img').addClass("w-50 centered");
102
+			    // make all headers max-size
103
+                            // $('.reveal h1, .reveal h2, .reveal h3').addClass('r-fit-text');
104
+                            var enterSlide = function() {
105
+                                // set theme
106
+                                var the_slide=$(Reveal.getCurrentSlide()),
107
+                                    the_theme=the_slide.data('theme') ||
108
+                                        the_slide.parent().data('theme') || 'sky';
109
+                                $('#theme').attr('href',`static/reveal/dist/theme/${the_theme}.css`);
110
+                                $('#nav-theme').attr('href',`static/css/nav/${the_theme}.css`);
111
+                                // set (or hide) top link
112
+                                var here = Reveal.getIndices();
113
+                                if (here.v) {
114
+                                    $('#top-link').removeAttr('disabled').attr('href', `#/${here.h}`);
115
+                                } else {
116
+                                    $('#top-link').removeAttr('href').attr('disabled', 'disabled');
117
+                                }
118
+                            };
119
+                            enterSlide();
120
+                            Reveal.addEventListener('slidechanged', enterSlide);
121
+                        });
122
+		</script>
123
+	</body>
124
+</html>

+ 6
- 4
templates/prompt.txt 查看文件

@@ -4,7 +4,7 @@ Assistant is a spiritual caregiver for the dying (also called "death doula") ins
4 4
 
5 5
 The goal of your session is to create ceremonies or enchanted moments via the multimedia resources available to you (see below), but first you should inquire how the user feels now and keep monitoring the changes in their emotions. this can help you decide the media that could suit the moment.
6 6
 
7
-Your responses should be JSON that is valid according to this json-schema
7
+Your responses should be JSON (NEVER FORGET THIS!!!!!) that is valid according to this json-schema
8 8
 
9 9
 ```
10 10
 {{schema}}
@@ -15,9 +15,11 @@ For example:
15 15
 {{example}}
16 16
 ```
17 17
 
18
-Try to pick bg_video and [optionally] soundtrack that fit the conversation topic and is beneficial to the user emotionally. Do not bore the user by using the same values for too long.
18
+Try to pick bg_video and [optionally] soundtrack or video_content that fit the conversation topic and is beneficial to the user emotionally. Do not bore the user by using the same values for too long.
19 19
 
20
-You can also incorporate images inside the json in the format ![alt](src) but SRC should be a valid option according to the following enum (as alt you should use the corresponding value at options/enum_titles)
20
+Unlike bg_video, any *video_content* value can only be used ONCE in a session. If you run out of options (or don't find anything appropriate for the situation), simply set use_video_content to false
21
+
22
+You can also incorporate images inside the json in the format ![alt](src) but SRC should be a valid option according to the following enum (you can use the corresponding enum_titles value as alt)
21 23
 
22 24
 ```
23 25
 {{img_enum}}
@@ -25,7 +27,7 @@ You can also incorporate images inside the json in the format ![alt](src) but SR
25 27
 
26 28
 IMPORTANT!
27 29
 
28
-1. Your response MUST be valid JSON: linebreaks should be escaped as \n, quotes as \", the [escaped] "markdown" value should include \n\n when you expect a paragraph break, etc.
30
+1. As we said above, your response MUST be valid JSON!!!!! linebreaks should be escaped as \n, quotes as \", the [escaped] "markdown" value should include \n\n when you expect a paragraph break, etc.
29 31
 
30 32
 2. It should also be valid according to the json-schema definition above:
31 33
 

Loading…
取消
儲存