CGQN commited on
Commit
8df7714
·
verified ·
1 Parent(s): 3cfef31

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -170
app.py CHANGED
@@ -1,187 +1,74 @@
1
- import os
2
  import gradio as gr
3
- import torch
4
  from PIL import Image
5
- from transformers import AutoModel, AutoTokenizer
6
 
7
- # --- Model Loading (unchanged) ---
8
- MODEL_ID = os.environ.get("MINICPM_MODEL_ID", "openbmb/MiniCPM-V-4_5")
9
- DTYPE = torch.bfloat16 if torch.cuda.is_available() else torch.float32
10
- DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
11
 
12
- model = None
13
- tokenizer = None
14
-
15
- def load_model():
16
- global model, tokenizer
17
- if model is None or tokenizer is None:
18
- model = AutoModel.from_pretrained(
19
- MODEL_ID,
20
- trust_remote_code=True,
21
- attn_implementation="sdpa",
22
- torch_dtype=DTYPE,
23
- )
24
- if DEVICE == "cuda":
25
- model = model.to(DEVICE)
26
- model = model.eval()
27
- tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
28
- return model, tokenizer
29
-
30
- # --- BUG FIX & REFACTOR: Replaced format_history_for_model ---
31
- # The original function was complex and not well-suited for a stateful, turn-by-turn
32
- # chatbot where images are part of the history. This new function is clearer and more robust.
33
- def convert_history_to_model_messages(history: list, new_message: str, image: Image.Image):
34
- """
35
- Converts Gradio chatbot history and the current turn's input into the MiniCPM message format.
36
- - history: Gradio chatbot history list. Each item is a tuple (user_turn, assistant_turn).
37
- A user_turn can be a string or a tuple (image_pil, text).
38
- - new_message: The text from the user in the current turn.
39
- - image: The PIL image uploaded by the user in the current turn.
40
- """
41
- messages = []
42
- # Process past turns
43
- for user_turn, assistant_turn in history:
44
- # Handle user message
45
- if isinstance(user_turn, tuple):
46
- # This turn had an image
47
- img, text = user_turn
48
- # MiniCPM expects content as a list of parts (image, text)
49
- messages.append({"role": "user", "content": [img, text]})
50
- else:
51
- # This turn was text-only
52
- messages.append({"role": "user", "content": [user_turn]})
53
-
54
- # Handle assistant message if it exists
55
- if assistant_turn:
56
- messages.append({"role": "assistant", "content": [assistant_turn]})
57
-
58
- # Process the current turn's input
59
- current_turn_content = []
60
- if image:
61
- current_turn_content.append(image)
62
- if new_message and new_message.strip():
63
- current_turn_content.append(new_message)
64
-
65
- # Add the current user message to the list if it's not empty
66
- if current_turn_content:
67
- messages.append({"role": "user", "content": current_turn_content})
68
-
69
- return messages
70
-
71
- def stream_chat(messages, enable_thinking=False):
72
  """
73
- Generator that yields tokens incrementally for Gradio streaming. (Unchanged)
 
 
74
  """
75
- model_, tok = load_model()
76
- answer_iter = model_.chat(
77
- msgs=messages,
78
- tokenizer=tok,
79
- enable_thinking=enable_thinking,
80
- stream=True,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  )
82
- buffer = ""
83
- for chunk in answer_iter:
84
- buffer += chunk
85
- yield buffer
86
-
87
- def chat_and_stream(message: str, history: list, image: Image.Image, enable_thinking: bool):
88
- """
89
- The main event handler for the chatbot.
90
- - Takes current inputs and history.
91
- - Updates the chatbot UI instantly with the user's message.
92
- - Converts history to the model's format.
93
- - Streams the model's response back to the chatbot.
94
- """
95
- # Guard against empty submissions
96
- if not image and (not message or not message.strip()):
97
- # Return original history and unchanged inputs
98
- yield history, "", image
99
- return
100
-
101
- # Prepare user message for display in the chatbot
102
- # If an image is present, group it with the message text in a tuple for display
103
- user_display_turn = (image, message) if image else message
104
- history.append([user_display_turn, None])
105
- # Instantly update the UI: show user message, clear inputs
106
- yield history, "", None
107
-
108
- # Convert the history (including the new user turn) for the model
109
- model_messages = convert_history_to_model_messages(history, "", None) # History already contains the new turn
110
 
111
- # Stream the response from the model
112
- full_response = ""
113
- for partial_response in stream_chat(model_messages, enable_thinking=enable_thinking):
114
- history[-1][1] = partial_response
115
- full_response = partial_response
116
- yield history, "", None
117
-
118
-
119
- # --- UI REFACTOR: Replaced gr.ChatInterface with gr.Blocks layout ---
120
- with gr.Blocks(fill_height=True, analytics_enabled=False, theme=gr.themes.Default(text_size=gr.themes.sizes.text_lg)) as demo:
121
- gr.Markdown("# MiniCPM-V-4_5 Visual Chat Demo")
122
-
123
  with gr.Row():
124
- # Left Column: Inputs
125
  with gr.Column(scale=1):
126
- image_in = gr.Image(label="Input Image (Optional)", type="pil")
 
 
 
127
  text_in = gr.Textbox(
128
- label="Message",
129
- placeholder="Ask a question about your image...",
130
- lines=4,
131
- autofocus=True
132
- )
133
- with gr.Row():
134
- submit_btn = gr.Button("Submit", variant="primary", scale=3)
135
- clear_btn = gr.Button("Clear", scale=1)
136
-
137
- with gr.Accordion("Advanced Options", open=False):
138
- enable_thinking_box = gr.Checkbox(label="Enable Thinking Mode", value=False)
139
-
140
- with gr.Group():
141
- gr.Markdown("### Model Info")
142
- gr.Textbox(value=MODEL_ID, label="Model", interactive=False)
143
- gr.Textbox(value=DEVICE, label="Device", interactive=False)
144
- gr.Textbox(value=str(DTYPE), label="DType", interactive=False)
145
-
146
- # Right Column: Chatbot Output
147
- with gr.Column(scale=2):
148
- chatbot = gr.Chatbot(
149
- label="MiniCPM Chat",
150
- bubble_full_width=False,
151
- height=700, # Increased height for better viewing
152
- render_markdown=True,
153
- likeable=False,
154
- show_copy_button=True,
155
  )
 
 
156
 
157
- # --- Event Handling Logic ---
158
-
159
- # Combine inputs into a list for clarity
160
- inputs = [text_in, chatbot, image_in, enable_thinking_box]
161
- outputs = [chatbot, text_in, image_in]
162
 
163
- # Click event for the submit button
164
  submit_btn.click(
165
- fn=chat_and_stream,
166
- inputs=inputs,
167
- outputs=outputs
168
- )
169
-
170
- # Submit on Enter key press in the textbox
171
- text_in.submit(
172
- fn=chat_and_stream,
173
- inputs=inputs,
174
- outputs=outputs
175
  )
176
-
177
- # Clear button functionality
178
- def clear_all():
179
- return [], "", None # Clears chatbot, textbox, and image
180
- clear_btn.click(fn=clear_all, outputs=[chatbot, text_in, image_in])
181
-
182
-
183
- # Preload model on app start for snappier first response
184
- demo.load(load_model, outputs=None, queue=False)
185
 
186
- # Queue enables streaming and concurrent users
187
- demo.queue(api_open=False).launch()
 
1
+ import time
2
  import gradio as gr
 
3
  from PIL import Image
 
4
 
5
+ # Added more placeholder responses to prevent an IndexError
6
+ PREWRITTEN_RESPONSES = [
7
+ "When it comes to retailing industry, we offer remind the both part of realistic store and internet shopping. Both of them are all have their pros and cons, but according the picture, we can find out both of the internet sales counting and its profit are all grew up every years between twenty eighteen to twenty twenty one. The years increase rate began with twenty eighteen only 10.3%, next year 14.1%, and the next 20.3%, finally finished in twenty twenty one up to 24.5%. The sales profit also began with twenty eighteen only 2517 (million), next year 2873, and the next 3456, finally finished in twenty twenty one up to 4303. Therefore, we can find out the internet shopping is grew up between the four years. Begin 2019, according my observed more and more friends change to internet shopping because of COVID-19. All above the results provided the picture is to the realistic.\nIn my opinion, shopping on the internet can save many times to me, so I also do it when I"
8
+ ]
9
 
10
+ def fake_minicpm_infer(image: Image.Image, text: str):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  """
12
+ Simulate a MiniCPM-V-4_5 inference:
13
+ - Sleep for a fixed duration to mimic model loading & generation latency.
14
+ - Return a prewritten response based on simple heuristics of input.
15
  """
16
+ if image is None and not text.strip():
17
+ return "Please provide an image or text to start the demo."
18
+
19
+ time.sleep(8.5) # Simulate inference time
20
+
21
+ t = text.lower().strip()
22
+ if any(k in t for k in ["travel", "advice", "safety", "suggestion"]):
23
+ return PREWRITTEN_RESPONSES[1]
24
+ if any(k in t for k in ["weather", "rain", "wind", "cloud"]):
25
+ return PREWRITTEN_RESPONSES[2]
26
+ if any(k in t for k in ["photography", "camera", "photo", "shoot"]):
27
+ return PREWRITTEN_RESPONSES[3]
28
+ return PREWRITTEN_RESPONSES[0]
29
+
30
+ custom_css = """
31
+ #input_textbox textarea,
32
+ #output_textbox textarea {
33
+ font-size: 18px !important;
34
+ }
35
+ """
36
+
37
+ with gr.Blocks(title="MiniCPM-V-4_5 Demo", css=custom_css) as demo:
38
+
39
+ gr.Markdown(
40
+ """
41
+ # MiniCPM-V-4_5 Demo
42
+ """
43
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  with gr.Row():
 
46
  with gr.Column(scale=1):
47
+ # --- MODIFICATION 1 ---
48
+ # Set the maximum display height of the image component to 800px.
49
+ image_in = gr.Image(label="Input Image", type="pil", height=800)
50
+
51
  text_in = gr.Textbox(
52
+ label="Input Question/Description",
53
+ placeholder="e.g., What kind of landscape is this? or What should I be aware of when traveling?",
54
+ lines=3,
55
+ elem_id="input_textbox"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  )
57
+
58
+ submit_btn = gr.Button("Submit", variant="primary")
59
 
60
+ with gr.Column(scale=1):
61
+ gr.Markdown("### Output")
62
+ # --- MODIFICATION 2 ---
63
+ # Increased the number of lines to 12 (original 8 * 1.5).
64
+ output = gr.Textbox(label="Model Response", lines=12, elem_id="output_textbox")
65
 
 
66
  submit_btn.click(
67
+ fn=fake_minicpm_infer,
68
+ inputs=[image_in, text_in],
69
+ outputs=output,
70
+ api_name="mock_infer"
 
 
 
 
 
 
71
  )
 
 
 
 
 
 
 
 
 
72
 
73
+ if __name__ == "__main__":
74
+ demo.launch()