Spaces:
Running
Running
Oviya
commited on
Commit
·
0044218
1
Parent(s):
53384db
update toolspage
Browse files- src/app/chatbot/chatbot.html +36 -7
- src/app/chatbot/chatbot.scss +48 -107
- src/app/chatbot/chatbot.ts +44 -35
- src/app/chatbot/llama.service.ts +51 -0
- src/app/toolspage/toolspage.component.ts +1 -0
src/app/chatbot/chatbot.html
CHANGED
|
@@ -1,10 +1,39 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
</div>
|
| 8 |
-
<input [(ngModel)]="userQuestion" placeholder="Ask a question..." />
|
| 9 |
-
<button (click)="getChatbotResponse()">Ask</button>
|
| 10 |
</div>
|
|
|
|
| 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>
|
src/app/chatbot/chatbot.scss
CHANGED
|
@@ -1,133 +1,74 @@
|
|
| 1 |
-
/*
|
| 2 |
-
.
|
| 3 |
-
max-width:
|
| 4 |
-
margin:
|
| 5 |
-
padding:
|
| 6 |
-
border-radius:
|
| 7 |
-
background
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
font-family: 'Arial', sans-serif;
|
| 11 |
}
|
| 12 |
|
| 13 |
-
|
| 14 |
-
.chatbox {
|
| 15 |
-
max-height: 300px;
|
| 16 |
-
overflow-y: auto;
|
| 17 |
-
margin-bottom: 20px;
|
| 18 |
-
padding-right: 10px;
|
| 19 |
-
border-bottom: 2px solid #dcdfe6;
|
| 20 |
-
padding-left: 15px;
|
| 21 |
-
background: #fff;
|
| 22 |
-
border-radius: 10px;
|
| 23 |
-
}
|
| 24 |
-
|
| 25 |
-
/* Individual Message Styling */
|
| 26 |
-
.message {
|
| 27 |
-
margin-bottom: 15px;
|
| 28 |
display: flex;
|
| 29 |
flex-direction: column;
|
| 30 |
-
|
| 31 |
}
|
| 32 |
|
| 33 |
-
.
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
margin-bottom: 5px;
|
| 38 |
-
max-width: 80%;
|
| 39 |
-
align-self: flex-start;
|
| 40 |
-
font-size: 14px;
|
| 41 |
-
color: #00796b;
|
| 42 |
-
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
| 43 |
-
animation: fadeIn 0.5s ease;
|
| 44 |
}
|
| 45 |
|
| 46 |
-
|
| 47 |
-
background
|
| 48 |
-
|
| 49 |
-
border
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
font-size: 14px;
|
| 53 |
-
color: #388e3c;
|
| 54 |
-
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
| 55 |
-
animation: fadeIn 0.5s ease;
|
| 56 |
}
|
| 57 |
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
border-radius: 25px;
|
| 64 |
-
border: 1px solid #ccc;
|
| 65 |
-
margin-right: 10px;
|
| 66 |
-
background-color: #ffffff;
|
| 67 |
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
| 68 |
}
|
| 69 |
|
| 70 |
button {
|
| 71 |
-
padding:
|
| 72 |
-
|
| 73 |
-
background-color: #00796b;
|
| 74 |
-
color: white;
|
| 75 |
border: none;
|
| 76 |
-
|
|
|
|
| 77 |
cursor: pointer;
|
| 78 |
-
transition: all 0.3s;
|
| 79 |
}
|
| 80 |
|
| 81 |
-
button
|
| 82 |
-
|
| 83 |
-
|
| 84 |
}
|
| 85 |
|
| 86 |
-
|
| 87 |
-
|
|
|
|
| 88 |
}
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
}
|
| 94 |
|
| 95 |
-
.
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
background-color: #f4f7fc;
|
| 102 |
-
}
|
| 103 |
-
|
| 104 |
-
/* Loading Spinner */
|
| 105 |
-
.loader {
|
| 106 |
-
border: 4px solid #f3f3f3;
|
| 107 |
-
border-top: 4px solid #00796b;
|
| 108 |
-
border-radius: 50%;
|
| 109 |
-
width: 24px;
|
| 110 |
-
height: 24px;
|
| 111 |
-
animation: spin 1s linear infinite;
|
| 112 |
-
margin: 0 auto;
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
@keyframes spin {
|
| 116 |
-
0% {
|
| 117 |
-
transform: rotate(0deg);
|
| 118 |
-
}
|
| 119 |
-
|
| 120 |
-
100% {
|
| 121 |
-
transform: rotate(360deg);
|
| 122 |
-
}
|
| 123 |
}
|
| 124 |
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
}
|
| 129 |
-
|
| 130 |
-
100% {
|
| 131 |
-
opacity: 1;
|
| 132 |
-
}
|
| 133 |
}
|
|
|
|
| 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 |
}
|
src/app/chatbot/chatbot.ts
CHANGED
|
@@ -2,54 +2,63 @@ import { CommonModule } from '@angular/common';
|
|
| 2 |
import { Component } from '@angular/core';
|
| 3 |
import { FormsModule } from '@angular/forms';
|
| 4 |
import axios from 'axios';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
@Component({
|
| 7 |
selector: 'app-chatbot',
|
| 8 |
standalone: true,
|
| 9 |
-
imports: [FormsModule],
|
| 10 |
templateUrl: './chatbot.html',
|
| 11 |
styleUrl: './chatbot.scss'
|
| 12 |
})
|
| 13 |
export class Chatbot {
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
private readonly baseUrl =
|
| 21 |
-
location.hostname.endsWith('hf.space')
|
| 22 |
-
? 'https://pykara-pytrade-backend.hf.space'
|
| 23 |
-
: 'http://127.0.0.1:5000'; // change to 5400 if your local backend uses that port
|
| 24 |
-
|
| 25 |
-
// Handle user input and make API call to backend
|
| 26 |
-
async getChatbotResponse() {
|
| 27 |
-
if (this.userQuestion.trim()) {
|
| 28 |
-
// Add user's question to the messages array
|
| 29 |
-
this.messages.push({ user: this.userQuestion, bot: '...' });
|
| 30 |
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
-
|
| 42 |
-
this.messages[this.messages.length - 1].bot = this.chatbotAnswer;
|
| 43 |
|
| 44 |
-
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
this.
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
| 52 |
}
|
| 53 |
-
}
|
| 54 |
}
|
| 55 |
}
|
|
|
|
| 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 |
}
|
src/app/chatbot/llama.service.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
}
|
src/app/toolspage/toolspage.component.ts
CHANGED
|
@@ -156,6 +156,7 @@ export class ToolspageComponent {
|
|
| 156 |
);
|
| 157 |
})
|
| 158 |
);
|
|
|
|
| 159 |
}
|
| 160 |
|
| 161 |
// ---------- Search selection ----------
|
|
|
|
| 156 |
);
|
| 157 |
})
|
| 158 |
);
|
| 159 |
+
console.log(this.filteredCompanies$);
|
| 160 |
}
|
| 161 |
|
| 162 |
// ---------- Search selection ----------
|