Code
http://github.com/semiosis/pen.el
Prompts
http://github.com/semiosis/prompts

Summary

I combine GPT-3 with org-brain to expand on topics, suggesting subtopics and providing an interactive tutor for any topic.

Demonstration

Subtopic generation

I demonstrate how to explore arbitrary topics with GPT-3 by automatically generating subtopics, and then allowing you to invoke the GPT-3 tutor to answer questions within that context.

Tutor demonstration

  • Rolling conversation is a work in progress, but on its way.

Learn about AI

Learn about microbiology

Code

Subtopic prompt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
title: "subtopic generation"
prompt: |+
    The following is a list of subtopics relating to microbiology:
    - Bacteriology
    - Mycology
    - Protozoology
    - Phycology/algology
    - Parasitology
    - Immunology
    - Virology
    - Nematology
    ###
    The following is a list of subtopics relating to natural language processing / NLP:
    - extractive question answering
    - language modelling
    - named entity recognition
    - sequence classification
    - summarization
    - text generation
    - topic modelling
    - translation
    ###
    The following is a list of subtopics relating to language modelling in NLP:
    - casual language modelling
    - masked language modelling
    - gext generation
    ###
    The following is a list of subtopics relating to <1>:
    -    
engine: "davinci"
temperature: 0.8
max-tokens: 60
top-p: 1
frequency-penalty: 0.8
presence-penalty: 0.0
best-of: 1
stop-sequences:
- "###"
chomp-start: on
chomp-end: off
inject-start-text: yes
inject-restart-text: yes
show-probabilities: off
# Cache the function by default when running the prompt function
cache: on
vars:
- "topic"
examples:
- "Advanced Type Systems in Haskell"
# External provides an alternate script that performs the same function
# external:
# - "extract-keyphrases"

Tutor prompt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
title: "Generic tutor for any topic"
prompt: |+
    This is a conversation between a human and a brilliant AI.
    The topic is "<1>".

    Human: Hello, are you my <2> tutor?
    ###
    AI: Hi there. Yes I am. How can I help you today?
    ###
    Human: What questions can I ask you about <1>?
    ###
    AI: You may ask me anything relating to <2>.
    ###
    Human: OK then. <3>
    ###
    AI: I would be happy to answer your question.
engine: "davinci"
# 0.0 = /r/hadastroke
# 1.0 = /r/iamveryrandom
# Use 0.3-0.8
temperature: 0.8
max-tokens: 60
top-p: 1.0
# Not available yet: openai api completions.create --help
frequency-penalty: 0.5
# If I make presence-penalty 0 then it will get very terse
presence-penalty: 0.0
best-of: 3
stop-sequences:
- "###"
inject-start-text: yes
inject-restart-text: yes
show-probabilities: off
vars:
- "topic"
- "in the context of"
- "question"
examples:
- "node js"
- "programming"
- "What was the version of node in 2018?"
chomp-start: on
chomp-end: off
external: ""
conversation-mode: no
filter: no
# Keep stitching together until reaching this limit
# This allows a full response for answers which may need n*max-tokens to reach the stop-sequence.
stitch-max: 0
needs-work: no

elisp for the tutor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
(defun org-brain-name-from-list-maybe (l)
  (if (and (listp l)
           (> (length l) 1))
      (second l)
    l))

(defun org-brain-remove-irrelevant-names-from-path (path)
  (-filter
   (lambda
     (e)
     (not
      (string-equal "infogetics" e)))
   path))

(defun org-brain-parent-name ()
  (snc "s join"
       (list2str
        (org-brain-remove-irrelevant-names-from-path
         (mapcar
          'org-brain-name-from-list-maybe
          (org-brain-parents org-brain--vis-entry))))))

(defun org-brain-current-name ()
  (car
   (org-brain-remove-irrelevant-names-from-path
    (mapcar
     'org-brain-name-from-list-maybe
     (list org-brain--vis-entry)))))

(defun org-brain-current-topic (&optional for-external-searching)
  (interactive)
  (let ((path
         (mapcar
          'org-brain-name-from-list-maybe
          (append (org-brain-parents org-brain--vis-entry) (list org-brain--vis-entry)))))

    (setq path
          (if for-external-searching
              (-filter (lambda (e) (not (string-equal "infogetics" e))) path)
            path))
    (let ((topic
           (chomp (apply 'cmd path))))
      (if (interactive-p)
          (etv topic)
        topic))))

(defun org-brain-asktutor (question)
  (interactive (list (read-string-hist (concat (org-brain-current-topic) ": "))))
  (mu
   (etv
    (snc
     (concat
      (cmd
       "oci"
       "openai-complete"
       "$MYGIT/semiosis/prompts/prompts/tutor.prompt"
       (org-brain-current-name)
       (org-brain-parent-name)
       question)
      " | tpp")))))

elisp for subtopic generation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
(defun org-brain-suggest-subtopics (&optional update)
  (interactive)
  (message "Using pen.el to suggest subtopics...")
  (let ((subtopic-candidates
         ;; (pen-pf-keyword-extraction (org-brain-current-topic t))
         (let ((sh-update (or sh-update
                              update
                              (eq (prefix-numeric-value current-prefix-arg) 4))))
           (let ((s (pen-pf-subtopic-generation (org-brain-pf-topic) (org-brain-existing-subtopics-stringlist))))
             (if (not (sor s))
                 (progn
                   (message "Empty generation 1/3. Trying again.")
                   (setq s (upd (pen-pf-subtopic-generation (org-brain-pf-topic) (org-brain-existing-subtopics-stringlist))))
                   (if (not (sor s))
                       (progn
                         (message "Empty generation 2/3. Trying again.")
                         (setq s (upd (pen-pf-subtopic-generation (org-brain-pf-topic) (org-brain-existing-subtopics-stringlist))))
                         (if (not (sor s))
                             (progn
                               (message "Empty generation 3/3. Giving up.")
                               (error "Empty generation 3/3. Giving up."))
                           s))
                     s)
                   s)
               s)))))

    (setq subtopic-candidates
          (str2list
           (cl-sn
            "sed 's/^- //'"
            :stdin
            (chomp
             (snc
              (cmd "scrape" "^- [a-zA-Z -]+$")
              (concat "- " subtopic-candidates))) :chomp t)))

    ;; (ns current-prefix-arg)
    (if (interactive-p)
        (let ((subtopic-selected
               (try
                (cond
                 ((or (>= (prefix-numeric-value current-prefix-arg) 16)
                      (>= (prefix-numeric-value current-prefix-arg) 32))
                  (let ((b (nbfs (list2str subtopic-candidates))))
                    (with-current-buffer b
                      (let ((r (if (yn "Add all?")
                                   subtopic-candidates)))
                        (kill-buffer b)
                        r))))
                 (t
                  ;; Select one, do not refresh cache
                  (list (fz subtopic-candidates)))))))
          (if subtopic-selected
              (cl-loop for st in subtopic-selected do
                       (org-brain-add-child-headline org-brain--vis-entry st))))
      subtopic-candidates)))

pen.el improvements

Extra demos

Learning the flamenco guitar – subtopic generation and tutor

Asking the AI professor about Paleoceanography