Jiangxz01 commited on
Commit
b1bc271
·
verified ·
1 Parent(s): b04d1ed

Upload app.py

Browse files

Llama 3.2 90B Vision

Files changed (1) hide show
  1. app.py +177 -0
app.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # 財政部財政資訊中心 江信宗
3
+
4
+ import gradio as gr
5
+ import requests
6
+ import base64
7
+ import json
8
+ import os
9
+ from PIL import Image
10
+ from io import BytesIO
11
+
12
+ invoke_url = "https://ai.api.nvidia.com/v1/gr/meta/llama-3.2-90b-vision-instruct/chat/completions"
13
+ stream = True
14
+
15
+ def compress_image(image_path, max_size_kb=175):
16
+ max_size_bytes = max_size_kb * 1024
17
+ quality = 95
18
+ with Image.open(image_path) as img:
19
+ img.thumbnail((800, 800))
20
+ while True:
21
+ img_byte_arr = BytesIO()
22
+ img.save(img_byte_arr, format='JPEG', quality=quality)
23
+ if img_byte_arr.tell() <= max_size_bytes or quality <= 10:
24
+ return img_byte_arr.getvalue()
25
+ quality = max(quality - 10, 10)
26
+
27
+ def process_image(image_path, api_key, question):
28
+ try:
29
+ compressed_image = compress_image(image_path)
30
+ image_b64 = base64.b64encode(compressed_image).decode()
31
+ assert len(image_b64) < 180_000, \
32
+ "Image is still too large after compression. Please try a smaller image."
33
+ prompt = f"{question} . Must reply to me in \"Traditional Chinese\"."
34
+ headers = {
35
+ "Authorization": f"Bearer {api_key}",
36
+ "Accept": "text/event-stream" if stream else "application/json"
37
+ }
38
+ payload = {
39
+ "model": 'meta/llama-3.2-90b-vision-instruct',
40
+ "messages": [
41
+ {
42
+ "role": "user",
43
+ "content": f'{prompt} <img src="data:image/jpeg;base64,{image_b64}" />'
44
+ }
45
+ ],
46
+ "max_tokens": 512,
47
+ "temperature": 1.00,
48
+ "top_p": 1.00,
49
+ "stream": stream
50
+ }
51
+ response = requests.post(invoke_url, headers=headers, json=payload, stream=True)
52
+ if response.status_code == 200:
53
+ full_response = ""
54
+ for line in response.iter_lines():
55
+ if line:
56
+ line = line.decode('utf-8')
57
+ if line.startswith('data: '):
58
+ json_str = line[6:]
59
+ if json_str.strip() == '[DONE]':
60
+ break
61
+ try:
62
+ json_obj = json.loads(json_str)
63
+ content = json_obj['choices'][0]['delta'].get('content', '')
64
+ full_response += content
65
+ yield full_response
66
+ except json.JSONDecodeError:
67
+ print(f"Failed to parse JSON: {json_str}")
68
+ return full_response
69
+ elif response.status_code == 402:
70
+ return "錯誤:API 帳號積分已過期。請至 NVIDIA 官網檢查您的帳號狀態。"
71
+ else:
72
+ error_message = f"錯誤 {response.status_code}: {response.text}"
73
+ print(error_message)
74
+ return f"發生錯誤。請稍後再試或聯繫管理員。錯誤代碼:{response.status_code}"
75
+ except Exception as e:
76
+ print(f"發生異常:{str(e)}")
77
+ return f"處理請求時發生錯誤:{str(e)}"
78
+
79
+ custom_css = """
80
+ .center-aligned {
81
+ text-align: center !important;
82
+ color: #ff4081;
83
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
84
+ margin-bottom: -5px !important;
85
+ }
86
+ .gen-button {
87
+ border-radius: 10px !important;
88
+ background-color: #ff4081 !important;
89
+ color: white !important;
90
+ font-weight: bold !important;
91
+ transition: all 0.3s ease !important;
92
+ }
93
+ .gen-button:hover {
94
+ background-color: #f50057 !important;
95
+ transform: scale(1.05);
96
+ }
97
+ .gr-input, .gr-box, .gr-dropdown {
98
+ border-radius: 10px !important;
99
+ border: 2px solid #ff4081 !important;
100
+ }
101
+ .gr-input:focus, .gr-box:focus, .gr-dropdown:focus {
102
+ border-color: #f50057 !important;
103
+ box-shadow: 0 0 0 2px rgba(245,0,87,0.2) !important;
104
+ }
105
+ .input-background {
106
+ background-color: #B7E0FF !important;
107
+ padding: 15px !important;
108
+ border-radius: 10px !important;
109
+ }
110
+ .gr-box {
111
+ border-radius: 10px !important;
112
+ border: 2px solid #ff4081 !important;
113
+ }
114
+ .api-background {
115
+ background-color: #FFCFB3 !important;
116
+ padding: 15px !important;
117
+ border-radius: 10px !important;
118
+ }
119
+ .output-background {
120
+ background-color: #FFF4B5 !important;
121
+ padding: 15px !important;
122
+ border-radius: 10px !important;
123
+ }
124
+ .image-background {
125
+ border-radius: 10px !important;
126
+ border: 2px solid #B7E0FF !important;
127
+ }
128
+ .clear-button {
129
+ border-radius: 10px !important;
130
+ background-color: #333333 !important;
131
+ color: white !important;
132
+ font-weight: bold !important;
133
+ transition: all 0.3s ease !important;
134
+ }
135
+ .clear-button:hover {
136
+ background-color: #000000 !important;
137
+ transform: scale(1.05);
138
+ }
139
+ """
140
+
141
+ with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as demo:
142
+ gr.Markdown("# 👹 Llama 3.2 90B Vision. Deployed by 江信宗", elem_classes="center-aligned")
143
+ image_input = gr.Image(type="filepath", label="上傳圖片", elem_classes="image-background")
144
+ with gr.Row():
145
+ question_input = gr.Textbox(label="請輸入您的問題", placeholder="例如:What is in this image?", scale=2, elem_classes="input-background")
146
+ api_key_input = gr.Textbox(type="password", label="請輸入您的 API Key", placeholder="API authentication key for large language models", scale=1, elem_classes="api-background")
147
+ output = gr.Textbox(label="Vision Model 回覆", elem_classes="output-background", max_lines=20)
148
+ with gr.Row():
149
+ submit_button = gr.Button("傳送", variant="primary", scale=2, elem_classes="gen-button")
150
+ clear_button = gr.Button("清除", variant="secondary", scale=1, elem_classes="clear-button")
151
+ def clear_inputs():
152
+ gr.Info("已成功清除所有內容,歡迎繼續提問......")
153
+ return None, "", ""
154
+ clear_button.click(
155
+ fn=clear_inputs,
156
+ inputs=None,
157
+ outputs=[image_input, question_input, output]
158
+ )
159
+ submit_button.click(fn=process_image, inputs=[image_input, api_key_input, question_input], outputs=output)
160
+ gr.HTML("""
161
+ <script>
162
+ document.addEventListener('click', function(e) {
163
+ if (e.target && e.target.textContent === '清除') {
164
+ var fileInput = document.querySelector('.upload-button input[type=file]');
165
+ if (fileInput) {
166
+ fileInput.value = '';
167
+ }
168
+ }
169
+ });
170
+ </script>
171
+ """)
172
+
173
+ if __name__ == "__main__":
174
+ if "SPACE_ID" in os.environ:
175
+ demo.queue().launch()
176
+ else:
177
+ demo.queue().launch(share=True, show_api=False)