|
from fastapi import FastAPI |
|
from pydantic import BaseModel |
|
import gradio as gr |
|
import uvicorn |
|
from fastapi.middleware.cors import CORSMiddleware |
|
import threading |
|
|
|
app = FastAPI() |
|
|
|
|
|
app.add_middleware( |
|
CORSMiddleware, |
|
allow_origins=["*"], |
|
allow_credentials=True, |
|
allow_methods=["*"], |
|
allow_headers=["*"], |
|
|
|
) |
|
|
|
class Item(BaseModel): |
|
prompt: str |
|
zeitstempel: int |
|
|
|
@app.post("/items/") |
|
async def create_item(item: Item): |
|
global prompt |
|
prompt = item.prompt |
|
zeitstempel = item.zeitstempel |
|
return {"prompt": prompt} |
|
|
|
|
|
prompt = "" |
|
|
|
def get_prompt(prompt): |
|
return prompt |
|
|
|
|
|
def show_html(): |
|
return """<!DOCTYPE html> |
|
<html lang="de"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> |
|
<meta http-equiv="cache-control" content="no-cache"> |
|
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Roboto+Slab:400,700|Material+Icons" /> |
|
<link rel="icon" type="image/vnd.microsoft.icon" href="favicon.ico"> |
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway"> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"> |
|
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3pro.css"> |
|
<link rel="stylesheet" href="style.css"> |
|
<script type="module" src="https://md-block.verou.me/md-block.js"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> |
|
|
|
<title>Chatbot-Interface</title> |
|
<style> |
|
body { |
|
background-color: #121212; |
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
height: 100vh; |
|
margin: 0; |
|
display: flex; |
|
flex-direction: column; |
|
justify-content: space-between; |
|
} |
|
.chatbot-container { |
|
width: 380px; |
|
flex: 1; |
|
display: flex; |
|
flex-direction: column; |
|
background-color: black; |
|
padding: 10px; |
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); |
|
margin-bottom: 10px; |
|
border-radius: 25px; |
|
border: 2px solid #121212; |
|
} |
|
.chatbot-header { |
|
background-color: black; |
|
padding: 10px; |
|
border-bottom: 1px solid #666; |
|
} |
|
.chatbot-header h1 { |
|
color: #fff; |
|
margin: 0; |
|
} |
|
.chatbot-messages { |
|
padding: 10px; |
|
flex: 1; |
|
overflow-y: auto; |
|
} |
|
#messages { |
|
list-style: none; |
|
padding: 0; |
|
margin: 0; |
|
} |
|
#messages li { |
|
padding: 10px; |
|
border-bottom: 1px solid #161616; |
|
background-color: #161616; |
|
color: white; |
|
} |
|
#messages li:last-child { |
|
border-bottom: none; |
|
} |
|
.chatbot-input { |
|
padding: 10px; |
|
background-color: #121212; |
|
border-radius: 15px; |
|
position: sticky; |
|
bottom: 0; |
|
z-index: 10; |
|
} |
|
.btn { |
|
color: white; |
|
width: 50px; |
|
height: 50px; |
|
background: #121212; |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
float: right; |
|
box-shadow: var(--box-shadow); |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
} |
|
.btn:hover { |
|
background: #444; |
|
} |
|
#input { |
|
width: 100%; |
|
height: 60px; |
|
padding: 15px; |
|
font-size: 16px; |
|
border: none; |
|
border-radius: 5px; |
|
background-color: #282828; |
|
color: white; |
|
} |
|
#senden { |
|
width: 20%; |
|
height: 30px; |
|
padding: 0px; |
|
font-size: 16px; |
|
border: none; |
|
background-color: #484848; |
|
color: #fff; |
|
cursor: pointer; |
|
border-bottom: 1px solid #666; |
|
float: right; |
|
} |
|
#senden:hover { |
|
background-color: #666; |
|
} |
|
.icon-wrapper { |
|
width: 50px; |
|
height: 50px; |
|
background: var(--background-color); |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
position: relative; |
|
box-shadow: var(--box-shadow); |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
} |
|
#appleImage { |
|
display: none; |
|
} |
|
.search-bar { |
|
display: flex; |
|
align-items: center; |
|
background-color: #282828; |
|
padding: 10px 20px; |
|
width: 100%; |
|
border-radius: 25px; |
|
} |
|
.search-bar textarea { |
|
width: 100%; |
|
border: none; |
|
background-color: #121212; |
|
color: white; |
|
outline: none; |
|
flex: 1; |
|
font-size: 18px; |
|
} |
|
.search-bar textarea::placeholder { |
|
color: white; |
|
} |
|
.search-bar .icon { |
|
background-color: #282828; |
|
color: white; |
|
font-size: 30px; |
|
float: right; |
|
} |
|
.search-bar .icon:hover { |
|
background: #444; |
|
} |
|
.search-bar .microphone { |
|
background-color: #282828; |
|
color: white; |
|
font-size: 30px; |
|
padding-right: 10px; |
|
float: left; |
|
} |
|
.search-bar .speaker { |
|
background-color: #282828; |
|
color: white; |
|
font-size: 30px; |
|
float: left; |
|
} |
|
.search-bar .speaker:hover { |
|
background: #444; |
|
} |
|
.container { |
|
display: flex; |
|
gap: 50px; |
|
} |
|
img { |
|
object-fit: cover; |
|
} |
|
button { |
|
background-color: var(--background-color); |
|
border: none; |
|
padding: 10px 20px; |
|
font-size: 1em; |
|
color: var(--heart-color); |
|
cursor: pointer; |
|
box-shadow: var(--box-shadow); |
|
transition: all 0.3s ease-in-out; |
|
} |
|
.switch { |
|
position: relative; |
|
display: inline-block; |
|
width: 60px; |
|
height: 34px; |
|
} |
|
.switch input { |
|
opacity: 0; |
|
width: 0; |
|
height: 0; |
|
} |
|
.slider { |
|
position: absolute; |
|
cursor: pointer; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background-color: grey; |
|
-webkit-transition: .4s; |
|
transition: .4s; |
|
} |
|
.slider:before { |
|
position: absolute; |
|
content: ""; |
|
height: 26px; |
|
width: 26px; |
|
left: 4px; |
|
bottom: 4px; |
|
background-color: white; |
|
-webkit-transition: .4s; |
|
transition: .4s; |
|
} |
|
input:checked + .slider { |
|
background-color: orange; |
|
} |
|
input:focus + .slider { |
|
box-shadow: 0 0 1px #2196F3; |
|
} |
|
input:checked + .slider:before { |
|
-webkit-transform: translateX(26px); |
|
-ms-transform: translateX(26px); |
|
transform: translateX(26px); |
|
} |
|
.slider.round { |
|
border-radius: 34px; |
|
} |
|
.slider.round:before { |
|
border-radius: 50%; |
|
} |
|
input[type="range"] { |
|
-webkit-appearance: none; |
|
width: 100%; |
|
height: 8px; |
|
background: #ddd; |
|
outline: none; |
|
opacity: 0.7; |
|
-webkit-transition: .2s; |
|
transition: opacity .2s; |
|
} |
|
input[type="range"]::-webkit-slider-thumb { |
|
-webkit-appearance: none; |
|
appearance: none; |
|
width: 25px; |
|
height: 25px; |
|
background: grey; |
|
cursor: pointer; |
|
border-radius: 50%; |
|
} |
|
input[type="range"]::-moz-range-thumb { |
|
width: 25px; |
|
height: 25px; |
|
background: grey; |
|
cursor: pointer; |
|
border-radius: 50%; |
|
} |
|
.textborder { |
|
color: #383838; |
|
padding: 5px; |
|
display: inline-block; |
|
} |
|
.text-outline { |
|
font-size: 70px; |
|
color: grey; |
|
text-shadow: -3px -1px 0 #e08341; |
|
} |
|
</style> |
|
<style> |
|
#results-container { |
|
display:none; |
|
} |
|
</style> |
|
<script> |
|
/* |
|
if (window.innerWidth <= 800) { // Überprüft die Breite des Bildschirms |
|
window.location.href = "https://specialist-it.de/chatbot/mobile/"; // Leitet auf die mobile Version um |
|
} |
|
*/ |
|
</script> |
|
</head> |
|
<body style="background-color:#121212;color:white"> |
|
<br> |
|
<div class="w3-third"> |
|
<div class="chatbot-container" style="margin-top: 0px; margin-left: 0px;"> |
|
<div class="chatbot-header" style="padding-right: 10px"> |
|
<div class="w3-cell-row" style=""> |
|
<div class="w3-cell " style=""> |
|
<h1>Voicebot</h1> |
|
</div> |
|
<div class="w3-cell " style="color: white; background-color: black; float:right"> |
|
<center><img id="appleImage" src="apple.gif" alt="Apple" style="width: 100px;"></center> |
|
</div> |
|
</div> |
|
|
|
</div> |
|
<div class="chatbot-messages"> |
|
<center> <img id="ava" src="ava.png" style="width: 280px;"></center> |
|
|
|
<div class="w3-cell-row" style="padding-left: 10px"> |
|
<div class="w3-cell w3-cell-bottom"> |
|
<div id="markdown" style="color:white; margin-left:0px"><b></b></div> |
|
</div> |
|
<div class="w3-cell w3-cell-top" style="color: white; background-color: black; padding: 8px; border-radius: 8px;height:"> |
|
|
|
</div> |
|
</div> |
|
|
|
<div class="w3-card-4 w3-container" style="width: 300px; border-radius:10px; margin-left:0px;"> |
|
<div class="w3-cell-row"> |
|
<div class="w3-cell"> |
|
<p><label for="language-select" style="color: white;">Sprache:</label></p> |
|
<select id="language-select" style="width: 280px;"> |
|
<option value="de-DE">Deutsch</option> |
|
<option value="en-US">Englisch (USA)</option> |
|
<option value="fr-FR">Französisch</option> |
|
<option value="it-IT">Italienisch</option> |
|
</select> |
|
</div> |
|
</div> |
|
<div class="w3-cell-row"> |
|
<div class="w3-cell"> |
|
<p><label for="voice-select" style="color: white; margin-left:0px">Stimme:</label></p> |
|
<select id="voice-select" style="width: 280px; margin-left:0px"></select> |
|
</div> |
|
</div> |
|
<div class="w3-cell-row"> |
|
<div class="w3-cell w3-cell-top"> |
|
<p><label style="color:white" for="rate-slider">Speaking Rate:</label></p> |
|
<input style="background-color: orange;" type="range" id="rate-slider" min="0.7" max="1.3" step="0.1" value="1"> |
|
</div> |
|
<div class="w3-cell" style="padding-left:40px"> |
|
<p><label for="pitch" style="color: white">Websuche</label></p> |
|
<label class="switch"> |
|
<input style="padding-left:20px" class="w3-right" type="checkbox" id="pitch" checked> |
|
<span class="slider round"></span> |
|
</label> |
|
</div> |
|
</div> |
|
<br> |
|
</div> |
|
</div> |
|
<div class="chatbot-input" style="background:black;"> |
|
<div class="search-bar" style="width: 100%;"> |
|
<button id="recording" class="microphone btn">🎤</button> |
|
<button id="stop" class="speaker btn">🔊</button> |
|
<textarea id="input" rows="2" placeholder=" ask anything..."></textarea> |
|
<button id="senden" class="icon " style="width:50px;height: 50px;border-radius:15px">⏎</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="w3-container w3-twothird" style="font-size:24px; padding:20px"> |
|
<md-block> |
|
<ul class="" id="messages" style="background:; color:white; height:600px; padding:20px"> |
|
<code><pre> |
|
|
|
</pre></code> |
|
</ul> |
|
</md-block> |
|
</div> |
|
|
|
<div id="results-container"> |
|
<!-- Hier werden die Suchergebnisse angezeigt --> |
|
<gcse:searchresults-only></gcse:searchresults-only> |
|
</div> |
|
|
|
|
|
<script async src="https://cse.google.com/cse.js?cx=77f1602c0ff764edb"></script> |
|
<script> |
|
const submitButton = document.getElementById('senden'); |
|
const promptInput = document.getElementById('input'); |
|
const messages = document.getElementById('messages'); |
|
const recording = document.getElementById('recording'); |
|
const stop = document.getElementById('stop'); |
|
const input = document.getElementById('input'); |
|
const toggle = document.getElementById('pitch'); |
|
const apple = document.getElementById('apple'); |
|
let recognition; |
|
let x = ""; |
|
const languageSelect = document.getElementById('language-select'); |
|
const voiceSelect = document.getElementById('voice-select'); |
|
let voices = []; |
|
let speech = new SpeechSynthesisUtterance(); |
|
|
|
submitButton.addEventListener('click', async () => { |
|
if (toggle.checked) { |
|
const prompt = promptInput.value; |
|
const result = await performSearch(prompt); |
|
chat(result); |
|
speak(result); |
|
} else { |
|
chat(promptInput.value); |
|
} |
|
}); |
|
|
|
recording.addEventListener('click', async () => { |
|
start(); |
|
}); |
|
|
|
stop.addEventListener('click', () => { |
|
window.speechSynthesis.cancel(); |
|
document.getElementById("appleImage").style.display = 'none'; |
|
}); |
|
|
|
function sendRequest(json) { |
|
const url = 'https://api.groq.com/openai/v1/chat/completions'; |
|
const options = { |
|
method: 'POST', |
|
headers: { |
|
'Authorization': 'Bearer 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', |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
messages: [{ role: 'user', content: json }], |
|
model: 'llama3-70b-8192' |
|
}) |
|
}; |
|
|
|
return fetch(url, options) |
|
.then(response => response.json()) |
|
.then(data => { |
|
const responseText = data.choices[0].message.content; |
|
return responseText.replace(/\*/g, ""); |
|
}) |
|
.catch(error => console.error('Error:', error)); |
|
} |
|
|
|
function performSearch(prompt) { |
|
const searchTerm = prompt; |
|
if (searchTerm.trim() === '') { |
|
return ''; // Return empty string for empty search |
|
} |
|
|
|
const cx = '77f1602c0ff764edb'; |
|
const gcse = google.search.cse.element.getElement('searchresults-only0'); |
|
gcse.execute(searchTerm); |
|
|
|
return new Promise((resolve) => { |
|
setTimeout(() => { |
|
const result = document.getElementById('___gcse_0').innerText; |
|
const searchQuery = `${prompt} antworte kurz und knapp. antworte auf deutsch. du findest die antwort hier: ${result}`; |
|
sendRequest(searchQuery).then(resolve); |
|
}, 2000); // Adjust timeout as needed |
|
}); |
|
} |
|
|
|
function initSpeechRecognition() { |
|
recognition = new webkitSpeechRecognition(); |
|
recognition.continuous = false; |
|
recognition.interimResults = false; |
|
recognition.lang = languageSelect.value || "de-DE"; |
|
} |
|
|
|
function populateVoiceSelect(selectedLang) { |
|
let langFilter = selectedLang || 'de-DE'; |
|
voices = speechSynthesis.getVoices().filter(voice => voice.lang === langFilter); |
|
voiceSelect.innerHTML = ''; |
|
voices.forEach(voice => { |
|
const option = document.createElement('option'); |
|
option.value = voice.name; |
|
option.textContent = voice.name + ' (' + voice.lang + ')'; |
|
voiceSelect.appendChild(option); |
|
}); |
|
if (voices.length > 0) { |
|
voiceSelect.value = voices[0].name; |
|
speech.voice = voices[0]; |
|
} |
|
} |
|
|
|
languageSelect.addEventListener('change', function() { |
|
const selectedLang = languageSelect.value; |
|
if (recognition) { |
|
recognition.lang = selectedLang; |
|
} |
|
speech.lang = selectedLang; |
|
populateVoiceSelect(selectedLang); |
|
}); |
|
|
|
voiceSelect.addEventListener('change', function() { |
|
const selectedVoice = voiceSelect.value; |
|
speech.voice = voices.find(voice => voice.name === selectedVoice); |
|
}); |
|
|
|
speechSynthesis.onvoiceschanged = function() { |
|
populateVoiceSelect(languageSelect.value || 'de-DE'); |
|
}; |
|
|
|
// Initial population |
|
populateVoiceSelect(languageSelect.value || 'de-DE'); |
|
initSpeechRecognition(); |
|
|
|
async function start() { |
|
if (!recognition) { |
|
initSpeechRecognition(); |
|
} |
|
|
|
recognition.onresult = async function (event) { |
|
for (let i = 0; i < event.results.length; i++) { |
|
x = event.results[i][0].transcript; |
|
if (toggle.checked) { |
|
const result = await performSearch(x); |
|
chat(result); |
|
speak(result); |
|
} else { |
|
chat(x); |
|
} |
|
} |
|
} |
|
recognition.start(); |
|
} |
|
|
|
let assist = '<div class="w3-cell-row" style="padding-left: 30px"><div class="w3-cell"><img src="mia.png"></img></div><div class="w3-cell"><h4>Ich bin ein hilfsbereiter KI Assistent. Wie kann ich ihnen helfen?</h4></div></div>'; |
|
|
|
function chat(response) { |
|
const ul = document.getElementById("messages"); |
|
ul.innerHTML = ""; // Clear previous messages |
|
const li = document.createElement("li"); |
|
const div = document.createElement("div"); |
|
div.innerHTML = "<md-block>" + response + "</md-block>"; |
|
li.appendChild(div); |
|
ul.appendChild(li); |
|
} |
|
|
|
function speak(texte) { |
|
speech.text = texte; |
|
speech.lang = languageSelect.value || "de-DE"; |
|
window.speechSynthesis.speak(speech); |
|
document.getElementById("appleImage").style.display = 'block'; |
|
speech.onend = function() { |
|
document.getElementById("appleImage").style.display = 'none'; |
|
}; |
|
console.log(texte); |
|
} |
|
</script> |
|
</body> |
|
</html> |
|
""" |
|
|
|
with gr.Blocks() as demo: |
|
gr.HTML(show_html) |
|
with gr.Row(): |
|
|
|
details_output = gr.Textbox(label="Ausgabe") |
|
with gr.Row(): |
|
ort_input = gr.Textbox(label="", placeholder="ask anything...") |
|
with gr.Row(): |
|
button = gr.Button("Senden") |
|
|
|
|
|
button.click(fn=get_prompt, inputs=ort_input, outputs=details_output) |
|
|
|
|
|
demo.launch() |
|
|
|
|
|
@app.get("/") |
|
def read_root(): |
|
return {"message": "Willkommen am Root-Endpunkt."} |
|
|
|
if __name__ == "__main__": |
|
|
|
threading.Thread(target=start_gradio).start() |
|
uvicorn.run(app, host="0.0.0.0", port=8000) |
|
|