Added and compiled with playground

This commit is contained in:
Saifeddine ALOUI 2023-08-19 03:25:36 +02:00
parent c10621107a
commit a61b31d386
11 changed files with 336 additions and 91 deletions

View File

@ -507,6 +507,164 @@ class LoLLMsAPPI(LollmsApplication):
}, room=client_id
)
# A copy of the original lollms-server generation code needed for playground
@self.socketio.on('generate_text')
def handle_generate_text(data):
client_id = request.sid
ASCIIColors.info(f"Text generation requested by client: {client_id}")
if self.buzy:
emit("buzzy", {"message":"I am buzzy. Come back later."}, room=client_id)
self.socketio.sleep(0)
ASCIIColors.warning(f"OOps request {client_id} refused!! Server buzy")
return
def generate_text():
self.buzy = True
try:
model = self.model
self.connections[client_id]["is_generating"]=True
self.connections[client_id]["requested_stop"]=False
prompt = data['prompt']
personality_id = data['personality']
n_predicts = data["n_predicts"]
parameters = data.get("parameters",{
"temperature":self.config["temperature"],
"top_k":self.config["top_k"],
"top_p":self.config["top_p"],
"repeat_penalty":self.config["repeat_penalty"],
"repeat_last_n":self.config["repeat_last_n"],
"seed":self.config["seed"]
})
if personality_id==-1:
# Raw text generation
self.answer = {"full_text":""}
def callback(text, message_type: MSG_TYPE, metadata:dict={}):
if message_type == MSG_TYPE.MSG_TYPE_CHUNK:
ASCIIColors.success(f"generated:{len(self.answer['full_text'].split())} words", end='\r')
self.answer["full_text"] = self.answer["full_text"] + text
self.socketio.emit('text_chunk', {'chunk': text, 'type':MSG_TYPE.MSG_TYPE_CHUNK.value}, room=client_id)
self.socketio.sleep(0)
if client_id in self.connections:# Client disconnected
if self.connections[client_id]["requested_stop"]:
return False
else:
return True
else:
return False
tk = model.tokenize(prompt)
n_tokens = len(tk)
fd = model.detokenize(tk[-min(self.config.ctx_size-n_predicts,n_tokens):])
try:
ASCIIColors.print("warming up", ASCIIColors.color_bright_cyan)
generated_text = model.generate(fd,
n_predict=n_predicts,
callback=callback,
temperature = parameters["temperature"],
top_k = parameters["top_k"],
top_p = parameters["top_p"],
repeat_penalty = parameters["repeat_penalty"],
repeat_last_n = parameters["repeat_last_n"],
seed = parameters["seed"]
)
ASCIIColors.success(f"\ndone")
if client_id in self.connections:
if not self.connections[client_id]["requested_stop"]:
# Emit the generated text to the client
self.socketio.emit('text_generated', {'text': generated_text}, room=client_id)
self.socketio.sleep(0)
except Exception as ex:
self.socketio.emit('generation_error', {'error': str(ex)}, room=client_id)
ASCIIColors.error(f"\ndone")
self.buzy = False
else:
try:
personality: AIPersonality = self.personalities[personality_id]
ump = self.config.discussion_prompt_separator +self.config.user_name+": " if self.config.use_user_name_in_discussions else self.personality.user_message_prefix
personality.model = model
cond_tk = personality.model.tokenize(personality.personality_conditioning)
n_cond_tk = len(cond_tk)
# Placeholder code for text generation
# Replace this with your actual text generation logic
print(f"Text generation requested by client: {client_id}")
self.answer["full_text"] = ''
full_discussion_blocks = self.connections[client_id]["full_discussion_blocks"]
if prompt != '':
if personality.processor is not None and personality.processor_cfg["process_model_input"]:
preprocessed_prompt = personality.processor.process_model_input(prompt)
else:
preprocessed_prompt = prompt
if personality.processor is not None and personality.processor_cfg["custom_workflow"]:
full_discussion_blocks.append(ump)
full_discussion_blocks.append(preprocessed_prompt)
else:
full_discussion_blocks.append(ump)
full_discussion_blocks.append(preprocessed_prompt)
full_discussion_blocks.append(personality.link_text)
full_discussion_blocks.append(personality.ai_message_prefix)
full_discussion = personality.personality_conditioning + ''.join(full_discussion_blocks)
def callback(text, message_type: MSG_TYPE, metadata:dict={}):
if message_type == MSG_TYPE.MSG_TYPE_CHUNK:
self.answer["full_text"] = self.answer["full_text"] + text
self.socketio.emit('text_chunk', {'chunk': text}, room=client_id)
self.socketio.sleep(0)
try:
if self.connections[client_id]["requested_stop"]:
return False
else:
return True
except: # If the client is disconnected then we stop talking to it
return False
tk = personality.model.tokenize(full_discussion)
n_tokens = len(tk)
fd = personality.model.detokenize(tk[-min(self.config.ctx_size-n_cond_tk-personality.model_n_predicts,n_tokens):])
if personality.processor is not None and personality.processor_cfg["custom_workflow"]:
ASCIIColors.info("processing...")
generated_text = personality.processor.run_workflow(prompt, previous_discussion_text=personality.personality_conditioning+fd, callback=callback)
else:
ASCIIColors.info("generating...")
generated_text = personality.model.generate(
personality.personality_conditioning+fd,
n_predict=personality.model_n_predicts,
callback=callback)
if personality.processor is not None and personality.processor_cfg["process_model_output"]:
generated_text = personality.processor.process_model_output(generated_text)
full_discussion_blocks.append(generated_text.strip())
ASCIIColors.success("\ndone")
# Emit the generated text to the client
self.socketio.emit('text_generated', {'text': generated_text}, room=client_id)
self.socketio.sleep(0)
except Exception as ex:
self.socketio.emit('generation_error', {'error': str(ex)}, room=client_id)
ASCIIColors.error(f"\ndone")
self.buzy = False
except Exception as ex:
trace_exception(ex)
self.socketio.emit('generation_error', {'error': str(ex)}, room=client_id)
self.buzy = False
# Start the text generation task in a separate thread
task = self.socketio.start_background_task(target=generate_text)
@socketio.on('generate_msg')
def generate_msg(data):
client_id = request.sid

36
app.py
View File

@ -409,7 +409,41 @@ class LoLLMsWebUI(LoLLMsAPPI):
"/import_multiple_discussions", "import_multiple_discussions", self.import_multiple_discussions, methods=["POST"]
)
self.add_endpoint(
"/presets.json", "presets.json", self.get_presets, methods=["GET"]
)
self.add_endpoint(
"/save_presets", "save_presets", self.save_presets, methods=["POST"]
)
def get_presets(self):
presets_file = self.lollms_paths.personal_databases_path/"presets.json"
if not presets_file.exists():
shutil.copy("presets/presets.json",presets_file)
with open(presets_file) as f:
data = json.loads(f.read())
return jsonify(data)
def save_presets(self):
"""Saves a preset to a file.
Args:
None.
Returns:
None.
"""
# Get the JSON data from the POST request.
preset_data = request.get_json()
presets_file = self.lollms_paths.personal_databases_path/"presets.json"
# Save the JSON data to a file.
with open(presets_file, "w") as f:
json.dump(preset_data, f, indent=4)
return "Preset saved successfully!"
def export_multiple_discussions(self):
data = request.get_json()

7
presets/presets.json Normal file
View File

@ -0,0 +1,7 @@
{
"Writing a Book in Latex": "<Add some context information to give the AI some context about the book or leave blank if you have no specific idea>\n```latex\n\\documentclass[12pt]{book}\n\\usepackage{url}\n\\begin{document}\n\\title{<Put the title of the book here>}\n\\author{<Put the author name here>} % Author\n\\date{\\today} % Date\n\\maketitle\n\\tableofcontents\n\\chapter{Introduction}\n<Add any required text then press generate to push the AI to build your book>\n",
"Simple Book writing":"Once apon a time",
"Simple Question Answer":"User:<Put your question here>\nAssistant:",
"Question Answer with conditionning":"Assistant is a highly developed AI capable of answering any question about any subject.\nUser:<Put your question here>\nAssistant:",
"Instruct mode": "Instructions:\n<Put your instructions here>\nAnswer:"
}

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Copyright 2023 Saifeddine ALOUI (aka parisneo)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

8
web/dist/assets/index-edffcce0.css vendored Normal file

File diff suppressed because one or more lines are too long

4
web/dist/index.html vendored
View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI - Welcome</title>
<script type="module" crossorigin src="/assets/index-7801f2bd.js"></script>
<link rel="stylesheet" href="/assets/index-3e7ad0ad.css">
<script type="module" crossorigin src="/assets/index-76118a1a.js"></script>
<link rel="stylesheet" href="/assets/index-edffcce0.css">
</head>
<body>
<div id="app"></div>

View File

@ -7,6 +7,11 @@
Discussions
</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'playground' }" class="link-item dark:link-item-dark">
Playground
</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'settings' }" class="link-item dark:link-item-dark">
Settings

View File

@ -1,4 +1,5 @@
import { createRouter, createWebHistory } from 'vue-router'
import PlayGroundView from '../views/PlayGroundView.vue'
import ExtensionsView from '../views/ExtensionsView.vue'
import HelpView from '../views/HelpView.vue'
import SettingsView from '../views/SettingsView.vue'
@ -10,6 +11,11 @@ import DiscussionsView from '../views/DiscussionsView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/playground/',
name: 'playground',
component: PlayGroundView
},
{
path: '/extensions/',
name: 'extensions',

View File

@ -1,29 +1,32 @@
<template>
<div class="container mx-auto p-4 bg-gray-100 shadow-lg">
<div class="flex justify-between">
<div class="m-0">
<button id="generate-button" @click="generate" class="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white font-bold py-2 px-4 rounded ml-2">Generate Text</button>
<button v-if="!generating" id="stop-button" @click="stopGeneration" class="bg-red-500 hover:bg-red-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded hidden ml-2 ">Stop Generation</button>
<button v-else id="export-button" @click="exportText" class="bg-green-500 hover:bg-green-600 active:bg-green-700 text-white font-bold py-2 px-4 rounded ml-2">Export Text</button>
</div>
</div>
<div class="flex flex-row h-full">
<div class="flex-grow ml-2">
<div class="mt-4 d-flex justify-content-space-between flex-row">
<label class="mt-2">Presets</label>
<select v-model="selectedPreset" class="w-25 m-2">
<select v-model="selectedPreset" class="w-25 m-2 border-2 rounded-md shadow-sm">
<option v-for="preset in Object.keys(presets)" :key="preset" :value="preset">
{{ preset }}
</option>
</select>
<button class="bg-red-500 hover:bg-red-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2 " @click="setPreset">Use preset</button>
<button class="bg-green-500 hover:bg-green-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2 " @click="addPreset">Add preset</button>
<button class="bg-red-500 hover:bg-red-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2" @click="removePreset">Remove preset</button>
<button class="bg-red-500 hover:bg-red-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2" @click="removePreset">Save preset</button>
<button class="bg-green-500 hover:bg-green-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2 " @click="setPreset" title="Use preset"><i data-feather="check"></i></button>
<button class="bg-green-500 hover:bg-green-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2 " @click="addPreset" title="Add this text as a preset"><i data-feather="plus"></i></button>
<button class="bg-red-500 hover:bg-red-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2" @click="removePreset" title="Remove preset"><i data-feather="x"></i></button>
<button class="bg-green-500 hover:bg-green-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2" @click="savePreset" title="Save presets list"><i data-feather="save"></i></button>
<button class="bg-green-500 hover:bg-green-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2" @click="reloadPresets" title="Reload presets list"><i data-feather="refresh-ccw"></i></button>
</div>
<div class="flex-grow">
<textarea v-model="text" id="text_element" class="mt-4 p-2 border border-gray-300 rounded-md h-64 overflow-y-scroll w-full" type="text"></textarea>
</div>
<div class="flex justify-between">
<div class="m-0">
<button v-show="!generating" id="generate-button" @click="generate" class="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white font-bold py-2 px-4 rounded ml-2">Generate Text</button>
<button v-show="generating" id="stop-button" @click="stopGeneration" class="bg-red-500 hover:bg-red-600 active:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2 ">Stop Generation</button>
<button v-show="!generating" id="export-button" @click="exportText" class="bg-green-500 hover:bg-green-600 active:bg-green-700 text-white font-bold py-2 px-4 rounded ml-2">Export Text</button>
</div>
</div>
</div>
<div id="settings" class="border border-blue-300 bg-blue-200 mt-4 w-25 mr-2 h-full mb-10" style="align-items: center; height: fit-content; margin: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); border-radius: 4px;">
<div id="title" class="border border-blue-600 bg-blue-300 m-0" style="align-items: center; height: fit-content; margin: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); border-radius: 4px;">
@ -54,6 +57,12 @@
<input type="range" v-model="repeat_last_n" min="0" max="100" step="1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ repeat_last_n }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Number of tokens to generate</h3>
<input type="number" v-model="n_predicts" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ n_predicts }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Seed</h3>
<input type="number" v-model="seed" class="w-full">
@ -68,6 +77,8 @@
</template>
<script>
import feather from 'feather-icons'
import axios from "axios";
import socket from '@/services/websocket.js'
import Toast from '../components/Toast.vue'
@ -84,16 +95,25 @@ export default {
top_p: 0.9,
repeat_penalty: 1.3,
repeat_last_n: 50,
n_predicts: 2000,
seed: -1,
};
},
components:{
Toast,
},
mounted() {
//console.log('chatbox mnt',this.$refs)
this.$nextTick(() => {
feather.replace();
});
},
created(){
axios.get('./presets.json').then(response => {
console.log(response.data)
this.presets=response.data
}).catch(ex=>{
this.$refs.toast.showToast(`Error: ${ex}`,4,false)
});
// Event handler for receiving generated text chunks
socket.on('text_chunk', data => {
@ -149,7 +169,7 @@ export default {
var prompt = this.text
console.log(prompt)
// Trigger the 'generate_text' event with the prompt
socket.emit('generate_text', { prompt: prompt, personality: -1, n_predicts: 1024 ,
socket.emit('generate_text', { prompt: prompt, personality: -1, n_predicts: this.n_predicts ,
parameters: {
temperature: this.temperature,
top_k: this.top_k,
@ -167,7 +187,14 @@ export default {
socket.emit('cancel_generation',{});
},
exportText(){
const textToExport = this.text;
const element = document.createElement('a');
const file = new Blob([textToExport], {type: 'text/plain'});
element.href = URL.createObjectURL(file);
element.download = 'exported_text.txt';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
},
setPreset() {
this.text = this.presets[this.selectedPreset];
@ -182,11 +209,19 @@ export default {
}
},
savePreset() {
axios.post("/save_preset", presets).then((response) => {
axios.post("/save_presets", this.presets).then((response) => {
console.log(response);
this.$refs.toast.showToast(`Preset saved`,4,true)
this.$refs.toast.showToast(`Presets saved`,4,true)
});
}
},
reloadPresets() {
axios.get('./presets.json').then(response => {
console.log(response.data)
this.presets=response.data
}).catch(ex=>{
this.$refs.toast.showToast(`Error: ${ex}`,4,false)
});
},
}
};
</script>