feat: release v0.74.0 - Chrome Bridge 浏览器自动化集成

🎉 重大功能
- Chrome Bridge: 完整的浏览器自动化控制系统
- 零配置自动连接:扩展自动加载和配置
- AI 原生集成:作为 MCP 工具支持自然语言控制
- 支持导航、页面读取、元素交互、表单操作等

🐛 Bug 修复
- WebSocket 路由修复 (Axum 路径参数语法)
- Chrome 扩展存储清理
- 扩展重复注入防护
- 剪贴板权限添加

🔧 代码质量
- 修复 33+ Clippy 警告
- 所有 259 个测试通过
- ESLint 无警告

📝 文档
- Chrome Bridge 使用指南
- API 技术文档
- 快速参考卡片
This commit is contained in:
coso
2026-02-28 16:05:36 +08:00
parent 0686737331
commit cd95cac72f
108 changed files with 18916 additions and 1921 deletions
+6
View File
@@ -0,0 +1,6 @@
//! 主题模块聚合
//!
//! 按主题组织前后端能力,支持渐进式迁移。
pub mod novel;
pub mod video;
+93
View File
@@ -0,0 +1,93 @@
//! 小说主题命令适配层
//!
//! 提供 novel tauri commands 的主题化实现入口。
use crate::database::DbConnection;
use crate::services::novel_service::{
NovelCheckConsistencyRequest, NovelCreateProjectRequest, NovelGenerateChapterRequest,
NovelGenerateRequest, NovelGenerateResult, NovelGenerationRun, NovelListRunsRequest,
NovelPolishChapterRequest, NovelProject, NovelProjectSnapshot, NovelRewriteChapterRequest,
NovelSettingsRecord, NovelUpdateSettingsRequest,
};
use tauri::State;
fn service(db: &State<'_, DbConnection>) -> crate::services::novel_service::NovelService {
crate::services::novel_service::NovelService::new(db.inner().clone())
}
pub async fn novel_create_project(
db: State<'_, DbConnection>,
request: NovelCreateProjectRequest,
) -> Result<NovelProject, String> {
service(&db).create_project(request)
}
pub async fn novel_update_settings(
db: State<'_, DbConnection>,
request: NovelUpdateSettingsRequest,
) -> Result<NovelSettingsRecord, String> {
service(&db).update_settings(request)
}
pub async fn novel_generate_outline(
db: State<'_, DbConnection>,
request: NovelGenerateRequest,
) -> Result<NovelGenerateResult, String> {
service(&db).generate_outline(request).await
}
pub async fn novel_generate_characters(
db: State<'_, DbConnection>,
request: NovelGenerateRequest,
) -> Result<NovelGenerateResult, String> {
service(&db).generate_characters(request).await
}
pub async fn novel_generate_chapter(
db: State<'_, DbConnection>,
request: NovelGenerateChapterRequest,
) -> Result<NovelGenerateResult, String> {
service(&db).generate_chapter(request).await
}
pub async fn novel_continue_chapter(
db: State<'_, DbConnection>,
request: NovelGenerateRequest,
) -> Result<NovelGenerateResult, String> {
service(&db).continue_chapter(request).await
}
pub async fn novel_rewrite_chapter(
db: State<'_, DbConnection>,
request: NovelRewriteChapterRequest,
) -> Result<NovelGenerateResult, String> {
service(&db).rewrite_chapter(request).await
}
pub async fn novel_polish_chapter(
db: State<'_, DbConnection>,
request: NovelPolishChapterRequest,
) -> Result<NovelGenerateResult, String> {
service(&db).polish_chapter(request).await
}
pub async fn novel_check_consistency(
db: State<'_, DbConnection>,
request: NovelCheckConsistencyRequest,
) -> Result<crate::services::novel_service::NovelConsistencyCheck, String> {
service(&db).check_consistency(request)
}
pub async fn novel_get_project_snapshot(
db: State<'_, DbConnection>,
project_id: String,
) -> Result<NovelProjectSnapshot, String> {
service(&db).get_project_snapshot(&project_id)
}
pub async fn novel_list_runs(
db: State<'_, DbConnection>,
request: NovelListRunsRequest,
) -> Result<Vec<NovelGenerationRun>, String> {
service(&db).list_runs(request)
}
+3
View File
@@ -0,0 +1,3 @@
//! 小说主题模块
pub mod command;
+84
View File
@@ -0,0 +1,84 @@
//! 视频主题命令适配层
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use tauri::State;
use crate::commands::api_key_provider_cmd::ApiKeyProviderServiceState;
use crate::database::DbConnection;
use proxycast_core::database::dao::video_generation_task_dao::VideoGenerationTask;
use proxycast_services::video_generation_service::{
CreateVideoGenerationRequest, VideoGenerationService,
};
static VIDEO_GENERATION_SERVICE: Lazy<VideoGenerationService> =
Lazy::new(VideoGenerationService::new);
/// 获取视频任务请求参数
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetVideoTaskRequest {
pub task_id: String,
pub refresh_status: Option<bool>,
}
/// 列表视频任务请求参数
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListVideoTasksRequest {
pub project_id: String,
pub limit: Option<i64>,
}
/// 取消视频任务请求参数
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CancelVideoTaskRequest {
pub task_id: String,
}
pub async fn create_video_generation_task(
db: State<'_, DbConnection>,
api_key_provider_service: State<'_, ApiKeyProviderServiceState>,
request: CreateVideoGenerationRequest,
) -> Result<VideoGenerationTask, String> {
VIDEO_GENERATION_SERVICE
.create_task(&db, &api_key_provider_service.0, request)
.await
}
pub async fn get_video_generation_task(
db: State<'_, DbConnection>,
api_key_provider_service: State<'_, ApiKeyProviderServiceState>,
request: GetVideoTaskRequest,
) -> Result<Option<VideoGenerationTask>, String> {
VIDEO_GENERATION_SERVICE
.get_task(
&db,
&api_key_provider_service.0,
&request.task_id,
request.refresh_status.unwrap_or(true),
)
.await
}
pub fn list_video_generation_tasks(
db: State<'_, DbConnection>,
request: ListVideoTasksRequest,
) -> Result<Vec<VideoGenerationTask>, String> {
VIDEO_GENERATION_SERVICE.list_tasks(
&db,
&request.project_id,
request.limit.unwrap_or(50).clamp(1, 200),
)
}
pub async fn cancel_video_generation_task(
db: State<'_, DbConnection>,
api_key_provider_service: State<'_, ApiKeyProviderServiceState>,
request: CancelVideoTaskRequest,
) -> Result<Option<VideoGenerationTask>, String> {
VIDEO_GENERATION_SERVICE
.cancel_task(&db, &api_key_provider_service.0, &request.task_id)
.await
}
+3
View File
@@ -0,0 +1,3 @@
//! 视频主题模块
pub mod command;