Compare commits
No commits in common. 'zhu1ku3' and 'main' have entirely different histories.
@ -1,8 +0,0 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1 +0,0 @@
|
||||
Revision:6239268765d383704e5cb48b62c9ead0898ce22d,CreatedAt:unknown
|
||||
File diff suppressed because one or more lines are too long
@ -1,111 +0,0 @@
|
||||
{
|
||||
"Global": {
|
||||
"model_name": "PP-OCRv5_server_det"
|
||||
},
|
||||
"Hpi": {
|
||||
"backend_configs": {
|
||||
"paddle_infer": {
|
||||
"trt_dynamic_shapes": {
|
||||
"x": [
|
||||
[
|
||||
1,
|
||||
3,
|
||||
32,
|
||||
32
|
||||
],
|
||||
[
|
||||
1,
|
||||
3,
|
||||
736,
|
||||
736
|
||||
],
|
||||
[
|
||||
1,
|
||||
3,
|
||||
4000,
|
||||
4000
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"tensorrt": {
|
||||
"dynamic_shapes": {
|
||||
"x": [
|
||||
[
|
||||
1,
|
||||
3,
|
||||
32,
|
||||
32
|
||||
],
|
||||
[
|
||||
1,
|
||||
3,
|
||||
736,
|
||||
736
|
||||
],
|
||||
[
|
||||
1,
|
||||
3,
|
||||
4000,
|
||||
4000
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PreProcess": {
|
||||
"transform_ops": [
|
||||
{
|
||||
"DecodeImage": {
|
||||
"channel_first": false,
|
||||
"img_mode": "BGR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"DetLabelEncode": null
|
||||
},
|
||||
{
|
||||
"DetResizeForTest": {
|
||||
"resize_long": 960
|
||||
}
|
||||
},
|
||||
{
|
||||
"NormalizeImage": {
|
||||
"mean": [
|
||||
0.485,
|
||||
0.456,
|
||||
0.406
|
||||
],
|
||||
"order": "hwc",
|
||||
"scale": "1./255.",
|
||||
"std": [
|
||||
0.229,
|
||||
0.224,
|
||||
0.225
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"ToCHWImage": null
|
||||
},
|
||||
{
|
||||
"KeepKeys": {
|
||||
"keep_keys": [
|
||||
"image",
|
||||
"shape",
|
||||
"polys",
|
||||
"ignore_tags"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"PostProcess": {
|
||||
"name": "DBPostProcess",
|
||||
"thresh": 0.3,
|
||||
"box_thresh": 0.6,
|
||||
"max_candidates": 1000,
|
||||
"unclip_ratio": 1.5
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1,53 +0,0 @@
|
||||
Global:
|
||||
model_name: PP-OCRv5_server_det
|
||||
Hpi:
|
||||
backend_configs:
|
||||
paddle_infer:
|
||||
trt_dynamic_shapes: &id001
|
||||
x:
|
||||
- - 1
|
||||
- 3
|
||||
- 32
|
||||
- 32
|
||||
- - 1
|
||||
- 3
|
||||
- 736
|
||||
- 736
|
||||
- - 1
|
||||
- 3
|
||||
- 4000
|
||||
- 4000
|
||||
tensorrt:
|
||||
dynamic_shapes: *id001
|
||||
PreProcess:
|
||||
transform_ops:
|
||||
- DecodeImage:
|
||||
channel_first: false
|
||||
img_mode: BGR
|
||||
- DetLabelEncode: null
|
||||
- DetResizeForTest:
|
||||
resize_long: 960
|
||||
- NormalizeImage:
|
||||
mean:
|
||||
- 0.485
|
||||
- 0.456
|
||||
- 0.406
|
||||
order: hwc
|
||||
scale: 1./255.
|
||||
std:
|
||||
- 0.229
|
||||
- 0.224
|
||||
- 0.225
|
||||
- ToCHWImage: null
|
||||
- KeepKeys:
|
||||
keep_keys:
|
||||
- image
|
||||
- shape
|
||||
- polys
|
||||
- ignore_tags
|
||||
PostProcess:
|
||||
name: DBPostProcess
|
||||
thresh: 0.3
|
||||
box_thresh: 0.6
|
||||
max_candidates: 1000
|
||||
unclip_ratio: 1.5
|
||||
Binary file not shown.
@ -1 +0,0 @@
|
||||
Revision:08795e15fc7eb7ccc79a9b8d5241f59cfa61e5de,CreatedAt:unknown
|
||||
@ -1,169 +0,0 @@
|
||||
---
|
||||
license: Apache License 2.0
|
||||
library_name: PaddleOCR
|
||||
language:
|
||||
- English
|
||||
pipeline_tag: image-to-text
|
||||
tags:
|
||||
- OCR
|
||||
- PaddlePaddle
|
||||
- PaddleOCR
|
||||
- textline_recognition
|
||||
---
|
||||
|
||||
# en_PP-OCRv5_mobile_rec
|
||||
|
||||
## Introduction
|
||||
|
||||
en_PP-OCRv5_mobile_rec is one of the PP-OCRv5_rec that are the latest generation text line recognition models developed by PaddleOCR team. It aims to efficiently and accurately support the recognition of English. The key accuracy metrics are as follow:
|
||||
|
||||
| Model | Accuracy (%) |
|
||||
|-|-|
|
||||
| en_PP-OCRv5_mobile_rec | 85.3|
|
||||
|
||||
|
||||
|
||||
**Note**: If any character (including punctuation) in a line was incorrect, the entire line was marked as wrong. This ensures higher accuracy in practical applications.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Installation
|
||||
|
||||
1. PaddlePaddle
|
||||
|
||||
Please refer to the following commands to install PaddlePaddle using pip:
|
||||
|
||||
```bash
|
||||
# for CUDA11.8
|
||||
python -m pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
|
||||
|
||||
# for CUDA12.6
|
||||
python -m pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu126/
|
||||
|
||||
# for CPU
|
||||
python -m pip install paddlepaddle==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
|
||||
```
|
||||
|
||||
For details about PaddlePaddle installation, please refer to the [PaddlePaddle official website](https://www.paddlepaddle.org.cn/en/install/quick).
|
||||
|
||||
2. PaddleOCR
|
||||
|
||||
Install the latest version of the PaddleOCR inference package from PyPI:
|
||||
|
||||
```bash
|
||||
python -m pip install paddleocr
|
||||
```
|
||||
|
||||
### Model Usage
|
||||
|
||||
You can quickly experience the functionality with a single command:
|
||||
|
||||
```bash
|
||||
paddleocr text_recognition \
|
||||
--model_name en_PP-OCRv5_mobile_rec \
|
||||
-i https://cdn-uploads.huggingface.co/production/uploads/681c1ecd9539bdde5ae1733c/QmaPtftqwOgCtx0AIvU2z.png
|
||||
```
|
||||
|
||||
You can also integrate the model inference of the text recognition module into your project. Before running the following code, please download the sample image to your local machine.
|
||||
|
||||
```python
|
||||
from paddleocr import TextRecognition
|
||||
model = TextRecognition(model_name="en_PP-OCRv5_mobile_rec")
|
||||
output = model.predict(input="QmaPtftqwOgCtx0AIvU2z.png", batch_size=1)
|
||||
for res in output:
|
||||
res.print()
|
||||
res.save_to_img(save_path="./output/")
|
||||
res.save_to_json(save_path="./output/res.json")
|
||||
```
|
||||
|
||||
After running, the obtained result is as follows:
|
||||
|
||||
```json
|
||||
{'res': {'input_path': '/root/.paddlex/predict_input/QmaPtftqwOgCtx0AIvU2z.png', 'page_index': None, 'rec_text': 'the number of model parameters and FLOPs get larger, it', 'rec_score': 0.993655264377594}}
|
||||
```
|
||||
|
||||
The visualized image is as follows:
|
||||
|
||||

|
||||
|
||||
For details about usage command and descriptions of parameters, please refer to the [Document](https://paddlepaddle.github.io/PaddleOCR/latest/en/version3.x/module_usage/text_recognition.html#iii-quick-start).
|
||||
|
||||
### Pipeline Usage
|
||||
|
||||
The ability of a single model is limited. But the pipeline consists of several models can provide more capacity to resolve difficult problems in real-world scenarios.
|
||||
|
||||
#### PP-OCRv5
|
||||
|
||||
The general OCR pipeline is used to solve text recognition tasks by extracting text information from images and outputting it in string format. And there are 5 modules in the pipeline:
|
||||
* Document Image Orientation Classification Module (Optional)
|
||||
* Text Image Unwarping Module (Optional)
|
||||
* Text Line Orientation Classification Module (Optional)
|
||||
* Text Detection Module
|
||||
* Text Recognition Module
|
||||
|
||||
Run a single command to quickly experience the OCR pipeline:
|
||||
|
||||
```bash
|
||||
paddleocr ocr -i https://cdn-uploads.huggingface.co/production/uploads/681c1ecd9539bdde5ae1733c/c3hSldnYVQXp48T5V0Ze4.png \
|
||||
--text_recognition_model_name en_PP-OCRv5_mobile_rec \
|
||||
--use_doc_orientation_classify False \
|
||||
--use_doc_unwarping False \
|
||||
--use_textline_orientation True \
|
||||
--save_path ./output \
|
||||
--device gpu:0
|
||||
```
|
||||
|
||||
Results are printed to the terminal:
|
||||
|
||||
```json
|
||||
{'res': {'input_path': '/root/.paddlex/predict_input/c3hSldnYVQXp48T5V0Ze4.png', 'page_index': None, 'model_settings': {'use_doc_preprocessor': True, 'use_textline_orientation': False}, 'doc_preprocessor_res': {'input_path': None, 'page_index': None, 'model_settings': {'use_doc_orientation_classify': False, 'use_doc_unwarping': False}, 'angle': -1}, 'dt_polys': array([[[252, 172],
|
||||
...,
|
||||
[254, 241]],
|
||||
|
||||
...,
|
||||
|
||||
[[665, 566],
|
||||
...,
|
||||
[663, 601]]], dtype=int16), 'text_det_params': {'limit_side_len': 64, 'limit_type': 'min', 'thresh': 0.3, 'max_side_limit': 4000, 'box_thresh': 0.6, 'unclip_ratio': 1.5}, 'text_type': 'general', 'textline_orientation_angles': array([-1, ..., -1]), 'text_rec_score_thresh': 0.0, 'return_word_box': False, 'rec_texts': ['The moon tells the sky', 'The sky tells the sea', 'The sea tells the tide', 'And the tide tells me', 'Lemn Sissay'], 'rec_scores': array([0.98405874, ..., 0.9837752 ]), 'rec_polys': array([[[252, 172],
|
||||
...,
|
||||
[254, 241]],
|
||||
|
||||
...,
|
||||
|
||||
[[665, 566],
|
||||
...,
|
||||
[663, 601]]], dtype=int16), 'rec_boxes': array([[252, ..., 241],
|
||||
...,
|
||||
[663, ..., 612]], dtype=int16)}}
|
||||
```
|
||||
|
||||
If save_path is specified, the visualization results will be saved under `save_path`. The visualization output is shown below:
|
||||
|
||||

|
||||
|
||||
The command-line method is for quick experience. For project integration, also only a few codes are needed as well:
|
||||
|
||||
```python
|
||||
from paddleocr import PaddleOCR
|
||||
|
||||
ocr = PaddleOCR(
|
||||
text_recognition_model_name="en_PP-OCRv5_mobile_rec",
|
||||
use_doc_orientation_classify=False, # Use use_doc_orientation_classify to enable/disable document orientation classification model
|
||||
use_doc_unwarping=False, # Use use_doc_unwarping to enable/disable document unwarping module
|
||||
use_textline_orientation=True, # Use use_textline_orientation to enable/disable textline orientation classification model
|
||||
device="gpu:0", # Use device to specify GPU for model inference
|
||||
)
|
||||
result = ocr.predict("https://cdn-uploads.huggingface.co/production/uploads/681c1ecd9539bdde5ae1733c/6KQKOS42DKVEUnrticvhd.png")
|
||||
for res in result:
|
||||
res.print()
|
||||
res.save_to_img("output")
|
||||
res.save_to_json("output")
|
||||
```
|
||||
|
||||
The default model used in pipeline is `PP-OCRv5_server_rec`, so it is needed that specifing to `en_PP-OCRv5_mobile_rec` by argument `text_recognition_model_name`. And you can also use the local model file by argument `text_recognition_model_dir`. For details about usage command and descriptions of parameters, please refer to the [Document](https://paddlepaddle.github.io/PaddleOCR/latest/en/version3.x/pipeline_usage/OCR.html#2-quick-start).
|
||||
|
||||
## Links
|
||||
|
||||
[PaddleOCR Repo](https://github.com/paddlepaddle/paddleocr)
|
||||
|
||||
[PaddleOCR Documentation](https://paddlepaddle.github.io/PaddleOCR/latest/en/index.html)
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,188 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
桌面应用打包脚本
|
||||
使用PyInstaller将应用打包为可执行文件
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
def check_dependencies():
|
||||
"""检查打包依赖"""
|
||||
required_packages = ['pywebview', 'flask', 'pyinstaller']
|
||||
missing_packages = []
|
||||
|
||||
for package in required_packages:
|
||||
try:
|
||||
__import__(package)
|
||||
except ImportError:
|
||||
missing_packages.append(package)
|
||||
|
||||
if missing_packages:
|
||||
print(f"❌ 缺少必要的包: {', '.join(missing_packages)}")
|
||||
print("请运行: pip install " + " ".join(missing_packages))
|
||||
return False
|
||||
|
||||
print("✓ 所有依赖包已安装")
|
||||
return True
|
||||
|
||||
def create_spec_file():
|
||||
"""创建PyInstaller spec文件"""
|
||||
spec_content = """
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
project_root = Path(__file__).parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['desktop_app.py'],
|
||||
pathex=[str(project_root)],
|
||||
binaries=[],
|
||||
datas=[
|
||||
('templates/*', 'templates'),
|
||||
('static/*', 'static'),
|
||||
('config.env', '.'),
|
||||
('requirements.txt', '.'),
|
||||
],
|
||||
hiddenimports=[
|
||||
'flask',
|
||||
'webview',
|
||||
'json_dao',
|
||||
'ai_service',
|
||||
'ocr_service',
|
||||
'auth_utils',
|
||||
'performance',
|
||||
'scoring_service',
|
||||
'article_scoring_standards',
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='AI写作辅导软件',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False, # 设置为True可显示控制台窗口
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon='static/favicon.ico' if os.path.exists('static/favicon.ico') else None,
|
||||
)
|
||||
"""
|
||||
|
||||
spec_path = Path('desktop_app.spec')
|
||||
with open(spec_path, 'w', encoding='utf-8') as f:
|
||||
f.write(spec_content)
|
||||
|
||||
return spec_path
|
||||
|
||||
def build_application():
|
||||
"""打包应用"""
|
||||
try:
|
||||
print("🚀 开始打包应用...")
|
||||
|
||||
# 创建spec文件
|
||||
spec_file = create_spec_file()
|
||||
print("✓ Spec文件创建完成")
|
||||
|
||||
# 运行PyInstaller
|
||||
cmd = [sys.executable, '-m', 'PyInstaller', '--clean', str(spec_file)]
|
||||
|
||||
print("📦 正在打包,这可能需要几分钟...")
|
||||
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ 应用打包成功!")
|
||||
|
||||
# 显示输出目录
|
||||
dist_dir = Path('dist')
|
||||
if dist_dir.exists():
|
||||
exe_files = list(dist_dir.glob('*.exe'))
|
||||
if exe_files:
|
||||
print(f"📁 可执行文件位置: {exe_files[0]}")
|
||||
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 打包失败: {result.stderr}")
|
||||
return False
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ 打包过程出错: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 打包失败: {e}")
|
||||
return False
|
||||
|
||||
def cleanup():
|
||||
"""清理临时文件"""
|
||||
temp_dirs = ['build', 'dist', '__pycache__']
|
||||
temp_files = ['desktop_app.spec']
|
||||
|
||||
for temp_dir in temp_dirs:
|
||||
if Path(temp_dir).exists():
|
||||
shutil.rmtree(temp_dir)
|
||||
print(f"🧹 清理目录: {temp_dir}")
|
||||
|
||||
for temp_file in temp_files:
|
||||
if Path(temp_file).exists():
|
||||
Path(temp_file).unlink()
|
||||
print(f"🧹 清理文件: {temp_file}")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("=" * 60)
|
||||
print("AI智能写作辅导软件 - 桌面应用打包工具")
|
||||
print("=" * 60)
|
||||
|
||||
# 检查依赖
|
||||
if not check_dependencies():
|
||||
return
|
||||
|
||||
# 清理之前的构建
|
||||
cleanup()
|
||||
|
||||
# 打包应用
|
||||
if build_application():
|
||||
print("\n🎉 打包完成!")
|
||||
print("\n📋 使用说明:")
|
||||
print("1. 在 'dist' 目录中找到可执行文件")
|
||||
print("2. 可以直接运行或分发给其他用户")
|
||||
print("3. 首次启动可能需要几秒钟初始化时间")
|
||||
else:
|
||||
print("\n💥 打包失败,请检查错误信息")
|
||||
|
||||
# 询问是否清理
|
||||
if input("\n是否清理临时文件? (y/n): ").lower() == 'y':
|
||||
cleanup()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@ -1,61 +0,0 @@
|
||||
"""
|
||||
桌面应用配置文件
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# 应用基本信息
|
||||
APP_NAME = "EGA"
|
||||
APP_VERSION = "2.0.0"
|
||||
APP_DESCRIPTION = "AI智能写作辅导软件 - 桌面版"
|
||||
|
||||
# 窗口配置
|
||||
WINDOW_CONFIG = {
|
||||
'title': APP_NAME, # 统一使用APP_NAME
|
||||
'width': 1800,
|
||||
'height': 1200,
|
||||
'min_width': 1000,
|
||||
'min_height': 700,
|
||||
'resizable': True,
|
||||
'fullscreen': False,
|
||||
'frameless': False,
|
||||
'easy_drag': True,
|
||||
'on_top': False,
|
||||
'confirm_close': True,
|
||||
'hidpi': True,
|
||||
'high_dpi': True,
|
||||
'text_scale': 1.2 # 文本缩放比例
|
||||
}
|
||||
|
||||
# 服务器配置
|
||||
SERVER_CONFIG = {
|
||||
'host': '127.0.0.1',
|
||||
'port': 8080,
|
||||
'debug': False
|
||||
}
|
||||
|
||||
# 路径配置
|
||||
BASE_DIR = Path(__file__).parent
|
||||
DATA_DIR = BASE_DIR / 'data'
|
||||
LOG_DIR = BASE_DIR / 'logs'
|
||||
TEMP_DIR = BASE_DIR / 'temp'
|
||||
|
||||
# 创建必要目录
|
||||
for directory in [DATA_DIR, LOG_DIR, TEMP_DIR]:
|
||||
directory.mkdir(exist_ok=True)
|
||||
|
||||
# 特殊功能配置
|
||||
FEATURE_FLAGS = {
|
||||
'enable_tray_icon': True,
|
||||
'enable_system_notifications': True,
|
||||
'enable_auto_update': False,
|
||||
'enable_hot_reload': False
|
||||
}
|
||||
|
||||
# 主题配置
|
||||
THEME_CONFIG = {
|
||||
'dark_mode': False,
|
||||
'accent_color': '#2196F3',
|
||||
'background_color': '#FFFFFF',
|
||||
'font_family': 'Microsoft YaHei, Arial, sans-serif'
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
# diagnostic.py
|
||||
import sys
|
||||
import socket
|
||||
import psutil
|
||||
from pathlib import Path
|
||||
|
||||
def run_diagnostics():
|
||||
print("=== 应用诊断信息 ===")
|
||||
|
||||
# 检查端口占用
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.bind(('127.0.0.1', 8080))
|
||||
print("✓ 端口8080可用")
|
||||
sock.close()
|
||||
except OSError:
|
||||
print("❌ 端口8080被占用")
|
||||
|
||||
# 检查必要目录
|
||||
required_dirs = ['data', 'logs', 'temp']
|
||||
for dir_name in required_dirs:
|
||||
dir_path = Path(__file__).parent / dir_name
|
||||
if dir_path.exists():
|
||||
print(f"✓ 目录 {dir_name} 存在")
|
||||
else:
|
||||
print(f"❌ 目录 {dir_name} 缺失")
|
||||
|
||||
# 检查Python包
|
||||
required_packages = ['webview', 'flask', 'pillow']
|
||||
for package in required_packages:
|
||||
try:
|
||||
__import__(package)
|
||||
print(f"✓ 包 {package} 已安装")
|
||||
except ImportError:
|
||||
print(f"❌ 包 {package} 未安装")
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_diagnostics()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,122 +0,0 @@
|
||||
"""
|
||||
OCR相关路由
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
from flask import Blueprint, request, jsonify, current_app
|
||||
from werkzeug.utils import secure_filename
|
||||
import base64
|
||||
|
||||
from ocr_service import ocr_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 创建OCR蓝图
|
||||
ocr_bp = Blueprint('ocr', __name__)
|
||||
|
||||
def allowed_file(filename):
|
||||
"""检查文件类型是否允许"""
|
||||
allowed_extensions = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff'}
|
||||
return '.' in filename and \
|
||||
filename.rsplit('.', 1)[1].lower() in allowed_extensions
|
||||
|
||||
@ocr_bp.route('/api/ocr/recognize', methods=['POST'])
|
||||
def recognize_text():
|
||||
"""
|
||||
图片文字识别接口
|
||||
支持文件上传和base64数据
|
||||
"""
|
||||
print("收到OCR识别请求")
|
||||
try:
|
||||
# 检查是否有文件上传
|
||||
if 'image' in request.files:
|
||||
file = request.files['image']
|
||||
if file.filename == '':
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "未选择文件",
|
||||
"text": ""
|
||||
}), 400
|
||||
print("处理上传的文件")
|
||||
if file and allowed_file(file.filename):
|
||||
# 读取文件数据
|
||||
image_data = file.read()
|
||||
result = ocr_service.recognize_text_from_bytes(image_data)
|
||||
print("OCR识别完成,from file upload")
|
||||
return jsonify(result)
|
||||
else:
|
||||
print("不支持的文件格式")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "不支持的文件格式",
|
||||
"text": ""
|
||||
}), 400
|
||||
|
||||
# 检查是否有base64数据
|
||||
elif 'image_data' in request.json:
|
||||
image_data_base64 = request.json['image_data']
|
||||
try:
|
||||
# 解码base64数据
|
||||
if ',' in image_data_base64:
|
||||
# 处理data URL格式
|
||||
image_data_base64 = image_data_base64.split(',')[1]
|
||||
|
||||
image_data = base64.b64decode(image_data_base64)
|
||||
result = ocr_service.recognize_text_from_bytes(image_data)
|
||||
print("OCR识别完成,from base64 data")
|
||||
return jsonify(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Base64解码失败: {e}")
|
||||
print("Base64解码失败")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "图片数据格式错误",
|
||||
"text": ""
|
||||
}), 400
|
||||
|
||||
else:
|
||||
print("未提供图片文件或base64数据")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "请提供图片文件或base64数据",
|
||||
"text": ""
|
||||
}), 400
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"OCR识别接口错误: {e}")
|
||||
print("OCR识别接口发生错误")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": f"服务器错误: {str(e)}",
|
||||
"text": ""
|
||||
}), 500
|
||||
|
||||
@ocr_bp.route('/api/ocr/status', methods=['GET'])
|
||||
def get_ocr_status():
|
||||
"""获取OCR服务状态"""
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"initialized": ocr_service.is_initialized,
|
||||
"status": "ready" if ocr_service.is_initialized else "not_initialized"
|
||||
})
|
||||
|
||||
@ocr_bp.route('/api/ocr/initialize', methods=['POST'])
|
||||
def initialize_ocr():
|
||||
"""手动初始化OCR服务"""
|
||||
print("收到OCR初始化请求")
|
||||
try:
|
||||
success = ocr_service.initialize_ocr()
|
||||
if success:
|
||||
print("OCR服务初始化成功")
|
||||
else:
|
||||
print("OCR服务初始化失败")
|
||||
return jsonify({
|
||||
"success": success,
|
||||
"message": "OCR初始化成功" if success else "OCR初始化失败"
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": f"初始化失败: {str(e)}"
|
||||
}), 500
|
||||
|
Before Width: | Height: | Size: 21 KiB |
File diff suppressed because it is too large
Load Diff
@ -1,106 +0,0 @@
|
||||
"""
|
||||
系统托盘支持
|
||||
仅在Windows/Linux系统有效
|
||||
"""
|
||||
import sys
|
||||
import threading
|
||||
import webview
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
if sys.platform == 'win32':
|
||||
import pystray
|
||||
from pystray import MenuItem, Menu
|
||||
from PIL import Image, ImageDraw
|
||||
elif sys.platform.startswith('linux'):
|
||||
# Linux系统托盘支持
|
||||
print("暂时不支持Linux系统托盘功能")
|
||||
except ImportError:
|
||||
print(f"系统托盘功能不可用,缺少必要的依赖包: {e}")
|
||||
print("请运行: pip install pystray pillow")
|
||||
sys.exit(1)
|
||||
|
||||
class SystemTray:
|
||||
"""系统托盘管理器"""
|
||||
|
||||
def __init__(self, window, app_name="AI写作辅导"):
|
||||
self.window = window
|
||||
self.app_name = app_name
|
||||
self.tray_icon = None
|
||||
self.is_running = False
|
||||
|
||||
def create_icon(self):
|
||||
"""创建托盘图标"""
|
||||
try:
|
||||
# 创建一个简单的图标
|
||||
width = 64
|
||||
height = 64
|
||||
image = Image.new('RGB', (width, height), color='white')
|
||||
dc = ImageDraw.Draw(image)
|
||||
|
||||
# 绘制一个简单的AI图标
|
||||
dc.rectangle([10, 10, width-10, height-10], fill='#2196F3', outline='#1976D2')
|
||||
dc.text((width/2, height/2), 'AI', fill='white', anchor='mm')
|
||||
|
||||
return image
|
||||
except:
|
||||
# 如果创建图标失败,返回一个空图像
|
||||
return Image.new('RGB', (64, 64), color='white')
|
||||
|
||||
def on_show_window(self, icon, item):
|
||||
"""显示窗口"""
|
||||
if self.window:
|
||||
self.window.show()
|
||||
self.window.restore()
|
||||
|
||||
def on_hide_window(self, icon, item):
|
||||
"""隐藏窗口"""
|
||||
if self.window:
|
||||
self.window.hide()
|
||||
|
||||
def on_quit(self, icon, item):
|
||||
"""退出应用"""
|
||||
if self.window:
|
||||
webview.destroy_window(self.window)
|
||||
icon.stop()
|
||||
os._exit(0)
|
||||
|
||||
def create_menu(self):
|
||||
"""创建托盘菜单"""
|
||||
return Menu(
|
||||
MenuItem('显示窗口', self.on_show_window),
|
||||
MenuItem('隐藏窗口', self.on_hide_window),
|
||||
MenuItem('退出', self.on_quit)
|
||||
)
|
||||
|
||||
def start(self):
|
||||
"""启动系统托盘"""
|
||||
if sys.platform not in ['win32', 'linux']:
|
||||
return
|
||||
|
||||
try:
|
||||
icon_image = self.create_icon()
|
||||
menu = self.create_menu()
|
||||
|
||||
self.tray_icon = pystray.Icon(
|
||||
self.app_name,
|
||||
icon_image,
|
||||
self.app_name,
|
||||
menu
|
||||
)
|
||||
|
||||
self.is_running = True
|
||||
|
||||
# 在单独的线程中运行托盘图标
|
||||
tray_thread = threading.Thread(target=self.tray_icon.run, daemon=True)
|
||||
tray_thread.start()
|
||||
|
||||
except Exception as e:
|
||||
print(f"系统托盘启动失败: {e}")
|
||||
|
||||
def stop(self):
|
||||
"""停止系统托盘"""
|
||||
if self.tray_icon and self.is_running:
|
||||
self.tray_icon.stop()
|
||||
self.is_running = False
|
||||
@ -1,22 +0,0 @@
|
||||
{
|
||||
"ai_model": {
|
||||
"value": "gpt-3.5-turbo",
|
||||
"description": "默认配置: ai_model",
|
||||
"updated_at": "2025-10-14T19:10:47.462376"
|
||||
},
|
||||
"max_word_count": {
|
||||
"value": 800,
|
||||
"description": "默认配置: max_word_count",
|
||||
"updated_at": "2025-10-14T19:10:47.476253"
|
||||
},
|
||||
"enable_ai_suggestions": {
|
||||
"value": true,
|
||||
"description": "默认配置: enable_ai_suggestions",
|
||||
"updated_at": "2025-10-14T19:10:47.491171"
|
||||
},
|
||||
"auto_save_interval": {
|
||||
"value": 30,
|
||||
"description": "默认配置: auto_save_interval",
|
||||
"updated_at": "2025-10-14T19:10:47.504964"
|
||||
}
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"username": "267278466@qq.com",
|
||||
"password_hash": "07d0a715a160482331a556b514bee739$fe094c2d3e40fad4e83c6b06aaa95976c68e325bd899a003e7a2928edfe0fce8",
|
||||
"grade": "高中",
|
||||
"subject": "英语",
|
||||
"ai_provider": "DeepSeek",
|
||||
"ai_model": "deepseek-chat",
|
||||
"ai_api_key": "sk-4fa62c38b3f44e1da5741c553ebe0344",
|
||||
"ai_base_url": "https://api.deepseek.com",
|
||||
"created_at": "2025-10-14T19:10:47.461150",
|
||||
"updated_at": "2025-11-02T16:36:09.442564"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"username": "3272999867@qq.com",
|
||||
"password_hash": "726de539acd8e4c5421d3ecb3fe3aa5d$1acc29ac6234ed4f638a18e4bcda6ce57815163122f327023547459cf4cce89a",
|
||||
"grade": "大学",
|
||||
"subject": "英语",
|
||||
"ai_provider": "DeepSeek",
|
||||
"ai_model": "deepseek-chat",
|
||||
"ai_api_key": "sk-c48f5640166f4506b42a453496670f79",
|
||||
"ai_base_url": "https://api.deepseek.com",
|
||||
"created_at": "2025-11-17T11:07:40.705257",
|
||||
"updated_at": "2025-11-19T09:21:30.760003"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"username": "001test002",
|
||||
"password_hash": "9d364bb19e8dd5fef19f272895c2449f$b54ea039ebf26ba88e546ba9f93d6044ea372eb6c26029db8c503c7ba5bf835f",
|
||||
"grade": "初中",
|
||||
"subject": "语文",
|
||||
"ai_provider": "",
|
||||
"ai_model": "",
|
||||
"ai_api_key": "",
|
||||
"ai_base_url": "",
|
||||
"created_at": "2025-11-17T14:57:02.456902"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"username": "001test001",
|
||||
"password_hash": "7262f58e0058915cab291f5607b82875$82af48df1348a4426e10b5d3884e097bfa9bd308e9ab8cf233ef6848d14daea5",
|
||||
"grade": "初中",
|
||||
"subject": "语文",
|
||||
"ai_provider": "",
|
||||
"ai_model": "",
|
||||
"ai_api_key": "",
|
||||
"ai_base_url": "",
|
||||
"created_at": "2025-11-17T15:00:50.660112"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"username": "zhu1ku1",
|
||||
"password_hash": "4e4f9a130c7a4bdbf1090a190836b72b$574747ced27254f92f626ad6ff91c793060a53399400f87a5f4c45ee7cb26568",
|
||||
"grade": "大学",
|
||||
"subject": "英语",
|
||||
"ai_provider": "",
|
||||
"ai_model": "",
|
||||
"ai_api_key": "",
|
||||
"ai_base_url": "",
|
||||
"created_at": "2025-11-19T14:02:58.670260"
|
||||
}
|
||||
]
|
||||
Loading…
Reference in new issue