OverviewFilesCommitsIssuesDocsReleasesPeers

hypercore-kb / opencog-kb / language-learning / chatbot / shell.scm

193 lines · scm ref:
;
; shell.scm - Interactive chatbot shell
;
; Handles input/output, commands, and dispatches to layers.
;

(use-modules (ice-9 readline))
(use-modules (ice-9 regex))
(use-modules (ice-9 format))

(activate-readline)

;; ═══════════════════════════════════════════════════════════════════
;; CONVERSATION STORAGE
;; ═══════════════════════════════════════════════════════════════════

(define utterance-count 0)

(define (store-utterance text role)
  "Store utterance in AtomSpace"
  (set! utterance-count (+ 1 utterance-count))
  (let ((node (cog-new-node 'ConceptNode
                (format #f "utterance:~a:~a" role utterance-count))))
    ;; Store the text as a value
    (cog-set-value! node (Predicate "text") (StringValue text))
    (cog-set-value! node (Predicate "time") (FloatValue (current-time)))
    node))

;; ═══════════════════════════════════════════════════════════════════
;; COMMAND HANDLING
;; ═══════════════════════════════════════════════════════════════════

(define (command? text)
  (string-prefix? "/" text))

(define (parse-command text)
  "Parse /command arg1 arg2 into (command arg1 arg2)"
  (let ((parts (string-split (substring text 1) #\space)))
    (filter (lambda (s) (> (string-length s) 0)) parts)))

(define (handle-command parts)
  (let ((cmd (car parts))
        (args (cdr parts)))
    (cond
      ((string=? cmd "help")
       (show-help))

      ((string=? cmd "stats")
       (show-stats))

      ((string=? cmd "assoc")
       (if (null? args)
           "Usage: /assoc <word>"
           (show-associations (car args))))

      ((string=? cmd "pmi")
       (if (< (length args) 2)
           "Usage: /pmi <word1> <word2>"
           (show-pmi (car args) (cadr args))))

      ((string=? cmd "dump")
       (show-atomspace))

      ((string=? cmd "clear")
       (clear-atomspace))

      ((string=? cmd "vagueness")
       (if (null? args)
           (show-overall-vagueness)
           (show-vagueness (car args))))

      ((string=? cmd "explain")
       (if (null? args)
           "Usage: /explain <word>"
           (explain-word (car args))))

      ((string=? cmd "quit")
       'quit)

      (else
       (format #f "Unknown command: /~a (try /help)" cmd)))))

(define (show-help)
  "
Commands:
  /help              Show this help
  /stats             Show learning statistics
  /assoc <word>      Show top associations for word
  /pmi <w1> <w2>     Show PMI between two words
  /vagueness [word]  Show uncertainty (overall or for word)
  /explain <word>    Show all evidence about word
  /dump              Show raw AtomSpace contents
  /clear             Clear all knowledge (careful!)
  /quit              Exit chatbot
")

;; ═══════════════════════════════════════════════════════════════════
;; MAIN PROCESSING
;; ═══════════════════════════════════════════════════════════════════

(define (process-input text)
  "Process user input through all layers"

  ;; Layer 1: Count word pairs
  (layer1-process text)

  ;; Layer 2: Update clusters (when implemented)
  ;; (layer2-process text)

  ;; Generate response
  (generate-response text))

(define (generate-response text)
  "Generate response based on current knowledge"
  ;; Phase 0: Simple acknowledgment
  ;; Later: Use layer knowledge for intelligent responses
  (let ((pairs-learned (layer1-count-for-text text)))
    (if (> pairs-learned 0)
        (format #f "Learned ~a word associations." pairs-learned)
        "I heard you.")))

;; ═══════════════════════════════════════════════════════════════════
;; STATS & INTROSPECTION
;; ═══════════════════════════════════════════════════════════════════

(define (show-stats)
  (format #f "
Statistics:
  Utterances: ~a
  Word pairs: ~a
  Unique words: ~a
  Total observations: ~a
"
    utterance-count
    (layer1-pair-count)
    (layer1-word-count)
    (layer1-total-observations)))

(define (show-atomspace)
  (format #f "AtomSpace contains ~a atoms\n~a"
    (cog-count-atoms 'Atom)
    (cog-prt-atomspace)))

(define (clear-atomspace)
  (cog-atomspace-clear)
  (set! utterance-count 0)
  (layer1-reset)
  "Knowledge cleared.")

;; Placeholders for higher layers
(define (show-overall-vagueness)
  "Vagueness tracking not yet implemented (Layer 6+)")

(define (show-vagueness word)
  (format #f "Vagueness for '~a': not yet implemented" word))

(define (explain-word word)
  (let ((assocs (layer1-associations word 5)))
    (if (null? assocs)
        (format #f "No knowledge about '~a'" word)
        (format #f "Evidence for '~a':\n  Layer 1 (associations): ~a"
                word assocs))))

;; ═══════════════════════════════════════════════════════════════════
;; MAIN LOOP
;; ═══════════════════════════════════════════════════════════════════

(define (chatbot-loop)
  (let ((input (readline "you> ")))
    (cond
      ((not input)  ; EOF
       (display "\nGoodbye!\n"))

      ((string=? input "")
       (chatbot-loop))

      ((command? input)
       (let ((result (handle-command (parse-command input))))
         (if (eq? result 'quit)
             (display "Goodbye!\n")
             (begin
               (display result)
               (newline)
               (chatbot-loop)))))

      (else
       ;; Store and process
       (store-utterance input "user")
       (let ((response (process-input input)))
         (display (format #f "bot> ~a\n" response))
         (store-utterance response "bot"))
       (chatbot-loop)))))