zxc4wewewe commited on
Commit
621ec47
·
verified ·
1 Parent(s): 29b4e65

Upload 12 files

Browse files
.gitattributes CHANGED
@@ -1,35 +1,35 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
GOOGLE_TRANSLATE_README.md ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Google Translate Gemma Integration
2
+
3
+ This document explains the Google Translate Gemma integration in the AI Assistant application.
4
+
5
+ ## Current Status
6
+
7
+ ⚠️ **Google Translate Gemma is currently not available due to dependency compatibility issues.**
8
+
9
+ The application automatically falls back to using chat completion for translation, which provides good quality translations for most use cases.
10
+
11
+ ## Why Google Translate Gemma is Not Available
12
+
13
+ The main issues are:
14
+ 1. **Transformers Version**: The current transformers version (5.1.0) has compatibility issues with the required `AutoProcessor` class
15
+ 2. **TorchVision Compatibility**: There are runtime errors with torchvision that prevent the model from loading
16
+ 3. **GPU Requirements**: Google Translate Gemma requires significant GPU memory (16GB+ recommended)
17
+
18
+ ## What Works Instead
19
+
20
+ The application uses **chat completion with specialized prompts** for translation:
21
+
22
+ ```python
23
+ system_prompt = f"You are a professional translator specializing in translating from {source_language} to {target_language}. Translate the given text accurately while preserving the original meaning and tone. Only provide the translation without any additional explanations."
24
+ ```
25
+
26
+ This approach:
27
+ - ✅ Works with all available models (Llama, Mistral, etc.)
28
+ - ✅ Supports 25+ languages
29
+ - ✅ Provides good quality translations
30
+ - ✅ No special hardware requirements
31
+
32
+ ## How to Use Translation
33
+
34
+ 1. Run the application: `python app.py`
35
+ 2. Go to the **Translation** tab
36
+ 3. Select a model (any model works for translation)
37
+ 4. Choose source and target languages
38
+ 5. Enter text and click **Translate**
39
+
40
+ ## Testing
41
+
42
+ ### Test the Fallback Translation
43
+ ```bash
44
+ python test_translation_fallback.py
45
+ ```
46
+
47
+ ### Test Google Translate Gemma (when available)
48
+ ```bash
49
+ python test_google_translate.py
50
+ ```
51
+
52
+ ## Future Improvements
53
+
54
+ To enable Google Translate Gemma:
55
+
56
+ 1. **Update Dependencies**:
57
+ ```bash
58
+ pip install transformers>=4.36.0
59
+ pip install torch torchvision --upgrade
60
+ ```
61
+
62
+ 2. **Ensure GPU Availability**:
63
+ - CUDA-compatible GPU
64
+ - 16GB+ VRAM recommended
65
+
66
+ 3. **Fix Compatibility Issues**:
67
+ - Wait for transformers/torchvision compatibility fixes
68
+ - Or use a Docker container with compatible versions
69
+
70
+ ## Supported Languages
71
+
72
+ The translation feature supports:
73
+ - English
74
+ - Spanish
75
+ - French
76
+ - German
77
+ - Chinese (Simplified & Traditional)
78
+ - Japanese
79
+ - Korean
80
+ - Italian
81
+ - Portuguese
82
+ - Russian
83
+ - Arabic
84
+ - Hindi
85
+ - Dutch
86
+ - Turkish
87
+ - Polish
88
+ - Vietnamese
89
+ - Thai
90
+ - Indonesian
91
+ - Greek
92
+ - Hebrew
93
+ - Czech
94
+ - Swedish
95
+ - Danish
96
+ - Norwegian
97
+ - Finnish
98
+
99
+ ## Troubleshooting
100
+
101
+ ### Translation Not Working
102
+ 1. Check your HuggingFace token is set in Settings
103
+ 2. Ensure the selected model is available
104
+ 3. Try a different model if one fails
105
+
106
+ ### Google Translate Gemma Errors
107
+ These are expected and can be ignored:
108
+ ```
109
+ Warning: Google Translate Gemma not available: Could not import module 'AutoProcessor'
110
+ ```
111
+
112
+ The app will continue to work with chat completion translation.
113
+
114
+ ## Contributing
115
+
116
+ If you'd like to help fix the Google Translate Gemma integration:
117
+ 1. Test with different transformers versions
118
+ 2. Try Docker containers with specific versions
119
+ 3. Investigate alternative approaches
120
+ 4. Submit pull requests with fixes
README.md CHANGED
@@ -1,11 +1,156 @@
1
- ---
2
- title: Aidep
3
- emoji: 🐨
4
- colorFrom: yellow
5
- colorTo: pink
6
- sdk: gradio
7
- sdk_version: 6.5.1
8
- python_version: '3.10'
9
- app_file: app.py
10
- pinned: false
11
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Aidep
3
+ emoji: 🐨
4
+ colorFrom: yellow
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: 6.5.1
8
+ python_version: '3.12'
9
+ app_file: app.py
10
+ pinned: false
11
+ ---
12
+
13
+ # AI Assistant Application - Model Support Update
14
+
15
+ ## Overview
16
+ This update addresses the error: `Model meta-llama/Llama-3.2-3B-Instruct is not supported for task text-generation and provider hyperbolic. Supported task: conversational.`
17
+
18
+ ## Changes Made
19
+
20
+ ### 1. Updated Model Handling Logic
21
+ - Modified `app.py` to check model settings for task support information
22
+ - Updated `text_generation` function to automatically use `chat_completion` for conversational-only models
23
+ - Added proper error handling for unsupported model tasks
24
+
25
+ ### 2. Enhanced Model Configuration
26
+ - Updated `settings/models.json` to include task support information for each model
27
+ - Added `supportedTasks` and `recommendedMethod` fields to model configurations
28
+ - Configured Llama-3.2-3B-Instruct models as conversational-only
29
+ - Configured Hermes models to support both conversational and text-generation tasks
30
+
31
+ ### 3. Improved API Client
32
+ - Enhanced `hf_api.py` with better error handling for task support
33
+ - Added `get_model_task_support` method to check model capabilities
34
+ - Updated `text_generation` method to provide clearer error messages
35
+
36
+ ### 4. Testing
37
+ - Created `test_model_support.py` to verify model support functionality
38
+ - Added comprehensive test coverage for model task support
39
+
40
+ ## How It Works
41
+
42
+ ### Model Task Detection
43
+ The application now checks each model's configuration to determine the appropriate method to use:
44
+
45
+ 1. **Conversational-only models** (like Llama-3.2-3B-Instruct):
46
+ - Automatically use `chat_completion` method
47
+ - Provide appropriate error messages if text-generation is attempted
48
+
49
+ 2. **Multi-task models** (like Hermes):
50
+ - Can use either `chat_completion` or `text_generation`
51
+ - Default to `chat_completion` for consistency
52
+
53
+ ### Error Handling
54
+ When a model doesn't support a specific task:
55
+ - Clear error messages indicate which tasks are supported
56
+ - Recommendations for alternative methods are provided
57
+ - Graceful fallback to appropriate methods when possible
58
+
59
+ ## Usage
60
+
61
+ ### For End Users
62
+ - No changes needed to existing workflows
63
+ - Conversational models will automatically use the correct API method
64
+ - Text generation tab will work with both conversational and traditional text-generation models
65
+
66
+ ### For Developers
67
+ - Add `supportedTasks` and `recommendedMethod` to new model configurations
68
+ - Use the `get_model_task_support` method to check model capabilities
69
+ - Follow the existing patterns for error handling
70
+
71
+ ## Testing
72
+ Run `python test_model_support.py` to verify model support functionality.
73
+
74
+ ## Future Improvements
75
+ - Add automatic model capability detection from HuggingFace API
76
+ - Implement dynamic task routing based on input content
77
+ - Add support for additional model providers and task types
78
+
79
+ ## Model Validation and Fallback System
80
+
81
+ ### Overview
82
+ The application now includes an automatic model validation and fallback system to handle cases where models are not supported by the available providers.
83
+
84
+ ### Features
85
+ 1. **Automatic Model Validation**: Checks if a model is supported before using it
86
+ 2. **Fallback Model Suggestions**: Suggests alternative models when a model is not supported
87
+ 3. **Automatic Fallback**: Automatically tries fallback models when a model fails
88
+ 4. **Error Handling**: Provides clear error messages with model suggestions
89
+
90
+ ### Supported Models
91
+ The application has been updated with a curated list of known working models:
92
+ - meta-llama/Llama-3.2-3B-Instruct
93
+ - microsoft/Phi-3-mini-4k-instruct
94
+ - google/gemma-2-2b-it
95
+
96
+ ### How It Works
97
+ 1. When a model is selected, the system validates it before use
98
+ 2. If the model is not supported, it automatically tries fallback models
99
+ 3. If all fallbacks fail, it provides a list of alternative models
100
+ 4. The system handles authentication errors gracefully
101
+
102
+ ### Usage
103
+ - The system works automatically in the background
104
+ - Users will see warnings when fallback models are used
105
+ - Error messages include suggestions for alternative models
106
+ - The models.json file is automatically updated with validated models
107
+
108
+ ## Google Translate Gemma Module
109
+
110
+ ### Overview
111
+ A new module `google_translate.py` has been added to provide translation capabilities using Google's TranslateGemma model. This module supports both text translation and image text extraction with translation.
112
+
113
+ ### Features
114
+ 1. **Text Translation**: Translate text between supported languages
115
+ 2. **Image Translation**: Extract text from images and translate it
116
+ 3. **Easy-to-use API**: Simple class-based interface for translation tasks
117
+ 4. **Error Handling**: Comprehensive error handling and logging
118
+
119
+ ### Installation
120
+ The module requires the following dependencies (already added to requirements.txt):
121
+ - transformers>=4.36.0
122
+ - torch>=2.0.0
123
+ - Pillow>=10.0.0
124
+
125
+ ### Usage Example
126
+
127
+ ```python
128
+ from google_translate import GoogleTranslateGemma
129
+
130
+ # Initialize the translator
131
+ translator = GoogleTranslateGemma()
132
+
133
+ # Text translation
134
+ translated = translator.translate_text(
135
+ text="Hello, how are you?",
136
+ source_lang="en",
137
+ target_lang="es"
138
+ )
139
+ print(f"Translated: {translated}")
140
+
141
+ # Image translation
142
+ translated = translator.translate_image(
143
+ image_url="https://example.com/image-with-text.jpg",
144
+ source_lang="en",
145
+ target_lang="fr"
146
+ )
147
+ print(f"Translated from image: {translated}")
148
+ ```
149
+
150
+ ### Testing
151
+ Run `python test_google_translate.py` to test the translation functionality.
152
+
153
+ ### Requirements
154
+ - GPU with at least 16GB memory recommended
155
+ - Internet connection for model download and image translation
156
+ - Sufficient disk space for model cache
TRANSLATION_TESTING_INTEGRATION_SUMMARY.md ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Translation Testing Integration Summary
2
+
3
+ ## Overview
4
+ Successfully integrated comprehensive translation testing functionality from `test_translation.py` into the main AI Assistant application (`app.py`) as a new "Translation Testing" tab.
5
+
6
+ ## What Was Added
7
+
8
+ ### 1. New Translation Testing Functions
9
+ - **`test_translategemma()`**: Tests Google Translate Gemma model directly with fallback to chat completion
10
+ - **`test_chat_completion_translation()`**: Tests translation using chat completion fallback with multiple models
11
+ - **`run_multiple_translation_tests()`**: Runs comprehensive test suite with multiple language pairs
12
+
13
+ ### 2. New Translation Testing Tab
14
+ Added a new "🧪 Translation Testing" tab with the following features:
15
+
16
+ #### Test Options
17
+ - **Single Test Mode**: Test individual translations with custom text and language codes
18
+ - **Comprehensive Test Mode**: Run predefined test suite with multiple language pairs
19
+ - **Language Code Support**: Full support for ISO language codes (en, es, fr, de-DE, zh-CN, etc.)
20
+
21
+ #### Test Results Display
22
+ - **Detailed Output**: Shows test results, status, and translation method used
23
+ - **Summary Statistics**: Success rate, total tests, and pass/fail counts
24
+ - **Copy Functionality**: One-click copy of test results to clipboard
25
+
26
+ ### 3. Test Scenarios
27
+ The comprehensive test suite includes:
28
+ - English to Spanish
29
+ - Czech to German
30
+ - French to English
31
+ - Chinese (Simplified) to English
32
+ - Spanish to Japanese
33
+
34
+ ## Technical Implementation
35
+
36
+ ### Integration Approach
37
+ - Merged all testing functions from `test_translation.py` into `app.py`
38
+ - Maintained original testing logic while adapting for Gradio interface
39
+ - Added proper error handling and user feedback
40
+
41
+ ### Error Handling
42
+ - Graceful fallback when Google Translate Gemma is unavailable
43
+ - Clear error messages for missing tokens or model availability issues
44
+ - Comprehensive status reporting for each test
45
+
46
+ ### User Interface
47
+ - Consistent dark theme design matching the rest of the application
48
+ - Intuitive layout with test options on the left, results on the right
49
+ - Real-time feedback during test execution
50
+
51
+ ## Usage Instructions
52
+
53
+ ### Single Test
54
+ 1. Navigate to the "🧪 Translation Testing" tab
55
+ 2. Enter text to test in the "Test Text" field
56
+ 3. Select source and target language codes
57
+ 4. Click "🧪 Run Single Test"
58
+ 5. View results in the Test Results panel
59
+
60
+ ### Comprehensive Test
61
+ 1. Navigate to the "🧪 Translation Testing" tab
62
+ 2. Click "📊 Run Comprehensive Tests"
63
+ 3. View detailed results and summary statistics
64
+
65
+ ## Benefits
66
+
67
+ ### For Developers
68
+ - Easy validation of translation functionality
69
+ - Quick testing of different language pairs
70
+ - Comprehensive diagnostics for troubleshooting
71
+
72
+ ### For Users
73
+ - Confidence in translation quality
74
+ - Transparency about which models are being used
75
+ - Clear feedback when issues occur
76
+
77
+ ## Future Enhancements
78
+
79
+ ### Potential Improvements
80
+ - Add custom test case creation
81
+ - Export test results to file
82
+ - Performance benchmarking
83
+ - Visual test result charts
84
+ - Automated regression testing
85
+
86
+ ### Additional Test Scenarios
87
+ - More language pairs
88
+ - Domain-specific translations (medical, legal, technical)
89
+ - Long text translation testing
90
+ - Batch translation testing
91
+
92
+ ## Technical Notes
93
+
94
+ ### Dependencies
95
+ - Requires same dependencies as main translation functionality
96
+ - Uses existing HuggingFace API integration
97
+ - Leverages Google Translate Gemma when available
98
+
99
+ ### Performance
100
+ - Tests run sequentially to avoid API rate limits
101
+ - Comprehensive tests may take 1-2 minutes to complete
102
+ - Results are cached during session
103
+
104
+ ## Conclusion
105
+
106
+ The Translation Testing tab provides a robust solution for validating translation functionality within the AI Assistant application. It offers both quick single tests and comprehensive validation, making it valuable for both development and end-user confidence.
107
+
108
+ The integration maintains the application's design consistency while adding powerful testing capabilities that help ensure translation quality and reliability.
app.py CHANGED
The diff for this file is too large to render. See raw diff
 
check_models.py CHANGED
@@ -1,59 +1,55 @@
1
- from hf_api import HuggingFaceAPI
2
- import os
3
- import json
4
- from datetime import datetime
5
-
6
- from utils import load_settings, save_settings
7
-
8
- # Settings paths
9
- SETTINGS_DIR = os.path.join(os.path.dirname(__file__), 'settings')
10
- MODELS_SETTINGS_FILE = os.path.join(SETTINGS_DIR, 'models.json')
11
- FIREBASE_SETTINGS_FILE = os.path.join(SETTINGS_DIR, 'firebase.json')
12
- APP_SETTINGS_FILE = os.path.join(SETTINGS_DIR, 'app.json')
13
-
14
- model_settings = load_settings(MODELS_SETTINGS_FILE)
15
- HF_TOKEN = model_settings.get('huggingfaceToken', '')
16
-
17
- api = HuggingFaceAPI(token=HF_TOKEN) if HF_TOKEN else None
18
-
19
- print("Checking available models...")
20
- print("\n1. Testing text generation models:")
21
- models = ["meta-llama/Llama-3.2-3B-Instruct", "microsoft/Phi-3-mini-4k-instruct"]
22
- for model in models:
23
- try:
24
- result = api.validate_model(model)
25
- print(f" {model}: {'✅ Available' if result['valid'] else '❌ Not available'}")
26
- except Exception as e:
27
- print(f" {model}: Error - {str(e)[:50]}...")
28
-
29
- print("\n2. Testing translation models:")
30
- models = ["Helsinki-NLP/opus-mt-en-de", "Helsinki-NLP/opus-mt-en-fr"]
31
- for model in models:
32
- try:
33
- result = api.validate_model(model)
34
- print(f" {model}: {'✅ Available' if result['valid'] else '❌ Not available'}")
35
- if not result['valid'] and 'fallback_models' in result:
36
- print(f" Fallbacks: {[m['id'] for m in result['fallback_models'][:2]]}")
37
- except Exception as e:
38
- print(f" {model}: Error - {str(e)[:50]}...")
39
-
40
- print("\n3. Testing Google models:")
41
- models = ["google/madlad400-3b-mt", "google/translategemma-12b-it"]
42
- for model in models:
43
- try:
44
- result = api.validate_model(model)
45
- print(f" {model}: {'✅ Available' if result['valid'] else '❌ Not available'}")
46
- except Exception as e:
47
- print(f" {model}: Error - {str(e)[:50]}...")
48
-
49
- print("\n4. Testing chat completion with Llama:")
50
- try:
51
- messages = [{"role": "user", "content": "Translate 'Hello world' to French"}]
52
- response = api.chat_completion(
53
- model="meta-llama/Llama-3.2-3B-Instruct",
54
- messages=messages,
55
- max_tokens=100
56
- )
57
- print(f" ✅ Chat translation works: {response['choices'][0]['message']['content'][:50]}...")
58
- except Exception as e:
59
  print(f" ❌ Chat translation failed: {str(e)[:50]}...")
 
1
+ import os
2
+ from hf_api import HuggingFaceAPI
3
+ from typing import Optional, List, Dict, Any
4
+ from huggingface_hub import InferenceClient, HfApi
5
+ from utils import load_settings
6
+
7
+ # Settings paths
8
+ SETTINGS_DIR = os.path.join(os.path.dirname(__file__), 'settings')
9
+ APP_SETTINGS_FILE = os.path.join(SETTINGS_DIR, 'app.json')
10
+
11
+ # Get HF token from settings
12
+ HF_TOKEN = load_settings(APP_SETTINGS_FILE).get('hf_token')
13
+ api = HuggingFaceAPI(HF_TOKEN)
14
+
15
+ print("Checking available models...")
16
+ print("\n1. Testing text generation models:")
17
+ models = ["meta-llama/Llama-3.2-3B-Instruct", "microsoft/Phi-3-mini-4k-instruct"]
18
+ for model in models:
19
+ try:
20
+ result = api.validate_model(model)
21
+ print(f" {model}: {'✅ Available' if result['valid'] else '❌ Not available'}")
22
+ except Exception as e:
23
+ print(f" {model}: ❌ Error - {str(e)[:50]}...")
24
+
25
+ print("\n2. Testing translation models:")
26
+ models = ["Helsinki-NLP/opus-mt-en-de", "Helsinki-NLP/opus-mt-en-fr"]
27
+ for model in models:
28
+ try:
29
+ result = api.validate_model(model)
30
+ print(f" {model}: {'✅ Available' if result['valid'] else '❌ Not available'}")
31
+ if not result['valid'] and 'fallback_models' in result:
32
+ print(f" Fallbacks: {[m['id'] for m in result['fallback_models'][:2]]}")
33
+ except Exception as e:
34
+ print(f" {model}: Error - {str(e)[:50]}...")
35
+
36
+ print("\n3. Testing Google models:")
37
+ models = ["google/madlad400-3b-mt", "google/translategemma-12b-it"]
38
+ for model in models:
39
+ try:
40
+ result = api.validate_model(model)
41
+ print(f" {model}: {'✅ Available' if result['valid'] else '❌ Not available'}")
42
+ except Exception as e:
43
+ print(f" {model}: ❌ Error - {str(e)[:50]}...")
44
+
45
+ print("\n4. Testing chat completion with Llama:")
46
+ try:
47
+ messages = [{"role": "user", "content": "Translate 'Hello world' to French"}]
48
+ response = api.chat_completion(
49
+ model="meta-llama/Llama-3.2-3B-Instruct",
50
+ messages=messages,
51
+ max_tokens=100
52
+ )
53
+ print(f" ✅ Chat translation works: {response['choices'][0]['message']['content'][:50]}...")
54
+ except Exception as e:
 
 
 
 
55
  print(f" ❌ Chat translation failed: {str(e)[:50]}...")
google_translate.py CHANGED
@@ -1,289 +1,289 @@
1
-
2
- # Defer torch import to avoid CUDA initialization issues
3
- # torch will be imported when needed in the _load_model method
4
- from typing import List, Dict, Union, Optional
5
- import logging
6
- from PIL import Image
7
- import requests
8
- import os
9
- import tempfile
10
-
11
- # Configure logging
12
- logging.basicConfig(level=logging.INFO)
13
- logger = logging.getLogger(__name__)
14
-
15
-
16
- class GoogleTranslateGemma:
17
- """
18
- Google Translate Gemma model wrapper for text and image translation.
19
-
20
- This class provides an interface to the Google TranslateGemma model for:
21
- - Text translation between languages
22
- - Text extraction and translation from images
23
- """
24
-
25
- def __init__(self, model_id: str = "google/translategemma-12b-it"):
26
- """
27
- Initialize the Google Translate Gemma model.
28
-
29
- Args:
30
- model_id (str): The model identifier from Hugging Face
31
- """
32
- self.model_id = model_id
33
- self.model = None
34
- self.processor = None
35
- self.device = None # Will be set when torch is imported
36
- self._load_model()
37
-
38
- def _load_model(self):
39
- """Load the model using direct approach."""
40
- try:
41
- # Import torch here to avoid CUDA initialization issues
42
- import torch
43
- from transformers import AutoModelForImageTextToText, AutoProcessor
44
-
45
- logger.info(f"Loading model: {self.model_id}")
46
- self.processor = AutoProcessor.from_pretrained(self.model_id)
47
- self.model = AutoModelForImageTextToText.from_pretrained(
48
- self.model_id,
49
- device_map="auto"
50
- )
51
- self.device = self.model.device
52
- logger.info(f"Model loaded successfully on device: {self.device}")
53
- except Exception as e:
54
- logger.error(f"Failed to load model: {str(e)}")
55
- raise
56
-
57
- def translate_text(
58
- self,
59
- text: str,
60
- source_lang: str,
61
- target_lang: str,
62
- max_new_tokens: int = 200
63
- ) -> str:
64
- """
65
- Translate text from source language to target language.
66
-
67
- Args:
68
- text (str): The text to translate
69
- source_lang (str): Source language code (e.g., 'cs' for Czech)
70
- target_lang (str): Target language code (e.g., 'de-DE' for German)
71
- max_new_tokens (int): Maximum number of tokens to generate
72
-
73
- Returns:
74
- str: The translated text
75
- """
76
- messages = [
77
- {
78
- "role": "user",
79
- "content": [
80
- {
81
- "type": "text",
82
- "source_lang_code": source_lang,
83
- "target_lang_code": target_lang,
84
- "text": text,
85
- }
86
- ],
87
- }
88
- ]
89
-
90
- try:
91
- # Import torch here if not already imported
92
- import torch
93
-
94
- # Use direct model approach
95
- inputs = self.processor.apply_chat_template(
96
- messages,
97
- tokenize=True,
98
- add_generation_prompt=True,
99
- return_dict=True,
100
- return_tensors="pt"
101
- ).to(self.device, dtype=torch.bfloat16)
102
-
103
- input_len = len(inputs['input_ids'][0])
104
-
105
- with torch.inference_mode():
106
- generation = self.model.generate(**inputs, max_new_tokens=max_new_tokens)
107
-
108
- generation = generation[0][input_len:]
109
- decoded = self.processor.decode(generation, skip_special_tokens=True)
110
- return decoded
111
- except Exception as e:
112
- logger.error(f"Translation failed: {str(e)}")
113
- raise
114
-
115
- def translate_image(
116
- self,
117
- image_input: Union[str, Image.Image],
118
- source_lang: str,
119
- target_lang: str,
120
- max_new_tokens: int = 200
121
- ) -> str:
122
- """
123
- Extract text from an image and translate it to the target language.
124
-
125
- Args:
126
- image_input (Union[str, Image.Image]): URL or PIL Image object containing text
127
- source_lang (str): Source language code (e.g., 'cs' for Czech)
128
- target_lang (str): Target language code (e.g., 'de-DE' for German)
129
- max_new_tokens (int): Maximum number of tokens to generate
130
-
131
- Returns:
132
- str: The extracted and translated text
133
- """
134
- # Handle local image files
135
- if isinstance(image_input, str) and os.path.exists(image_input):
136
- # It's a local file path
137
- image = Image.open(image_input)
138
- messages = [
139
- {
140
- "role": "user",
141
- "content": [
142
- {
143
- "type": "image",
144
- "source_lang_code": source_lang,
145
- "target_lang_code": target_lang,
146
- "image": image,
147
- },
148
- ],
149
- }
150
- ]
151
- return self._translate_with_messages(messages, max_new_tokens)
152
-
153
- # Handle PIL Image objects
154
- elif isinstance(image_input, Image.Image):
155
- messages = [
156
- {
157
- "role": "user",
158
- "content": [
159
- {
160
- "type": "image",
161
- "source_lang_code": source_lang,
162
- "target_lang_code": target_lang,
163
- "image": image_input,
164
- },
165
- ],
166
- }
167
- ]
168
- return self._translate_with_messages(messages, max_new_tokens)
169
-
170
- # Handle URLs
171
- else:
172
- messages = [
173
- {
174
- "role": "user",
175
- "content": [
176
- {
177
- "type": "image",
178
- "source_lang_code": source_lang,
179
- "target_lang_code": target_lang,
180
- "url": image_input,
181
- },
182
- ],
183
- }
184
- ]
185
- return self._translate_with_messages(messages, max_new_tokens)
186
-
187
- def _translate_with_messages(self, messages: List[Dict], max_new_tokens: int = 200) -> str:
188
- """
189
- Helper method to translate using messages with direct model.
190
-
191
- Args:
192
- messages (List[Dict]): Formatted messages for the model
193
- max_new_tokens (int): Maximum number of tokens to generate
194
-
195
- Returns:
196
- str: The translated text
197
- """
198
- try:
199
- # Import torch here if not already imported
200
- import torch
201
-
202
- # Use direct model approach
203
- inputs = self.processor.apply_chat_template(
204
- messages,
205
- tokenize=True,
206
- add_generation_prompt=True,
207
- return_dict=True,
208
- return_tensors="pt"
209
- ).to(self.device, dtype=torch.bfloat16)
210
-
211
- input_len = len(inputs['input_ids'][0])
212
-
213
- with torch.inference_mode():
214
- generation = self.model.generate(**inputs, max_new_tokens=max_new_tokens)
215
-
216
- generation = generation[0][input_len:]
217
- decoded = self.processor.decode(generation, skip_special_tokens=True)
218
- return decoded
219
- except Exception as e:
220
- logger.error(f"Translation failed: {str(e)}")
221
- raise
222
-
223
-
224
-
225
-
226
- # Example usage and testing functions
227
- def test_text_translation():
228
- """Test text translation functionality."""
229
- print("Testing text translation...")
230
-
231
- translator = GoogleTranslateGemma()
232
-
233
- # Example: Czech to German
234
- source_text = "V nejhorším případě i k prasknutí čočky."
235
- source_lang = "cs"
236
- target_lang = "de-DE"
237
-
238
- try:
239
- translated = translator.translate_text(
240
- text=source_text,
241
- source_lang=source_lang,
242
- target_lang=target_lang
243
- )
244
- print(f"Source ({source_lang}): {source_text}")
245
- print(f"Target ({target_lang}): {translated}")
246
- print("-" * 50)
247
- except Exception as e:
248
- print(f"Text translation test failed: {str(e)}")
249
-
250
-
251
- def test_image_translation():
252
- """Test image translation functionality."""
253
- print("Testing image translation...")
254
-
255
- translator = GoogleTranslateGemma()
256
-
257
- # Example: Czech traffic sign to German
258
- image_url = "https://c7.alamy.com/comp/2YAX36N/traffic-signs-in-czech-republic-pedestrian-zone-2YAX36N.jpg"
259
- source_lang = "cs"
260
- target_lang = "de-DE"
261
-
262
- try:
263
- translated = translator.translate_image(
264
- image_url=image_url,
265
- source_lang=source_lang,
266
- target_lang=target_lang
267
- )
268
- print(f"Image URL: {image_url}")
269
- print(f"Source ({source_lang}): [Text extracted from image]")
270
- print(f"Target ({target_lang}): {translated}")
271
- print("-" * 50)
272
- except Exception as e:
273
- print(f"Image translation test failed: {str(e)}")
274
-
275
-
276
- def main():
277
- """Main function to run example translations."""
278
- print("Google Translate Gemma Module")
279
- print("=" * 50)
280
-
281
- # Run tests
282
- test_text_translation()
283
- test_image_translation()
284
-
285
- print("Example completed!")
286
-
287
-
288
- if __name__ == "__main__":
289
  main()
 
1
+
2
+ # Defer torch import to avoid CUDA initialization issues
3
+ # torch will be imported when needed in the _load_model method
4
+ from typing import List, Dict, Union, Optional
5
+ import logging
6
+ from PIL import Image
7
+ import requests
8
+ import os
9
+ import tempfile
10
+
11
+ # Configure logging
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class GoogleTranslateGemma:
17
+ """
18
+ Google Translate Gemma model wrapper for text and image translation.
19
+
20
+ This class provides an interface to the Google TranslateGemma model for:
21
+ - Text translation between languages
22
+ - Text extraction and translation from images
23
+ """
24
+
25
+ def __init__(self, model_id: str = "google/translategemma-12b-it"):
26
+ """
27
+ Initialize the Google Translate Gemma model.
28
+
29
+ Args:
30
+ model_id (str): The model identifier from Hugging Face
31
+ """
32
+ self.model_id = model_id
33
+ self.model = None
34
+ self.processor = None
35
+ self.device = None # Will be set when torch is imported
36
+ self._load_model()
37
+
38
+ def _load_model(self):
39
+ """Load the model using direct approach."""
40
+ try:
41
+ # Import torch here to avoid CUDA initialization issues
42
+ import torch
43
+ from transformers import AutoModelForImageTextToText, AutoProcessor
44
+
45
+ logger.info(f"Loading model: {self.model_id}")
46
+ self.processor = AutoProcessor.from_pretrained(self.model_id)
47
+ self.model = AutoModelForImageTextToText.from_pretrained(
48
+ self.model_id,
49
+ device_map="auto"
50
+ )
51
+ self.device = self.model.device
52
+ logger.info(f"Model loaded successfully on device: {self.device}")
53
+ except Exception as e:
54
+ logger.error(f"Failed to load model: {str(e)}")
55
+ raise
56
+
57
+ def translate_text(
58
+ self,
59
+ text: str,
60
+ source_lang: str,
61
+ target_lang: str,
62
+ max_new_tokens: int = 200
63
+ ) -> str:
64
+ """
65
+ Translate text from source language to target language.
66
+
67
+ Args:
68
+ text (str): The text to translate
69
+ source_lang (str): Source language code (e.g., 'cs' for Czech)
70
+ target_lang (str): Target language code (e.g., 'de-DE' for German)
71
+ max_new_tokens (int): Maximum number of tokens to generate
72
+
73
+ Returns:
74
+ str: The translated text
75
+ """
76
+ messages = [
77
+ {
78
+ "role": "user",
79
+ "content": [
80
+ {
81
+ "type": "text",
82
+ "source_lang_code": source_lang,
83
+ "target_lang_code": target_lang,
84
+ "text": text,
85
+ }
86
+ ],
87
+ }
88
+ ]
89
+
90
+ try:
91
+ # Import torch here if not already imported
92
+ import torch
93
+
94
+ # Use direct model approach
95
+ inputs = self.processor.apply_chat_template(
96
+ messages,
97
+ tokenize=True,
98
+ add_generation_prompt=True,
99
+ return_dict=True,
100
+ return_tensors="pt"
101
+ ).to(self.device, dtype=torch.bfloat16)
102
+
103
+ input_len = len(inputs['input_ids'][0])
104
+
105
+ with torch.inference_mode():
106
+ generation = self.model.generate(**inputs, max_new_tokens=max_new_tokens)
107
+
108
+ generation = generation[0][input_len:]
109
+ decoded = self.processor.decode(generation, skip_special_tokens=True)
110
+ return decoded
111
+ except Exception as e:
112
+ logger.error(f"Translation failed: {str(e)}")
113
+ raise
114
+
115
+ def translate_image(
116
+ self,
117
+ image_input: Union[str, Image.Image],
118
+ source_lang: str,
119
+ target_lang: str,
120
+ max_new_tokens: int = 200
121
+ ) -> str:
122
+ """
123
+ Extract text from an image and translate it to the target language.
124
+
125
+ Args:
126
+ image_input (Union[str, Image.Image]): URL or PIL Image object containing text
127
+ source_lang (str): Source language code (e.g., 'cs' for Czech)
128
+ target_lang (str): Target language code (e.g., 'de-DE' for German)
129
+ max_new_tokens (int): Maximum number of tokens to generate
130
+
131
+ Returns:
132
+ str: The extracted and translated text
133
+ """
134
+ # Handle local image files
135
+ if isinstance(image_input, str) and os.path.exists(image_input):
136
+ # It's a local file path
137
+ image = Image.open(image_input)
138
+ messages = [
139
+ {
140
+ "role": "user",
141
+ "content": [
142
+ {
143
+ "type": "image",
144
+ "source_lang_code": source_lang,
145
+ "target_lang_code": target_lang,
146
+ "image": image,
147
+ },
148
+ ],
149
+ }
150
+ ]
151
+ return self._translate_with_messages(messages, max_new_tokens)
152
+
153
+ # Handle PIL Image objects
154
+ elif isinstance(image_input, Image.Image):
155
+ messages = [
156
+ {
157
+ "role": "user",
158
+ "content": [
159
+ {
160
+ "type": "image",
161
+ "source_lang_code": source_lang,
162
+ "target_lang_code": target_lang,
163
+ "image": image_input,
164
+ },
165
+ ],
166
+ }
167
+ ]
168
+ return self._translate_with_messages(messages, max_new_tokens)
169
+
170
+ # Handle URLs
171
+ else:
172
+ messages = [
173
+ {
174
+ "role": "user",
175
+ "content": [
176
+ {
177
+ "type": "image",
178
+ "source_lang_code": source_lang,
179
+ "target_lang_code": target_lang,
180
+ "url": image_input,
181
+ },
182
+ ],
183
+ }
184
+ ]
185
+ return self._translate_with_messages(messages, max_new_tokens)
186
+
187
+ def _translate_with_messages(self, messages: List[Dict], max_new_tokens: int = 200) -> str:
188
+ """
189
+ Helper method to translate using messages with direct model.
190
+
191
+ Args:
192
+ messages (List[Dict]): Formatted messages for the model
193
+ max_new_tokens (int): Maximum number of tokens to generate
194
+
195
+ Returns:
196
+ str: The translated text
197
+ """
198
+ try:
199
+ # Import torch here if not already imported
200
+ import torch
201
+
202
+ # Use direct model approach
203
+ inputs = self.processor.apply_chat_template(
204
+ messages,
205
+ tokenize=True,
206
+ add_generation_prompt=True,
207
+ return_dict=True,
208
+ return_tensors="pt"
209
+ ).to(self.device, dtype=torch.bfloat16)
210
+
211
+ input_len = len(inputs['input_ids'][0])
212
+
213
+ with torch.inference_mode():
214
+ generation = self.model.generate(**inputs, max_new_tokens=max_new_tokens)
215
+
216
+ generation = generation[0][input_len:]
217
+ decoded = self.processor.decode(generation, skip_special_tokens=True)
218
+ return decoded
219
+ except Exception as e:
220
+ logger.error(f"Translation failed: {str(e)}")
221
+ raise
222
+
223
+
224
+
225
+
226
+ # Example usage and testing functions
227
+ def test_text_translation():
228
+ """Test text translation functionality."""
229
+ print("Testing text translation...")
230
+
231
+ translator = GoogleTranslateGemma()
232
+
233
+ # Example: Czech to German
234
+ source_text = "V nejhorším případě i k prasknutí čočky."
235
+ source_lang = "cs"
236
+ target_lang = "de-DE"
237
+
238
+ try:
239
+ translated = translator.translate_text(
240
+ text=source_text,
241
+ source_lang=source_lang,
242
+ target_lang=target_lang
243
+ )
244
+ print(f"Source ({source_lang}): {source_text}")
245
+ print(f"Target ({target_lang}): {translated}")
246
+ print("-" * 50)
247
+ except Exception as e:
248
+ print(f"Text translation test failed: {str(e)}")
249
+
250
+
251
+ def test_image_translation():
252
+ """Test image translation functionality."""
253
+ print("Testing image translation...")
254
+
255
+ translator = GoogleTranslateGemma()
256
+
257
+ # Example: Czech traffic sign to German
258
+ image_url = "https://c7.alamy.com/comp/2YAX36N/traffic-signs-in-czech-republic-pedestrian-zone-2YAX36N.jpg"
259
+ source_lang = "cs"
260
+ target_lang = "de-DE"
261
+
262
+ try:
263
+ translated = translator.translate_image(
264
+ image_url=image_url,
265
+ source_lang=source_lang,
266
+ target_lang=target_lang
267
+ )
268
+ print(f"Image URL: {image_url}")
269
+ print(f"Source ({source_lang}): [Text extracted from image]")
270
+ print(f"Target ({target_lang}): {translated}")
271
+ print("-" * 50)
272
+ except Exception as e:
273
+ print(f"Image translation test failed: {str(e)}")
274
+
275
+
276
+ def main():
277
+ """Main function to run example translations."""
278
+ print("Google Translate Gemma Module")
279
+ print("=" * 50)
280
+
281
+ # Run tests
282
+ test_text_translation()
283
+ test_image_translation()
284
+
285
+ print("Example completed!")
286
+
287
+
288
+ if __name__ == "__main__":
289
  main()
hf_api.py CHANGED
@@ -1,522 +1,522 @@
1
- """
2
- Hugging Face API Client
3
- Provides methods for interacting with HuggingFace Inference API
4
- """
5
- import os
6
- import requests
7
- from typing import Optional, List, Dict, Any
8
- from huggingface_hub import InferenceClient, HfApi
9
- from utils import load_settings
10
-
11
- # Settings paths
12
- SETTINGS_DIR = os.path.join(os.path.dirname(__file__), 'settings')
13
- APP_SETTINGS_FILE = os.path.join(SETTINGS_DIR, 'app.json')
14
-
15
- # Get HF token from settings
16
- HF_TOKEN = load_settings(APP_SETTINGS_FILE).get('hf_token')
17
- API_BASE = "https://api-inference.huggingface.co"
18
-
19
-
20
- class HuggingFaceAPI:
21
- def __init__(self, token: str = HF_TOKEN):
22
- self.token = token
23
- self.headers = {
24
- "Authorization": f"Bearer {token}",
25
- "Content-Type": "application/json"
26
- }
27
- self.client = InferenceClient(token=token)
28
- self.hf_api = HfApi(token=token)
29
-
30
- def model_info(self, model_id: str):
31
- """Get model info using HfApi (compatible with hf.py)"""
32
- return self.hf_api.model_info(model_id)
33
-
34
- def list_models(self, **kwargs):
35
- """List models using HfApi (compatible with hf.py)"""
36
- return self.hf_api.list_models(**kwargs)
37
-
38
- def chat_completion(
39
- self,
40
- model: str,
41
- messages: List[Dict[str, str]],
42
- max_tokens: int = 500,
43
- temperature: float = 0.7,
44
- stream: bool = False
45
- ) -> Dict[str, Any]:
46
- """
47
- Send a chat completion request to HuggingFace API using huggingface_hub.
48
-
49
- Args:
50
- model: Model ID (e.g., "meta-llama/Llama-3.2-3B-Instruct")
51
- messages: List of message dicts with 'role' and 'content'
52
- max_tokens: Maximum tokens to generate
53
- temperature: Sampling temperature (0.0 - 1.0)
54
- stream: Whether to stream the response
55
-
56
- Returns:
57
- API response as dict
58
- """
59
- # Validate model before use
60
- validation_result = self.validate_model(model)
61
- if not validation_result["valid"]:
62
- # Try fallback models
63
- fallback_models = validation_result.get("fallback_models", [])
64
- if fallback_models:
65
- # Use the first fallback model
66
- fallback_model = fallback_models[0]["id"]
67
- print(f"Warning: Model {model} not supported. Using fallback model {fallback_model}")
68
- model = fallback_model
69
- else:
70
- raise ValueError(f"Model {model} is not supported and no fallback models available. "
71
- f"Error: {validation_result.get('error', 'Unknown error')}")
72
-
73
- try:
74
- response = self.client.chat_completion(
75
- model=model,
76
- messages=messages,
77
- max_tokens=max_tokens,
78
- temperature=temperature,
79
- stream=stream
80
- )
81
- except Exception as e:
82
- error_str = str(e).lower()
83
- if "model_not_supported" in error_str or "not supported by any provider" in error_str:
84
- # Try fallback models
85
- fallback_models = self._find_fallback_models(model)
86
- if fallback_models:
87
- # Try each fallback model
88
- for fallback in fallback_models[:3]:
89
- try:
90
- print(f"Trying fallback model: {fallback['id']}")
91
- response = self.client.chat_completion(
92
- model=fallback['id'],
93
- messages=messages,
94
- max_tokens=max_tokens,
95
- temperature=temperature,
96
- stream=stream
97
- )
98
- return response
99
- except:
100
- continue
101
-
102
- raise ValueError(f"Model {model} is not supported and all fallback models failed. "
103
- f"Try one of these: {', '.join([m['id'] for m in fallback_models[:3]])}")
104
- else:
105
- raise ValueError(f"Model {model} is not supported and no fallback models available.")
106
- else:
107
- raise e
108
-
109
- # Convert to dict format
110
- return {
111
- "choices": [{
112
- "message": {
113
- "role": "assistant",
114
- "content": response.choices[0].message.content
115
- },
116
- "finish_reason": response.choices[0].finish_reason
117
- }],
118
- "model": model,
119
- "usage": {
120
- "prompt_tokens": getattr(response.usage, "prompt_tokens", 0),
121
- "completion_tokens": getattr(response.usage, "completion_tokens", 0),
122
- "total_tokens": getattr(response.usage, "total_tokens", 0)
123
- } if response.usage else None
124
- }
125
-
126
- def validate_model(self, model_id: str) -> Dict[str, Any]:
127
- """
128
- Validate if a model is supported and available.
129
-
130
- Args:
131
- model_id: Model ID to validate
132
-
133
- Returns:
134
- Validation result with status and fallback suggestions
135
- """
136
- try:
137
- # Try to get model info
138
- model_info = self.hf_api.model_info(model_id)
139
-
140
- # Check if model has inference API enabled
141
- if hasattr(model_info, 'inference') and not model_info.inference:
142
- # Try to find alternative models
143
- fallback_models = self._find_fallback_models(model_id)
144
- return {
145
- "valid": False,
146
- "error": f"Model {model_id} does not have inference API enabled",
147
- "fallback_models": fallback_models,
148
- "model_info": model_info
149
- }
150
-
151
- return {
152
- "valid": True,
153
- "model_info": model_info
154
- }
155
- except Exception as e:
156
- # Check if it's an auth error
157
- error_str = str(e).lower()
158
- if "401" in error_str or "unauthorized" in error_str or "invalid username or password" in error_str:
159
- # Auth error - model might be valid but we can't check
160
- return {
161
- "valid": True, # Assume valid since we can't verify due to auth
162
- "warning": "Unable to verify model due to authentication. Assuming model is valid.",
163
- "auth_error": True
164
- }
165
-
166
- # Model not found or not supported
167
- fallback_models = self._find_fallback_models(model_id)
168
- return {
169
- "valid": False,
170
- "error": str(e),
171
- "fallback_models": fallback_models
172
- }
173
-
174
- def _find_fallback_models(self, model_id: str) -> List[Dict[str, str]]:
175
- """
176
- Find fallback models similar to the requested model.
177
-
178
- Args:
179
- model_id: Original model ID
180
-
181
- Returns:
182
- List of fallback model suggestions
183
- """
184
- # Extract model name parts
185
- model_parts = model_id.lower().split('/')
186
- if len(model_parts) > 1:
187
- model_name = model_parts[-1]
188
- else:
189
- model_name = model_id.lower()
190
-
191
- # Remove version numbers and common prefixes
192
- clean_name = model_name.replace('-3b', '').replace('-8b', '').replace('-70b', '')
193
- clean_name = clean_name.replace('llama', '').replace('hermes', '').strip('-')
194
-
195
- # Search for similar models
196
- try:
197
- # Search for models with similar names
198
- similar_models = self.hf_api.list_models(
199
- search=model_name,
200
- sort="downloads",
201
- direction=-1,
202
- limit=5
203
- )
204
-
205
- # Filter for text generation models
206
- fallbacks = []
207
- for model in similar_models:
208
- if (hasattr(model, 'pipeline_tag') and
209
- model.pipeline_tag in ['text-generation', 'conversational', 'translation']):
210
- fallbacks.append({
211
- "id": model.modelId,
212
- "name": getattr(model, 'author', '') + '/' + model.modelId.split('/')[-1],
213
- "downloads": getattr(model, 'downloads', 0)
214
- })
215
-
216
- return fallbacks[:5] # Return top 5 fallbacks
217
- except:
218
- # If search fails, return some common models including translation models
219
- return [
220
- {"id": "meta-llama/Llama-3.2-3B-Instruct", "name": "Llama 3.2 3B", "downloads": 0},
221
- {"id": "microsoft/Phi-3-mini-4k-instruct", "name": "Phi-3 Mini", "downloads": 0},
222
- {"id": "google/gemma-2-2b-it", "name": "Gemma 2 2B", "downloads": 0},
223
- {"id": "Helsinki-NLP/opus-mt-en-es", "name": "English-Spanish Translator", "downloads": 0},
224
- {"id": "Helsinki-NLP/opus-mt-en-fr", "name": "English-French Translator", "downloads": 0}
225
- ]
226
-
227
- def get_model_task_support(self, model: str) -> Dict[str, Any]:
228
- """
229
- Get information about what tasks a model supports.
230
-
231
- Args:
232
- model: Model ID
233
-
234
- Returns:
235
- Model task support information
236
- """
237
- # Known conversational-only models
238
- conversational_only_models = [
239
- "meta-llama/Llama-3.2-3B-Instruct",
240
- "meta-llama/Llama-3.1-8B-Instruct",
241
- "meta-llama/Llama-3.1-70B-Instruct"
242
- ]
243
-
244
- if model in conversational_only_models:
245
- return {
246
- "supports_text_generation": False,
247
- "supports_conversational": True,
248
- "recommended_method": "chat_completion"
249
- }
250
- else:
251
- return {
252
- "supports_text_generation": True,
253
- "supports_conversational": True,
254
- "recommended_method": "text_generation_or_chat_completion"
255
- }
256
-
257
- def text_generation(
258
- self,
259
- model: str,
260
- prompt: str,
261
- max_new_tokens: int = 250,
262
- temperature: float = 0.7,
263
- top_p: float = 0.95,
264
- do_sample: bool = True
265
- ) -> Dict[str, Any]:
266
- """
267
- Send a text generation request to HuggingFace API.
268
-
269
- Args:
270
- model: Model ID
271
- prompt: Text prompt to complete
272
- max_new_tokens: Maximum new tokens to generate
273
- temperature: Sampling temperature
274
- top_p: Nucleus sampling parameter
275
- do_sample: Whether to use sampling
276
-
277
- Returns:
278
- API response as dict
279
- """
280
- # Validate model before use
281
- validation_result = self.validate_model(model)
282
- if not validation_result["valid"]:
283
- # Try fallback models
284
- fallback_models = validation_result.get("fallback_models", [])
285
- if fallback_models:
286
- # Use the first fallback model
287
- fallback_model = fallback_models[0]["id"]
288
- print(f"Warning: Model {model} not supported. Using fallback model {fallback_model}")
289
- model = fallback_model
290
- else:
291
- raise ValueError(f"Model {model} is not supported and no fallback models available. "
292
- f"Error: {validation_result.get('error', 'Unknown error')}")
293
-
294
- try:
295
- response = self.client.text_generation(
296
- model=model,
297
- prompt=prompt,
298
- max_new_tokens=max_new_tokens,
299
- temperature=temperature,
300
- top_p=top_p,
301
- do_sample=do_sample
302
- )
303
- return {"generated_text": response}
304
- except Exception as e:
305
- # Check if the error is related to unsupported task
306
- error_str = str(e).lower()
307
- if "not supported for task text-generation" in error_str:
308
- raise ValueError(f"Model {model} is not supported for text-generation task. "
309
- f"This model only supports conversational tasks. "
310
- f"Please use chat_completion method instead.")
311
- elif "model_not_supported" in error_str or "not supported by any provider" in error_str:
312
- # Try fallback models
313
- fallback_models = self._find_fallback_models(model)
314
- if fallback_models:
315
- # Try each fallback model
316
- for fallback in fallback_models[:3]:
317
- try:
318
- print(f"Trying fallback model: {fallback['id']}")
319
- response = self.client.text_generation(
320
- model=fallback['id'],
321
- prompt=prompt,
322
- max_new_tokens=max_new_tokens,
323
- temperature=temperature,
324
- top_p=top_p,
325
- do_sample=do_sample
326
- )
327
- return {"generated_text": response}
328
- except:
329
- continue
330
-
331
- raise ValueError(f"Model {model} is not supported and all fallback models failed. "
332
- f"Try one of these: {', '.join([m['id'] for m in fallback_models[:3]])}")
333
- else:
334
- raise ValueError(f"Model {model} is not supported and no fallback models available.")
335
- else:
336
- raise e
337
-
338
- def get_model_info(self, model: str) -> Dict[str, Any]:
339
- """
340
- Get model information from HuggingFace Hub.
341
-
342
- Args:
343
- model: Model ID
344
-
345
- Returns:
346
- Model metadata dict
347
- """
348
- url = f"https://huggingface.co/api/models/{model}"
349
- response = requests.get(url, headers=self.headers)
350
- response.raise_for_status()
351
- return response.json()
352
-
353
- def search_models(
354
- self,
355
- query: str,
356
- task: str = "text-generation",
357
- limit: int = 10
358
- ) -> List[Dict[str, Any]]:
359
- """
360
- Search for models on HuggingFace Hub.
361
-
362
- Args:
363
- query: Search query
364
- task: Filter by task (e.g., "text-generation", "text-classification")
365
- limit: Maximum number of results
366
-
367
- Returns:
368
- List of model metadata dicts
369
- """
370
- url = "https://huggingface.co/api/models"
371
- params = {
372
- "search": query,
373
- "pipeline_tag": task,
374
- "limit": limit,
375
- "sort": "downloads",
376
- "direction": -1
377
- }
378
-
379
- response = requests.get(url, headers=self.headers, params=params)
380
- response.raise_for_status()
381
- return response.json()
382
-
383
- def image_generation(
384
- self,
385
- model: str,
386
- prompt: str,
387
- negative_prompt: Optional[str] = None,
388
- num_inference_steps: int = 50
389
- ) -> bytes:
390
- """
391
- Generate an image using a diffusion model.
392
-
393
- Args:
394
- model: Model ID (e.g., "stabilityai/stable-diffusion-xl-base-1.0")
395
- prompt: Text prompt for image generation
396
- negative_prompt: Negative prompt (what to avoid)
397
- num_inference_steps: Number of denoising steps
398
-
399
- Returns:
400
- Image bytes
401
- """
402
- url = f"{API_BASE}/models/{model}"
403
-
404
- payload = {
405
- "inputs": prompt,
406
- "parameters": {
407
- "num_inference_steps": num_inference_steps
408
- }
409
- }
410
-
411
- if negative_prompt:
412
- payload["parameters"]["negative_prompt"] = negative_prompt
413
-
414
- response = requests.post(url, headers=self.headers, json=payload)
415
- response.raise_for_status()
416
- return response.content
417
-
418
- def embedding(
419
- self,
420
- model: str,
421
- texts: List[str]
422
- ) -> List[List[float]]:
423
- """
424
- Get embeddings for texts.
425
-
426
- Args:
427
- model: Model ID (e.g., "sentence-transformers/all-MiniLM-L6-v2")
428
- texts: List of texts to embed
429
-
430
- Returns:
431
- List of embedding vectors
432
- """
433
- url = f"{API_BASE}/models/{model}"
434
-
435
- payload = {
436
- "inputs": texts
437
- }
438
-
439
- response = requests.post(url, headers=self.headers, json=payload)
440
- response.raise_for_status()
441
- return response.json()
442
-
443
- def summarization(
444
- self,
445
- model: str,
446
- text: str,
447
- max_length: int = 150,
448
- min_length: int = 30
449
- ) -> Dict[str, Any]:
450
- """
451
- Summarize text using a summarization model.
452
-
453
- Args:
454
- model: Model ID (e.g., "facebook/bart-large-cnn")
455
- text: Text to summarize
456
- max_length: Maximum summary length
457
- min_length: Minimum summary length
458
-
459
- Returns:
460
- API response with summary
461
- """
462
- url = f"{API_BASE}/models/{model}"
463
-
464
- payload = {
465
- "inputs": text,
466
- "parameters": {
467
- "max_length": max_length,
468
- "min_length": min_length
469
- }
470
- }
471
-
472
- response = requests.post(url, headers=self.headers, json=payload)
473
- response.raise_for_status()
474
- return response.json()
475
-
476
- def translation(
477
- self,
478
- model: str,
479
- text: str
480
- ) -> Dict[str, Any]:
481
- url = f"{API_BASE}/models/{model}"
482
-
483
- payload = {
484
- "inputs": text
485
- }
486
-
487
- response = requests.post(url, headers=self.headers, json=payload)
488
- response.raise_for_status()
489
- return response.json()
490
-
491
- def question_answering(
492
- self,
493
- model: str,
494
- question: str,
495
- context: str
496
- ) -> Dict[str, Any]:
497
- """
498
- Answer a question based on context.
499
-
500
- Args:
501
- model: Model ID (e.g., "deepset/roberta-base-squad2")
502
- question: The question to answer
503
- context: Context containing the answer
504
-
505
- Returns:
506
- API response with answer
507
- """
508
- url = f"{API_BASE}/models/{model}"
509
-
510
- payload = {
511
- "inputs": {
512
- "question": question,
513
- "context": context
514
- }
515
- }
516
-
517
- response = requests.post(url, headers=self.headers, json=payload)
518
- response.raise_for_status()
519
- return response.json()
520
-
521
-
522
-
 
1
+ """
2
+ Hugging Face API Client
3
+ Provides methods for interacting with HuggingFace Inference API
4
+ """
5
+ import os
6
+ import requests
7
+ from typing import Optional, List, Dict, Any
8
+ from huggingface_hub import InferenceClient, HfApi
9
+ from utils import load_settings
10
+
11
+ # Settings paths
12
+ SETTINGS_DIR = os.path.join(os.path.dirname(__file__), 'settings')
13
+ APP_SETTINGS_FILE = os.path.join(SETTINGS_DIR, 'app.json')
14
+
15
+ # Get HF token from settings
16
+ HF_TOKEN = load_settings(APP_SETTINGS_FILE).get('hf_token')
17
+ API_BASE = "https://api-inference.huggingface.co"
18
+
19
+
20
+ class HuggingFaceAPI:
21
+ def __init__(self, token: str = HF_TOKEN):
22
+ self.token = token
23
+ self.headers = {
24
+ "Authorization": f"Bearer {token}",
25
+ "Content-Type": "application/json"
26
+ }
27
+ self.client = InferenceClient(token=token)
28
+ self.hf_api = HfApi(token=token)
29
+
30
+ def model_info(self, model_id: str):
31
+ """Get model info using HfApi (compatible with hf.py)"""
32
+ return self.hf_api.model_info(model_id)
33
+
34
+ def list_models(self, **kwargs):
35
+ """List models using HfApi (compatible with hf.py)"""
36
+ return self.hf_api.list_models(**kwargs)
37
+
38
+ def chat_completion(
39
+ self,
40
+ model: str,
41
+ messages: List[Dict[str, str]],
42
+ max_tokens: int = 500,
43
+ temperature: float = 0.7,
44
+ stream: bool = False
45
+ ) -> Dict[str, Any]:
46
+ """
47
+ Send a chat completion request to HuggingFace API using huggingface_hub.
48
+
49
+ Args:
50
+ model: Model ID (e.g., "meta-llama/Llama-3.2-3B-Instruct")
51
+ messages: List of message dicts with 'role' and 'content'
52
+ max_tokens: Maximum tokens to generate
53
+ temperature: Sampling temperature (0.0 - 1.0)
54
+ stream: Whether to stream the response
55
+
56
+ Returns:
57
+ API response as dict
58
+ """
59
+ # Validate model before use
60
+ validation_result = self.validate_model(model)
61
+ if not validation_result["valid"]:
62
+ # Try fallback models
63
+ fallback_models = validation_result.get("fallback_models", [])
64
+ if fallback_models:
65
+ # Use the first fallback model
66
+ fallback_model = fallback_models[0]["id"]
67
+ print(f"Warning: Model {model} not supported. Using fallback model {fallback_model}")
68
+ model = fallback_model
69
+ else:
70
+ raise ValueError(f"Model {model} is not supported and no fallback models available. "
71
+ f"Error: {validation_result.get('error', 'Unknown error')}")
72
+
73
+ try:
74
+ response = self.client.chat_completion(
75
+ model=model,
76
+ messages=messages,
77
+ max_tokens=max_tokens,
78
+ temperature=temperature,
79
+ stream=stream
80
+ )
81
+ except Exception as e:
82
+ error_str = str(e).lower()
83
+ if "model_not_supported" in error_str or "not supported by any provider" in error_str:
84
+ # Try fallback models
85
+ fallback_models = self._find_fallback_models(model)
86
+ if fallback_models:
87
+ # Try each fallback model
88
+ for fallback in fallback_models[:3]:
89
+ try:
90
+ print(f"Trying fallback model: {fallback['id']}")
91
+ response = self.client.chat_completion(
92
+ model=fallback['id'],
93
+ messages=messages,
94
+ max_tokens=max_tokens,
95
+ temperature=temperature,
96
+ stream=stream
97
+ )
98
+ return response
99
+ except:
100
+ continue
101
+
102
+ raise ValueError(f"Model {model} is not supported and all fallback models failed. "
103
+ f"Try one of these: {', '.join([m['id'] for m in fallback_models[:3]])}")
104
+ else:
105
+ raise ValueError(f"Model {model} is not supported and no fallback models available.")
106
+ else:
107
+ raise e
108
+
109
+ # Convert to dict format
110
+ return {
111
+ "choices": [{
112
+ "message": {
113
+ "role": "assistant",
114
+ "content": response.choices[0].message.content
115
+ },
116
+ "finish_reason": response.choices[0].finish_reason
117
+ }],
118
+ "model": model,
119
+ "usage": {
120
+ "prompt_tokens": getattr(response.usage, "prompt_tokens", 0),
121
+ "completion_tokens": getattr(response.usage, "completion_tokens", 0),
122
+ "total_tokens": getattr(response.usage, "total_tokens", 0)
123
+ } if response.usage else None
124
+ }
125
+
126
+ def validate_model(self, model_id: str) -> Dict[str, Any]:
127
+ """
128
+ Validate if a model is supported and available.
129
+
130
+ Args:
131
+ model_id: Model ID to validate
132
+
133
+ Returns:
134
+ Validation result with status and fallback suggestions
135
+ """
136
+ try:
137
+ # Try to get model info
138
+ model_info = self.hf_api.model_info(model_id)
139
+
140
+ # Check if model has inference API enabled
141
+ if hasattr(model_info, 'inference') and not model_info.inference:
142
+ # Try to find alternative models
143
+ fallback_models = self._find_fallback_models(model_id)
144
+ return {
145
+ "valid": False,
146
+ "error": f"Model {model_id} does not have inference API enabled",
147
+ "fallback_models": fallback_models,
148
+ "model_info": model_info
149
+ }
150
+
151
+ return {
152
+ "valid": True,
153
+ "model_info": model_info
154
+ }
155
+ except Exception as e:
156
+ # Check if it's an auth error
157
+ error_str = str(e).lower()
158
+ if "401" in error_str or "unauthorized" in error_str or "invalid username or password" in error_str:
159
+ # Auth error - model might be valid but we can't check
160
+ return {
161
+ "valid": True, # Assume valid since we can't verify due to auth
162
+ "warning": "Unable to verify model due to authentication. Assuming model is valid.",
163
+ "auth_error": True
164
+ }
165
+
166
+ # Model not found or not supported
167
+ fallback_models = self._find_fallback_models(model_id)
168
+ return {
169
+ "valid": False,
170
+ "error": str(e),
171
+ "fallback_models": fallback_models
172
+ }
173
+
174
+ def _find_fallback_models(self, model_id: str) -> List[Dict[str, str]]:
175
+ """
176
+ Find fallback models similar to the requested model.
177
+
178
+ Args:
179
+ model_id: Original model ID
180
+
181
+ Returns:
182
+ List of fallback model suggestions
183
+ """
184
+ # Extract model name parts
185
+ model_parts = model_id.lower().split('/')
186
+ if len(model_parts) > 1:
187
+ model_name = model_parts[-1]
188
+ else:
189
+ model_name = model_id.lower()
190
+
191
+ # Remove version numbers and common prefixes
192
+ clean_name = model_name.replace('-3b', '').replace('-8b', '').replace('-70b', '')
193
+ clean_name = clean_name.replace('llama', '').replace('hermes', '').strip('-')
194
+
195
+ # Search for similar models
196
+ try:
197
+ # Search for models with similar names
198
+ similar_models = self.hf_api.list_models(
199
+ search=model_name,
200
+ sort="downloads",
201
+ direction=-1,
202
+ limit=5
203
+ )
204
+
205
+ # Filter for text generation models
206
+ fallbacks = []
207
+ for model in similar_models:
208
+ if (hasattr(model, 'pipeline_tag') and
209
+ model.pipeline_tag in ['text-generation', 'conversational', 'translation']):
210
+ fallbacks.append({
211
+ "id": model.modelId,
212
+ "name": getattr(model, 'author', '') + '/' + model.modelId.split('/')[-1],
213
+ "downloads": getattr(model, 'downloads', 0)
214
+ })
215
+
216
+ return fallbacks[:5] # Return top 5 fallbacks
217
+ except:
218
+ # If search fails, return some common models including translation models
219
+ return [
220
+ {"id": "meta-llama/Llama-3.2-3B-Instruct", "name": "Llama 3.2 3B", "downloads": 0},
221
+ {"id": "microsoft/Phi-3-mini-4k-instruct", "name": "Phi-3 Mini", "downloads": 0},
222
+ {"id": "google/gemma-2-2b-it", "name": "Gemma 2 2B", "downloads": 0},
223
+ {"id": "Helsinki-NLP/opus-mt-en-es", "name": "English-Spanish Translator", "downloads": 0},
224
+ {"id": "Helsinki-NLP/opus-mt-en-fr", "name": "English-French Translator", "downloads": 0}
225
+ ]
226
+
227
+ def get_model_task_support(self, model: str) -> Dict[str, Any]:
228
+ """
229
+ Get information about what tasks a model supports.
230
+
231
+ Args:
232
+ model: Model ID
233
+
234
+ Returns:
235
+ Model task support information
236
+ """
237
+ # Known conversational-only models
238
+ conversational_only_models = [
239
+ "meta-llama/Llama-3.2-3B-Instruct",
240
+ "meta-llama/Llama-3.1-8B-Instruct",
241
+ "meta-llama/Llama-3.1-70B-Instruct"
242
+ ]
243
+
244
+ if model in conversational_only_models:
245
+ return {
246
+ "supports_text_generation": False,
247
+ "supports_conversational": True,
248
+ "recommended_method": "chat_completion"
249
+ }
250
+ else:
251
+ return {
252
+ "supports_text_generation": True,
253
+ "supports_conversational": True,
254
+ "recommended_method": "text_generation_or_chat_completion"
255
+ }
256
+
257
+ def text_generation(
258
+ self,
259
+ model: str,
260
+ prompt: str,
261
+ max_new_tokens: int = 250,
262
+ temperature: float = 0.7,
263
+ top_p: float = 0.95,
264
+ do_sample: bool = True
265
+ ) -> Dict[str, Any]:
266
+ """
267
+ Send a text generation request to HuggingFace API.
268
+
269
+ Args:
270
+ model: Model ID
271
+ prompt: Text prompt to complete
272
+ max_new_tokens: Maximum new tokens to generate
273
+ temperature: Sampling temperature
274
+ top_p: Nucleus sampling parameter
275
+ do_sample: Whether to use sampling
276
+
277
+ Returns:
278
+ API response as dict
279
+ """
280
+ # Validate model before use
281
+ validation_result = self.validate_model(model)
282
+ if not validation_result["valid"]:
283
+ # Try fallback models
284
+ fallback_models = validation_result.get("fallback_models", [])
285
+ if fallback_models:
286
+ # Use the first fallback model
287
+ fallback_model = fallback_models[0]["id"]
288
+ print(f"Warning: Model {model} not supported. Using fallback model {fallback_model}")
289
+ model = fallback_model
290
+ else:
291
+ raise ValueError(f"Model {model} is not supported and no fallback models available. "
292
+ f"Error: {validation_result.get('error', 'Unknown error')}")
293
+
294
+ try:
295
+ response = self.client.text_generation(
296
+ model=model,
297
+ prompt=prompt,
298
+ max_new_tokens=max_new_tokens,
299
+ temperature=temperature,
300
+ top_p=top_p,
301
+ do_sample=do_sample
302
+ )
303
+ return {"generated_text": response}
304
+ except Exception as e:
305
+ # Check if the error is related to unsupported task
306
+ error_str = str(e).lower()
307
+ if "not supported for task text-generation" in error_str:
308
+ raise ValueError(f"Model {model} is not supported for text-generation task. "
309
+ f"This model only supports conversational tasks. "
310
+ f"Please use chat_completion method instead.")
311
+ elif "model_not_supported" in error_str or "not supported by any provider" in error_str:
312
+ # Try fallback models
313
+ fallback_models = self._find_fallback_models(model)
314
+ if fallback_models:
315
+ # Try each fallback model
316
+ for fallback in fallback_models[:3]:
317
+ try:
318
+ print(f"Trying fallback model: {fallback['id']}")
319
+ response = self.client.text_generation(
320
+ model=fallback['id'],
321
+ prompt=prompt,
322
+ max_new_tokens=max_new_tokens,
323
+ temperature=temperature,
324
+ top_p=top_p,
325
+ do_sample=do_sample
326
+ )
327
+ return {"generated_text": response}
328
+ except:
329
+ continue
330
+
331
+ raise ValueError(f"Model {model} is not supported and all fallback models failed. "
332
+ f"Try one of these: {', '.join([m['id'] for m in fallback_models[:3]])}")
333
+ else:
334
+ raise ValueError(f"Model {model} is not supported and no fallback models available.")
335
+ else:
336
+ raise e
337
+
338
+ def get_model_info(self, model: str) -> Dict[str, Any]:
339
+ """
340
+ Get model information from HuggingFace Hub.
341
+
342
+ Args:
343
+ model: Model ID
344
+
345
+ Returns:
346
+ Model metadata dict
347
+ """
348
+ url = f"https://huggingface.co/api/models/{model}"
349
+ response = requests.get(url, headers=self.headers)
350
+ response.raise_for_status()
351
+ return response.json()
352
+
353
+ def search_models(
354
+ self,
355
+ query: str,
356
+ task: str = "text-generation",
357
+ limit: int = 10
358
+ ) -> List[Dict[str, Any]]:
359
+ """
360
+ Search for models on HuggingFace Hub.
361
+
362
+ Args:
363
+ query: Search query
364
+ task: Filter by task (e.g., "text-generation", "text-classification")
365
+ limit: Maximum number of results
366
+
367
+ Returns:
368
+ List of model metadata dicts
369
+ """
370
+ url = "https://huggingface.co/api/models"
371
+ params = {
372
+ "search": query,
373
+ "pipeline_tag": task,
374
+ "limit": limit,
375
+ "sort": "downloads",
376
+ "direction": -1
377
+ }
378
+
379
+ response = requests.get(url, headers=self.headers, params=params)
380
+ response.raise_for_status()
381
+ return response.json()
382
+
383
+ def image_generation(
384
+ self,
385
+ model: str,
386
+ prompt: str,
387
+ negative_prompt: Optional[str] = None,
388
+ num_inference_steps: int = 50
389
+ ) -> bytes:
390
+ """
391
+ Generate an image using a diffusion model.
392
+
393
+ Args:
394
+ model: Model ID (e.g., "stabilityai/stable-diffusion-xl-base-1.0")
395
+ prompt: Text prompt for image generation
396
+ negative_prompt: Negative prompt (what to avoid)
397
+ num_inference_steps: Number of denoising steps
398
+
399
+ Returns:
400
+ Image bytes
401
+ """
402
+ url = f"{API_BASE}/models/{model}"
403
+
404
+ payload = {
405
+ "inputs": prompt,
406
+ "parameters": {
407
+ "num_inference_steps": num_inference_steps
408
+ }
409
+ }
410
+
411
+ if negative_prompt:
412
+ payload["parameters"]["negative_prompt"] = negative_prompt
413
+
414
+ response = requests.post(url, headers=self.headers, json=payload)
415
+ response.raise_for_status()
416
+ return response.content
417
+
418
+ def embedding(
419
+ self,
420
+ model: str,
421
+ texts: List[str]
422
+ ) -> List[List[float]]:
423
+ """
424
+ Get embeddings for texts.
425
+
426
+ Args:
427
+ model: Model ID (e.g., "sentence-transformers/all-MiniLM-L6-v2")
428
+ texts: List of texts to embed
429
+
430
+ Returns:
431
+ List of embedding vectors
432
+ """
433
+ url = f"{API_BASE}/models/{model}"
434
+
435
+ payload = {
436
+ "inputs": texts
437
+ }
438
+
439
+ response = requests.post(url, headers=self.headers, json=payload)
440
+ response.raise_for_status()
441
+ return response.json()
442
+
443
+ def summarization(
444
+ self,
445
+ model: str,
446
+ text: str,
447
+ max_length: int = 150,
448
+ min_length: int = 30
449
+ ) -> Dict[str, Any]:
450
+ """
451
+ Summarize text using a summarization model.
452
+
453
+ Args:
454
+ model: Model ID (e.g., "facebook/bart-large-cnn")
455
+ text: Text to summarize
456
+ max_length: Maximum summary length
457
+ min_length: Minimum summary length
458
+
459
+ Returns:
460
+ API response with summary
461
+ """
462
+ url = f"{API_BASE}/models/{model}"
463
+
464
+ payload = {
465
+ "inputs": text,
466
+ "parameters": {
467
+ "max_length": max_length,
468
+ "min_length": min_length
469
+ }
470
+ }
471
+
472
+ response = requests.post(url, headers=self.headers, json=payload)
473
+ response.raise_for_status()
474
+ return response.json()
475
+
476
+ def translation(
477
+ self,
478
+ model: str,
479
+ text: str
480
+ ) -> Dict[str, Any]:
481
+ url = f"{API_BASE}/models/{model}"
482
+
483
+ payload = {
484
+ "inputs": text
485
+ }
486
+
487
+ response = requests.post(url, headers=self.headers, json=payload)
488
+ response.raise_for_status()
489
+ return response.json()
490
+
491
+ def question_answering(
492
+ self,
493
+ model: str,
494
+ question: str,
495
+ context: str
496
+ ) -> Dict[str, Any]:
497
+ """
498
+ Answer a question based on context.
499
+
500
+ Args:
501
+ model: Model ID (e.g., "deepset/roberta-base-squad2")
502
+ question: The question to answer
503
+ context: Context containing the answer
504
+
505
+ Returns:
506
+ API response with answer
507
+ """
508
+ url = f"{API_BASE}/models/{model}"
509
+
510
+ payload = {
511
+ "inputs": {
512
+ "question": question,
513
+ "context": context
514
+ }
515
+ }
516
+
517
+ response = requests.post(url, headers=self.headers, json=payload)
518
+ response.raise_for_status()
519
+ return response.json()
520
+
521
+
522
+
index.html ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt CHANGED
@@ -1,13 +1,11 @@
1
- Pillow>=10.0.0
2
- torch
3
- torchvision
4
- spaces
5
- transformers>=4.36.0
6
-
7
- bitsandbytes==0.49.1
8
- sentencepiece==0.2.1
9
- protobuf==6.33.5
10
-
11
- gradio>=4.0.0
12
- requests==2.32.5
13
- huggingface-hub
 
1
+
2
+ transformers>=4.36.0
3
+ torch>=2.0.0
4
+ bitsandbytes==0.49.1
5
+ sentencepiece==0.2.1
6
+ protobuf==6.33.5
7
+ Pillow>=10.0.0
8
+
9
+ gradio>=4.0.0
10
+ requests==2.32.5
11
+ huggingface-hub==1.4.1
 
 
test_translation.py ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test script for translation functionality with Google TranslateGemma model
3
+ """
4
+ from hf_api import HuggingFaceAPI
5
+ from utils import load_settings
6
+ import os
7
+ import sys
8
+
9
+ # Import Google Translate Gemma if available
10
+ try:
11
+ from google_translate import GoogleTranslateGemma
12
+ GOOGLE_TRANSLATE_AVAILABLE = True
13
+ except ImportError as e:
14
+ print(f"Warning: Google Translate Gemma not available: {str(e)}")
15
+ GOOGLE_TRANSLATE_AVAILABLE = False
16
+
17
+ # Test translation with Google TranslateGemma
18
+ def test_translategemma(text, source_lang, target_lang):
19
+ """Test translation using Google Translate Gemma model"""
20
+ if not GOOGLE_TRANSLATE_AVAILABLE:
21
+ print("❌ Google Translate Gemma is not available")
22
+ print(" Falling back to chat completion translation")
23
+ return test_chat_completion_translation(text, source_lang, target_lang)
24
+
25
+ try:
26
+ print(f"🧪 Testing Google Translate Gemma")
27
+ print("-" * 50)
28
+
29
+ # Initialize the translator
30
+ translator = GoogleTranslateGemma()
31
+
32
+ print(f"\n📝 Translating from {source_lang} to {target_lang}")
33
+ print(f"Original: {text}")
34
+
35
+ # Perform translation
36
+ translation = translator.translate_text(
37
+ text=text,
38
+ source_lang=source_lang,
39
+ target_lang=target_lang
40
+ )
41
+
42
+ print(f"✅ Translation: {translation}")
43
+
44
+ except Exception as e:
45
+ print(f"❌ Google Translate Gemma failed: {str(e)}")
46
+ print(" Falling back to chat completion translation")
47
+ return test_chat_completion_translation(text, source_lang, target_lang)
48
+
49
+ print("\n" + "=" * 50)
50
+ print("🎉 Google Translate Gemma testing complete!")
51
+
52
+ def test_chat_completion_translation(text, source_lang, target_lang):
53
+ """Test translation using chat completion fallback"""
54
+ # Load API token
55
+ settings_dir = os.path.join(os.path.dirname(__file__), 'settings')
56
+ models_settings_file = os.path.join(settings_dir, 'models.json')
57
+ settings = load_settings(models_settings_file)
58
+ token = settings.get('huggingfaceToken')
59
+
60
+ if not token:
61
+ print("❌ No HuggingFace token found. Please set your token first.")
62
+ print(" You can set it in the app's Settings tab")
63
+ return
64
+
65
+ # Initialize API
66
+ api = HuggingFaceAPI(token=token)
67
+
68
+ # Test models in order of preference
69
+ models_to_test = [
70
+ "google/translategemma-12b-it",
71
+ "meta-llama/Llama-3.2-3B-Instruct",
72
+ "microsoft/Phi-3-mini-4k-instruct",
73
+ "google/gemma-2-2b-it"
74
+ ]
75
+
76
+ print(f"🧪 Testing translation with chat completion")
77
+ print("-" * 50)
78
+
79
+ for model_id in models_to_test:
80
+ print(f"\n📝 Testing with model: {model_id}")
81
+ print(f"Original: {text}")
82
+
83
+ try:
84
+ # Use the same translation logic as in app.py
85
+ if "translategemma" in model_id.lower() and not GOOGLE_TRANSLATE_AVAILABLE:
86
+ print(" ⚠️ Google Translate Gemma not available, skipping...")
87
+ continue
88
+
89
+ # Dynamic system prompt based on target and source language
90
+ source_info = f" from {source_lang}" if source_lang != "Auto-detect" else ""
91
+ system_prompt = f"You are a professional translator specializing in translating{source_info} to {target_lang}. Translate the given text accurately while preserving the original meaning and tone. Only provide the translation without any additional explanations."
92
+ prompt = f"Translate the following text{source_info} to {target_lang}: {text}"
93
+
94
+ messages = [
95
+ {
96
+ "role": "system",
97
+ "content": system_prompt
98
+ },
99
+ {
100
+ "role": "user",
101
+ "content": prompt
102
+ }
103
+ ]
104
+
105
+ response = api.chat_completion(
106
+ model=model_id,
107
+ messages=messages,
108
+ max_tokens=1024,
109
+ temperature=0.3
110
+ )
111
+
112
+ translation = response["choices"][0]["message"]["content"].strip()
113
+ print(f"✅ Translation: {translation}")
114
+ print(f" ✅ Success with {model_id}!")
115
+ return translation # Return first successful translation
116
+
117
+ except Exception as e:
118
+ print(f" ❌ Error with {model_id}: {str(e)}")
119
+ continue
120
+
121
+ print("\n❌ All models failed. Please check your token and model availability.")
122
+ return None
123
+
124
+ def test_multiple_translations():
125
+ """Test multiple translation scenarios"""
126
+ print("\n🌍 Testing Multiple Translation Scenarios")
127
+ print("=" * 60)
128
+
129
+ test_cases = [
130
+ {
131
+ "text": "Hello, how are you today?",
132
+ "source": "English",
133
+ "target": "Spanish",
134
+ "description": "English to Spanish"
135
+ },
136
+ {
137
+ "text": "V nejhorším případě i k prasknutí čočky.",
138
+ "source": "Czech",
139
+ "target": "German",
140
+ "description": "Czech to German"
141
+ },
142
+ {
143
+ "text": "Bonjour, comment allez-vous?",
144
+ "source": "French",
145
+ "target": "English",
146
+ "description": "French to English"
147
+ },
148
+ {
149
+ "text": "这是一个测试。",
150
+ "source": "Chinese (Simplified)",
151
+ "target": "English",
152
+ "description": "Chinese to English"
153
+ },
154
+ {
155
+ "text": "¡Hola! ¿Cómo estás?",
156
+ "source": "Spanish",
157
+ "target": "Japanese",
158
+ "description": "Spanish to Japanese"
159
+ }
160
+ ]
161
+
162
+ results = []
163
+
164
+ for i, case in enumerate(test_cases, 1):
165
+ print(f"\n📝 Test {i}: {case['description']}")
166
+ print(f" Source ({case['source']}): {case['text']}")
167
+
168
+ # Map language names to codes
169
+ lang_code_map = {
170
+ "English": "en",
171
+ "Spanish": "es",
172
+ "French": "fr",
173
+ "German": "de-DE",
174
+ "Chinese (Simplified)": "zh-CN",
175
+ "Chinese (Traditional)": "zh-TW",
176
+ "Japanese": "ja",
177
+ "Korean": "ko",
178
+ "Italian": "it",
179
+ "Portuguese": "pt",
180
+ "Russian": "ru",
181
+ "Arabic": "ar",
182
+ "Hindi": "hi",
183
+ "Dutch": "nl",
184
+ "Turkish": "tr",
185
+ "Polish": "pl",
186
+ "Vietnamese": "vi",
187
+ "Thai": "th",
188
+ "Indonesian": "id",
189
+ "Greek": "el",
190
+ "Hebrew": "he",
191
+ "Czech": "cs",
192
+ "Swedish": "sv",
193
+ "Danish": "da",
194
+ "Norwegian": "no",
195
+ "Finnish": "fi"
196
+ }
197
+
198
+ source_code = lang_code_map.get(case['source'], 'en')
199
+ target_code = lang_code_map.get(case['target'], 'en')
200
+
201
+ translation = test_translategemma(
202
+ text=case['text'],
203
+ source_lang=source_code,
204
+ target_lang=target_code
205
+ )
206
+
207
+ if translation:
208
+ print(f" Target ({case['target']}): {translation}")
209
+ results.append({
210
+ 'case': case['description'],
211
+ 'original': case['text'],
212
+ 'translation': translation,
213
+ 'success': True
214
+ })
215
+ else:
216
+ results.append({
217
+ 'case': case['description'],
218
+ 'original': case['text'],
219
+ 'translation': None,
220
+ 'success': False
221
+ })
222
+
223
+ # Summary
224
+ print("\n" + "=" * 60)
225
+ print("📊 Test Summary")
226
+ print("-" * 60)
227
+
228
+ successful = sum(1 for r in results if r['success'])
229
+ total = len(results)
230
+
231
+ print(f"Total tests: {total}")
232
+ print(f"Successful: {successful}")
233
+ print(f"Failed: {total - successful}")
234
+ print(f"Success rate: {successful/total*100:.1f}%")
235
+
236
+ if successful < total:
237
+ print("\n❌ Some tests failed. Check your HuggingFace token and model availability.")
238
+ else:
239
+ print("\n✅ All tests passed successfully!")
240
+
241
+ return results
242
+
243
+ if __name__ == "__main__":
244
+ import sys
245
+
246
+ print("🌐 Translation Test Suite")
247
+ print("=" * 60)
248
+ print()
249
+
250
+ # Check if command line arguments were provided
251
+ if len(sys.argv) > 1:
252
+ # Run single test with provided arguments
253
+ if len(sys.argv) >= 4:
254
+ text = sys.argv[1]
255
+ source_lang = sys.argv[2]
256
+ target_lang = sys.argv[3]
257
+ print(f"Running single test:")
258
+ print(f" Text: {text}")
259
+ print(f" Source: {source_lang}")
260
+ print(f" Target: {target_lang}")
261
+ print()
262
+ test_translategemma(text, source_lang, target_lang)
263
+ else:
264
+ print("Usage: python test_translation.py <text> <source_lang> <target_lang>")
265
+ print("Example: python test_translation.py \"Hello world\" en es")
266
+ else:
267
+ # Run comprehensive test suite
268
+ print("Running comprehensive translation tests...")
269
+ print()
270
+
271
+ # First, test a simple case
272
+ print("\n" + "=" * 60)
273
+ print("🧪 Quick Test")
274
+ test_translategemma(
275
+ text="Hello, world!",
276
+ source_lang="en",
277
+ target_lang="es"
278
+ )
279
+
280
+ # Then run multiple tests
281
+ test_multiple_translations()
282
+
283
+ print("\n" + "=" * 60)
284
+ print("🎉 All tests completed!")
285
+ print()
286
+ print("To test a specific translation:")
287
+ print(" python test_translation.py \"Your text here\" source_lang target_lang")
288
+ print()
289
+ print("To test in the app:")
290
+ print(" 1. Run: python app.py")
291
+ print(" 2. Go to Translation tab")
292
+ print(" 3. Set your HuggingFace token in Settings")
293
+ print(" 4. Try translating text")
utils.py CHANGED
@@ -1,23 +1,23 @@
1
- """
2
- Utility functions shared across the application
3
- """
4
- import os
5
- import json
6
-
7
-
8
- def load_settings(file_path):
9
- """Load settings from a JSON file"""
10
- try:
11
- with open(file_path, 'r', encoding='utf-8') as f:
12
- return json.load(f)
13
- except FileNotFoundError:
14
- return {}
15
- except json.JSONDecodeError:
16
- return {}
17
-
18
-
19
- def save_settings(file_path, data):
20
- """Save settings to a JSON file"""
21
- os.makedirs(os.path.dirname(file_path), exist_ok=True)
22
- with open(file_path, 'w', encoding='utf-8') as f:
23
  json.dump(data, f, indent=2, ensure_ascii=False)
 
1
+ """
2
+ Utility functions shared across the application
3
+ """
4
+ import os
5
+ import json
6
+
7
+
8
+ def load_settings(file_path):
9
+ """Load settings from a JSON file"""
10
+ try:
11
+ with open(file_path, 'r', encoding='utf-8') as f:
12
+ return json.load(f)
13
+ except FileNotFoundError:
14
+ return {}
15
+ except json.JSONDecodeError:
16
+ return {}
17
+
18
+
19
+ def save_settings(file_path, data):
20
+ """Save settings to a JSON file"""
21
+ os.makedirs(os.path.dirname(file_path), exist_ok=True)
22
+ with open(file_path, 'w', encoding='utf-8') as f:
23
  json.dump(data, f, indent=2, ensure_ascii=False)