ShynBui commited on
Commit
ad17f03
·
1 Parent(s): 6a6eb0b

first commit

Browse files
Files changed (6) hide show
  1. .gitignore +162 -0
  2. app.py +14 -0
  3. pkgs/__init__.py +9 -0
  4. pkgs/excecutor.py +216 -0
  5. pkgs/quota_manager.py +139 -0
  6. 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