-
Notifications
You must be signed in to change notification settings - Fork 2
feat: split OCR functionality into independent project #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Created TelegramSearchBot.OCR as standalone OCR service - Implemented Redis-based communication between main bot and OCR service - Added Docker support for OCR service deployment - Updated PaddleOCRService to use RPC communication with standalone service - Added comprehensive documentation and configuration files - Maintained backward compatibility with existing OCR functionality The OCR service can now be deployed independently and scaled separately from the main Telegram bot application.
|
Claude finished @ModerRAS's task —— View job 🔍 Code Review: OCR Service SplitI've completed a thorough review of the OCR service split implementation. Here's my detailed analysis: ✅ Overall AssessmentThis is a well-architected implementation that successfully separates OCR functionality into an independent microservice. The design follows good practices for distributed systems. 🏗️ Architecture & DesignStrengths:
Areas for Improvement:
🐛 Potential IssuesCritical Issues:
Minor Issues:
⚡ Performance ConsiderationsGood Practices:
Optimization Opportunities:
🔒 Security AnalysisGood Security Practices:
Security Recommendations:
🧪 Test CoverageCurrent State:
Testing Recommendations:
📋 Specific Code IssuesOCRWorkerService.cs
OCRProcessingService.cs
Dockerfile
README.md
🚀 RecommendationsHigh Priority:
Medium Priority:
Low Priority:
📊 SummaryOverall Score: 8/10 This is a solid implementation that successfully achieves the goal of splitting OCR functionality. The architecture is sound and follows good practices. The main areas for improvement are testing coverage and configuration management. The implementation is production-ready with the recommended fixes, particularly around testing and configuration. View job run: https://github.com/ModerRAS/TelegramSearchBot/actions/runs/19361263374 |
🔍 PR检查报告📋 检查概览
🧪 测试结果
📊 代码质量
📁 测试产物
🔗 相关链接此报告由GitHub Actions自动生成 |
- Modified SubProcessService to automatically detect and launch independent OCR service - Updated OCR service to support both fork mode and standalone mode - Maintained backward compatibility with existing fork mechanism - Added automatic fallback to built-in OCR if independent service is not available - OCR service now supports the original command line arguments: OCR <port> - Enhanced error handling and logging for better debugging The OCR functionality can now work in two modes: 1. Fork mode: Main process automatically forks and launches TelegramSearchBot.OCR 2. Standalone mode: Independent deployment via Docker or direct execution Usage remains exactly the same as before - no changes required for existing deployments.
|
Claude finished @ModerRAS's task —— View job 🔍 Code Review: OCR Service Split ImplementationI've completed a thorough review of the OCR service split implementation. Here's my detailed analysis: ✅ Overall AssessmentThis is a well-architected implementation that successfully separates OCR functionality into an independent microservice. The design follows good practices for distributed systems with Redis-based communication. 🏗️ Architecture & DesignStrengths:
Areas for Improvement:
🐛 Potential IssuesCritical Issues:
Minor Issues:
⚡ Performance ConsiderationsGood Practices:
Optimization Opportunities:
🔒 Security AnalysisGood Security Practices:
Security Recommendations:
🧪 Test CoverageCurrent State:
Testing Recommendations:
📋 Specific Code IssuesOCRWorkerService.cs
OCRProcessingService.cs
Dockerfile
README.md
🚀 RecommendationsHigh Priority:
Medium Priority:
Low Priority:
📊 SummaryOverall Score: 8/10 This is a solid implementation that successfully achieves the goal of splitting OCR functionality. The architecture is sound and follows good practices. The main areas for improvement are testing coverage and configuration management. The implementation is production-ready with the recommended fixes, particularly around testing and configuration. View job run: https://github.com/ModerRAS/TelegramSearchBot/actions/runs/19361263374 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR splits OCR functionality from the main TelegramSearchBot project into an independent service (TelegramSearchBot.OCR) that communicates via Redis queues. The goal is to improve system scalability, maintainability, and fault isolation.
Key Changes:
- Created a new standalone OCR service using .NET 9.0 with PaddleOCR v3.0.1 for text recognition
- Implemented Redis-based asynchronous communication between main service and OCR service using queue pattern (
OCRTasksqueue,OCRResult-{taskId}storage) - Added Docker support with Dockerfile and docker-compose.yml for containerized deployment
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| TelegramSearchBot.sln | Added TelegramSearchBot.OCR project reference to solution |
| TelegramSearchBot/Service/AI/OCR/PaddleOCRService.cs | Updated to parse JSON results from independent OCR service and extract text |
| TelegramSearchBot.OCR/TelegramSearchBot.OCR.csproj | New project file defining OCR service dependencies and .NET 9.0 target |
| TelegramSearchBot.OCR/Program.cs | Entry point configuring hosted service with DI and logging |
| TelegramSearchBot.OCR/Services/OCRWorkerService.cs | Background service consuming OCR tasks from Redis queue |
| TelegramSearchBot.OCR/Services/OCRProcessingService.cs | Core OCR processing logic using PaddleOCR with thread-safe semaphore |
| TelegramSearchBot.OCR/appsettings.json | Configuration file for Redis connection and OCR model settings |
| TelegramSearchBot.OCR/Dockerfile | Multi-stage Docker build for OCR service deployment |
| TelegramSearchBot.OCR/docker-compose.yml | Docker Compose configuration with Redis and OCR service |
| TelegramSearchBot.OCR/README.md | Documentation covering features, deployment, and troubleshooting |
| test-swarm-config.sh | Claude Swarm configuration test script (unrelated to OCR split) |
| private List<Common.Model.Result> ConvertToResults(PaddleOcrResult paddleOcrResult) { | ||
| var results = new List<Result>(); | ||
| foreach (var region in paddleOcrResult.Regions) { | ||
| results.Add(new Common.Model.Result { |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type reference Common.Model.Result is ambiguous. Since TelegramSearchBot.Common.Model is imported on line 12, use either the simple name Result or the fully qualified name TelegramSearchBot.Common.Model.Result for clarity and consistency with C# naming conventions.
| private List<Common.Model.Result> ConvertToResults(PaddleOcrResult paddleOcrResult) { | |
| var results = new List<Result>(); | |
| foreach (var region in paddleOcrResult.Regions) { | |
| results.Add(new Common.Model.Result { | |
| private List<Result> ConvertToResults(PaddleOcrResult paddleOcrResult) { | |
| var results = new List<Result>(); | |
| foreach (var region in paddleOcrResult.Regions) { | |
| results.Add(new Result { |
| public class OCRProcessingService { | ||
| private readonly ILogger<OCRProcessingService> _logger; | ||
| private readonly PaddleOcrAll _ocrAll; | ||
| private static readonly SemaphoreSlim _semaphore = new(1); |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SemaphoreSlim is marked as static but is initialized with new(1), limiting OCR processing to one operation at a time across all instances of OCRProcessingService. If multiple instances of this service are created (which shouldn't happen given it's registered as Singleton, but isn't enforced), they would all share the same semaphore. Consider making this an instance field or explicitly documenting why it must be static.
| private static readonly SemaphoreSlim _semaphore = new(1); | |
| private readonly SemaphoreSlim _semaphore = new(1); |
| // 保存结果 | ||
| var resultKey = $"OCRResult-{taskId}"; | ||
| var resultJson = JsonConvert.SerializeObject(result); | ||
| await _db.StringSetAsync(resultKey, resultJson, TimeSpan.FromMinutes(10)); |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OCR result is stored with a 10-minute expiration (TimeSpan.FromMinutes(10)), but there's no corresponding configuration or documentation about how long the main service should wait for results. If the main service waits indefinitely or with a timeout longer than 10 minutes, it could miss completed results. Consider documenting this timeout or making it configurable to ensure the main service and OCR service are synchronized.
TelegramSearchBot.OCR/Dockerfile
Outdated
| FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base | ||
| WORKDIR /app | ||
|
|
||
| FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Dockerfile uses .NET 7.0 base images (mcr.microsoft.com/dotnet/aspnet:7.0 and mcr.microsoft.com/dotnet/sdk:7.0), but the project file targets net9.0. This mismatch will prevent the application from running in the container. Update to use .NET 9.0 images: mcr.microsoft.com/dotnet/aspnet:9.0 and mcr.microsoft.com/dotnet/sdk:9.0.
| FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base | |
| WORKDIR /app | |
| FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build | |
| FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base | |
| WORKDIR /app | |
| FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build |
| } | ||
| } catch (Exception ex) { | ||
| // 记录解析错误,但不抛出异常 | ||
| Console.WriteLine($"OCR结果解析失败: {ex.Message}"); |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Console.WriteLine for error logging is inconsistent with the project's use of Serilog logging throughout. The error should be logged using an injected ILogger instance instead, which will ensure proper log formatting, levels, and integration with the OpenTelemetry sink mentioned in the project overview.
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFramework>net9.0</TargetFramework> |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The project targets net9.0 but all Microsoft.Extensions packages are using version 7.0.x (lines 11-16). This version mismatch can cause compatibility issues. For .NET 9.0, you should use Microsoft.Extensions.* packages version 9.0.0 to match the target framework and align with the main project's dependencies.
test-swarm-config.sh
Outdated
| #!/bin/bash | ||
|
|
||
| # Claude Swarm 启动测试脚本 | ||
| # 用于测试 TelegramSearchBot AI 开发团队配置 | ||
|
|
||
| echo "🚀 Claude Swarm 配置验证测试" | ||
| echo "=================================" | ||
|
|
||
| # 1. 验证配置文件语法 | ||
| echo "1. 验证配置文件语法..." | ||
| if python3 -c "import yaml; yaml.safe_load(open('claude-swarm.yml', 'r'))"; then | ||
| echo "✅ YAML 语法正确" | ||
| else | ||
| echo "❌ YAML 语法错误" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # 2. 分析配置结构 | ||
| echo "2. 分析配置结构..." | ||
| python3 -c " | ||
| import yaml | ||
| with open('claude-swarm.yml', 'r') as f: | ||
| config = yaml.safe_load(f) | ||
| instances = config.get('swarm', {}).get('instances', {}) | ||
| print(f' 总实例数: {len(instances)}') | ||
| print(f' 主实例: {config.get(\"swarm\", {}).get(\"main\")}') | ||
| # 统计模型使用 | ||
| model_count = {} | ||
| for name, instance in instances.items(): | ||
| model = instance.get('model', 'unknown') | ||
| model_count[model] = model_count.get(model, 0) + 1 | ||
| print(' 模型分布:') | ||
| for model, count in model_count.items(): | ||
| print(f' {model}: {count} 个实例') | ||
| # 检查连接关系 | ||
| connections = {} | ||
| for name, instance in instances.items(): | ||
| connections[name] = instance.get('connections', []) | ||
| # 验证树形结构 | ||
| def has_cycle(graph, node, visited, rec_stack): | ||
| visited[node] = True | ||
| rec_stack[node] = True | ||
| for neighbor in graph.get(node, []): | ||
| if neighbor not in visited: | ||
| if has_cycle(graph, neighbor, visited, rec_stack): | ||
| return True | ||
| elif rec_stack[neighbor]: | ||
| return True | ||
| rec_stack[node] = False | ||
| return False | ||
| visited = {} | ||
| rec_stack = {} | ||
| has_cycle_detected = False | ||
| for node in connections: | ||
| if node not in visited: | ||
| if has_cycle(connections, node, visited, rec_stack): | ||
| has_cycle_detected = True | ||
| break | ||
| if has_cycle_detected: | ||
| print(' ❌ 发现循环依赖') | ||
| else: | ||
| print(' ✅ 树形结构正确,无循环依赖') | ||
| " | ||
|
|
||
| # 3. 验证项目依赖 | ||
| echo "3. 验证项目依赖..." | ||
| if [ -f "TelegramSearchBot.sln" ]; then | ||
| echo "✅ 找到解决方案文件" | ||
| if dotnet restore TelegramSearchBot.sln --verbosity quiet; then | ||
| echo "✅ 项目依赖恢复成功" | ||
| else | ||
| echo "⚠️ 项目依赖恢复失败(可能是网络问题)" | ||
| fi | ||
| else | ||
| echo "❌ 未找到解决方案文件" | ||
| fi | ||
|
|
||
| # 4. 验证目录结构 | ||
| echo "4. 验证目录结构..." | ||
| required_dirs=("TelegramSearchBot" "TelegramSearchBot.Test") | ||
| for dir in "${required_dirs[@]}"; do | ||
| if [ -d "$dir" ]; then | ||
| echo "✅ $dir 目录存在" | ||
| else | ||
| echo "❌ $dir 目录不存在" | ||
| fi | ||
| done | ||
|
|
||
| echo "" | ||
| echo "🎉 配置验证完成!" | ||
| echo "" | ||
| echo "📋 配置摘要:" | ||
| echo " - 团队名称: TelegramSearchBot AI Development Team" | ||
| echo " - 总角色数: 29个专业角色" | ||
| echo " - 架构层次: 4层树形结构" | ||
| echo " - 主模型: Opus (11个实例) + Sonnet (18个实例)" | ||
| echo " - 叶子节点: 21个专项专家" | ||
| echo "" | ||
| echo "🚀 要启动团队,请运行: claude-swarm start claude-swarm.yml" | ||
| echo " (注意: 需要交互式终端输入)" No newline at end of file |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] This test script for Claude Swarm configuration appears unrelated to the OCR service split described in the PR. Including unrelated changes in a feature PR reduces clarity and makes it harder to review and track changes. Consider moving this to a separate PR or removing it if it was added by mistake.
| } | ||
| return string.Join(" ", textResults.Where(t => !string.IsNullOrWhiteSpace(t))); | ||
| } | ||
| } catch (Exception ex) { |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic catch clause.
| } catch (Exception ex) { | |
| } catch (JsonException ex) { |
| } catch (Exception ex) { | ||
| _logger.LogError(ex, "处理OCR任务时发生错误"); | ||
| // 等待一段时间后继续 | ||
| await Task.Delay(5000, stoppingToken); | ||
| } |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic catch clause.
| } catch (Exception ex) { | ||
| _logger.LogError(ex, "OCR处理失败"); | ||
| return new PaddleOCRResult { | ||
| Results = new List<List<Result>>(), | ||
| Status = "1", | ||
| Message = ex.Message | ||
| }; | ||
| } |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic catch clause.
- Created TelegramSearchBot.OCR as a class library project - Moved OCR processing logic from PaddleOCR.cs to OCRService.cs - Updated OCRBootstrap to use the new OCR library - Maintained exact same fork behavior and API compatibility - All OCR functionality now resides in the independent library - Main project references the OCR library as a project reference The OCR functionality is now properly decoupled into a separate library while maintaining: - Same fork mechanism: main process forks itself with OCR args - Same Redis communication protocol - Same OCR processing pipeline - Same API interfaces and behavior This provides better code organization and maintainability without changing any runtime behavior.
|
Claude finished @ModerRAS's task —— View job 🔍 Code Review: OCR Service Split ImplementationI've completed a thorough review of the OCR service split implementation. Here's my detailed analysis focusing on code quality, best practices, potential issues, performance, security, and test coverage. ✅ Overall AssessmentThis is a well-architected implementation that successfully separates OCR functionality into an independent microservice. The design follows good practices for distributed systems with Redis-based communication. 🏗️ Architecture & DesignStrengths:
Areas for Improvement:
🐛 Potential IssuesCritical Issues:
Minor Issues:
⚡ Performance ConsiderationsGood Practices:
Optimization Opportunities:
🔒 Security AnalysisGood Security Practices:
Security Recommendations:
🧪 Test CoverageCurrent State:
Testing Recommendations:
📋 Specific Code IssuesOCRBootstrap.cs
OCRService.cs
OCRProcessingService.cs
PaddleOCRService.cs
🚀 RecommendationsHigh Priority:
Medium Priority:
Low Priority:
📊 SummaryOverall Score: 7.5/10 This implementation successfully achieves the goal of splitting OCR functionality into an independent service. The architecture is sound and follows good practices. The main areas for improvement are testing coverage, configuration management, and consolidation of duplicate services. The implementation would benefit from addressing the critical issues around task loss and resource management before production deployment. Key Strengths:
Key Areas for Improvement:
View job run: https://github.com/ModerRAS/TelegramSearchBot/actions/runs/19361263374 |
- 修复了PaddleOCRService中的命名空间引用问题 - 确保主项目优先使用内置的PaddleOCR类而不是OCR库中的类 - 保持了OCRBootstrap的原有逻辑不变 - 通过RPC机制调用OCR服务,实现了完全的模块化拆分
|
Claude finished @ModerRAS's task —— View job 🔍 Code Review: OCR Service Split ImplementationI've completed a thorough review of the OCR service split implementation. Here's my detailed analysis focusing on code quality, best practices, potential issues, performance, security, and test coverage. ✅ Overall AssessmentThis is a well-architected implementation that successfully separates OCR functionality into an independent service. The design follows good practices for distributed systems with Redis-based communication. 🏗️ Architecture & DesignStrengths:
Areas for Improvement:
🐛 Potential IssuesCritical Issues:
Minor Issues:
⚡ Performance ConsiderationsGood Practices:
Optimization Opportunities:
🔒 Security AnalysisGood Security Practices:
Security Recommendations:
🧪 Test CoverageCurrent State:
Testing Recommendations:
📋 Specific Code IssuesOCRBootstrap.cs
OCRService.cs
OCRProcessingService.cs
PaddleOCRService.cs
🚀 RecommendationsHigh Priority:
Medium Priority:
Low Priority:
📊 SummaryOverall Score: 7.5/10 This implementation successfully achieves the goal of splitting OCR functionality into an independent service. The architecture is sound and follows good practices. The main areas for improvement are testing coverage, configuration management, and consolidation of duplicate services. The implementation would benefit from addressing the critical issues around task loss and resource management before production deployment. Key Strengths:
Key Areas for Improvement:
View job run: https://github.com/ModerRAS/TelegramSearchBot/actions/runs/19361895319 |
- 回退了PaddleOCRService中错误的using语句删除 - PaddleOCRService作为RPC中间件,逻辑保持不变 - 删除了误提交的测试脚本test-swarm-config.sh - 确保主项目优先使用内置PaddleOCR类 - 保持完全的向后兼容性
|
I'll analyze this and get back to you. |
- 回退PaddleOCRService到master分支的原始状态 - 保持简单逻辑:图片转base64 -> RPC调用 -> 返回结果 - 删除所有不必要的JSON序列化/反序列化逻辑 - PaddleOCRService作为RPC中间件,不需要知道OCR具体实现 - 真正的OCR逻辑在Manager/PaddleOCR.cs中保持不变
|
Claude finished @ModerRAS's task —— View job 🔍 Code Review: OCR Service Split ImplementationI've completed a thorough review of the OCR service split implementation. Here's my detailed analysis focusing on code quality, best practices, potential issues, performance, security, and test coverage. ✅ Overall AssessmentThis is a well-architected implementation that successfully separates OCR functionality into an independent microservice. The design follows good practices for distributed systems with Redis-based communication. 🏗️ Architecture & DesignStrengths:
Areas for Improvement:
🐛 Potential IssuesCritical Issues:
Minor Issues:
⚡ Performance ConsiderationsGood Practices:
Optimization Opportunities:
🔒 Security AnalysisGood Security Practices:
Security Recommendations:
🧪 Test CoverageCurrent State:
Testing Recommendations:
📋 Specific Code IssuesOCRBootstrap.cs
OCRService.cs
OCRProcessingService.cs
PaddleOCRService.cs
🚀 RecommendationsHigh Priority:
Medium Priority:
Low Priority:
📊 SummaryOverall Score: 7.5/10 This implementation successfully achieves the goal of splitting OCR functionality into an independent service. The architecture is sound and follows good practices. The main areas for improvement are testing coverage, configuration management, and consolidation of duplicate services. The implementation would benefit from addressing the critical issues around task loss and resource management before production deployment. Key Strengths:
Key Areas for Improvement:
View job run: https://github.com/ModerRAS/TelegramSearchBot/actions/runs/19361895319 |
- OCR项目中的PaddleOCR.cs现在与master分支的Manager/PaddleOCR.cs完全一致 - 只修改了命名空间从TelegramSearchBot.Manager改为TelegramSearchBot.OCR - OCRBootstrap简化成与原始OCRBootstrap相同的简单逻辑 - 删除了不必要的OCRService和OCRProcessingService文件 - 保持完全的向后兼容性,零侵入性修改
|
Claude finished @ModerRAS's task —— View job 🔍 Code Review: OCR Service Split ImplementationI've completed a thorough review of the OCR service split implementation. Here's my detailed analysis focusing on code quality, best practices, potential issues, performance considerations, security concerns, and test coverage. ✅ Overall AssessmentThis is a well-architected implementation that successfully separates OCR functionality into an independent service. The design follows good practices for distributed systems with Redis-based communication. 🏗️ Architecture & DesignStrengths:
Areas for Improvement:
🐛 Potential IssuesCritical Issues:
Minor Issues:
⚡ Performance ConsiderationsGood Practices:
Optimization Opportunities:
🔒 Security AnalysisGood Security Practices:
Security Recommendations:
🧪 Test CoverageCurrent State:
Testing Recommendations:
📋 Specific Code IssuesOCRBootstrap.cs
PaddleOCR.cs
TelegramSearchBot.OCR.csproj
SubProcessService.cs
🚀 RecommendationsHigh Priority:
Medium Priority:
Low Priority:
📊 SummaryOverall Score: 7.5/10 This implementation successfully achieves the goal of splitting OCR functionality into an independent service. The architecture is sound and follows good practices. The main areas for improvement are testing coverage, configuration management, and task retry mechanism. The implementation would benefit from addressing the critical issues around task loss and resource management before production deployment. Key Strengths:
Key Areas for Improvement:
View job run: https://github.com/ModerRAS/TelegramSearchBot/actions/runs/19362075686 |

🎯 目标
将OCR功能从主项目中拆分出来,形成独立的服务,提高系统的可扩展性和维护性。
📋 变更内容
✨ 新增功能
🔧 技术实现
🔄 向后兼容
🚀 部署方式
本地开发
cd TelegramSearchBot.OCR && dotnet run
Docker部署
docker-compose up -d
📈 性能优势
✅ 测试验证
这个拆分让系统架构更加清晰,为未来的功能扩展和性能优化提供了更好的基础。