Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ For more details about ECA, check [ECA server](https://github.com/editor-code-as
- External `eca` server binary
- Automatic downloaded if `eca-custom-command` is `nil`
- Place it on your `$PATH` or customize `eca-custom-command`
- [whisper.el](https://github.com/natrys/whisper.el/blob/master/whisper.el) for Speech-to-Text support (optional)

## Installation

Expand All @@ -43,6 +44,25 @@ M-x package-install eca
3. Type your prompt after the `> ` and press RET.
4. Attach more context auto completing after the `@`.

## Usage

### Speech-to-Text support

If you have [whisper.el](https://github.com/natrys/whisper.el/blob/master/whisper.el) installed you can use the `eca-chat-talk`
command (or use the `C-t` keybinding) to talk to the Editor Code
Assistant. This will record audio until you press `RET`. Then, the
recorded audio will be transcribed to text and placed into the chat
buffer.

We recommend to use the `small`, it is a good trade-off between
accuracy and transcription speed.

```elisp
(use-package whisper
:custom
(whisper-model "small"))
```

## Contributing

Contributions are very welcome, please open a issue for discussion or pull request.
31 changes: 31 additions & 0 deletions eca-chat.el
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ Must be a valid model supported by server, check `eca-chat-select-model`."
(define-key map (kbd "S-<return>") #'eca-chat--key-pressed-newline)
(define-key map (kbd "S-<return>") #'eca-chat--key-pressed-newline)
(define-key map (kbd "C-k") #'eca-chat-clear)
(define-key map (kbd "C-t") #'eca-chat-talk)
(define-key map (kbd "<return>") #'eca-chat--key-pressed-return)
map)
"Keymap used by `eca-chat-mode'.")
Expand Down Expand Up @@ -583,5 +584,35 @@ This is similar to `backward-delete-char' but protects the prompt/context line."
(when-let* ((behavior (completing-read "Select a behavior:" (append (eca--session-chat-behaviors eca--session) nil) nil t)))
(setq eca-chat-custom-behavior behavior)))

(declare-function whisper-run "ext:whisper" ())

(defun eca-chat-talk ()
"Talk to the assistent by recording audio and transcribing it."
(interactive)
(unless (featurep 'whisper)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be a if and do not execute the rest of the code if whisper is not installed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would say calling this function (via M-x or the keybinding) without whisper.el installed is a user error and we should tell them what to do instead, no? I don't really mind, but I would not be silent about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agree, but my point is that the unless block is not wrapping the rest of the code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, so in my mind this is a guard, because user-error raises a condition. The code following it, won't be called. See: https://www.gnu.org/software/emacs/manual/html_node/elisp/Signaling-Errors.html

Here is a similar example from the CIDER code base:
https://github.com/r0man/cider/blob/aa8d638814d4f4da70e5f0fe5a9aec63eb6c5a8f/cider-clojuredocs.el#L195-L196

I could do an if/else branch like this if you prefer:

(defun eca-chat-talk ()
  "Talk to the assistent by recording audio and transcribing it."
  (interactive)
  (if (not (require 'whisper nil t))
      (user-error "Whisper.el is not available, please install it first")
    (eca-chat-open)
    (with-current-buffer (eca-chat--get-buffer)
      (goto-char (point-max)))
    (let ((buffer (get-buffer-create "*whisper-stdout*")))
      (with-current-buffer buffer
        (erase-buffer)
        (make-local-variable 'whisper-after-transcription-hook)
        (add-hook 'whisper-after-transcription-hook
                  (lambda ()
                    (let ((transcription (buffer-substring
                                          (line-beginning-position)
                                          (line-end-position))))
                      (with-current-buffer eca-chat-buffer-name
                        (insert transcription)
                        (newline)
                        (eca-chat--key-pressed-return))))
                  nil t)
        (whisper-run)
        (eca-info "Recording audio. Press RET when you are done.")
        (while (not (equal ?\r (read-char)))
          (sit-for 0.5))
        (whisper-run)))))

Wdyt?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh makes sense, forgot about this behavior of error.

(user-error "Whisper.el is not available, please install it first"))
(eca-chat-open)
(with-current-buffer (eca-chat--get-buffer)
(goto-char (point-max)))
(let ((buffer (get-buffer-create "*whisper-stdout*")))
(with-current-buffer buffer
(erase-buffer)
(make-local-variable 'whisper-after-transcription-hook)
(add-hook 'whisper-after-transcription-hook
(lambda ()
(let ((transcription (buffer-substring
(line-beginning-position)
(line-end-position))))
(with-current-buffer eca-chat-buffer-name
(insert transcription)
(newline)
(eca-chat--key-pressed-return))))
nil t)
(whisper-run)
(message "Recording audio. Press RET when you are done.")
(while (not (equal ?\r (read-char)))
(sit-for 0.5))
(whisper-run))))

(provide 'eca-chat)
;;; eca-chat.el ends here
Loading