chrome-lens-py 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Bropines
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.1
2
+ Name: chrome_lens_py
3
+ Version: 1.0.0
4
+ Summary: Library to use Google Lens OCR via API used in Chromium.
5
+ Home-page: https://github.com/bropines/chrome-lens-py
6
+ Author: Bropines
7
+ Author-email: bropines@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: requests
14
+ Requires-Dist: Pillow
15
+ Requires-Dist: filetype
16
+ Requires-Dist: lxml
17
+ Requires-Dist: json5
18
+ Requires-Dist: rich
19
+
20
+ # Chrome Lens API for Python
21
+
22
+ [English](/README.md) | [Русский](/README_RU.md)
23
+
24
+ This project provides a Python library and CLI tool for interacting with Google Lens's OCR functionality via the API used in Chromium. This allows you to process images and extract text data, including full text, coordinates, and stitched text using various methods.
25
+
26
+ ## Features
27
+
28
+ - **Full Text Extraction**: Extract the complete text from an image.
29
+ - **Coordinates Extraction**: Extract text along with its coordinates.
30
+ - **Stitched Text**: Reconstruct text from blocks using various methods:
31
+ - **Default Full Text**: Basic method for stitching text blocks.
32
+ - **Old Method**: Sequential text stitching.
33
+ - **New Method**: Enhanced text stitching.
34
+
35
+ PS. Lens has a problem with the way it displays full text, which is why methods have been added that stitch text from coordinates.
36
+
37
+ ## Installation
38
+
39
+ You can install the package using `pip`:
40
+
41
+ ### From PyPI (SOON)
42
+
43
+ ```bash
44
+ pip install chrome-lens-py
45
+ ```
46
+
47
+ ### From GIT
48
+
49
+ ```bash
50
+ pip install git+https://github.com/bropines/chrome-lens-py.git
51
+ ```
52
+
53
+ ### From source
54
+
55
+ Clone the repository and install the package:
56
+
57
+ ```bash
58
+ git clone https://github.com/bropines/chrome-lens-api-py.git
59
+ cd chrome-lens-api-py
60
+ pip install -r requirements.txt
61
+ pip install .
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ You can use the `lens_scan` command from the CLI to process images and extract text data, or you can use the Python API to integrate this functionality into your own projects.
67
+
68
+ ### CLI Usage
69
+
70
+ ```bash
71
+ lens_scan <image_file> <data_type>
72
+ ```
73
+
74
+ #### Data Types
75
+
76
+ - **all**: Get all data (full text, coordinates, and stitched text using both methods).
77
+ - **full_text_default**: Get only the default full text.
78
+ - **full_text_old_method**: Get stitched text using the old sequential method.
79
+ - **full_text_new_method**: Get stitched text using the new enhanced method.
80
+ - **coordinates**: Get text along with coordinates.
81
+
82
+ #### Example
83
+
84
+ To extract text using the new method for stitching:
85
+
86
+ ```bash
87
+ lens_scan path/to/image.jpg full_text_new_method
88
+ ```
89
+
90
+ To get all available data:
91
+
92
+ ```bash
93
+ lens_scan path/to/image.jpg all
94
+ ```
95
+
96
+ #### CLI Help
97
+
98
+ You can use the `-h` or `--help` option to display usage information:
99
+
100
+ ```bash
101
+ lens_scan -h
102
+ ```
103
+
104
+ ### Programmatic API Usage
105
+
106
+ In addition to the CLI tool, this project provides a Python API that can be used in your scripts.
107
+
108
+ #### Basic Programmatic Usage
109
+
110
+ First, import the `LensAPI` class:
111
+
112
+ ```python
113
+ from chrome_lens_py import LensAPI
114
+ ```
115
+
116
+ #### Example Programmatic Usage
117
+
118
+ 1. **Instantiate the API**:
119
+
120
+ ```python
121
+ api = LensAPI()
122
+ ```
123
+
124
+ 2. **Process an image**:
125
+
126
+ - **Get all data**:
127
+
128
+ ```python
129
+ result = api.get_all_data('path/to/image.jpg')
130
+ print(result)
131
+ ```
132
+
133
+ - **Get the default full text**:
134
+
135
+ ```python
136
+ result = api.get_full_text('path/to/image.jpg')
137
+ print(result)
138
+ ```
139
+
140
+ - **Get stitched text using the old method**:
141
+
142
+ ```python
143
+ result = api.get_stitched_text_sequential('path/to/image.jpg')
144
+ print(result)
145
+ ```
146
+
147
+ - **Get stitched text using the new method**:
148
+
149
+ ```python
150
+ result = api.get_stitched_text_smart('path/to/image.jpg')
151
+ print(result)
152
+ ```
153
+
154
+ - **Get text with coordinates**:
155
+
156
+ ```python
157
+ result = api.get_text_with_coordinates('path/to/image.jpg')
158
+ print(result)
159
+ ```
160
+
161
+ #### Programmatic API Methods
162
+
163
+ - **`get_all_data(image_path)`**: Returns all available data for the given image.
164
+ - **`get_full_text(image_path)`**: Returns only the full text from the image.
165
+ - **`get_text_with_coordinates(image_path)`**: Returns text along with its coordinates in JSON format.
166
+ - **`get_stitched_text_smart(image_path)`**: Returns stitched text using the enhanced method.
167
+ - **`get_stitched_text_sequential(image_path)`**: Returns stitched text using the basic sequential method.
168
+
169
+ ## Project Structure
170
+
171
+ ```
172
+ /chrome-lens-api-py
173
+ │
174
+ ├── /src
175
+ │ ├── /chrome_lens_py
176
+ │ │ ├── __init__.py # Package initialization
177
+ │ │ ├── constants.py # Constants used in the project
178
+ │ │ ├── utils.py # Utility functions
179
+ │ │ ├── image_processing.py # Image processing module
180
+ │ │ ├── request_handler.py # API request handling module
181
+ │ │ ├── text_processing.py # Text processing module
182
+ │ │ ├── lens_api.py # API interface for use in other scripts
183
+ │ │ └── main.py # CLI tool entry point
184
+ │
185
+ ├── setup.py # Installation setup
186
+ ├── README.md # Project description and usage guide
187
+ └── requirements.txt # Project dependencies
188
+ ```
189
+
190
+ ## Acknowledgments
191
+
192
+ Special thanks to [dimdenGD](https://github.com/dimdenGD) for the method of text extraction used in this project. You can check out their work on the [chrome-lens-ocr](https://github.com/dimdenGD/chrome-lens-ocr) repository. This project is inspired by their approach to leveraging Google Lens OCR functionality.
193
+
194
+ ## License
195
+
196
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
197
+
198
+ ## Disclaimer
199
+
200
+ This project is intended for educational purposes only. The use of Google Lens OCR functionality must comply with Google's Terms of Service. The author of this project is not responsible for any misuse of this software or for any consequences arising from its use. Users are solely responsible for ensuring that their use of this software complies with all applicable laws and regulations.
201
+
202
+ ## Author
203
+
204
+ ### Bropines - [Mail](mailto:bropines@gmail.com) / [Telegram](https://t.me/bropines)
@@ -0,0 +1,185 @@
1
+ # Chrome Lens API for Python
2
+
3
+ [English](/README.md) | [Русский](/README_RU.md)
4
+
5
+ This project provides a Python library and CLI tool for interacting with Google Lens's OCR functionality via the API used in Chromium. This allows you to process images and extract text data, including full text, coordinates, and stitched text using various methods.
6
+
7
+ ## Features
8
+
9
+ - **Full Text Extraction**: Extract the complete text from an image.
10
+ - **Coordinates Extraction**: Extract text along with its coordinates.
11
+ - **Stitched Text**: Reconstruct text from blocks using various methods:
12
+ - **Default Full Text**: Basic method for stitching text blocks.
13
+ - **Old Method**: Sequential text stitching.
14
+ - **New Method**: Enhanced text stitching.
15
+
16
+ PS. Lens has a problem with the way it displays full text, which is why methods have been added that stitch text from coordinates.
17
+
18
+ ## Installation
19
+
20
+ You can install the package using `pip`:
21
+
22
+ ### From PyPI (SOON)
23
+
24
+ ```bash
25
+ pip install chrome-lens-py
26
+ ```
27
+
28
+ ### From GIT
29
+
30
+ ```bash
31
+ pip install git+https://github.com/bropines/chrome-lens-py.git
32
+ ```
33
+
34
+ ### From source
35
+
36
+ Clone the repository and install the package:
37
+
38
+ ```bash
39
+ git clone https://github.com/bropines/chrome-lens-api-py.git
40
+ cd chrome-lens-api-py
41
+ pip install -r requirements.txt
42
+ pip install .
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ You can use the `lens_scan` command from the CLI to process images and extract text data, or you can use the Python API to integrate this functionality into your own projects.
48
+
49
+ ### CLI Usage
50
+
51
+ ```bash
52
+ lens_scan <image_file> <data_type>
53
+ ```
54
+
55
+ #### Data Types
56
+
57
+ - **all**: Get all data (full text, coordinates, and stitched text using both methods).
58
+ - **full_text_default**: Get only the default full text.
59
+ - **full_text_old_method**: Get stitched text using the old sequential method.
60
+ - **full_text_new_method**: Get stitched text using the new enhanced method.
61
+ - **coordinates**: Get text along with coordinates.
62
+
63
+ #### Example
64
+
65
+ To extract text using the new method for stitching:
66
+
67
+ ```bash
68
+ lens_scan path/to/image.jpg full_text_new_method
69
+ ```
70
+
71
+ To get all available data:
72
+
73
+ ```bash
74
+ lens_scan path/to/image.jpg all
75
+ ```
76
+
77
+ #### CLI Help
78
+
79
+ You can use the `-h` or `--help` option to display usage information:
80
+
81
+ ```bash
82
+ lens_scan -h
83
+ ```
84
+
85
+ ### Programmatic API Usage
86
+
87
+ In addition to the CLI tool, this project provides a Python API that can be used in your scripts.
88
+
89
+ #### Basic Programmatic Usage
90
+
91
+ First, import the `LensAPI` class:
92
+
93
+ ```python
94
+ from chrome_lens_py import LensAPI
95
+ ```
96
+
97
+ #### Example Programmatic Usage
98
+
99
+ 1. **Instantiate the API**:
100
+
101
+ ```python
102
+ api = LensAPI()
103
+ ```
104
+
105
+ 2. **Process an image**:
106
+
107
+ - **Get all data**:
108
+
109
+ ```python
110
+ result = api.get_all_data('path/to/image.jpg')
111
+ print(result)
112
+ ```
113
+
114
+ - **Get the default full text**:
115
+
116
+ ```python
117
+ result = api.get_full_text('path/to/image.jpg')
118
+ print(result)
119
+ ```
120
+
121
+ - **Get stitched text using the old method**:
122
+
123
+ ```python
124
+ result = api.get_stitched_text_sequential('path/to/image.jpg')
125
+ print(result)
126
+ ```
127
+
128
+ - **Get stitched text using the new method**:
129
+
130
+ ```python
131
+ result = api.get_stitched_text_smart('path/to/image.jpg')
132
+ print(result)
133
+ ```
134
+
135
+ - **Get text with coordinates**:
136
+
137
+ ```python
138
+ result = api.get_text_with_coordinates('path/to/image.jpg')
139
+ print(result)
140
+ ```
141
+
142
+ #### Programmatic API Methods
143
+
144
+ - **`get_all_data(image_path)`**: Returns all available data for the given image.
145
+ - **`get_full_text(image_path)`**: Returns only the full text from the image.
146
+ - **`get_text_with_coordinates(image_path)`**: Returns text along with its coordinates in JSON format.
147
+ - **`get_stitched_text_smart(image_path)`**: Returns stitched text using the enhanced method.
148
+ - **`get_stitched_text_sequential(image_path)`**: Returns stitched text using the basic sequential method.
149
+
150
+ ## Project Structure
151
+
152
+ ```
153
+ /chrome-lens-api-py
154
+ │
155
+ ├── /src
156
+ │ ├── /chrome_lens_py
157
+ │ │ ├── __init__.py # Package initialization
158
+ │ │ ├── constants.py # Constants used in the project
159
+ │ │ ├── utils.py # Utility functions
160
+ │ │ ├── image_processing.py # Image processing module
161
+ │ │ ├── request_handler.py # API request handling module
162
+ │ │ ├── text_processing.py # Text processing module
163
+ │ │ ├── lens_api.py # API interface for use in other scripts
164
+ │ │ └── main.py # CLI tool entry point
165
+ │
166
+ ├── setup.py # Installation setup
167
+ ├── README.md # Project description and usage guide
168
+ └── requirements.txt # Project dependencies
169
+ ```
170
+
171
+ ## Acknowledgments
172
+
173
+ Special thanks to [dimdenGD](https://github.com/dimdenGD) for the method of text extraction used in this project. You can check out their work on the [chrome-lens-ocr](https://github.com/dimdenGD/chrome-lens-ocr) repository. This project is inspired by their approach to leveraging Google Lens OCR functionality.
174
+
175
+ ## License
176
+
177
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
178
+
179
+ ## Disclaimer
180
+
181
+ This project is intended for educational purposes only. The use of Google Lens OCR functionality must comply with Google's Terms of Service. The author of this project is not responsible for any misuse of this software or for any consequences arising from its use. Users are solely responsible for ensuring that their use of this software complies with all applicable laws and regulations.
182
+
183
+ ## Author
184
+
185
+ ### Bropines - [Mail](mailto:bropines@gmail.com) / [Telegram](https://t.me/bropines)
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,39 @@
1
+ from setuptools import setup, find_packages
2
+ import pathlib
3
+
4
+ # The directory containing this file
5
+ HERE = pathlib.Path(__file__).parent
6
+
7
+ # The text of the README file
8
+ README = (HERE / "README.md").read_text()
9
+
10
+ setup(
11
+ name='chrome_lens_py',
12
+ version='1.0.0',
13
+ packages=find_packages(where="src"),
14
+ package_dir={"": "src"},
15
+ install_requires=[
16
+ 'requests',
17
+ 'Pillow',
18
+ 'filetype',
19
+ 'lxml',
20
+ 'json5',
21
+ 'rich',
22
+ ],
23
+ entry_points={
24
+ 'console_scripts': [
25
+ 'lens_scan=chrome_lens_py.main:main',
26
+ ],
27
+ },
28
+ description='Library to use Google Lens OCR via API used in Chromium.',
29
+ long_description=README,
30
+ long_description_content_type='text/markdown', # Указание типа содержимого
31
+ author='Bropines',
32
+ author_email='bropines@gmail.com',
33
+ url='https://github.com/bropines/chrome-lens-py',
34
+ classifiers=[
35
+ 'Programming Language :: Python :: 3',
36
+ 'License :: OSI Approved :: MIT License',
37
+ 'Operating System :: OS Independent',
38
+ ],
39
+ )
@@ -0,0 +1 @@
1
+ from .lens_api import LensAPI
@@ -0,0 +1,49 @@
1
+ # constants.py
2
+
3
+ LENS_ENDPOINT = 'https://lens.google.com/v3/upload'
4
+
5
+ SUPPORTED_MIMES = [
6
+ 'image/x-icon',
7
+ 'image/bmp',
8
+ 'image/jpeg',
9
+ 'image/png',
10
+ 'image/tiff',
11
+ 'image/webp',
12
+ 'image/heic'
13
+ ]
14
+
15
+ MIME_TO_EXT = {
16
+ 'image/x-icon': 'ico',
17
+ 'image/bmp': 'bmp',
18
+ 'image/jpeg': 'jpg',
19
+ 'image/png': 'png',
20
+ 'image/tiff': 'tiff',
21
+ 'image/webp': 'webp',
22
+ 'image/heic': 'heic'
23
+ }
24
+
25
+ HEADERS = {
26
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
27
+ 'Accept-Encoding': 'gzip, deflate, br',
28
+ 'Accept-Language': 'en-US,en;q=0.9',
29
+ 'Cache-Control': 'max-age=0',
30
+ 'Origin': 'https://lens.google.com',
31
+ 'Referer': 'https://lens.google.com/',
32
+ 'Sec-Ch-Ua': '"Not A(Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
33
+ 'Sec-Ch-Ua-Arch': '"x86"',
34
+ 'Sec-Ch-Ua-Bitness': '"64"',
35
+ 'Sec-Ch-Ua-Full-Version': '"91.0.4472.124"',
36
+ 'Sec-Ch-Ua-Full-Version-List': '"Not A(Brand";v="99.0.0.0", "Google Chrome";v="91", "Chromium";v="91"',
37
+ 'Sec-Ch-Ua-Mobile': '?0',
38
+ 'Sec-Ch-Ua-Model': '""',
39
+ 'Sec-Ch-Ua-Platform': '"Windows"',
40
+ 'Sec-Ch-Ua-Platform-Version': '"15.0.0"',
41
+ 'Sec-Ch-Ua-Wow64': '?0',
42
+ 'Sec-Fetch-Dest': 'document',
43
+ 'Sec-Fetch-Mode': 'navigate',
44
+ 'Sec-Fetch-Site': 'same-origin',
45
+ 'Sec-Fetch-User': '?1',
46
+ 'Upgrade-Insecure-Requests': '1',
47
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
48
+ 'X-Client-Data': 'CIW2yQEIorbJAQipncoBCIH+ygEIlaHLAQj1mM0BCIWgzQEI3ezNAQji+s0BCOmFzgEIponOAQj1ic4BCIeLzgEY1d3NARjS/s0BGNiGzgE='
49
+ }
@@ -0,0 +1,16 @@
1
+ # image_processing.py
2
+
3
+ import io
4
+ from PIL import Image
5
+ from .utils import is_supported_mime
6
+ from .constants import MIME_TO_EXT
7
+
8
+ def resize_image(image_path, max_size=(1000, 1000)):
9
+ """Изменяет размер изображения и конвертирует его в формат без альфа-канала."""
10
+ with Image.open(image_path) as img:
11
+ img.thumbnail(max_size)
12
+ if img.mode == 'RGBA':
13
+ img = img.convert('RGB')
14
+ buffer = io.BytesIO()
15
+ img.save(buffer, format="JPEG")
16
+ return buffer.getvalue(), img.size
@@ -0,0 +1,36 @@
1
+ # lens_api.py
2
+
3
+ from .request_handler import Lens
4
+ from .text_processing import simplify_output, extract_full_text, stitch_text_smart, stitch_text_sequential
5
+
6
+ class LensAPI:
7
+ def __init__(self, config=None, sleep_time=1000):
8
+ self.lens = Lens(config=config, sleep_time=sleep_time)
9
+
10
+ def get_all_data(self, file_path):
11
+ """Возвращает все данные для изображения"""
12
+ result = self.lens.scan_by_file(file_path)
13
+ return simplify_output(result)
14
+
15
+ def get_full_text(self, file_path):
16
+ """Возвращает полный текст"""
17
+ result = self.lens.scan_by_file(file_path)
18
+ return extract_full_text(result['data'])
19
+
20
+ def get_text_with_coordinates(self, file_path):
21
+ """Возвращает текст с координатами в формате JSON"""
22
+ result = self.lens.scan_by_file(file_path)
23
+ simplified_result = simplify_output(result)
24
+ return simplified_result['text_with_coordinates']
25
+
26
+ def get_stitched_text_smart(self, file_path):
27
+ """Возвращает сшитый текст (умный метод)"""
28
+ result = self.lens.scan_by_file(file_path)
29
+ simplified_result = simplify_output(result)
30
+ return simplified_result['stitched_text_smart']
31
+
32
+ def get_stitched_text_sequential(self, file_path):
33
+ """Возвращает сшитый текст (последовательный метод)"""
34
+ result = self.lens.scan_by_file(file_path)
35
+ simplified_result = simplify_output(result)
36
+ return simplified_result['stitched_text_sequential']
@@ -0,0 +1,59 @@
1
+ import sys
2
+ import json
3
+ import argparse
4
+ from .lens_api import LensAPI
5
+ from rich.console import Console
6
+ from rich.table import Table
7
+
8
+ console = Console()
9
+
10
+ def print_help():
11
+ console.print("Usage: [b]lens_scan [options] <image_file> <data_type>[/b]")
12
+ console.print("\nOptions:")
13
+ console.print("[b]-h, --help[/b] Show this help message and exit")
14
+ console.print("[b]<data_type>[/b] options:")
15
+ console.print("[b]all[/b] Get all data (full text, coordinates, and stitched text)")
16
+ console.print("[b]full_text_default[/b] Get only the default full text")
17
+ console.print("[b]full_text_old_method[/b] Get stitched text using the old method")
18
+ console.print("[b]full_text_new_method[/b] Get stitched text using the new method")
19
+ console.print("[b]coordinates[/b] Get text with coordinates")
20
+
21
+ def main():
22
+ parser = argparse.ArgumentParser(description="Process images with Google Lens API and extract text data.", add_help=False)
23
+ parser.add_argument('image_file', nargs='?', help="Path to the image file")
24
+ parser.add_argument('data_type', nargs='?', choices=['all', 'full_text_default', 'full_text_old_method', 'full_text_new_method', 'coordinates'], help="Type of data to extract")
25
+ parser.add_argument('-h', '--help', action='store_true', help="Show this help message and exit")
26
+
27
+ args = parser.parse_args()
28
+
29
+ if args.help or not args.image_file or not args.data_type:
30
+ print_help()
31
+ sys.exit(1)
32
+
33
+ image_file = args.image_file
34
+ data_type = args.data_type
35
+
36
+ try:
37
+ api = LensAPI()
38
+
39
+ if data_type == "all":
40
+ result = api.get_all_data(image_file)
41
+ elif data_type == "full_text_default":
42
+ result = api.get_full_text(image_file)
43
+ elif data_type == "full_text_old_method":
44
+ result = api.get_stitched_text_sequential(image_file)
45
+ elif data_type == "full_text_new_method":
46
+ result = api.get_stitched_text_smart(image_file)
47
+ elif data_type == "coordinates":
48
+ result = api.get_text_with_coordinates(image_file)
49
+ else:
50
+ console.print("Invalid data_type option", style="bold red")
51
+ sys.exit(1)
52
+
53
+ console.print(json.dumps(result, indent=2), style="bold white")
54
+
55
+ except Exception as e:
56
+ console.print(f"Error: {e}", style="bold red")
57
+
58
+ if __name__ == '__main__':
59
+ main()
@@ -0,0 +1,108 @@
1
+ # request_handler.py
2
+
3
+ import requests
4
+ import io
5
+ import os
6
+ import time
7
+ import http.cookiejar as cookielib
8
+ import lxml.html
9
+ import json5
10
+ import filetype
11
+ from PIL import Image
12
+ from .constants import LENS_ENDPOINT, HEADERS, MIME_TO_EXT, SUPPORTED_MIMES
13
+ from .utils import sleep, is_supported_mime
14
+ from .image_processing import resize_image
15
+
16
+ class LensError(Exception):
17
+ """Класс для обработки ошибок."""
18
+ def __init__(self, message, code=None, headers=None, body=None):
19
+ super().__init__(message)
20
+ self.code = code
21
+ self.headers = headers
22
+ self.body = body
23
+
24
+ class LensCore:
25
+ """Базовый класс для работы с Google Lens API."""
26
+ def __init__(self, config=None, sleep_time=1000):
27
+ self.config = config if config else {}
28
+ self.cookies = {}
29
+ self.sleep_time = sleep_time
30
+ self.parse_cookies()
31
+
32
+ def parse_cookies(self):
33
+ """Инициализирует куки."""
34
+ self.cookies = {
35
+ 'NID': {
36
+ 'name': 'NID',
37
+ 'value': '511=b-iPvznEQOKO1rDvyj7vkLrfe9i-PQiN0z_nhNv7lg-3_0YpQf2ZSKikTrlpu4W3mko4n2RAfYMho9NJqDEsmO-4BZG_iOqmufFZIzW4jiGJMmnaE1S3crNWwUL1HNnDqVUZZjRYkK_S-wsDWCuVul3Q_sCjucSvJ-CTN63GSjY',
38
+ 'expires': 1707050670000
39
+ }
40
+ }
41
+
42
+ def generate_cookie_header(self, headers):
43
+ """Добавляет куки в заголовки запроса."""
44
+ if self.cookies:
45
+ self.cookies = {k: v for k, v in self.cookies.items() if v['expires'] > time.time() * 1000}
46
+ headers['Cookie'] = '; '.join([f"{cookie['name']}={cookie['value']}" for cookie in self.cookies.values()])
47
+
48
+ def scan_by_data(self, data, mime, dimensions):
49
+ """Отправляет изображение на анализ в Google Lens API."""
50
+ headers = HEADERS.copy()
51
+ self.generate_cookie_header(headers)
52
+
53
+ session = requests.Session()
54
+ session.cookies = cookielib.CookieJar()
55
+ print(f"Sending data to {LENS_ENDPOINT}")
56
+
57
+ file_name = f"image.{MIME_TO_EXT[mime]}"
58
+ files = {
59
+ 'encoded_image': (file_name, data, mime),
60
+ 'original_width': (None, str(dimensions[0])),
61
+ 'original_height': (None, str(dimensions[1])),
62
+ 'processed_image_dimensions': (None, f"{dimensions[0]},{dimensions[1]}")
63
+ }
64
+
65
+ # Используем кастомное время задержки
66
+ sleep(self.sleep_time)
67
+
68
+ response = session.post(LENS_ENDPOINT, headers=headers, files=files)
69
+ print(f"Response status code: {response.status_code}")
70
+
71
+ if response.status_code != 200:
72
+ print(f"Response headers: {response.headers}")
73
+ print(f"Response body: {response.text}")
74
+ raise LensError("Failed to upload image", response.status_code, response.headers, response.text)
75
+
76
+ buffer_text = io.StringIO(response.text)
77
+ tree = lxml.html.parse(buffer_text)
78
+
79
+ r = tree.xpath("//script[@class='ds:1']")
80
+ return json5.loads(r[0].text[len("AF_initDataCallback("):-2])
81
+
82
+ class Lens(LensCore):
83
+ """Класс для работы с Google Lens API, предоставляющий удобные методы."""
84
+ def __init__(self, config=None, sleep_time=1000):
85
+ super().__init__(config, sleep_time)
86
+
87
+ def scan_by_file(self, file_path):
88
+ """Сканирует изображение по пути к файлу и возвращает результаты."""
89
+ if not os.path.isfile(file_path):
90
+ raise FileNotFoundError(f"File not found: {file_path}")
91
+ if not is_supported_mime(file_path):
92
+ raise ValueError("Unsupported file type")
93
+ img_data, dimensions = resize_image(file_path)
94
+ return self.scan_by_data(img_data, 'image/jpeg', dimensions)
95
+
96
+ def scan_by_buffer(self, buffer):
97
+ """Сканирует изображение из буфера и возвращает результаты."""
98
+ kind = filetype.guess(buffer)
99
+ if not kind or kind.mime not in SUPPORTED_MIMES:
100
+ raise ValueError("Unsupported file type")
101
+ img = Image.open(io.BytesIO(buffer))
102
+ img.thumbnail((1000, 1000))
103
+ if img.mode == 'RGBA':
104
+ img = img.convert('RGB')
105
+ img_buffer = io.BytesIO()
106
+ img.save(img_buffer, format="JPEG")
107
+ img_data = img_buffer.getvalue()
108
+ return self.scan_by_data(img_data, 'image/jpeg', img.size)
@@ -0,0 +1,116 @@
1
+ # text_processing.py
2
+
3
+ import re
4
+
5
+ def stitch_text_from_coordinates(text_with_coords):
6
+ """Сшивает текст из координат по строкам и позициям."""
7
+ sorted_elements = sorted(text_with_coords, key=lambda x: (round(x['coordinates'][1], 2), x['coordinates'][0]))
8
+
9
+ stitched_text = ""
10
+ current_y = None
11
+ current_line = []
12
+
13
+ for element in sorted_elements:
14
+ if current_y is None or abs(element['coordinates'][1] - current_y) > 0.05:
15
+ if current_line:
16
+ stitched_text += " ".join(current_line) + "\n"
17
+ current_line = []
18
+ current_y = element['coordinates'][1]
19
+ current_line.append(element['text'])
20
+
21
+ if current_line:
22
+ stitched_text += " ".join(current_line)
23
+
24
+ stitched_text = re.sub(r'\s+([,?.!])', r'\1', stitched_text)
25
+
26
+ return stitched_text.strip()
27
+
28
+ def stitch_text_smart(text_with_coords):
29
+ """Сшивает текст из координат умным методом."""
30
+ transformed_coords = [{'text': item['text'], 'coordinates': [item['coordinates'][1], item['coordinates'][0]]} for item in text_with_coords]
31
+ sorted_elements = sorted(transformed_coords, key=lambda x: (round(x['coordinates'][1], 2), x['coordinates'][0]))
32
+
33
+ stitched_text = []
34
+ current_y = None
35
+ current_line = []
36
+ word_threshold = 0.02
37
+
38
+ for element in sorted_elements:
39
+ if current_y is None or abs(element['coordinates'][1] - current_y) > 0.05:
40
+ if current_line:
41
+ stitched_text.append(" ".join(current_line))
42
+ current_line = []
43
+ current_y = element['coordinates'][1]
44
+
45
+ if element['text'] in [',', '.', '!', '?', ';', ':'] and current_line:
46
+ current_line[-1] += element['text']
47
+ else:
48
+ current_line.append(element['text'])
49
+
50
+ if current_line:
51
+ stitched_text.append(" ".join(current_line))
52
+
53
+ return "\n".join(stitched_text).strip()
54
+
55
+ def stitch_text_sequential(text_with_coords):
56
+ """Сшивает текст в последовательности, как он был распознан."""
57
+ stitched_text = " ".join([element['text'] for element in text_with_coords])
58
+ stitched_text = re.sub(r'\s+([,?.!])', r'\1', stitched_text)
59
+
60
+ return stitched_text.strip()
61
+
62
+ def extract_text_and_coordinates(data):
63
+ """Извлекает текст и координаты из структуры данных."""
64
+ text_with_coords = []
65
+ if isinstance(data, list):
66
+ for item in data:
67
+ if isinstance(item, list):
68
+ for sub_item in item:
69
+ if isinstance(sub_item, list) and len(sub_item) > 1 and isinstance(sub_item[0], str):
70
+ word = sub_item[0]
71
+ coords = sub_item[1]
72
+ if isinstance(coords, list) and all(isinstance(coord, (int, float)) for coord in coords):
73
+ text_with_coords.append({"text": word, "coordinates": coords})
74
+ else:
75
+ text_with_coords.extend(extract_text_and_coordinates(sub_item))
76
+ else:
77
+ text_with_coords.extend(extract_text_and_coordinates(item))
78
+ elif isinstance(data, dict):
79
+ for value in data.values():
80
+ text_with_coords.extend(extract_text_and_coordinates(value))
81
+ return text_with_coords
82
+
83
+ def extract_full_text(data):
84
+ """Извлекает полный текст из структуры данных."""
85
+ try:
86
+ text_data = data[3][4][0][0]
87
+ if isinstance(text_data, list):
88
+ return "\n".join(text_data)
89
+ return text_data
90
+ except (IndexError, TypeError):
91
+ return "Full text not found in expected structure"
92
+
93
+ def simplify_output(result):
94
+ """Упрощает структуру данных, извлекая ключевые элементы."""
95
+ simplified = {}
96
+
97
+ try:
98
+ if 'data' in result and isinstance(result['data'], list) and len(result['data']) > 3:
99
+ if isinstance(result['data'][3], list) and len(result['data'][3]) > 3:
100
+ simplified['language'] = result['data'][3][3]
101
+ else:
102
+ simplified['language'] = "Language not found in expected structure"
103
+
104
+ simplified['full_text'] = extract_full_text(result['data'])
105
+
106
+ if 'data' in result and isinstance(result['data'], list):
107
+ text_with_coords = extract_text_and_coordinates(result['data'])
108
+ simplified['text_with_coordinates'] = text_with_coords
109
+
110
+ simplified['stitched_text_smart'] = stitch_text_smart(text_with_coords)
111
+ simplified['stitched_text_sequential'] = stitch_text_sequential(text_with_coords)
112
+ except Exception as e:
113
+ print(f"Error in simplify_output: {e}")
114
+ simplified['error'] = str(e)
115
+
116
+ return simplified
@@ -0,0 +1,15 @@
1
+ # utils.py
2
+
3
+ import filetype
4
+ import time
5
+
6
+ from .constants import SUPPORTED_MIMES
7
+
8
+ def is_supported_mime(file_path):
9
+ """Проверяет, поддерживается ли MIME-тип файла."""
10
+ kind = filetype.guess(file_path)
11
+ return kind and kind.mime in SUPPORTED_MIMES
12
+
13
+ def sleep(ms):
14
+ """Функция ожидания."""
15
+ time.sleep(ms / 1000)
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.1
2
+ Name: chrome_lens_py
3
+ Version: 1.0.0
4
+ Summary: Library to use Google Lens OCR via API used in Chromium.
5
+ Home-page: https://github.com/bropines/chrome-lens-py
6
+ Author: Bropines
7
+ Author-email: bropines@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: requests
14
+ Requires-Dist: Pillow
15
+ Requires-Dist: filetype
16
+ Requires-Dist: lxml
17
+ Requires-Dist: json5
18
+ Requires-Dist: rich
19
+
20
+ # Chrome Lens API for Python
21
+
22
+ [English](/README.md) | [Русский](/README_RU.md)
23
+
24
+ This project provides a Python library and CLI tool for interacting with Google Lens's OCR functionality via the API used in Chromium. This allows you to process images and extract text data, including full text, coordinates, and stitched text using various methods.
25
+
26
+ ## Features
27
+
28
+ - **Full Text Extraction**: Extract the complete text from an image.
29
+ - **Coordinates Extraction**: Extract text along with its coordinates.
30
+ - **Stitched Text**: Reconstruct text from blocks using various methods:
31
+ - **Default Full Text**: Basic method for stitching text blocks.
32
+ - **Old Method**: Sequential text stitching.
33
+ - **New Method**: Enhanced text stitching.
34
+
35
+ PS. Lens has a problem with the way it displays full text, which is why methods have been added that stitch text from coordinates.
36
+
37
+ ## Installation
38
+
39
+ You can install the package using `pip`:
40
+
41
+ ### From PyPI (SOON)
42
+
43
+ ```bash
44
+ pip install chrome-lens-py
45
+ ```
46
+
47
+ ### From GIT
48
+
49
+ ```bash
50
+ pip install git+https://github.com/bropines/chrome-lens-py.git
51
+ ```
52
+
53
+ ### From source
54
+
55
+ Clone the repository and install the package:
56
+
57
+ ```bash
58
+ git clone https://github.com/bropines/chrome-lens-api-py.git
59
+ cd chrome-lens-api-py
60
+ pip install -r requirements.txt
61
+ pip install .
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ You can use the `lens_scan` command from the CLI to process images and extract text data, or you can use the Python API to integrate this functionality into your own projects.
67
+
68
+ ### CLI Usage
69
+
70
+ ```bash
71
+ lens_scan <image_file> <data_type>
72
+ ```
73
+
74
+ #### Data Types
75
+
76
+ - **all**: Get all data (full text, coordinates, and stitched text using both methods).
77
+ - **full_text_default**: Get only the default full text.
78
+ - **full_text_old_method**: Get stitched text using the old sequential method.
79
+ - **full_text_new_method**: Get stitched text using the new enhanced method.
80
+ - **coordinates**: Get text along with coordinates.
81
+
82
+ #### Example
83
+
84
+ To extract text using the new method for stitching:
85
+
86
+ ```bash
87
+ lens_scan path/to/image.jpg full_text_new_method
88
+ ```
89
+
90
+ To get all available data:
91
+
92
+ ```bash
93
+ lens_scan path/to/image.jpg all
94
+ ```
95
+
96
+ #### CLI Help
97
+
98
+ You can use the `-h` or `--help` option to display usage information:
99
+
100
+ ```bash
101
+ lens_scan -h
102
+ ```
103
+
104
+ ### Programmatic API Usage
105
+
106
+ In addition to the CLI tool, this project provides a Python API that can be used in your scripts.
107
+
108
+ #### Basic Programmatic Usage
109
+
110
+ First, import the `LensAPI` class:
111
+
112
+ ```python
113
+ from chrome_lens_py import LensAPI
114
+ ```
115
+
116
+ #### Example Programmatic Usage
117
+
118
+ 1. **Instantiate the API**:
119
+
120
+ ```python
121
+ api = LensAPI()
122
+ ```
123
+
124
+ 2. **Process an image**:
125
+
126
+ - **Get all data**:
127
+
128
+ ```python
129
+ result = api.get_all_data('path/to/image.jpg')
130
+ print(result)
131
+ ```
132
+
133
+ - **Get the default full text**:
134
+
135
+ ```python
136
+ result = api.get_full_text('path/to/image.jpg')
137
+ print(result)
138
+ ```
139
+
140
+ - **Get stitched text using the old method**:
141
+
142
+ ```python
143
+ result = api.get_stitched_text_sequential('path/to/image.jpg')
144
+ print(result)
145
+ ```
146
+
147
+ - **Get stitched text using the new method**:
148
+
149
+ ```python
150
+ result = api.get_stitched_text_smart('path/to/image.jpg')
151
+ print(result)
152
+ ```
153
+
154
+ - **Get text with coordinates**:
155
+
156
+ ```python
157
+ result = api.get_text_with_coordinates('path/to/image.jpg')
158
+ print(result)
159
+ ```
160
+
161
+ #### Programmatic API Methods
162
+
163
+ - **`get_all_data(image_path)`**: Returns all available data for the given image.
164
+ - **`get_full_text(image_path)`**: Returns only the full text from the image.
165
+ - **`get_text_with_coordinates(image_path)`**: Returns text along with its coordinates in JSON format.
166
+ - **`get_stitched_text_smart(image_path)`**: Returns stitched text using the enhanced method.
167
+ - **`get_stitched_text_sequential(image_path)`**: Returns stitched text using the basic sequential method.
168
+
169
+ ## Project Structure
170
+
171
+ ```
172
+ /chrome-lens-api-py
173
+ │
174
+ ├── /src
175
+ │ ├── /chrome_lens_py
176
+ │ │ ├── __init__.py # Package initialization
177
+ │ │ ├── constants.py # Constants used in the project
178
+ │ │ ├── utils.py # Utility functions
179
+ │ │ ├── image_processing.py # Image processing module
180
+ │ │ ├── request_handler.py # API request handling module
181
+ │ │ ├── text_processing.py # Text processing module
182
+ │ │ ├── lens_api.py # API interface for use in other scripts
183
+ │ │ └── main.py # CLI tool entry point
184
+ │
185
+ ├── setup.py # Installation setup
186
+ ├── README.md # Project description and usage guide
187
+ └── requirements.txt # Project dependencies
188
+ ```
189
+
190
+ ## Acknowledgments
191
+
192
+ Special thanks to [dimdenGD](https://github.com/dimdenGD) for the method of text extraction used in this project. You can check out their work on the [chrome-lens-ocr](https://github.com/dimdenGD/chrome-lens-ocr) repository. This project is inspired by their approach to leveraging Google Lens OCR functionality.
193
+
194
+ ## License
195
+
196
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
197
+
198
+ ## Disclaimer
199
+
200
+ This project is intended for educational purposes only. The use of Google Lens OCR functionality must comply with Google's Terms of Service. The author of this project is not responsible for any misuse of this software or for any consequences arising from its use. Users are solely responsible for ensuring that their use of this software complies with all applicable laws and regulations.
201
+
202
+ ## Author
203
+
204
+ ### Bropines - [Mail](mailto:bropines@gmail.com) / [Telegram](https://t.me/bropines)
@@ -0,0 +1,17 @@
1
+ LICENSE
2
+ README.md
3
+ setup.py
4
+ src/chrome_lens_py/__init__.py
5
+ src/chrome_lens_py/constants.py
6
+ src/chrome_lens_py/image_processing.py
7
+ src/chrome_lens_py/lens_api.py
8
+ src/chrome_lens_py/main.py
9
+ src/chrome_lens_py/request_handler.py
10
+ src/chrome_lens_py/text_processing.py
11
+ src/chrome_lens_py/utils.py
12
+ src/chrome_lens_py.egg-info/PKG-INFO
13
+ src/chrome_lens_py.egg-info/SOURCES.txt
14
+ src/chrome_lens_py.egg-info/dependency_links.txt
15
+ src/chrome_lens_py.egg-info/entry_points.txt
16
+ src/chrome_lens_py.egg-info/requires.txt
17
+ src/chrome_lens_py.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ lens_scan = chrome_lens_py.main:main
@@ -0,0 +1,6 @@
1
+ requests
2
+ Pillow
3
+ filetype
4
+ lxml
5
+ json5
6
+ rich
@@ -0,0 +1 @@
1
+ chrome_lens_py