فهرست منبع

chat component

Dr-Swopt 2 هفته پیش
والد
کامیت
7a7716a81e

+ 87 - 0
src/app/chat/chat.component.css

@@ -0,0 +1,87 @@
+.chat-container {
+  max-width: 600px;
+  margin: 30px auto;
+  display: flex;
+  flex-direction: column;
+  height: 500px;
+  border-radius: 12px;
+  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
+  background-color: #fafafa;
+}
+
+mat-card-title {
+  font-size: 1.6rem;
+  font-weight: 600;
+  text-align: center;
+  margin: 16px 0;
+}
+
+mat-card-content {
+  flex: 1;
+  overflow-y: auto;
+  padding: 16px;
+  display: flex;
+  flex-direction: column;
+  gap: 12px; /* space between messages */
+}
+
+.messages {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.message {
+  padding: 10px 16px;
+  border-radius: 20px;
+  max-width: 70%;
+  word-wrap: break-word;
+  overflow-wrap: break-word;
+  white-space: pre-wrap;
+  line-height: 1.4;
+}
+
+/* User messages */
+.user {
+  background-color: #1976d2;
+  color: white;
+  align-self: flex-end; /* pushes message to the right */
+  text-align: right;
+}
+
+/* Bot messages */
+.bot {
+  background-color: #e0e0e0;
+  color: #333;
+  align-self: flex-start; /* pushes message to the left */
+  text-align: left;
+}
+
+.bot-typing {
+  font-style: italic;
+  color: #666;
+}
+
+/* Chat input area */
+.chat-input {
+  display: flex;
+  gap: 10px;
+  padding: 12px 16px;
+  border-top: 1px solid #ddd;
+  background-color: #f5f5f5;
+}
+
+.chat-input mat-form-field {
+  flex: 1;
+  margin: 0;
+}
+
+/* Scrollbar styling */
+mat-card-content::-webkit-scrollbar {
+  width: 6px;
+}
+
+mat-card-content::-webkit-scrollbar-thumb {
+  background-color: rgba(0,0,0,0.2);
+  border-radius: 3px;
+}

+ 18 - 0
src/app/chat/chat.component.html

@@ -0,0 +1,18 @@
+<mat-card class="chat-container">
+  <mat-card-title>Web Chat</mat-card-title>
+  <mat-card-content>
+    <div class="messages">
+      <div *ngFor="let msg of messages" [ngClass]="['message', msg.sender]">
+        <strong>{{ msg.sender === 'user' ? 'You' : 'Bot' }}:</strong>
+        <span>{{ msg.content }}</span>
+      </div>
+    </div>
+    <div *ngIf="loading" class="bot-typing">Bot is typing...</div>
+  </mat-card-content>
+  <mat-card-actions class="chat-input">
+    <mat-form-field appearance="outline">
+      <input matInput placeholder="Type a message" [(ngModel)]="inputMessage" (keyup.enter)="sendMessage()" />
+    </mat-form-field>
+    <button mat-raised-button color="primary" (click)="sendMessage()">Send</button>
+  </mat-card-actions>
+</mat-card>

+ 23 - 0
src/app/chat/chat.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ChatComponent } from './chat.component';
+
+describe('Chat', () => {
+  let component: ChatComponent;
+  let fixture: ComponentFixture<ChatComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [ChatComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(ChatComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 53 - 0
src/app/chat/chat.component.ts

@@ -0,0 +1,53 @@
+import { Component } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { HttpClient, HttpClientModule } from '@angular/common/http';
+import { MatCardModule } from '@angular/material/card';
+import { MatInputModule } from '@angular/material/input';
+import { MatButtonModule } from '@angular/material/button';
+import { MatListModule } from '@angular/material/list';
+import { webConfig } from '../config';
+
+interface ChatMessage {
+  content: string;
+  sender: 'user' | 'bot';
+}
+
+@Component({
+  selector: 'app-chat',
+  standalone: true,
+  imports: [CommonModule, FormsModule, HttpClientModule, MatCardModule, MatInputModule, MatButtonModule, MatListModule],
+  templateUrl: './chat.component.html',
+  styleUrls: ['./chat.component.css']
+})
+export class ChatComponent {
+  messages: ChatMessage[] = [];
+  inputMessage: string = '';
+  loading = false;
+
+  constructor(private http: HttpClient) {}
+
+  sendMessage() {
+    if (!this.inputMessage.trim()) return;
+
+    const userMessage: ChatMessage = { content: this.inputMessage, sender: 'user' };
+    this.messages.push(userMessage);
+
+    const messageToSend = this.inputMessage;
+    this.inputMessage = '';
+    this.loading = true;
+
+    this.http.post<{ answer: string }>(`${webConfig.exposedUrl}/api/ffb-production/query`, { message: messageToSend })
+      .subscribe({
+        next: (res) => {
+          this.messages.push({ content: res.answer, sender: 'bot' });
+          this.loading = false;
+        },
+        error: (err) => {
+          console.error(err);
+          this.messages.push({ content: 'Error: Could not get response.', sender: 'bot' });
+          this.loading = false;
+        }
+      });
+  }
+}

+ 4 - 0
src/app/dashboard/dashboard.component.html

@@ -20,4 +20,8 @@
     <!-- Integrate PlantationTreeComponent here -->
     <app-plantation-tree></app-plantation-tree>
   </mat-tab>
+
+  <mat-tab label="Chat">
+    <app-chat></app-chat>
+  </mat-tab>
 </mat-tab-group>

+ 3 - 1
src/app/dashboard/dashboard.component.ts

@@ -8,6 +8,7 @@ import { PlantationTreeComponent } from "../plantation/plantation-tree.component
 import { ActivityComponent } from '../activity/activity.component';
 import { FfbProductionComponent } from "../ffb/ffb-production.component";
 import { WebcamComponent } from "../webcam/webcam.component";
+import { ChatComponent } from "../chat/chat.component";
 
 @Component({
   selector: 'app-dashboard',
@@ -20,7 +21,8 @@ import { WebcamComponent } from "../webcam/webcam.component";
     PlantationTreeComponent,
     ActivityComponent,
     FfbProductionComponent,
-    WebcamComponent
+    WebcamComponent,
+    ChatComponent
 ],
   templateUrl: './dashboard.component.html',
   styleUrls: ['./dashboard.component.css']