Spaces:
Running
Running
Oviya
commited on
Commit
·
678e6ea
1
Parent(s):
4a26147
update chatbot
Browse files- public/user.png +3 -0
- src/app/chatbot/chatbot.html +35 -33
- src/app/chatbot/chatbot.scss +140 -49
- src/app/chatbot/chatbot.service.ts +24 -0
- src/app/chatbot/chatbot.ts +50 -45
- src/app/chatbot/llama.service.ts +0 -51
public/user.png
ADDED
|
Git LFS Details
|
src/app/chatbot/chatbot.html
CHANGED
|
@@ -1,39 +1,41 @@
|
|
| 1 |
-
|
| 2 |
-
<div class="
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 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 |
-
<
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 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 |
-
/*
|
| 2 |
-
.
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 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 |
-
|
|
|
|
| 13 |
display: flex;
|
| 14 |
flex-direction: column;
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
}
|
| 17 |
|
| 18 |
-
.
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
| 22 |
}
|
| 23 |
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
border-radius: 8px;
|
| 29 |
-
padding: 10px;
|
| 30 |
}
|
| 31 |
|
| 32 |
-
.
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
| 37 |
}
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
border: none;
|
| 43 |
-
|
| 44 |
-
background: #a6ff00; /* subtle neon green accent */
|
| 45 |
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
}
|
| 47 |
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
| 51 |
}
|
| 52 |
|
| 53 |
-
.
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
}
|
| 57 |
|
| 58 |
-
.
|
| 59 |
-
|
| 60 |
-
color: #ff8080;
|
| 61 |
}
|
| 62 |
|
| 63 |
-
.
|
| 64 |
-
|
| 65 |
-
background: #0d0d0d;
|
| 66 |
-
border: 1px solid #242424;
|
| 67 |
-
border-radius: 8px;
|
| 68 |
-
padding: 12px;
|
| 69 |
}
|
| 70 |
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 {
|
| 3 |
import { FormsModule } from '@angular/forms';
|
| 4 |
-
import
|
| 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,
|
| 14 |
templateUrl: './chatbot.html',
|
| 15 |
-
|
| 16 |
})
|
| 17 |
export class Chatbot {
|
| 18 |
-
|
| 19 |
-
errorMsg = '';
|
| 20 |
-
resultText = '';
|
| 21 |
-
form: any;
|
| 22 |
-
|
| 23 |
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
max_tokens: [256],
|
| 28 |
-
temperature: [0.7],
|
| 29 |
-
top_p: [0.95],
|
| 30 |
-
repeat_penalty: [1.1]
|
| 31 |
-
});
|
| 32 |
-
}
|
| 33 |
|
| 34 |
-
|
| 35 |
-
this.errorMsg = '';
|
| 36 |
-
this.resultText = '';
|
| 37 |
-
if (this.form.invalid) {
|
| 38 |
-
this.errorMsg = 'Please enter a prompt.';
|
| 39 |
-
return;
|
| 40 |
-
}
|
| 41 |
|
| 42 |
-
|
|
|
|
|
|
|
| 43 |
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
repeat_penalty: Number(this.form.value.repeat_penalty ?? 1.1),
|
| 50 |
-
stop: ['[USER]'] // optional
|
| 51 |
-
};
|
| 52 |
|
| 53 |
-
this.
|
| 54 |
-
next: (
|
| 55 |
-
|
| 56 |
-
this.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|