diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index fb616b266..4340e4c92 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -3024,115 +3024,6 @@ class ProjectController extends AbstractController return Base::retSuccess('复制成功', $data); } - /** - * @api {post} api/project/task/ai_generate 使用 AI 助手生成任务 - * - * @apiDescription 需要token身份,使用AI根据用户输入和上下文信息生成任务标题和详细描述 - * @apiVersion 1.0.0 - * @apiGroup project - * @apiName task__ai_generate - * - * @apiParam {String} content 用户输入的任务描述(必填) - * @apiParam {String} [current_title] 当前已有的任务标题(用于优化改进) - * @apiParam {String} [current_content] 当前已有的任务内容(HTML格式,用于优化改进) - * @apiParam {String} [template_name] 选中的任务模板名称 - * @apiParam {String} [template_content] 选中的任务模板内容(HTML格式) - * @apiParam {Boolean} [has_owner] 是否已设置负责人 - * @apiParam {Boolean} [has_time_plan] 是否已设置计划时间 - * @apiParam {String} [priority_level] 任务优先级等级名称 - * - * @apiSuccess {Number} ret 返回状态码(1正确、0错误) - * @apiSuccess {String} msg 返回信息(错误描述) - * @apiSuccess {Object} data 返回数据 - * @apiSuccess {String} data.title AI 生成的任务标题 - * @apiSuccess {String} data.content AI 生成的任务内容(HTML 格式) - * @apiSuccess {Array} data.subtasks 当任务较复杂时生成的子任务名称列表 - */ - public function task__ai_generate() - { - User::auth(); - - // 获取用户输入的任务描述 - $content = Request::input('content'); - if (empty($content)) { - return Base::retError('任务描述不能为空'); - } - - // 获取上下文信息 - $context = [ - 'current_title' => Request::input('current_title', ''), - 'current_content' => Request::input('current_content', ''), - 'template_name' => Request::input('template_name', ''), - 'template_content' => Request::input('template_content', ''), - 'has_owner' => boolval(Request::input('has_owner', false)), - 'has_time_plan' => boolval(Request::input('has_time_plan', false)), - 'priority_level' => Request::input('priority_level', ''), - ]; - - // 如果当前内容是HTML格式,转换为markdown - if (!empty($context['current_content'])) { - $context['current_content'] = Base::html2markdown($context['current_content']); - } - if (!empty($context['template_content'])) { - $context['template_content'] = Base::html2markdown($context['template_content']); - } - - $result = AI::generateTask($content, $context); - if (Base::isError($result)) { - return Base::retError('生成任务失败', $result); - } - return Base::retSuccess('生成任务成功', $result['data']); - } - - /** - * @api {post} api/project/ai/generate 使用 AI 助手生成项目 - * - * @apiDescription 需要token身份,根据需求说明自动生成项目名称及任务列表 - * @apiVersion 1.0.0 - * @apiGroup project - * @apiName ai__generate - * - * @apiParam {String} content 项目需求或背景描述(必填) - * @apiParam {String} [current_name] 当前草拟的项目名称 - * @apiParam {Array|String} [current_columns] 已有任务列表(数组或以逗号/换行分隔的字符串) - * @apiParam {Array} [template_examples] 可参考的模板示例,格式:[ {name: 模板名, columns: [列表...] }, ... ] - * - * @apiSuccess {Number} ret 返回状态码(1正确、0错误) - * @apiSuccess {String} msg 返回信息(错误描述) - * @apiSuccess {Object} data 返回数据 - * @apiSuccess {String} data.name AI 生成的项目名称 - * @apiSuccess {Array} data.columns AI 生成的任务列表名称数组 - */ - public function ai__generate() - { - User::auth(); - - $content = trim((string)Request::input('content', '')); - if ($content === '') { - return Base::retError('项目需求描述不能为空'); - } - - $templateExamples = Request::input('template_examples', []); - if (!is_array($templateExamples)) { - $templateExamples = []; - } else { - $templateExamples = array_slice($templateExamples, 0, 6); - } - - $context = [ - 'current_name' => Request::input('current_name', ''), - 'current_columns' => Request::input('current_columns', []), - 'template_examples' => $templateExamples, - ]; - - $result = AI::generateProject($content, $context); - if (Base::isError($result)) { - return Base::retError('生成项目失败', $result); - } - - return Base::retSuccess('生成项目成功', $result['data']); - } - /** * @api {get} api/project/flow/list 工作流列表 * diff --git a/app/Module/AI.php b/app/Module/AI.php index 0152880e0..e81b39c02 100644 --- a/app/Module/AI.php +++ b/app/Module/AI.php @@ -318,244 +318,6 @@ class AI return $result; } - /** - * 通过 openAI 生成任务标题和描述 - * @param string $text 用户提供的提示词 - * @param array $context 上下文信息 - * @return array - */ - public static function generateTask($text, $context = []) - { - // 构建上下文提示信息 - $contextPrompt = self::buildTaskContextPrompt($context); - - $post = json_encode([ - "model" => "gpt-5-mini", - "reasoning_effort" => "minimal", - "messages" => [ - [ - "role" => "system", - "content" => << "user", - "content" => $contextPrompt . "\n\n请根据以上上下文并结合以下提示词生成一个完整的项目任务(包含标题和详细描述):\n\n" . $text - ] - ], - ]); - - $ai = new self($post); - $ai->setTimeout(60); - - $res = $ai->request(); - if (Base::isError($res)) { - return Base::retError("任务生成失败", $res); - } - - // 清理可能的markdown代码块标记 - $content = $res['data']; - $content = preg_replace('/^\s*```json\s*/', '', $content); - $content = preg_replace('/\s*```\s*$/', '', $content); - - if (empty($content)) { - return Base::retError("任务生成结果为空"); - } - - // 解析JSON - $parsedData = Base::json2array($content); - if (!$parsedData || !isset($parsedData['title']) || !isset($parsedData['content'])) { - return Base::retError("任务生成格式错误", $content); - } - - $title = trim($parsedData['title']); - $markdownContent = trim($parsedData['content']); - $rawSubtasks = $parsedData['subtasks'] ?? []; - - if (empty($title) || empty($markdownContent)) { - return Base::retError("生成的任务标题或内容为空", $parsedData); - } - - $subtasks = []; - if (is_array($rawSubtasks)) { - foreach ($rawSubtasks as $raw) { - if (is_array($raw)) { - $name = trim($raw['title'] ?? $raw['name'] ?? ''); - } else { - $name = trim($raw); - } - - if (!empty($name)) { - $subtasks[] = $name; - } - - if (count($subtasks) >= 8) { - break; - } - } - } - - return Base::retSuccess("success", [ - 'title' => $title, - 'content' => Base::markdown2html($markdownContent), // 将 Markdown 转换为 HTML - 'subtasks' => $subtasks - ]); - } - - /** - * 通过 openAI 生成项目名称与任务列表 - * @param string $text 用户提供的提示词 - * @param array $context 上下文信息 - * @return array - */ - public static function generateProject($text, $context = []) - { - $text = trim((string)$text); - if ($text === '') { - return Base::retError("项目提示词不能为空"); - } - - $context['current_name'] = trim($context['current_name'] ?? ''); - $context['current_columns'] = self::normalizeProjectColumns($context['current_columns'] ?? []); - - if (!empty($context['template_examples']) && is_array($context['template_examples'])) { - $examples = []; - foreach ($context['template_examples'] as $item) { - $name = trim($item['name'] ?? ''); - $columns = self::normalizeProjectColumns($item['columns'] ?? []); - if (empty($columns)) { - continue; - } - $examples[] = [ - 'name' => $name, - 'columns' => $columns, - ]; - if (count($examples) >= 6) { - break; - } - } - $context['template_examples'] = $examples; - } else { - $context['template_examples'] = []; - } - - $contextPrompt = self::buildProjectContextPrompt($context); - - $post = json_encode([ - "model" => "gpt-5-mini", - "reasoning_effort" => "minimal", - "messages" => [ - [ - "role" => "system", - "content" => << "user", - "content" => ($contextPrompt ? $contextPrompt . "\n\n" : "") . "请根据以上信息,并结合以下提示词生成适合的项目名称和任务列表:\n\n" . $text - ], - ], - ]); - - $ai = new self($post); - $ai->setTimeout(45); - - $res = $ai->request(); - if (Base::isError($res)) { - return Base::retError("项目生成失败", $res); - } - - $content = $res['data']; - $content = preg_replace('/^\s*```json\s*/', '', $content); - $content = preg_replace('/\s*```\s*$/', '', $content); - - if (empty($content)) { - return Base::retError("项目生成结果为空"); - } - - $parsedData = Base::json2array($content); - if (!$parsedData || !isset($parsedData['name'])) { - return Base::retError("项目生成格式错误", $content); - } - - $name = trim($parsedData['name']); - $columns = self::normalizeProjectColumns($parsedData['columns'] ?? []); - - if ($name === '') { - return Base::retError("生成的项目名称为空", $parsedData); - } - - if (empty($columns)) { - $columns = $context['current_columns']; - } - - return Base::retSuccess("success", [ - 'name' => $name, - 'columns' => $columns, - ]); - } - /** * 对工作汇报内容进行分析 * @param Report $report @@ -685,194 +447,6 @@ class AI ]); } - /** - * 构建任务生成的上下文提示信息 - * @param array $context 上下文信息 - * @return string - */ - private static function buildTaskContextPrompt($context) - { - $prompts = []; - - // 当前任务信息 - if (!empty($context['current_title']) || !empty($context['current_content'])) { - $prompts[] = "## 当前任务信息"; - if (!empty($context['current_title'])) { - $prompts[] = "当前标题:" . $context['current_title']; - } - if (!empty($context['current_content'])) { - $prompts[] = "当前内容:" . $context['current_content']; - } - $prompts[] = "请在此基础上优化改进,而不是完全重写。"; - } - - // 任务模板信息 - if (!empty($context['template_name']) || !empty($context['template_content'])) { - $prompts[] = "## 任务模板要求"; - if (!empty($context['template_name'])) { - $prompts[] = "模板名称:" . $context['template_name']; - } - if (!empty($context['template_content'])) { - $prompts[] = "模板内容结构:" . $context['template_content']; - } - $prompts[] = "请严格按照此模板的结构和格式要求生成内容。"; - } - - // 项目状态信息 - $statusInfo = []; - if (!empty($context['has_owner'])) { - $statusInfo[] = "已设置负责人"; - } - if (!empty($context['has_time_plan'])) { - $statusInfo[] = "已设置计划时间"; - } - if (!empty($context['priority_level'])) { - $statusInfo[] = "优先级:" . $context['priority_level']; - } - - if (!empty($statusInfo)) { - $prompts[] = "## 任务状态"; - $prompts[] = implode(",", $statusInfo); - $prompts[] = "请在任务描述中体现相应的要求和约束。"; - } - - return empty($prompts) ? "" : implode("\n", $prompts); - } - - private static function buildProjectContextPrompt($context) - { - $prompts = []; - - if (!empty($context['current_name']) || !empty($context['current_columns'])) { - $prompts[] = "## 当前项目草稿"; - if (!empty($context['current_name'])) { - $prompts[] = "已有名称:" . $context['current_name']; - } - if (!empty($context['current_columns'])) { - $prompts[] = "现有任务列表:" . implode("、", $context['current_columns']); - } - $prompts[] = "请在此基础上进行优化和补充。"; - } - - if (!empty($context['template_examples'])) { - $prompts[] = "## 常用模板示例"; - foreach ($context['template_examples'] as $example) { - $line = ''; - if (!empty($example['name'])) { - $line .= $example['name'] . ":"; - } - $line .= implode("、", $example['columns']); - $prompts[] = "- " . $line; - } - $prompts[] = "可以借鉴以上结构,但要结合用户需求生成更贴合的方案。"; - } - - return empty($prompts) ? "" : implode("\n", $prompts); - } - - public static function messageSystemPrompt() - { - return << '群聊', 'user' => '单聊']; - $prompts[] = "类型:" . ($typeMap[$context['dialog_type']] ?? $context['dialog_type']); - } - if (!empty($context['group_type'])) { - $prompts[] = "分类:" . Base::cutStr($context['group_type'], 60); - } - } - - if (!empty($context['members']) && is_array($context['members'])) { - $members = array_slice(array_filter($context['members']), 0, 10); - if (!empty($members)) { - $prompts[] = "## 会话成员"; - $prompts[] = implode(",", array_map(fn($name) => Base::cutStr($name, 30), $members)); - } - } - - if (!empty($context['recent_messages']) && is_array($context['recent_messages'])) { - $prompts[] = "## 最近消息"; - foreach ($context['recent_messages'] as $item) { - $sender = Base::cutStr(trim($item['sender'] ?? ''), 40) ?: '成员'; - $summary = Base::cutStr(trim($item['summary'] ?? ''), 120); - if ($summary !== '') { - $prompts[] = "- {$sender}:{$summary}"; - } - } - } - - if (!empty($context['quote_summary'])) { - $prompts[] = "## 引用消息"; - $quoteUser = Base::cutStr(trim($context['quote_user'] ?? ''), 40); - $quoteText = Base::cutStr(trim($context['quote_summary']), 200); - if ($quoteUser !== '') { - $prompts[] = "{$quoteUser}:{$quoteText}"; - } else { - $prompts[] = $quoteText; - } - } - - if (!empty($context['current_draft'])) { - $prompts[] = "## 当前草稿"; - $prompts[] = Base::cutStr(trim($context['current_draft']), 200); - } - - return empty($prompts) ? "" : implode("\n", $prompts); - } - - private static function normalizeProjectColumns($columns) - { - if (is_string($columns)) { - $columns = preg_split('/[\n\r,,;;|]/u', $columns); - } - - $normalized = []; - if (is_array($columns)) { - foreach ($columns as $item) { - if (is_array($item)) { - $item = $item['name'] ?? $item['title'] ?? reset($item); - } - $item = trim((string)$item); - if ($item === '') { - continue; - } - $item = mb_substr($item, 0, 30); - if (!in_array($item, $normalized)) { - $normalized[] = $item; - } - if (count($normalized) >= 8) { - break; - } - } - } - - return $normalized; - } - /** * 通过 openAI 生成职场笑话、心灵鸡汤 * @param bool $noCache 是否禁用缓存 diff --git a/language/original-web.txt b/language/original-web.txt index 869e2fb74..fe4d7f023 100644 --- a/language/original-web.txt +++ b/language/original-web.txt @@ -1956,8 +1956,6 @@ API请求的基础URL路径,如果没有请留空 Grok是由xAI开发的生成式人工智能聊天机器人,旨在通过实时回答用户问题来提供帮助。 Ollama 是一个轻量级、可扩展的框架,旨在让用户能够在本地机器上构建和运行大型语言模型。 -AI 列表 -AI 设置 思考中... 请先填写 Base URL @@ -2224,7 +2222,6 @@ AI 正在生成分析... 最后更新: 暂无 AI 分析,点击右侧按钮生成。 AI 整理汇报 -整理结果预览 应用到汇报 请先填写汇报内容 AI 未返回整理内容 diff --git a/language/translate.json b/language/translate.json index 245ffae01..f69446bdd 100644 --- a/language/translate.json +++ b/language/translate.json @@ -27899,30 +27899,6 @@ "id": "Ollama adalah kerangka kerja ringan dan skalabel yang dirancang untuk memungkinkan pengguna membangun dan menjalankan model bahasa besar pada mesin lokal.", "ru": "Ollama - это легкий, масштабируемый фреймворк, разработанный для того, чтобы пользователи могли создавать и запускать крупные языковые модели на локальных машинах." }, - { - "key": "AI 列表", - "zh": "", - "zh-CHT": "AI 列表", - "en": "AI List", - "ko": "AI 목록", - "ja": "AIリスト", - "de": "KI-Liste", - "fr": "Liste d'IA", - "id": "Daftar AI", - "ru": "Список AI" - }, - { - "key": "AI 设置", - "zh": "", - "zh-CHT": "AI 設置", - "en": "AI Settings", - "ko": "AI 설정", - "ja": "AI設定", - "de": "KI-Einstellungen", - "fr": "Paramètres de l'IA", - "id": "Pengaturan AI", - "ru": "Настройки AI" - }, { "key": "思考中...", "zh": "", diff --git a/resources/assets/js/pages/manage/application.vue b/resources/assets/js/pages/manage/application.vue index 9c677af75..bebeefaa5 100644 --- a/resources/assets/js/pages/manage/application.vue +++ b/resources/assets/js/pages/manage/application.vue @@ -155,62 +155,6 @@ - - - - -
-
-
    -
  • - - -
  • -
-
-
-
- - - - -
-
- - -
- -
-
-
-
-
-
-