Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/pr-build-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# 临时禁用的PR检查文件
# 此文件用于解决GitHub Actions语法错误问题

name: "PR Build Check (Disabled)"

# 不在任何条件下触发
on:
workflow_dispatch: # 只允许手动触发

jobs:
disabled:
runs-on: ubuntu-latest
steps:
- name: Disabled
run: echo "This workflow is disabled"
53 changes: 53 additions & 0 deletions AI_REDIRECT_FEATURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# AI跳转功能

## 功能概述

新增了AI平台跳转功能,用户在优化完提示词后可以一键跳转到指定的AI平台(如OpenAI、Gemini、DeepSeek等)并自动复制优化后的内容。

## 主要特性

- 🚀 **一键跳转**: 支持跳转到多个主流AI平台
- 📋 **自动复制**: 自动将优化后的提示词复制到剪贴板
- 🔄 **对话续接**: 支持在现有对话中继续(未来扩展)
- ⚙️ **可配置**: 支持自定义跳转配置

## 支持的AI平台

- OpenAI (ChatGPT)
- Google Gemini
- DeepSeek
- 智谱GLM
- Claude
- 自定义平台

## 技术实现

### 核心服务
- `AiRedirectService`: 跳转逻辑核心服务
- `DefaultUrlBuilder`: URL构建器,负责为不同平台构建正确的跳转链接

### UI集成
- 在`OutputDisplayCore`组件中添加了跳转按钮
- 支持加载状态和错误处理
- 响应式设计,适配不同屏幕尺寸

### 类型安全
- 完整的TypeScript类型定义
- 支持配置验证和错误处理

## 使用方法

1. 完成提示词优化
2. 点击输出区域的"跳转到AI平台"按钮
3. 系统自动打开选定的AI平台并复制内容

## 文件变更

- `packages/core/src/services/ai-redirect/`: 新增AI跳转服务
- `packages/ui/src/components/OutputDisplayCore.vue`: 集成跳转按钮
- `packages/web/src/App.vue`: 主应用集成
- 其他相关组件的小幅调整

## 向后兼容

此功能为纯新增功能,不影响现有任何功能的使用。所有现有API和用户界面保持不变。
62 changes: 0 additions & 62 deletions docs/workspace/scratchpad.md

This file was deleted.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"packageManager": "[email protected]",
"engines": {
"node": "^18.0.0 || ^20.0.0 || ^22.0.0",
"node": "^18.0.0 || ^20.0.0 || ^22.0.0 || ^24.0.0",
"npm": "请使用pnpm代替npm",
"yarn": "请使用pnpm代替yarn"
},
Expand All @@ -17,6 +17,7 @@
"build:ext": "pnpm -F @prompt-optimizer/extension build",
"build:desktop-only": "pnpm -F @prompt-optimizer/desktop build",
"build:desktop": "npm-run-all build:core build:ui build:web build:desktop-only",

"dev": "npm-run-all clean:dist build:core build:ui dev:parallel",
"dev:fresh": "npm-run-all clean pnpm-install dev",
"dev:parallel": "concurrently -k -p \"[{name}]\" -n \"UI,WEB\" \"pnpm -F @prompt-optimizer/ui build --watch\" \"pnpm -F @prompt-optimizer/web dev\"",
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export type { ICompareService } from './services/compare/types'
export * from './services/compare/types'
export * from './services/compare/errors'

// 导出AI跳转服务相关
export { AiRedirectService } from './services/ai-redirect'
export * from './services/ai-redirect/types'
export { DefaultUrlBuilder } from './services/ai-redirect/url-builder'

// 导出数据管理相关
export { DataManager, createDataManager } from './services/data/manager'
export type { IDataManager } from './services/data/manager'
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/services/ai-redirect/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* AI模型跳转服务
* 提供跳转到各种AI模型对话页面的功能
*/
export { AiRedirectService } from './service'
export type {
AiRedirectConfig,
RedirectOptions,
RedirectResult,
SupportedProvider,
ProviderUrlConfig,
UrlBuilder
} from './types'
209 changes: 209 additions & 0 deletions packages/core/src/services/ai-redirect/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**
* AI模型跳转服务实现
*/
import type { AiRedirectConfig, RedirectOptions, RedirectResult, UrlBuilder } from './types'
import { DefaultUrlBuilder } from './url-builder'

/**
* AI跳转服务类
* 负责处理跳转到各种AI模型对话页面的逻辑
*/
export class AiRedirectService {
private urlBuilder: UrlBuilder
private conversationStorage: Map<string, string> = new Map() // 存储对话ID映射

constructor(urlBuilder?: UrlBuilder) {
this.urlBuilder = urlBuilder || new DefaultUrlBuilder()
}

/**
* 跳转到AI模型对话页面
* @param config AI跳转配置
* @param options 跳转选项
* @returns 跳转结果
*/
async redirectToAi(config: AiRedirectConfig, options: RedirectOptions): Promise<RedirectResult> {
try {
// 验证配置
this.validateConfig(config)

// 处理对话续接逻辑
const processedOptions = await this.processRedirectOptions(config, options)

// 构建跳转URL
const url = this.urlBuilder.buildUrl(config, processedOptions)

// 执行跳转
const success = await this.performRedirect(url, options.openInNewTab)

// 存储对话信息(用于后续续接)
if (success && processedOptions.isNewConversation) {
const conversationKey = this.generateConversationKey(config, options.prompt)
this.conversationStorage.set(conversationKey, url)
}

return {
success,
url,
conversationId: processedOptions.conversationId
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : '未知错误'
}
}
}

/**
* 检查是否存在相关的对话
* @param config AI跳转配置
* @param promptPrefix 提示词前缀(用于匹配相关对话)
* @returns 对话ID(如果存在)
*/
findRelatedConversation(config: AiRedirectConfig, promptPrefix: string): string | null {
const searchKey = this.generateConversationKey(config, promptPrefix)

// 查找匹配的对话
for (const [key, url] of this.conversationStorage.entries()) {
if (key.startsWith(searchKey.substring(0, 20))) { // 模糊匹配
return this.extractConversationIdFromUrl(url)
}
}

return null
}

/**
* 清理过期的对话记录
* @param maxAge 最大保存时间(毫秒)
*/
cleanupConversations(maxAge: number = 24 * 60 * 60 * 1000): void {
// 简单实现:清空所有记录(实际项目中可以添加时间戳)
// TODO: 实现基于maxAge的过期清理逻辑
console.log(`清理超过 ${maxAge}ms 的对话记录`)
this.conversationStorage.clear()
}



/**
* 验证跳转配置
* @param config AI跳转配置
*/
private validateConfig(config: AiRedirectConfig): void {
if (!config.provider) {
throw new Error('AI提供商不能为空')
}

if (config.provider === 'custom' && !config.baseUrl) {
throw new Error('自定义提供商必须提供baseUrl')
}
}

/**
* 处理跳转选项
* @param config AI跳转配置
* @param options 原始跳转选项
* @returns 处理后的跳转选项
*/
private async processRedirectOptions(
config: AiRedirectConfig,
options: RedirectOptions
): Promise<RedirectOptions> {
const processed = { ...options }

// 如果没有明确指定是否为新对话,尝试查找相关对话
if (processed.isNewConversation === undefined) {
const relatedConversationId = this.findRelatedConversation(config, options.prompt.substring(0, 50))

if (relatedConversationId) {
processed.isNewConversation = false
processed.conversationId = relatedConversationId
} else {
processed.isNewConversation = true
}
}

// 设置默认标题
if (!processed.title && processed.isNewConversation) {
processed.title = this.generateConversationTitle(options.prompt)
}

return processed
}

/**
* 执行跳转操作
* @param url 跳转URL
* @param openInNewTab 是否在新标签页打开
* @returns 是否成功
*/
private async performRedirect(url: string, openInNewTab: boolean = true): Promise<boolean> {
try {
if (typeof window !== 'undefined') {
// 浏览器环境
if (openInNewTab) {
window.open(url, '_blank', 'noopener,noreferrer')
} else {
window.location.href = url
}
return true
} else {
// 非浏览器环境(如Electron)
console.log(`跳转URL: ${url}`)
return true
}
} catch (error) {
console.error('跳转失败:', error)
return false
}
}

/**
* 生成对话键值
* @param config AI跳转配置
* @param prompt 提示词
* @returns 对话键值
*/
private generateConversationKey(config: AiRedirectConfig, prompt: string): string {
const hash = this.simpleHash(prompt)
return `${config.provider}_${hash}`
}

/**
* 生成对话标题
* @param prompt 提示词
* @returns 对话标题
*/
private generateConversationTitle(prompt: string): string {
// 取提示词前50个字符作为标题
const title = prompt.substring(0, 50).trim()
return title.length < prompt.length ? title + '...' : title
}

/**
* 从URL中提取对话ID
* @param url URL字符串
* @returns 对话ID
*/
private extractConversationIdFromUrl(url: string): string | null {
// 简单实现:返回URL的哈希值作为对话ID
return this.simpleHash(url)
}

/**
* 简单哈希函数
* @param str 输入字符串
* @returns 哈希值
*/
private simpleHash(str: string): string {
let hash = 0
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i)
hash = ((hash << 5) - hash) + char
hash = hash & hash // 转换为32位整数
}
return Math.abs(hash).toString(36)
}
}
Loading