Oviya commited on
Commit
678e6ea
·
1 Parent(s): 4a26147

update chatbot

Browse files
public/user.png ADDED

Git LFS Details

  • SHA256: fff7792043ab393f315e35d1813c0b03e2c1a3263526c2b07f8c6e72a4e0eef6
  • Pointer size: 130 Bytes
  • Size of remote file: 46.7 kB
src/app/chatbot/chatbot.html CHANGED
@@ -1,39 +1,41 @@
1
- <!-- src/app/llama-demo/llama-demo.component.html -->
2
- <div class="card">
3
- <h2>GGUF LLaMA Demo</h2>
 
 
 
 
 
 
 
 
 
4
 
5
- <div class="field">
6
- <label>Prompt</label>
7
- <textarea rows="6" [formControl]="form.controls.prompt"
8
- placeholder="Write your question or instruction here"></textarea>
9
- </div>
10
-
11
- <div class="row">
12
- <div class="field">
13
- <label>Max tokens</label>
14
- <input type="number" [formControl]="form.controls.max_tokens" min="16" />
15
- </div>
16
- <div class="field">
17
- <label>Temperature</label>
18
- <input type="number" step="0.1" [formControl]="form.controls.temperature" />
19
- </div>
20
- <div class="field">
21
- <label>Top-p</label>
22
- <input type="number" step="0.05" [formControl]="form.controls.top_p" />
23
- </div>
24
- <div class="field">
25
- <label>Repeat penalty</label>
26
- <input type="number" step="0.1" [formControl]="form.controls.repeat_penalty" />
27
  </div>
28
  </div>
29
 
30
- <button (click)="onGenerate()" [disabled]="isLoading">Generate</button>
31
-
32
- <div class="status" *ngIf="isLoading">Generating…</div>
33
- <div class="error" *ngIf="errorMsg">{{ errorMsg }}</div>
34
-
35
- <div class="output" *ngIf="resultText">
36
- <h3>Output</h3>
37
- <pre>{{ resultText }}</pre>
38
  </div>
39
  </div>
 
1
+ <div class="chat-container">
2
+ <div class="chat-box" #chatBox>
3
+ <div class="chat-message" *ngFor="let message of messages; trackBy: trackByIndex">
4
+ <!-- User Message -->
5
+ <div class="user-message" *ngIf="message.user">
6
+ <div class="avatar">
7
+ <img src="/user.png" alt="User" />
8
+ </div>
9
+ <div class="message-content">
10
+ <p>{{ message.user }}</p>
11
+ </div>
12
+ </div>
13
 
14
+ <!-- Bot Message -->
15
+ <div class="bot-message" *ngIf="message.bot !== null">
16
+ <div class="message-content">
17
+ <!-- Show typing dots for the latest pair while waiting -->
18
+ <ng-container *ngIf="message.bot === '' && isLast(message) && loading; else botText">
19
+ <div class="typing">
20
+ <span></span><span></span><span></span>
21
+ </div>
22
+ </ng-container>
23
+ <ng-template #botText>
24
+ <p>{{ message.bot }}</p>
25
+ </ng-template>
26
+ </div>
27
+ <div class="avatar">
28
+ <img src="/chatbot.png" alt="Bot" />
29
+ </div>
30
+ </div>
 
 
 
 
 
31
  </div>
32
  </div>
33
 
34
+ <div class="input-box">
35
+ <input type="text"
36
+ [(ngModel)]="question"
37
+ placeholder="Type your message here..."
38
+ (keyup.enter)="askQuestion()" />
39
+ <button (click)="askQuestion()" [disabled]="loading && question.trim() === ''">Send</button>
 
 
40
  </div>
41
  </div>
src/app/chatbot/chatbot.scss CHANGED
@@ -1,74 +1,165 @@
1
- /* src/app/llama-demo/llama-demo.component.css */
2
- .card {
3
- max-width: 860px;
4
- margin: 24px auto;
5
- padding: 16px;
6
- border-radius: 12px;
7
- background: #111;
8
- color: #eee;
9
- box-shadow: 0 8px 24px rgba(0,0,0,0.3);
10
  }
11
 
12
- .field {
 
13
  display: flex;
14
  flex-direction: column;
15
- margin-bottom: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
17
 
18
- .field > label {
19
- font-size: 0.9rem;
20
- opacity: 0.9;
21
- margin-bottom: 4px;
 
 
22
  }
23
 
24
- textarea, input {
25
- background: #181818;
26
- color: #f0f0f0;
27
- border: 1px solid #2a2a2a;
28
- border-radius: 8px;
29
- padding: 10px;
30
  }
31
 
32
- .row {
33
- display: grid;
34
- grid-template-columns: repeat(4, 1fr);
35
- gap: 12px;
36
- margin: 12px 0;
 
37
  }
38
 
39
- button {
40
- padding: 10px 16px;
41
- border-radius: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  border: none;
43
- color: #0b0b0b;
44
- background: #a6ff00; /* subtle neon green accent */
45
  cursor: pointer;
 
 
 
 
 
 
 
46
  }
47
 
48
- button[disabled] {
49
- opacity: 0.6;
50
- cursor: not-allowed;
 
 
 
51
  }
52
 
53
- .status {
54
- margin-top: 12px;
55
- opacity: 0.9;
 
 
 
 
56
  }
57
 
58
- .error {
59
- margin-top: 12px;
60
- color: #ff8080;
61
  }
62
 
63
- .output {
64
- margin-top: 16px;
65
- background: #0d0d0d;
66
- border: 1px solid #242424;
67
- border-radius: 8px;
68
- padding: 12px;
69
  }
70
 
71
- pre {
72
- white-space: pre-wrap;
73
- word-break: break-word;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
 
1
+ /* Container */
2
+ .chat-container {
3
+ overflow-y: overlay;
4
+ padding-top: 10vw;
5
+ height: 30vw;
 
 
 
 
6
  }
7
 
8
+ /* Message wrapper */
9
+ .chat-message {
10
  display: flex;
11
  flex-direction: column;
12
+ gap: 6px;
13
+ animation: fadeIn 0.25s ease-out;
14
+ max-width: 100%;
15
+ }
16
+
17
+ .user-message,
18
+ .bot-message {
19
+ display: flex;
20
+ align-items: center;
21
+ padding: 12px 20px;
22
+ gap: 2vw;
23
+ }
24
+
25
+ .user-message {
26
+ justify-content: flex-start;
27
+ }
28
+
29
+ .bot-message {
30
+ justify-content: flex-end;
31
+ align-self: flex-end;
32
  }
33
 
34
+ .avatar {
35
+ width: 40px;
36
+ height: 40px;
37
+ border-radius: 50%;
38
+ overflow: hidden;
39
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
40
  }
41
 
42
+ .avatar img {
43
+ width: 100%;
44
+ height: 100%;
45
+ object-fit: cover;
 
 
46
  }
47
 
48
+ .user-message .message-content,
49
+ .bot-message .message-content {
50
+ padding: 12px 20px;
51
+ border-radius: 10px;
52
+ box-shadow: 0 4px 10px rgba(0,0,0,0.1);
53
+ width: 50%;
54
  }
55
 
56
+ .user-message .message-content {
57
+ background-color: #f4f4f4;
58
+ width: auto;
59
+ }
60
+
61
+ .bot-message .message-content {
62
+ background-color: #f4f4f4;
63
+ }
64
+
65
+ .message-content p {
66
+ margin: 0;
67
+ color: #333;
68
+ font-size: 1vw;
69
+ line-height: 1.5;
70
+ }
71
+
72
+ /* Input */
73
+ .input-box {
74
+ display: flex;
75
+ gap: 1vw;
76
+ padding: 2vw;
77
+ border-top: 1px solid #ddd;
78
+ background-color: #fff;
79
+ position: absolute;
80
+ bottom: 0;
81
+ width: -webkit-fill-available;
82
+ }
83
+
84
+ .input-box input {
85
+ flex: 1 1 auto;
86
+ padding: 1vw;
87
+ font-size: 1vw;
88
+ border-radius: 12px;
89
+ border: 1px solid #ddd;
90
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
91
+ outline: none;
92
+ transition: border 0.3s ease;
93
+ font-family: 'Roboto', sans-serif;
94
+ }
95
+
96
+ .input-box input:focus {
97
+ border-color: #4e8fff;
98
+ box-shadow: 0 4px 10px rgba(78,143,255,0.3);
99
+ }
100
+
101
+ .input-box button {
102
+ padding: 10px 15px;
103
+ background-color: #4e8fff;
104
+ color: #fff;
105
  border: none;
106
+ border-radius: 12px;
 
107
  cursor: pointer;
108
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
109
+ transition: background-color 0.3s ease;
110
+ font-family: 'Roboto', sans-serif;
111
+ }
112
+
113
+ .input-box button:hover {
114
+ background-color: #1e6ab2;
115
  }
116
 
117
+ /* Typing dots */
118
+ .typing {
119
+ display: inline-flex;
120
+ align-items: center;
121
+ gap: 6px;
122
+ height: 1em;
123
  }
124
 
125
+ .typing span {
126
+ width: 6px;
127
+ height: 6px;
128
+ border-radius: 50%;
129
+ background: #333;
130
+ display: inline-block;
131
+ animation: bounce 1s infinite ease-in-out;
132
  }
133
 
134
+ .typing span:nth-child(2) {
135
+ animation-delay: 0.15s;
 
136
  }
137
 
138
+ .typing span:nth-child(3) {
139
+ animation-delay: 0.30s;
 
 
 
 
140
  }
141
 
142
+ @keyframes bounce {
143
+ 0%, 80%, 100% {
144
+ transform: translateY(0);
145
+ opacity: 0.4;
146
+ }
147
+
148
+ 40% {
149
+ transform: translateY(-6px);
150
+ opacity: 1;
151
+ }
152
+ }
153
+
154
+ /* Enter animation */
155
+ @keyframes fadeIn {
156
+ from {
157
+ opacity: 0;
158
+ transform: translateY(10px);
159
+ }
160
+
161
+ to {
162
+ opacity: 1;
163
+ transform: translateY(0);
164
+ }
165
  }
src/app/chatbot/chatbot.service.ts ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Injectable } from '@angular/core';
2
+ import { HttpClient } from '@angular/common/http';
3
+ import { map, Observable } from 'rxjs';
4
+
5
+ @Injectable({
6
+ providedIn: 'root'
7
+ })
8
+ export class ChatBotService {
9
+
10
+ private readonly baseUrl =
11
+ location.hostname.endsWith('hf.space')
12
+ ? 'https://pykara-pytrade-backend.hf.space'
13
+ : 'http://127.0.0.1:5000';
14
+
15
+ private apiUrl = `${this.baseUrl}/chat`;
16
+ constructor(private http: HttpClient) { }
17
+
18
+ // Function to send a prompt to the Flask API and fetch the response
19
+ generateResponse(prompt: string): Observable<any> {
20
+ const body = { message: prompt }; // The prompt object sent to the API
21
+ return this.http.post<any>(this.apiUrl, body); // Sending POST request
22
+ }
23
+
24
+ }
src/app/chatbot/chatbot.ts CHANGED
@@ -1,64 +1,69 @@
 
 
1
  import { CommonModule } from '@angular/common';
2
- import { Component } from '@angular/core';
3
  import { FormsModule } from '@angular/forms';
4
- import axios from 'axios';
5
- import { FormBuilder, Validators } from '@angular/forms';
6
- import { LlamaService, GenerateResponse } from './llama.service';
7
- import { ReactiveFormsModule } from '@angular/forms';
8
 
 
9
 
10
  @Component({
11
  selector: 'app-chatbot',
12
  standalone: true,
13
- imports: [CommonModule,ReactiveFormsModule,FormsModule],
14
  templateUrl: './chatbot.html',
15
- styleUrl: './chatbot.scss'
16
  })
17
  export class Chatbot {
18
- isLoading = false;
19
- errorMsg = '';
20
- resultText = '';
21
- form: any;
22
-
23
 
24
- constructor(private fb: FormBuilder, private llama: LlamaService) {
25
- this.form = this.fb.group({
26
- prompt: ['', [Validators.required]],
27
- max_tokens: [256],
28
- temperature: [0.7],
29
- top_p: [0.95],
30
- repeat_penalty: [1.1]
31
- });
32
- }
33
 
34
- onGenerate() {
35
- this.errorMsg = '';
36
- this.resultText = '';
37
- if (this.form.invalid) {
38
- this.errorMsg = 'Please enter a prompt.';
39
- return;
40
- }
41
 
42
- this.isLoading = true;
 
 
43
 
44
- const body = {
45
- prompt: this.form.value.prompt ?? '',
46
- max_tokens: Number(this.form.value.max_tokens ?? 256),
47
- temperature: Number(this.form.value.temperature ?? 0.7),
48
- top_p: Number(this.form.value.top_p ?? 0.95),
49
- repeat_penalty: Number(this.form.value.repeat_penalty ?? 1.1),
50
- stop: ['[USER]'] // optional
51
- };
52
 
53
- this.llama.generate(body).subscribe({
54
- next: (res: GenerateResponse) => {
55
- this.resultText = res.output || '';
56
- this.isLoading = false;
 
 
 
 
 
 
 
 
57
  },
58
- error: (err: Error) => {
59
- this.errorMsg = err.message || 'Request failed';
60
- this.isLoading = false;
61
- }
62
  });
63
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
 
1
+ import { Component, ElementRef, ViewChild } from '@angular/core';
2
+ import { HttpClient } from '@angular/common/http';
3
  import { CommonModule } from '@angular/common';
4
+ import { HttpClientModule } from '@angular/common/http';
5
  import { FormsModule } from '@angular/forms';
6
+ import { ChatBotService } from './chatbot.service';
 
 
 
7
 
8
+ type ChatPair = { user: string; bot: string | null };
9
 
10
  @Component({
11
  selector: 'app-chatbot',
12
  standalone: true,
13
+ imports: [CommonModule, HttpClientModule, FormsModule],
14
  templateUrl: './chatbot.html',
15
+ styleUrls: ['./chatbot.scss'],
16
  })
17
  export class Chatbot {
18
+ @ViewChild('chatBox') chatBoxRef!: ElementRef<HTMLDivElement>;
 
 
 
 
19
 
20
+ question: string = '';
21
+ loading: boolean = false;
22
+ messages: ChatPair[] = [];
 
 
 
 
 
 
23
 
24
+ constructor(private chatService: ChatBotService) { }
 
 
 
 
 
 
25
 
26
+ askQuestion(): void {
27
+ const q = this.question.trim();
28
+ if (!q) return;
29
 
30
+ // push one pair: user + empty bot (will show typing dots)
31
+ this.messages.push({ user: q, bot: '' });
32
+ this.question = '';
33
+ this.loading = true;
34
+ this.scrollToBottomSoon();
 
 
 
35
 
36
+ this.chatService.generateResponse(q).subscribe({
37
+ next: (response) => {
38
+ const answer = response?.answer ?? 'No response received.';
39
+ this.messages[this.messages.length - 1].bot = answer;
40
+ this.loading = false;
41
+ this.scrollToBottomSoon();
42
+ },
43
+ error: () => {
44
+ this.messages[this.messages.length - 1].bot =
45
+ 'Error: Could not get a response from the server.';
46
+ this.loading = false;
47
+ this.scrollToBottomSoon();
48
  },
 
 
 
 
49
  });
50
  }
51
+
52
+ isLast(msg: ChatPair): boolean {
53
+ return this.messages.length > 0 && this.messages[this.messages.length - 1] === msg;
54
+ }
55
+
56
+ trackByIndex(index: number): number {
57
+ return index;
58
+ }
59
+
60
+ private scrollToBottomSoon() {
61
+ // Wait for DOM update
62
+ setTimeout(() => {
63
+ try {
64
+ const el = this.chatBoxRef?.nativeElement;
65
+ if (el) el.scrollTop = el.scrollHeight;
66
+ } catch { }
67
+ }, 0);
68
+ }
69
  }
src/app/chatbot/llama.service.ts DELETED
@@ -1,51 +0,0 @@
1
- // src/app/services/llama.service.ts
2
- import { Injectable } from '@angular/core';
3
- import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
4
-
5
- import { Observable, throwError } from 'rxjs';
6
- import { catchError } from 'rxjs/operators';
7
-
8
- export interface GenerateRequest {
9
- prompt: string;
10
- max_tokens?: number;
11
- temperature?: number;
12
- top_p?: number;
13
- repeat_penalty?: number;
14
- stop?: string[];
15
- system?: string;
16
- }
17
-
18
- export interface GenerateResponse {
19
- output: string;
20
- usage?: any;
21
- model?: string;
22
- params?: any;
23
- }
24
-
25
- @Injectable({ providedIn: 'root' })
26
- export class LlamaService {
27
- private base = "http://127.0.0.1:5000";
28
-
29
- constructor(private http: HttpClient) { }
30
-
31
- generate(body: GenerateRequest): Observable<GenerateResponse> {
32
- const url = `${this.base}/generate`;
33
- const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
34
- return this.http.post<GenerateResponse>(url, body, { headers })
35
- .pipe(catchError(this.handleError));
36
- }
37
-
38
- // Optional: Streaming with SSE (requires a streaming endpoint in Flask; see section 5)
39
- generateStream(prompt: string): EventSource {
40
- const url = `${this.base}/generate_stream?prompt=${encodeURIComponent(prompt)}`;
41
- const es = new EventSource(url);
42
- return es;
43
- }
44
-
45
- private handleError(err: HttpErrorResponse) {
46
- if (err.error instanceof ErrorEvent) {
47
- return throwError(() => new Error(`Client error: ${err.error.message}`));
48
- }
49
- return throwError(() => new Error(`Server error ${err.status}: ${err.message}`));
50
- }
51
- }