Spaces:
Running
Running
Comprehensive improvements and modernization
Browse files- Upgrade to Gradio 5.35.0 with proper message formatting
- Add comprehensive CLAUDE.md development documentation
- Improve security with environment-based access code storage
- Enhance README with detailed feature descriptions and architecture
- Add vector RAG testing capabilities and documentation
- Update dependency management and version constraints
- Remove generated zip files and update .gitignore
- Improve UI layout and template selection workflow
- Fix access control implementation with global state management
- Add development testing commands and component isolation
- .gitignore +4 -1
- CLAUDE.md +155 -0
- CLAUDE_DESKTOP_DEVELOPMENT.md +411 -0
- README.md +38 -6
- app.py +62 -41
- requirements.txt +3 -2
- test_document.txt +24 -0
- test_vector_db.py +196 -0
.gitignore
CHANGED
@@ -23,4 +23,7 @@ ENV/
|
|
23 |
Thumbs.db
|
24 |
|
25 |
# Logs
|
26 |
-
*.log
|
|
|
|
|
|
|
|
23 |
Thumbs.db
|
24 |
|
25 |
# Logs
|
26 |
+
*.log
|
27 |
+
|
28 |
+
# Generated files
|
29 |
+
*.zip
|
CLAUDE.md
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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**: Integration with Crawl4AI 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 |
+
- **ScrapingService** (`scraping_service.py`): Crawl4AI integration for web content extraction
|
22 |
+
|
23 |
+
### Package Generation
|
24 |
+
The tool generates complete HuggingFace Spaces with:
|
25 |
+
- `app.py`: Chat interface with OpenRouter API integration
|
26 |
+
- `requirements.txt`: Gradio 5.x and dependencies
|
27 |
+
- `README.md`: Deployment instructions with security setup
|
28 |
+
- `config.json`: Configuration backup
|
29 |
+
- Optional embedded RAG data for document-aware responses
|
30 |
+
|
31 |
+
## Development Commands
|
32 |
+
|
33 |
+
### Running the Application
|
34 |
+
```bash
|
35 |
+
python app.py
|
36 |
+
```
|
37 |
+
|
38 |
+
### Testing Vector Database Functionality
|
39 |
+
```bash
|
40 |
+
python test_vector_db.py
|
41 |
+
```
|
42 |
+
|
43 |
+
### Testing Individual Components
|
44 |
+
```bash
|
45 |
+
# Test document processing only
|
46 |
+
python -c "from test_vector_db import test_document_processing; test_document_processing()"
|
47 |
+
|
48 |
+
# Test vector store only
|
49 |
+
python -c "from test_vector_db import test_vector_store; test_vector_store()"
|
50 |
+
|
51 |
+
# Test full RAG pipeline
|
52 |
+
python -c "from test_vector_db import test_rag_tool; test_rag_tool()"
|
53 |
+
```
|
54 |
+
|
55 |
+
### Dependencies Management
|
56 |
+
```bash
|
57 |
+
pip install -r requirements.txt
|
58 |
+
```
|
59 |
+
|
60 |
+
### Key Dependencies
|
61 |
+
- **Gradio 5.35.0+**: Main UI framework
|
62 |
+
- **Crawl4AI 0.4.0+**: Web scraping with async support
|
63 |
+
- **sentence-transformers**: Embeddings for RAG (optional)
|
64 |
+
- **faiss-cpu**: Vector similarity search (optional)
|
65 |
+
- **PyMuPDF**: PDF text extraction (optional)
|
66 |
+
- **python-docx**: DOCX document processing (optional)
|
67 |
+
- **beautifulsoup4**: HTML parsing for web scraping
|
68 |
+
- **python-dotenv**: Environment variable management
|
69 |
+
|
70 |
+
## Configuration Patterns
|
71 |
+
|
72 |
+
### Template Variables
|
73 |
+
Generated spaces use these template substitutions:
|
74 |
+
- `{name}`, `{description}`: Basic space metadata
|
75 |
+
- `{system_prompt}`: Combined assistant configuration
|
76 |
+
- `{model}`: OpenRouter model selection
|
77 |
+
- `{grounding_urls}`: Static URL list for context
|
78 |
+
- `{enable_dynamic_urls}`: Runtime URL fetching capability
|
79 |
+
- `{enable_vector_rag}`: Document search integration
|
80 |
+
- `{rag_data_json}`: Serialized embeddings and chunks
|
81 |
+
|
82 |
+
### Access Control
|
83 |
+
- Environment variable `SPACE_ACCESS_CODE` for student access control
|
84 |
+
- Global state management for session-based access in generated spaces
|
85 |
+
- Security-first approach storing credentials as HuggingFace Spaces secrets
|
86 |
+
|
87 |
+
### RAG Integration
|
88 |
+
- Modular design with optional imports (`HAS_RAG` flag in app.py:23)
|
89 |
+
- FAISS index serialization for deployment portability
|
90 |
+
- 10MB file size limits with validation
|
91 |
+
- Semantic chunking (800 chars, 100 overlap) for optimal retrieval
|
92 |
+
- Graceful degradation when vector dependencies unavailable
|
93 |
+
|
94 |
+
## Architecture Notes
|
95 |
+
|
96 |
+
### State Management
|
97 |
+
- Extensive use of `gr.State()` for maintaining session data
|
98 |
+
- Global variables for access control in generated templates
|
99 |
+
- URL content caching to prevent redundant web requests
|
100 |
+
|
101 |
+
### Template Generation Pattern
|
102 |
+
All generated HuggingFace Spaces follow consistent structure:
|
103 |
+
1. Configuration section with environment variable loading
|
104 |
+
2. Web scraping functions (sync/async Crawl4AI wrappers)
|
105 |
+
3. RAG context retrieval (if enabled)
|
106 |
+
4. OpenRouter API integration with conversation history
|
107 |
+
5. Gradio ChatInterface with access control
|
108 |
+
|
109 |
+
### Error Handling
|
110 |
+
- Graceful degradation when optional dependencies unavailable
|
111 |
+
- Comprehensive validation for file uploads and URL processing
|
112 |
+
- User-friendly error messages with specific guidance
|
113 |
+
|
114 |
+
### Security Considerations
|
115 |
+
- Never embed API keys or access codes in generated templates
|
116 |
+
- Environment variable pattern for all sensitive configuration
|
117 |
+
- Input validation for uploaded files and URL processing
|
118 |
+
- Content length limits for web scraping operations
|
119 |
+
|
120 |
+
### Dependency Management Pattern
|
121 |
+
The codebase uses conditional imports with feature flags:
|
122 |
+
```python
|
123 |
+
try:
|
124 |
+
from rag_tool import RAGTool
|
125 |
+
HAS_RAG = True
|
126 |
+
except ImportError:
|
127 |
+
HAS_RAG = False
|
128 |
+
RAGTool = None
|
129 |
+
```
|
130 |
+
This pattern allows the main application to function even when optional vector database dependencies are unavailable.
|
131 |
+
|
132 |
+
## Important Implementation Details
|
133 |
+
|
134 |
+
### Gradio 5.x Compatibility
|
135 |
+
- Uses `type="messages"` for chat history format
|
136 |
+
- `gr.ChatInterface` for modern chat UI components
|
137 |
+
- Proper message format handling for OpenRouter API
|
138 |
+
|
139 |
+
### Dynamic URL Fetching
|
140 |
+
When enabled, generated spaces can extract URLs from user messages and fetch content dynamically using regex pattern matching and Crawl4AI processing.
|
141 |
+
|
142 |
+
### Vector RAG Workflow
|
143 |
+
1. Documents uploaded through Gradio File component
|
144 |
+
2. Processed via DocumentProcessor (PDF/DOCX/TXT/MD support)
|
145 |
+
3. Chunked and embedded using sentence-transformers
|
146 |
+
4. FAISS index created and serialized to base64
|
147 |
+
5. Embedded in generated template for deployment portability
|
148 |
+
6. Runtime similarity search for context-aware responses
|
149 |
+
|
150 |
+
### Mock vs Production Web Scraping
|
151 |
+
The application has two modes for web scraping:
|
152 |
+
- **Mock mode** (lines 14-18 in app.py): Returns placeholder content for testing
|
153 |
+
- **Production mode**: Uses Crawl4AI via scraping_service.py for actual web content extraction
|
154 |
+
|
155 |
+
Switch between modes by commenting/uncommenting the imports and function definitions.
|
CLAUDE_DESKTOP_DEVELOPMENT.md
ADDED
@@ -0,0 +1,411 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Claude Desktop Development Guidelines
|
2 |
+
|
3 |
+
## Overview
|
4 |
+
This document provides comprehensive guidelines for all-purpose software architecting and development when working with Claude Desktop. These instructions optimize collaboration between developers and Claude for efficient, high-quality software delivery.
|
5 |
+
|
6 |
+
## Core Principles
|
7 |
+
|
8 |
+
### 1. Context-First Development
|
9 |
+
- **Always provide context**: Before asking Claude to work on code, ensure it has adequate context about the project structure, technologies used, and existing patterns
|
10 |
+
- **Use file exploration**: Leverage Claude's file reading capabilities to understand codebases before making changes
|
11 |
+
- **Reference existing patterns**: Point Claude to similar implementations in the codebase to maintain consistency
|
12 |
+
|
13 |
+
### 2. Incremental and Iterative Approach
|
14 |
+
- **Break down complex tasks**: Divide large features into smaller, manageable components
|
15 |
+
- **Test frequently**: Implement and test individual components before moving to the next
|
16 |
+
- **Use TodoWrite**: Track progress on complex tasks to maintain visibility and ensure nothing is missed
|
17 |
+
|
18 |
+
### 3. Documentation-Driven Development
|
19 |
+
- **CLAUDE.md integration**: Maintain project-specific instructions in CLAUDE.md for consistent behavior
|
20 |
+
- **Code documentation**: Ensure all complex logic is well-documented for future maintenance
|
21 |
+
- **Architecture decisions**: Document architectural choices and trade-offs
|
22 |
+
|
23 |
+
## Project Architecture Guidelines
|
24 |
+
|
25 |
+
### File Organization
|
26 |
+
```
|
27 |
+
project-root/
|
28 |
+
βββ CLAUDE.md # Claude-specific project instructions
|
29 |
+
βββ README.md # Project overview and setup
|
30 |
+
βββ .env.example # Environment variable template
|
31 |
+
βββ src/
|
32 |
+
β βββ components/ # Reusable UI components
|
33 |
+
β βββ services/ # Business logic and API calls
|
34 |
+
β βββ utils/ # Helper functions and utilities
|
35 |
+
β βββ types/ # Type definitions (TypeScript)
|
36 |
+
β βββ tests/ # Test files
|
37 |
+
βββ docs/ # Additional documentation
|
38 |
+
βββ scripts/ # Build and deployment scripts
|
39 |
+
βββ config/ # Configuration files
|
40 |
+
```
|
41 |
+
|
42 |
+
### Configuration Management
|
43 |
+
- **Environment-based configs**: Use environment variables for deployment-specific settings
|
44 |
+
- **Type-safe configurations**: Define configuration schemas with validation
|
45 |
+
- **Hierarchical configs**: Support development, staging, and production configurations
|
46 |
+
- **Secret management**: Never commit secrets; use environment variables or secret management tools
|
47 |
+
|
48 |
+
### Error Handling Strategy
|
49 |
+
- **Graceful degradation**: Design systems to handle failures gracefully
|
50 |
+
- **Comprehensive logging**: Implement structured logging for debugging and monitoring
|
51 |
+
- **User-friendly errors**: Provide meaningful error messages to end users
|
52 |
+
- **Recovery mechanisms**: Implement retry logic and fallback strategies where appropriate
|
53 |
+
|
54 |
+
## Development Workflow
|
55 |
+
|
56 |
+
### 1. Project Initialization
|
57 |
+
```bash
|
58 |
+
# Set up project structure
|
59 |
+
mkdir project-name && cd project-name
|
60 |
+
git init
|
61 |
+
touch CLAUDE.md README.md .env.example
|
62 |
+
mkdir -p src/{components,services,utils,types,tests}
|
63 |
+
```
|
64 |
+
|
65 |
+
### 2. CLAUDE.md Configuration
|
66 |
+
Create project-specific instructions:
|
67 |
+
```markdown
|
68 |
+
# Project: [Project Name]
|
69 |
+
|
70 |
+
## Tech Stack
|
71 |
+
- Framework: [React/Vue/Angular/etc.]
|
72 |
+
- Language: [TypeScript/JavaScript/Python/etc.]
|
73 |
+
- Database: [PostgreSQL/MongoDB/etc.]
|
74 |
+
- Testing: [Jest/Pytest/etc.]
|
75 |
+
|
76 |
+
## Coding Standards
|
77 |
+
- Use TypeScript for all new code
|
78 |
+
- Follow ESLint configuration
|
79 |
+
- Write tests for all business logic
|
80 |
+
- Document complex functions
|
81 |
+
|
82 |
+
## Architecture Patterns
|
83 |
+
- Use custom hooks for React state logic
|
84 |
+
- Implement repository pattern for data access
|
85 |
+
- Follow MVC pattern for API endpoints
|
86 |
+
|
87 |
+
## Deployment
|
88 |
+
- Test commands: npm test
|
89 |
+
- Build commands: npm run build
|
90 |
+
- Lint commands: npm run lint
|
91 |
+
```
|
92 |
+
|
93 |
+
### 3. Development Process
|
94 |
+
1. **Analysis Phase**
|
95 |
+
- Understand requirements thoroughly
|
96 |
+
- Review existing codebase patterns
|
97 |
+
- Identify potential integration points
|
98 |
+
- Plan architecture approach
|
99 |
+
|
100 |
+
2. **Implementation Phase**
|
101 |
+
- Start with core functionality
|
102 |
+
- Build incrementally with frequent testing
|
103 |
+
- Maintain consistent code style
|
104 |
+
- Document as you go
|
105 |
+
|
106 |
+
3. **Testing Phase**
|
107 |
+
- Unit tests for individual components
|
108 |
+
- Integration tests for workflows
|
109 |
+
- End-to-end tests for critical paths
|
110 |
+
- Performance testing where relevant
|
111 |
+
|
112 |
+
4. **Documentation Phase**
|
113 |
+
- Update README if necessary
|
114 |
+
- Document API changes
|
115 |
+
- Update configuration guides
|
116 |
+
- Record architectural decisions
|
117 |
+
|
118 |
+
## Tool Usage Best Practices
|
119 |
+
|
120 |
+
### File Operations
|
121 |
+
- **Read before edit**: Always read files before making changes to understand context
|
122 |
+
- **Batch operations**: Use MultiEdit for multiple changes to the same file
|
123 |
+
- **Glob patterns**: Use Glob tool for finding files by patterns
|
124 |
+
- **Grep for search**: Use Grep tool for content searches across files
|
125 |
+
|
126 |
+
### Code Quality
|
127 |
+
- **Linting**: Run linters before committing code
|
128 |
+
- **Type checking**: Ensure TypeScript compilation succeeds
|
129 |
+
- **Testing**: Run test suites and ensure they pass
|
130 |
+
- **Security**: Never commit secrets or sensitive information
|
131 |
+
|
132 |
+
### Git Integration
|
133 |
+
- **Atomic commits**: Make focused commits with clear messages
|
134 |
+
- **Branch strategy**: Use feature branches for development
|
135 |
+
- **Pull requests**: Create PRs with comprehensive descriptions
|
136 |
+
- **Commit messages**: Follow conventional commit format
|
137 |
+
|
138 |
+
## Technology-Specific Guidelines
|
139 |
+
|
140 |
+
### Frontend Development
|
141 |
+
```typescript
|
142 |
+
// Component structure
|
143 |
+
interface Props {
|
144 |
+
// Define all props with types
|
145 |
+
}
|
146 |
+
|
147 |
+
export const Component: React.FC<Props> = ({ prop1, prop2 }) => {
|
148 |
+
// Custom hooks for state management
|
149 |
+
const { state, actions } = useCustomHook();
|
150 |
+
|
151 |
+
// Event handlers
|
152 |
+
const handleSubmit = useCallback((event: FormEvent) => {
|
153 |
+
// Implementation
|
154 |
+
}, [dependencies]);
|
155 |
+
|
156 |
+
return (
|
157 |
+
// JSX with proper accessibility
|
158 |
+
);
|
159 |
+
};
|
160 |
+
```
|
161 |
+
|
162 |
+
### Backend Development
|
163 |
+
```python
|
164 |
+
# Service layer pattern
|
165 |
+
class UserService:
|
166 |
+
def __init__(self, repository: UserRepository):
|
167 |
+
self.repository = repository
|
168 |
+
|
169 |
+
async def create_user(self, user_data: UserCreateSchema) -> User:
|
170 |
+
# Validation
|
171 |
+
# Business logic
|
172 |
+
# Persistence
|
173 |
+
return await self.repository.create(user_data)
|
174 |
+
|
175 |
+
# API endpoint
|
176 |
+
@router.post("/users", response_model=UserResponse)
|
177 |
+
async def create_user(
|
178 |
+
user_data: UserCreateSchema,
|
179 |
+
service: UserService = Depends(get_user_service)
|
180 |
+
):
|
181 |
+
return await service.create_user(user_data)
|
182 |
+
```
|
183 |
+
|
184 |
+
### Database Design
|
185 |
+
- **Normalization**: Design normalized schemas to avoid data duplication
|
186 |
+
- **Indexing**: Add indexes for frequently queried columns
|
187 |
+
- **Migrations**: Use migration scripts for schema changes
|
188 |
+
- **Relationships**: Define clear foreign key relationships
|
189 |
+
|
190 |
+
## Security Guidelines
|
191 |
+
|
192 |
+
### Authentication & Authorization
|
193 |
+
- **JWT tokens**: Use short-lived access tokens with refresh tokens
|
194 |
+
- **Role-based access**: Implement granular permission systems
|
195 |
+
- **Input validation**: Validate all user inputs server-side
|
196 |
+
- **Rate limiting**: Implement rate limiting for API endpoints
|
197 |
+
|
198 |
+
### Data Protection
|
199 |
+
- **Encryption**: Encrypt sensitive data at rest and in transit
|
200 |
+
- **Environment variables**: Store secrets in environment variables
|
201 |
+
- **HTTPS**: Always use HTTPS in production
|
202 |
+
- **CORS**: Configure CORS policies appropriately
|
203 |
+
|
204 |
+
## Performance Optimization
|
205 |
+
|
206 |
+
### Frontend
|
207 |
+
- **Code splitting**: Implement route-based code splitting
|
208 |
+
- **Lazy loading**: Lazy load components and images
|
209 |
+
- **Memoization**: Use React.memo and useMemo for expensive operations
|
210 |
+
- **Bundle analysis**: Regularly analyze bundle sizes
|
211 |
+
|
212 |
+
### Backend
|
213 |
+
- **Caching**: Implement Redis caching for frequently accessed data
|
214 |
+
- **Database optimization**: Use connection pooling and query optimization
|
215 |
+
- **Async operations**: Use async/await for I/O operations
|
216 |
+
- **Monitoring**: Implement application performance monitoring
|
217 |
+
|
218 |
+
## Testing Strategy
|
219 |
+
|
220 |
+
### Unit Tests
|
221 |
+
```typescript
|
222 |
+
describe('UserService', () => {
|
223 |
+
it('should create user with valid data', async () => {
|
224 |
+
// Arrange
|
225 |
+
const userData = { name: 'John', email: '[email protected]' };
|
226 |
+
|
227 |
+
// Act
|
228 |
+
const result = await userService.createUser(userData);
|
229 |
+
|
230 |
+
// Assert
|
231 |
+
expect(result).toMatchObject(userData);
|
232 |
+
});
|
233 |
+
});
|
234 |
+
```
|
235 |
+
|
236 |
+
### Integration Tests
|
237 |
+
- Test API endpoints with real database
|
238 |
+
- Test component integration with services
|
239 |
+
- Test external service integrations
|
240 |
+
- Verify error handling scenarios
|
241 |
+
|
242 |
+
### E2E Tests
|
243 |
+
```typescript
|
244 |
+
test('user registration flow', async ({ page }) => {
|
245 |
+
await page.goto('/register');
|
246 |
+
await page.fill('[data-testid="email"]', '[email protected]');
|
247 |
+
await page.fill('[data-testid="password"]', 'password123');
|
248 |
+
await page.click('[data-testid="submit"]');
|
249 |
+
await expect(page).toHaveURL('/dashboard');
|
250 |
+
});
|
251 |
+
```
|
252 |
+
|
253 |
+
## Deployment Guidelines
|
254 |
+
|
255 |
+
### Environment Configuration
|
256 |
+
```bash
|
257 |
+
# Development
|
258 |
+
NODE_ENV=development
|
259 |
+
DATABASE_URL=postgresql://localhost:5432/myapp_dev
|
260 |
+
API_URL=http://localhost:3000
|
261 |
+
|
262 |
+
# Production
|
263 |
+
NODE_ENV=production
|
264 |
+
DATABASE_URL=${DATABASE_URL}
|
265 |
+
API_URL=https://api.myapp.com
|
266 |
+
```
|
267 |
+
|
268 |
+
### CI/CD Pipeline
|
269 |
+
```yaml
|
270 |
+
# .github/workflows/deploy.yml
|
271 |
+
name: Deploy
|
272 |
+
on:
|
273 |
+
push:
|
274 |
+
branches: [main]
|
275 |
+
jobs:
|
276 |
+
test:
|
277 |
+
runs-on: ubuntu-latest
|
278 |
+
steps:
|
279 |
+
- uses: actions/checkout@v2
|
280 |
+
- run: npm ci
|
281 |
+
- run: npm test
|
282 |
+
- run: npm run lint
|
283 |
+
- run: npm run build
|
284 |
+
deploy:
|
285 |
+
needs: test
|
286 |
+
runs-on: ubuntu-latest
|
287 |
+
steps:
|
288 |
+
- run: echo "Deploy to production"
|
289 |
+
```
|
290 |
+
|
291 |
+
## Monitoring and Maintenance
|
292 |
+
|
293 |
+
### Application Monitoring
|
294 |
+
- **Error tracking**: Use services like Sentry for error monitoring
|
295 |
+
- **Performance monitoring**: Track application performance metrics
|
296 |
+
- **User analytics**: Monitor user behavior and feature usage
|
297 |
+
- **Infrastructure monitoring**: Monitor server resources and uptime
|
298 |
+
|
299 |
+
### Maintenance Tasks
|
300 |
+
- **Dependency updates**: Regularly update dependencies
|
301 |
+
- **Security patches**: Apply security updates promptly
|
302 |
+
- **Database maintenance**: Regular backups and performance tuning
|
303 |
+
- **Documentation updates**: Keep documentation current
|
304 |
+
|
305 |
+
## Collaboration Guidelines
|
306 |
+
|
307 |
+
### Code Reviews
|
308 |
+
- **Review scope**: Focus on logic, security, and maintainability
|
309 |
+
- **Constructive feedback**: Provide specific, actionable feedback
|
310 |
+
- **Testing verification**: Ensure tests cover new functionality
|
311 |
+
- **Documentation check**: Verify documentation is updated
|
312 |
+
|
313 |
+
### Communication
|
314 |
+
- **Clear requirements**: Provide detailed specifications
|
315 |
+
- **Progress updates**: Regular status updates on complex tasks
|
316 |
+
- **Technical discussions**: Use pull request comments for technical discussions
|
317 |
+
- **Knowledge sharing**: Document learnings and solutions
|
318 |
+
|
319 |
+
## Common Patterns
|
320 |
+
|
321 |
+
### State Management
|
322 |
+
```typescript
|
323 |
+
// Custom hook pattern
|
324 |
+
export const useUserData = () => {
|
325 |
+
const [user, setUser] = useState<User | null>(null);
|
326 |
+
const [loading, setLoading] = useState(true);
|
327 |
+
const [error, setError] = useState<string | null>(null);
|
328 |
+
|
329 |
+
const fetchUser = useCallback(async (id: string) => {
|
330 |
+
try {
|
331 |
+
setLoading(true);
|
332 |
+
const userData = await userService.getUser(id);
|
333 |
+
setUser(userData);
|
334 |
+
} catch (err) {
|
335 |
+
setError(err.message);
|
336 |
+
} finally {
|
337 |
+
setLoading(false);
|
338 |
+
}
|
339 |
+
}, []);
|
340 |
+
|
341 |
+
return { user, loading, error, fetchUser };
|
342 |
+
};
|
343 |
+
```
|
344 |
+
|
345 |
+
### API Integration
|
346 |
+
```typescript
|
347 |
+
// Repository pattern
|
348 |
+
export class ApiRepository {
|
349 |
+
constructor(private httpClient: HttpClient) {}
|
350 |
+
|
351 |
+
async get<T>(endpoint: string): Promise<T> {
|
352 |
+
try {
|
353 |
+
const response = await this.httpClient.get(endpoint);
|
354 |
+
return response.data;
|
355 |
+
} catch (error) {
|
356 |
+
throw new ApiError(error.message, error.status);
|
357 |
+
}
|
358 |
+
}
|
359 |
+
}
|
360 |
+
```
|
361 |
+
|
362 |
+
### Configuration
|
363 |
+
```typescript
|
364 |
+
// Type-safe configuration
|
365 |
+
interface Config {
|
366 |
+
api: {
|
367 |
+
baseUrl: string;
|
368 |
+
timeout: number;
|
369 |
+
};
|
370 |
+
features: {
|
371 |
+
enableNewFeature: boolean;
|
372 |
+
};
|
373 |
+
}
|
374 |
+
|
375 |
+
export const config: Config = {
|
376 |
+
api: {
|
377 |
+
baseUrl: process.env.API_URL || 'http://localhost:3000',
|
378 |
+
timeout: parseInt(process.env.API_TIMEOUT || '5000'),
|
379 |
+
},
|
380 |
+
features: {
|
381 |
+
enableNewFeature: process.env.ENABLE_NEW_FEATURE === 'true',
|
382 |
+
},
|
383 |
+
};
|
384 |
+
```
|
385 |
+
|
386 |
+
## Troubleshooting Guide
|
387 |
+
|
388 |
+
### Common Issues
|
389 |
+
1. **Build failures**: Check dependency versions and environment variables
|
390 |
+
2. **Test failures**: Verify test data and mock configurations
|
391 |
+
3. **Performance issues**: Profile code and check for memory leaks
|
392 |
+
4. **Security vulnerabilities**: Run security audits and update dependencies
|
393 |
+
|
394 |
+
### Debugging Strategies
|
395 |
+
- **Structured logging**: Use consistent log levels and formats
|
396 |
+
- **Debug tools**: Leverage browser dev tools and IDE debuggers
|
397 |
+
- **Error boundaries**: Implement React error boundaries for graceful failures
|
398 |
+
- **Health checks**: Implement endpoint health checks for monitoring
|
399 |
+
|
400 |
+
## Conclusion
|
401 |
+
|
402 |
+
These guidelines provide a comprehensive framework for developing high-quality software with Claude Desktop. Adapt these patterns to fit your specific project needs while maintaining the core principles of clarity, maintainability, and security.
|
403 |
+
|
404 |
+
Remember to:
|
405 |
+
- Keep documentation updated
|
406 |
+
- Test thoroughly at each stage
|
407 |
+
- Follow security best practices
|
408 |
+
- Maintain consistent code quality
|
409 |
+
- Collaborate effectively with clear communication
|
410 |
+
|
411 |
+
For project-specific guidance, always reference the CLAUDE.md file in your project root.
|
README.md
CHANGED
@@ -4,7 +4,7 @@ emoji: π»
|
|
4 |
colorFrom: gray
|
5 |
colorTo: red
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 5.
|
8 |
app_file: app.py
|
9 |
pinned: true
|
10 |
thumbnail: >-
|
@@ -14,17 +14,49 @@ short_description: Configure, download, and deploy a simple chat interface
|
|
14 |
|
15 |
# Chat UI Helper
|
16 |
|
17 |
-
A tool
|
18 |
|
19 |
## Features
|
20 |
|
21 |
-
|
22 |
-
|
|
|
|
|
|
|
|
|
23 |
|
24 |
-
|
|
|
|
|
|
|
25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
Set your OpenRouter API key as a secret:
|
27 |
- Go to Settings β Variables and secrets
|
28 |
- Add secret: `OPENROUTER_API_KEY`
|
29 |
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
colorFrom: gray
|
5 |
colorTo: red
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 5.35.0
|
8 |
app_file: app.py
|
9 |
pinned: true
|
10 |
thumbnail: >-
|
|
|
14 |
|
15 |
# Chat UI Helper
|
16 |
|
17 |
+
A Gradio-based tool for generating and configuring chat interfaces for HuggingFace Spaces. Create deployable packages with custom assistants, web scraping capabilities, and optional vector RAG functionality.
|
18 |
|
19 |
## Features
|
20 |
|
21 |
+
### Spaces Configuration
|
22 |
+
- **Custom Assistant Creation**: Define role, purpose, audience, and tasks
|
23 |
+
- **Template System**: Choose from research assistant template or build from scratch
|
24 |
+
- **Tool Integration**: Optional dynamic URL fetching and document RAG
|
25 |
+
- **Access Control**: Secure access code protection for educational use
|
26 |
+
- **Complete Deployment Package**: Generates app.py, requirements.txt, README.md, and config.json
|
27 |
|
28 |
+
### Chat Support
|
29 |
+
- **Expert Guidance**: Get personalized help with Gradio configurations
|
30 |
+
- **Context-Aware**: URL grounding for informed responses about HuggingFace Spaces
|
31 |
+
- **Deployment Assistance**: Troubleshooting and best practices
|
32 |
|
33 |
+
## Quick Start
|
34 |
+
|
35 |
+
### Running Locally
|
36 |
+
```bash
|
37 |
+
pip install -r requirements.txt
|
38 |
+
python app.py
|
39 |
+
```
|
40 |
+
|
41 |
+
### For Chat Support (Optional)
|
42 |
Set your OpenRouter API key as a secret:
|
43 |
- Go to Settings β Variables and secrets
|
44 |
- Add secret: `OPENROUTER_API_KEY`
|
45 |
|
46 |
+
## Generated Space Features
|
47 |
+
|
48 |
+
Each generated space includes:
|
49 |
+
- **OpenRouter API Integration**: Support for multiple LLM models
|
50 |
+
- **Web Scraping**: Crawl4AI integration for URL content fetching
|
51 |
+
- **Document RAG**: Optional upload and search through PDF, DOCX, TXT, MD files
|
52 |
+
- **Access Control**: Environment-based student access codes
|
53 |
+
- **Modern UI**: Gradio 5.x ChatInterface with proper message formatting
|
54 |
+
|
55 |
+
## Architecture
|
56 |
+
|
57 |
+
- **Main Application**: `app.py` with two-tab interface
|
58 |
+
- **Document Processing**: RAG pipeline with FAISS vector search
|
59 |
+
- **Web Scraping**: Async Crawl4AI integration
|
60 |
+
- **Template Generation**: Complete HuggingFace Space creation
|
61 |
+
|
62 |
+
For detailed development guidance, see [CLAUDE.md](CLAUDE.md).
|
app.py
CHANGED
@@ -42,7 +42,8 @@ SPACE_DESCRIPTION = "{description}"
|
|
42 |
SYSTEM_PROMPT = """{system_prompt}"""
|
43 |
MODEL = "{model}"
|
44 |
GROUNDING_URLS = {grounding_urls}
|
45 |
-
|
|
|
46 |
ENABLE_DYNAMIC_URLS = {enable_dynamic_urls}
|
47 |
ENABLE_VECTOR_RAG = {enable_vector_rag}
|
48 |
RAG_DATA = {rag_data_json}
|
@@ -224,20 +225,26 @@ def generate_response(message, history):
|
|
224 |
|
225 |
# Access code verification
|
226 |
access_granted = gr.State(False)
|
|
|
227 |
|
228 |
def verify_access_code(code):
|
229 |
\"\"\"Verify the access code\"\"\"
|
|
|
230 |
if not ACCESS_CODE:
|
|
|
231 |
return gr.update(visible=False), gr.update(visible=True), True
|
232 |
|
233 |
if code == ACCESS_CODE:
|
|
|
234 |
return gr.update(visible=False), gr.update(visible=True), True
|
235 |
else:
|
|
|
236 |
return gr.update(visible=True, value="β Incorrect access code. Please try again."), gr.update(visible=False), False
|
237 |
|
238 |
-
def protected_generate_response(message, history
|
239 |
\"\"\"Protected response function that checks access\"\"\"
|
240 |
-
if
|
|
|
241 |
return "Please enter the access code to continue."
|
242 |
return generate_response(message, history)
|
243 |
|
@@ -262,7 +269,7 @@ with gr.Blocks(title=SPACE_NAME) as demo:
|
|
262 |
# Main chat interface (hidden until access granted)
|
263 |
with gr.Column(visible=not bool(ACCESS_CODE)) as chat_section:
|
264 |
chat_interface = gr.ChatInterface(
|
265 |
-
fn=
|
266 |
title="", # Title already shown above
|
267 |
description="", # Description already shown above
|
268 |
examples={examples}
|
@@ -344,7 +351,7 @@ emoji: π€
|
|
344 |
colorFrom: blue
|
345 |
colorTo: red
|
346 |
sdk: gradio
|
347 |
-
sdk_version:
|
348 |
app_file: app.py
|
349 |
pinned: false
|
350 |
---
|
@@ -378,15 +385,22 @@ pinned: false
|
|
378 |
5. Value: Your OpenRouter API key
|
379 |
6. Click "Add"
|
380 |
|
381 |
-
{f'''### Step 4: Configure Access Control
|
382 |
Your Space is configured with access code protection. Students will need to enter the access code to use the chatbot.
|
383 |
|
384 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
|
386 |
To disable access protection:
|
387 |
-
1.
|
388 |
-
2.
|
389 |
-
3. The Space will rebuild automatically
|
390 |
|
391 |
''' if config['access_code'] else ''}
|
392 |
|
@@ -448,7 +462,7 @@ Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} with Chat U/I Helper
|
|
448 |
|
449 |
def create_requirements(enable_vector_rag=False):
|
450 |
"""Generate requirements.txt"""
|
451 |
-
base_requirements = "gradio
|
452 |
|
453 |
if enable_vector_rag:
|
454 |
base_requirements += "\nfaiss-cpu==1.7.4\nnumpy==1.24.3"
|
@@ -499,15 +513,18 @@ def generate_zip(name, description, role_purpose, intended_audience, key_tasks,
|
|
499 |
'max_tokens': int(max_tokens),
|
500 |
'examples': examples_json,
|
501 |
'grounding_urls': json.dumps(grounding_urls),
|
502 |
-
'access_code':
|
503 |
'enable_dynamic_urls': enable_dynamic_urls,
|
504 |
'enable_vector_rag': enable_vector_rag,
|
505 |
-
'rag_data_json': json.dumps(rag_data) if rag_data else '
|
506 |
}
|
507 |
|
508 |
# Generate files
|
509 |
app_content = SPACE_TEMPLATE.format(**config)
|
510 |
-
|
|
|
|
|
|
|
511 |
requirements_content = create_requirements(enable_vector_rag)
|
512 |
|
513 |
# Create zip file with clean naming
|
@@ -658,7 +675,8 @@ def respond(message, chat_history, url1="", url2="", url3="", url4=""):
|
|
658 |
|
659 |
if not api_key:
|
660 |
response = "Please set your OPENROUTER_API_KEY in the Space settings to use the chat support."
|
661 |
-
chat_history.append(
|
|
|
662 |
return "", chat_history
|
663 |
|
664 |
# Get grounding context from URLs using cached approach
|
@@ -789,15 +807,7 @@ def remove_chat_urls(count):
|
|
789 |
|
790 |
def update_template_fields(choice):
|
791 |
"""Update assistant configuration fields based on template choice"""
|
792 |
-
if choice == "
|
793 |
-
return (
|
794 |
-
gr.update(value="You are a research assistant that provides link-grounded information through Crawl4AI web fetching. Use MLA documentation for parenthetical citations and bibliographic entries."),
|
795 |
-
gr.update(value="This assistant is designed for students and researchers conducting academic inquiry."),
|
796 |
-
gr.update(value="Your main responsibilities include: analyzing academic sources, fact-checking claims with evidence, providing properly cited research summaries, and helping users navigate scholarly information."),
|
797 |
-
gr.update(value="Ground all responses in provided URL contexts and any additional URLs you're instructed to fetch. Never rely on memory for factual claims."),
|
798 |
-
gr.update(value=True) # Enable dynamic URL fetching for research template
|
799 |
-
)
|
800 |
-
else: # Custom assistant from scratch
|
801 |
return (
|
802 |
gr.update(value=""),
|
803 |
gr.update(value=""),
|
@@ -805,6 +815,14 @@ def update_template_fields(choice):
|
|
805 |
gr.update(value=""),
|
806 |
gr.update(value=False) # Disable dynamic URL fetching for custom template
|
807 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
808 |
|
809 |
# Create Gradio interface with proper tab structure
|
810 |
with gr.Blocks(title="Chat U/I Helper") as demo:
|
@@ -824,7 +842,7 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
824 |
label="Space Description",
|
825 |
placeholder="A customizable AI chat interface for...",
|
826 |
lines=2,
|
827 |
-
value="
|
828 |
)
|
829 |
|
830 |
model = gr.Dropdown(
|
@@ -853,10 +871,10 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
853 |
template_choice = gr.Radio(
|
854 |
label="How would you like to get started?",
|
855 |
choices=[
|
856 |
-
"
|
857 |
-
"
|
858 |
],
|
859 |
-
value="
|
860 |
info="Choose a starting point for your assistant configuration"
|
861 |
)
|
862 |
|
@@ -864,7 +882,7 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
864 |
label="Role and Purpose",
|
865 |
placeholder="You are a research assistant that...",
|
866 |
lines=2,
|
867 |
-
value="
|
868 |
info="Define what the assistant is and its primary function"
|
869 |
)
|
870 |
|
@@ -872,7 +890,7 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
872 |
label="Intended Audience",
|
873 |
placeholder="This assistant is designed for undergraduate students...",
|
874 |
lines=2,
|
875 |
-
value="
|
876 |
info="Specify who will be using this assistant and their context"
|
877 |
)
|
878 |
|
@@ -880,7 +898,7 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
880 |
label="Key Tasks",
|
881 |
placeholder="Your main responsibilities include...",
|
882 |
lines=3,
|
883 |
-
value="
|
884 |
info="List the specific tasks and capabilities the assistant should focus on"
|
885 |
)
|
886 |
|
@@ -888,11 +906,13 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
888 |
label="Additional Context",
|
889 |
placeholder="Remember to always...",
|
890 |
lines=2,
|
891 |
-
value="
|
892 |
info="Any additional instructions, constraints, or behavioral guidelines"
|
893 |
)
|
|
|
|
|
|
|
894 |
|
895 |
-
gr.Markdown("### Tool Settings")
|
896 |
enable_dynamic_urls = gr.Checkbox(
|
897 |
label="Enable Dynamic URL Fetching",
|
898 |
value=False,
|
@@ -920,13 +940,6 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
920 |
# State to store RAG tool
|
921 |
rag_tool_state = gr.State(None)
|
922 |
|
923 |
-
examples_text = gr.Textbox(
|
924 |
-
label="Example Prompts (one per line)",
|
925 |
-
placeholder="Can you analyze this research paper: https://example.com/paper.pdf\nWhat are the latest findings on climate change adaptation?\nHelp me fact-check claims about renewable energy efficiency",
|
926 |
-
lines=3,
|
927 |
-
info="These will appear as clickable examples in the chat interface"
|
928 |
-
)
|
929 |
-
|
930 |
with gr.Accordion("URL Grounding (Optional)", open=False):
|
931 |
gr.Markdown("Add URLs to provide context. Content will be fetched and added to the system prompt.")
|
932 |
|
@@ -964,6 +977,13 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
964 |
remove_url_btn = gr.Button("- Remove URLs", size="sm", visible=False)
|
965 |
url_count = gr.State(2) # Track number of visible URLs
|
966 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
967 |
with gr.Row():
|
968 |
temperature = gr.Slider(
|
969 |
label="Temperature",
|
@@ -1036,7 +1056,8 @@ with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
1036 |
chatbot = gr.Chatbot(
|
1037 |
value=[],
|
1038 |
label="Chat Support Assistant",
|
1039 |
-
height=400
|
|
|
1040 |
)
|
1041 |
msg = gr.Textbox(
|
1042 |
label="Ask about configuring chat UIs for courses, research, or custom HuggingFace Spaces",
|
|
|
42 |
SYSTEM_PROMPT = """{system_prompt}"""
|
43 |
MODEL = "{model}"
|
44 |
GROUNDING_URLS = {grounding_urls}
|
45 |
+
# Get access code from environment variable for security
|
46 |
+
ACCESS_CODE = os.environ.get("SPACE_ACCESS_CODE", "{access_code}")
|
47 |
ENABLE_DYNAMIC_URLS = {enable_dynamic_urls}
|
48 |
ENABLE_VECTOR_RAG = {enable_vector_rag}
|
49 |
RAG_DATA = {rag_data_json}
|
|
|
225 |
|
226 |
# Access code verification
|
227 |
access_granted = gr.State(False)
|
228 |
+
_access_granted_global = False # Global fallback
|
229 |
|
230 |
def verify_access_code(code):
|
231 |
\"\"\"Verify the access code\"\"\"
|
232 |
+
global _access_granted_global
|
233 |
if not ACCESS_CODE:
|
234 |
+
_access_granted_global = True
|
235 |
return gr.update(visible=False), gr.update(visible=True), True
|
236 |
|
237 |
if code == ACCESS_CODE:
|
238 |
+
_access_granted_global = True
|
239 |
return gr.update(visible=False), gr.update(visible=True), True
|
240 |
else:
|
241 |
+
_access_granted_global = False
|
242 |
return gr.update(visible=True, value="β Incorrect access code. Please try again."), gr.update(visible=False), False
|
243 |
|
244 |
+
def protected_generate_response(message, history):
|
245 |
\"\"\"Protected response function that checks access\"\"\"
|
246 |
+
# Check if access is granted via the global variable
|
247 |
+
if ACCESS_CODE and not _access_granted_global:
|
248 |
return "Please enter the access code to continue."
|
249 |
return generate_response(message, history)
|
250 |
|
|
|
269 |
# Main chat interface (hidden until access granted)
|
270 |
with gr.Column(visible=not bool(ACCESS_CODE)) as chat_section:
|
271 |
chat_interface = gr.ChatInterface(
|
272 |
+
fn=protected_generate_response,
|
273 |
title="", # Title already shown above
|
274 |
description="", # Description already shown above
|
275 |
examples={examples}
|
|
|
351 |
colorFrom: blue
|
352 |
colorTo: red
|
353 |
sdk: gradio
|
354 |
+
sdk_version: 5.35.0
|
355 |
app_file: app.py
|
356 |
pinned: false
|
357 |
---
|
|
|
385 |
5. Value: Your OpenRouter API key
|
386 |
6. Click "Add"
|
387 |
|
388 |
+
{f'''### Step 4: Configure Access Control
|
389 |
Your Space is configured with access code protection. Students will need to enter the access code to use the chatbot.
|
390 |
|
391 |
+
1. Go to Settings (gear icon)
|
392 |
+
2. Click "Variables and secrets"
|
393 |
+
3. Click "New secret"
|
394 |
+
4. Name: `SPACE_ACCESS_CODE`
|
395 |
+
5. Value: `{config['access_code']}`
|
396 |
+
6. Click "Add"
|
397 |
+
|
398 |
+
**Important**: The access code is now stored securely as an environment variable and is not visible in your app code.
|
399 |
|
400 |
To disable access protection:
|
401 |
+
1. Go to Settings β Variables and secrets
|
402 |
+
2. Delete the `SPACE_ACCESS_CODE` secret
|
403 |
+
3. The Space will rebuild automatically with no access protection
|
404 |
|
405 |
''' if config['access_code'] else ''}
|
406 |
|
|
|
462 |
|
463 |
def create_requirements(enable_vector_rag=False):
|
464 |
"""Generate requirements.txt"""
|
465 |
+
base_requirements = "gradio>=5.35.0\nrequests>=2.32.3\ncrawl4ai>=0.4.0\naiofiles>=24.0"
|
466 |
|
467 |
if enable_vector_rag:
|
468 |
base_requirements += "\nfaiss-cpu==1.7.4\nnumpy==1.24.3"
|
|
|
513 |
'max_tokens': int(max_tokens),
|
514 |
'examples': examples_json,
|
515 |
'grounding_urls': json.dumps(grounding_urls),
|
516 |
+
'access_code': "", # Access code stored in environment variable for security
|
517 |
'enable_dynamic_urls': enable_dynamic_urls,
|
518 |
'enable_vector_rag': enable_vector_rag,
|
519 |
+
'rag_data_json': json.dumps(rag_data) if rag_data else 'None'
|
520 |
}
|
521 |
|
522 |
# Generate files
|
523 |
app_content = SPACE_TEMPLATE.format(**config)
|
524 |
+
# Pass original access_code to README for documentation
|
525 |
+
readme_config = config.copy()
|
526 |
+
readme_config['access_code'] = access_code or ""
|
527 |
+
readme_content = create_readme(readme_config)
|
528 |
requirements_content = create_requirements(enable_vector_rag)
|
529 |
|
530 |
# Create zip file with clean naming
|
|
|
675 |
|
676 |
if not api_key:
|
677 |
response = "Please set your OPENROUTER_API_KEY in the Space settings to use the chat support."
|
678 |
+
chat_history.append({"role": "user", "content": message})
|
679 |
+
chat_history.append({"role": "assistant", "content": response})
|
680 |
return "", chat_history
|
681 |
|
682 |
# Get grounding context from URLs using cached approach
|
|
|
807 |
|
808 |
def update_template_fields(choice):
|
809 |
"""Update assistant configuration fields based on template choice"""
|
810 |
+
if choice == "System Prompt (Custom)":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
811 |
return (
|
812 |
gr.update(value=""),
|
813 |
gr.update(value=""),
|
|
|
815 |
gr.update(value=""),
|
816 |
gr.update(value=False) # Disable dynamic URL fetching for custom template
|
817 |
)
|
818 |
+
else: # Research Assistant Template (Extended)
|
819 |
+
return (
|
820 |
+
gr.update(value="You are a research assistant that provides link-grounded information through Crawl4AI web fetching. Use MLA documentation for parenthetical citations and bibliographic entries."),
|
821 |
+
gr.update(value="This assistant is designed for students and researchers conducting academic inquiry."),
|
822 |
+
gr.update(value="Your main responsibilities include: analyzing academic sources, fact-checking claims with evidence, providing properly cited research summaries, and helping users navigate scholarly information."),
|
823 |
+
gr.update(value="Ground all responses in provided URL contexts and any additional URLs you're instructed to fetch. Never rely on memory for factual claims."),
|
824 |
+
gr.update(value=True) # Enable dynamic URL fetching for research template
|
825 |
+
)
|
826 |
|
827 |
# Create Gradio interface with proper tab structure
|
828 |
with gr.Blocks(title="Chat U/I Helper") as demo:
|
|
|
842 |
label="Space Description",
|
843 |
placeholder="A customizable AI chat interface for...",
|
844 |
lines=2,
|
845 |
+
value=""
|
846 |
)
|
847 |
|
848 |
model = gr.Dropdown(
|
|
|
871 |
template_choice = gr.Radio(
|
872 |
label="How would you like to get started?",
|
873 |
choices=[
|
874 |
+
"System Prompt (Custom)",
|
875 |
+
"Research Assistant Template (Extended)"
|
876 |
],
|
877 |
+
value="System Prompt (Custom)",
|
878 |
info="Choose a starting point for your assistant configuration"
|
879 |
)
|
880 |
|
|
|
882 |
label="Role and Purpose",
|
883 |
placeholder="You are a research assistant that...",
|
884 |
lines=2,
|
885 |
+
value="",
|
886 |
info="Define what the assistant is and its primary function"
|
887 |
)
|
888 |
|
|
|
890 |
label="Intended Audience",
|
891 |
placeholder="This assistant is designed for undergraduate students...",
|
892 |
lines=2,
|
893 |
+
value="",
|
894 |
info="Specify who will be using this assistant and their context"
|
895 |
)
|
896 |
|
|
|
898 |
label="Key Tasks",
|
899 |
placeholder="Your main responsibilities include...",
|
900 |
lines=3,
|
901 |
+
value="",
|
902 |
info="List the specific tasks and capabilities the assistant should focus on"
|
903 |
)
|
904 |
|
|
|
906 |
label="Additional Context",
|
907 |
placeholder="Remember to always...",
|
908 |
lines=2,
|
909 |
+
value="",
|
910 |
info="Any additional instructions, constraints, or behavioral guidelines"
|
911 |
)
|
912 |
+
|
913 |
+
with gr.Accordion("Tool Settings", open=True):
|
914 |
+
gr.Markdown("### Configure available tools and capabilities")
|
915 |
|
|
|
916 |
enable_dynamic_urls = gr.Checkbox(
|
917 |
label="Enable Dynamic URL Fetching",
|
918 |
value=False,
|
|
|
940 |
# State to store RAG tool
|
941 |
rag_tool_state = gr.State(None)
|
942 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
943 |
with gr.Accordion("URL Grounding (Optional)", open=False):
|
944 |
gr.Markdown("Add URLs to provide context. Content will be fetched and added to the system prompt.")
|
945 |
|
|
|
977 |
remove_url_btn = gr.Button("- Remove URLs", size="sm", visible=False)
|
978 |
url_count = gr.State(2) # Track number of visible URLs
|
979 |
|
980 |
+
examples_text = gr.Textbox(
|
981 |
+
label="Example Prompts (one per line)",
|
982 |
+
placeholder="Can you analyze this research paper: https://example.com/paper.pdf\nWhat are the latest findings on climate change adaptation?\nHelp me fact-check claims about renewable energy efficiency",
|
983 |
+
lines=3,
|
984 |
+
info="These will appear as clickable examples in the chat interface"
|
985 |
+
)
|
986 |
+
|
987 |
with gr.Row():
|
988 |
temperature = gr.Slider(
|
989 |
label="Temperature",
|
|
|
1056 |
chatbot = gr.Chatbot(
|
1057 |
value=[],
|
1058 |
label="Chat Support Assistant",
|
1059 |
+
height=400,
|
1060 |
+
type="messages"
|
1061 |
)
|
1062 |
msg = gr.Textbox(
|
1063 |
label="Ask about configuring chat UIs for courses, research, or custom HuggingFace Spaces",
|
requirements.txt
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
-
gradio>=
|
2 |
requests>=2.32.3
|
3 |
beautifulsoup4>=4.12.3
|
4 |
python-dotenv>=1.0.0
|
5 |
-
crawl4ai>=0.4.
|
|
|
6 |
|
7 |
# Vector RAG dependencies (optional)
|
8 |
sentence-transformers>=2.2.2
|
|
|
1 |
+
gradio>=5.35.0
|
2 |
requests>=2.32.3
|
3 |
beautifulsoup4>=4.12.3
|
4 |
python-dotenv>=1.0.0
|
5 |
+
crawl4ai>=0.4.0
|
6 |
+
aiofiles>=24.0
|
7 |
|
8 |
# Vector RAG dependencies (optional)
|
9 |
sentence-transformers>=2.2.2
|
test_document.txt
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Vector Database Test Document
|
2 |
+
|
3 |
+
This is a test document for evaluating the vector database functionality.
|
4 |
+
|
5 |
+
Section 1: Introduction to Vector Databases
|
6 |
+
Vector databases store and query high-dimensional vector representations of data. They enable semantic search by finding vectors similar to a query vector in an embedding space.
|
7 |
+
|
8 |
+
Section 2: Use Cases
|
9 |
+
Common applications include:
|
10 |
+
- Document retrieval and question answering
|
11 |
+
- Similarity search for products or content
|
12 |
+
- Recommendation systems
|
13 |
+
- Semantic search in chatbots
|
14 |
+
|
15 |
+
Section 3: Technical Implementation
|
16 |
+
Vector databases typically use embedding models to convert text into dense vectors, then use algorithms like cosine similarity or approximate nearest neighbor search to find relevant results.
|
17 |
+
|
18 |
+
Section 4: Benefits
|
19 |
+
- Semantic understanding beyond keyword matching
|
20 |
+
- Scalable retrieval for large document collections
|
21 |
+
- Integration with modern AI systems and large language models
|
22 |
+
- Support for multi-modal data (text, images, audio)
|
23 |
+
|
24 |
+
This document should generate multiple chunks when processed by the system.
|
test_vector_db.py
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
Test script to verify vector database creation functionality
|
4 |
+
"""
|
5 |
+
|
6 |
+
import sys
|
7 |
+
import os
|
8 |
+
from pathlib import Path
|
9 |
+
|
10 |
+
# Add current directory to path to import modules
|
11 |
+
sys.path.append(str(Path(__file__).parent))
|
12 |
+
|
13 |
+
try:
|
14 |
+
from rag_tool import RAGTool
|
15 |
+
from vector_store import VectorStore
|
16 |
+
from document_processor import DocumentProcessor
|
17 |
+
print("β
Successfully imported all RAG modules")
|
18 |
+
except ImportError as e:
|
19 |
+
print(f"β Failed to import RAG modules: {e}")
|
20 |
+
sys.exit(1)
|
21 |
+
|
22 |
+
def test_document_processing():
|
23 |
+
"""Test document processing functionality"""
|
24 |
+
print("\n=== Testing Document Processing ===")
|
25 |
+
|
26 |
+
processor = DocumentProcessor(chunk_size=200, chunk_overlap=50)
|
27 |
+
|
28 |
+
# Test with our test document
|
29 |
+
test_file = "test_document.txt"
|
30 |
+
if not os.path.exists(test_file):
|
31 |
+
print(f"β Test file {test_file} not found")
|
32 |
+
return False
|
33 |
+
|
34 |
+
try:
|
35 |
+
chunks = processor.process_file(test_file)
|
36 |
+
print(f"β
Processed {test_file} into {len(chunks)} chunks")
|
37 |
+
|
38 |
+
# Show first chunk
|
39 |
+
if chunks:
|
40 |
+
first_chunk = chunks[0]
|
41 |
+
print(f"First chunk preview: {first_chunk.text[:100]}...")
|
42 |
+
print(f"Chunk metadata: {first_chunk.metadata}")
|
43 |
+
|
44 |
+
return True
|
45 |
+
except Exception as e:
|
46 |
+
print(f"β Failed to process document: {e}")
|
47 |
+
return False
|
48 |
+
|
49 |
+
def test_vector_store():
|
50 |
+
"""Test vector store functionality"""
|
51 |
+
print("\n=== Testing Vector Store ===")
|
52 |
+
|
53 |
+
try:
|
54 |
+
# Initialize vector store
|
55 |
+
vector_store = VectorStore()
|
56 |
+
print("β
Initialized vector store")
|
57 |
+
|
58 |
+
# Create test data
|
59 |
+
test_chunks = [
|
60 |
+
{
|
61 |
+
'text': 'Vector databases are used for semantic search',
|
62 |
+
'chunk_id': 'test1',
|
63 |
+
'metadata': {'file_name': 'test.txt', 'chunk_index': 0}
|
64 |
+
},
|
65 |
+
{
|
66 |
+
'text': 'Machine learning models convert text to embeddings',
|
67 |
+
'chunk_id': 'test2',
|
68 |
+
'metadata': {'file_name': 'test.txt', 'chunk_index': 1}
|
69 |
+
},
|
70 |
+
{
|
71 |
+
'text': 'FAISS provides efficient similarity search capabilities',
|
72 |
+
'chunk_id': 'test3',
|
73 |
+
'metadata': {'file_name': 'test.txt', 'chunk_index': 2}
|
74 |
+
}
|
75 |
+
]
|
76 |
+
|
77 |
+
# Build index
|
78 |
+
print("Building vector index...")
|
79 |
+
vector_store.build_index(test_chunks, show_progress=True)
|
80 |
+
print("β
Built vector index")
|
81 |
+
|
82 |
+
# Test search
|
83 |
+
query = "How do vector databases work?"
|
84 |
+
results = vector_store.search(query, top_k=2)
|
85 |
+
|
86 |
+
print(f"Search results for '{query}':")
|
87 |
+
for i, result in enumerate(results):
|
88 |
+
print(f" {i+1}. Score: {result.score:.3f} - {result.text[:50]}...")
|
89 |
+
|
90 |
+
# Test serialization
|
91 |
+
serialized = vector_store.serialize()
|
92 |
+
print(f"β
Serialized data size: {len(serialized['index_base64'])} characters")
|
93 |
+
|
94 |
+
return True
|
95 |
+
|
96 |
+
except Exception as e:
|
97 |
+
print(f"β Failed vector store test: {e}")
|
98 |
+
import traceback
|
99 |
+
traceback.print_exc()
|
100 |
+
return False
|
101 |
+
|
102 |
+
def test_rag_tool():
|
103 |
+
"""Test complete RAG tool functionality"""
|
104 |
+
print("\n=== Testing RAG Tool ===")
|
105 |
+
|
106 |
+
try:
|
107 |
+
# Initialize RAG tool
|
108 |
+
rag_tool = RAGTool()
|
109 |
+
print("β
Initialized RAG tool")
|
110 |
+
|
111 |
+
# Process test document
|
112 |
+
test_files = ["test_document.txt"]
|
113 |
+
result = rag_tool.process_uploaded_files(test_files)
|
114 |
+
|
115 |
+
if result['success']:
|
116 |
+
print(f"β
{result['message']}")
|
117 |
+
|
118 |
+
# Show summary
|
119 |
+
summary = result['summary']
|
120 |
+
print(f"Files processed: {summary['total_files']}")
|
121 |
+
print(f"Total chunks: {summary['total_chunks']}")
|
122 |
+
|
123 |
+
# Test context retrieval
|
124 |
+
query = "What are the benefits of vector databases?"
|
125 |
+
context = rag_tool.get_relevant_context(query, max_chunks=2)
|
126 |
+
|
127 |
+
if context:
|
128 |
+
print(f"\nContext for '{query}':")
|
129 |
+
print(context[:300] + "..." if len(context) > 300 else context)
|
130 |
+
print("β
Successfully retrieved context")
|
131 |
+
else:
|
132 |
+
print("β οΈ No context retrieved")
|
133 |
+
|
134 |
+
# Test serialization for deployment
|
135 |
+
serialized_data = rag_tool.get_serialized_data()
|
136 |
+
if serialized_data:
|
137 |
+
print("β
Successfully serialized RAG data for deployment")
|
138 |
+
print(f"Serialized keys: {list(serialized_data.keys())}")
|
139 |
+
else:
|
140 |
+
print("β Failed to serialize RAG data")
|
141 |
+
|
142 |
+
return True
|
143 |
+
else:
|
144 |
+
print(f"β {result['message']}")
|
145 |
+
return False
|
146 |
+
|
147 |
+
except Exception as e:
|
148 |
+
print(f"β Failed RAG tool test: {e}")
|
149 |
+
import traceback
|
150 |
+
traceback.print_exc()
|
151 |
+
return False
|
152 |
+
|
153 |
+
def main():
|
154 |
+
"""Run all tests"""
|
155 |
+
print("=== Vector Database Testing ===")
|
156 |
+
print("Testing vector database creation and functionality...")
|
157 |
+
|
158 |
+
# Check dependencies
|
159 |
+
print("\n=== Checking Dependencies ===")
|
160 |
+
try:
|
161 |
+
import sentence_transformers
|
162 |
+
import faiss
|
163 |
+
import fitz # PyMuPDF
|
164 |
+
print("β
All required dependencies available")
|
165 |
+
except ImportError as e:
|
166 |
+
print(f"β Missing dependency: {e}")
|
167 |
+
return
|
168 |
+
|
169 |
+
# Run tests
|
170 |
+
tests = [
|
171 |
+
("Document Processing", test_document_processing),
|
172 |
+
("Vector Store", test_vector_store),
|
173 |
+
("RAG Tool", test_rag_tool)
|
174 |
+
]
|
175 |
+
|
176 |
+
results = []
|
177 |
+
for test_name, test_func in tests:
|
178 |
+
print(f"\n{'='*20}")
|
179 |
+
success = test_func()
|
180 |
+
results.append((test_name, success))
|
181 |
+
|
182 |
+
# Summary
|
183 |
+
print(f"\n{'='*40}")
|
184 |
+
print("TEST SUMMARY:")
|
185 |
+
for test_name, success in results:
|
186 |
+
status = "β
PASS" if success else "β FAIL"
|
187 |
+
print(f" {test_name}: {status}")
|
188 |
+
|
189 |
+
all_passed = all(success for _, success in results)
|
190 |
+
if all_passed:
|
191 |
+
print("\nπ All tests passed! Vector database functionality is working.")
|
192 |
+
else:
|
193 |
+
print("\nβ οΈ Some tests failed. Check the output above for details.")
|
194 |
+
|
195 |
+
if __name__ == "__main__":
|
196 |
+
main()
|