Vue AI Chat System
April 13, 2025 · AI Conversations
—
### **1. Pinia Store: Manage Chat Flow**
Create `stores/chat.ts`:
import { defineStore } from 'pinia'
interface ChatMessage {
from: 'bot' | 'user';
message: string;
}
export const useChatStore = defineStore('chat', {
state: () => ({
messages: [] as ChatMessage[],
currentQuestionIndex: 0,
questions: [
'Hi! What’s your name?',
'How can I help you today?',
'Do you prefer email or chat support?',
'Thanks! We’ll get back to you soon.'
],
}),
actions: {
nextQuestion() {
if (this.currentQuestionIndex < this.questions.length) {
this.messages.push({
from: 'bot',
message: this.questions[this.currentQuestionIndex],
});
}
},
userReply(message: string) {
this.messages.push({ from: 'user', message });
this.currentQuestionIndex++;
setTimeout(() => this.nextQuestion(), 500); // simulate delay
},
startChat() {
this.messages = [];
this.currentQuestionIndex = 0;
this.nextQuestion();
}
},
});
—
### **2. Chat UI Component**
<template>
<v-container>
<v-card>
<v-card-title>Chat Assistant</v-card-title>
<v-card-text>
<div v-for="(msg, index) in chatStore.messages" :key="index" class="my-2">
<div :class="msg.from === 'bot' ? 'text-left' : 'text-right'">
<v-chip :color="msg.from === 'bot' ? 'grey lighten-2' : 'blue lighten-2'">
{{ msg.message }}
</v-chip>
</div>
</div>
<v-text-field
v-model="input"
@keydown.enter="sendMessage"
label="Type your reply..."
variant="outlined"
></v-text-field>
</v-card-text>
</v-card>
</v-container>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useChatStore } from '@/stores/chat'
const chatStore = useChatStore()
const input = ref('')
function sendMessage() {
if (!input.value.trim()) return;
chatStore.userReply(input.value.trim())
input.value = ''
}
onMounted(() => {
chatStore.startChat()
})
</script>
<style scoped>
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
</style>
—
### **3. Add Store to App**
Make sure you register Pinia in your main file:
// main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import vuetify from './plugins/vuetify'
const app = createApp(App)
app.use(createPinia())
app.use(vuetify)
app.mount('#app')
—
This setup simulates a simple AI conversation using predefined questions. You can easily expand it with conditional logic, backend connection, or dynamic question branching.
Let me know if you want a Firebase backend or admin response logic too!
Then start chat with Admin
1. User **enters name and email**
2. Then you **authenticate anonymously via Firebase**
3. Then the **chat interface starts**, allowing the user to talk with the admin
4. Admin replies via a separate panel (Firebase Realtime DB or Firestore backend)
Let’s break this into **2 parts**:
**User Side Setup** and **Basic Firebase Auth + Chat Flow**.
—
### **1. Firebase Setup**
First, set up Firebase:
– Enable **Anonymous Auth** in Firebase console.
– Create a **Firestore** or **Realtime Database** for storing chats.
– Add your Firebase config to a local file.
Create `firebase.ts`:
// src/firebase.ts
import { initializeApp } from "firebase/app";
import { getAuth, signInAnonymously } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
const firebaseConfig = {
apiKey: "your-key",
authDomain: "your-app.firebaseapp.com",
projectId: "your-project-id",
storageBucket: "your-bucket",
messagingSenderId: "sender-id",
appId: "your-app-id"
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);
export const signInAnon = () => signInAnonymously(auth);
—
### **2. Pinia Store (Chat Logic + User Info)**
Create `stores/chat.ts`:
import { defineStore } from 'pinia'
import { signInAnon } from '@/firebase'
export const useChatStore = defineStore('chat', {
state: () => ({
name: '',
email: '',
userId: '',
authenticated: false,
chatStarted: false
}),
actions: {
async authenticate() {
const { user } = await signInAnon()
this.userId = user.uid
this.authenticated = true
},
async startChat(name: string, email: string) {
this.name = name
this.email = email
await this.authenticate()
this.chatStarted = true
}
}
})
—
### **3. Form to Enter Name & Email**
<template>
<v-container class="fill-height d-flex align-center justify-center">
<v-card width="400">
<v-card-title>User Info</v-card-title>
<v-card-text>
<v-text-field v-model="name" label="Name" required />
<v-text-field v-model="email" label="Email" required type="email" />
</v-card-text>
<v-card-actions>
<v-btn :disabled="!name || !email" @click="start" block color="primary">Start Chat</v-btn>
</v-card-actions>
</v-card>
</v-container>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useChatStore } from '@/stores/chat'
const chatStore = useChatStore()
const name = ref('')
const email = ref('')
const start = async () => {
await chatStore.startChat(name.value, email.value)
}
</script>
—
### **4. Conditionally Show Chat or Form**
In your main view:
<template>
<div>
<UserForm v-if="!chatStore.chatStarted" />
<ChatWindow v-else />
</div>
</template>
<script setup lang="ts">
import { useChatStore } from '@/stores/chat'
import UserForm from '@/components/UserForm.vue'
import ChatWindow from '@/components/ChatWindow.vue'
const chatStore = useChatStore()
</script>
—
Once authenticated, you can now build the chat logic using Firestore like:
– Collection: `chats`
– Document: `userID`
– Subcollection: `messages`
Let me know if you want the **admin panel code** or **Firestore message sync logic** next.