Some small fixes

This commit is contained in:
Heiner Lohaus 2024-04-10 14:23:30 +02:00
parent 00951eb791
commit 65bcc8ae8b
9 changed files with 137 additions and 81 deletions

3
.gitignore vendored
View File

@ -55,3 +55,6 @@ local.py
image.py image.py
.buildozer .buildozer
hardir hardir
node_modules
models
projects/windows/g4f

View File

@ -10,8 +10,6 @@ from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
from .helper import format_prompt from .helper import format_prompt
from ..image import ImageResponse, to_bytes, is_accepted_format from ..image import ImageResponse, to_bytes, is_accepted_format
from ..requests import StreamSession, FormData, raise_for_status from ..requests import StreamSession, FormData, raise_for_status
from ..errors import MissingRequirementsError
from .you.har_file import get_dfp_telemetry_id from .you.har_file import get_dfp_telemetry_id
class You(AsyncGeneratorProvider, ProviderModelMixin): class You(AsyncGeneratorProvider, ProviderModelMixin):

View File

@ -646,6 +646,21 @@ select {
width: 160px; width: 160px;
} }
#systemPrompt, .settings textarea {
font-size: 15px;
width: 100%;
color: var(--colour-3);
min-height: 50px;
height: 59px;
outline: none;
padding: var(--inner-gap) var(--section-gap);
resize: vertical;
}
#systemPrompt {
padding-left: 35px;
}
@media only screen and (min-width: 40em) { @media only screen and (min-width: 40em) {
select { select {
width: 200px; width: 200px;
@ -836,6 +851,10 @@ ul {
.mobile-sidebar { .mobile-sidebar {
display: flex !important; display: flex !important;
} }
#systemPrompt {
padding-left: 48px;
}
} }
.shown { .shown {
@ -1064,22 +1083,11 @@ a:-webkit-any-link {
border: 1px solid #e4d4ffc9; border: 1px solid #e4d4ffc9;
} }
#systemPrompt, .settings textarea {
font-size: 15px;
width: 100%;
color: var(--colour-3);
min-height: 50px;
height: 59px;
outline: none;
padding: var(--inner-gap) var(--section-gap);
resize: vertical;
}
.settings textarea { .settings textarea {
height: 51px; height: 51px;
} }
.settings { .settings, .images {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -10,13 +10,14 @@ const sendButton = document.getElementById("send-button");
const imageInput = document.getElementById("image"); const imageInput = document.getElementById("image");
const cameraInput = document.getElementById("camera"); const cameraInput = document.getElementById("camera");
const fileInput = document.getElementById("file"); const fileInput = document.getElementById("file");
const microLabel = document.querySelector(".micro-label") const microLabel = document.querySelector(".micro-label");
const inputCount = document.getElementById("input-count") const inputCount = document.getElementById("input-count");
const providerSelect = document.getElementById("provider"); const providerSelect = document.getElementById("provider");
const modelSelect = document.getElementById("model"); const modelSelect = document.getElementById("model");
const modelProvider = document.getElementById("model2"); const modelProvider = document.getElementById("model2");
const systemPrompt = document.getElementById("systemPrompt") const systemPrompt = document.getElementById("systemPrompt");
const settings = document.querySelector(".settings") const settings = document.querySelector(".settings");
const album = document.querySelector(".images");
let prompt_lock = false; let prompt_lock = false;
@ -49,6 +50,12 @@ const markdown_render = (content) => {
.replaceAll('<code>', '<code class="language-plaintext">') .replaceAll('<code>', '<code class="language-plaintext">')
} }
function filter_message(text) {
return text.replaceAll(
/<!-- generated images start -->[\s\S]+<!-- generated images end -->/gm, ""
)
}
hljs.addPlugin(new CopyButtonPlugin()); hljs.addPlugin(new CopyButtonPlugin());
let typesetPromise = Promise.resolve(); let typesetPromise = Promise.resolve();
const highlight = (container) => { const highlight = (container) => {
@ -64,7 +71,6 @@ const highlight = (container) => {
); );
} }
let stopped = false;
const register_message_buttons = async () => { const register_message_buttons = async () => {
document.querySelectorAll(".message .fa-xmark").forEach(async (el) => { document.querySelectorAll(".message .fa-xmark").forEach(async (el) => {
if (!("click" in el.dataset)) { if (!("click" in el.dataset)) {
@ -95,69 +101,76 @@ const register_message_buttons = async () => {
if (!("click" in el.dataset)) { if (!("click" in el.dataset)) {
el.dataset.click = "true"; el.dataset.click = "true";
el.addEventListener("click", async () => { el.addEventListener("click", async () => {
if ("active" in el.classList || window.doSpeech) { let playlist = [];
el.classList.add("blink") function play_next() {
stopped = true; const next = playlist.shift();
return; if (next)
next.play();
} }
if (stopped) { if (el.dataset.stopped) {
el.classList.remove("blink") el.classList.remove("blink")
stopped = false; delete el.dataset.stopped;
return; return;
} }
if (el.dataset.running) {
el.dataset.stopped = true;
el.classList.add("blink")
playlist = [];
return;
}
el.dataset.running = true;
el.classList.add("blink") el.classList.add("blink")
el.classList.add("active") el.classList.add("active")
const message_el = el.parentElement.parentElement.parentElement;
const content_el = el.parentElement.parentElement; const content_el = el.parentElement.parentElement;
const message_el = content_el.parentElement;
let speechText = await get_message(window.conversation_id, message_el.dataset.index); let speechText = await get_message(window.conversation_id, message_el.dataset.index);
speechText = speechText.replaceAll(/([^0-9])\./gm, "$1.;");
speechText = speechText.replaceAll("?", "?;");
speechText = speechText.replaceAll(/\[(.+)\]\(.+\)/gm, "($1)"); speechText = speechText.replaceAll(/\[(.+)\]\(.+\)/gm, "($1)");
speechText = speechText.replaceAll("`", "").replaceAll("#", "") speechText = speechText.replaceAll(/```[a-z]+/gm, "");
speechText = speechText.replaceAll( speechText = filter_message(speechText.replaceAll("`", "").replaceAll("#", ""))
/<!-- generated images start -->[\s\S]+<!-- generated images end -->/gm, const lines = speechText.trim().split(/\n|;/).filter(v => v.trim());
""
)
const lines = speechText.trim().split(/\n|\.|;/);
let ended = true;
window.onSpeechResponse = (url) => { window.onSpeechResponse = (url) => {
if (!el.dataset.stopped) {
el.classList.remove("blink") el.classList.remove("blink")
}
if (url) { if (url) {
var sound = document.createElement('audio'); var sound = document.createElement('audio');
sound.controls = 'controls'; sound.controls = 'controls';
sound.src = url; sound.src = url;
sound.type = 'audio/wav'; sound.type = 'audio/wav';
sound.onended = function() { sound.onended = function() {
ended = true; el.dataset.do_play = true;
setTimeout(play_next, 1000);
}; };
sound.onplay = function() { sound.onplay = function() {
ended = false; delete el.dataset.do_play;
}; };
var container = document.createElement('div'); var container = document.createElement('div');
container.classList.add("audio"); container.classList.add("audio");
container.appendChild(sound); container.appendChild(sound);
content_el.appendChild(container); content_el.appendChild(container);
if (ended && !stopped) { if (!el.dataset.stopped) {
sound.play(); playlist.push(sound);
if (el.dataset.do_play) {
play_next();
} }
} }
if (lines.length < 1 || stopped) { }
let line = lines.length > 0 ? lines.shift() : null;
if (line && !el.dataset.stopped) {
handleGenerateSpeech(line);
} else {
el.classList.remove("active"); el.classList.remove("active");
return; el.classList.remove("blink");
delete el.dataset.running;
} }
while (lines.length > 0) { }
el.dataset.do_play = true;
let line = lines.shift(); let line = lines.shift();
var reg = new RegExp('^[0-9]$'); handleGenerateSpeech(line);
if (line && !reg.test(line)) {
return handleGenerateSpeech(line);
}
}
if (!line) {
el.classList.remove("active")
}
}
let line = lines.shift();
return handleGenerateSpeech(line);
}); });
} }
}); });
@ -399,7 +412,7 @@ const ask_gpt = async () => {
provider = "Bing"; provider = "Bing";
let api_key = null; let api_key = null;
if (provider) if (provider)
api_key = document.getElementById(`${provider}-api_key`)?.value; api_key = document.getElementById(`${provider}-api_key`)?.value || null;
await api("conversation", { await api("conversation", {
id: window.token, id: window.token,
conversation_id: window.conversation_id, conversation_id: window.conversation_id,
@ -717,7 +730,7 @@ const load_conversations = async () => {
</div> </div>
`; `;
}); });
box_conversations.innerHTML = html; box_conversations.innerHTML += html;
}; };
document.getElementById("cancelButton").addEventListener("click", async () => { document.getElementById("cancelButton").addEventListener("click", async () => {
@ -790,6 +803,17 @@ function open_settings() {
} }
} }
function open_album() {
if (album.classList.contains("hidden")) {
sidebar.classList.remove("shown");
settings.classList.add("hidden");
album.classList.remove("hidden");
history.pushState({}, null, "/images/");
} else {
album.classList.add("hidden");
}
}
const register_settings_storage = async () => { const register_settings_storage = async () => {
optionElements.forEach((element) => { optionElements.forEach((element) => {
if (element.type == "textarea") { if (element.type == "textarea") {
@ -1232,12 +1256,12 @@ if (SpeechRecognition) {
} }
let startValue; let startValue;
let lastValue;
let timeoutHandle; let timeoutHandle;
let lastDebounceTranscript;
recognition.onstart = function() { recognition.onstart = function() {
microLabel.classList.add("recognition"); microLabel.classList.add("recognition");
startValue = messageInput.value; startValue = messageInput.value;
lastValue = ""; lastDebounceTranscript = "";
timeoutHandle = window.setTimeout(may_stop, 8000); timeoutHandle = window.setTimeout(may_stop, 8000);
}; };
recognition.onend = function() { recognition.onend = function() {
@ -1248,22 +1272,27 @@ if (SpeechRecognition) {
return; return;
} }
window.clearTimeout(timeoutHandle); window.clearTimeout(timeoutHandle);
let newText;
Array.from(event.results).forEach((result) => { let result = event.results[event.resultIndex];
newText = result[0].transcript; let isFinal = result.isFinal && (result[0].confidence > 0);
if (newText && newText != lastValue) { let transcript = result[0].transcript;
messageInput.value = `${startValue ? startValue+"\n" : ""}${newText.trim()}`; if (isFinal) {
if (result.isFinal) { if(transcript == lastDebounceTranscript) {
lastValue = newText; return;
}
lastDebounceTranscript = transcript;
}
if (transcript) {
messageInput.value = `${startValue ? startValue+"\n" : ""}${transcript.trim()}`;
if (isFinal) {
startValue = messageInput.value; startValue = messageInput.value;
messageInput.focus(); messageInput.focus();
} }
messageInput.style.height = messageInput.scrollHeight + "px"; messageInput.style.height = messageInput.scrollHeight + "px";
messageInput.scrollTop = messageInput.scrollHeight; messageInput.scrollTop = messageInput.scrollHeight;
} }
});
window.clearTimeout(timeoutHandle); timeoutHandle = window.setTimeout(may_stop, transcript ? 8000 : 5000);
timeoutHandle = window.setTimeout(may_stop, newText ? 8000 : 5000);
}; };
microLabel.addEventListener("click", () => { microLabel.addEventListener("click", () => {

View File

@ -78,6 +78,7 @@ class AbstractProvider(BaseProvider):
timeout=kwargs.get("timeout") timeout=kwargs.get("timeout")
) )
@classmethod
def get_parameters(cls) -> dict: def get_parameters(cls) -> dict:
return signature( return signature(
cls.create_async_generator if issubclass(cls, AsyncGeneratorProvider) else cls.create_async_generator if issubclass(cls, AsyncGeneratorProvider) else
@ -107,7 +108,9 @@ class AbstractProvider(BaseProvider):
continue continue
args += f"\n {name}" args += f"\n {name}"
args += f": {get_type_name(param.annotation)}" if param.annotation is not Parameter.empty else "" args += f": {get_type_name(param.annotation)}" if param.annotation is not Parameter.empty else ""
args += f' = "{param.default}"' if param.default == "" else f" = {param.default}" if param.default is not Parameter.empty else "" default_value = f'"{param.default}"' if isinstance(param.default, str) else param.default
args += f" = {default_value}" if param.default is not Parameter.empty else ""
args += ","
return f"g4f.Provider.{cls.__name__} supports: ({args}\n)" return f"g4f.Provider.{cls.__name__} supports: ({args}\n)"

View File

@ -33,9 +33,14 @@ class StreamSession(ClientSession):
**DEFAULT_HEADERS, **DEFAULT_HEADERS,
**headers **headers
} }
connect = None
if isinstance(timeout, tuple):
connect, timeout = timeout;
if timeout is not None:
timeout = ClientTimeout(timeout, connect)
super().__init__( super().__init__(
**kwargs, **kwargs,
timeout=ClientTimeout(timeout) if timeout else None, timeout=timeout,
response_class=StreamResponse, response_class=StreamResponse,
connector=get_connector(connector, proxies.get("all", proxies.get("https"))), connector=get_connector(connector, proxies.get("all", proxies.get("https"))),
headers=headers headers=headers

View File

@ -1,6 +1,11 @@
from __future__ import annotations from __future__ import annotations
from curl_cffi.requests import AsyncSession, Response, CurlMime from curl_cffi.requests import AsyncSession, Response
try:
from curl_cffi.requests import CurlMime
has_curl_mime = True
except ImportError:
has_curl_mime = False
from typing import AsyncGenerator, Any from typing import AsyncGenerator, Any
from functools import partialmethod from functools import partialmethod
import json import json
@ -78,6 +83,11 @@ class StreamSession(AsyncSession):
patch = partialmethod(request, "PATCH") patch = partialmethod(request, "PATCH")
delete = partialmethod(request, "DELETE") delete = partialmethod(request, "DELETE")
class FormData(CurlMime): if has_curl_mime:
class FormData(CurlMime):
def add_field(self, name, data=None, content_type: str = None, filename: str = None) -> None: def add_field(self, name, data=None, content_type: str = None, filename: str = None) -> None:
self.addpart(name, content_type=content_type, filename=filename, data=data) self.addpart(name, content_type=content_type, filename=filename, data=data)
else:
class FormData():
def __init__(self) -> None:
raise RuntimeError("CurlMimi in curl_cffi is missing | pip install -U g4f[curl_cffi]")

View File

@ -12,8 +12,5 @@
"pack": "^2.2.0", "pack": "^2.2.0",
"web": "^0.0.2", "web": "^0.0.2",
"webpack-cli": "^5.1.4" "webpack-cli": "^5.1.4"
}, }
"bundleDependencies": [
"@xenova/transformers"
]
} }

View File

@ -74,6 +74,9 @@ EXTRA_REQUIRE = {
], ],
"local": [ "local": [
"gpt4all" "gpt4all"
],
"curl_cffi": [
"curl_cffi>=0.6.2",
] ]
} }