Spaces:
Sleeping
Sleeping
first commit
Browse files- .gitignore +162 -0
- app.py +14 -0
- pkgs/__init__.py +9 -0
- pkgs/excecutor.py +216 -0
- pkgs/quota_manager.py +139 -0
- utils.py +37 -0
.gitignore
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
share/python-wheels/
|
24 |
+
*.egg-info/
|
25 |
+
.installed.cfg
|
26 |
+
*.egg
|
27 |
+
MANIFEST
|
28 |
+
|
29 |
+
# PyInstaller
|
30 |
+
# Usually these files are written by a python script from a template
|
31 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
32 |
+
*.manifest
|
33 |
+
*.spec
|
34 |
+
|
35 |
+
# Installer logs
|
36 |
+
pip-log.txt
|
37 |
+
pip-delete-this-directory.txt
|
38 |
+
|
39 |
+
# Unit test / coverage reports
|
40 |
+
htmlcov/
|
41 |
+
.tox/
|
42 |
+
.nox/
|
43 |
+
.coverage
|
44 |
+
.coverage.*
|
45 |
+
.cache
|
46 |
+
nosetests.xml
|
47 |
+
coverage.xml
|
48 |
+
*.cover
|
49 |
+
*.py,cover
|
50 |
+
.hypothesis/
|
51 |
+
.pytest_cache/
|
52 |
+
cover/
|
53 |
+
|
54 |
+
# Translations
|
55 |
+
*.mo
|
56 |
+
*.pot
|
57 |
+
|
58 |
+
# Django stuff:
|
59 |
+
*.log
|
60 |
+
local_settings.py
|
61 |
+
db.sqlite3
|
62 |
+
db.sqlite3-journal
|
63 |
+
|
64 |
+
# Flask stuff:
|
65 |
+
instance/
|
66 |
+
.webassets-cache
|
67 |
+
|
68 |
+
# Scrapy stuff:
|
69 |
+
.scrapy
|
70 |
+
|
71 |
+
# Sphinx documentation
|
72 |
+
docs/_build/
|
73 |
+
|
74 |
+
# PyBuilder
|
75 |
+
.pybuilder/
|
76 |
+
target/
|
77 |
+
|
78 |
+
# Jupyter Notebook
|
79 |
+
.ipynb_checkpoints
|
80 |
+
|
81 |
+
# IPython
|
82 |
+
profile_default/
|
83 |
+
ipython_config.py
|
84 |
+
|
85 |
+
# pyenv
|
86 |
+
# For a library or package, you might want to ignore these files since the code is
|
87 |
+
# intended to run in multiple environments; otherwise, check them in:
|
88 |
+
# .python-version
|
89 |
+
|
90 |
+
# pipenv
|
91 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
92 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
93 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
94 |
+
# install all needed dependencies.
|
95 |
+
#Pipfile.lock
|
96 |
+
|
97 |
+
# poetry
|
98 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
99 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
100 |
+
# commonly ignored for libraries.
|
101 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
102 |
+
#poetry.lock
|
103 |
+
|
104 |
+
# pdm
|
105 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
106 |
+
#pdm.lock
|
107 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
108 |
+
# in version control.
|
109 |
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
110 |
+
.pdm.toml
|
111 |
+
.pdm-python
|
112 |
+
.pdm-build/
|
113 |
+
|
114 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
115 |
+
__pypackages__/
|
116 |
+
|
117 |
+
# Celery stuff
|
118 |
+
celerybeat-schedule
|
119 |
+
celerybeat.pid
|
120 |
+
|
121 |
+
# SageMath parsed files
|
122 |
+
*.sage.py
|
123 |
+
|
124 |
+
# Environments
|
125 |
+
.env
|
126 |
+
.venv
|
127 |
+
env/
|
128 |
+
venv/
|
129 |
+
ENV/
|
130 |
+
env.bak/
|
131 |
+
venv.bak/
|
132 |
+
|
133 |
+
# Spyder project settings
|
134 |
+
.spyderproject
|
135 |
+
.spyproject
|
136 |
+
|
137 |
+
# Rope project settings
|
138 |
+
.ropeproject
|
139 |
+
|
140 |
+
# mkdocs documentation
|
141 |
+
/site
|
142 |
+
|
143 |
+
# mypy
|
144 |
+
.mypy_cache/
|
145 |
+
.dmypy.json
|
146 |
+
dmypy.json
|
147 |
+
|
148 |
+
# Pyre type checker
|
149 |
+
.pyre/
|
150 |
+
|
151 |
+
# pytype static type analyzer
|
152 |
+
.pytype/
|
153 |
+
|
154 |
+
# Cython debug symbols
|
155 |
+
cython_debug/
|
156 |
+
|
157 |
+
# PyCharm
|
158 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
159 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
160 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
161 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
162 |
+
#.idea/
|
app.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from utils import *
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
gradio_app = gr.Interface(
|
7 |
+
answer,
|
8 |
+
inputs= gr.Image(label="Input Image", sources=['upload', 'webcam'], type="pil"),
|
9 |
+
outputs= gr.Text(),
|
10 |
+
title="Describe things",
|
11 |
+
)
|
12 |
+
|
13 |
+
if __name__ == '__main__':
|
14 |
+
gradio_app.launch(share=True)
|
pkgs/__init__.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .excecutor import LangChainExecutor
|
2 |
+
from .quota_manager import QuotaManager
|
3 |
+
import os
|
4 |
+
from dotenv import load_dotenv
|
5 |
+
|
6 |
+
|
7 |
+
|
8 |
+
load_dotenv()
|
9 |
+
executor = QuotaManager(model_name='gemini-1.5-flash', api_keys= eval(os.getenv('LIST_GEMINI_API_KEY')))
|
pkgs/excecutor.py
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
2 |
+
from langchain_core.prompts import ChatPromptTemplate
|
3 |
+
from langchain_core.output_parsers import StrOutputParser, SimpleJsonOutputParser
|
4 |
+
from langchain_openai import ChatOpenAI
|
5 |
+
import re
|
6 |
+
|
7 |
+
import concurrent.futures
|
8 |
+
import copy
|
9 |
+
import os
|
10 |
+
|
11 |
+
class LangChainExecutor:
|
12 |
+
def __init__(self, model_name):
|
13 |
+
self.model_name = model_name
|
14 |
+
self.platform = 'gpt' if 'gpt' in model_name else 'gemini'
|
15 |
+
self.api_key = os.getenv("OPEN_AI_API_KEY") if self.platform == "gpt" else os.getenv("GEMINI_API_KEY")
|
16 |
+
if self.platform == "gpt":
|
17 |
+
self.default_config = {
|
18 |
+
"temperature": 1,
|
19 |
+
"max_tokens": None,
|
20 |
+
}
|
21 |
+
elif self.platform == "gemini":
|
22 |
+
self.default_config = {
|
23 |
+
"temperature": 1,
|
24 |
+
"top_p": 0.95,
|
25 |
+
"top_k": 64,
|
26 |
+
"max_output_tokens": 8192,
|
27 |
+
}
|
28 |
+
|
29 |
+
def create_model(self, model_name, cp_config):
|
30 |
+
# redefine by model_name
|
31 |
+
self.platform = 'gpt' if 'gpt' in model_name else 'gemini'
|
32 |
+
self.api_key = os.getenv("OPEN_AI_API_KEY") if self.platform == "gpt" else os.getenv("GEMINI_API_KEY")
|
33 |
+
if self.platform == "gpt":
|
34 |
+
self.default_config = {
|
35 |
+
"temperature": 1,
|
36 |
+
"max_tokens": None,
|
37 |
+
}
|
38 |
+
elif self.platform == "gemini":
|
39 |
+
self.default_config = {
|
40 |
+
"temperature": 1,
|
41 |
+
"top_p": 0.95,
|
42 |
+
"top_k": 64,
|
43 |
+
"max_output_tokens": None,
|
44 |
+
}
|
45 |
+
|
46 |
+
if self.platform == "gpt":
|
47 |
+
return ChatOpenAI(
|
48 |
+
model=model_name,
|
49 |
+
api_key=self.api_key,
|
50 |
+
temperature=cp_config["temperature"],
|
51 |
+
max_tokens=cp_config.get("max_tokens")
|
52 |
+
)
|
53 |
+
elif self.platform == "gemini":
|
54 |
+
return ChatGoogleGenerativeAI(
|
55 |
+
model=model_name,
|
56 |
+
google_api_key=self.api_key,
|
57 |
+
temperature=cp_config["temperature"],
|
58 |
+
top_p=cp_config.get("top_p"),
|
59 |
+
top_k=cp_config.get("top_k"),
|
60 |
+
max_output_tokens=cp_config.get("max_output_tokens")
|
61 |
+
)
|
62 |
+
|
63 |
+
def clean_response(self, response):
|
64 |
+
if response.startswith("```") and response.endswith("```"):
|
65 |
+
pattern = r'^(?:```json|```csv|```)\s*(.*?)\s*```$'
|
66 |
+
return re.sub(pattern, r'\1', response, flags=re.DOTALL).strip()
|
67 |
+
return response.strip()
|
68 |
+
|
69 |
+
def execute(self, model_input, user_input, model_name="", temperature=0, prefix=None, infix=None, suffix=None, json_output=False):
|
70 |
+
cp_config = copy.deepcopy(self.default_config)
|
71 |
+
cp_config["temperature"] = temperature
|
72 |
+
if model_name == "":
|
73 |
+
model_name = self.model_name
|
74 |
+
|
75 |
+
model = self.create_model(model_name, cp_config)
|
76 |
+
|
77 |
+
full_prompt_parts = []
|
78 |
+
|
79 |
+
if prefix:
|
80 |
+
full_prompt_parts.append(prefix)
|
81 |
+
if infix:
|
82 |
+
full_prompt_parts.append(infix)
|
83 |
+
full_prompt_parts.append(model_input)
|
84 |
+
if suffix:
|
85 |
+
full_prompt_parts.append(suffix)
|
86 |
+
|
87 |
+
# Kết hợp các phần thành một chuỗi duy nhất
|
88 |
+
full_prompt = "\n".join(full_prompt_parts)
|
89 |
+
|
90 |
+
chat_template = ChatPromptTemplate.from_messages(
|
91 |
+
[
|
92 |
+
("system", "{full_prompt}"),
|
93 |
+
("human", "{user_input}"),
|
94 |
+
]
|
95 |
+
)
|
96 |
+
|
97 |
+
if json_output:
|
98 |
+
parser = SimpleJsonOutputParser()
|
99 |
+
else:
|
100 |
+
parser = StrOutputParser()
|
101 |
+
|
102 |
+
run_chain = chat_template | model | parser
|
103 |
+
|
104 |
+
map_args = {
|
105 |
+
"full_prompt": full_prompt,
|
106 |
+
"user_input": user_input,
|
107 |
+
}
|
108 |
+
response = run_chain.invoke(map_args)
|
109 |
+
|
110 |
+
if json_output == False:
|
111 |
+
# print('Yess')
|
112 |
+
response = self.clean_response(response)
|
113 |
+
|
114 |
+
# print("Nooo")
|
115 |
+
|
116 |
+
return response
|
117 |
+
|
118 |
+
def execute_with_image(self, model_input, user_input, base64_image, model_name="", temperature=0, prefix=None, infix=None, suffix=None, json_output=False):
|
119 |
+
|
120 |
+
full_prompt_parts = []
|
121 |
+
if prefix:
|
122 |
+
full_prompt_parts.append(prefix)
|
123 |
+
if infix:
|
124 |
+
full_prompt_parts.append(infix)
|
125 |
+
full_prompt_parts.append(model_input)
|
126 |
+
if suffix:
|
127 |
+
full_prompt_parts.append(suffix)
|
128 |
+
|
129 |
+
# Kết hợp các phần thành một chuỗi duy nhất
|
130 |
+
full_prompt = "\n".join(full_prompt_parts)
|
131 |
+
|
132 |
+
|
133 |
+
prompt = ChatPromptTemplate.from_messages(
|
134 |
+
[
|
135 |
+
("system", "{full_prompt}\n{user_input}"),
|
136 |
+
(
|
137 |
+
"user",
|
138 |
+
[
|
139 |
+
{
|
140 |
+
"type": "image_url",
|
141 |
+
"image_url": {"url": "data:image/jpeg;base64,{image_data}"},
|
142 |
+
}
|
143 |
+
],
|
144 |
+
),
|
145 |
+
]
|
146 |
+
)
|
147 |
+
|
148 |
+
cp_config = copy.deepcopy(self.default_config)
|
149 |
+
cp_config["temperature"] = temperature
|
150 |
+
if model_name == "":
|
151 |
+
model_name = self.model_name
|
152 |
+
|
153 |
+
model = self.create_model(model_name, cp_config)
|
154 |
+
|
155 |
+
if json_output:
|
156 |
+
parser = SimpleJsonOutputParser()
|
157 |
+
else:
|
158 |
+
parser = StrOutputParser()
|
159 |
+
|
160 |
+
run_chain = prompt | model | parser
|
161 |
+
|
162 |
+
response = run_chain.invoke({
|
163 |
+
"image_data": base64_image,
|
164 |
+
"full_prompt": full_prompt,
|
165 |
+
"user_input": user_input
|
166 |
+
})
|
167 |
+
|
168 |
+
if json_output == False:
|
169 |
+
# print('Yess')
|
170 |
+
response = self.clean_response(response)
|
171 |
+
|
172 |
+
# print("Nooo")
|
173 |
+
|
174 |
+
return response
|
175 |
+
|
176 |
+
def batch_execute(self, requests):
|
177 |
+
"""
|
178 |
+
Execute multiple requests in parallel for both `execute` and `execute_with_image`.
|
179 |
+
|
180 |
+
Args:
|
181 |
+
requests (list of dict): List of requests, each containing `model_input`, `user_input`,
|
182 |
+
and optionally `model_name`, `temperature`, and `base64_image`.
|
183 |
+
|
184 |
+
Returns:
|
185 |
+
list of str: List of responses for each request, mapped correctly to their input.
|
186 |
+
"""
|
187 |
+
responses = [None] * len(requests)
|
188 |
+
|
189 |
+
def process_request(index, request):
|
190 |
+
model_input = request.get("model_input", "")
|
191 |
+
user_input = request.get("user_input", "")
|
192 |
+
prefix = request.get("prefix", None)
|
193 |
+
infix = request.get("infix", None)
|
194 |
+
suffix = request.get("suffix", None)
|
195 |
+
model_name = request.get("model_name", self.model_name)
|
196 |
+
temperature = request.get("temperature", 0)
|
197 |
+
base64_image = request.get("base64_image", None)
|
198 |
+
|
199 |
+
if base64_image:
|
200 |
+
result = self.execute_with_image(model_input, user_input, base64_image, model_name, temperature, prefix, infix, suffix)
|
201 |
+
else:
|
202 |
+
result = self.execute(model_input, user_input, model_name, temperature, prefix, infix, suffix)
|
203 |
+
|
204 |
+
responses[index] = result
|
205 |
+
|
206 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
207 |
+
futures = {executor.submit(process_request, i, request): i for i, request in enumerate(requests)}
|
208 |
+
|
209 |
+
for future in concurrent.futures.as_completed(futures):
|
210 |
+
index = futures[future]
|
211 |
+
try:
|
212 |
+
future.result()
|
213 |
+
except Exception as exc:
|
214 |
+
responses[index] = f"Exception occurred: {exc}"
|
215 |
+
|
216 |
+
return responses
|
pkgs/quota_manager.py
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
import os
|
3 |
+
import copy
|
4 |
+
import concurrent.futures
|
5 |
+
from pkgs import LangChainExecutor
|
6 |
+
|
7 |
+
|
8 |
+
class QuotaManager(LangChainExecutor):
|
9 |
+
def __init__(self, model_name, api_keys):
|
10 |
+
"""
|
11 |
+
Khởi tạo QuotaManager với danh sách các API key.
|
12 |
+
|
13 |
+
:param model_name: Tên của mô hình LLM. #gpt-... pr gemini-...
|
14 |
+
:param api_keys: Danh sách các API key.
|
15 |
+
"""
|
16 |
+
self.api_keys = api_keys
|
17 |
+
self.current_key_index = 0
|
18 |
+
self.last_used_time = time.time()
|
19 |
+
super().__init__(model_name)
|
20 |
+
self.update_api_key()
|
21 |
+
|
22 |
+
def update_api_key(self):
|
23 |
+
"""
|
24 |
+
Cập nhật API key hiện tại từ danh sách.
|
25 |
+
"""
|
26 |
+
self.api_key = self.api_keys[self.current_key_index]
|
27 |
+
os.environ["GEMINI_API_KEY"] = self.api_key
|
28 |
+
print(f"Đang sử dụng API key: {self.api_key}")
|
29 |
+
|
30 |
+
def rotate_api_key(self):
|
31 |
+
"""
|
32 |
+
Xoay vòng sang API key tiếp theo khi API key hiện tại bị giới hạn.
|
33 |
+
"""
|
34 |
+
current_time = time.time()
|
35 |
+
|
36 |
+
# Kiểm tra thời gian, nếu đã qua 60 giây kể từ lần sử dụng cuối, đặt lại chỉ số key
|
37 |
+
if current_time - self.last_used_time >= 60:
|
38 |
+
self.current_key_index = 0
|
39 |
+
else:
|
40 |
+
# Chuyển sang API key tiếp theo
|
41 |
+
self.current_key_index = (self.current_key_index + 1) % len(self.api_keys)
|
42 |
+
|
43 |
+
self.update_api_key()
|
44 |
+
self.last_used_time = current_time
|
45 |
+
|
46 |
+
def execute(self, model_input, user_input, model_name="", temperature=0, prefix=None, infix=None, suffix=None,
|
47 |
+
json_output=False):
|
48 |
+
"""
|
49 |
+
Thực thi yêu cầu với kiểm tra và thay đổi API key nếu cần thiết.
|
50 |
+
|
51 |
+
:param model_input: Đầu vào cho mô hình.
|
52 |
+
:param user_input: Đầu vào từ người dùng.
|
53 |
+
:param model_name: Tên mô hình (tuỳ chọn).
|
54 |
+
:param temperature: Nhiệt độ điều chỉnh tính ngẫu nhiên của mô hình.
|
55 |
+
:param prefix: Chuỗi tiền tố tuỳ chọn.
|
56 |
+
:param infix: Chuỗi xen giữa tuỳ chọn.
|
57 |
+
:param suffix: Chuỗi hậu tố tuỳ chọn.
|
58 |
+
:param json_output: Cờ để xác định có trả về kết quả JSON hay không.
|
59 |
+
:return: Kết quả từ mô hình.
|
60 |
+
"""
|
61 |
+
try:
|
62 |
+
return super().execute(model_input, user_input, model_name, temperature, prefix, infix, suffix, json_output)
|
63 |
+
except Exception as e:
|
64 |
+
if "Resource has been exhausted" in str(e):
|
65 |
+
print("Lỗi:", e)
|
66 |
+
print(f"API key bị giới hạn: {self.api_key}. Đang chuyển sang API key khác...")
|
67 |
+
self.rotate_api_key()
|
68 |
+
return super().execute(model_input, user_input, model_name, temperature, prefix, infix, suffix,
|
69 |
+
json_output)
|
70 |
+
else:
|
71 |
+
print("Lỗi:", e)
|
72 |
+
raise e
|
73 |
+
|
74 |
+
def execute_with_image(self, model_input, user_input, base64_image, model_name="", temperature=0, prefix=None,
|
75 |
+
infix=None, suffix=None, json_output=False):
|
76 |
+
"""
|
77 |
+
Thực thi yêu cầu với ảnh, kiểm tra và thay đổi API key nếu cần thiết.
|
78 |
+
|
79 |
+
:param model_input: Đầu vào cho mô hình.
|
80 |
+
:param user_input: Đầu vào từ người dùng.
|
81 |
+
:param base64_image: Ảnh được mã hóa base64.
|
82 |
+
:param model_name: Tên mô hình (tuỳ chọn).
|
83 |
+
:param temperature: Nhiệt độ điều chỉnh tính ngẫu nhiên của mô hình.
|
84 |
+
:param prefix: Chuỗi tiền tố tuỳ chọn.
|
85 |
+
:param infix: Chuỗi xen giữa tuỳ chọn.
|
86 |
+
:param suffix: Chuỗi hậu tố tuỳ chọn.
|
87 |
+
:param json_output: Cờ để xác định có trả về kết quả JSON hay không.
|
88 |
+
:return: Kết quả từ mô hình.
|
89 |
+
"""
|
90 |
+
try:
|
91 |
+
return super().execute_with_image(model_input, user_input, base64_image, model_name, temperature, prefix,
|
92 |
+
infix, suffix, json_output)
|
93 |
+
except Exception as e:
|
94 |
+
if "Resource has been exhausted" in str(e):
|
95 |
+
print(f"API key bị giới hạn: {self.api_key}. Đang chuyển sang API key khác...")
|
96 |
+
self.rotate_api_key()
|
97 |
+
return super().execute_with_image(model_input, user_input, base64_image, model_name, temperature,
|
98 |
+
prefix, infix, suffix, json_output)
|
99 |
+
else:
|
100 |
+
raise e
|
101 |
+
|
102 |
+
def batch_execute(self, requests):
|
103 |
+
"""
|
104 |
+
Thực thi nhiều yêu cầu song song với việc kiểm tra và thay đổi API key nếu cần thiết.
|
105 |
+
|
106 |
+
:param requests: Danh sách các yêu cầu.
|
107 |
+
:return: Danh sách các phản hồi, tương ứng với từng yêu cầu.
|
108 |
+
"""
|
109 |
+
responses = [None] * len(requests)
|
110 |
+
|
111 |
+
def process_request(index, request):
|
112 |
+
model_input = request.get("model_input", "")
|
113 |
+
user_input = request.get("user_input", "")
|
114 |
+
prefix = request.get("prefix", None)
|
115 |
+
infix = request.get("infix", None)
|
116 |
+
suffix = request.get("suffix", None)
|
117 |
+
model_name = request.get("model_name", self.model_name)
|
118 |
+
temperature = request.get("temperature", 0)
|
119 |
+
base64_image = request.get("base64_image", None)
|
120 |
+
|
121 |
+
if base64_image:
|
122 |
+
result = self.execute_with_image(model_input, user_input, base64_image, model_name, temperature, prefix,
|
123 |
+
infix, suffix)
|
124 |
+
else:
|
125 |
+
result = self.execute(model_input, user_input, model_name, temperature, prefix, infix, suffix)
|
126 |
+
|
127 |
+
responses[index] = result
|
128 |
+
|
129 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
130 |
+
futures = {executor.submit(process_request, i, request): i for i, request in enumerate(requests)}
|
131 |
+
|
132 |
+
for future in concurrent.futures.as_completed(futures):
|
133 |
+
index = futures[future]
|
134 |
+
try:
|
135 |
+
future.result()
|
136 |
+
except Exception as exc:
|
137 |
+
responses[index] = f"Exception occurred: {exc}"
|
138 |
+
|
139 |
+
return responses
|
utils.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pkgs import QuotaManager, executor
|
2 |
+
import os
|
3 |
+
import base64
|
4 |
+
from PIL import Image
|
5 |
+
import io
|
6 |
+
|
7 |
+
os.environ['PROMPT'] = '''
|
8 |
+
Nhận vào một hình ảnh từ người dùng. Hãy phân tích và cung cấp một mô tả chi tiết về hình ảnh này giống như một mục từ trong quyển bách khoa toàn thư. Mô tả bao gồm các thành phần sau:
|
9 |
+
|
10 |
+
1.Tên đồ vật trong ảnh:
|
11 |
+
- Liệt kê tất cả các đồ vật, sinh vật, hoặc yếu tố chính xuất hiện trong hình ảnh. Mỗi đối tượng phải được đặt tên rõ ràng và cụ thể.
|
12 |
+
2. Mô tả chi tiết đồ vật:
|
13 |
+
- Mô tả kỹ lưỡng từng đồ vật, sinh vật hoặc yếu tố đã được liệt kê. Bao gồm các thông tin về:
|
14 |
+
+ Kích thước: Đánh giá kích thước tương đối hoặc tuyệt đối của đồ vật.
|
15 |
+
+ Hình dáng: Mô tả hình dạng, cấu trúc, và các đặc điểm nhận dạng.
|
16 |
+
+ Màu sắc: Cung cấp thông tin về màu sắc chính và các biến thể màu sắc nếu có.
|
17 |
+
+ Chất liệu: Mô tả vật liệu cấu thành, nếu có thể xác định.
|
18 |
+
+ Chức năng hoặc vai trò: Giải thích chức năng, vai trò hoặc ý nghĩa của đồ vật hoặc sinh vật trong ngữ cảnh của hình ảnh.
|
19 |
+
3. Bối cảnh và không gian:
|
20 |
+
- Mô tả không gian chung của hình ảnh, bao gồm môi trường xung quanh và cách các đồ vật, sinh vật tương tác hoặc được sắp đặt trong không gian này.
|
21 |
+
- Nếu hình ảnh liên quan đến một địa điểm, thời gian, hoặc sự kiện cụ thể, hãy mô tả ngắn gọn về ngữ cảnh đó.
|
22 |
+
4. Liên hệ văn hóa hoặc lịch sử:
|
23 |
+
- Nếu các đồ vật hoặc sinh vật có liên hệ đến các khái niệm, sự kiện, hoặc hiện tượng văn hóa, lịch sử nào, hãy cung cấp một đoạn mô tả ngắn gọn về liên hệ đó.
|
24 |
+
5. Tầm quan trọng hoặc ứng dụng:
|
25 |
+
- Nêu rõ tầm quan trọng của các đồ vật hoặc sinh vật trong hình ảnh. Điều này có thể bao gồm ý nghĩa văn hóa, giá trị thực tiễn, hoặc ứng dụng cụ thể trong đời sống hoặc trong nghiên cứu khoa học."
|
26 |
+
6. Trình bày rõ ràng.
|
27 |
+
'''
|
28 |
+
|
29 |
+
def answer(input_img):
|
30 |
+
buffer = io.BytesIO()
|
31 |
+
input_img.save(buffer, format="PNG")
|
32 |
+
image_data = base64.b64encode(buffer.getvalue()).decode('utf-8')
|
33 |
+
# print(os.getenv('PROMPT'))
|
34 |
+
|
35 |
+
respose = executor.execute_with_image(user_input= '', model_input= os.getenv('PROMPT'), base64_image=image_data)
|
36 |
+
|
37 |
+
return respose
|