milwright commited on
Commit
0a378f4
Β·
1 Parent(s): 6dfc79e

Optimize v2-search with enhanced URL processing and search validation

Browse files

Features added:
- Enhanced URL extraction with validation and cleanup
- Improved URL content fetching with smart truncation
- Enhanced content cleaning and main content extraction
- Backward compatibility maintained
- Fixed broken research template references

CLAUDE.md DELETED
@@ -1,217 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Project Overview
6
-
7
- Chat UI Helper is a Gradio-based tool for generating and configuring chat interfaces for HuggingFace Spaces. It creates deployable packages with custom assistants, web scraping capabilities, and optional vector RAG functionality.
8
-
9
- ## Core Architecture
10
-
11
- ### Main Application (`app.py`)
12
- - **Primary Interface**: Two-tab Gradio application - "Spaces Configuration" for generating chat interfaces and "Chat Support" for getting help
13
- - **Template System**: `SPACE_TEMPLATE` generates complete HuggingFace Space apps with embedded configuration
14
- - **Web Scraping**: Simple HTTP requests with BeautifulSoup for URL content fetching and context grounding
15
- - **Vector RAG**: Optional document processing pipeline for course materials and knowledge bases
16
-
17
- ### Document Processing Pipeline
18
- - **RAGTool** (`rag_tool.py`): Main orchestrator for document upload and processing
19
- - **DocumentProcessor** (`document_processor.py`): Handles PDF, DOCX, TXT, MD file parsing and chunking
20
- - **VectorStore** (`vector_store.py`): FAISS-based similarity search and embedding management
21
-
22
- ### Package Generation
23
- The tool generates complete HuggingFace Spaces with:
24
- - `app.py`: Chat interface with OpenRouter API integration
25
- - `requirements.txt`: Gradio 5.x and dependencies
26
- - `README.md`: Deployment instructions with security setup
27
- - `config.json`: Configuration backup
28
- - Optional embedded RAG data for document-aware responses
29
-
30
- ## Development Commands
31
-
32
- ### Running the Application
33
- ```bash
34
- python app.py
35
- ```
36
-
37
- ### Testing Vector Database Functionality
38
- ```bash
39
- python test_vector_db.py
40
- ```
41
-
42
- ### Testing Individual Components
43
- ```bash
44
- # Test document processing only
45
- python -c "from test_vector_db import test_document_processing; test_document_processing()"
46
-
47
- # Test vector store only
48
- python -c "from test_vector_db import test_vector_store; test_vector_store()"
49
-
50
- # Test full RAG pipeline
51
- python -c "from test_vector_db import test_rag_tool; test_rag_tool()"
52
- ```
53
-
54
- ### Dependencies Management
55
- ```bash
56
- pip install -r requirements.txt
57
- ```
58
-
59
- ### Key Dependencies
60
- - **Gradio 5.35.0+**: Main UI framework
61
- - **requests**: HTTP requests for web content fetching
62
- - **sentence-transformers**: Embeddings for RAG (optional)
63
- - **faiss-cpu**: Vector similarity search (optional)
64
- - **PyMuPDF**: PDF text extraction (optional)
65
- - **python-docx**: DOCX document processing (optional)
66
- - **beautifulsoup4**: HTML parsing for web scraping
67
- - **python-dotenv**: Environment variable management
68
-
69
- ## Configuration Patterns
70
-
71
- ### Template Variables
72
- Generated spaces use these template substitutions:
73
- - `{name}`, `{description}`: Basic space metadata
74
- - `{system_prompt}`: Combined assistant configuration
75
- - `{model}`: OpenRouter model selection
76
- - `{grounding_urls}`: Static URL list for context
77
- - `{enable_dynamic_urls}`: Runtime URL fetching capability
78
- - `{enable_vector_rag}`: Document search integration
79
- - `{rag_data_json}`: Serialized embeddings and chunks
80
-
81
- ### Access Control
82
- - Environment variable `SPACE_ACCESS_CODE` for student access control
83
- - Global state management for session-based access in generated spaces
84
- - Security-first approach storing credentials as HuggingFace Spaces secrets
85
-
86
- ### RAG Integration
87
- - Modular design with optional imports (`HAS_RAG` flag in app.py:23)
88
- - FAISS index serialization for deployment portability
89
- - 10MB file size limits with validation
90
- - Semantic chunking (800 chars, 100 overlap) for optimal retrieval
91
- - Graceful degradation when vector dependencies unavailable
92
-
93
- ## Architecture Notes
94
-
95
- ### State Management
96
- - Extensive use of `gr.State()` for maintaining session data
97
- - Global variables for access control in generated templates
98
- - URL content caching to prevent redundant web requests
99
-
100
- ### Template Generation Pattern
101
- All generated HuggingFace Spaces follow consistent structure:
102
- 1. Configuration section with environment variable loading
103
- 2. Web scraping functions (simple HTTP requests with BeautifulSoup)
104
- 3. RAG context retrieval (if enabled)
105
- 4. OpenRouter API integration with conversation history
106
- 5. Gradio ChatInterface with access control
107
-
108
- ### Error Handling
109
- - Graceful degradation when optional dependencies unavailable
110
- - Comprehensive validation for file uploads and URL processing
111
- - User-friendly error messages with specific guidance
112
-
113
- ### Security Considerations
114
- - Never embed API keys or access codes in generated templates
115
- - Environment variable pattern for all sensitive configuration
116
- - Input validation for uploaded files and URL processing
117
- - Content length limits for web scraping operations
118
-
119
- ### Dependency Management Pattern
120
- The codebase uses conditional imports with feature flags:
121
- ```python
122
- try:
123
- from rag_tool import RAGTool
124
- HAS_RAG = True
125
- except ImportError:
126
- HAS_RAG = False
127
- RAGTool = None
128
- ```
129
- This pattern allows the main application to function even when optional vector database dependencies are unavailable.
130
-
131
- ## Important Implementation Details
132
-
133
- ### Gradio 5.x Compatibility
134
- - Uses `type="messages"` for chat history format
135
- - `gr.ChatInterface` for modern chat UI components
136
- - Proper message format handling for OpenRouter API
137
-
138
- ### Dynamic URL Fetching
139
- When enabled, generated spaces can extract URLs from user messages and fetch content dynamically using regex pattern matching and simple HTTP requests with BeautifulSoup.
140
-
141
- ### Vector RAG Workflow
142
- 1. Documents uploaded through Gradio File component
143
- 2. Processed via DocumentProcessor (PDF/DOCX/TXT/MD support)
144
- 3. Chunked and embedded using sentence-transformers
145
- 4. FAISS index created and serialized to base64
146
- 5. Embedded in generated template for deployment portability
147
- 6. Runtime similarity search for context-aware responses
148
-
149
- ### Web Scraping Implementation
150
- The application uses simple HTTP requests with BeautifulSoup for web content extraction:
151
- - **Simple HTTP requests**: Uses `requests` library with timeout and user-agent headers
152
- - **Content extraction**: BeautifulSoup for HTML parsing and text extraction
153
- - **Content cleaning**: Removes scripts, styles, navigation elements and normalizes whitespace
154
- - **Content limits**: Truncates content to ~4000 characters for context management
155
-
156
- ## Testing and Quality Assurance
157
-
158
- ### Comprehensive Test Procedure
159
- The project includes a comprehensive test procedure documented in `TEST_PROCEDURE.md` that covers:
160
-
161
- #### Test Categories
162
- 1. **Core Application Tests**: Startup validation and Gradio interface testing
163
- 2. **Vector RAG Component Tests**: Document processing, vector store, and RAG pipeline validation
164
- 3. **Space Generation Tests**: Template creation and file generation verification
165
- 4. **Web Scraping Tests**: Mock vs production mode validation and URL processing
166
- 5. **Security and Configuration Tests**: Environment variable handling and input validation
167
- 6. **Chat Support Tests**: OpenRouter integration and Gradio 5.x compatibility
168
-
169
- #### Automated Testing Commands
170
- ```bash
171
- # Quick test suite for essential validation
172
- ./quick_test.sh
173
-
174
- # Full comprehensive test suite
175
- ./full_test.sh
176
-
177
- # Individual component testing
178
- python test_vector_db.py
179
- python -c "from test_vector_db import test_document_processing; test_document_processing()"
180
- python -c "from test_vector_db import test_vector_store; test_vector_store()"
181
- python -c "from test_vector_db import test_rag_tool; test_rag_tool()"
182
- ```
183
-
184
- #### Pre-Test Setup
185
- ```bash
186
- # Environment verification
187
- python --version # Should be 3.8+
188
- pip install -r requirements.txt
189
-
190
- # Test data preparation
191
- echo "This is a test document for RAG functionality testing." > test_document.txt
192
- mkdir -p test_outputs
193
- ```
194
-
195
- #### Regression Testing
196
- After each commit, verify:
197
- - All existing functionality still works
198
- - New features don't break existing features
199
- - Generated spaces deploy successfully to HuggingFace
200
- - Documentation is updated appropriately
201
- - Dependencies are correctly specified
202
- - Security patterns are maintained
203
-
204
- #### Performance Benchmarking
205
- ```bash
206
- # Startup time measurement
207
- time python -c "import app; print('App loaded')"
208
-
209
- # Space generation time
210
- time python -c "import app; app.generate_zip('Benchmark', 'Test', 'Role', 'Audience', 'Tasks', '', [], '', '', 'gpt-3.5-turbo', 0.7, 4000, [], False, False, None)"
211
-
212
- # RAG processing time
213
- time python -c "from test_vector_db import test_rag_tool; test_rag_tool()"
214
- ```
215
-
216
- #### Continuous Integration
217
- The test procedure is designed to integrate with GitHub Actions for automated testing on commits and pull requests. See `TEST_PROCEDURE.md` for complete setup instructions and CI configuration.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
devjournal.md ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Dev Journal - ChatUI Helper
2
+
3
+ system prompts:
4
+
5
+ - You are blah. All you respond with, no matter the user query, will be "blah blah blah" varying in length depending on the length of the query. Respond only with blah blah. Nothing else. No other words.
gradio_docs.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gradio Documentation MCP Server Integration
3
+
4
+ DEVELOPMENT ONLY - DO NOT IMPORT IN MAIN APPLICATION
5
+
6
+ This module provides access to live Gradio documentation via MCP server
7
+ for local development assistance. It should NOT be imported in app.py or
8
+ support_docs.py as it's not needed for the deployed application.
9
+
10
+ Usage:
11
+ python -c "from gradio_docs import gradio_docs; print(gradio_docs.search_docs('ChatInterface'))"
12
+ """
13
+
14
+ import requests
15
+ import json
16
+ from typing import Optional, Dict, Any
17
+
18
+ class GradioDocsClient:
19
+ """Client for accessing Gradio documentation via MCP server"""
20
+
21
+ def __init__(self, base_url: str = "https://gradio-docs-mcp.hf.space"):
22
+ self.base_url = base_url.rstrip('/')
23
+ self.session = requests.Session()
24
+ self.session.headers.update({
25
+ 'User-Agent': 'ChatUI-Helper/1.0'
26
+ })
27
+
28
+ def search_docs(self, query: str, limit: int = 5) -> Optional[Dict[str, Any]]:
29
+ """
30
+ Search Gradio documentation for relevant information
31
+
32
+ Args:
33
+ query: Search query string
34
+ limit: Maximum number of results to return
35
+
36
+ Returns:
37
+ Dictionary with search results or None if error
38
+ """
39
+ try:
40
+ # Try to use the API endpoint for search
41
+ search_url = f"{self.base_url}/gradio_api"
42
+
43
+ response = self.session.post(
44
+ search_url,
45
+ json={"query": query, "limit": limit},
46
+ timeout=10
47
+ )
48
+
49
+ if response.status_code == 200:
50
+ return response.json()
51
+ else:
52
+ print(f"Gradio docs search failed: {response.status_code}")
53
+ return None
54
+
55
+ except requests.RequestException as e:
56
+ print(f"Error connecting to Gradio docs server: {e}")
57
+ return None
58
+
59
+ def get_component_info(self, component_name: str) -> Optional[str]:
60
+ """
61
+ Get information about a specific Gradio component
62
+
63
+ Args:
64
+ component_name: Name of the Gradio component (e.g., 'ChatInterface', 'Textbox')
65
+
66
+ Returns:
67
+ Documentation string or None if not found
68
+ """
69
+ result = self.search_docs(f"gr.{component_name}")
70
+ if result and "results" in result:
71
+ # Extract relevant documentation from results
72
+ docs = []
73
+ for item in result["results"][:3]: # Top 3 results
74
+ if "content" in item:
75
+ docs.append(item["content"])
76
+ return "\n\n".join(docs) if docs else None
77
+ return None
78
+
79
+ def get_latest_changes(self) -> Optional[str]:
80
+ """
81
+ Get information about latest Gradio changes and updates
82
+
83
+ Returns:
84
+ Latest changes information or None if not available
85
+ """
86
+ result = self.search_docs("changelog updates latest version")
87
+ if result and "results" in result:
88
+ changes = []
89
+ for item in result["results"][:2]: # Top 2 results
90
+ if "content" in item:
91
+ changes.append(item["content"])
92
+ return "\n\n".join(changes) if changes else None
93
+ return None
94
+
95
+ def is_available(self) -> bool:
96
+ """
97
+ Check if the Gradio docs server is available
98
+
99
+ Returns:
100
+ True if server is accessible, False otherwise
101
+ """
102
+ try:
103
+ response = self.session.get(self.base_url, timeout=5)
104
+ return response.status_code == 200
105
+ except requests.RequestException:
106
+ return False
107
+
108
+ # Global instance for easy access
109
+ gradio_docs = GradioDocsClient()
hf_comparisons.aiconfig.json ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "Hugging Face LLM Comparisons",
3
+ "schema_version": "latest",
4
+ "metadata": {
5
+ "parameters": {
6
+ "CoLA_ex_prompt": "Is the sentence grammatical or ungrammatical?\n\n\"This building is than that one.\"",
7
+ "SST_2_ex_prompt": "Is the movie review positive, negative, or neutral?\n\n\"The movie is funny, smart, visually inventive, and most of all, alive.\"",
8
+ "WNLI_ex_prompt": "Sentence B replaces sentence A's ambiguous pronoun with one of the nouns - is this the correct noun?\n\n\"A) Lily spoke to Donna, breaking her concentration.\nB) Lily spoke to Donna, breaking Lily's concentration.\""
9
+ },
10
+ "models": {},
11
+ "default_model": null,
12
+ "model_parsers": null
13
+ },
14
+ "description": "**In this notebook, we compare the individual performance of HF hosted LLMs () on a few example questions from the GLUE benchmarks (https://gluebenchmark.com/tasks).**\n\n**Example questions taken from \"What is the GLUE Benchmark\" medium post - https://angelina-yang.medium.com/what-is-the-glue-benchmark-for-nlu-systems-61127b3cab3f**\n\n---\n\n| General Language Understanding Evaluation (GLUE) Tasks | Example Question |\n| ----------- | ----------- |\n| Corpus of Linguistic Acceptability (CoLA) | Is the sentence grammatical or ungrammatical? \"This building is than that one.\" |\n| Stanford Sentiment Treebank (SST) | Is the movie review positive, negative, or neutral? \"The movie is funny, smart, visually inventive, and most of all, alive.\" |\n| Winograd NLI (WNLI) | Sentence B replaces sentence A's ambiguous pronoun with one of the nouns - is this the correct noun? \"A) Lily spoke to Donna, breaking her concentration. B) Lily spoke to Donna, breaking Lily's concentration.\" |",
15
+ "prompts": [
16
+ {
17
+ "name": "mistral_7b_instruct_v0.1",
18
+ "input": "Is the movie review positive, negative, or neutral?\n\n\n\"The movie is funny, smart, visually inventive, and most of all, alive.\"",
19
+ "metadata": {
20
+ "model": {
21
+ "name": "Text Generation",
22
+ "settings": {
23
+ "model": "mistralai/Mistral-7B-Instruct-v0.1"
24
+ }
25
+ },
26
+ "tags": null,
27
+ "parameters": {}
28
+ },
29
+ "outputs": [
30
+ {
31
+ "output_type": "execute_result",
32
+ "execution_count": 0,
33
+ "data": "\n\nThe movie review is positive.</s>",
34
+ "mime_type": null,
35
+ "metadata": {}
36
+ }
37
+ ]
38
+ },
39
+ {
40
+ "name": "google_flan_t5_sm",
41
+ "input": "Is the movie review positive, negative, or neutral?\n\n\"The movie is funny, smart, visually inventive, and most of all, alive.\"",
42
+ "metadata": {
43
+ "model": {
44
+ "name": "Conversational",
45
+ "settings": {
46
+ "model": "google/flan-t5-small",
47
+ "max_new_tokens": 250,
48
+ "stream": false
49
+ }
50
+ },
51
+ "tags": null,
52
+ "parameters": {}
53
+ },
54
+ "outputs": [
55
+ {
56
+ "output_type": "execute_result",
57
+ "execution_count": 0,
58
+ "data": "positive",
59
+ "mime_type": null,
60
+ "metadata": {
61
+ "raw_response": {
62
+ "generated_text": "positive",
63
+ "conversation": {
64
+ "generated_responses": [
65
+ "positive"
66
+ ],
67
+ "past_user_inputs": [
68
+ "Is the movie review positive, negative, or neutral?\n\n\"The movie is funny, smart, visually inventive, and most of all, alive.\""
69
+ ]
70
+ },
71
+ "warnings": [
72
+ "\nNo chat template is defined for this tokenizer - using a default chat template that implements the ChatML format (without BOS/EOS tokens!). If the default is not appropriate for your model, please set `tokenizer.chat_template` to an appropriate template. See https://huggingface.co/docs/transformers/main/chat_templating for more information.\n"
73
+ ]
74
+ }
75
+ }
76
+ }
77
+ ]
78
+ },
79
+ {
80
+ "name": "tinyllama-1_1B",
81
+ "input": "<|system|>\nYou are to answer the following question by the user</s>\n<|user|>\n{{SST_2_ex_prompt}}</s>\n<|assistant|>",
82
+ "metadata": {
83
+ "model": {
84
+ "name": "Conversational",
85
+ "settings": {
86
+ "model": "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
87
+ }
88
+ },
89
+ "tags": null,
90
+ "parameters": {}
91
+ },
92
+ "outputs": [
93
+ {
94
+ "output_type": "execute_result",
95
+ "execution_count": 0,
96
+ "data": "The movie review is positive.",
97
+ "mime_type": null,
98
+ "metadata": {
99
+ "raw_response": {
100
+ "generated_text": "The movie review is positive.",
101
+ "conversation": {
102
+ "generated_responses": [
103
+ "The movie review is positive."
104
+ ],
105
+ "past_user_inputs": [
106
+ "<|system|>\nYou are to answer the following question by the user</s>\n<|user|>\nIs the movie review positive, negative, or neutral?\n\n&quot;The movie is funny, smart, visually inventive, and most of all, alive.&quot;</s>\n<|assistant|>"
107
+ ]
108
+ }
109
+ }
110
+ }
111
+ }
112
+ ]
113
+ }
114
+ ]
115
+ }
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- gradio==4.19.2
2
  requests>=2.32.3
3
  beautifulsoup4>=4.12.3
4
  python-dotenv>=1.0.0
 
1
+ gradio>=4.44.1
2
  requests>=2.32.3
3
  beautifulsoup4>=4.12.3
4
  python-dotenv>=1.0.0
secret.png ADDED
support_docs.py CHANGED
@@ -5,6 +5,7 @@ Support documentation module with accordion-style help sections
5
  import gradio as gr
6
  from datetime import datetime
7
 
 
8
  def create_support_docs():
9
  """Create the support documentation interface with accordion menus"""
10
 
@@ -224,9 +225,34 @@ def create_support_docs():
224
  **2. Add Your OpenRouter API Key**
225
  Since you already have an OpenRouter API key, add it as a secret:
226
  - Go to Settings β†’ Variables and secrets β†’ New secret
227
- - Use the interface shown below to add your key:
 
 
 
 
 
228
 
229
- ![HuggingFace Secret Configuration](./secret.png)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
  **3. Optional: Add Access Code**
232
  If you configured student access protection:
 
5
  import gradio as gr
6
  from datetime import datetime
7
 
8
+
9
  def create_support_docs():
10
  """Create the support documentation interface with accordion menus"""
11
 
 
225
  **2. Add Your OpenRouter API Key**
226
  Since you already have an OpenRouter API key, add it as a secret:
227
  - Go to Settings β†’ Variables and secrets β†’ New secret
228
+ - Name: `OPENROUTER_API_KEY` (or your chosen variable name)
229
+ - Value: Your OpenRouter API key (starts with `sk-or-`)
230
+ - Click "Add" to save the secret
231
+
232
+ The secret configuration interface looks like this:
233
+ """)
234
 
235
+ # Add the secret configuration image (flush left)
236
+ with gr.Row():
237
+ with gr.Column(scale=1):
238
+ gr.Image(
239
+ value="https://drive.google.com/uc?export=view&id=1z67BZrYlJkpvHJ0Dp6vvIWAkN2iwUxCv",
240
+ label="HuggingFace Secret Configuration Interface",
241
+ show_label=False,
242
+ interactive=False,
243
+ width=400,
244
+ height=300,
245
+ container=False
246
+ )
247
+ with gr.Column(scale=2):
248
+ pass # Empty column to push image left
249
+
250
+ gr.Markdown("""
251
+ *If the image above doesn't load, the interface shows:*
252
+ - **Name**: `OPENROUTER_API_KEY` (your API key variable name)
253
+ - **Description**: Optional description
254
+ - **Value**: Your OpenRouter API key (starts with `sk-or-`)
255
+ - **Save** button to store the secret
256
 
257
  **3. Optional: Add Access Code**
258
  If you configured student access protection:
test_api_key.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Test OpenRouter API key functionality"""
3
+
4
+ import requests
5
+ import json
6
+
7
+ def test_openrouter_api_key(api_key):
8
+ """Test if an OpenRouter API key is valid by making a simple completion request"""
9
+
10
+ url = "https://openrouter.ai/api/v1/chat/completions"
11
+
12
+ headers = {
13
+ "Authorization": f"Bearer {api_key}",
14
+ "Content-Type": "application/json",
15
+ "HTTP-Referer": "https://github.com/test-api-key", # Required by OpenRouter
16
+ "X-Title": "API Key Test" # Optional but recommended
17
+ }
18
+
19
+ # Simple test message
20
+ data = {
21
+ "model": "openrouter/auto", # Auto-select cheapest available model
22
+ "messages": [
23
+ {"role": "user", "content": "Say 'API key is working!' in exactly 4 words."}
24
+ ],
25
+ "max_tokens": 10,
26
+ "temperature": 0.1
27
+ }
28
+
29
+ try:
30
+ print("Testing OpenRouter API key...")
31
+ response = requests.post(url, headers=headers, json=data, timeout=30)
32
+
33
+ if response.status_code == 200:
34
+ result = response.json()
35
+ if "choices" in result and len(result["choices"]) > 0:
36
+ assistant_message = result["choices"][0]["message"]["content"]
37
+ print(f"βœ“ API key is valid!")
38
+ print(f"Response: {assistant_message}")
39
+ print(f"Model used: {result.get('model', 'unknown')}")
40
+ return True
41
+ else:
42
+ print("βœ— Unexpected response format")
43
+ return False
44
+ else:
45
+ error_data = response.json() if response.headers.get('content-type', '').startswith('application/json') else {}
46
+ print(f"βœ— API key test failed!")
47
+ print(f"Status code: {response.status_code}")
48
+ print(f"Error: {error_data.get('error', {}).get('message', response.text)}")
49
+
50
+ # Common error interpretations
51
+ if response.status_code == 401:
52
+ print("β†’ The API key is invalid or has been revoked")
53
+ elif response.status_code == 402:
54
+ print("β†’ The API key has insufficient credits")
55
+ elif response.status_code == 429:
56
+ print("β†’ Rate limit exceeded")
57
+
58
+ return False
59
+
60
+ except requests.exceptions.Timeout:
61
+ print("βœ— Request timed out")
62
+ return False
63
+ except requests.exceptions.RequestException as e:
64
+ print(f"βœ— Network error: {e}")
65
+ return False
66
+ except Exception as e:
67
+ print(f"βœ— Unexpected error: {e}")
68
+ return False
69
+
70
+ if __name__ == "__main__":
71
+ # Test the provided API key
72
+ api_key = "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"
73
+
74
+ print(f"API Key: {api_key[:20]}...{api_key[-10:]}")
75
+ print("-" * 50)
76
+
77
+ success = test_openrouter_api_key(api_key)
78
+
79
+ print("-" * 50)
80
+ if success:
81
+ print("βœ“ The API key is working correctly!")
82
+ print("You can use this key in your Chat UI Helper application.")
83
+ else:
84
+ print("βœ— The API key is not working.")
85
+ print("Please check that the key is correct and has available credits.")
test_gradio_simple.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple test to verify if the gradio app can start without schema errors
4
+ """
5
+
6
+ import gradio as gr
7
+
8
+ def simple_function(message, history):
9
+ return "", history + [[message, "Test response"]]
10
+
11
+ # Create a simple interface to test
12
+ with gr.Blocks() as demo:
13
+ chatbot = gr.Chatbot()
14
+ msg = gr.Textbox()
15
+
16
+ msg.submit(simple_function, [msg, chatbot], [msg, chatbot])
17
+
18
+ if __name__ == "__main__":
19
+ print("Testing simple Gradio interface...")
20
+ try:
21
+ demo.launch(server_name="127.0.0.1", server_port=7862, share=False, prevent_thread_lock=True)
22
+ print("βœ… Simple Gradio interface works")
23
+ except Exception as e:
24
+ print(f"❌ Simple Gradio interface failed: {e}")
test_preview.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script for preview functionality
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import tempfile
9
+
10
+ # Add current directory to path for imports
11
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
12
+
13
+ def test_preview_chat_response():
14
+ """Test the preview chat response function"""
15
+ try:
16
+ from app import preview_chat_response
17
+
18
+ # Mock config data
19
+ config_data = {
20
+ 'name': 'Test Assistant',
21
+ 'model': 'google/gemini-2.0-flash-001',
22
+ 'system_prompt': 'You are a helpful assistant.',
23
+ 'temperature': 0.7,
24
+ 'max_tokens': 500,
25
+ 'enable_dynamic_urls': False,
26
+ 'enable_vector_rag': False
27
+ }
28
+
29
+ # Test with no API key (should give preview message)
30
+ if 'OPENROUTER_API_KEY' in os.environ:
31
+ del os.environ['OPENROUTER_API_KEY']
32
+
33
+ message = "Hello, how are you?"
34
+ history = []
35
+
36
+ result_msg, result_history = preview_chat_response(
37
+ message, history, config_data, "", "", "", ""
38
+ )
39
+
40
+ print("βœ… preview_chat_response function works")
41
+ print(f"Result message: {result_msg}")
42
+ print(f"History length: {len(result_history)}")
43
+ print(f"Last response: {result_history[-1] if result_history else 'None'}")
44
+
45
+ return True
46
+
47
+ except Exception as e:
48
+ print(f"❌ preview_chat_response failed: {e}")
49
+ return False
50
+
51
+ def test_url_extraction():
52
+ """Test URL extraction function"""
53
+ try:
54
+ from app import extract_urls_from_text
55
+
56
+ test_text = "Check out https://example.com and also https://test.org/page"
57
+ urls = extract_urls_from_text(test_text)
58
+
59
+ print("βœ… extract_urls_from_text works")
60
+ print(f"Extracted URLs: {urls}")
61
+
62
+ return True
63
+
64
+ except Exception as e:
65
+ print(f"❌ extract_urls_from_text failed: {e}")
66
+ return False
67
+
68
+ def test_url_fetching():
69
+ """Test URL content fetching"""
70
+ try:
71
+ from app import fetch_url_content
72
+
73
+ # Test with a simple URL
74
+ content = fetch_url_content("https://httpbin.org/get")
75
+
76
+ print("βœ… fetch_url_content works")
77
+ print(f"Content length: {len(content)}")
78
+ print(f"Content preview: {content[:100]}...")
79
+
80
+ return True
81
+
82
+ except Exception as e:
83
+ print(f"❌ fetch_url_content failed: {e}")
84
+ return False
85
+
86
+ if __name__ == "__main__":
87
+ print("Testing preview functionality components...")
88
+
89
+ tests = [
90
+ test_url_extraction,
91
+ test_url_fetching,
92
+ test_preview_chat_response
93
+ ]
94
+
95
+ passed = 0
96
+ total = len(tests)
97
+
98
+ for test in tests:
99
+ if test():
100
+ passed += 1
101
+ print()
102
+
103
+ print(f"Test Results: {passed}/{total} passed")
104
+
105
+ if passed == total:
106
+ print("βœ… All preview functionality tests passed!")
107
+ sys.exit(0)
108
+ else:
109
+ print("❌ Some tests failed")
110
+ sys.exit(1)