mirror of https://github.com/xtekky/gpt4free.git
Merge pull request #1575 from hlohaus/openai
Add GPT 4 support in You Fix convert image to jpg with exceptional modes in Bing Add camera input in GUI Enable logging on debug in GUI Don't load expired cookies Fix display upload image in GUI Add upload image in You provider Add disable history button in GUI Change python version to 3.12 in unittests
This commit is contained in:
commit
3c498496f8
|
@ -27,7 +27,7 @@ jobs:
|
||||||
- name: Set up Python 3.11
|
- name: Set up Python 3.11
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.12"
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
- name: Install requirements
|
- name: Install requirements
|
||||||
run: pip install -r requirements.txt
|
run: pip install -r requirements.txt
|
||||||
|
|
|
@ -1,40 +1,155 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import base64
|
||||||
|
import uuid
|
||||||
|
from aiohttp import ClientSession, FormData
|
||||||
|
|
||||||
from ..requests import StreamSession
|
from ..typing import AsyncGenerator, Messages, ImageType, Cookies
|
||||||
from ..typing import AsyncGenerator, Messages
|
from .base_provider import AsyncGeneratorProvider
|
||||||
from .base_provider import AsyncGeneratorProvider, format_prompt
|
from .helper import get_connector, format_prompt
|
||||||
|
from ..image import to_bytes
|
||||||
|
from ..defaults import DEFAULT_HEADERS
|
||||||
|
|
||||||
class You(AsyncGeneratorProvider):
|
class You(AsyncGeneratorProvider):
|
||||||
url = "https://you.com"
|
url = "https://you.com"
|
||||||
working = True
|
working = True
|
||||||
supports_gpt_35_turbo = True
|
supports_gpt_35_turbo = True
|
||||||
|
supports_gpt_4 = True
|
||||||
|
_cookies = None
|
||||||
|
_cookies_used = 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_async_generator(
|
async def create_async_generator(
|
||||||
cls,
|
cls,
|
||||||
model: str,
|
model: str,
|
||||||
messages: Messages,
|
messages: Messages,
|
||||||
|
image: ImageType = None,
|
||||||
|
image_name: str = None,
|
||||||
proxy: str = None,
|
proxy: str = None,
|
||||||
timeout: int = 120,
|
chat_mode: str = "default",
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> AsyncGenerator:
|
) -> AsyncGenerator:
|
||||||
async with StreamSession(proxies={"https": proxy}, impersonate="chrome107", timeout=timeout) as session:
|
async with ClientSession(
|
||||||
|
connector=get_connector(kwargs.get("connector"), proxy),
|
||||||
|
headers=DEFAULT_HEADERS
|
||||||
|
) as client:
|
||||||
|
if image:
|
||||||
|
chat_mode = "agent"
|
||||||
|
elif model == "gpt-4":
|
||||||
|
chat_mode = model
|
||||||
|
cookies = await cls.get_cookies(client) if chat_mode != "default" else None
|
||||||
|
upload = json.dumps([await cls.upload_file(client, cookies, to_bytes(image), image_name)]) if image else ""
|
||||||
|
#questions = [message["content"] for message in messages if message["role"] == "user"]
|
||||||
|
# chat = [
|
||||||
|
# {"question": questions[idx-1], "answer": message["content"]}
|
||||||
|
# for idx, message in enumerate(messages)
|
||||||
|
# if message["role"] == "assistant"
|
||||||
|
# and idx < len(questions)
|
||||||
|
# ]
|
||||||
headers = {
|
headers = {
|
||||||
"Accept": "text/event-stream",
|
"Accept": "text/event-stream",
|
||||||
"Referer": f"{cls.url}/search?fromSearchBar=true&tbm=youchat",
|
"Referer": f"{cls.url}/search?fromSearchBar=true&tbm=youchat",
|
||||||
}
|
}
|
||||||
data = {"q": format_prompt(messages), "domain": "youchat", "chat": ""}
|
data = {
|
||||||
async with session.get(
|
"userFiles": upload,
|
||||||
|
"q": format_prompt(messages),
|
||||||
|
"domain": "youchat",
|
||||||
|
"selectedChatMode": chat_mode,
|
||||||
|
#"chat": json.dumps(chat),
|
||||||
|
}
|
||||||
|
async with (client.post if chat_mode == "default" else client.get)(
|
||||||
f"{cls.url}/api/streamingSearch",
|
f"{cls.url}/api/streamingSearch",
|
||||||
params=data,
|
data=data,
|
||||||
headers=headers
|
headers=headers,
|
||||||
|
cookies=cookies
|
||||||
) as response:
|
) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
start = b'data: {"youChatToken": '
|
async for line in response.content:
|
||||||
async for line in response.iter_lines():
|
if line.startswith(b'event: '):
|
||||||
if line.startswith(start):
|
event = line[7:-1]
|
||||||
yield json.loads(line[len(start):-1])
|
elif line.startswith(b'data: '):
|
||||||
|
if event == b"youChatUpdate" or event == b"youChatToken":
|
||||||
|
data = json.loads(line[6:-1])
|
||||||
|
if event == b"youChatToken" and "youChatToken" in data:
|
||||||
|
yield data["youChatToken"]
|
||||||
|
elif event == b"youChatUpdate" and "t" in data:
|
||||||
|
yield data["t"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def upload_file(cls, client: ClientSession, cookies: Cookies, file: bytes, filename: str = None) -> dict:
|
||||||
|
async with client.get(
|
||||||
|
f"{cls.url}/api/get_nonce",
|
||||||
|
cookies=cookies,
|
||||||
|
) as response:
|
||||||
|
response.raise_for_status()
|
||||||
|
upload_nonce = await response.text()
|
||||||
|
data = FormData()
|
||||||
|
data.add_field('file', file, filename=filename)
|
||||||
|
async with client.post(
|
||||||
|
f"{cls.url}/api/upload",
|
||||||
|
data=data,
|
||||||
|
headers={
|
||||||
|
"X-Upload-Nonce": upload_nonce,
|
||||||
|
},
|
||||||
|
cookies=cookies
|
||||||
|
) as response:
|
||||||
|
if not response.ok:
|
||||||
|
raise RuntimeError(f"Response: {await response.text()}")
|
||||||
|
result = await response.json()
|
||||||
|
result["user_filename"] = filename
|
||||||
|
result["size"] = len(file)
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_cookies(cls, client: ClientSession) -> Cookies:
|
||||||
|
if not cls._cookies or cls._cookies_used >= 5:
|
||||||
|
cls._cookies = await cls.create_cookies(client)
|
||||||
|
cls._cookies_used = 0
|
||||||
|
cls._cookies_used += 1
|
||||||
|
return cls._cookies
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_sdk(cls) -> str:
|
||||||
|
return base64.standard_b64encode(json.dumps({
|
||||||
|
"event_id":f"event-id-{str(uuid.uuid4())}",
|
||||||
|
"app_session_id":f"app-session-id-{str(uuid.uuid4())}",
|
||||||
|
"persistent_id":f"persistent-id-{uuid.uuid4()}",
|
||||||
|
"client_sent_at":"","timezone":"",
|
||||||
|
"stytch_user_id":f"user-live-{uuid.uuid4()}",
|
||||||
|
"stytch_session_id":f"session-live-{uuid.uuid4()}",
|
||||||
|
"app":{"identifier":"you.com"},
|
||||||
|
"sdk":{"identifier":"Stytch.js Javascript SDK","version":"3.3.0"
|
||||||
|
}}).encode()).decode()
|
||||||
|
|
||||||
|
def get_auth() -> str:
|
||||||
|
auth_uuid = "507a52ad-7e69-496b-aee0-1c9863c7c8"
|
||||||
|
auth_token = f"public-token-live-{auth_uuid}bb:public-token-live-{auth_uuid}19"
|
||||||
|
auth = base64.standard_b64encode(auth_token.encode()).decode()
|
||||||
|
return f"Basic {auth}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def create_cookies(cls, client: ClientSession) -> Cookies:
|
||||||
|
user_uuid = str(uuid.uuid4())
|
||||||
|
async with client.post(
|
||||||
|
"https://web.stytch.com/sdk/v1/passwords",
|
||||||
|
headers={
|
||||||
|
"Authorization": cls.get_auth(),
|
||||||
|
"X-SDK-Client": cls.get_sdk(),
|
||||||
|
"X-SDK-Parent-Host": cls.url
|
||||||
|
},
|
||||||
|
json={
|
||||||
|
"email": f"{user_uuid}@gmail.com",
|
||||||
|
"password": f"{user_uuid}#{user_uuid}",
|
||||||
|
"session_duration_minutes": 129600
|
||||||
|
}
|
||||||
|
) as response:
|
||||||
|
if not response.ok:
|
||||||
|
raise RuntimeError(f"Response: {await response.text()}")
|
||||||
|
session = (await response.json())["data"]
|
||||||
|
return {
|
||||||
|
"stytch_session": session["session_token"],
|
||||||
|
'stytch_session_jwt': session["session_jwt"],
|
||||||
|
'ydc_stytch_session': session["session_token"],
|
||||||
|
'ydc_stytch_session_jwt': session["session_jwt"],
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from platformdirs import user_config_dir
|
from platformdirs import user_config_dir
|
||||||
|
@ -72,6 +73,7 @@ def load_cookies_from_browsers(domain_name: str, raise_requirements_error: bool
|
||||||
print(f"Read cookies from {cookie_fn.__name__} for {domain_name}")
|
print(f"Read cookies from {cookie_fn.__name__} for {domain_name}")
|
||||||
for cookie in cookie_jar:
|
for cookie in cookie_jar:
|
||||||
if cookie.name not in cookies:
|
if cookie.name not in cookies:
|
||||||
|
if not cookie.expires or cookie.expires > time.time():
|
||||||
cookies[cookie.name] = cookie.value
|
cookies[cookie.name] = cookie.value
|
||||||
if single_browser and len(cookie_jar):
|
if single_browser and len(cookie_jar):
|
||||||
break
|
break
|
||||||
|
|
|
@ -7,6 +7,9 @@ except ImportError:
|
||||||
raise MissingRequirementsError('Install "flask" package for the gui')
|
raise MissingRequirementsError('Install "flask" package for the gui')
|
||||||
|
|
||||||
def run_gui(host: str = '0.0.0.0', port: int = 8080, debug: bool = False) -> None:
|
def run_gui(host: str = '0.0.0.0', port: int = 8080, debug: bool = False) -> None:
|
||||||
|
if debug:
|
||||||
|
import g4f
|
||||||
|
g4f.debug.logging = True
|
||||||
config = {
|
config = {
|
||||||
'host' : host,
|
'host' : host,
|
||||||
'port' : port,
|
'port' : port,
|
||||||
|
|
|
@ -404,7 +404,7 @@ body {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#image, #file {
|
#image, #file, #camera {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,20 +412,37 @@ label[for="image"]:has(> input:valid){
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label[for="camera"]:has(> input:valid){
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
label[for="file"]:has(> input:valid){
|
label[for="file"]:has(> input:valid){
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
label[for="image"], label[for="file"] {
|
label[for="image"], label[for="file"], label[for="camera"] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
label[for="file"] {
|
label[for="image"] {
|
||||||
top: 32px;
|
top: 32px;
|
||||||
left: 10px;
|
}
|
||||||
|
|
||||||
|
label[for="camera"] {
|
||||||
|
top: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label[for="camera"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (pointer:none), (pointer:coarse) {
|
||||||
|
label[for="camera"] {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons input[type="checkbox"] {
|
.buttons input[type="checkbox"] {
|
||||||
|
|
|
@ -114,10 +114,14 @@
|
||||||
<div class="box input-box">
|
<div class="box input-box">
|
||||||
<textarea id="message-input" placeholder="Ask a question" cols="30" rows="10"
|
<textarea id="message-input" placeholder="Ask a question" cols="30" rows="10"
|
||||||
style="white-space: pre-wrap;resize: none;"></textarea>
|
style="white-space: pre-wrap;resize: none;"></textarea>
|
||||||
<label for="image" title="Works only with Bing and OpenaiChat">
|
<label for="image" title="Works with Bing, Gemini, OpenaiChat and You">
|
||||||
<input type="file" id="image" name="image" accept="image/png, image/gif, image/jpeg, image/svg+xml" required/>
|
<input type="file" id="image" name="image" accept="image/*" required/>
|
||||||
<i class="fa-regular fa-image"></i>
|
<i class="fa-regular fa-image"></i>
|
||||||
</label>
|
</label>
|
||||||
|
<label for="camera">
|
||||||
|
<input type="file" id="camera" name="camera" accept="image/*" capture="camera" required/>
|
||||||
|
<i class="fa-solid fa-camera"></i>
|
||||||
|
</label>
|
||||||
<label for="file">
|
<label for="file">
|
||||||
<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/>
|
<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>
|
<i class="fa-solid fa-paperclip"></i>
|
||||||
|
@ -157,20 +161,26 @@
|
||||||
<option value="Gemini">Gemini</option>
|
<option value="Gemini">Gemini</option>
|
||||||
<option value="Liaobots">Liaobots</option>
|
<option value="Liaobots">Liaobots</option>
|
||||||
<option value="Phind">Phind</option>
|
<option value="Phind">Phind</option>
|
||||||
|
<option value="You">You</option>
|
||||||
<option value="">----</option>
|
<option value="">----</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<input type="checkbox" id="switch" />
|
<input type="checkbox" id="switch" />
|
||||||
<label for="switch"></label>
|
<label for="switch" title="Add the pages of the first 5 search results to the query."></label>
|
||||||
<span class="about">Web Access</span>
|
<span class="about">Web Access</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<input type="checkbox" id="patch" />
|
<input type="checkbox" id="patch" />
|
||||||
<label for="patch" title="Works only with Bing and some other providers"></label>
|
<label for="patch" title="Enable create images with Bing."></label>
|
||||||
<span class="about">Image Generator</span>
|
<span class="about">Image Generator</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<input type="checkbox" id="history" />
|
||||||
|
<label for="history" title="To improve the reaction time or if you have trouble with large conversations."></label>
|
||||||
|
<span class="about">Disable History</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,6 +8,7 @@ const stop_generating = document.querySelector(`.stop_generating`);
|
||||||
const regenerate = document.querySelector(`.regenerate`);
|
const regenerate = document.querySelector(`.regenerate`);
|
||||||
const send_button = document.querySelector(`#send-button`);
|
const send_button = document.querySelector(`#send-button`);
|
||||||
const imageInput = document.querySelector('#image');
|
const imageInput = document.querySelector('#image');
|
||||||
|
const cameraInput = document.querySelector('#camera');
|
||||||
const fileInput = document.querySelector('#file');
|
const fileInput = document.querySelector('#file');
|
||||||
|
|
||||||
let prompt_lock = false;
|
let prompt_lock = false;
|
||||||
|
@ -63,6 +64,10 @@ const handle_ask = async () => {
|
||||||
? '<img src="' + imageInput.dataset.src + '" alt="Image upload">'
|
? '<img src="' + imageInput.dataset.src + '" alt="Image upload">'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
${cameraInput.dataset.src
|
||||||
|
? '<img src="' + cameraInput.dataset.src + '" alt="Image capture">'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -95,6 +100,11 @@ const ask_gpt = async () => {
|
||||||
delete messages[i]["provider"];
|
delete messages[i]["provider"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove history, if it is selected
|
||||||
|
if (document.getElementById('history')?.checked) {
|
||||||
|
messages = [messages[messages.length-1]]
|
||||||
|
}
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
window.controller = new AbortController();
|
window.controller = new AbortController();
|
||||||
|
|
||||||
|
@ -141,9 +151,10 @@ const ask_gpt = async () => {
|
||||||
const headers = {
|
const headers = {
|
||||||
accept: 'text/event-stream'
|
accept: 'text/event-stream'
|
||||||
}
|
}
|
||||||
if (imageInput && imageInput.files.length > 0) {
|
const input = imageInput && imageInput.files.length > 0 ? imageInput : cameraInput
|
||||||
|
if (input && input.files.length > 0) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('image', imageInput.files[0]);
|
formData.append('image', input.files[0]);
|
||||||
formData.append('json', body);
|
formData.append('json', body);
|
||||||
body = formData;
|
body = formData;
|
||||||
} else {
|
} else {
|
||||||
|
@ -211,8 +222,11 @@ const ask_gpt = async () => {
|
||||||
message_box.scrollTo({ top: message_box.scrollHeight, behavior: "auto" });
|
message_box.scrollTo({ top: message_box.scrollHeight, behavior: "auto" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!error && imageInput) imageInput.value = "";
|
if (!error) {
|
||||||
if (!error && fileInput) fileInput.value = "";
|
if (imageInput) imageInput.value = "";
|
||||||
|
if (cameraInput) cameraInput.value = "";
|
||||||
|
if (fileInput) fileInput.value = "";
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
||||||
|
@ -482,7 +496,7 @@ document.querySelector(".mobile-sidebar").addEventListener("click", (event) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const register_settings_localstorage = async () => {
|
const register_settings_localstorage = async () => {
|
||||||
for (id of ["switch", "model", "jailbreak", "patch", "provider"]) {
|
for (id of ["switch", "model", "jailbreak", "patch", "provider", "history"]) {
|
||||||
element = document.getElementById(id);
|
element = document.getElementById(id);
|
||||||
element.addEventListener('change', async (event) => {
|
element.addEventListener('change', async (event) => {
|
||||||
switch (event.target.type) {
|
switch (event.target.type) {
|
||||||
|
@ -500,7 +514,7 @@ const register_settings_localstorage = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const load_settings_localstorage = async () => {
|
const load_settings_localstorage = async () => {
|
||||||
for (id of ["switch", "model", "jailbreak", "patch", "provider"]) {
|
for (id of ["switch", "model", "jailbreak", "patch", "provider", "history"]) {
|
||||||
element = document.getElementById(id);
|
element = document.getElementById(id);
|
||||||
value = localStorage.getItem(element.id);
|
value = localStorage.getItem(element.id);
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -668,21 +682,26 @@ observer.observe(message_input, { attributes: true });
|
||||||
}
|
}
|
||||||
document.getElementById("version_text").innerHTML = text
|
document.getElementById("version_text").innerHTML = text
|
||||||
})()
|
})()
|
||||||
imageInput.addEventListener('click', async (event) => {
|
for (const el of [imageInput, cameraInput]) {
|
||||||
imageInput.value = '';
|
console.log(el.files);
|
||||||
|
el.addEventListener('click', async () => {
|
||||||
|
el.value = '';
|
||||||
|
delete el.dataset.src;
|
||||||
|
});
|
||||||
|
do_load = async () => {
|
||||||
|
if (el.files.length) {
|
||||||
delete imageInput.dataset.src;
|
delete imageInput.dataset.src;
|
||||||
});
|
delete cameraInput.dataset.src;
|
||||||
imageInput.addEventListener('change', async (event) => {
|
|
||||||
if (imageInput.files.length) {
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.addEventListener('load', (event) => {
|
reader.addEventListener('load', (event) => {
|
||||||
imageInput.dataset.src = event.target.result;
|
el.dataset.src = event.target.result;
|
||||||
});
|
});
|
||||||
reader.readAsDataURL(imageInput.files[0]);
|
reader.readAsDataURL(el.files[0]);
|
||||||
} else {
|
|
||||||
delete imageInput.dataset.src;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
do_load()
|
||||||
|
el.addEventListener('change', do_load);
|
||||||
|
}
|
||||||
fileInput.addEventListener('click', async (event) => {
|
fileInput.addEventListener('click', async (event) => {
|
||||||
fileInput.value = '';
|
fileInput.value = '';
|
||||||
delete fileInput.dataset.text;
|
delete fileInput.dataset.text;
|
||||||
|
|
|
@ -134,25 +134,31 @@ class Backend_Api:
|
||||||
dict: Arguments prepared for chat completion.
|
dict: Arguments prepared for chat completion.
|
||||||
"""
|
"""
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if 'image' in request.files:
|
if "image" in request.files:
|
||||||
file = request.files['image']
|
file = request.files['image']
|
||||||
if file.filename != '' and is_allowed_extension(file.filename):
|
if file.filename != '' and is_allowed_extension(file.filename):
|
||||||
kwargs['image'] = to_image(file.stream, file.filename.endswith('.svg'))
|
kwargs['image'] = to_image(file.stream, file.filename.endswith('.svg'))
|
||||||
if 'json' in request.form:
|
kwargs['image_name'] = file.filename
|
||||||
|
if "json" in request.form:
|
||||||
json_data = json.loads(request.form['json'])
|
json_data = json.loads(request.form['json'])
|
||||||
else:
|
else:
|
||||||
json_data = request.json
|
json_data = request.json
|
||||||
|
|
||||||
provider = json_data.get('provider', '').replace('g4f.Provider.', '')
|
provider = json_data.get('provider', '').replace('g4f.Provider.', '')
|
||||||
provider = provider if provider and provider != "Auto" else None
|
provider = provider if provider and provider != "Auto" else None
|
||||||
|
|
||||||
|
if "image" in kwargs and not provider:
|
||||||
|
provider = "Bing"
|
||||||
if provider == 'OpenaiChat':
|
if provider == 'OpenaiChat':
|
||||||
kwargs['auto_continue'] = True
|
kwargs['auto_continue'] = True
|
||||||
|
|
||||||
messages = json_data['messages']
|
messages = json_data['messages']
|
||||||
if json_data.get('web_search'):
|
if json_data.get('web_search'):
|
||||||
if provider == "Bing":
|
if provider == "Bing":
|
||||||
kwargs['web_search'] = True
|
kwargs['web_search'] = True
|
||||||
else:
|
else:
|
||||||
messages[-1]["content"] = get_search_message(messages[-1]["content"])
|
messages[-1]["content"] = get_search_message(messages[-1]["content"])
|
||||||
|
|
||||||
model = json_data.get('model')
|
model = json_data.get('model')
|
||||||
model = model if model else models.default
|
model = model if model else models.default
|
||||||
patch = patch_provider if json_data.get('patch_provider') else None
|
patch = patch_provider if json_data.get('patch_provider') else None
|
||||||
|
|
28
g4f/image.py
28
g4f/image.py
|
@ -137,12 +137,12 @@ def get_orientation(image: Image) -> int:
|
||||||
if orientation is not None:
|
if orientation is not None:
|
||||||
return orientation
|
return orientation
|
||||||
|
|
||||||
def process_image(img: Image, new_width: int, new_height: int) -> Image:
|
def process_image(image: Image, new_width: int, new_height: int) -> Image:
|
||||||
"""
|
"""
|
||||||
Processes the given image by adjusting its orientation and resizing it.
|
Processes the given image by adjusting its orientation and resizing it.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
img (Image): The image to process.
|
image (Image): The image to process.
|
||||||
new_width (int): The new width of the image.
|
new_width (int): The new width of the image.
|
||||||
new_height (int): The new height of the image.
|
new_height (int): The new height of the image.
|
||||||
|
|
||||||
|
@ -150,25 +150,27 @@ def process_image(img: Image, new_width: int, new_height: int) -> Image:
|
||||||
Image: The processed image.
|
Image: The processed image.
|
||||||
"""
|
"""
|
||||||
# Fix orientation
|
# Fix orientation
|
||||||
orientation = get_orientation(img)
|
orientation = get_orientation(image)
|
||||||
if orientation:
|
if orientation:
|
||||||
if orientation > 4:
|
if orientation > 4:
|
||||||
img = img.transpose(FLIP_LEFT_RIGHT)
|
image = image.transpose(FLIP_LEFT_RIGHT)
|
||||||
if orientation in [3, 4]:
|
if orientation in [3, 4]:
|
||||||
img = img.transpose(ROTATE_180)
|
image = image.transpose(ROTATE_180)
|
||||||
if orientation in [5, 6]:
|
if orientation in [5, 6]:
|
||||||
img = img.transpose(ROTATE_270)
|
image = image.transpose(ROTATE_270)
|
||||||
if orientation in [7, 8]:
|
if orientation in [7, 8]:
|
||||||
img = img.transpose(ROTATE_90)
|
image = image.transpose(ROTATE_90)
|
||||||
# Resize image
|
# Resize image
|
||||||
img.thumbnail((new_width, new_height))
|
image.thumbnail((new_width, new_height))
|
||||||
# Remove transparency
|
# Remove transparency
|
||||||
if img.mode == "RGBA":
|
if image.mode == "RGBA":
|
||||||
img.load()
|
image.load()
|
||||||
white = new_image('RGB', img.size, (255, 255, 255))
|
white = new_image('RGB', image.size, (255, 255, 255))
|
||||||
white.paste(img, mask=img.split()[-1])
|
white.paste(image, mask=image.split()[-1])
|
||||||
return white
|
return white
|
||||||
return img
|
elif image.mode != "RGB":
|
||||||
|
image = image.convert("RGB")
|
||||||
|
return image
|
||||||
|
|
||||||
def to_base64_jpg(image: Image, compression_rate: float) -> str:
|
def to_base64_jpg(image: Image, compression_rate: float) -> str:
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue