Beta version
Browse files
app.py
ADDED
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import requests
|
3 |
+
from PIL import Image
|
4 |
+
from pdf2image import convert_from_path
|
5 |
+
from typing import List, Union, Dict, Optional, Tuple
|
6 |
+
from io import BytesIO
|
7 |
+
import base64
|
8 |
+
import numpy as np
|
9 |
+
import json
|
10 |
+
|
11 |
+
prompt = """You are an advanced document parsing bot. Given the fixture schedule I provided, you need to parse out
|
12 |
+
|
13 |
+
1. the name of the fixture
|
14 |
+
2. the company that produces this fixture
|
15 |
+
3. the part number of this fixture. It is a series of specification codes connected with - , and you can get the info by reading the texts marked in a different color or reading the top bar. Include every specification code in a correct order in your answer.
|
16 |
+
4. the input wattage of this fixture, short answer. Please answer the wattage according to the part number you found in question 3
|
17 |
+
|
18 |
+
Please format your response in json format
|
19 |
+
{
|
20 |
+
"fixture_name": <fixture name>,
|
21 |
+
"manufacture_name": <company name>,
|
22 |
+
"mfr": <part number>,
|
23 |
+
"input wattage": <numerical input wattage>
|
24 |
+
}
|
25 |
+
|
26 |
+
---
|
27 |
+
For example
|
28 |
+
{
|
29 |
+
"fixture_name": "SW24/1.5 Led Strips - Static White",
|
30 |
+
"manufacture_name": "Q-Tran Inc.",
|
31 |
+
"mfr": "SW24-1.5-DRY-30-BW-BW-WH-CL2-535",
|
32 |
+
"input wattage": "1.5W"
|
33 |
+
}"""
|
34 |
+
|
35 |
+
def query_openai_api(messages, model, temperature=0, api_key=None, organization_key=None, json_mode=False):
|
36 |
+
try:
|
37 |
+
url = "https://api.openai.com/v1/chat/completions"
|
38 |
+
if organization_key is not None:
|
39 |
+
headers = {
|
40 |
+
"Content-Type": "application/json",
|
41 |
+
"Authorization": f"Bearer {api_key}",
|
42 |
+
"OpenAI-Organization": f"{organization_key}",
|
43 |
+
}
|
44 |
+
else:
|
45 |
+
headers = {
|
46 |
+
"Content-Type": "application/json",
|
47 |
+
"Authorization": f"Bearer {api_key}",
|
48 |
+
}
|
49 |
+
data = {"model": model, "messages": messages, "temperature": temperature}
|
50 |
+
if json_mode:
|
51 |
+
data["response_format"] = {"type": "json_object"}
|
52 |
+
|
53 |
+
# Make the POST request and return the response
|
54 |
+
response = requests.post(url, headers=headers, data=json.dumps(data)).json()
|
55 |
+
print(response)
|
56 |
+
return response["choices"][0]["message"]["content"].lstrip(), response
|
57 |
+
except Exception as e:
|
58 |
+
print(f"An error occurred: {e}")
|
59 |
+
return f"API_ERROR: {e}", None
|
60 |
+
|
61 |
+
class GPT4V_Client:
|
62 |
+
def __init__(self, api_key, organization_key, model_name="gpt-4-vision-preview", max_tokens=512):
|
63 |
+
self.api_key = api_key
|
64 |
+
self.organization_key = organization_key
|
65 |
+
# self.client = OpenAI(api_key=api_key)
|
66 |
+
self.model_name = model_name
|
67 |
+
self.max_tokens = max_tokens
|
68 |
+
|
69 |
+
def chat(self, messages, json_mode):
|
70 |
+
return query_openai_api(messages, self.model_name, api_key=self.api_key, organization_key=self.organization_key, json_mode=json_mode)
|
71 |
+
|
72 |
+
def one_step_chat(
|
73 |
+
self,
|
74 |
+
text,
|
75 |
+
image: Union[Image.Image, np.ndarray],
|
76 |
+
system_msg: Optional[str] = None,
|
77 |
+
json_mode=False,
|
78 |
+
):
|
79 |
+
jpeg_buffer = BytesIO()
|
80 |
+
|
81 |
+
# Save the image as JPEG to the buffer
|
82 |
+
if isinstance(image, np.ndarray):
|
83 |
+
image = Image.fromarray(image)
|
84 |
+
image = image.convert("RGB")
|
85 |
+
image.save(jpeg_buffer, format="JPEG")
|
86 |
+
|
87 |
+
# Get the byte data from the buffer
|
88 |
+
jpeg_data = jpeg_buffer.getvalue()
|
89 |
+
|
90 |
+
# Encode the JPEG image data in base64
|
91 |
+
jpg_base64 = base64.b64encode(jpeg_data)
|
92 |
+
|
93 |
+
# If you need it in string format
|
94 |
+
jpg_base64_str = jpg_base64.decode("utf-8")
|
95 |
+
messages = []
|
96 |
+
if system_msg is not None:
|
97 |
+
messages.append({"role": "system", "content": system_msg})
|
98 |
+
messages += [
|
99 |
+
{
|
100 |
+
"role": "user",
|
101 |
+
"content": [
|
102 |
+
{"type": "text", "text": text},
|
103 |
+
{
|
104 |
+
"type": "image_url",
|
105 |
+
"image_url": {
|
106 |
+
"url": f"data:image/jpeg;base64,{jpg_base64_str}"
|
107 |
+
},
|
108 |
+
},
|
109 |
+
],
|
110 |
+
}
|
111 |
+
]
|
112 |
+
return self.chat(messages, json_mode=json_mode)
|
113 |
+
|
114 |
+
def one_step_multi_image_chat(
|
115 |
+
self,
|
116 |
+
text,
|
117 |
+
images: list[Union[Image.Image, np.ndarray]],
|
118 |
+
system_msg: Optional[str] = None,
|
119 |
+
json_mode=False,
|
120 |
+
):
|
121 |
+
"""
|
122 |
+
images: [{"image": PIL.image, "detail": "high" or "low }]
|
123 |
+
|
124 |
+
For low res mode, we expect a 512px x 512px image. For high res mode, the short side of the image should be less than 768px and the long side should be less than 2,000px.
|
125 |
+
"""
|
126 |
+
details = [i["detail"] for i in images]
|
127 |
+
img_strs = []
|
128 |
+
for img_info in images:
|
129 |
+
image = img_info["image"]
|
130 |
+
jpeg_buffer = BytesIO()
|
131 |
+
|
132 |
+
# Save the image as JPEG to the buffer
|
133 |
+
if isinstance(image, np.ndarray):
|
134 |
+
image = Image.fromarray(image)
|
135 |
+
image = image.convert("RGB")
|
136 |
+
image.save(jpeg_buffer, format="JPEG")
|
137 |
+
|
138 |
+
# Get the byte data from the buffer
|
139 |
+
jpeg_data = jpeg_buffer.getvalue()
|
140 |
+
|
141 |
+
# Encode the JPEG image data in base64
|
142 |
+
jpg_base64 = base64.b64encode(jpeg_data)
|
143 |
+
|
144 |
+
# If you need it in string format
|
145 |
+
jpg_base64_str = jpg_base64.decode("utf-8")
|
146 |
+
img_strs.append(f"data:image/jpeg;base64,{jpg_base64_str}")
|
147 |
+
messages = []
|
148 |
+
if system_msg is not None:
|
149 |
+
messages.append({"role": "system", "content": system_msg})
|
150 |
+
|
151 |
+
img_sub_msg = [
|
152 |
+
{
|
153 |
+
"type": "image_url",
|
154 |
+
"image_url": {"url": img_str, "detail": detail},
|
155 |
+
}
|
156 |
+
for img_str, detail in zip(img_strs, details)
|
157 |
+
]
|
158 |
+
messages += [
|
159 |
+
{
|
160 |
+
"role": "user",
|
161 |
+
"content": [
|
162 |
+
{"type": "text", "text": text},
|
163 |
+
]
|
164 |
+
+ img_sub_msg,
|
165 |
+
}
|
166 |
+
]
|
167 |
+
return self.chat(messages, json_mode=json_mode)
|
168 |
+
|
169 |
+
def markdown_json_to_table(markdown_json_string, iteration):
|
170 |
+
if markdown_json_string[0] == '`':
|
171 |
+
json_string = markdown_json_string.strip("```json\n").rstrip("```")
|
172 |
+
json_object = json.loads(json_string)
|
173 |
+
values = json_object.values()
|
174 |
+
if iteration == 0:
|
175 |
+
headers = json_object.keys()
|
176 |
+
markdown_table = "| " + " | ".join(headers) + " |\n" + \
|
177 |
+
"|---" * len(json_object) + "|\n" + \
|
178 |
+
"| " + " | ".join(map(str, values)) + " |"
|
179 |
+
else:
|
180 |
+
markdown_table = "|---" * len(json_object) + "|\n" + \
|
181 |
+
"| " + " | ".join(map(str, values)) + " |"
|
182 |
+
else:
|
183 |
+
markdown_table = ""
|
184 |
+
return markdown_table
|
185 |
+
|
186 |
+
def gptRead(cutsheets, api_key, organization_key):
|
187 |
+
fixtureInfo = ""
|
188 |
+
iteration = 0
|
189 |
+
for cutsheet in cutsheets:
|
190 |
+
source = (convert_from_path(cutsheet.name))[0]
|
191 |
+
client = GPT4V_Client(api_key=api_key, organization_key=organization_key)
|
192 |
+
fixtureInfo += markdown_json_to_table(client.one_step_chat(prompt, source)[0], iteration)
|
193 |
+
iteration += 1
|
194 |
+
return fixtureInfo
|
195 |
+
|
196 |
+
if __name__ == "__main__":
|
197 |
+
with gr.Blocks() as demo:
|
198 |
+
gr.Markdown("# Lighting Manufacture Cutsheet GPT Tool")
|
199 |
+
api_key = gr.Textbox(label = "Input your ChatGPT4 API Key: ")
|
200 |
+
organization_key = gr.Textbox(label = "Input your ChatGPT4 API Organization Key: ", info = "(optional)")
|
201 |
+
# image = gr.Image()
|
202 |
+
file_uploader = gr.UploadButton("Upload cutsheets", type="filepath", file_count="multiple")
|
203 |
+
form = gr.Markdown()
|
204 |
+
file_uploader.upload(gptRead, [file_uploader, api_key, organization_key], form)
|
205 |
+
|
206 |
+
demo.launch(share=True)
|
207 |
+
|