mirror of
https://github.com/xtekky/gpt4free.git
synced 2024-09-19 04:37:48 +03:00
Add DuckDuckGo Provider, Add SpeechRecognition to gui
This commit is contained in:
parent
926ddfd543
commit
24345bc07b
64
g4f/Provider/DuckDuckGo.py
Normal file
64
g4f/Provider/DuckDuckGo.py
Normal file
@ -0,0 +1,64 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import aiohttp
|
||||
|
||||
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
||||
from ..typing import AsyncResult, Messages
|
||||
from ..requests.raise_for_status import raise_for_status
|
||||
|
||||
class DuckDuckGo(AsyncGeneratorProvider, ProviderModelMixin):
|
||||
url = "https://duckduckgo.com/duckchat"
|
||||
working = True
|
||||
supports_gpt_35_turbo = True
|
||||
supports_message_history = True
|
||||
|
||||
default_model = "gpt-3.5-turbo-0125"
|
||||
models = ["gpt-3.5-turbo-0125", "claude-instant-1.2"]
|
||||
model_aliases = {"gpt-3.5-turbo": "gpt-3.5-turbo-0125"}
|
||||
|
||||
status_url = "https://duckduckgo.com/duckchat/v1/status"
|
||||
chat_url = "https://duckduckgo.com/duckchat/v1/chat"
|
||||
user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0'
|
||||
headers = {
|
||||
'User-Agent': user_agent,
|
||||
'Accept': 'text/event-stream',
|
||||
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Referer': 'https://duckduckgo.com/',
|
||||
'Content-Type': 'application/json',
|
||||
'Origin': 'https://duckduckgo.com',
|
||||
'Connection': 'keep-alive',
|
||||
'Cookie': 'dcm=1',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'Pragma': 'no-cache',
|
||||
'TE': 'trailers'
|
||||
}
|
||||
|
||||
@classmethod
|
||||
async def create_async_generator(
|
||||
cls,
|
||||
model: str,
|
||||
messages: Messages,
|
||||
**kwargs
|
||||
) -> AsyncResult:
|
||||
async with aiohttp.ClientSession(headers=cls.headers) as session:
|
||||
async with session.get(cls.status_url, headers={"x-vqd-accept": "1"}) as response:
|
||||
await raise_for_status(response)
|
||||
vqd_4 = response.headers.get("x-vqd-4")
|
||||
payload = {
|
||||
'model': cls.get_model(model),
|
||||
'messages': messages
|
||||
}
|
||||
async with session.post(cls.chat_url, json=payload, headers={"x-vqd-4": vqd_4}) as response:
|
||||
await raise_for_status(response)
|
||||
async for line in response.content:
|
||||
if line.startswith(b"data: "):
|
||||
chunk = line[6:]
|
||||
if chunk.startswith(b"[DONE]"):
|
||||
break
|
||||
data = json.loads(chunk)
|
||||
if "message" in data:
|
||||
yield data["message"]
|
@ -49,7 +49,7 @@
|
||||
<body>
|
||||
<div class="gradient"></div>
|
||||
<div class="row">
|
||||
<div class="box conversations hidden">
|
||||
<div class="box conversations">
|
||||
<div class="top">
|
||||
<button class="new_convo" onclick="new_conversation()">
|
||||
<i class="fa-regular fa-plus"></i>
|
||||
@ -61,9 +61,14 @@
|
||||
<i class="fa-solid fa-toolbox"></i>
|
||||
<span>Open Settings</span>
|
||||
</button>
|
||||
<div class="info">
|
||||
<i class="fa-brands fa-discord"></i>
|
||||
<span class="convo-title">discord ~ <a href="https://discord.gg/XfybzPXPH5">discord.gg/XfybzPXPH5</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<i class="fa-brands fa-github"></i>
|
||||
<span class="convo-title">github ~ <a href="https://github.com/xtekky/gpt4free">@gpt4free</a>
|
||||
<span class="convo-title">github ~ <a href="https://github.com/xtekky/gpt4free">@xtekky/gpt4free</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
@ -73,6 +78,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings hidden">
|
||||
<div class="paper">
|
||||
<div class="field">
|
||||
<span class="label">Web Access</span>
|
||||
<input type="checkbox" id="switch" />
|
||||
@ -91,9 +97,16 @@
|
||||
<div class="field">
|
||||
<span class="label">Auto continue</span>
|
||||
<input id="auto_continue" type="checkbox" name="auto_continue" checked/>
|
||||
<label for="auto_continue" class="toogle" title="Continue long responses in OpenaiChat"></label>
|
||||
<label for="auto_continue" class="toogle" title="Continue large responses in OpenaiChat"></label>
|
||||
</div>
|
||||
<div class="field box">
|
||||
<label for="message-input-height" class="label" title="">Input max. grow height</label>
|
||||
<input type="number" id="message-input-height" value="200"/>
|
||||
</div>
|
||||
<div class="field box">
|
||||
<label for="recognition-language" class="label" title="">Speech recognition lang</label>
|
||||
<input type="text" id="recognition-language" value="" placeholder="navigator.language"/>
|
||||
</div>
|
||||
<div class="paper">
|
||||
<div class="field box">
|
||||
<label for="OpenaiChat-api_key" class="label" title="">OpenaiChat: api_key</label>
|
||||
<textarea id="OpenaiChat-api_key" name="OpenaiChat[api_key]" placeholder="..."></textarea>
|
||||
@ -170,6 +183,9 @@
|
||||
<input type="file" id="file" name="file" accept="text/plain, text/html, text/xml, application/json, text/javascript, .sh, .py, .php, .css, .yaml, .sql, .log, .csv, .twig, .md" required/>
|
||||
<i class="fa-solid fa-paperclip"></i>
|
||||
</label>
|
||||
<label class="micro-label" for="micro">
|
||||
<i class="fa-solid fa-microphone-slash"></i>
|
||||
</label>
|
||||
<div id="send-button">
|
||||
<i class="fa-solid fa-paper-plane-top"></i>
|
||||
</div>
|
||||
|
@ -88,6 +88,8 @@ body {
|
||||
background: var(--colour-1);
|
||||
color: var(--colour-3);
|
||||
height: 100vh;
|
||||
max-width: 1600px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.row {
|
||||
@ -106,10 +108,6 @@ body {
|
||||
border: 1px solid var(--blur-border);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.conversations {
|
||||
max-width: 280px;
|
||||
padding: var(--section-gap);
|
||||
@ -138,8 +136,7 @@ body {
|
||||
}
|
||||
|
||||
.conversation .user-input {
|
||||
max-height: 200px;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.conversation .user-input input {
|
||||
@ -504,7 +501,8 @@ body {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-label {
|
||||
.file-label,
|
||||
.micro-label {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
@ -512,7 +510,8 @@ body {
|
||||
}
|
||||
|
||||
.file-label:has(> input:valid),
|
||||
.file-label.selected {
|
||||
.file-label.selected,
|
||||
.micro-label.recognition {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
@ -520,11 +519,12 @@ label[for="image"] {
|
||||
top: 32px;
|
||||
}
|
||||
|
||||
label[for="camera"] {
|
||||
label[for="micro"] {
|
||||
top: 54px;
|
||||
}
|
||||
|
||||
label[for="camera"] {
|
||||
top: 74px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -597,7 +597,7 @@ label[for="camera"] {
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
width: 100%;
|
||||
margin-bottom: 2px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.field {
|
||||
@ -668,7 +668,7 @@ select {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin: 4px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.bottom_buttons button {
|
||||
@ -841,7 +841,7 @@ a:-webkit-any-link {
|
||||
color: var(--colour-3);
|
||||
|
||||
resize: vertical;
|
||||
max-height: 150px;
|
||||
max-height: 200px;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
@ -1080,6 +1080,19 @@ a:-webkit-any-link {
|
||||
padding: var(--inner-gap) 0;
|
||||
}
|
||||
|
||||
.settings input {
|
||||
background-color: transparent;
|
||||
padding: 2px;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
width: 100%;
|
||||
color: var(--colour-3);
|
||||
}
|
||||
|
||||
.settings input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.settings .label {
|
||||
font-size: 15px;
|
||||
padding: var(--inner-gap) 0;
|
||||
@ -1100,7 +1113,7 @@ a:-webkit-any-link {
|
||||
border-radius: 5px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--accent)
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
.hljs {
|
||||
@ -1114,8 +1127,13 @@ a:-webkit-any-link {
|
||||
#message-input {
|
||||
height: 82px;
|
||||
margin-left: 20px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
#message-input::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
@ -10,6 +10,7 @@ const sendButton = document.getElementById("send-button");
|
||||
const imageInput = document.getElementById("image");
|
||||
const cameraInput = document.getElementById("camera");
|
||||
const fileInput = document.getElementById("file");
|
||||
const microLabel = document.querySelector(".micro-label")
|
||||
const inputCount = document.getElementById("input-count")
|
||||
const providerSelect = document.getElementById("provider");
|
||||
const modelSelect = document.getElementById("model");
|
||||
@ -81,7 +82,7 @@ const register_message_buttons = async () => {
|
||||
if (!("click" in el.dataset)) {
|
||||
el.dataset.click = "true";
|
||||
el.addEventListener("click", async () => {
|
||||
const message_el = el.parentElement.parentElement;
|
||||
const message_el = el.parentElement.parentElement.parentElement;
|
||||
const copyText = await get_message(window.conversation_id, message_el.dataset.index);
|
||||
navigator.clipboard.writeText(copyText);
|
||||
el.classList.add("clicked");
|
||||
@ -552,8 +553,10 @@ async function save_system_message() {
|
||||
return;
|
||||
}
|
||||
const conversation = await get_conversation(window.conversation_id);
|
||||
if (conversation) {
|
||||
conversation.system = systemPrompt?.value;
|
||||
await save_conversation(window.conversation_id, conversation);
|
||||
}
|
||||
}
|
||||
|
||||
const hide_last_message = async (conversation_id) => {
|
||||
@ -586,8 +589,9 @@ const remove_message = async (conversation_id, index) => {
|
||||
};
|
||||
|
||||
const get_message = async (conversation_id, index) => {
|
||||
const conversation = await get_conversation(conversation_id);
|
||||
return conversation.items[index]["content"];
|
||||
const messages = await get_messages(conversation_id);
|
||||
if (index in messages)
|
||||
return messages[index]["content"];
|
||||
};
|
||||
|
||||
const add_message = async (conversation_id, role, content, provider) => {
|
||||
@ -707,18 +711,27 @@ function open_settings() {
|
||||
|
||||
const register_settings_storage = async () => {
|
||||
optionElements.forEach((element) => {
|
||||
if (element.type == "textarea") {
|
||||
element.addEventListener('input', async (event) => {
|
||||
appStorage.setItem(element.id, element.value);
|
||||
});
|
||||
} else {
|
||||
element.addEventListener('change', async (event) => {
|
||||
switch (event.target.type) {
|
||||
switch (element.type) {
|
||||
case "checkbox":
|
||||
appStorage.setItem(element.id, event.target.checked);
|
||||
appStorage.setItem(element.id, element.checked);
|
||||
break;
|
||||
case "select-one":
|
||||
appStorage.setItem(element.id, event.target.selectedIndex);
|
||||
appStorage.setItem(element.id, element.selectedIndex);
|
||||
break;
|
||||
case "text":
|
||||
appStorage.setItem(element.id, element.value);
|
||||
break;
|
||||
default:
|
||||
console.warn("Unresolved element type");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -735,6 +748,10 @@ const load_settings_storage = async () => {
|
||||
case "select-one":
|
||||
element.selectedIndex = parseInt(value);
|
||||
break;
|
||||
case "text":
|
||||
case "textarea":
|
||||
element.value = value;
|
||||
break;
|
||||
default:
|
||||
console.warn("Unresolved element type");
|
||||
}
|
||||
@ -831,7 +848,7 @@ systemPrompt.addEventListener("focus", function() {
|
||||
countFocus = systemPrompt;
|
||||
count_input();
|
||||
});
|
||||
systemPrompt.addEventListener("blur", function() {
|
||||
systemPrompt.addEventListener("input", function() {
|
||||
countFocus = messageInput;
|
||||
count_input();
|
||||
});
|
||||
@ -911,6 +928,15 @@ async function on_api() {
|
||||
systemPrompt.classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
const messageInputHeight = document.getElementById("message-input-height");
|
||||
if (messageInputHeight) {
|
||||
if (messageInputHeight.value) {
|
||||
messageInput.style.maxHeight = `${messageInputHeight.value}px`;
|
||||
}
|
||||
messageInputHeight.addEventListener('change', async () => {
|
||||
messageInput.style.maxHeight = `${messageInputHeight.value}px`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function load_version() {
|
||||
@ -980,7 +1006,7 @@ fileInput.addEventListener('change', async (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
systemPrompt?.addEventListener("blur", async () => {
|
||||
systemPrompt?.addEventListener("input", async () => {
|
||||
await save_system_message();
|
||||
});
|
||||
|
||||
@ -1092,7 +1118,7 @@ function save_storage() {
|
||||
}
|
||||
}
|
||||
data = JSON.stringify(data, null, 4);
|
||||
const blob = new Blob([data], {type: 'text/csv'});
|
||||
const blob = new Blob([data], {type: 'application/json'});
|
||||
if(window.navigator.msSaveOrOpenBlob) {
|
||||
window.navigator.msSaveBlob(blob, filename);
|
||||
} else{
|
||||
@ -1104,3 +1130,68 @@ function save_storage() {
|
||||
document.body.removeChild(elem);
|
||||
}
|
||||
}
|
||||
|
||||
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||||
if (SpeechRecognition) {
|
||||
const mircoIcon = microLabel.querySelector("i");
|
||||
mircoIcon.classList.add("fa-microphone");
|
||||
mircoIcon.classList.remove("fa-microphone-slash");
|
||||
|
||||
const recognition = new SpeechRecognition();
|
||||
recognition.continuous = true;
|
||||
recognition.interimResults = true;
|
||||
recognition.maxAlternatives = 1;
|
||||
|
||||
function may_stop() {
|
||||
if (microLabel.classList.contains("recognition")) {
|
||||
recognition.stop();
|
||||
}
|
||||
}
|
||||
|
||||
let startValue;
|
||||
let timeoutHandle;
|
||||
recognition.onstart = function() {
|
||||
microLabel.classList.add("recognition");
|
||||
startValue = messageInput.value;
|
||||
timeoutHandle = window.setTimeout(may_stop, 8000);
|
||||
};
|
||||
recognition.onend = function() {
|
||||
microLabel.classList.remove("recognition");
|
||||
};
|
||||
recognition.onresult = function(event) {
|
||||
if (!event.results) {
|
||||
return;
|
||||
}
|
||||
window.clearTimeout(timeoutHandle);
|
||||
let notFinal = "";
|
||||
event.results.forEach((result) => {
|
||||
const newText = result[0].transcript;
|
||||
if (newText) {
|
||||
if (result.isFinal) {
|
||||
messageInput.value = `${startValue ? startValue+"\n" : ""}${newText.trim()}`;
|
||||
startValue = messageInput.value;
|
||||
notFinal = "";
|
||||
messageInput.focus();
|
||||
} else {
|
||||
notFinal += newText;
|
||||
messageInput.value = `${startValue ? startValue+"\n" : ""}${notFinal.trim()}`;
|
||||
}
|
||||
messageInput.style.height = messageInput.scrollHeight + "px";
|
||||
messageInput.scrollTop = messageInput.scrollHeight;
|
||||
}
|
||||
});
|
||||
window.clearTimeout(timeoutHandle);
|
||||
timeoutHandle = window.setTimeout(may_stop, notFinal ? 5000 : 8000);
|
||||
};
|
||||
|
||||
microLabel.addEventListener("click", () => {
|
||||
if (microLabel.classList.contains("recognition")) {
|
||||
window.clearTimeout(timeoutHandle);
|
||||
recognition.stop();
|
||||
} else {
|
||||
const lang = document.getElementById("recognition-language")?.value || navigator.language;
|
||||
recognition.lang = lang;
|
||||
recognition.start();
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user