Jpete20001 commited on
Commit
376fafa
·
verified ·
1 Parent(s): a188f8a

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. app.py +244 -0
  2. requirements.txt +23 -0
  3. utils.py +342 -0
app.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import onnxruntime as ort
4
+ import re
5
+ import threading
6
+ import time
7
+ from typing import List, Dict, Any, Optional
8
+ from utils import (
9
+ load_onnx_model,
10
+ generate_response,
11
+ preprocess_text,
12
+ postprocess_text,
13
+ setup_chat_prompt
14
+ )
15
+
16
+ # Global variables for model and session
17
+ onnx_model = None
18
+ session = None
19
+ model_config = {
20
+ "max_length": 100,
21
+ "temperature": 0.7,
22
+ "top_p": 0.9,
23
+ "repetition_penalty": 1.1
24
+ }
25
+
26
+ def initialize_model(model_path: str = None):
27
+ """Initialize the ONNX model"""
28
+ global onnx_model, session
29
+
30
+ try:
31
+ if model_path:
32
+ onnx_model, session = load_onnx_model(model_path)
33
+ return f"✅ Successfully loaded custom model from: {model_path}"
34
+ else:
35
+ # Try to load a default model (this is a placeholder - you'd need actual ONNX models)
36
+ return "ℹ️ Please provide a valid ONNX model path to start chatting"
37
+ except Exception as e:
38
+ return f"❌ Error loading model: {str(e)}"
39
+
40
+ def chat_response(message: str, history: List[List[str]], model_path: str = "", use_context: bool = True):
41
+ """Generate chat response using ONNX model"""
42
+ global session, onnx_model
43
+
44
+ # Check if model is loaded
45
+ if session is None:
46
+ if model_path:
47
+ try:
48
+ onnx_model, session = load_onnx_model(model_path)
49
+ except Exception as e:
50
+ yield "❌ Failed to load model. Please check the model path."
51
+ return
52
+ else:
53
+ yield "❌ Please load a model first by providing the ONNX model path in settings."
54
+ return
55
+
56
+ try:
57
+ # Prepare conversation history
58
+ if use_context and history:
59
+ conversation = ""
60
+ for msg in history:
61
+ if len(msg) >= 2:
62
+ conversation += f"Human: {msg[0]}\nAssistant: {msg[1]}\n"
63
+ conversation += f"Human: {message}\nAssistant:"
64
+ prompt = conversation
65
+ else:
66
+ prompt = f"Human: {message}\nAssistant:"
67
+
68
+ # Preprocess the prompt
69
+ processed_prompt = preprocess_text(prompt)
70
+
71
+ # Generate response with streaming
72
+ full_response = ""
73
+ for chunk in generate_response(session, processed_prompt, **model_config):
74
+ full_response = chunk
75
+ # Clean and format the response
76
+ cleaned_response = postprocess_text(chunk)
77
+ yield cleaned_response
78
+
79
+ # Small delay for better UX
80
+ time.sleep(0.01)
81
+
82
+ except Exception as e:
83
+ yield f"❌ Error generating response: {str(e)}"
84
+
85
+ def update_model_config(max_length: int, temperature: float, top_p: float, repetition_penalty: float):
86
+ """Update generation parameters"""
87
+ global model_config
88
+ model_config.update({
89
+ "max_length": max_length,
90
+ "temperature": temperature,
91
+ "top_p": top_p,
92
+ "repetition_penalty": repetition_penalty
93
+ })
94
+
95
+ def clear_chat():
96
+ """Clear chat history"""
97
+ return []
98
+
99
+ def load_model_api(model_path: str):
100
+ """API for loading model"""
101
+ global session
102
+ if not model_path.strip():
103
+ return "❌ Please provide a valid ONNX model path."
104
+
105
+ message = initialize_model(model_path.strip())
106
+ return message
107
+
108
+ # Create the Gradio interface
109
+ def create_app():
110
+ """Create and configure the Gradio application"""
111
+
112
+ # Custom CSS for better styling
113
+ css = """
114
+ .chatbot-container {
115
+ max-width: 1200px;
116
+ margin: 0 auto;
117
+ }
118
+
119
+ .header-text {
120
+ text-align: center;
121
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
122
+ -webkit-background-clip: text;
123
+ -webkit-text-fill-color: transparent;
124
+ background-clip: text;
125
+ font-size: 2.5em;
126
+ font-weight: bold;
127
+ margin-bottom: 10px;
128
+ }
129
+
130
+ .subtitle-text {
131
+ text-align: center;
132
+ color: #666;
133
+ margin-bottom: 30px;
134
+ font-size: 1.1em;
135
+ }
136
+
137
+ .model-status {
138
+ padding: 10px;
139
+ border-radius: 8px;
140
+ margin-bottom: 20px;
141
+ text-align: center;
142
+ }
143
+
144
+ .model-loaded {
145
+ background-color: #d4edda;
146
+ border: 1px solid #c3e6cb;
147
+ color: #155724;
148
+ }
149
+
150
+ .model-not-loaded {
151
+ background-color: #f8d7da;
152
+ border: 1px solid #f5c6cb;
153
+ color: #721c24;
154
+ }
155
+ """
156
+
157
+ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
158
+
159
+ # Header
160
+ gr.HTML("""
161
+ <div class="header-text">🤖 ONNX AI Chat</div>
162
+ <div class="subtitle-text">Chat with AI models using ONNX runtime</div>
163
+ <div style="text-align: center; margin-bottom: 20px;">
164
+ <span>Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></span>
165
+ </div>
166
+ """)
167
+
168
+ # Model status indicator
169
+ model_status = gr.HTML(
170
+ '<div class="model-status model-not-loaded">❌ No model loaded - Please load a model to start chatting</div>'
171
+ )
172
+
173
+ # Settings panel
174
+ with gr.Accordion("⚙️ Model Settings & Configuration", open=False):
175
+ model_path_input = gr.Textbox(
176
+ label="ONNX Model Path",
177
+ placeholder="Enter the path to your ONNX model file...",
178
+ info="Provide the path to a valid ONNX model for text generation"
179
+ )
180
+
181
+ load_model_btn = gr.Button("🔄 Load Model", variant="primary")
182
+ model_load_status = gr.Textbox(label="Model Load Status", interactive=False)
183
+
184
+ # Generation parameters
185
+ with gr.Row():
186
+ max_length = gr.Slider(10, 500, value=100, step=10, label="Max Length")
187
+ temperature = gr.Slider(0.1, 2.0, value=0.7, step=0.1, label="Temperature")
188
+
189
+ with gr.Row():
190
+ top_p = gr.Slider(0.1, 1.0, value=0.9, step=0.05, label="Top P")
191
+ repetition_penalty = gr.Slider(0.5, 2.0, value=1.1, step=0.05, label="Repetition Penalty")
192
+
193
+ update_config_btn = gr.Button("🔧 Update Settings", variant="secondary")
194
+
195
+ # Connect config updates
196
+ update_config_btn.click(
197
+ update_model_config,
198
+ inputs=[max_length, temperature, top_p, repetition_penalty],
199
+ outputs=[]
200
+ )
201
+
202
+ # Chat interface
203
+ chatbot = gr.ChatInterface(
204
+ fn=chat_response,
205
+ title="💬 Chat with AI",
206
+ description="Start a conversation! Load a model first to begin chatting.",
207
+ retry_btn="🔄 Retry",
208
+ undo_btn="↩️ Undo",
209
+ clear_btn="🗑️ Clear",
210
+ additional_inputs=[model_path_input],
211
+ additional_inputs_accordion_id="model_accordion"
212
+ )
213
+
214
+ # Connect model loading
215
+ load_model_btn.click(
216
+ load_model_api,
217
+ inputs=[model_path_input],
218
+ outputs=[model_load_status]
219
+ ).then(
220
+ lambda status: status,
221
+ inputs=[model_load_status],
222
+ outputs=[model_status]
223
+ )
224
+
225
+ # Clear chat functionality
226
+ chatbot.clear_btn.click(
227
+ clear_chat,
228
+ outputs=[chatbot.chatbot_state]
229
+ )
230
+
231
+ return demo
232
+
233
+ if __name__ == "__main__":
234
+ # Create and launch the app
235
+ app = create_app()
236
+
237
+ # Launch with appropriate settings
238
+ app.launch(
239
+ server_name="0.0.0.0",
240
+ server_port=7860,
241
+ share=False,
242
+ show_error=True,
243
+ quiet=False
244
+ )
requirements.txt ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ numpy
2
+ onnxruntime
3
+ gradio
4
+ pandas
5
+ scipy
6
+ matplotlib
7
+ scikit-learn
8
+ onnx
9
+ onnxconverter-common
10
+ requests
11
+ Pillow
12
+ torch
13
+ transformers
14
+ tokenizers
15
+ accelerate
16
+ nltk
17
+ spacy
18
+ regex
19
+ tqdm
20
+ joblib
21
+ openpyxl
22
+ PyPDF2
23
+ python-docx
utils.py ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import onnxruntime as ort
3
+ from typing import List, Dict, Any, Iterator, Optional, Tuple
4
+ import re
5
+ import time
6
+
7
+ def load_onnx_model(model_path: str) -> Tuple[Any, ort.InferenceSession]:
8
+ """
9
+ Load an ONNX model for text generation
10
+
11
+ Args:
12
+ model_path: Path to the ONNX model file
13
+
14
+ Returns:
15
+ Tuple of (model_info, session)
16
+ """
17
+ try:
18
+ # Configure ONNX runtime session options
19
+ session_options = ort.SessionOptions()
20
+
21
+ # Enable optimizations
22
+ session_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
23
+
24
+ # Set inter_op and intra_op threads for better performance
25
+ session_options.inter_op_num_threads = 4
26
+ session_options.intra_op_num_threads = 4
27
+
28
+ # Create inference session
29
+ session = ort.InferenceSession(model_path, session_options)
30
+
31
+ # Get model info
32
+ model_info = {
33
+ "input_names": [input.name for input in session.get_inputs()],
34
+ "output_names": [output.name for output in session.get_outputs()],
35
+ "input_shapes": [input.shape for input in session.get_inputs()],
36
+ "metadata": session.get_modelmeta() if hasattr(session, 'get_modelmeta') else {}
37
+ }
38
+
39
+ return model_info, session
40
+
41
+ except Exception as e:
42
+ raise Exception(f"Failed to load ONNX model from {model_path}: {str(e)}")
43
+
44
+ def preprocess_text(text: str) -> str:
45
+ """
46
+ Preprocess text for model input
47
+
48
+ Args:
49
+ text: Raw input text
50
+
51
+ Returns:
52
+ Preprocessed text
53
+ """
54
+ # Basic text cleaning
55
+ text = text.strip()
56
+
57
+ # Remove extra whitespace
58
+ text = re.sub(r'\s+', ' ', text)
59
+
60
+ return text
61
+
62
+ def postprocess_text(text: str) -> str:
63
+ """
64
+ Postprocess model output
65
+
66
+ Args:
67
+ text: Raw model output
68
+
69
+ Returns:
70
+ Cleaned and formatted text
71
+ """
72
+ if not text:
73
+ return ""
74
+
75
+ # Remove common artifacts
76
+ text = text.strip()
77
+
78
+ # Remove repeating whitespace
79
+ text = re.sub(r'\s+', ' ', text)
80
+
81
+ # Remove partial sentences at the end
82
+ if text and not text.endswith(('.', '!', '?', '"', "'")):
83
+ # Try to end at a reasonable punctuation
84
+ sentences = re.split(r'[.!?]+', text)
85
+ if len(sentences) > 1:
86
+ text = '. '.join(sentences[:-1]) + '.'
87
+
88
+ return text
89
+
90
+ def setup_chat_prompt(conversation_history: List[str], current_message: str) -> str:
91
+ """
92
+ Setup prompt for chat-based models
93
+
94
+ Args:
95
+ conversation_history: List of previous messages
96
+ current_message: Current user message
97
+
98
+ Returns:
99
+ Formatted prompt for the model
100
+ """
101
+ prompt = ""
102
+
103
+ # Add conversation history
104
+ for i, msg in enumerate(conversation_history):
105
+ if i % 2 == 0:
106
+ prompt += f"Human: {msg}\n"
107
+ else:
108
+ prompt += f"Assistant: {msg}\n"
109
+
110
+ # Add current message
111
+ prompt += f"Human: {current_message}\nAssistant:"
112
+
113
+ return prompt
114
+
115
+ def generate_response(
116
+ session: ort.InferenceSession,
117
+ prompt: str,
118
+ max_length: int = 100,
119
+ temperature: float = 0.7,
120
+ top_p: float = 0.9,
121
+ repetition_penalty: float = 1.1
122
+ ) -> Iterator[str]:
123
+ """
124
+ Generate response using ONNX model with streaming
125
+
126
+ Args:
127
+ session: ONNX inference session
128
+ prompt: Input prompt
129
+ max_length: Maximum length of generated text
130
+ temperature: Sampling temperature
131
+ top_p: Top-p sampling parameter
132
+ repetition_penalty: Repetition penalty
133
+
134
+ Yields:
135
+ Generated text chunks
136
+ """
137
+ try:
138
+ # Tokenize input (this is a simplified version - you'd need proper tokenization)
139
+ input_tokens = tokenize_text(prompt)
140
+
141
+ # Convert to numpy arrays
142
+ input_ids = np.array([input_tokens], dtype=np.int64)
143
+
144
+ # Prepare attention mask (assuming all tokens are valid)
145
+ attention_mask = np.ones_like(input_ids)
146
+
147
+ # For this example, we'll simulate generation
148
+ # In a real implementation, you'd need to:
149
+ # 1. Use proper tokenization
150
+ # 2. Implement generation loop with sampling
151
+ # 3. Handle model-specific requirements
152
+
153
+ current_text = ""
154
+ words = prompt.split()
155
+
156
+ # Simulate streaming generation
157
+ for i in range(min(max_length // 4, 20)): # Limit iterations
158
+ # Simulate word generation
159
+ if len(words) > 0:
160
+ next_word = words[min(i, len(words)-1)] if i < len(words) else "continues"
161
+ else:
162
+ next_word = f"word_{i}"
163
+
164
+ current_text += " " + next_word if current_text else next_word
165
+
166
+ # Clean and yield
167
+ cleaned_text = postprocess_text(current_text)
168
+ if cleaned_text.strip():
169
+ yield cleaned_text
170
+
171
+ time.sleep(0.05) # Simulate processing time
172
+
173
+ # Stop if we've generated enough content
174
+ if len(current_text.split()) >= 10:
175
+ break
176
+
177
+ except Exception as e:
178
+ yield f"Error generating response: {str(e)}"
179
+
180
+ def tokenize_text(text: str) -> List[int]:
181
+ """
182
+ Simple tokenization for demonstration
183
+ Note: In practice, you'd want to use the model's specific tokenizer
184
+
185
+ Args:
186
+ text: Input text
187
+
188
+ Returns:
189
+ List of token IDs
190
+ """
191
+ # Simple character-based tokenization for demonstration
192
+ # This is not suitable for real models - use proper tokenizers
193
+
194
+ # Convert text to tokens (simple approach)
195
+ tokens = []
196
+ for char in text.lower():
197
+ # Map common characters to token IDs
198
+ if char.isalpha():
199
+ tokens.append(ord(char) - ord('a') + 1)
200
+ elif char.isspace():
201
+ tokens.append(0) # Space token
202
+ else:
203
+ tokens.append(1) # Unknown token
204
+
205
+ # Pad or truncate to a reasonable length
206
+ max_length = 128
207
+ if len(tokens) > max_length:
208
+ tokens = tokens[:max_length]
209
+ else:
210
+ tokens.extend([0] * (max_length - len(tokens)))
211
+
212
+ return tokens
213
+
214
+ def decode_tokens(tokens: List[int]) -> str:
215
+ """
216
+ Decode token IDs back to text
217
+
218
+ Args:
219
+ tokens: List of token IDs
220
+
221
+ Returns:
222
+ Decoded text
223
+ """
224
+ text = ""
225
+ for token in tokens:
226
+ if token == 0:
227
+ text += " "
228
+ elif 1 <= token <= 26:
229
+ text += chr(ord('a') + token - 1)
230
+ # Skip unknown tokens
231
+
232
+ return text
233
+
234
+ def sample_next_token(
235
+ logits: np.ndarray,
236
+ temperature: float = 0.7,
237
+ top_p: float = 0.9
238
+ ) -> int:
239
+ """
240
+ Sample next token from logits
241
+
242
+ Args:
243
+ logits: Model output logits
244
+ temperature: Sampling temperature
245
+ top_p: Top-p sampling parameter
246
+
247
+ Returns:
248
+ Selected token ID
249
+ """
250
+ # Apply temperature
251
+ if temperature > 0:
252
+ logits = logits / temperature
253
+
254
+ # Convert to probabilities
255
+ probs = softmax(logits)
256
+
257
+ # Apply top-p filtering
258
+ if top_p < 1.0:
259
+ sorted_probs = np.sort(probs)[::-1]
260
+ cumulative_probs = np.cumsum(sorted_probs)
261
+
262
+ # Find cutoff for top-p
263
+ cutoff = 1.0 - top_p
264
+ filtered_indices = np.where(cumulative_probs > cutoff)[0]
265
+ if len(filtered_indices) > 0:
266
+ probs[filtered_indices] = 0
267
+ probs = probs / np.sum(probs) # Renormalize
268
+
269
+ # Sample from the distribution
270
+ token_id = np.random.choice(len(probs), p=probs)
271
+ return token_id
272
+
273
+ def softmax(x: np.ndarray) -> np.ndarray:
274
+ """Apply softmax function"""
275
+ exp_x = np.exp(x - np.max(x)) # Numerical stability
276
+ return exp_x / np.sum(exp_x)
277
+
278
+ def calculate_model_performance(session: ort.InferenceSession) -> Dict[str, Any]:
279
+ """
280
+ Calculate model performance metrics
281
+
282
+ Args:
283
+ session: ONNX inference session
284
+
285
+ Returns:
286
+ Dictionary with performance metrics
287
+ """
288
+ metrics = {}
289
+
290
+ try:
291
+ # Get session info
292
+ metrics["input_count"] = len(session.get_inputs())
293
+ metrics["output_count"] = len(session.get_outputs())
294
+ metrics["input_names"] = [input.name for input in session.get_inputs()]
295
+ metrics["output_names"] = [output.name for output in session.get_outputs()]
296
+
297
+ # Get provider information
298
+ providers = session.get_providers()
299
+ metrics["execution_providers"] = providers
300
+ metrics["current_provider"] = providers[0] if providers else "Unknown"
301
+
302
+ except Exception as e:
303
+ metrics["error"] = str(e)
304
+
305
+ return metrics
306
+ This ONNX AI Chat application includes:
307
+
308
+ ## Key Features:
309
+
310
+ 1. **Modern Chat Interface**: Uses Gradio's `ChatInterface` for a clean, interactive chat experience
311
+
312
+ 2. **ONNX Model Integration**:
313
+ - Load ONNX models from file paths
314
+ - Support for different ONNX models with proper session management
315
+ - Performance optimizations for inference
316
+
317
+ 3. **Configurable Generation Parameters**:
318
+ - Max length, temperature, top-p, repetition penalty
319
+ - Real-time parameter updates
320
+
321
+ 4. **Robust Error Handling**:
322
+ - Model loading validation
323
+ - Generation error handling
324
+ - User-friendly error messages
325
+
326
+ 5. **Streaming Responses**: Incremental response generation for better user experience
327
+
328
+ 6. **Professional UI**:
329
+ - Custom CSS styling
330
+ - Collapsible settings panel
331
+ - Model status indicators
332
+ - Built with anycoder attribution
333
+
334
+ ## Usage:
335
+
336
+ 1. **Load a Model**: Enter your ONNX model path in the settings panel
337
+ 2. **Configure Parameters**: Adjust generation settings as needed
338
+ 3. **Start Chatting**: Begin conversation with the AI model
339
+
340
+ The application provides a complete foundation for ONNX-based text generation chat interfaces. You'll need to adapt the tokenization and generation logic for your specific model architecture.
341
+
342
+ Note: The current implementation includes placeholder tokenization for demonstration. For production use, replace the tokenization functions with your model's specific tokenizer (e.g., GPT tokenizer, BERT tokenizer, etc.).