mirror of
https://github.com/coaidev/coai.git
synced 2025-06-07 22:30:17 +09:00
update chat interface
This commit is contained in:
parent
4bd30fba8f
commit
4d74ec5efe
60
app/src/assets/script/conversation.ts
Normal file
60
app/src/assets/script/conversation.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { reactive, ref } from "vue";
|
||||||
|
import type { Ref } from "vue";
|
||||||
|
|
||||||
|
type Message = {
|
||||||
|
content: string;
|
||||||
|
role: string;
|
||||||
|
timestamp: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Conversation {
|
||||||
|
id: number;
|
||||||
|
messages: Message[];
|
||||||
|
len: Ref<number>;
|
||||||
|
state: Ref<boolean>;
|
||||||
|
|
||||||
|
public constructor(id: number) {
|
||||||
|
this.id = id;
|
||||||
|
this.messages = reactive([]);
|
||||||
|
this.state = ref(false);
|
||||||
|
this.len = ref(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addMessage(message: Message): void {
|
||||||
|
this.state.value = true;
|
||||||
|
this.messages.push(message);
|
||||||
|
this.len.value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addMessageFromUser(content: string): void {
|
||||||
|
this.addMessage({
|
||||||
|
content: content,
|
||||||
|
role: "user",
|
||||||
|
timestamp: new Date().toLocaleTimeString(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public addMessageFromAI(content: string): void {
|
||||||
|
this.addMessage({
|
||||||
|
content: content,
|
||||||
|
role: "bot",
|
||||||
|
timestamp: new Date().toLocaleTimeString(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessages(): Message[] {
|
||||||
|
return this.messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessagesByRole(role: string): Message[] {
|
||||||
|
return this.messages.filter(message => message.role === role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLength(): Ref<number> {
|
||||||
|
return this.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getState(): Ref<boolean> {
|
||||||
|
return this.state;
|
||||||
|
}
|
||||||
|
}
|
21
app/src/assets/style/anim.css
Normal file
21
app/src/assets/style/anim.css
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
@keyframes FlexInAnimationFromLeft {
|
||||||
|
0% {
|
||||||
|
opacity: .2;
|
||||||
|
transform: translateX(-50px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes FlexInAnimationFromRight {
|
||||||
|
0% {
|
||||||
|
opacity: .2;
|
||||||
|
transform: translateX(50px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import './style.css'
|
import './assets/style/base.css'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from "../router";
|
import router from "../router";
|
||||||
|
|
||||||
|
@ -1,13 +1,49 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Send from "../src/components/icons/send.vue";
|
import Post from "../src/components/icons/post.vue";
|
||||||
import Openai from "../src/components/icons/openai.vue";
|
import Openai from "../src/components/icons/openai.vue";
|
||||||
|
import {Conversation} from "../src/assets/script/conversation";
|
||||||
|
import {nextTick, onMounted, ref} from "vue";
|
||||||
|
|
||||||
|
const conversation = new Conversation(1);
|
||||||
|
const state = conversation.getState(), length = conversation.getLength(), messages = conversation.getMessages();
|
||||||
|
const input = ref("");
|
||||||
|
const inputEl = ref<HTMLElement | undefined>();
|
||||||
|
const chatEl = ref<HTMLElement | undefined>();
|
||||||
|
|
||||||
|
function send() {
|
||||||
|
if (input.value) {
|
||||||
|
console.log(input.value)
|
||||||
|
conversation.addMessageFromUser(input.value);
|
||||||
|
input.value = "";
|
||||||
|
nextTick(() => {
|
||||||
|
if (!chatEl.value) return;
|
||||||
|
const el = chatEl.value as HTMLElement;
|
||||||
|
el.scrollTop = el.scrollHeight;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!inputEl.value) return;
|
||||||
|
(inputEl.value as HTMLElement).addEventListener("keydown", (e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-wrapper">
|
<div class="chat-wrapper" ref="chatEl">
|
||||||
<div class="preview">
|
<div class="conversation" v-if="state">
|
||||||
|
<div class="message" v-for="(message, index) in messages" :key="index" :class="{'user': message.role === 'user'}">
|
||||||
|
<div class="grow" v-if="message.role === 'user'"></div>
|
||||||
|
<div class="content">{{ message.content }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="preview" v-else>
|
||||||
<h1><openai /> ChatGPT</h1>
|
<h1><openai /> ChatGPT</h1>
|
||||||
<p>👋 你好!欢迎来到ChatNIO!</p>
|
<p>👋 你好!欢迎来到 ChatNio!</p>
|
||||||
<p>🧐 ChatNio 是一个 AI 聊天网站,它可以与您进行对话并提供各种功能。</p>
|
<p>🧐 ChatNio 是一个 AI 聊天网站,它可以与您进行对话并提供各种功能。</p>
|
||||||
<p>🎃 您可以向它提问问题、寻求建议,或者闲聊。</p>
|
<p>🎃 您可以向它提问问题、寻求建议,或者闲聊。</p>
|
||||||
<p>🎈 欢迎开始与 ChatNio 展开交流!</p>
|
<p>🎈 欢迎开始与 ChatNio 展开交流!</p>
|
||||||
@ -15,19 +51,25 @@ import Openai from "../src/components/icons/openai.vue";
|
|||||||
</div>
|
</div>
|
||||||
<div class="input-wrapper">
|
<div class="input-wrapper">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<input type="text" placeholder="写点什么" />
|
<input type="text" placeholder="写点什么" v-model="input" ref="inputEl" />
|
||||||
<button><send /></button>
|
<button @click="send"><post /></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@import "../src/assets/style/anim.css";
|
||||||
.chat-wrapper {
|
.chat-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 86px);
|
height: calc(100% - 86px);
|
||||||
|
max-height: calc(100vh - 86px);
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-wrapper {
|
.input-wrapper {
|
||||||
@ -107,6 +149,55 @@ import Openai from "../src/components/icons/openai.vue";
|
|||||||
fill: var(--card-text);
|
fill: var(--card-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grow {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: calc(100% - 36px);
|
||||||
|
height: auto;
|
||||||
|
margin: 12px 0;
|
||||||
|
padding: 0 18px;
|
||||||
|
animation: FlexInAnimationFromLeft 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message .content {
|
||||||
|
color: var(--card-text);
|
||||||
|
background: var(--card-input);
|
||||||
|
border: 1px solid var(--card-input-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 18px;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
transition: .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message .content:hover {
|
||||||
|
border: 1px solid var(--card-input-border-hover);
|
||||||
|
color: var(--card-text-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message .content {
|
||||||
|
color: var(--card-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.user {
|
||||||
|
animation: FlexInAnimationFromRight 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.user .content {
|
||||||
|
background: var(--card--element);
|
||||||
|
border: 1px solid var(--card-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.user .content:hover {
|
||||||
|
border: 1px solid var(--card-border-hover);
|
||||||
|
}
|
||||||
|
|
||||||
.input button svg:hover {
|
.input button svg:hover {
|
||||||
fill: var(--card-text-hover);
|
fill: var(--card-text-hover);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user