jeanbaptdzd commited on
Commit
20548ac
·
1 Parent(s): fdc8bbe

refactor: Improve type hints and code quality across codebase

Browse files

- Remove obsolete documentation files (CLEANUP_*, CODERABBIT_*, TEST_CODERABBIT)
- Add comprehensive type hints to all functions and methods
- Improve middleware with better type annotations and error messages
- Add docstrings to service layer functions
- Refactor _messages_to_prompt to use list joining instead of string concatenation
- Extract PUBLIC_PATHS as module-level constant in middleware
- Improve code readability and maintainability

This expands code coverage for CodeRabbit review across multiple modules.

CLEANUP_PLAN.md DELETED
@@ -1,155 +0,0 @@
1
- # Code Cleanup Plan
2
-
3
- ## Overview
4
- This document outlines the cleanup strategy for the simple-llm-pro-finance project to remove obsolete files and improve code organization.
5
-
6
- ## Files to Remove
7
-
8
- ### 1. Obsolete Test Scripts (Root Directory)
9
- **Reason:** All functional tests have been moved to `tests/` directory. These are one-off debugging scripts.
10
-
11
- - `analyze_performance.py` - Performance analysis done, results in FINAL_TEST_REPORT.md
12
- - `debug_chat_template.py` - Debug script, no longer needed
13
- - `final_clean_test.py` - One-off test
14
- - `investigate_french_consistency.py` - Investigation complete
15
- - `quiz_finance_francais.py` - Test script (also in git staging)
16
- - `test_advanced_finance.py` - Moved to tests/
17
- - `test_all_fixes.py` - One-off validation
18
- - `test_debug_endpoint.sh` - Shell test script
19
- - `test_finance_final.py` - One-off test
20
- - `test_finance_improved.py` - One-off test
21
- - `test_finance_queries.py` - One-off test
22
- - `test_french_direct.py` - One-off test
23
- - `test_french_final_check.py` - One-off test
24
- - `test_french_simple.sh` - Shell test script
25
- - `test_french_strategies.py` - One-off test
26
- - `test_generation_fix.sh` - Shell test script
27
- - `test_memory_stress.py` - Moved to tests/
28
- - `test_quick_french.py` - One-off test
29
- - `test_service.py` - One-off test
30
- - `test_system_prompt.py` - One-off test
31
- - `test_tokenizer_debug.py` - Debug script
32
- - `test_truncation_issue.py` - One-off test
33
-
34
- **Total:** 21 test files
35
-
36
- ### 2. Obsolete Documentation Files
37
- **Reason:** Superseded by comprehensive final reports.
38
-
39
- - `STATUS.md` - Historical status, superseded by FINAL_STATUS.md
40
- - `FIXES_SUMMARY.md` - Historical, covered in FINAL_TEST_REPORT.md
41
- - `PERFORMANCE_REPORT.md` - Covered in FINAL_TEST_REPORT.md
42
- - `memory_test_results.txt` - Old test results
43
- - `test_results.txt` - Old test results
44
-
45
- **Total:** 5 documentation files
46
-
47
- ### 3. Empty/Debug Code Directories
48
- **Reason:** Unused or debug-only code.
49
-
50
- - `app/utils/` - Empty directory (only __pycache__)
51
- - `app/routers/debug.py` - Debug endpoint not needed in production
52
-
53
- **Total:** 1 directory, 1 file
54
-
55
- ## Files to Keep
56
-
57
- ### Core Application
58
- - `app/` directory (except items listed for removal)
59
- - `main.py` - FastAPI application
60
- - `config.py` - Configuration
61
- - `middleware.py` - API key authentication
62
- - `models/openai.py` - Pydantic models
63
- - `providers/base.py` - Provider protocol
64
- - `providers/transformers_provider.py` - Main inference engine
65
- - `routers/openai_api.py` - OpenAI-compatible API
66
- - `services/chat_service.py` - Chat service wrapper
67
-
68
- ### Tests
69
- - `tests/` directory - Proper pytest structure
70
- - `conftest.py`
71
- - `test_config.py`
72
- - `test_middleware.py`
73
- - `test_openai_models.py`
74
- - `test_openai_routes.py`
75
- - `test_providers.py`
76
- - `performance/` - Performance benchmarks
77
-
78
- ### Documentation
79
- - `README.md` - Main documentation (needs cleanup)
80
- - `FINAL_STATUS.md` - Final deployment status
81
- - `FINAL_TEST_REPORT.md` - Comprehensive test results
82
- - `LICENSE` - MIT license
83
-
84
- ### Configuration & Deployment
85
- - `Dockerfile` - Docker build configuration
86
- - `requirements.txt` - Production dependencies
87
- - `requirements-dev.txt` - Development dependencies
88
-
89
- ### Scripts
90
- - `scripts/validate_hf_readme.py` - Useful validation utility
91
- - `scripts/README.md` - Scripts documentation
92
-
93
- ## Refactoring Needed
94
-
95
- ### 1. Remove Debug Router from Production
96
- **File:** `app/main.py`
97
- **Change:** Remove debug router import and mount
98
- ```python
99
- # Remove this line
100
- app.include_router(debug.router, prefix="/v1")
101
- ```
102
-
103
- ### 2. Clean Up README.md
104
- **File:** `README.md`
105
- **Changes:**
106
- - Remove outdated test coverage stats (91% reference)
107
- - Update to reflect current stable state
108
- - Simplify configuration section
109
- - Remove references to obsolete features
110
-
111
- ### 3. Remove Empty Utils Directory
112
- **Directory:** `app/utils/`
113
- **Action:** Delete the entire directory as it's unused
114
-
115
- ## Impact Assessment
116
-
117
- ### Breaking Changes
118
- **None** - All removed files are development/debugging artifacts.
119
-
120
- ### Non-Breaking Changes
121
- - Removing debug endpoint (`/v1/debug/prompt`) - Not documented in README
122
- - Cleaner project structure
123
- - Reduced repository size
124
-
125
- ### Benefits
126
- - **Clarity:** Easier to understand project structure
127
- - **Maintenance:** Fewer files to maintain
128
- - **Size:** Reduced repo size
129
- - **Professionalism:** Clean, production-ready codebase
130
-
131
- ## Execution Plan
132
-
133
- 1. ✅ Create backup branch
134
- 2. ✅ Remove obsolete test files
135
- 3. ✅ Remove obsolete documentation
136
- 4. ✅ Remove debug code
137
- 5. ✅ Update README.md
138
- 6. ✅ Run tests to verify nothing broke
139
- 7. ✅ Commit and push changes
140
-
141
- ## Success Criteria
142
-
143
- - ✅ All tests in `tests/` directory still pass
144
- - ✅ Application still starts and serves requests
145
- - ✅ README.md is accurate and up-to-date
146
- - ✅ No broken imports or references
147
- - ✅ Git history preserved (files deleted, not rewritten)
148
-
149
- ## Rollback Plan
150
-
151
- If issues arise:
152
- 1. Git checkout the cleanup branch: `git checkout pre-cleanup-backup`
153
- 2. Review what was removed
154
- 3. Restore only necessary files
155
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
CLEANUP_SUMMARY.md DELETED
@@ -1,190 +0,0 @@
1
- # Cleanup Summary - November 2, 2025
2
-
3
- ## Overview
4
- Comprehensive codebase cleanup to remove obsolete test scripts, redundant documentation, and debug code from the project.
5
-
6
- ## Files Removed
7
-
8
- ### Test Scripts (21 files)
9
- All one-off debugging and validation scripts have been removed. Proper tests remain in `tests/` directory.
10
-
11
- ✅ Removed:
12
- - `analyze_performance.py`
13
- - `debug_chat_template.py`
14
- - `final_clean_test.py`
15
- - `investigate_french_consistency.py`
16
- - `quiz_finance_francais.py`
17
- - `test_advanced_finance.py`
18
- - `test_all_fixes.py`
19
- - `test_debug_endpoint.sh`
20
- - `test_finance_final.py`
21
- - `test_finance_improved.py`
22
- - `test_finance_queries.py`
23
- - `test_french_direct.py`
24
- - `test_french_final_check.py`
25
- - `test_french_simple.sh`
26
- - `test_french_strategies.py`
27
- - `test_generation_fix.sh`
28
- - `test_memory_stress.py`
29
- - `test_quick_french.py`
30
- - `test_service.py`
31
- - `test_system_prompt.py`
32
- - `test_tokenizer_debug.py`
33
- - `test_truncation_issue.py`
34
-
35
- ### Documentation Files (5 files)
36
- Historical documentation superseded by comprehensive final reports.
37
-
38
- ✅ Removed:
39
- - `STATUS.md` (superseded by FINAL_STATUS.md)
40
- - `FIXES_SUMMARY.md` (covered in FINAL_TEST_REPORT.md)
41
- - `PERFORMANCE_REPORT.md` (covered in FINAL_TEST_REPORT.md)
42
- - `memory_test_results.txt` (old test results)
43
- - `test_results.txt` (old test results)
44
-
45
- ### Code Files (2 items)
46
- Debug code not needed in production.
47
-
48
- ✅ Removed:
49
- - `app/routers/debug.py` - Debug endpoint for prompt inspection
50
- - `app/utils/` - Empty directory
51
-
52
- ## Code Changes
53
-
54
- ### Modified: `app/main.py`
55
- **Before:**
56
- ```python
57
- from app.routers import openai_api, debug
58
- ...
59
- app.include_router(debug.router, prefix="/v1")
60
- ```
61
-
62
- **After:**
63
- ```python
64
- from app.routers import openai_api
65
- ...
66
- # Debug router removed
67
- ```
68
-
69
- ### Modified: `README.md`
70
- Updated to reflect:
71
- - Current stable state (production-ready)
72
- - Accurate feature list
73
- - Better API examples with realistic max_tokens
74
- - Chain-of-thought reasoning explanation
75
- - Language support details
76
- - Removed outdated test coverage stats
77
- - Added technical specifications section
78
-
79
- ## Project Structure (After Cleanup)
80
-
81
- ```
82
- simple-llm-pro-finance/
83
- ├── app/ # Core application
84
- │ ├── config.py # Configuration
85
- │ ├── main.py # FastAPI app
86
- │ ├── middleware.py # API key auth
87
- │ ├── models/
88
- │ │ └── openai.py # Pydantic models
89
- │ ├── providers/
90
- │ │ ├── base.py # Provider protocol
91
- │ │ └── transformers_provider.py # Main inference engine
92
- │ ├── routers/
93
- │ │ └── openai_api.py # OpenAI-compatible API
94
- │ └── services/
95
- │ └── chat_service.py # Chat service wrapper
96
- ├── tests/ # Proper test suite
97
- │ ├── conftest.py
98
- │ ├── test_*.py # Unit tests
99
- │ └── performance/ # Performance benchmarks
100
- ├── scripts/ # Utility scripts
101
- │ └── validate_hf_readme.py # README validator
102
- ├── Dockerfile # Docker build config
103
- ├── requirements.txt # Production dependencies
104
- ├── requirements-dev.txt # Development dependencies
105
- ├── README.md # Main documentation
106
- ├── FINAL_STATUS.md # Deployment status
107
- ├── FINAL_TEST_REPORT.md # Test results & metrics
108
- ├── CLEANUP_PLAN.md # This cleanup plan
109
- └── LICENSE # MIT license
110
- ```
111
-
112
- ## Impact Assessment
113
-
114
- ### Breaking Changes
115
- **None** - All removed files were development artifacts.
116
-
117
- ### Removed Endpoints
118
- - `/v1/debug/prompt` - Debug endpoint (never documented in README)
119
-
120
- ### Benefits
121
- - ✅ **Cleaner structure** - 28 fewer files in root directory
122
- - ✅ **Better organization** - Clear separation of concerns
123
- - ✅ **Easier navigation** - No clutter from obsolete scripts
124
- - ✅ **Professional appearance** - Production-ready codebase
125
- - ✅ **Reduced confusion** - No outdated documentation
126
- - ✅ **Smaller repo size** - Faster clones and deployments
127
-
128
- ## Verification
129
-
130
- ### Syntax Validation
131
- ✅ All Python files compile successfully:
132
- - `app/main.py` ✓
133
- - `app/routers/openai_api.py` ✓
134
- - `app/services/chat_service.py` ✓
135
-
136
- ### Import Structure
137
- ✅ No broken imports detected
138
- ✅ All module dependencies satisfied
139
-
140
- ### Test Suite
141
- ✅ Tests remain in `tests/` directory
142
- ✅ Proper pytest structure maintained
143
- ✅ Performance benchmarks preserved
144
-
145
- ## Git Status
146
-
147
- ### Staged Changes (Existing)
148
- - `app/providers/transformers_provider.py` (previous work)
149
- - `quiz_finance_francais.py` (previous work)
150
-
151
- ### Unstaged Changes (This Cleanup)
152
- - Modified: `app/main.py` (removed debug router)
153
- - Modified: `README.md` (updated documentation)
154
- - Deleted: 26 obsolete files
155
- - Added: `CLEANUP_PLAN.md` (this document)
156
-
157
- ## Backup
158
- ✅ Backup branch created: `pre-cleanup-backup`
159
-
160
- To restore if needed:
161
- ```bash
162
- git checkout pre-cleanup-backup
163
- ```
164
-
165
- ## Next Steps
166
-
167
- 1. ✅ Review changes
168
- 2. ⏳ Stage cleanup changes: `git add -A`
169
- 3. ⏳ Commit: `git commit -m "Clean up: Remove obsolete test scripts and documentation"`
170
- 4. ⏳ Optional: Squash with staged changes
171
- 5. ⏳ Push to repository
172
-
173
- ## Success Criteria
174
-
175
- - ✅ All obsolete files removed
176
- - ✅ Code syntax valid
177
- - ✅ No broken imports
178
- - ✅ README updated and accurate
179
- - ✅ Backup created
180
- - ✅ Professional project structure
181
-
182
- ## Summary
183
-
184
- **Removed:** 28 files (21 test scripts, 5 docs, 2 code files)
185
- **Modified:** 2 files (main.py, README.md)
186
- **Added:** 2 files (CLEANUP_PLAN.md, CLEANUP_SUMMARY.md)
187
- **Net Change:** -24 files
188
-
189
- The codebase is now clean, well-organized, and production-ready! 🎉
190
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
CODERABBIT_SETUP.md DELETED
@@ -1,83 +0,0 @@
1
- # CodeRabbit Setup Troubleshooting
2
-
3
- ## Issue: CodeRabbit not appearing in PRs
4
-
5
- ### Step 1: Verify Installation
6
-
7
- 1. Go to: https://github.com/marketplace/coderabbitai
8
- 2. Click "Install it for free" or "Configure access"
9
- 3. Make sure it's installed for your organization/user
10
- 4. Verify it has access to `DealExMachina/simple-llm-pro-finance`
11
-
12
- ### Step 2: Check Repository Settings
13
-
14
- 1. Go to: https://github.com/DealExMachina/simple-llm-pro-finance/settings/installations
15
- 2. Look for "CodeRabbitAI" in installed GitHub Apps
16
- 3. Click "Configure" next to it
17
- 4. Ensure this repository is selected (or "All repositories")
18
-
19
- ### Step 3: Check Webhooks
20
-
21
- 1. Go to: https://github.com/DealExMachina/simple-llm-pro-finance/settings/hooks
22
- 2. Look for a webhook pointing to: `https://app.coderabbit.ai/githubHandler`
23
- 3. If missing, CodeRabbit should create it automatically, but you can check
24
-
25
- ### Step 4: Test with a Real PR
26
-
27
- CodeRabbit may need:
28
- - **Code changes** (not just docs)
29
- - **Multiple files** changed
30
- - **Python files** to review
31
-
32
- Try this:
33
-
34
- ```bash
35
- # Create a test PR with actual code changes
36
- git checkout -b test-coderabbit-code
37
- # Make a small code change (add a comment, fix formatting)
38
- # Then create PR
39
- ```
40
-
41
- ### Step 5: Check PR for CodeRabbit Bot
42
-
43
- - Look for user: `@coderabbitai` or `@coderabbit`
44
- - Check "Conversation" tab in PR
45
- - Sometimes it takes 2-5 minutes to appear
46
-
47
- ### Step 6: Manual Trigger
48
-
49
- Try adding this to your PR description:
50
- ```
51
- @coderabbitai please review
52
- ```
53
-
54
- Or mention it:
55
- ```
56
- @coderabbit please review this PR
57
- ```
58
-
59
- ### Step 7: Verify Configuration File
60
-
61
- The `.coderabbit.yaml` file has been created. CodeRabbit should respect this configuration.
62
-
63
- ### Alternative: Use CodeRabbit Comments
64
-
65
- If CodeRabbit is installed but not auto-commenting, try:
66
- 1. Comment in the PR: `/review` or `/review_code`
67
- 2. Or use: `/ask @coderabbitai review this PR`
68
-
69
- ## Still Not Working?
70
-
71
- 1. Check CodeRabbit status: https://status.coderabbit.ai/
72
- 2. Review CodeRabbit docs: https://docs.coderabbit.ai/
73
- 3. Contact support: https://coderabbit.ai/support
74
-
75
- ## What CodeRabbit Should Review:
76
-
77
- - Code quality and best practices
78
- - Security vulnerabilities
79
- - Performance issues
80
- - Python-specific patterns
81
- - Error handling
82
- - Documentation completeness
83
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
CODERABBIT_TEST_PR.md DELETED
@@ -1,15 +0,0 @@
1
- # CodeRabbit Test PR - Code Changes
2
-
3
- This PR includes intentional code changes that CodeRabbit should review:
4
-
5
- ## Changes Made:
6
- 1. Added input validation to chat completions endpoint
7
- 2. Improved error handling with better error messages
8
- 3. Added type hints improvements
9
-
10
- ## What CodeRabbit Should Catch:
11
- - Code quality improvements
12
- - Potential security issues
13
- - Best practices suggestions
14
- - Python typing improvements
15
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
CODE_REVIEW_SUMMARY.md DELETED
@@ -1,119 +0,0 @@
1
- # Code Review and Cleanup Summary
2
-
3
- **Date:** November 2, 2025
4
- **Reviewer:** AI Assistant
5
- **Status:** Complete
6
-
7
- ## Executive Summary
8
-
9
- Comprehensive codebase cleanup removing 28 obsolete files and refactoring documentation to be professional and concise.
10
-
11
- ## Changes Made
12
-
13
- ### Files Removed: 28
14
-
15
- **Test Scripts (21 files):**
16
- - All one-off test/debug scripts moved or removed
17
- - Proper tests retained in `tests/` directory
18
-
19
- **Documentation (5 files):**
20
- - Obsolete status reports superseded by final documentation
21
- - Old test result files removed
22
-
23
- **Code (2 items):**
24
- - Debug router removed from production code
25
- - Empty utils directory removed
26
-
27
- ### Files Modified: 2
28
-
29
- **app/main.py:**
30
- - Removed debug router import and mount
31
- - Cleaned up for production deployment
32
-
33
- **README.md:**
34
- - Removed all emojis from section headers
35
- - Eliminated redundant self-congratulatory content
36
- - Condensed from 189 to 139 lines
37
- - Made professional and concise
38
- - Removed "Features" checklist section
39
- - Streamlined technical specifications
40
- - Removed unnecessary "Contributing" section
41
-
42
- ### Files Added: 3
43
-
44
- - `CLEANUP_PLAN.md` - Detailed cleanup strategy
45
- - `CLEANUP_SUMMARY.md` - Execution summary
46
- - `CODE_REVIEW_SUMMARY.md` - This document
47
-
48
- ## Project Structure (After Cleanup)
49
-
50
- ```
51
- simple-llm-pro-finance/
52
- ├── app/ # Application code
53
- │ ├── config.py
54
- │ ├── main.py
55
- │ ├── middleware.py
56
- │ ├── models/
57
- │ ├── providers/
58
- │ ├── routers/
59
- │ └── services/
60
- ├── tests/ # Test suite
61
- ├── scripts/ # Utilities
62
- ├── Dockerfile
63
- ├── requirements.txt
64
- ├── requirements-dev.txt
65
- ├── README.md # Clean, professional docs
66
- ├── FINAL_STATUS.md
67
- ├── FINAL_TEST_REPORT.md
68
- └── LICENSE
69
- ```
70
-
71
- ## Code Quality Improvements
72
-
73
- **Before:**
74
- - 50+ files in repository
75
- - Multiple redundant documentation files
76
- - Debug endpoints in production code
77
- - Verbose, emoji-heavy documentation
78
- - Test scripts scattered in root directory
79
-
80
- **After:**
81
- - 26 essential files
82
- - Single source of truth for documentation
83
- - Production-ready code only
84
- - Professional, concise documentation
85
- - Organized test directory structure
86
-
87
- ## Verification
88
-
89
- - Python syntax validation: PASSED
90
- - Import structure: VALID
91
- - No broken references: CONFIRMED
92
- - Backup created: `pre-cleanup-backup` branch
93
-
94
- ## Impact
95
-
96
- **Breaking Changes:** None
97
- **Removed Endpoints:** `/v1/debug/prompt` (undocumented)
98
- **Repository Size:** Reduced by ~24 files
99
- **Maintainability:** Significantly improved
100
-
101
- ## Recommendations
102
-
103
- ### Immediate
104
- 1. Review and approve changes
105
- 2. Stage all changes: `git add -A`
106
- 3. Commit with message: "refactor: Clean up codebase - remove obsolete files and improve documentation"
107
- 4. Push to repository
108
-
109
- ### Future Considerations
110
- 1. Consider removing `CLEANUP_PLAN.md` and `CLEANUP_SUMMARY.md` after merge
111
- 2. Update `.gitignore` to prevent future test script accumulation
112
- 3. Establish guidelines for temporary debugging files
113
-
114
- ## Conclusion
115
-
116
- The codebase is now clean, professional, and production-ready. All obsolete development artifacts have been removed, documentation is concise and accurate, and the project structure is well-organized.
117
-
118
- **Net Result:** -24 files, cleaner code, better documentation.
119
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
TEST_CODERABBIT.md DELETED
@@ -1,40 +0,0 @@
1
- # Testing CodeRabbit Integration
2
-
3
- ## What to do:
4
-
5
- 1. **Create a branch:**
6
- ```bash
7
- git checkout -b test-coderabbit-review
8
- ```
9
-
10
- 2. **Commit this test file:**
11
- ```bash
12
- git add TEST_CODERABBIT.md .github/pull_request_template.md
13
- git commit -m "test: Add PR template and test CodeRabbit integration"
14
- ```
15
-
16
- 3. **Push and create PR:**
17
- ```bash
18
- git push origin test-coderabbit-review
19
- ```
20
- Then go to GitHub and create a Pull Request from `test-coderabbit-review` to `master`
21
-
22
- 4. **Watch for CodeRabbit:**
23
- - CodeRabbit should automatically comment on your PR
24
- - It will review code quality, suggest improvements
25
- - Check for CodeRabbit comments in the PR thread
26
-
27
- ## What CodeRabbit will review:
28
- - Code quality and best practices
29
- - Potential bugs or security issues
30
- - Performance optimizations
31
- - Documentation completeness
32
- - Test coverage
33
-
34
- ## To test more thoroughly:
35
- After this test, try creating a PR with:
36
- - A small bug (see if it catches it)
37
- - Missing error handling
38
- - Performance issues
39
- - Security concerns
40
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/middleware.py CHANGED
@@ -1,26 +1,46 @@
1
- from fastapi import Request, HTTPException
2
- from fastapi.responses import JSONResponse
 
3
 
4
  from app.config import settings
5
 
 
 
6
 
7
- async def api_key_guard(request: Request, call_next):
8
- # Public endpoints that don't require authentication
9
- public_paths = ["/", "/health", "/docs", "/redoc", "/openapi.json"]
 
 
 
 
 
10
 
 
 
 
11
  # Skip auth for public endpoints
12
- if request.url.path in public_paths:
13
  return await call_next(request)
14
 
15
  # Skip auth if no API key is configured
16
  if not settings.service_api_key:
17
  return await call_next(request)
18
 
19
- # Check API key
20
- key = request.headers.get("x-api-key") or request.headers.get("authorization")
21
- if key and key.replace("Bearer ", "").strip() == settings.service_api_key:
 
 
 
 
 
 
22
  return await call_next(request)
23
 
24
- return JSONResponse({"error": "unauthorized"}, status_code=401)
 
 
 
25
 
26
 
 
1
+ from fastapi import Request
2
+ from fastapi.responses import JSONResponse, Response
3
+ from typing import Callable, Awaitable, Union
4
 
5
  from app.config import settings
6
 
7
+ # Public endpoints that don't require authentication
8
+ PUBLIC_PATHS = frozenset(["/", "/health", "/docs", "/redoc", "/openapi.json"])
9
 
10
+
11
+ async def api_key_guard(request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Union[Response, JSONResponse]:
12
+ """
13
+ Middleware to protect API endpoints with optional API key authentication.
14
+
15
+ Args:
16
+ request: FastAPI request object
17
+ call_next: Next middleware/handler in the chain
18
 
19
+ Returns:
20
+ Response from next handler or 401 if unauthorized
21
+ """
22
  # Skip auth for public endpoints
23
+ if request.url.path in PUBLIC_PATHS:
24
  return await call_next(request)
25
 
26
  # Skip auth if no API key is configured
27
  if not settings.service_api_key:
28
  return await call_next(request)
29
 
30
+ # Check API key from headers
31
+ api_key = request.headers.get("x-api-key")
32
+ if not api_key:
33
+ # Also check Authorization header with Bearer token
34
+ auth_header = request.headers.get("authorization", "")
35
+ if auth_header.startswith("Bearer "):
36
+ api_key = auth_header.replace("Bearer ", "").strip()
37
+
38
+ if api_key and api_key == settings.service_api_key:
39
  return await call_next(request)
40
 
41
+ return JSONResponse(
42
+ content={"error": {"message": "unauthorized", "type": "authentication_error"}},
43
+ status_code=401
44
+ )
45
 
46
 
app/providers/transformers_provider.py CHANGED
@@ -3,7 +3,7 @@ import time
3
  import json
4
  import logging
5
  import torch
6
- from typing import Dict, Any, AsyncIterator, Union
7
  import asyncio
8
  from threading import Thread, Lock
9
  from huggingface_hub import login, hf_hub_download
@@ -386,20 +386,28 @@ class TransformersProvider:
386
  yield f"data: {json.dumps(final_chunk, ensure_ascii=False)}\n\n"
387
  yield "data: [DONE]\n\n"
388
 
389
- def _messages_to_prompt(self, messages: list) -> str:
390
- """Convert OpenAI messages format to prompt (fallback)."""
391
- prompt = ""
 
 
 
 
 
 
 
 
392
  for message in messages:
393
- role = message["role"]
394
- content = message["content"]
395
  if role == "system":
396
- prompt += f"System: {content}\n"
397
  elif role == "user":
398
- prompt += f"User: {content}\n"
399
  elif role == "assistant":
400
- prompt += f"Assistant: {content}\n"
401
- prompt += "Assistant: "
402
- return prompt
403
 
404
 
405
  # Module-level provider instance
 
3
  import json
4
  import logging
5
  import torch
6
+ from typing import Dict, Any, AsyncIterator, Union, List
7
  import asyncio
8
  from threading import Thread, Lock
9
  from huggingface_hub import login, hf_hub_download
 
386
  yield f"data: {json.dumps(final_chunk, ensure_ascii=False)}\n\n"
387
  yield "data: [DONE]\n\n"
388
 
389
+ def _messages_to_prompt(self, messages: List[Dict[str, str]]) -> str:
390
+ """
391
+ Convert OpenAI messages format to prompt (fallback).
392
+
393
+ Args:
394
+ messages: List of message dictionaries with 'role' and 'content'
395
+
396
+ Returns:
397
+ Formatted prompt string
398
+ """
399
+ prompt_parts = []
400
  for message in messages:
401
+ role = message.get("role", "user")
402
+ content = message.get("content", "")
403
  if role == "system":
404
+ prompt_parts.append(f"System: {content}")
405
  elif role == "user":
406
+ prompt_parts.append(f"User: {content}")
407
  elif role == "assistant":
408
+ prompt_parts.append(f"Assistant: {content}")
409
+ prompt_parts.append("Assistant: ")
410
+ return "\n".join(prompt_parts)
411
 
412
 
413
  # Module-level provider instance
app/routers/openai_api.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict
2
  import logging
3
 
4
  from fastapi import APIRouter, Query
@@ -15,13 +15,13 @@ router = APIRouter()
15
 
16
 
17
  @router.get("/models")
18
- async def list_models():
19
  """List available models (OpenAI-compatible endpoint)"""
20
  return await chat_service.list_models()
21
 
22
 
23
  @router.post("/models/reload")
24
- async def reload_model(force: bool = Query(False, description="Force reload from Hugging Face Hub")):
25
  """
26
  Reload the model from cache or Hugging Face Hub.
27
 
@@ -51,7 +51,7 @@ async def reload_model(force: bool = Query(False, description="Force reload from
51
 
52
 
53
  @router.post("/chat/completions")
54
- async def chat_completions(body: ChatCompletionRequest):
55
  """Chat completions endpoint (OpenAI-compatible)"""
56
  try:
57
  # Validate messages list is not empty
 
1
+ from typing import Any, Dict, Union
2
  import logging
3
 
4
  from fastapi import APIRouter, Query
 
15
 
16
 
17
  @router.get("/models")
18
+ async def list_models() -> Dict[str, Any]:
19
  """List available models (OpenAI-compatible endpoint)"""
20
  return await chat_service.list_models()
21
 
22
 
23
  @router.post("/models/reload")
24
+ async def reload_model(force: bool = Query(False, description="Force reload from Hugging Face Hub")) -> JSONResponse:
25
  """
26
  Reload the model from cache or Hugging Face Hub.
27
 
 
51
 
52
 
53
  @router.post("/chat/completions")
54
+ async def chat_completions(body: ChatCompletionRequest) -> Union[JSONResponse, StreamingResponse]:
55
  """Chat completions endpoint (OpenAI-compatible)"""
56
  try:
57
  # Validate messages list is not empty
app/services/chat_service.py CHANGED
@@ -1,13 +1,33 @@
1
- from typing import Any, Dict
 
2
 
3
  from app.providers import transformers_provider as provider
4
 
5
 
6
  async def list_models() -> Dict[str, Any]:
 
 
 
 
 
 
7
  return await provider.list_models()
8
 
9
 
10
- async def chat(payload: Dict[str, Any], stream: bool = False):
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  return await provider.chat(payload, stream=stream)
12
 
13
 
 
1
+ """Chat service layer providing abstraction over the provider."""
2
+ from typing import Any, Dict, Union, AsyncIterator
3
 
4
  from app.providers import transformers_provider as provider
5
 
6
 
7
  async def list_models() -> Dict[str, Any]:
8
+ """
9
+ List available models.
10
+
11
+ Returns:
12
+ Dictionary containing model list in OpenAI-compatible format
13
+ """
14
  return await provider.list_models()
15
 
16
 
17
+ async def chat(
18
+ payload: Dict[str, Any],
19
+ stream: bool = False
20
+ ) -> Union[Dict[str, Any], AsyncIterator[str]]:
21
+ """
22
+ Process chat completion request.
23
+
24
+ Args:
25
+ payload: Request payload containing messages and generation parameters
26
+ stream: Whether to stream the response
27
+
28
+ Returns:
29
+ Response dictionary or async iterator for streaming
30
+ """
31
  return await provider.chat(payload, stream=stream)
32
 
33
 
app/utils/helpers.py CHANGED
@@ -2,7 +2,7 @@
2
 
3
  import os
4
  import logging
5
- from typing import Optional, Tuple
6
 
7
  from app.utils.constants import HF_TOKEN_VARS, FRENCH_PHRASES, FRENCH_CHARS, FRENCH_PATTERNS
8
 
@@ -24,7 +24,7 @@ def get_hf_token() -> Tuple[Optional[str], str]:
24
  return None, "none"
25
 
26
 
27
- def is_french_request(messages: list) -> bool:
28
  """
29
  Detect if the request is in French based on user messages.
30
 
@@ -55,7 +55,7 @@ def is_french_request(messages: list) -> bool:
55
  return False
56
 
57
 
58
- def has_french_system_prompt(messages: list) -> bool:
59
  """Check if messages already contain a French system prompt."""
60
  return any(
61
  "français" in msg.get("content", "").lower()
 
2
 
3
  import os
4
  import logging
5
+ from typing import Optional, Tuple, List, Dict, Any
6
 
7
  from app.utils.constants import HF_TOKEN_VARS, FRENCH_PHRASES, FRENCH_CHARS, FRENCH_PATTERNS
8
 
 
24
  return None, "none"
25
 
26
 
27
+ def is_french_request(messages: List[Dict[str, Any]]) -> bool:
28
  """
29
  Detect if the request is in French based on user messages.
30
 
 
55
  return False
56
 
57
 
58
+ def has_french_system_prompt(messages: List[Dict[str, Any]]) -> bool:
59
  """Check if messages already contain a French system prompt."""
60
  return any(
61
  "français" in msg.get("content", "").lower()