Skip to content

Commit

Permalink
Implement agent
Browse files Browse the repository at this point in the history
  • Loading branch information
dxlliv committed Jan 2, 2025
1 parent f243cec commit f9292f0
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 6 deletions.
3 changes: 3 additions & 0 deletions app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export default defineAppConfig({
agent: {
baseURL: 'https://agent.dxlliv.dev',
},
links: {
instagram: "https://instagram.com/dxlliv",
email: "mailto:[email protected]",
Expand Down
23 changes: 23 additions & 0 deletions app/components/Agent/AgentDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
defineProps<{
fullscreen?: boolean
}>()
const dialog = ref(false)
</script>

<template>
<v-dialog
activator="parent"
:model-value="true"
:width="600" max-width="calc(100vw - 36px)"
:fullscreen="fullscreen"
transition="dialog-bottom-transition"
>
<v-card :rounded="!fullscreen">

<AgentForm/>

</v-card>
</v-dialog>
</template>
58 changes: 58 additions & 0 deletions app/components/Agent/AgentForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<script setup lang="ts">
const listElement = useTemplateRef<any>('listElement')
const waitingReply = ref(false)
const appConfig = useAppConfig()
const agentBaseURL = appConfig.agent.baseURL
const chatManager = new ChatManager(listElement, agentBaseURL)
const text = ref('')
async function onNewMessage() {
const message = String(text.value)
text.value = ''
chatManager.addNewMessage('me', message)
waitingReply.value = true
await chatManager.sendMessage(message)
waitingReply.value = false
}
</script>

<template>
<v-list ref="listElement" class="mt-2" height="50vh" :max-height="400">
<v-list-item v-for="message of chatManager.chat.value" :class="['py-1']">
<AgentMessage :author="message.author" :class="[{ 'float-right': message.author === 'me' }]">
{{message.text}}
</AgentMessage>
</v-list-item>

<v-list-item v-if="waitingReply" class="py-1">
<AgentMessageWaiting />
</v-list-item>

<v-list-item v-if="chatManager.chat.value.length === 0" class="fill-height text-center">
Let's talk about projects!<br />
What do you have in mind?
</v-list-item>
</v-list>

<v-text-field
v-model="text"
variant="solo"
flat
hide-details
:readonly="waitingReply"
placeholder="Type a message"
@keydown.enter="onNewMessage"
>
<template v-slot:prepend>
<v-icon icon="mdi-account-circle-outline" class="ml-5 mr-n4" />
</template>
</v-text-field>
</template>
20 changes: 20 additions & 0 deletions app/components/Agent/AgentMessage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
defineProps<{
author: string
}>()
</script>

<template>
<v-card
class="d-inline-block text-subtitle-2 px-4 py-3"
:color="author === 'me' ? 'grey-lighten-2' : 'grey-lighten-4'" rounded flat max-width="70%"
>
<slot />
</v-card>
</template>

<style scoped lang="scss">
.v-card {
line-height: 22px;
}
</style>
5 changes: 5 additions & 0 deletions app/components/Agent/AgentMessageWaiting.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<AgentMessage author="bot" :width="56">
<v-progress-linear indeterminate color="grey-lighten-2" />
</AgentMessage>
</template>
6 changes: 1 addition & 5 deletions app/components/Toolbar/Toolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ const sliderHorizontalStore = useSliderHorizontalStore()
<v-col class="flex-grow-0 px-5" align-self="center">

<ToolbarAvailability>
<ContactDialog/>
<!--
v-if="$vuetify.display.smAndUp"
<ContactBottomSheet v-else/>
-->
<AgentDialog/>
</ToolbarAvailability>

</v-col>
Expand Down
74 changes: 74 additions & 0 deletions app/models/ChatManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
export class ChatManager {
chat: Ref<any[]> = ref([])
listElement: any
agentBaseURL: string
userId: string
roomId: string

constructor(listElement: any, agentBaseURL: string) {
this.listElement = listElement
this.agentBaseURL = agentBaseURL

this.userId = `user-${ChatManager.generateUUID()}`
this.roomId = `default-room-${ChatManager.generateUUID()}`
}

static generateUUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = Math.random() * 16 | 0
const v = c === 'x' ? r : (r & 0x3 | 0x8)
return v.toString(16)
})
}

scrollToBottom(): void {
this.listElement.value.$el.scrollTop = this.listElement.value.$el.scrollHeight
}

addNewMessage(author: string, text: string): void {
this.chat.value.push({
author,
text,
})

setTimeout(() => {
this.scrollToBottom()
}, 25)
}

async sendMessage(text: string): Promise<void> {
const data = {
text,
userId: this.userId,
roomId: this.roomId,
}

const url = `${this.agentBaseURL}/message`

await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify(data),
})
.then((response) => {
if (!response.ok) {
throw new Error(`Request failed with status: ${response.status}`)
}

return response.json()
})
.then((messages) => {
if (messages.length > 0) {
this.addNewMessage('bot', messages[0].text)
}
})
.catch(async () => {
return new Promise(resolve => setTimeout(() => {
this.addNewMessage('bot', 'There was an error')
resolve(true)
}, 3000))
})
}
}
2 changes: 1 addition & 1 deletion nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default defineNuxtConfig({
],

imports: {
dirs: ['composables', 'stores', 'utils']
dirs: ['composables', 'models', 'stores', 'utils']
},

i18n: {
Expand Down

0 comments on commit f9292f0

Please sign in to comment.