Keep updating ui-template

I have a process that takes some time to complete and I wanted to add a Vue Timeline to show which steps are being executed. So the idea was that in the process (long chain of various nodes), at certain steps I branch out to the below ui-template node. So the same message is sent to this UI template, with different content, some properies are getting added as more steps are executed in the process.

The ui-template looks like this:

<template>
    <v-timeline side="end">
        <v-timeline-item :dot-color="voice_color" size="small">
            <div class="d-flex">
                <strong class="me-4">{{voice_amount}}</strong>
                <div>
                    <strong>Audio recording</strong>
                    <div class="text-body-small">
                        {{voice_text}}
                    </div>
                </div>
            </div>
        </v-timeline-item>

        <v-timeline-item :dot-color="whisper_color" size="small">
            <div class="d-flex">
                <strong class="me-4">{{whisper_amount}}</strong>
                <div>
                    <strong>Transcribe Audio</strong>
                    <div class="text-body-small">
                        {{whisper_text}}
                    </div>
                </div>
            </div>
        </v-timeline-item>

        <v-timeline-item :dot-color="llm_color" size="small">
            <div class="d-flex">
                <strong class="me-4">{{llm_amount}}</strong>
                <div>
                    <strong>Recognize Intent</strong>
                    <div class="text-body-small">
                        {{llm_text}}
                    </div>
                </div>
            </div>
        </v-timeline-item>

    </v-timeline>
</template>

<script>
    export default {
        data() {
            // define variables available component-wide
            // (in <template> and component functions)
            return {
                voice_color: 'grey',
                voice_text: 'No Audio',
                voice_amount: '',
                whisper_color: 'grey',
                whisper_text: 'Not completed yet',
                whisper_amount: '',
                llm_color: 'grey',
                llm_text: 'Not triggered yet',
                llm_amount: '',
            }
        },
        watch: {
            // watch for any changes of "count"

            msg: function(){
                    this.resetDefaults();

                    if (this.msg.rec_start) {
                        this.voice_color = 'red';
                        this.voice_amount = '';
                        this.voice_text = 'Recording...';
                    } 
                    if (this.msg.fname !== undefined) {
                        this.voice_color = 'green';
                        this.voice_amount = 'Saved';
                        this.voice_text = this.msg.fname;
                        this.whisper_color = 'yellow';
                    } 
                    if (this.msg.transcribedtext !== undefined) {
                        this.whisper_color = 'green';
                        this.whisper_amount = this.msg.whisperseconds + "ms";
                        this.whisper_text = this.msg.transcribedtext;
                        this.llm_color = 'yellow';
                    } 
                    if (this.msg.llmoutputstep) {
                        if (!this.msg.payload.done) { 
                            this.llm_color = 'red';
                            this.llm_amount = this.msg.llmseconds + "ms";
                            this.llm_text = "Error";
                        } else {
                            this.llm_color = 'green';
                            this.llm_amount = this.msg.llmseconds + "ms";
                            this.llm_text = this.msg.payload.message.content;
                        }
                    }
                
            }
        },
        computed: {

        },
        methods: {
            // expose a method to our <template> and Vue Application
            resetDefaults() {
                this.voice_color = 'grey';
                this.voice_text = 'No Audio';
                this.voice_amount = '';
                this.whisper_color = 'grey';
                this.whisper_text = 'Not completed yet';
                this.whisper_amount = '';
                this.llm_color = 'grey';
                this.llm_text = 'Not triggered yet';
                this.llm_amount = '';
            }
        },
        mounted() {
            // code here when the component is first loaded
        },
        unmounted() {
            // code here when the component is removed from the Dashboard
            // i.e. when the user navigates away from the page
        }
    }
</script>

It sort of works and sort of not:

  • when I restart the process, I would expect step 2 and 3 to be grey because the default values, but they seem to show the values from the previous message. Although the new message clearly does not have the properties in the if statements.
  • if I send an empty payload, it does not reset the UI to the grey states that I expect.

I have not done much Node-Red work in the past few months, but I am sure I have not forgotten that much, and the basic if logic is correct. If certain attributes do not exists the UI should fall back to the default color/text.

I asked Gemini about this, he said that insteal of this.msg.... I should change the watch to a handler: function(val) { and deep: true, but that seem to make no difference at all.

I am looking at this for a few hours now and just can't figure out what I have done wrong.

P.S. ignore some of the comments on the code, it is from an earlier template node.

Try putting the msg detection in mounted instead. this.msg seems to retain all previous messages

        watch: {

        },

        mounted() {
            // code here when the component is first loaded
            this.$socket.on('msg-input:' + this.id, (msg) => {
                // do stuff with msg
                // runs only when messages are received
                    this.resetDefaults()
                    
                    this.send({payload: msg.fname === undefined})

                    if (msg.rec_start) {
                        this.voice_color = 'red';
                        this.voice_amount = '';
                        this.voice_text = 'Recording...';
                    } 
                    if (msg.fname !== undefined) {
                        this.voice_color = 'green';
                        this.voice_amount = 'Saved';
                        this.voice_text = msg.fname;
                        this.whisper_color = 'yellow';
                    } 
                    if (msg.transcribedtext !== undefined) {
                        this.whisper_color = 'green';
                        this.whisper_amount = msg.whisperseconds + "ms";
                        this.whisper_text = msg.transcribedtext;
                        this.llm_color = 'yellow';
                    } 
                    if (msg.llmoutputstep) {
                        if (!this.msg.payload.done) { 
                            this.llm_color = 'red';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = "Error";
                        } else {
                            this.llm_color = 'green';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = msg.payload.message.content;
                        }
                    }

            })
        },

I tried, but with that change the UI does not render at all: SyntaxError: Unexpected keyword 'this' (21:12) (at index-B1862Wtn.js:92:9306). I can't figure out what is causing it.

Apologies, I missed a this.msg

                     if (msg.llmoutputstep) {
                        if (!this.msg.payload.done)

should be

                    if (msg.llmoutputstep) {
                        if (!msg.payload.done) { 
                            this.llm_color = 'red';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = "Error";
                        } else {
                            this.llm_color = 'green';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = msg.payload.message.content;
                        }
1 Like

Thanks, it works perfectly now.

I still don't fully understand why I had to used the mounted method this time, and was OK to use the watch method every other case I was using the ui-template node in the past.

Maybe I should have null-ed the msg object at the end of the watch function?

I tried that and it didn't make any difference.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.