Spaces:
Running
Running
Commit
·
a9fb7e9
0
Parent(s):
feat: Initial clean commit
Browse files- .gitattributes +36 -0
- .gitignore +15 -0
- GEMINI.md +236 -0
- README.md +13 -0
- __pycache__/config.cpython-313.pyc +0 -0
- __pycache__/local.cpython-313.pyc +0 -0
- __pycache__/models.cpython-313.pyc +0 -0
- __pycache__/tab_chat.cpython-313.pyc +0 -0
- __pycache__/tab_code.cpython-313.pyc +0 -0
- __pycache__/tab_search.cpython-313.pyc +0 -0
- __pycache__/tab_workflow.cpython-313.pyc +0 -0
- __pycache__/utils.cpython-313.pyc +0 -0
- app.py +104 -0
- config.py +208 -0
- docs/backlog/2025-10-11-18-43-auto-fix-for-code-generator.md +23 -0
- docs/backlog/2025-10-11-19-41-add-local-model-id-mapping.md +5 -0
- docs/refs/anycoder_gen.md +940 -0
- docs/refs/ref_anycoder.py +0 -0
- docs/refs/ref_gemini.md +182 -0
- docs/requirements/2025-10-11-14-23-add-chat-send-button.md +11 -0
- docs/requirements/2025-10-11-14-35-fix-chat-model-display-name.md +10 -0
- docs/requirements/2025-10-11-14-37-update-model-descriptions.md +11 -0
- docs/requirements/2025-10-11-14-39-update-chat-example-prompts.md +11 -0
- docs/requirements/2025-10-11-15-08-refactor-chat-examples-to-scenarios.md +12 -0
- docs/requirements/2025-10-11-15-47-add-model-identity-to-chat-output.md +10 -0
- docs/requirements/2025-10-11-16-47-implement-static-page-generation.md +36 -0
- docs/requirements/2025-10-11-16-56-add-code-generation-presets.md +32 -0
- docs/requirements/2025-10-11-16-59-add-fullscreen-preview.md +39 -0
- docs/requirements/2025-10-11-17-12-refactor-code-preview-to-tabs.md +42 -0
- docs/requirements/2025-10-11-17-14-add-elephant-toothpaste-example.md +30 -0
- docs/requirements/2025-10-11-17-38-add-floating-island-example.md +28 -0
- docs/requirements/2025-10-11-18-18-add-model-selection-switch.md +35 -0
- docs/requirements/2025-10-11-18-18-display-think-tags-in-source-only.md +37 -0
- docs/requirements/2025-10-11-18-50-multi-provider-config-loading.md +28 -0
- docs/uncategorized/development_todo.md +31 -0
- models.py +127 -0
- openai_api.py +47 -0
- requirements.txt +1 -0
- tab_chat.py +170 -0
- tab_code.py +245 -0
- tab_search.py +36 -0
- tab_workflow.py +74 -0
- utils.py +19 -0
.gitattributes
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Log files
|
| 2 |
+
app.log
|
| 3 |
+
|
| 4 |
+
# Local configuration
|
| 5 |
+
local.py
|
| 6 |
+
|
| 7 |
+
# IDE settings
|
| 8 |
+
.idea/
|
| 9 |
+
|
| 10 |
+
# Python cache
|
| 11 |
+
__pycache__/
|
| 12 |
+
/site/
|
| 13 |
+
*.pyc
|
| 14 |
+
*.pyo
|
| 15 |
+
*.pyd
|
GEMINI.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ling & Ring Playground - 项目与协作文档
|
| 2 |
+
|
| 3 |
+
> **[重要] 上下文说明:** 本文档定义了 **Ling & Ring Playground** 项目的具体设计和流程。我们的整体协作模式、沟通风格、以及通用的文档和目录规范,均遵循一套**全局 `GEMINI.md` 核心协作指令**。阅读本文档前,建议先了解该全局框架,以获得完整的上下文。
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## 第一部分:元信息与协作流程
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## Gemini 用例
|
| 12 |
+
|
| 13 |
+
### 运行项目
|
| 14 |
+
|
| 15 |
+
要启动此 Gradio 应用,请遵循以下步骤:
|
| 16 |
+
|
| 17 |
+
1. **安装依赖:** 确保所有必要的库都已安装。
|
| 18 |
+
```bash
|
| 19 |
+
uv pip install -r requirements.txt
|
| 20 |
+
```
|
| 21 |
+
*注意: 如果遇到与 SOCKS 代理相关的 `ImportError`,请额外运行 `uv pip install "httpx[socks]"`。*
|
| 22 |
+
|
| 23 |
+
2. **启动应用:** 在后台静默运行应用。
|
| 24 |
+
```bash
|
| 25 |
+
source .venv/bin/activate && python3 app.py > /dev/null 2>&1 &
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
3. **验证:** 在浏览器中打开 `http://127.0.0.1:7860` 以确认应用正在运行。
|
| 29 |
+
|
| 30 |
+
### 需求开发流程
|
| 31 |
+
|
| 32 |
+
为确保每个需求的精确实现和追踪,我们遵循以下协作流程:
|
| 33 |
+
|
| 34 |
+
1. **需求接收 (Requirement Reception):**
|
| 35 |
+
- 当你提出新需求时,我将首先在 `docs/backlog/` 目录下创建一个 Markdown 文件,作为“需求池”的记录。
|
| 36 |
+
- 文件名格式为 `YYYY-MM-DD-HH-mm-需求简述.md`。
|
| 37 |
+
- 文件内容将包含:需求描述、创建时间、初始状态 `待处理 (Pending)`、验证方式(暂空)、验证结果(暂空)。
|
| 38 |
+
|
| 39 |
+
2. **规划与确认 (Plan & Confirm):**
|
| 40 |
+
- 当我们决定处理一个需求时,我会基于其文档,提出具体的执行计划。
|
| 41 |
+
- 在你确认计划后,我会将该需求文件从 `docs/backlog/` **移动**到 `docs/requirements/` 目录,并将其状态更新为 `开发中 (In Progress)`。
|
| 42 |
+
|
| 43 |
+
3. **修订章程 (Revise Charter):**
|
| 44 |
+
- 我会更新 `GEMINI.md` 的“第三部分:详细设计”,以反映新功能的设计细节。
|
| 45 |
+
|
| 46 |
+
4. **执行 (Execute):**
|
| 47 |
+
- 我将根据确认的计划进行编码实现。
|
| 48 |
+
|
| 49 |
+
5. **提交验证 (Submit for Verification):**
|
| 50 |
+
- 完成代码编写后,我会重启应用,并**自动刷新你的浏览器以展示最新版本**。
|
| 51 |
+
- 同时,我将更新需求文件,将状态改为 `已完成 (Completed)`,并填入“验证方式”供你参考。
|
| 52 |
+
|
| 53 |
+
6. **确认与关闭 (Confirm & Close):**
|
| 54 |
+
- 在你完成验证并确认功能符合预期后,我会将需求文件的“验证结果”更新为 `已验证 (Verified)`,至此该需求流程关闭。
|
| 55 |
+
|
| 56 |
+
### 调试与 Bug 修复流程
|
| 57 |
+
|
| 58 |
+
当功能未按预期工作时,我们将采用以下高效的诊断流程:
|
| 59 |
+
|
| 60 |
+
1. **问题报告:** 你需要向我清晰地描述问题,包括:
|
| 61 |
+
- **复现步骤:** 你进行了哪些具体操作。
|
| 62 |
+
- **预期结果:** 你期望看到什么。
|
| 63 |
+
- **实际结果:** 你实际看到了什么(例如:报错、无响应、界面错乱等)。
|
| 64 |
+
|
| 65 |
+
2. **启动日志模式:** 我会终止在后台静默运行的应用,并以日志模式重新启动它。这能让我观察到应用在运行期间的所有内部活动和潜在错误。
|
| 66 |
+
```bash
|
| 67 |
+
# 命令示例
|
| 68 |
+
source .venv/bin/activate && python3 app.py > app.log 2>&1 &
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
3. **复现与分析:** 我会请你重新执行一遍复现步骤。在你操作完成后,我将立即读取 `app.log` 文件,分析其中的错误信息和执行轨迹,定位问题的根本原因。
|
| 72 |
+
|
| 73 |
+
4. **修复与验证:**
|
| 74 |
+
- 根据日志分析,我会提出具体的修复方案并执行。
|
| 75 |
+
- 修复后,我会重启应用(仍处于日志模式),并**自动刷新你的浏览器**,然后请你再次验证。
|
| 76 |
+
- 如果问题依然存在,我们将重复步骤 3 和 4。
|
| 77 |
+
|
| 78 |
+
5. **流程结束:** 在你确认 Bug 已被完全修复后,此调试流程结束。我会终止日志模式的应用,清理日志文件,**以标准的静默模式重新启动应用,并为你刷新浏览器**。
|
| 79 |
+
|
| 80 |
+
### 代码提交与版本管理
|
| 81 |
+
|
| 82 |
+
在完成一个需求或修复一个 Bug 后,我们将遵循以下流程来提交代码和管理版本:
|
| 83 |
+
|
| 84 |
+
1. **暂存变更:**
|
| 85 |
+
- 使用 `git add .` 暂存所有修改。
|
| 86 |
+
|
| 87 |
+
2. **编写提交信息 (Commit Message):**
|
| 88 |
+
- Commit message 应遵循**约定式提交 (Conventional Commits)**规范。
|
| 89 |
+
- 格式为 `<类型>(<范围>): <描述>`,例如:
|
| 90 |
+
- `feat(chat): 添加发送按钮`
|
| 91 |
+
- `fix(models): 修正 Ring 模型流式输出问题`
|
| 92 |
+
- `docs(workflow): 更新调试与验证流程`
|
| 93 |
+
- 常用的类型包括 `feat`, `fix`, `docs`, `style`, `refactor`, `test` 等。
|
| 94 |
+
|
| 95 |
+
3. **创建版本标签 (Git Tag):**
|
| 96 |
+
- **检查现有版本:** 在打标签前,**必须**先运行 `git tag` 查看所有历史版本,以确定下一个正确的版本号。
|
| 97 |
+
- **确定版本号:** 遵循**语义化版本 (Semantic Versioning)**。在 `v1.0.0` 之前,我们主要递增次版本号(如 `v0.4` -> `v0.5`)。
|
| 98 |
+
- **���建附注标签:** 使用 `git tag -a <版本号> -m "<版本摘要>"` 创建一个附注标签,其中摘要应简明扼要地概括该版本的主要变更。例如:
|
| 99 |
+
```bash
|
| 100 |
+
git tag -a v0.5 -m "v0.5: Automate browser verification and formalize debugging process"
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
4. **最终确认:**
|
| 104 |
+
- 提交和打标签后,运行 `git status` 和 `git tag` 确认工作区干净且新标签已成功创建。
|
| 105 |
+
|
| 106 |
+
---
|
| 107 |
+
|
| 108 |
+
## 第二部分:整体设计
|
| 109 |
+
|
| 110 |
+
### 2.1 项目目标
|
| 111 |
+
|
| 112 |
+
创建一个名为 “Ling & Ring Playground” 的 Hugging Face Space,用于展示两个核心 AI 模型:
|
| 113 |
+
|
| 114 |
+
- **Ling (🧠):** 通用对话模型。
|
| 115 |
+
- **Ring (💍):** 推理/代理模型,用于代码生成、网页检索和工作流执行。
|
| 116 |
+
|
| 117 |
+
### 2.2 核心设计原则
|
| 118 |
+
|
| 119 |
+
- **任务导向:** UI 围绕用户任务(聊天、编码等)组织,而非直接暴露模型。
|
| 120 |
+
- **品牌明晰:** 在每个功能界面清晰标注“由 Ling/Ring 模型驱动”。
|
| 121 |
+
- **无缝体验:** 用户无需手动输入 API Token,认证在后端自动完成。
|
| 122 |
+
- **引导优先:** 提供精心设计的示例,确保用户获得高质量的初次体验。
|
| 123 |
+
|
| 124 |
+
### 2.3 技术栈与架构
|
| 125 |
+
|
| 126 |
+
- **前端/UI:** Gradio `gr.Blocks`
|
| 127 |
+
- **后端:** Python
|
| 128 |
+
- **安全:** 所有 API 密钥通过 Hugging Face Space Secrets 管理。
|
| 129 |
+
|
| 130 |
+
### 2.3.1 配置加载策略
|
| 131 |
+
|
| 132 |
+
为兼顾本地开发的便利性、线上部署的安全性与成本效益,项目采用了一种分层配置加载机制:
|
| 133 |
+
|
| 134 |
+
1. **本地优先 (`local.py`):** 在项目根目录下,可以创建一个 `local.py` 文件来存放本地开发所需的配置,例如使用内部免费 Provider 的 API Key 和 Endpoint。此文件**必须**被 `.gitignore` 忽略,以防止任何敏感信息被提交到版本控制中。
|
| 135 |
+
2. **环境变量回退:** 当 `local.py` 文件不存在时(例如在 Hugging Face Spaces 的生产环境中),系统将自动回退,尝试从环境变量中读取所需的配置。这种方式使得 API Key 等敏感信息可以通过平台安全地注入,而无需硬编码在代码中。
|
| 136 |
+
3. **模型 ID 本地映射:** 为了方便本地开发和调试,系统还支持通过在 `local.py` 文件中定义一个 `get_local_model_id_map` 函数,来实现从在线模型 ID 到本地模型 ID 的映射。这允许开发者在不修改核心代码库的情况下,将模型请求指向本地运行的服务或不同的模型版本。
|
| 137 |
+
|
| 138 |
+
此策略确保了开发者在本地可以快速迭代,而线上部署则遵循了安全最佳实践。
|
| 139 |
+
|
| 140 |
+
### 2.4 项目结构
|
| 141 |
+
|
| 142 |
+
```
|
| 143 |
+
/
|
| 144 |
+
├───.gitignore
|
| 145 |
+
├───app.py # 应用主入口
|
| 146 |
+
├───config.py # 配置文件,用于存放 API 密钥等
|
| 147 |
+
├───GEMINI.md # 项目与协作文档(唯一事实来源)
|
| 148 |
+
├───models.py # 模型交互逻辑
|
| 149 |
+
├───requirements.txt # Python 依赖
|
| 150 |
+
├───tab_chat.py # “聊天”功能模块
|
| 151 |
+
├───tab_code.py # “代码生成”功能模块
|
| 152 |
+
├───tab_search.py # “网页检索”功能模块
|
| 153 |
+
├───tab_workflow.py # “工作流”功能模块
|
| 154 |
+
├───utils.py # 通用工具函数
|
| 155 |
+
└───docs/
|
| 156 |
+
├───backlog/ # 待办需求池
|
| 157 |
+
├───requirements/ # 需求文档(Git 跟踪)
|
| 158 |
+
└───refs/ # 本地参考资料(Git 忽略)
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
### 2.5 代码架构
|
| 162 |
+
|
| 163 |
+
1. **`models.py`**: 存放所有与模型对接和交互的逻辑。
|
| 164 |
+
2. **`app.py`**: 作为应用的统一入口,仅保留最精简的组装和启动逻辑。
|
| 165 |
+
3. **`tab_*.py`**: 每个标签页(如 `tab_chat.py`)独立一个文件,负责构建该标签页的UI和处理其特定的后端逻辑。
|
| 166 |
+
4. **`app.py` 调用**: 主入口 `app.py` 通过调用各个 `tab_*.py` 中的函数来创建和组装完整的应用界面。
|
| 167 |
+
5. **`utils.py`**: 存放可被多处复用的纯静态方法、常量或辅助函数。
|
| 168 |
+
|
| 169 |
+
---
|
| 170 |
+
|
| 171 |
+
## 第三部分:详细设计
|
| 172 |
+
|
| 173 |
+
应用为一个包含页头和四个核心功能标签页的单页应用。
|
| 174 |
+
|
| 175 |
+
### Tab 1: 聊天 (Chat) - `tab_chat.py`
|
| 176 |
+
|
| 177 |
+
- **目标:** 提供一个与 Ling 模型进行高质量对话的界面。
|
| 178 |
+
- **UI 布局:**
|
| 179 |
+
- **左侧面板:** `gr.Chatbot` (对话历史), `gr.Textbox` (输入框) 与 `gr.Button` ("发送") 在同一行, `gr.Examples` (示例)。
|
| 180 |
+
- **右侧面板:** `gr.Textbox` (System Prompt), `gr.Slider` (温度), `gr.Dropdown` (模型选择)。
|
| 181 |
+
- **用户用例:**
|
| 182 |
+
1. 用户在输入框中输入问题,按回车提交。
|
| 183 |
+
2. Ling 模型的响应以流式方式出现在聊天历史中,且每条回复的开头都会以 `**<模型名称>**` 的形式清晰地标识出当前是哪个模型在回答。
|
| 184 |
+
3. 用户可继续多轮对话,或通过右侧面板调整模型行为。
|
| 185 |
+
|
| 186 |
+
### Tab 2: 代码生成 (Code Generation) - `tab_code.py`
|
| 187 |
+
|
| 188 |
+
- **目标:** 利用 Ring 模型,根据用户需求生成代码,并提供实时预览。
|
| 189 |
+
- **UI 布局:**
|
| 190 |
+
- **左侧面板:** `gr.Radio` (代码类型), `gr.Radio` (模型选择), `gr.Textbox` (需求输入), `gr.Examples` (预设选项), `gr.Button` (生成)。
|
| 191 |
+
- **右侧面板:** `gr.Tabs`
|
| 192 |
+
- **Tab 1: "实时预览"**: `gr.Button` (全屏预览), `gr.HTML` (`<iframe>` 预览容器)。
|
| 193 |
+
- **Tab 2: "生成的源代码"**: `gr.Code` (源代码显示)。
|
| 194 |
+
- **用户用例:**
|
| 195 |
+
1. 用户选择代码类型(“静态页面”或“Gradio 应用”)。当选择“静态页面”时,功能由 `Ling-1T` 模型驱动。
|
| 196 |
+
2. 用户输入需求(例如:“创建一个带标题和按钮的页面”)。
|
| 197 |
+
3. 点击“生成代码”后,`tab_code.py` 中的 `generate_code` 函数会作为一个生成器工作。
|
| 198 |
+
4. 它会迭代调用模型返回的流式数据,在每次 `yield` 时同时更新下方的源代码区域(累积的代码)和右侧的预览区域。
|
| 199 |
+
5. 预览区域的 `<iframe>` 默认以**缩放模式**显示,以便用户看到整体效果。
|
| 200 |
+
6. 用户可以点击“全屏预览”按钮,此时输入和代码区域会隐藏,预览区将放大以提供更沉浸的体验。再次点击可恢复。
|
| 201 |
+
7. 对于 Gradio 应用,后端会启动一个独立的子进程来运行代码,并将应用界面嵌入到预览区。
|
| 202 |
+
|
| 203 |
+
### Tab 3: 网页检索 (Web Search) - `tab_search.py`
|
| 204 |
+
|
| 205 |
+
- **目标:** 利用 Ring 模型的检索能力,提供精准的网页信息摘要。
|
| 206 |
+
- **UI 布局:** 单栏居中布局,包含 `gr.Textbox` (输入), `gr.Button` (搜索), `gr.Markdown` (结果)。
|
| 207 |
+
- **用户用例:**
|
| 208 |
+
1. 用户输入问题(例如:“什么是 Transformer 架构?”)。
|
| 209 |
+
2. 点击“搜索”后,Ring 模型返回的摘要和来源链接会显示在结果区。
|
| 210 |
+
|
| 211 |
+
### Tab 4: 工作流执行 (Workflow Execution) - `tab_workflow.py`
|
| 212 |
+
|
| 213 |
+
- **目标:** 展示 Ring 模型作为 Agent 执行复杂工作流的能力。
|
| 214 |
+
- **UI 布局:**
|
| 215 |
+
- **左侧面板:** `gr.Textbox` (工作流描述), `gr.Button` (执行), `gr.Markdown` (工作流可视化)。
|
| 216 |
+
- **右侧面板:** `gr.Textbox` (状态日志), `gr.Chatbot` (人机交互)。
|
| 217 |
+
- **用户用例:**
|
| 218 |
+
1. 用户输入任务描述(例如:“查找最新的 Llama 3 模型并总结其模型卡片”)。
|
| 219 |
+
2. Ring 模型生成执行计划并可视化,然后开始执行。
|
| 220 |
+
3. 右侧面板实时显示执行日志,并在需要时通过聊天机器人向用户请求决策。
|
| 221 |
+
|
| 222 |
+
---
|
| 223 |
+
|
| 224 |
+
## 第四部分:待办事项
|
| 225 |
+
|
| 226 |
+
### 4.1 进行中的任务
|
| 227 |
+
|
| 228 |
+
- [x] **任务: 实现代码生成 Tab (`tab_code.py`)**
|
| 229 |
+
- [x] UI 构建 (`gr.Radio`, `gr.Textbox`, `gr.Button`, `gr.Code`, `gr.HTML`)
|
| 230 |
+
- [x] 后端逻辑 (System Prompts, 子进程管理, `<iframe>` 预览)
|
| 231 |
+
- [x] 应用整合 (在 `app.py` 中装配 Tab)
|
| 232 |
+
- [x] 模块化重构 (将模型调用逻辑移至 `models.py`)
|
| 233 |
+
|
| 234 |
+
### 4.2 待修复的问题
|
| 235 |
+
|
| 236 |
+
- (暂无)
|
README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Ling Playground 2
|
| 3 |
+
emoji: 🔥
|
| 4 |
+
colorFrom: pink
|
| 5 |
+
colorTo: purple
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 5.49.1
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: apache-2.0
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
__pycache__/config.cpython-313.pyc
ADDED
|
Binary file (8.31 kB). View file
|
|
|
__pycache__/local.cpython-313.pyc
ADDED
|
Binary file (1.1 kB). View file
|
|
|
__pycache__/models.cpython-313.pyc
ADDED
|
Binary file (5.36 kB). View file
|
|
|
__pycache__/tab_chat.cpython-313.pyc
ADDED
|
Binary file (8.8 kB). View file
|
|
|
__pycache__/tab_code.cpython-313.pyc
ADDED
|
Binary file (12.7 kB). View file
|
|
|
__pycache__/tab_search.cpython-313.pyc
ADDED
|
Binary file (2.38 kB). View file
|
|
|
__pycache__/tab_workflow.cpython-313.pyc
ADDED
|
Binary file (4.12 kB). View file
|
|
|
__pycache__/utils.cpython-313.pyc
ADDED
|
Binary file (1.24 kB). View file
|
|
|
app.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
|
| 3 |
+
# Import UI creation and handler functions from tab modules
|
| 4 |
+
from tab_chat import create_chat_tab, handle_chat
|
| 5 |
+
from tab_code import create_code_tab
|
| 6 |
+
from tab_search import create_search_tab, handle_web_search
|
| 7 |
+
from tab_workflow import create_workflow_tab, handle_workflow_generation, handle_workflow_chat
|
| 8 |
+
|
| 9 |
+
# --- Main Gradio UI Definition ---
|
| 10 |
+
with gr.Blocks(theme=gr.themes.Default(primary_hue="blue")) as demo:
|
| 11 |
+
# Global state for the workflow tab
|
| 12 |
+
workflow_state = gr.State()
|
| 13 |
+
|
| 14 |
+
# --- Header ---
|
| 15 |
+
with gr.Row():
|
| 16 |
+
gr.Markdown("""
|
| 17 |
+
# Ling & Ring Playground
|
| 18 |
+
### 体验下一代聊天、编码、检索与工作流自动化
|
| 19 |
+
""")
|
| 20 |
+
with gr.Row():
|
| 21 |
+
gr.Markdown("""
|
| 22 |
+
[Ling Model Card](https://huggingface.co) | [Ring Model Card](https://huggingface.co) | [Read the Paper](https://huggingface.co) | [Join our Discord](https://huggingface.co)
|
| 23 |
+
""")
|
| 24 |
+
|
| 25 |
+
# --- Main UI Tabs ---
|
| 26 |
+
with gr.Tabs() as main_ui:
|
| 27 |
+
# Create tabs by calling functions from modules
|
| 28 |
+
with gr.Tab("聊天 (Chat)"):
|
| 29 |
+
chat_components = create_chat_tab()
|
| 30 |
+
with gr.Tab("代码生成 (Code Generation)"):
|
| 31 |
+
create_code_tab() # The code tab now handles its own events
|
| 32 |
+
with gr.Tab("网页检索 (Web Search)"):
|
| 33 |
+
search_components = create_search_tab()
|
| 34 |
+
with gr.Tab("工作流 (Workflow)"):
|
| 35 |
+
workflow_components = create_workflow_tab()
|
| 36 |
+
|
| 37 |
+
# --- Event Handling Logic ---
|
| 38 |
+
|
| 39 |
+
# Chat Tab Events
|
| 40 |
+
chat_submit_event = chat_components["chat_input"].submit(
|
| 41 |
+
fn=handle_chat,
|
| 42 |
+
inputs=[
|
| 43 |
+
chat_components["chat_input"],
|
| 44 |
+
chat_components["chatbot"],
|
| 45 |
+
chat_components["system_prompt"],
|
| 46 |
+
chat_components["temperature_slider"],
|
| 47 |
+
chat_components["model_selector"]
|
| 48 |
+
],
|
| 49 |
+
outputs=[
|
| 50 |
+
chat_components["chatbot"],
|
| 51 |
+
chat_components["chat_input"]
|
| 52 |
+
]
|
| 53 |
+
)
|
| 54 |
+
chat_components["send_button"].click(
|
| 55 |
+
fn=handle_chat,
|
| 56 |
+
inputs=[
|
| 57 |
+
chat_components["chat_input"],
|
| 58 |
+
chat_components["chatbot"],
|
| 59 |
+
chat_components["system_prompt"],
|
| 60 |
+
chat_components["temperature_slider"],
|
| 61 |
+
chat_components["model_selector"]
|
| 62 |
+
],
|
| 63 |
+
outputs=[
|
| 64 |
+
chat_components["chatbot"],
|
| 65 |
+
chat_components["chat_input"]
|
| 66 |
+
]
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
# Web Search Tab Events
|
| 70 |
+
search_components["search_button"].click(
|
| 71 |
+
fn=handle_web_search,
|
| 72 |
+
inputs=[search_components["search_input"]],
|
| 73 |
+
outputs=[search_components["search_results_output"]]
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
# Workflow Tab Events
|
| 77 |
+
workflow_components["generate_workflow_button"].click(
|
| 78 |
+
fn=handle_workflow_generation,
|
| 79 |
+
inputs=[workflow_components["workflow_description_input"]],
|
| 80 |
+
outputs=[
|
| 81 |
+
workflow_components["workflow_visualization_output"],
|
| 82 |
+
workflow_components["workflow_status_output"],
|
| 83 |
+
workflow_components["workflow_chatbot"],
|
| 84 |
+
workflow_state,
|
| 85 |
+
workflow_components["workflow_chat_input"] # 新增:直接作为输出
|
| 86 |
+
]
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
workflow_components["workflow_chat_input"].submit(
|
| 90 |
+
fn=handle_workflow_chat,
|
| 91 |
+
inputs=[
|
| 92 |
+
workflow_components["workflow_chat_input"],
|
| 93 |
+
workflow_components["workflow_chatbot"],
|
| 94 |
+
workflow_state
|
| 95 |
+
],
|
| 96 |
+
outputs=[
|
| 97 |
+
workflow_components["workflow_chatbot"],
|
| 98 |
+
workflow_state,
|
| 99 |
+
workflow_components["workflow_status_output"],
|
| 100 |
+
workflow_components["workflow_chat_input"]
|
| 101 |
+
]
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
demo.launch()
|
config.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Configuration file for the Ling & Ring Playground application.
|
| 3 |
+
|
| 4 |
+
This file centralizes all the configuration variables, such as API endpoints,
|
| 5 |
+
API keys, and system prompts for different functionalities.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
|
| 10 |
+
# --- API Configuration ---
|
| 11 |
+
# This follows a layered configuration strategy.
|
| 12 |
+
# 1. It first tries to import configurations from a local `local.py` file.
|
| 13 |
+
# This file is intended for local development and is ignored by Git.
|
| 14 |
+
# 2. If `local.py` is not found, it falls back to environment variables,
|
| 15 |
+
# which is ideal for production environments like Hugging Face Spaces.
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
# For local development: create a local.py file with your credentials.
|
| 19 |
+
# Example local.py:
|
| 20 |
+
# ANTCHAT_BASE_URL = "http://your-local-endpoint/v1"
|
| 21 |
+
# ANTCHAT_API_KEY = "your-local-api-key"
|
| 22 |
+
from local import ANTCHAT_BASE_URL, ANTCHAT_API_KEY
|
| 23 |
+
print("✅ Loaded configuration from local.py")
|
| 24 |
+
except ImportError:
|
| 25 |
+
# For production/HF Spaces: set these as environment variables.
|
| 26 |
+
print("🤔 `local.py` not found. Attempting to load configuration from environment variables.")
|
| 27 |
+
ANTCHAT_BASE_URL = os.getenv("ANTCHAT_BASE_URL")
|
| 28 |
+
ANTCHAT_API_KEY = os.getenv("ANTCHAT_API_KEY")
|
| 29 |
+
|
| 30 |
+
# A check to ensure that the credentials are not None.
|
| 31 |
+
if not ANTCHAT_BASE_URL or not ANTCHAT_API_KEY:
|
| 32 |
+
print("⚠️ Warning: ANTCHAT_BASE_URL or ANTCHAT_API_KEY is not set. The application may not function correctly.")
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# --- System Prompts ---
|
| 36 |
+
|
| 37 |
+
# For the Chat tab
|
| 38 |
+
CHAT_SYSTEM_PROMPT_PLACEHOLDER = "e.g., You are a helpful assistant."
|
| 39 |
+
|
| 40 |
+
# For the Code Generation tab
|
| 41 |
+
CODE_SYSTEM_PROMPT = "You are an expert code generation assistant. Generate clean, efficient code based on the user's request. Only output the code itself inside a markdown block. Do not add any other explanation."
|
| 42 |
+
|
| 43 |
+
# Code generation options with different system prompts
|
| 44 |
+
CODE_SYSTEM_PROMPTS = {
|
| 45 |
+
"html": "You are an expert HTML/CSS/JavaScript developer. Generate clean, semantic HTML code with inline CSS and JavaScript. Only output the complete HTML code inside a markdown block. Do not add any other explanation.",
|
| 46 |
+
"python": "You are an expert Python developer. Generate clean, efficient Python code. Only output the code inside a markdown block with python syntax. Do not add any other explanation.",
|
| 47 |
+
"javascript": "You are an expert JavaScript developer. Generate clean, efficient JavaScript code. Only output the code inside a markdown block with javascript syntax. Do not add any other explanation.",
|
| 48 |
+
"sql": "You are an expert SQL developer. Generate clean, efficient SQL queries. Only output the SQL code inside a markdown block. Do not add any other explanation.",
|
| 49 |
+
"general": CODE_SYSTEM_PROMPT
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
# For the Web Search tab
|
| 53 |
+
SEARCH_SYSTEM_PROMPT = "You are an expert web search assistant. You will be provided with a user query. Perform a web search and provide a concise summary of the findings, including key points and source links."
|
| 54 |
+
|
| 55 |
+
# For the Workflow Generation
|
| 56 |
+
WORKFLOW_GENERATE_SYSTEM_PROMPT = "You are a workflow analysis agent. Analyze the user's description and break it down into a numbered list of executable steps. Be precise and clear."
|
| 57 |
+
|
| 58 |
+
# For the Workflow Execution
|
| 59 |
+
WORKFLOW_EXECUTE_SYSTEM_PROMPT = "You are a workflow execution assistant. Your goal is to guide the user step-by-step through the predefined workflow. At each step, clearly state the task and ask for confirmation or necessary input to proceed."
|
| 60 |
+
|
| 61 |
+
# --- Model Specifications ---
|
| 62 |
+
|
| 63 |
+
CHAT_MODEL_SPECS = {
|
| 64 |
+
"inclusionai/ling-1t": {
|
| 65 |
+
"model_id": "inclusionai/ling-1t",
|
| 66 |
+
"display_name": "🧠 Ling-1T (1T)",
|
| 67 |
+
"description": "一款万亿级参数的大语言模型,为追求极致性能和高流畅度的复杂自然语言理解与生成任务而设计。",
|
| 68 |
+
"prompt_scenarios": [
|
| 69 |
+
{
|
| 70 |
+
"title": "深度分析报告撰写",
|
| 71 |
+
"system_prompt": "你是一位资深的行业分析师,能够撰写逻辑清晰、数据充分、观点独到的深度分析报告。",
|
| 72 |
+
"message_examples": [
|
| 73 |
+
"撰写一篇关于人工智能在医疗领域应用的深度分析报告,至少800字。",
|
| 74 |
+
"分析当前宏观经济形势,并预测未来一年的发展趋势。",
|
| 75 |
+
"为一家新成立的科技公司制定一份详细的品牌推广策略。"
|
| 76 |
+
]
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"title": "莎士比亚风格文案",
|
| 80 |
+
"system_prompt": "你是一位模仿大师,能够以威廉·莎士比亚的风格和口吻进行文学创作。",
|
| 81 |
+
"message_examples": [
|
| 82 |
+
"以莎士比亚的风格,写一段关于“代码”的独白。",
|
| 83 |
+
"假如哈姆雷特是一个程序员,他会如何抱怨一个难缠的 bug?",
|
| 84 |
+
"把“用户体验”这个词用十四行诗的形式表达出来。"
|
| 85 |
+
]
|
| 86 |
+
}
|
| 87 |
+
]
|
| 88 |
+
},
|
| 89 |
+
"inclusionai/ling-flash-2.0": {
|
| 90 |
+
"model_id": "inclusionai/ling-flash-2.0",
|
| 91 |
+
"display_name": "🧠 Ling-flash-2.0 (103B)",
|
| 92 |
+
"description": "一款性能卓越的十亿级参数模型,专为需要高速响应和复杂指令遵循的场景优化。",
|
| 93 |
+
"prompt_scenarios": [
|
| 94 |
+
{
|
| 95 |
+
"title": "技术文档撰写",
|
| 96 |
+
"system_prompt": "你是一位专业的技术作家,能够清晰、准确地解释复杂的技术概念。",
|
| 97 |
+
"message_examples": [
|
| 98 |
+
"为一段新的 API 端点编写清晰的文档。",
|
| 99 |
+
"解释一下什么是 'Transformer' 架构。",
|
| 100 |
+
"如何为开源项目编写一份贡献指南?"
|
| 101 |
+
]
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"title": "创意头脑风暴",
|
| 105 |
+
"system_prompt": "你是一位充满创意的伙伴,可以进行头脑风暴并提供新颖的想法。",
|
| 106 |
+
"message_examples": [
|
| 107 |
+
"为一个新的播客想 5 个吸引人的名字。",
|
| 108 |
+
"我应该为我的博客写些什么内容?",
|
| 109 |
+
"想一个关于时间旅行的短篇故事点子。"
|
| 110 |
+
]
|
| 111 |
+
}
|
| 112 |
+
]
|
| 113 |
+
},
|
| 114 |
+
"inclusionai/ring-flash-2.0": {
|
| 115 |
+
"model_id": "inclusionai/ring-flash-2.0",
|
| 116 |
+
"display_name": "💍 Ring-flash-2.0 (103B)",
|
| 117 |
+
"description": "一款十亿级参数的推理模型,在性能和成本之间取得了很好的平衡,适合需要逐步思考或生成代码的通用任务。",
|
| 118 |
+
"prompt_scenarios": [
|
| 119 |
+
{
|
| 120 |
+
"title": "旅行规划专家",
|
| 121 |
+
"system_prompt": "你是一位经验丰富的旅行规划师,精通全球各地的旅行路线、交通和预算规划。",
|
| 122 |
+
"message_examples": [
|
| 123 |
+
"规划一个为期五天的日本东京自由行,包含详细的每日行程、交通和预算。",
|
| 124 |
+
"我应该如何选择我的第一把电吉他?请给出步骤和建议。",
|
| 125 |
+
"为我的周末家庭聚餐推荐三个菜谱。"
|
| 126 |
+
]
|
| 127 |
+
},
|
| 128 |
+
{
|
| 129 |
+
"title": "Python 脚本生成器",
|
| 130 |
+
"system_prompt": "你是一位 Python 编程专家,能够根据需求生成高质量、可执行的 Python 脚本。",
|
| 131 |
+
"message_examples": [
|
| 132 |
+
"生成一个 Python 脚本,监控网站价格变化并在降价时发邮件提醒。",
|
| 133 |
+
"写一个 Python 函数,用于计算两个日期之间相差了多少天。",
|
| 134 |
+
"用 Python 实现一个简单的命令行计算器。"
|
| 135 |
+
]
|
| 136 |
+
}
|
| 137 |
+
]
|
| 138 |
+
},
|
| 139 |
+
"inclusionai/ling-mini-2.0": {
|
| 140 |
+
"model_id": "inclusionai/ling-mini-2.0",
|
| 141 |
+
"display_name": "🧠 Ling-mini-2.0 (16B)",
|
| 142 |
+
"description": "一款轻量级对话模型,经过优化,可在消费级硬件上高效运行,非常适合移动端或本地化部署场景。",
|
| 143 |
+
"prompt_scenarios": [
|
| 144 |
+
{
|
| 145 |
+
"title": "高效邮件助手",
|
| 146 |
+
"system_prompt": "你是一位专业的行政助理,擅长撰写清晰、简洁、专业的电子邮件。",
|
| 147 |
+
"message_examples": [
|
| 148 |
+
"给我写一封简短的邮件,提醒团队成员明天上午10点开会。",
|
| 149 |
+
"草拟一封邮件,向客户询问项目进展。",
|
| 150 |
+
"帮我写一封得体的拒绝信,回复一个不合适的合作邀请。"
|
| 151 |
+
]
|
| 152 |
+
},
|
| 153 |
+
{
|
| 154 |
+
"title": "文本摘要与翻译",
|
| 155 |
+
"system_prompt": "你是一位语言专家,能够快速准确地进行文本摘要和多语言翻译。",
|
| 156 |
+
"message_examples": [
|
| 157 |
+
"总结这篇新闻的主要内容,不超过三句话。",
|
| 158 |
+
"将这段英文翻译成中文:'Gradio is an open-source Python library...'",
|
| 159 |
+
"推荐三部适合周末看的科幻电影。"
|
| 160 |
+
]
|
| 161 |
+
}
|
| 162 |
+
]
|
| 163 |
+
},
|
| 164 |
+
"inclusionai/ring-mini-2.0": {
|
| 165 |
+
"model_id": "inclusionai/ring-mini-2.0",
|
| 166 |
+
"display_name": "💍 Ring-mini-2.0 (3B)",
|
| 167 |
+
"description": "一款经过量化、极致高效的推理模型,为速度和效率要求严苛的资源受限环境(如边缘计算)而设计。",
|
| 168 |
+
"prompt_scenarios": [
|
| 169 |
+
{
|
| 170 |
+
"title": "生活日常助手",
|
| 171 |
+
"system_prompt": "你是一位乐于助人的生活助手,可以处理各种日常请求。",
|
| 172 |
+
"message_examples": [
|
| 173 |
+
"帮我设置一个25分钟的番茄钟。",
|
| 174 |
+
"在我的购物清单里加入牛奶和面包。",
|
| 175 |
+
"查询今天北京的天气。"
|
| 176 |
+
]
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"title": "简单代码片段",
|
| 180 |
+
"system_prompt": "你是一位代码片段生成器,为常见的编程问题提供简洁、正确的代码示例。",
|
| 181 |
+
"message_examples": [
|
| 182 |
+
"提供一个用 JavaScript 实现的 GET 请求示例。",
|
| 183 |
+
"如何用 CSS 让一个 div 水平居中?",
|
| 184 |
+
"从1数到10。"
|
| 185 |
+
]
|
| 186 |
+
}
|
| 187 |
+
]
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
# --- Local Model ID Mapping Override ---
|
| 192 |
+
# Attempt to import a mapping from online model IDs to local model IDs
|
| 193 |
+
# from local.py. This allows developers to use different model names for
|
| 194 |
+
# local testing without changing the core application code.
|
| 195 |
+
try:
|
| 196 |
+
from local import get_local_model_id_map
|
| 197 |
+
local_model_id_map = get_local_model_id_map()
|
| 198 |
+
for model_id, spec in CHAT_MODEL_SPECS.items():
|
| 199 |
+
if model_id in local_model_id_map:
|
| 200 |
+
spec['model_id'] = local_model_id_map[model_id]
|
| 201 |
+
print(f"🔄 Overrode model ID for '{model_id}': '{model_id}' -> '{spec['model_id']}'")
|
| 202 |
+
except ImportError:
|
| 203 |
+
# local.py does not exist or does not contain the mapping function.
|
| 204 |
+
# This is expected in a production environment.
|
| 205 |
+
pass
|
| 206 |
+
except Exception as e:
|
| 207 |
+
print(f"⚠️ Warning: Failed to apply local model ID mapping. Error: {e}")
|
| 208 |
+
|
docs/backlog/2025-10-11-18-43-auto-fix-for-code-generator.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:代码生成器自动修复功能
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11-18-43
|
| 4 |
+
- **状态:** 待处理 (Pending)
|
| 5 |
+
|
| 6 |
+
## 需求描述
|
| 7 |
+
|
| 8 |
+
当前使用的模型生成的代码可能存在 bug,导致在运行时于控制台输出异常。此功能旨在实现一种“自动修复”机制。
|
| 9 |
+
|
| 10 |
+
具体实现思路如下:
|
| 11 |
+
1. 在代码生成器的 UI 中增加一个“自动修复”功能的开关。
|
| 12 |
+
2. 当该开关开启后,系统将修改 System Prompt,赋予模型捕获和处理异常的能力。
|
| 13 |
+
3. 运行时,系统将捕获控制台中的异常信息。
|
| 14 |
+
4. 将捕获到的异常作为新的输入,反馈给 LLM。
|
| 15 |
+
5. LLM 根据异常信息,对已生成的代码进行编辑和修正,以解决问题。
|
| 16 |
+
|
| 17 |
+
## 验证方式
|
| 18 |
+
|
| 19 |
+
(暂无)
|
| 20 |
+
|
| 21 |
+
## 验证结果
|
| 22 |
+
|
| 23 |
+
(暂无)
|
docs/backlog/2025-10-11-19-41-add-local-model-id-mapping.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
- **需求描述:** 为了同时兼顾在线部署和本地开发的便利性,需要实现一套模型 ID 的映射机制。代码中应默认使用在线部署的官方模型 ID,但允许通过一个本地的 `local.py` 文件来覆盖这些 ID,使其指向本地开发环境中使用的不同模型名称。此外,模型列表需要新增 `inclusionai/ring-mini-2.0`,并为其补充相应的 UI 示例。
|
| 2 |
+
- **创建时间:** 2025-10-11-19-41
|
| 3 |
+
- **初始状态:** 待处理 (Pending)
|
| 4 |
+
- **验证方式:** (暂空)
|
| 5 |
+
- **验证结果:** (暂空)
|
docs/refs/anycoder_gen.md
ADDED
|
@@ -0,0 +1,940 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AnyCoder 代码生成方案
|
| 2 |
+
|
| 3 |
+
本文档基于对 `docs/ref_anycoder.py` 的分析,总结了其中代码生成功能的实现方案。
|
| 4 |
+
|
| 5 |
+
### 1. 用户 Prompt 输入
|
| 6 |
+
|
| 7 |
+
用户通过一个标记为 “User Prompt” 的文本框(`gr.Textbox`)输入他们的代码生成请求。此外,系统还支持通过图片(`gr.Image`)或视频(`gr.Video`)上传作为多模态输入,以辅助代码生成。
|
| 8 |
+
|
| 9 |
+
### 2. System Prompt 构建流程
|
| 10 |
+
|
| 11 |
+
用户的输入在发送给大模型之前,会与一个动态构建的 System Prompt 结合。这个 System Prompt 的内容由多个UI选项决定,旨在精确控制模型的输出。主要选项包括:
|
| 12 |
+
|
| 13 |
+
* **目标语言/框架选择**: 用户通过单选按钮(`gr.Radio`)选择生成代码的类型,例如 `HTML`, `Gradio`, `Svelte`, `Python` 等。
|
| 14 |
+
* 每种选择都对应一个精心设计的、特定的 System Prompt 模板(如 `HTML_SYSTEM_PROMPT`, `GRADIO_SYSTEM_PROMPT`)。
|
| 15 |
+
* 这些模板包含了对模型输出格式、代码风格、必需库和最佳实践的详细指示。
|
| 16 |
+
* **网络搜索能力**: 一个复选框(`gr.Checkbox`)允许用户启用网络搜索功能。
|
| 17 |
+
* 如果勾选,系统会切换到带有 “WITH_SEARCH” 后缀的 System Prompt 模板(如 `HTML_SYSTEM_PROMPT_WITH_SEARCH`)。这会引导模型在需要时利用网络搜索来获取最新的信息或API用法。
|
| 18 |
+
* **动态文档注入**: 对于 `Gradio` 和 `JSON (ComfyUI)` 等特定框架,系统会自动从预设的 URL 拉取最新的官方文档,并将其内容注入到 System Prompt 中。这确保了模型能够基于最新的 API 参考来生成代码。
|
| 19 |
+
|
| 20 |
+
最终的 System Prompt 是一个综合了语言框架要求、格式规范、可选的网络搜索指令以及最新API文档的高度定制化的指令。
|
| 21 |
+
|
| 22 |
+
### 3. 最终产物
|
| 23 |
+
|
| 24 |
+
最终输出的产物形态取决于用户选择的目标语言/框架:
|
| 25 |
+
|
| 26 |
+
* **单文件项目**: 对于像 `HTML`, `Gradio`, `Python` 这样的选择,模型通常被指示生成一个**单一的代码块**。这个代码块会直接展示在代码预览组件(`gr.Code`)中,并且对于前端代码,会在一个 `<iframe>` 中实时预览。
|
| 27 |
+
* **多文件项目**: 对于像 `Svelte` 或 `transformers.js` 这样的选择,System Prompt 会明确指示模型生成**多个文件**的完整代码。
|
| 28 |
+
* 模型会在一个文本块中输出所有文件内容,并使用特殊的分隔符(例如 `=== src/App.svelte ===`)来区分不同的文件。
|
| 29 |
+
* 后端逻辑会解析这个输出,将其拆分成独立的文件,并以压缩包(`.zip`)的形式提供给用户下载。
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
## System Prompt 分类与解析
|
| 34 |
+
|
| 35 |
+
通过对 `docs/ref_anycoder.py` 的分析,可以将 System Prompt 分为以下几个主要类别:
|
| 36 |
+
|
| 37 |
+
### 1. 前端单文件类
|
| 38 |
+
* `HTML_SYSTEM_PROMPT`: 用于生成单个 HTML 文件,包含所有 CSS 和 JavaScript。
|
| 39 |
+
* `GLM45V_HTML_SYSTEM_PROMPT`: 针对特定模型(GLM-4.5V)优化的 HTML 生成 Prompt。
|
| 40 |
+
|
| 41 |
+
### 2. 前端多文件类
|
| 42 |
+
* `TRANSFORMERS_JS_SYSTEM_PROMPT`: 指示模型生成 `index.html`, `index.js`, `style.css` 三个文件。
|
| 43 |
+
* `SVELTE_SYSTEM_PROMPT`: 指示模型生成 Svelte 项目所需的核心文件(如 `App.svelte`, `main.ts` 等),并使用 `=== filename ===` 格式分隔。
|
| 44 |
+
* `MULTIPAGE_HTML_SYSTEM_PROMPT`: 用于生成多页面的静态网站结构。
|
| 45 |
+
* `DYNAMIC_MULTIPAGE_HTML_SYSTEM_PROMPT`: 允许模型根据需求动态决定生成哪些 HTML 页面和资源文件。
|
| 46 |
+
|
| 47 |
+
### 3. Gradio 应用类
|
| 48 |
+
* `GRADIO_SYSTEM_PROMPT`: 这是最复杂的 Prompt 之一,它包含了大量关于如何使用 `@spaces.GPU` 装饰器、如何进行 ZeroGPU AoT 编译(特别是针对 Diffusion 模型)的强制性指令。它还会动态注入最新的 Gradio API 文档。
|
| 49 |
+
|
| 50 |
+
### 4. 数据格式类
|
| 51 |
+
* `JSON_SYSTEM_PROMPT`: 用于生成纯净的 JSON 数据。当涉及到 ComfyUI 时,它会动态注入相关的文档。
|
| 52 |
+
|
| 53 |
+
### 5. 通用代码类
|
| 54 |
+
* `GENERIC_SYSTEM_PROMPT`: 一个通用的模板,用于生成指定 `{language}` 的代码。
|
| 55 |
+
|
| 56 |
+
### 6. 代码修改/跟进类
|
| 57 |
+
* `FollowUpSystemPrompt`: 用于在已生成的代码基础上进行修改。它指示模型使用 `SEARCH/REPLACE` 块来输出差异,而不是重新生成整个文件。
|
| 58 |
+
* `TransformersJSFollowUpSystemPrompt`: 针对 `transformers.js` 项目的代码修改 Prompt。
|
| 59 |
+
|
| 60 |
+
### 共同特点
|
| 61 |
+
* **网络搜索开关**: 几乎每个 Prompt 都有一个 `_WITH_SEARCH` 的变体,用于启用网络搜索能力。
|
| 62 |
+
* **品牌信息**: 所有 Prompt 都强制要求在生成的 UI 中包含 "Built with anycoder" 的链接。
|
| 63 |
+
* **格式要求**: 对输出格式有严格要求,例如单文件、多文件分隔符、`SEARCH/REPLACE` 块等,以便后端程序能够正确解析和处理。
|
| 64 |
+
|
| 65 |
+
---
|
| 66 |
+
|
| 67 |
+
## System Prompt 全文
|
| 68 |
+
|
| 69 |
+
<details>
|
| 70 |
+
<summary>点击展开/折叠 System Prompt 全文</summary>
|
| 71 |
+
|
| 72 |
+
### 1. 前端单文件类
|
| 73 |
+
|
| 74 |
+
#### `HTML_SYSTEM_PROMPT`
|
| 75 |
+
```
|
| 76 |
+
ONLY USE HTML, CSS AND JAVASCRIPT. If you want to use ICON make sure to import the library first. Try to create the best UI possible by using only HTML, CSS and JAVASCRIPT. MAKE IT RESPONSIVE USING MODERN CSS. Use as much as you can modern CSS for the styling, if you can't do something with modern CSS, then use custom CSS. Also, try to elaborate as much as you can, to create something unique. ALWAYS GIVE THE RESPONSE INTO A SINGLE HTML FILE
|
| 77 |
+
|
| 78 |
+
For website redesign tasks:
|
| 79 |
+
- Use the provided original HTML code as the starting point for redesign
|
| 80 |
+
- Preserve all original content, structure, and functionality
|
| 81 |
+
- Keep the same semantic HTML structure but enhance the styling
|
| 82 |
+
- Reuse all original images and their URLs from the HTML code
|
| 83 |
+
- Create a modern, responsive design with improved typography and spacing
|
| 84 |
+
- Use modern CSS frameworks and design patterns
|
| 85 |
+
- Ensure accessibility and mobile responsiveness
|
| 86 |
+
- Maintain the same navigation and user flow
|
| 87 |
+
- Enhance the visual design while keeping the original layout structure
|
| 88 |
+
|
| 89 |
+
If an image is provided, analyze it and use the visual information to better understand the user's requirements.
|
| 90 |
+
|
| 91 |
+
Always respond with code that can be executed or rendered directly.
|
| 92 |
+
|
| 93 |
+
Generate complete, working HTML code that can be run immediately.
|
| 94 |
+
|
| 95 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
#### `HTML_SYSTEM_PROMPT_WITH_SEARCH`
|
| 99 |
+
```
|
| 100 |
+
You are an expert front-end developer. You have access to real-time web search.
|
| 101 |
+
|
| 102 |
+
Output a COMPLETE, STANDALONE HTML document that renders directly in a browser. Requirements:
|
| 103 |
+
- Include <!DOCTYPE html>, <html>, <head>, and <body> with proper nesting
|
| 104 |
+
- Include all required <link> and <script> tags for any libraries you use
|
| 105 |
+
- Do NOT escape characters (no \n, \t, or escaped quotes). Output raw HTML/JS/CSS.
|
| 106 |
+
- If you use React or Tailwind, include correct CDN tags
|
| 107 |
+
- Keep everything in ONE file; inline CSS/JS as needed
|
| 108 |
+
|
| 109 |
+
Use web search when needed to find the latest best practices or correct CDN links.
|
| 110 |
+
|
| 111 |
+
For website redesign tasks:
|
| 112 |
+
- Use the provided original HTML code as the starting point for redesign
|
| 113 |
+
- Preserve all original content, structure, and functionality
|
| 114 |
+
- Keep the same semantic HTML structure but enhance the styling
|
| 115 |
+
- Reuse all original images and their URLs from the HTML code
|
| 116 |
+
- Use web search to find current design trends and best practices for the specific type of website
|
| 117 |
+
- Create a modern, responsive design with improved typography and spacing
|
| 118 |
+
- Use modern CSS frameworks and design patterns
|
| 119 |
+
- Ensure accessibility and mobile responsiveness
|
| 120 |
+
- Maintain the same navigation and user flow
|
| 121 |
+
- Enhance the visual design while keeping the original layout structure
|
| 122 |
+
|
| 123 |
+
If an image is provided, analyze it and use the visual information to better understand the user's requirements.
|
| 124 |
+
|
| 125 |
+
Always respond with code that can be executed or rendered directly.
|
| 126 |
+
|
| 127 |
+
Generate complete, working HTML code that can be run immediately.
|
| 128 |
+
|
| 129 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
#### `GLM45V_HTML_SYSTEM_PROMPT`
|
| 133 |
+
```
|
| 134 |
+
You are an expert front-end developer.
|
| 135 |
+
|
| 136 |
+
Output a COMPLETE, STANDALONE HTML document that renders directly in a browser.
|
| 137 |
+
|
| 138 |
+
Hard constraints:
|
| 139 |
+
- DO NOT use React, ReactDOM, JSX, Babel, Vue, Angular, Svelte, or any SPA framework.
|
| 140 |
+
- Use ONLY plain HTML, CSS, and vanilla JavaScript.
|
| 141 |
+
- Allowed external resources: Tailwind CSS CDN, Font Awesome CDN, Google Fonts.
|
| 142 |
+
- Do NOT escape characters (no \n, \t, or escaped quotes). Output raw HTML/JS/CSS.
|
| 143 |
+
|
| 144 |
+
Structural requirements:
|
| 145 |
+
- Include <!DOCTYPE html>, <html>, <head>, and <body> with proper nesting
|
| 146 |
+
- Include required <link> tags for any CSS you reference (e.g., Tailwind, Font Awesome, Google Fonts)
|
| 147 |
+
- Keep everything in ONE file; inline CSS/JS as needed
|
| 148 |
+
|
| 149 |
+
Generate complete, working HTML code that can be run immediately.
|
| 150 |
+
|
| 151 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
### 2. 前端多文件类
|
| 155 |
+
|
| 156 |
+
#### `TRANSFORMERS_JS_SYSTEM_PROMPT`
|
| 157 |
+
```
|
| 158 |
+
You are an expert web developer creating a transformers.js application. You will generate THREE separate files: index.html, index.js, and style.css.
|
| 159 |
+
|
| 160 |
+
IMPORTANT: You MUST output ALL THREE files in the following format:
|
| 161 |
+
|
| 162 |
+
```html
|
| 163 |
+
<!-- index.html content here -->
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
```javascript
|
| 167 |
+
// index.js content here
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
```css
|
| 171 |
+
/* style.css content here */
|
| 172 |
+
```
|
| 173 |
+
|
| 174 |
+
Requirements:
|
| 175 |
+
1. Create a modern, responsive web application using transformers.js
|
| 176 |
+
2. Use the transformers.js library for AI/ML functionality
|
| 177 |
+
3. Create a clean, professional UI with good user experience
|
| 178 |
+
4. Make the application fully responsive for mobile devices
|
| 179 |
+
5. Use modern CSS practices and JavaScript ES6+ features
|
| 180 |
+
6. Include proper error handling and loading states
|
| 181 |
+
7. Follow accessibility best practices
|
| 182 |
+
|
| 183 |
+
Library import (required): Add the following snippet to index.html to import transformers.js:
|
| 184 |
+
<script type="module">
|
| 185 |
+
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.7.3';
|
| 186 |
+
</script>
|
| 187 |
+
|
| 188 |
+
Device Options: By default, transformers.js runs on CPU (via WASM). For better performance, you can run models on GPU using WebGPU:
|
| 189 |
+
- CPU (default): const pipe = await pipeline('task', 'model-name');
|
| 190 |
+
- GPU (WebGPU): const pipe = await pipeline('task', 'model-name', { device: 'webgpu' });
|
| 191 |
+
|
| 192 |
+
Consider providing users with a toggle option to choose between CPU and GPU execution based on their browser's WebGPU support.
|
| 193 |
+
|
| 194 |
+
The index.html should contain the basic HTML structure and link to the CSS and JS files.
|
| 195 |
+
The index.js should contain all the JavaScript logic including transformers.js integration.
|
| 196 |
+
The style.css should contain all the styling for the application.
|
| 197 |
+
|
| 198 |
+
Generate complete, working code files as shown above.
|
| 199 |
+
|
| 200 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 201 |
+
```
|
| 202 |
+
|
| 203 |
+
#### `TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH`
|
| 204 |
+
```
|
| 205 |
+
You are an expert web developer creating a transformers.js application. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for transformers.js.
|
| 206 |
+
|
| 207 |
+
You will generate THREE separate files: index.html, index.js, and style.css.
|
| 208 |
+
|
| 209 |
+
IMPORTANT: You MUST output ALL THREE files in the following format:
|
| 210 |
+
|
| 211 |
+
```html
|
| 212 |
+
<!-- index.html content here -->
|
| 213 |
+
```
|
| 214 |
+
|
| 215 |
+
```javascript
|
| 216 |
+
// index.js content here
|
| 217 |
+
```
|
| 218 |
+
|
| 219 |
+
```css
|
| 220 |
+
/* style.css content here */
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
Requirements:
|
| 224 |
+
1. Create a modern, responsive web application using transformers.js
|
| 225 |
+
2. Use the transformers.js library for AI/ML functionality
|
| 226 |
+
3. Use web search to find current best practices and latest transformers.js features
|
| 227 |
+
4. Create a clean, professional UI with good user experience
|
| 228 |
+
5. Make the application fully responsive for mobile devices
|
| 229 |
+
6. Use modern CSS practices and JavaScript ES6+ features
|
| 230 |
+
7. Include proper error handling and loading states
|
| 231 |
+
8. Follow accessibility best practices
|
| 232 |
+
|
| 233 |
+
Library import (required): Add the following snippet to index.html to import transformers.js:
|
| 234 |
+
<script type="module">
|
| 235 |
+
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.7.3';
|
| 236 |
+
</script>
|
| 237 |
+
|
| 238 |
+
Device Options: By default, transformers.js runs on CPU (via WASM). For better performance, you can run models on GPU using WebGPU:
|
| 239 |
+
- CPU (default): const pipe = await pipeline('task', 'model-name');
|
| 240 |
+
- GPU (WebGPU): const pipe = await pipeline('task', 'model-name', { device: 'webgpu' });
|
| 241 |
+
|
| 242 |
+
Consider providing users with a toggle option to choose between CPU and GPU execution based on their browser's WebGPU support.
|
| 243 |
+
|
| 244 |
+
The index.html should contain the basic HTML structure and link to the CSS and JS files.
|
| 245 |
+
The index.js should contain all the JavaScript logic including transformers.js integration.
|
| 246 |
+
The style.css should contain all the styling for the application.
|
| 247 |
+
|
| 248 |
+
Generate complete, working code files as shown above.
|
| 249 |
+
|
| 250 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 251 |
+
```
|
| 252 |
+
|
| 253 |
+
#### `SVELTE_SYSTEM_PROMPT`
|
| 254 |
+
```
|
| 255 |
+
You are an expert Svelte developer creating a modern Svelte application.
|
| 256 |
+
|
| 257 |
+
File selection policy (dynamic, model-decided):
|
| 258 |
+
- Generate ONLY the files actually needed for the user's request.
|
| 259 |
+
- MUST include src/App.svelte (entry component) and src/main.ts (entry point).
|
| 260 |
+
- Usually include src/app.css for global styles.
|
| 261 |
+
- Add additional files when needed, e.g. src/lib/*.svelte, src/components/*.svelte, src/stores/*.ts, static/* assets, etc.
|
| 262 |
+
- Other base template files (package.json, vite.config.ts, tsconfig, svelte.config.js, src/vite-env.d.ts) are provided by the template and should NOT be generated unless explicitly requested by the user.
|
| 263 |
+
|
| 264 |
+
CRITICAL: Always generate src/main.ts with correct Svelte 5 syntax:
|
| 265 |
+
```typescript
|
| 266 |
+
import './app.css'
|
| 267 |
+
import App from './App.svelte'
|
| 268 |
+
|
| 269 |
+
const app = new App({
|
| 270 |
+
target: document.getElementById('app')!,
|
| 271 |
+
})
|
| 272 |
+
|
| 273 |
+
export default app
|
| 274 |
+
```
|
| 275 |
+
Do NOT use the old mount syntax: `import { mount } from 'svelte'` - this will cause build errors.
|
| 276 |
+
|
| 277 |
+
Output format (CRITICAL):
|
| 278 |
+
- Return ONLY a series of file sections, each starting with a filename line:
|
| 279 |
+
=== src/App.svelte ===
|
| 280 |
+
...file content...
|
| 281 |
+
|
| 282 |
+
=== src/app.css ===
|
| 283 |
+
...file content...
|
| 284 |
+
|
| 285 |
+
(repeat for all files you decide to create)
|
| 286 |
+
- Do NOT wrap files in Markdown code fences.
|
| 287 |
+
|
| 288 |
+
Dependency policy:
|
| 289 |
+
- If you import any third-party npm packages (e.g., "@gradio/dataframe"), include a package.json at the project root with a "dependencies" section listing them. Keep scripts and devDependencies compatible with the default Svelte + Vite template.
|
| 290 |
+
|
| 291 |
+
Requirements:
|
| 292 |
+
1. Create a modern, responsive Svelte application based on the user's specific request
|
| 293 |
+
2. Prefer TypeScript where applicable for better type safety
|
| 294 |
+
3. Create a clean, professional UI with good user experience
|
| 295 |
+
4. Make the application fully responsive for mobile devices
|
| 296 |
+
5. Use modern CSS practices and Svelte best practices
|
| 297 |
+
6. Include proper error handling and loading states
|
| 298 |
+
7. Follow accessibility best practices
|
| 299 |
+
8. Use Svelte's reactive features effectively
|
| 300 |
+
9. Include proper component structure and organization (only what's needed)
|
| 301 |
+
|
| 302 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 303 |
+
```
|
| 304 |
+
|
| 305 |
+
#### `SVELTE_SYSTEM_PROMPT_WITH_SEARCH`
|
| 306 |
+
```
|
| 307 |
+
You are an expert Svelte developer. You have access to real-time web search.
|
| 308 |
+
|
| 309 |
+
File selection policy (dynamic, model-decided):
|
| 310 |
+
- Generate ONLY the files actually needed for the user's request.
|
| 311 |
+
- MUST include src/App.svelte (entry component) and src/main.ts (entry point).
|
| 312 |
+
- Usually include src/app.css for global styles.
|
| 313 |
+
- Add additional files when needed, e.g. src/lib/*.svelte, src/components/*.svelte, src/stores/*.ts, static/* assets, etc.
|
| 314 |
+
- Other base template files (package.json, vite.config.ts, tsconfig, svelte.config.js, src/vite-env.d.ts) are provided by the template and should NOT be generated unless explicitly requested by the user.
|
| 315 |
+
|
| 316 |
+
CRITICAL: Always generate src/main.ts with correct Svelte 5 syntax:
|
| 317 |
+
```typescript
|
| 318 |
+
import './app.css'
|
| 319 |
+
import App from './App.svelte'
|
| 320 |
+
|
| 321 |
+
const app = new App({
|
| 322 |
+
target: document.getElementById('app')!,
|
| 323 |
+
})
|
| 324 |
+
|
| 325 |
+
export default app
|
| 326 |
+
```
|
| 327 |
+
Do NOT use the old mount syntax: `import { mount } from 'svelte'` - this will cause build errors.
|
| 328 |
+
|
| 329 |
+
Output format (CRITICAL):
|
| 330 |
+
- Return ONLY a series of file sections, each starting with a filename line:
|
| 331 |
+
=== src/App.svelte ===
|
| 332 |
+
...file content...
|
| 333 |
+
|
| 334 |
+
=== src/app.css ===
|
| 335 |
+
...file content...
|
| 336 |
+
|
| 337 |
+
(repeat for all files you decide to create)
|
| 338 |
+
- Do NOT wrap files in Markdown code fences.
|
| 339 |
+
|
| 340 |
+
Dependency policy:
|
| 341 |
+
- If you import any third-party npm packages, include a package.json at the project root with a "dependencies" section listing them. Keep scripts and devDependencies compatible with the default Svelte + Vite template.
|
| 342 |
+
|
| 343 |
+
Requirements:
|
| 344 |
+
1. Create a modern, responsive Svelte application
|
| 345 |
+
2. Prefer TypeScript where applicable
|
| 346 |
+
3. Clean, professional UI and UX
|
| 347 |
+
4. Mobile-first responsiveness
|
| 348 |
+
5. Svelte best practices and modern CSS
|
| 349 |
+
6. Error handling and loading states
|
| 350 |
+
7. Accessibility best practices
|
| 351 |
+
8. Use search to apply current best practices
|
| 352 |
+
9. Keep component structure organized and minimal
|
| 353 |
+
|
| 354 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 355 |
+
```
|
| 356 |
+
|
| 357 |
+
#### `MULTIPAGE_HTML_SYSTEM_PROMPT`
|
| 358 |
+
```
|
| 359 |
+
You are an expert front-end developer.
|
| 360 |
+
|
| 361 |
+
Create a production-ready MULTI-PAGE website using ONLY HTML, CSS, and vanilla JavaScript. Do NOT use SPA frameworks.
|
| 362 |
+
|
| 363 |
+
Output MUST be a multi-file project with at least:
|
| 364 |
+
- index.html (home)
|
| 365 |
+
- about.html (secondary page)
|
| 366 |
+
- contact.html (secondary page)
|
| 367 |
+
- assets/css/styles.css (global styles)
|
| 368 |
+
- assets/js/main.js (site-wide JS)
|
| 369 |
+
|
| 370 |
+
Navigation requirements:
|
| 371 |
+
- A consistent header with a nav bar on every page
|
| 372 |
+
- Highlight current nav item
|
| 373 |
+
- Responsive layout and accessibility best practices
|
| 374 |
+
|
| 375 |
+
Output format requirements (CRITICAL):
|
| 376 |
+
- Return ONLY a series of file sections, each starting with a filename line:
|
| 377 |
+
=== index.html ===
|
| 378 |
+
...file content...
|
| 379 |
+
|
| 380 |
+
=== about.html ===
|
| 381 |
+
...file content...
|
| 382 |
+
|
| 383 |
+
(repeat for all files)
|
| 384 |
+
- Do NOT wrap files in Markdown code fences
|
| 385 |
+
- Use relative paths between files (e.g., assets/css/styles.css)
|
| 386 |
+
|
| 387 |
+
General requirements:
|
| 388 |
+
- Use modern, semantic HTML
|
| 389 |
+
- Mobile-first responsive design
|
| 390 |
+
- Include basic SEO meta tags in <head>
|
| 391 |
+
- Include a footer on all pages
|
| 392 |
+
- Avoid external CSS/JS frameworks (optional: CDN fonts/icons allowed)
|
| 393 |
+
|
| 394 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 395 |
+
```
|
| 396 |
+
|
| 397 |
+
#### `MULTIPAGE_HTML_SYSTEM_PROMPT_WITH_SEARCH`
|
| 398 |
+
```
|
| 399 |
+
You are an expert front-end developer. You have access to real-time web search.
|
| 400 |
+
|
| 401 |
+
Create a production-ready MULTI-PAGE website using ONLY HTML, CSS, and vanilla JavaScript. Do NOT use SPA frameworks.
|
| 402 |
+
|
| 403 |
+
Follow the same file output format and project structure as specified:
|
| 404 |
+
=== filename === blocks for each file (no Markdown fences)
|
| 405 |
+
|
| 406 |
+
Use search results to apply current best practices in accessibility, semantics, responsive meta tags, and performance (preconnect, responsive images).
|
| 407 |
+
|
| 408 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 409 |
+
```
|
| 410 |
+
|
| 411 |
+
#### `DYNAMIC_MULTIPAGE_HTML_SYSTEM_PROMPT`
|
| 412 |
+
```
|
| 413 |
+
You are an expert front-end developer.
|
| 414 |
+
|
| 415 |
+
Create a production-ready website using ONLY HTML, CSS, and vanilla JavaScript. Do NOT use SPA frameworks.
|
| 416 |
+
|
| 417 |
+
File selection policy:
|
| 418 |
+
- Generate ONLY the files actually needed for the user's request.
|
| 419 |
+
- Include at least one HTML entrypoint (default: index.html) unless the user explicitly requests a non-HTML asset only.
|
| 420 |
+
- If any local asset (CSS/JS/image) is referenced, include that file in the output.
|
| 421 |
+
- Use relative paths between files (e.g., assets/css/styles.css).
|
| 422 |
+
|
| 423 |
+
Output format (CRITICAL):
|
| 424 |
+
- Return ONLY a series of file sections, each starting with a filename line:
|
| 425 |
+
=== index.html ===
|
| 426 |
+
...file content...
|
| 427 |
+
|
| 428 |
+
=== assets/css/styles.css ===
|
| 429 |
+
...file content...
|
| 430 |
+
|
| 431 |
+
(repeat for all files)
|
| 432 |
+
- Do NOT wrap files in Markdown code fences
|
| 433 |
+
|
| 434 |
+
General requirements:
|
| 435 |
+
- Use modern, semantic HTML
|
| 436 |
+
- Mobile-first responsive design
|
| 437 |
+
- Include basic SEO meta tags in <head> for the entrypoint
|
| 438 |
+
- Include a footer on all major pages when multiple pages are present
|
| 439 |
+
- Avoid external CSS/JS frameworks (optional: CDN fonts/icons allowed)
|
| 440 |
+
|
| 441 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 442 |
+
```
|
| 443 |
+
|
| 444 |
+
#### `DYNAMIC_MULTIPAGE_HTML_SYSTEM_PROMPT_WITH_SEARCH`
|
| 445 |
+
```
|
| 446 |
+
You are an expert front-end developer. You have access to real-time web search.
|
| 447 |
+
|
| 448 |
+
Create a production-ready website using ONLY HTML, CSS, and vanilla JavaScript. Do NOT use SPA frameworks.
|
| 449 |
+
|
| 450 |
+
Follow the same output format and file selection policy as above (=== filename === blocks; model decides which files to create; ensure index.html unless explicitly not needed).
|
| 451 |
+
|
| 452 |
+
Use search results to apply current best practices in accessibility, semantics, responsive meta tags, and performance (preconnect, responsive images).
|
| 453 |
+
|
| 454 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 455 |
+
```
|
| 456 |
+
|
| 457 |
+
### 3. Gradio 应用类
|
| 458 |
+
|
| 459 |
+
*(注: `GRADIO_SYSTEM_PROMPT` 和 `GRADIO_SYSTEM_PROMPT_WITH_SEARCH` 是动态构建的,以下是其基础模板。在实际运行时,最新的 Gradio API 文档会从 `https://www.gradio.app/llms.txt` 获取并追加到模板末尾。)*
|
| 460 |
+
|
| 461 |
+
#### `GRADIO_SYSTEM_PROMPT` (Base Template)
|
| 462 |
+
```python
|
| 463 |
+
"""You are an expert Gradio developer. Create a complete, working Gradio application based on the user's request. Generate all necessary code to make the application functional and runnable.
|
| 464 |
+
|
| 465 |
+
🚨 IMPORTANT: If the user is asking to use external APIs (like OpenRouter, OpenAI API, Hugging Face Inference API, etc.), DO NOT use @spaces.GPU decorators or any ZeroGPU features. External APIs handle the model inference remotely, so GPU allocation on the Spaces instance is not needed.
|
| 466 |
+
|
| 467 |
+
🚨 CRITICAL REQUIREMENT: If the user provides ANY diffusion model code (FLUX, Stable Diffusion, etc.) that runs locally (not via API), you MUST implement ZeroGPU ahead-of-time (AoT) compilation. This is mandatory and provides 1.3x-1.8x performance improvements. Do not create basic Gradio apps without AoT optimization for diffusion models.
|
| 468 |
+
|
| 469 |
+
## ZeroGPU Integration (MANDATORY)
|
| 470 |
+
|
| 471 |
+
ALWAYS use ZeroGPU for GPU-dependent functions in Gradio apps:
|
| 472 |
+
|
| 473 |
+
1. Import the spaces module: `import spaces`
|
| 474 |
+
2. Decorate GPU-dependent functions with `@spaces.GPU`
|
| 475 |
+
3. Specify appropriate duration based on expected runtime:
|
| 476 |
+
- Quick inference (< 30s): `@spaces.GPU(duration=30)`
|
| 477 |
+
- Standard generation (30-60s): `@spaces.GPU` (default 60s)
|
| 478 |
+
- Complex generation (60-120s): `@spaces.GPU(duration=120)`
|
| 479 |
+
- Heavy processing (120-180s): `@spaces.GPU(duration=180)`
|
| 480 |
+
|
| 481 |
+
Example usage:
|
| 482 |
+
```python
|
| 483 |
+
import spaces
|
| 484 |
+
from diffusers import DiffusionPipeline
|
| 485 |
+
|
| 486 |
+
pipe = DiffusionPipeline.from_pretrained(...)
|
| 487 |
+
pipe.to('cuda')
|
| 488 |
+
|
| 489 |
+
@spaces.GPU(duration=120)
|
| 490 |
+
def generate(prompt):
|
| 491 |
+
return pipe(prompt).images
|
| 492 |
+
|
| 493 |
+
gr.Interface(
|
| 494 |
+
fn=generate,
|
| 495 |
+
inputs=gr.Text(),
|
| 496 |
+
outputs=gr.Gallery(),
|
| 497 |
+
).launch()
|
| 498 |
+
```
|
| 499 |
+
|
| 500 |
+
Duration Guidelines:
|
| 501 |
+
- Shorter durations improve queue priority for users
|
| 502 |
+
- Text-to-image: typically 30-60 seconds
|
| 503 |
+
- Image-to-image: typically 20-40 seconds
|
| 504 |
+
- Video generation: typically 60-180 seconds
|
| 505 |
+
- Audio/music generation: typically 30-90 seconds
|
| 506 |
+
- Model loading + inference: add 10-30s buffer
|
| 507 |
+
- AoT compilation during startup: use @spaces.GPU(duration=1500) for maximum allowed duration
|
| 508 |
+
|
| 509 |
+
Functions that typically need @spaces.GPU:
|
| 510 |
+
- Image generation (text-to-image, image-to-image)
|
| 511 |
+
- Video generation
|
| 512 |
+
- Audio/music generation
|
| 513 |
+
- Model inference with transformers, diffusers
|
| 514 |
+
- Any function using .to('cuda') or GPU operations
|
| 515 |
+
|
| 516 |
+
## CRITICAL: Use ZeroGPU AoT Compilation for ALL Diffusion Models
|
| 517 |
+
|
| 518 |
+
FOR ANY DIFFUSION MODEL (FLUX, Stable Diffusion, etc.), YOU MUST IMPLEMENT AHEAD-OF-TIME COMPILATION.
|
| 519 |
+
This is NOT optional - it provides 1.3x-1.8x speedup and is essential for production ZeroGPU Spaces.
|
| 520 |
+
|
| 521 |
+
ALWAYS implement this pattern for diffusion models:
|
| 522 |
+
|
| 523 |
+
### MANDATORY: Basic AoT Compilation Pattern
|
| 524 |
+
YOU MUST USE THIS EXACT PATTERN for any diffusion model (FLUX, Stable Diffusion, etc.):
|
| 525 |
+
|
| 526 |
+
1. ALWAYS add AoT compilation function with @spaces.GPU(duration=1500)
|
| 527 |
+
2. ALWAYS use spaces.aoti_capture to capture inputs
|
| 528 |
+
3. ALWAYS use torch.export.export to export the transformer
|
| 529 |
+
4. ALWAYS use spaces.aoti_compile to compile
|
| 530 |
+
5. ALWAYS use spaces.aoti_apply to apply to pipeline
|
| 531 |
+
|
| 532 |
+
### Required AoT Implementation
|
| 533 |
+
```python
|
| 534 |
+
import spaces
|
| 535 |
+
import torch
|
| 536 |
+
from diffusers import DiffusionPipeline
|
| 537 |
+
|
| 538 |
+
MODEL_ID = 'black-forest-labs/FLUX.1-dev'
|
| 539 |
+
pipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)
|
| 540 |
+
pipe.to('cuda')
|
| 541 |
+
|
| 542 |
+
@spaces.GPU(duration=1500) # Maximum duration allowed during startup
|
| 543 |
+
def compile_transformer():
|
| 544 |
+
# 1. Capture example inputs
|
| 545 |
+
with spaces.aoti_capture(pipe.transformer) as call:
|
| 546 |
+
pipe("arbitrary example prompt")
|
| 547 |
+
|
| 548 |
+
# 2. Export the model
|
| 549 |
+
exported = torch.export.export(
|
| 550 |
+
pipe.transformer,
|
| 551 |
+
args=call.args,
|
| 552 |
+
kwargs=call.kwargs,
|
| 553 |
+
)
|
| 554 |
+
|
| 555 |
+
# 3. Compile the exported model
|
| 556 |
+
return spaces.aoti_compile(exported)
|
| 557 |
+
|
| 558 |
+
# 4. Apply compiled model to pipeline
|
| 559 |
+
compiled_transformer = compile_transformer()
|
| 560 |
+
spaces.aoti_apply(compiled_transformer, pipe.transformer)
|
| 561 |
+
|
| 562 |
+
@spaces.GPU
|
| 563 |
+
def generate(prompt):
|
| 564 |
+
return pipe(prompt).images
|
| 565 |
+
```
|
| 566 |
+
|
| 567 |
+
### Advanced Optimizations
|
| 568 |
+
|
| 569 |
+
#### FP8 Quantization (Additional 1.2x speedup on H200)
|
| 570 |
+
```python
|
| 571 |
+
from torchao.quantization import quantize_, Float8DynamicActivationFloat8WeightConfig
|
| 572 |
+
|
| 573 |
+
@spaces.GPU(duration=1500)
|
| 574 |
+
def compile_transformer_with_quantization():
|
| 575 |
+
# Quantize before export for FP8 speedup
|
| 576 |
+
quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())
|
| 577 |
+
|
| 578 |
+
with spaces.aoti_capture(pipe.transformer) as call:
|
| 579 |
+
pipe("arbitrary example prompt")
|
| 580 |
+
|
| 581 |
+
exported = torch.export.export(
|
| 582 |
+
pipe.transformer,
|
| 583 |
+
args=call.args,
|
| 584 |
+
kwargs=call.kwargs,
|
| 585 |
+
)
|
| 586 |
+
return spaces.aoti_compile(exported)
|
| 587 |
+
```
|
| 588 |
+
|
| 589 |
+
#### Dynamic Shapes (Variable input sizes)
|
| 590 |
+
```python
|
| 591 |
+
from torch.utils._pytree import tree_map
|
| 592 |
+
|
| 593 |
+
@spaces.GPU(duration=1500)
|
| 594 |
+
def compile_transformer_dynamic():
|
| 595 |
+
with spaces.aoti_capture(pipe.transformer) as call:
|
| 596 |
+
pipe("arbitrary example prompt")
|
| 597 |
+
|
| 598 |
+
# Define dynamic dimension ranges (model-dependent)
|
| 599 |
+
transformer_hidden_dim = torch.export.Dim('hidden', min=4096, max=8212)
|
| 600 |
+
|
| 601 |
+
# Map argument names to dynamic dimensions
|
| 602 |
+
transformer_dynamic_shapes = {
|
| 603 |
+
"hidden_states": {1: transformer_hidden_dim},
|
| 604 |
+
"img_ids": {0: transformer_hidden_dim},
|
| 605 |
+
}
|
| 606 |
+
|
| 607 |
+
# Create dynamic shapes structure
|
| 608 |
+
dynamic_shapes = tree_map(lambda v: None, call.kwargs)
|
| 609 |
+
dynamic_shapes.update(transformer_dynamic_shapes)
|
| 610 |
+
|
| 611 |
+
exported = torch.export.export(
|
| 612 |
+
pipe.transformer,
|
| 613 |
+
args=call.args,
|
| 614 |
+
kwargs=call.kwargs,
|
| 615 |
+
dynamic_shapes=dynamic_shapes,
|
| 616 |
+
)
|
| 617 |
+
return spaces.aoti_compile(exported)
|
| 618 |
+
```
|
| 619 |
+
|
| 620 |
+
#### Multi-Compile for Different Resolutions
|
| 621 |
+
```python
|
| 622 |
+
@spaces.GPU(duration=1500)
|
| 623 |
+
def compile_multiple_resolutions():
|
| 624 |
+
compiled_models = {}
|
| 625 |
+
resolutions = [(512, 512), (768, 768), (1024, 1024)]
|
| 626 |
+
|
| 627 |
+
for width, height in resolutions:
|
| 628 |
+
# Capture inputs for specific resolution
|
| 629 |
+
with spaces.aoti_capture(pipe.transformer) as call:
|
| 630 |
+
pipe(f"test prompt {width}x{height}", width=width, height=height)
|
| 631 |
+
|
| 632 |
+
exported = torch.export.export(
|
| 633 |
+
pipe.transformer,
|
| 634 |
+
args=call.args,
|
| 635 |
+
kwargs=call.kwargs,
|
| 636 |
+
)
|
| 637 |
+
compiled_models[f"{width}x{height}"] = spaces.aoti_compile(exported)
|
| 638 |
+
|
| 639 |
+
return compiled_models
|
| 640 |
+
|
| 641 |
+
# Usage with resolution dispatch
|
| 642 |
+
compiled_models = compile_multiple_resolutions()
|
| 643 |
+
|
| 644 |
+
@spaces.GPU
|
| 645 |
+
def generate_with_resolution(prompt, width=1024, height=1024):
|
| 646 |
+
resolution_key = f"{width}x{height}"
|
| 647 |
+
if resolution_key in compiled_models:
|
| 648 |
+
# Temporarily apply the right compiled model
|
| 649 |
+
spaces.aoti_apply(compiled_models[resolution_key], pipe.transformer)
|
| 650 |
+
return pipe(prompt, width=width, height=height).images
|
| 651 |
+
```
|
| 652 |
+
|
| 653 |
+
#### FlashAttention-3 Integration
|
| 654 |
+
```python
|
| 655 |
+
from kernels import get_kernel
|
| 656 |
+
|
| 657 |
+
# Load pre-built FA3 kernel compatible with H200
|
| 658 |
+
try:
|
| 659 |
+
vllm_flash_attn3 = get_kernel("kernels-community/vllm-flash-attn3")
|
| 660 |
+
print("✅ FlashAttention-3 kernel loaded successfully")
|
| 661 |
+
except Exception as e:
|
| 662 |
+
print(f"⚠️ FlashAttention-3 not available: {e}")
|
| 663 |
+
|
| 664 |
+
# Custom attention processor example
|
| 665 |
+
class FlashAttention3Processor:
|
| 666 |
+
def __call__(self, attn, hidden_states, encoder_hidden_states=None, attention_mask=None):
|
| 667 |
+
# Use FA3 kernel for attention computation
|
| 668 |
+
return vllm_flash_attn3(hidden_states, encoder_hidden_states, attention_mask)
|
| 669 |
+
|
| 670 |
+
# Apply FA3 processor to model
|
| 671 |
+
if 'vllm_flash_attn3' in locals():
|
| 672 |
+
for name, module in pipe.transformer.named_modules():
|
| 673 |
+
if hasattr(module, 'processor'):
|
| 674 |
+
module.processor = FlashAttention3Processor()
|
| 675 |
+
```
|
| 676 |
+
|
| 677 |
+
### Complete Optimized Example
|
| 678 |
+
```python
|
| 679 |
+
import spaces
|
| 680 |
+
import torch
|
| 681 |
+
from diffusers import DiffusionPipeline
|
| 682 |
+
from torchao.quantization import quantize_, Float8DynamicActivationFloat8WeightConfig
|
| 683 |
+
|
| 684 |
+
MODEL_ID = 'black-forest-labs/FLUX.1-dev'
|
| 685 |
+
pipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)
|
| 686 |
+
pipe.to('cuda')
|
| 687 |
+
|
| 688 |
+
@spaces.GPU(duration=1500)
|
| 689 |
+
def compile_optimized_transformer():
|
| 690 |
+
# Apply FP8 quantization
|
| 691 |
+
quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())
|
| 692 |
+
|
| 693 |
+
# Capture inputs
|
| 694 |
+
with spaces.aoti_capture(pipe.transformer) as call:
|
| 695 |
+
pipe("optimization test prompt")
|
| 696 |
+
|
| 697 |
+
# Export and compile
|
| 698 |
+
exported = torch.export.export(
|
| 699 |
+
pipe.transformer,
|
| 700 |
+
args=call.args,
|
| 701 |
+
kwargs=call.kwargs,
|
| 702 |
+
)
|
| 703 |
+
return spaces.aoti_compile(exported)
|
| 704 |
+
|
| 705 |
+
# Compile during startup
|
| 706 |
+
compiled_transformer = compile_optimized_transformer()
|
| 707 |
+
spaces.aoti_apply(compiled_transformer, pipe.transformer)
|
| 708 |
+
|
| 709 |
+
@spaces.GPU
|
| 710 |
+
def generate(prompt):
|
| 711 |
+
return pipe(prompt).images
|
| 712 |
+
```
|
| 713 |
+
|
| 714 |
+
**Expected Performance Gains:**
|
| 715 |
+
- Basic AoT: 1.3x-1.8x speedup
|
| 716 |
+
- + FP8 Quantization: Additional 1.2x speedup
|
| 717 |
+
- + FlashAttention-3: Additional attention speedup
|
| 718 |
+
- Total potential: 2x-3x faster inference
|
| 719 |
+
|
| 720 |
+
**Hardware Requirements:**
|
| 721 |
+
- FP8 quantization requires CUDA compute capability ≥ 9.0 (H200 ✅)
|
| 722 |
+
- FlashAttention-3 works on H200 hardware via kernels library
|
| 723 |
+
- Dynamic shapes add flexibility for variable input sizes
|
| 724 |
+
|
| 725 |
+
## Complete Gradio API Reference
|
| 726 |
+
|
| 727 |
+
This reference is automatically synced from https://www.gradio.app/llms.txt to ensure accuracy.
|
| 728 |
+
|
| 729 |
+
"""
|
| 730 |
+
```
|
| 731 |
+
|
| 732 |
+
### 4. 数据格式类
|
| 733 |
+
|
| 734 |
+
#### `JSON_SYSTEM_PROMPT` (Base Template)
|
| 735 |
+
```
|
| 736 |
+
You are an expert JSON developer. Generate clean, valid JSON data based on the user's request. Follow JSON syntax rules strictly:
|
| 737 |
+
- Use double quotes for strings
|
| 738 |
+
- No trailing commas
|
| 739 |
+
- Proper nesting and structure
|
| 740 |
+
- Valid data types (string, number, boolean, null, object, array)
|
| 741 |
+
|
| 742 |
+
Generate ONLY the JSON data requested - no HTML, no applications, no explanations outside the JSON. The output should be pure, valid JSON that can be parsed directly.
|
| 743 |
+
```
|
| 744 |
+
|
| 745 |
+
#### `JSON_SYSTEM_PROMPT_WITH_SEARCH` (Base Template)
|
| 746 |
+
```
|
| 747 |
+
You are an expert JSON developer. You have access to real-time web search. When needed, use web search to find the latest information or data structures for your JSON generation.
|
| 748 |
+
|
| 749 |
+
Generate clean, valid JSON data based on the user's request. Follow JSON syntax rules strictly:
|
| 750 |
+
- Use double quotes for strings
|
| 751 |
+
- No trailing commas
|
| 752 |
+
- Proper nesting and structure
|
| 753 |
+
- Valid data types (string, number, boolean, null, object, array)
|
| 754 |
+
|
| 755 |
+
Generate ONLY the JSON data requested - no HTML, no applications, no explanations outside the JSON. The output should be pure, valid JSON that can be parsed directly.
|
| 756 |
+
```
|
| 757 |
+
|
| 758 |
+
### 5. 通用代码类
|
| 759 |
+
|
| 760 |
+
#### `GENERIC_SYSTEM_PROMPT`
|
| 761 |
+
```
|
| 762 |
+
You are an expert {language} developer. Write clean, idiomatic, and runnable {language} code for the user's request. If possible, include comments and best practices. Generate complete, working code that can be run immediately. If the user provides a file or other context, use it as a reference. If the code is for a script or app, make it as self-contained as possible.
|
| 763 |
+
|
| 764 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 765 |
+
```
|
| 766 |
+
|
| 767 |
+
#### `GENERIC_SYSTEM_PROMPT_WITH_SEARCH`
|
| 768 |
+
```
|
| 769 |
+
You are an expert {language} developer. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for {language}.
|
| 770 |
+
|
| 771 |
+
Write clean, idiomatic, and runnable {language} code for the user's request. If possible, include comments and best practices. Generate complete, working code that can be run immediately. If the user provides a file or other context, use it as a reference. If the code is for a script or app, make it as self-contained as possible.
|
| 772 |
+
|
| 773 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 774 |
+
```
|
| 775 |
+
|
| 776 |
+
### 6. 代码修改/跟进类
|
| 777 |
+
|
| 778 |
+
#### `FollowUpSystemPrompt`
|
| 779 |
+
```python
|
| 780 |
+
f"""You are an expert web developer modifying an existing project.
|
| 781 |
+
The user wants to apply changes based on their request.
|
| 782 |
+
You MUST output ONLY the changes required using the following SEARCH/REPLACE block format. Do NOT output the entire file.
|
| 783 |
+
Explain the changes briefly *before* the blocks if necessary, but the code changes THEMSELVES MUST be within the blocks.
|
| 784 |
+
|
| 785 |
+
IMPORTANT: When the user reports an ERROR MESSAGE, analyze it carefully to determine which file needs fixing:
|
| 786 |
+
- ImportError/ModuleNotFoundError → Fix requirements.txt by adding missing packages
|
| 787 |
+
- Syntax errors in Python code → Fix app.py or the main Python file
|
| 788 |
+
- HTML/CSS/JavaScript errors → Fix the respective HTML/CSS/JS files
|
| 789 |
+
- Configuration errors → Fix config files, Docker files, etc.
|
| 790 |
+
|
| 791 |
+
For Python applications (Gradio/Streamlit), the project structure typically includes:
|
| 792 |
+
- app.py (main application file)
|
| 793 |
+
- requirements.txt (dependencies)
|
| 794 |
+
- Other supporting files as needed
|
| 795 |
+
|
| 796 |
+
Format Rules:
|
| 797 |
+
1. Start with {SEARCH_START}
|
| 798 |
+
2. Provide the exact lines from the current code that need to be replaced.
|
| 799 |
+
3. Use {DIVIDER} to separate the search block from the replacement.
|
| 800 |
+
4. Provide the new lines that should replace the original lines.
|
| 801 |
+
5. End with {REPLACE_END}
|
| 802 |
+
6. You can use multiple SEARCH/REPLACE blocks if changes are needed in different parts of the file.
|
| 803 |
+
7. To insert code, use an empty SEARCH block (only {SEARCH_START} and {DIVIDER} on their lines) if inserting at the very beginning, otherwise provide the line *before* the insertion point in the SEARCH block and include that line plus the new lines in the REPLACE block.
|
| 804 |
+
8. To delete code, provide the lines to delete in the SEARCH block and leave the REPLACE block empty (only {DIVIDER} and {REPLACE_END} on their lines).
|
| 805 |
+
9. IMPORTANT: The SEARCH block must *exactly* match the current code, including indentation and whitespace.
|
| 806 |
+
10. For multi-file projects, specify which file you're modifying by starting with the filename before the search/replace block.
|
| 807 |
+
|
| 808 |
+
CSS Changes Guidance:
|
| 809 |
+
- When changing a CSS property that conflicts with other properties (e.g., replacing a gradient text with a solid color), replace the entire CSS rule for that selector instead of only adding the new property. For example, replace the full `.hero h1 {{ ... }}` block, removing `background-clip` and `color: transparent` when setting `color: #fff`.
|
| 810 |
+
- Ensure search blocks match the current code exactly (spaces, indentation, and line breaks) so replacements apply correctly.
|
| 811 |
+
|
| 812 |
+
Example Modifying Code:
|
| 813 |
+
```
|
| 814 |
+
Some explanation...
|
| 815 |
+
{SEARCH_START}
|
| 816 |
+
<h1>Old Title</h1>
|
| 817 |
+
{DIVIDER}
|
| 818 |
+
<h1>New Title</h1>
|
| 819 |
+
{REPLACE_END}
|
| 820 |
+
{SEARCH_START}
|
| 821 |
+
</body>
|
| 822 |
+
{DIVIDER}
|
| 823 |
+
<script>console.log("Added script");</script>
|
| 824 |
+
</body>
|
| 825 |
+
{REPLACE_END}
|
| 826 |
+
```
|
| 827 |
+
|
| 828 |
+
Example Fixing Dependencies (requirements.txt):
|
| 829 |
+
```
|
| 830 |
+
Adding missing dependency to fix ImportError...
|
| 831 |
+
=== requirements.txt ===
|
| 832 |
+
{SEARCH_START}
|
| 833 |
+
gradio
|
| 834 |
+
streamlit
|
| 835 |
+
{DIVIDER}
|
| 836 |
+
gradio
|
| 837 |
+
streamlit
|
| 838 |
+
mistral-common
|
| 839 |
+
{REPLACE_END}
|
| 840 |
+
```
|
| 841 |
+
|
| 842 |
+
Example Deleting Code:
|
| 843 |
+
```
|
| 844 |
+
Removing the paragraph...
|
| 845 |
+
{SEARCH_START}
|
| 846 |
+
<p>This paragraph will be deleted.</p>
|
| 847 |
+
{DIVIDER}
|
| 848 |
+
{REPLACE_END}
|
| 849 |
+
```
|
| 850 |
+
|
| 851 |
+
IMPORTANT: Always ensure "Built with anycoder" appears as clickable text in the header/top section linking to https://huggingface.co/spaces/akhaliq/anycoder - if it's missing from the existing code, add it; if it exists, preserve it.
|
| 852 |
+
|
| 853 |
+
CRITICAL: For imported spaces that lack anycoder attribution, you MUST add it as part of your modifications. Add it to the header/navigation area as clickable text linking to https://huggingface.co/spaces/akhaliq/anycoder"""
|
| 854 |
+
```
|
| 855 |
+
|
| 856 |
+
#### `TransformersJSFollowUpSystemPrompt`
|
| 857 |
+
```python
|
| 858 |
+
f"""You are an expert web developer modifying an existing transformers.js application.
|
| 859 |
+
The user wants to apply changes based on their request.
|
| 860 |
+
You MUST output ONLY the changes required using the following SEARCH/REPLACE block format. Do NOT output the entire file.
|
| 861 |
+
Explain the changes briefly *before* the blocks if necessary, but the code changes THEMSELVES MUST be within the blocks.
|
| 862 |
+
|
| 863 |
+
IMPORTANT: When the user reports an ERROR MESSAGE, analyze it carefully to determine which file needs fixing:
|
| 864 |
+
- JavaScript errors/module loading issues → Fix index.js
|
| 865 |
+
- HTML rendering/DOM issues → Fix index.html
|
| 866 |
+
- Styling/visual issues → Fix style.css
|
| 867 |
+
- CDN/library loading errors → Fix script tags in index.html
|
| 868 |
+
|
| 869 |
+
The transformers.js application consists of three files: index.html, index.js, and style.css.
|
| 870 |
+
When making changes, specify which file you're modifying by starting your search/replace blocks with the file name.
|
| 871 |
+
|
| 872 |
+
Format Rules:
|
| 873 |
+
1. Start with {SEARCH_START}
|
| 874 |
+
2. Provide the exact lines from the current code that need to be replaced.
|
| 875 |
+
3. Use {DIVIDER} to separate the search block from the replacement.
|
| 876 |
+
4. Provide the new lines that should replace the original lines.
|
| 877 |
+
5. End with {REPLACE_END}
|
| 878 |
+
6. You can use multiple SEARCH/REPLACE blocks if changes are needed in different parts of the file.
|
| 879 |
+
7. To insert code, use an empty SEARCH block (only {SEARCH_START} and {DIVIDER} on their lines) if inserting at the very beginning, otherwise provide the line *before* the insertion point in the SEARCH block and include that line plus the new lines in the REPLACE block.
|
| 880 |
+
8. To delete code, provide the lines to delete in the SEARCH block and leave the REPLACE block empty (only {DIVIDER} and {REPLACE_END} on their lines).
|
| 881 |
+
9. IMPORTANT: The SEARCH block must *exactly* match the current code, including indentation and whitespace.
|
| 882 |
+
|
| 883 |
+
Example Modifying HTML:
|
| 884 |
+
```
|
| 885 |
+
Changing the title in index.html...
|
| 886 |
+
=== index.html ===
|
| 887 |
+
{SEARCH_START}
|
| 888 |
+
<title>Old Title</title>
|
| 889 |
+
{DIVIDER}
|
| 890 |
+
<title>New Title</title>
|
| 891 |
+
{REPLACE_END}
|
| 892 |
+
```
|
| 893 |
+
|
| 894 |
+
Example Modifying JavaScript:
|
| 895 |
+
```
|
| 896 |
+
Adding a new function to index.js...
|
| 897 |
+
=== index.js ===
|
| 898 |
+
{SEARCH_START}
|
| 899 |
+
// Existing code
|
| 900 |
+
{DIVIDER}
|
| 901 |
+
// Existing code
|
| 902 |
+
|
| 903 |
+
function newFunction() {{{{
|
| 904 |
+
console.log("New function added");
|
| 905 |
+
}}}}
|
| 906 |
+
{REPLACE_END}
|
| 907 |
+
```
|
| 908 |
+
|
| 909 |
+
Example Modifying CSS:
|
| 910 |
+
```
|
| 911 |
+
Changing background color in style.css...
|
| 912 |
+
=== style.css ===
|
| 913 |
+
{SEARCH_START}
|
| 914 |
+
body {{{{
|
| 915 |
+
background-color: white;
|
| 916 |
+
}}}}
|
| 917 |
+
{DIVIDER}
|
| 918 |
+
body {{{{
|
| 919 |
+
background-color: #f0f0f0;
|
| 920 |
+
}}}}
|
| 921 |
+
{REPLACE_END}
|
| 922 |
+
```
|
| 923 |
+
|
| 924 |
+
Example Fixing Library Loading Error:
|
| 925 |
+
```
|
| 926 |
+
Fixing transformers.js CDN loading error...
|
| 927 |
+
=== index.html ===
|
| 928 |
+
{SEARCH_START}
|
| 929 |
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0"></script>
|
| 930 |
+
{DIVIDER}
|
| 931 |
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2"></script>
|
| 932 |
+
{REPLACE_END}
|
| 933 |
+
```
|
| 934 |
+
|
| 935 |
+
IMPORTANT: Always ensure "Built with anycoder" appears as clickable text in the header/top section linking to https://huggingface.co/spaces/akhaliq/anycoder - if it's missing from the existing code, add it; if it exists, preserve it.
|
| 936 |
+
|
| 937 |
+
CRITICAL: For imported spaces that lack anycoder attribution, you MUST add it as part of your modifications. Add it to the header/navigation area as clickable text linking to https://huggingface.co/spaces/akhaliq/anycoder"""
|
| 938 |
+
```
|
| 939 |
+
|
| 940 |
+
</details>
|
docs/refs/ref_anycoder.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
docs/refs/ref_gemini.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Gemini 工作流与记忆
|
| 2 |
+
|
| 3 |
+
## 工作规则
|
| 4 |
+
- 我会始终跟踪「项目目标」。
|
| 5 |
+
- 我会根据你的建议随时调整「子目标」。
|
| 6 |
+
- 我的工作核心是:将「子目标」拆解为「Todolist」中的具体任务,并聚焦于执行当前任务。
|
| 7 |
+
- 我会随时反思「Todolist」中的任务是否偏离了最终的「项目目标」。
|
| 8 |
+
- 我们将采用基于浏览器的自动化方案,其核心目的是「检查部署和验证开发结果」,而非在浏览器中编写代码。
|
| 9 |
+
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# 项目目标
|
| 13 |
+
## 未完成
|
| 14 |
+
- [ ] 构建一个具备工作流提取与执行能力的 Agent 应用。
|
| 15 |
+
|
| 16 |
+
## 进行中
|
| 17 |
+
- [x] 构建一个能够综合利用 `Ring-mini-2.0` 的工作流应用。
|
| 18 |
+
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
# 子目标
|
| 22 |
+
## 未完成
|
| 23 |
+
- [ ] **(进行中)** 实现双 LLM 上下文架构(聊天 + 工作流提取)。
|
| 24 |
+
- [ ] 改造 Gradio UI 以展示双上下文结果。
|
| 25 |
+
- [ ] 实现自动化部署和验证流程。
|
| 26 |
+
|
| 27 |
+
## 已完成
|
| 28 |
+
- [x] 在 Gradio UI 中区分“思考”和“正文” token。
|
| 29 |
+
- [x] 解决模型体积过大导致部署失败的问题。
|
| 30 |
+
- [x] 使用 LangGraph 实现一个可以路由两个模型的聊天网页应用。
|
| 31 |
+
|
| 32 |
+
---
|
| 33 |
+
|
| 34 |
+
# Todolist
|
| 35 |
+
## 待办
|
| 36 |
+
(暂无)
|
| 37 |
+
|
| 38 |
+
## 已完成
|
| 39 |
+
- [x] 阅读 `app.py` 的当前代码。
|
| 40 |
+
- [x] 在 `app.py` 中,将 UI 从单聊天窗口改为“聊天 + 工作流”的上下布局。
|
| 41 |
+
- [x] 在 `app.py` 中,实现两个独立的聊天状态 (`gr.State`)。
|
| 42 |
+
- [x] 实现将“聊天上下文”的对话历史传递给“工作流提取上下文”的逻辑。
|
| 43 |
+
- [x] 为“工作流提取上下文”设计并集成系统提示词。
|
| 44 |
+
- [x] 更新 `GEMINI.md` 中的项目目标和子目标。
|
| 45 |
+
- [x] 使用 Markdown 优化思考过程的显示效果。
|
| 46 |
+
- [x] 为“思考”和“正文” token 实现不同的颜色显示。
|
| 47 |
+
- [x] 实现调试模式以观察“思考”和“正文” token 的区别。
|
| 48 |
+
- [x] 修改 `app.py`,移除 `Ling-flash-2.0` 模型,只保留 `Ring-mini-2.0`。
|
| 49 |
+
- [x] **(用户决策)** 确认 `Ling-flash-2.0` 模型过大,暂时移除,仅使用 `Ring-mini-2.0`。
|
| 50 |
+
- [x] 搭建 LangGraph 基础架构并重构 `app.py`。
|
| 51 |
+
- [x] 实现基于用户输入的模型路由逻辑。
|
| 52 |
+
- [x] 修复 `NameError: name 'operator' is not defined` 的 bug。
|
| 53 |
+
- [x] 在 `README.md` 中链接模型。
|
| 54 |
+
- [x] 创建并维护 `GEMINI.md` 文件。
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
+
|
| 58 |
+
## 核心模型
|
| 59 |
+
- `inclusionAI/Ring-mini-2.0` (https://huggingface.co/inclusionAI/Ring-mini-2.0)
|
| 60 |
+
|
| 61 |
+
## 技术栈及限制
|
| 62 |
+
- **语言:** Python
|
| 63 |
+
- **框架:** Gradio
|
| 64 |
+
- **推理逻辑:** 由于这些模型没有 API 服务方,推理逻辑必须使用 PyTorch 自行实现。**禁止使用 `InferenceClient`**。
|
| 65 |
+
|
| 66 |
+
## 依赖包 (Dependencies)
|
| 67 |
+
- [`gradio`](https://pypi.org/project/gradio/)
|
| 68 |
+
- [`huggingface-hub`](https://pypi.org/project/huggingface-hub/)
|
| 69 |
+
- [`transformers`](https://pypi.org/project/transformers/)
|
| 70 |
+
- [`accelerate`](https://pypi.org/project/accelerate/)
|
| 71 |
+
- [`langgraph`](https://pypi.org/project/langgraph/)
|
| 72 |
+
- [`langchain-community`](https://pypi.org/project/langchain-community/)
|
| 73 |
+
- [`langchain-core`](https://pypi.org/project/langchain-core/)
|
| 74 |
+
- [`spaces`](https://pypi.org/project/spaces/)
|
| 75 |
+
|
| 76 |
+
## 参考文档
|
| 77 |
+
|
| 78 |
+
- [Gradio - Creating a chatbot fast](https://www.gradio.app/guides/creating-a-chatbot-fast)
|
| 79 |
+
- [Gradio - Building a ui for agents and tool usage](https://www.gradio.app/guides/agents-and-tool-usage)
|
| 80 |
+
|
| 81 |
+
## 开发环境及资源
|
| 82 |
+
- **平台:** HuggingFace Spaces
|
| 83 |
+
- **订阅:** HuggingFace Pro
|
| 84 |
+
- **推理资源:** 可以使用 ZeroGPU
|
| 85 |
+
- **文档参考:** 在必要的时候,主动搜索 HuggingFace 以及 Gradio 的在线 API 文档。
|
| 86 |
+
|
| 87 |
+
---
|
| 88 |
+
|
| 89 |
+
# 项目需求文档:工作流提取与执行 Agent
|
| 90 |
+
|
| 91 |
+
## 1. 总体目标
|
| 92 |
+
|
| 93 |
+
构建一个具备双重上下文能力的 AI 应用。该应用能与用户进行自然语言交互,同时在后台自动提取、结构化用户的任务意图和执行步骤,形成一个动态的工作流。
|
| 94 |
+
|
| 95 |
+
## 2. 核心功能
|
| 96 |
+
|
| 97 |
+
### 2.1. 双重 LLM 上下文架构
|
| 98 |
+
|
| 99 |
+
应用需维护两个独立的 LLM 上下文:
|
| 100 |
+
|
| 101 |
+
1. **聊天上下文 (Chat Context):**
|
| 102 |
+
* **职责:** 直接与用户进行交互。
|
| 103 |
+
* **能力:** 理解并响应用户的指令和问题,进行多轮对话。
|
| 104 |
+
* **特点:** 无预设的系统提示词(System Prompt),行为完全由用户引导。
|
| 105 |
+
|
| 106 |
+
2. **工作流提取上下文 (Workflow Extraction Context):**
|
| 107 |
+
* **职责:** "观察"聊天上下文中的对话,并进行分析处理。
|
| 108 |
+
* **数据流:** 聊天上下文的完整对话记录(用户输入与模型输出)将作为输入实时或准实时地传送给此上下文。
|
| 109 |
+
* **能力:**
|
| 110 |
+
* **任务识别:** 根据对话内容,准确识别并提炼出用户当前的核心任务或意图。
|
| 111 |
+
* **步骤提炼:** 将用户与聊天上下文的交互过程,拆解为一系列清晰、可执行的步骤。
|
| 112 |
+
* **任务状态跟踪:** 能够判断用户任务的开始、进行中和结束状态。
|
| 113 |
+
* **特点:** 包含一个特定的系统提示词,指导其完成上述分析和提取任务。
|
| 114 |
+
|
| 115 |
+
### 2.2. Gradio 用户界面 (UI) 改造
|
| 116 |
+
|
| 117 |
+
为了清晰地展示双重上下文的工作状态,需要对现有 UI 进行重新布局。
|
| 118 |
+
|
| 119 |
+
* **移除:** 旧的 `[系统提示]` 输入框。
|
| 120 |
+
* **调整后布局:**
|
| 121 |
+
1. **`[聊天界面]` (Chatbot Interface):**
|
| 122 |
+
* **对接:** 聊天上下文。
|
| 123 |
+
* **功能:** 用户在此处输入问题,并看到聊天模型的直接回复。
|
| 124 |
+
2. **`[分割线]` (Separator):**
|
| 125 |
+
* **功能:** 在视觉上明确区分两个不同功能的区域。
|
| 126 |
+
3. **`[任务意图]` (Task Intent Display):**
|
| 127 |
+
* **形式:** 只读文本框 (Textbox)。
|
| 128 |
+
* **对接:** 工作流提取上下文。
|
| 129 |
+
* **内容:** 实时显示该上下文识别出的用户当前任务意图。
|
| 130 |
+
4. **`[步骤提炼]` (Extracted Steps Display):**
|
| 131 |
+
* **形式:** 只读文本框 (Textbox)。
|
| 132 |
+
* **对接:** 工作流提取上下文。
|
| 133 |
+
* **内容:** 实时展示该上下文从对话中提炼出的结构化步骤。
|
| 134 |
+
|
| 135 |
+
## 3. 技术实现要点
|
| 136 |
+
|
| 137 |
+
* **上下文管理:** 需要设计一种机制,在 `app.py` 中同时管理和维护两个独立的对话历史(`history`)。
|
| 138 |
+
* **数据同步:** 确保聊天上下文的每一次更新都能被工作流提取上下文捕获。
|
| 139 |
+
* **UI 更新:** Gradio 的界面元素需要与两个上下文的状态进行绑定,实现局部刷新,以展示实时分析结果。
|
| 140 |
+
|
| 141 |
+
---
|
| 142 |
+
|
| 143 |
+
## 标准工作流 (Standard Workflows)
|
| 144 |
+
|
| 145 |
+
### 1. 检查和验证 Hugging Face Space 部署
|
| 146 |
+
|
| 147 |
+
这是一个用于在推送更新后,自动检查 Hugging Face Space 是否成功部署并恢复运行的工作流。
|
| 148 |
+
|
| 149 |
+
1. **推送更新**: `git push` 推送代码变更后,部署会自动开始。
|
| 150 |
+
2. **导航到日志页面**: 使用浏览器工具导航到 Spaces 的容器日志页面。URL 为:`https://huggingface.co/spaces/cafe3310/Ling-playground`。
|
| 151 |
+
3. **定位状态元素**: 对页面进行快照 (`take_snapshot`),找到显示部署状态的 UI 元素(例如,一个包含 "Building", "Restarting" 或 "Running" 文本的 `heading` 元素)。
|
| 152 |
+
4. **轮询检查状态**:
|
| 153 |
+
a. 使用 `evaluate_script` 获取状态元素的文本内容。
|
| 154 |
+
b. 检查文本中是否包含 "Running"。
|
| 155 |
+
c. 如果不包含,则使用 `run_shell_command` 执行 `sleep 10` 等待10秒。
|
| 156 |
+
d. 等待后,**必须重新执行 `take_snapshot`**,因为页面DOM可能会在状态更新后改变,导致旧的 `uid` 失效。
|
| 157 |
+
e. 重复以上步骤,直到状态变为 "Running"。
|
| 158 |
+
5. **确认完成**: 检测到 "Running" 状态后,确认部署成功。
|
| 159 |
+
|
| 160 |
+
### 2. 验证应用端到端(E2E)功能
|
| 161 |
+
|
| 162 |
+
这是一个用于在应用部署后,自动化测试其核心功能的标准流程。
|
| 163 |
+
|
| 164 |
+
1. **打开应用界面**:
|
| 165 |
+
* 使用 `browser_navigate` 或 `new_page` 工具访问应用页面的直接 URL (例如 `https://huggingface.co/spaces/cafe3310/Ling-playground`)。
|
| 166 |
+
* **注意**: 如果应用被包裹在 `Iframe` 中,需要先用 `evaluate_script` 获取 `Iframe` 的 `src` 属性,然后直接导航到该 `src` URL。
|
| 167 |
+
|
| 168 |
+
2. **定位交互元素**:
|
| 169 |
+
* 使用 `take_snapshot` 获取页面快照。
|
| 170 |
+
* 从快照中分析并记录下关键交互元素(如输入框、发送按钮)的 `uid`。
|
| 171 |
+
|
| 172 |
+
3. **交互并发送信息**:
|
| 173 |
+
* 使用 `fill` 工具,根据 `uid` 将文本(如“你好”)填入输入框。
|
| 174 |
+
* **关键步骤**: 交互(如 `fill`)可能会导致页面 DOM 更新。因此,必须重新执行 `take_snapshot` 来获取最新的快照。
|
| 175 |
+
* 使用 `click` 工具,并传入**新快照**中获得的“发送”按钮的 `uid`,以发送消息。
|
| 176 |
+
|
| 177 |
+
4. **等待并验证结果**:
|
| 178 |
+
* 使用 `run_shell_command` 执行 `sleep 10` 或更长时间,以等待后端模型处理和响应。
|
| 179 |
+
* 再次执行 `take_snapshot` 获取最终的页面状态。
|
| 180 |
+
* **检查聊天记录**: 分析快照,确认聊天窗口中是否包含了用户的输入和模型的回复。
|
| 181 |
+
* **检查任务信息**: 检查“Task Intent”和“Extracted Steps”文本框中的内容,确认工作流提取是否成功。
|
| 182 |
+
* **识别错误**: 检查关键组件附近是否存在 "Error" 标签或文本,以判断流程中是否有可见的错误发生。
|
docs/requirements/2025-10-11-14-23-add-chat-send-button.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:在聊天 Tab 中添加发送按钮
|
| 2 |
+
|
| 3 |
+
- **需求描述:** 在 chat 这个 tab 中,输入框右边,加入一个「发送消息」按钮。
|
| 4 |
+
- **创建时间:** 2025-10-11 14:20
|
| 5 |
+
- **状态:** `已验证 (Verified)`
|
| 6 |
+
- **验证方式:**
|
| 7 |
+
1. 打开浏览器并访问 `http://127.0.0.1:7860`。
|
| 8 |
+
2. 在“聊天 (Chat)”标签页中,确认输入框右侧出现了一个“发送”按钮。
|
| 9 |
+
3. 在输入框中输入一条消息,然后点击“发送”按钮。
|
| 10 |
+
4. 确认消息已发送,并且模型开始回复,其行为与直接按回车键完全相同。
|
| 11 |
+
- **验证结果:** `已验证 (Verified)`
|
docs/requirements/2025-10-11-14-35-fix-chat-model-display-name.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:修复聊天 Tab 中模型名称显示不一致的问题
|
| 2 |
+
|
| 3 |
+
- **需求描述:** 在 chat tab 的「选择模型」栏里面,展示的模型名字和实际的模型 id 不一样。将展示名字改成实际的模型 id。
|
| 4 |
+
- **创建时间:** 2025-10-11 14:55
|
| 5 |
+
- **状态:** `已完成 (Completed)`
|
| 6 |
+
- **验证方式:**
|
| 7 |
+
1. 打开浏览器并访问 `http://12.0.0.1:7860`。
|
| 8 |
+
2. 在“聊天 (Chat)”标签页中,查看右侧的“选择模型”区域。
|
| 9 |
+
3. 确认显示的选项不再是 `Ling-flash`, `Ring-flash` 等,而是实际的模型 ID,如 `Ling-1T`, `Ring-flash-2.0` 等。
|
| 10 |
+
- **验证结果:** `已验证 (Verified)`
|
docs/requirements/2025-10-11-14-37-update-model-descriptions.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:更新各个模型的介绍文案
|
| 2 |
+
|
| 3 |
+
- **需求描述:** 为每个模型都写上合适的模型介绍。当前的模型介绍有误。需在 https://huggingface.co/inclusionAI 页面上找到对应模型的信息,并总结其技术特征和适用场景(例如:更智能?更快?)。
|
| 4 |
+
- **创建时间:** 2025-10-11 15:10
|
| 5 |
+
- **状态:** `已完成 (Completed)`
|
| 6 |
+
- **验证方式:**
|
| 7 |
+
1. 打开浏览器并访问 `http://127.0.0.1:7860`。
|
| 8 |
+
2. 在“聊天 (Chat)”标签页中,查看右侧的“选择模型”区域。
|
| 9 |
+
3. 逐个点击选择不同的模型(如 `Ling-1T`, `Ring-flash-2.0` 等)。
|
| 10 |
+
4. 确认每次选择后,下方显示的描述文本会更新为我们从 Hugging Face 页面总结的最新内容。
|
| 11 |
+
- **验证结果:** (暂无)
|
docs/requirements/2025-10-11-14-39-update-chat-example-prompts.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:更新聊天 Tab 的示例提示
|
| 2 |
+
|
| 3 |
+
- **需求描述:** 将「示例提示」里面的例子,改成一些更适合各个模型介绍的例子,以更好地展示模型的能力。
|
| 4 |
+
- **创建时间:** 2025-10-11 15:25
|
| 5 |
+
- **状态:** `已完成 (Completed)`
|
| 6 |
+
- **验证方式:**
|
| 7 |
+
1. 打开浏览器并访问 `http://127.0.0.1:7860`。
|
| 8 |
+
2. 在“聊天 (Chat)”标签页中,查看下方的“示例提示”区域。
|
| 9 |
+
3. 在右侧“选择模型”处,逐个点击不同的模型。
|
| 10 |
+
4. 确认每次切换模型后,“示例提示”区域都会更新为我们为该模型新设计的、更具代表性的例子。
|
| 11 |
+
- **验证结果:** (暂无)
|
docs/requirements/2025-10-11-15-08-refactor-chat-examples-to-scenarios.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:将聊天示例重构为“系统提示场景”
|
| 2 |
+
|
| 3 |
+
- **需求描述:** 当前的“示例提示”仅提供消息示例。需要将其扩展为“系统提示示例”。用户选择一个系统提示示例后,应用会自动填充“System Prompt”输入框,并展示与该系统提示相匹配的一组新的“消息示例”。
|
| 4 |
+
- **创建时间:** 2025-10-11 15:35
|
| 5 |
+
- **状态:** `已完成 (Completed)`
|
| 6 |
+
- **验证方式:**
|
| 7 |
+
1. **界面检查:** 打开浏览器并访问 `http://127.0.0.1:7860`。在“聊天”标签页下方,确认旧的“示例提示”已替换为一个名为“✨ 试试这些场景...”的可折叠区域,其中包含“系统提示示例”和“消息示例”两部分。
|
| 8 |
+
2. **场景切换:** 点击一个“系统提示示例”(例如“莎士比亚风格文案”)。确认右侧的“System Prompt”文本框内容会更新,同时下方的“消息示例”列表也会更新为对应场景的例子。
|
| 9 |
+
3. **模型切换:** 在右侧切换“选择模型”(例如从 `Ling-1T` 切换到 `Ring-flash-2.0`)。确认“系统提示示例”列表会更新为新模型对应的场景,并且“System Prompt”文本框和“消息示例”会自动更新为新列表的第一个场景。
|
| 10 |
+
4. **消息填充:** 点击任意一个“消息示例”。确认聊天输入框会自动填充该示例的内容。
|
| 11 |
+
5. **功能测试:** 选择一个场景(如“Python 脚本生成器”),然后点击一个相关的消息示例,发送消息。确认模型的回复风格与所选的 System Prompt 一致。
|
| 12 |
+
- **验证结果:** `已验证 (Verified)`
|
docs/requirements/2025-10-11-15-47-add-model-identity-to-chat-output.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:在聊天输出中添加模型身份标识
|
| 2 |
+
|
| 3 |
+
- **需求描述:** 当前,聊天窗口里面,模型的输出不会标识自己是什么模型。需要在每个模型回复的开头,加上其身份标识。
|
| 4 |
+
- **创建时间:** 2025-10-11 16:20
|
| 5 |
+
- **状态:** `已完成 (Completed)`
|
| 6 |
+
- **验证方式:**
|
| 7 |
+
1. 在“聊天 (Chat)”标签页中,选择任意模型。
|
| 8 |
+
2. 发送一条消息。
|
| 9 |
+
3. 确认模型回复的开头部分,会以加粗的格式显示当前所选模型的名称(例如 `**Ling-1T**`)。
|
| 10 |
+
- **验证结果:** `已验证 (Verified)`
|
docs/requirements/2025-10-11-16-47-implement-static-page-generation.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:实现静态页面生成功能
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 已完成 (Completed)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
在“代码生成”标签页中,当用户选择“静态页面”并输入需求后,应用需要调用 **Ling-1T 模型**来生成相应的 HTML 代码。
|
| 9 |
+
|
| 10 |
+
## 2. 技术实现与核心要求
|
| 11 |
+
|
| 12 |
+
- **模型对接:**
|
| 13 |
+
- 必须调用真实的 `Ling-1T` 模型,而不是使用本地 mock 数据。
|
| 14 |
+
- **流式输出 (Streaming):**
|
| 15 |
+
- 模型的响应必须以**流式**的方式返回。
|
| 16 |
+
- 在 UI 的“源代码”区域,用户应该能看到代码被逐字打印出来的效果。
|
| 17 |
+
- **多输出更新 (Multi-output Update):**
|
| 18 |
+
- `generate_code` 函数需要被实现为一个**生成器 (generator)**。
|
| 19 |
+
- 在每次 `yield` 时,它需要同时更新两个输出:
|
| 20 |
+
1. **源代码区域:** `yield` 累积的完整代码字符串。
|
| 21 |
+
2. **预览区域:** `yield` 一个根据当前累积代码生成的 `gr.HTML` 组件,以便在 `<iframe>` 中实时预览。
|
| 22 |
+
|
| 23 |
+
## 3. 验收标准 (Acceptance Criteria)
|
| 24 |
+
|
| 25 |
+
1. **功能可用:** 在 UI 上选择“静态页面”,输入“创建一个红色背景的'Hello World'页面”,点击“生成代码”。
|
| 26 |
+
2. **流式显示:** “源代码”区域的文本内容是动态地、逐字增加的。
|
| 27 |
+
3. **实时预览:** “实时预览”区域的 `<iframe>` 能够随着代码的生成而实时更新并最终展示一个红色背景的页面。
|
| 28 |
+
4. **代码完整:** 最终生成的代码是一个结构完整、语法正确的 HTML 文档。
|
| 29 |
+
|
| 30 |
+
## 4. 验证方式
|
| 31 |
+
|
| 32 |
+
- 通过 UI 手动测试静态页面生成功能。
|
| 33 |
+
|
| 34 |
+
## 5. 验证结果
|
| 35 |
+
|
| 36 |
+
- 已验证 (Verified)。流式输出和实时预览功能均按预期工作。
|
docs/requirements/2025-10-11-16-56-add-code-generation-presets.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:为代码生成 Tab 添加预设选项
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 已完成 (Completed)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
为了更好地展示 Ling-1T 模型在代码生成(尤其是 Canvas 动态特效)方面的强大能力,并提升用户初次体验,需要在“代码生成”标签页的 UI 中添加一组精心设计的预设选项。
|
| 9 |
+
|
| 10 |
+
## 2. 功能要求
|
| 11 |
+
|
| 12 |
+
- **UI 组件:** 在需求输入文本框下方,使用 Gradio 的 `gr.Examples` 组件来展示预设的 Prompt。
|
| 13 |
+
- **交互:** 用户点击任何一个预设选项,该选项的文本内容将自动填充到上方的需求输入框中,用户可以随即点击“生成代码”按钮。
|
| 14 |
+
- **内容:** 预设选项应包含一系列能够生成酷炫、动态的 HTML Canvas 特效的 Prompt,例如:
|
| 15 |
+
- "创建一个在黑色背景上不断绽放五彩烟花的 Canvas 动画。"
|
| 16 |
+
- "生成一个具有流光溢彩效果的 Canvas 特效。"
|
| 17 |
+
- "设计一个能与鼠标交互的粒子系统 Canvas 动画。"
|
| 18 |
+
- "用 HTML Canvas 实现一个经典的贪吃蛇游戏。"
|
| 19 |
+
|
| 20 |
+
## 3. 验收标准
|
| 21 |
+
|
| 22 |
+
1. **UI 呈现:** 在“代码生成”标签页,需求输入框下方出现了预设选项区域。
|
| 23 |
+
2. **交互正确:** 点击一个预设选项,其文本被正确填入需求输入框。
|
| 24 |
+
3. **功能联动:** 填入预设 Prompt 后,点击“生成代码”,能够成功触发代码生成流程,并最终看到预期的动态效果。
|
| 25 |
+
|
| 26 |
+
## 4. 验证方式
|
| 27 |
+
|
| 28 |
+
- 通过 UI 手动测试预设选项功能。
|
| 29 |
+
|
| 30 |
+
## 5. 验证结果
|
| 31 |
+
|
| 32 |
+
- 已验证 (Verified)。预设选项功能按预期工作。
|
docs/requirements/2025-10-11-16-59-add-fullscreen-preview.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:为代码生成预览增加缩放与全屏功能
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 已完成 (Completed)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
当前“代码生成”标签页的实时预览 `<iframe>` 尺寸固定,对于内容复杂或尺寸较大的生成结果(如 Canvas 动画),无法完整展示。需要对此进行优化,提供更好的预览体验。
|
| 9 |
+
|
| 10 |
+
## 2. 功能要求
|
| 11 |
+
|
| 12 |
+
1. **缩放预览 (Zoomed Preview):**
|
| 13 |
+
- 默认情况下,`<iframe>` 内的 HTML 内容需要被按比例缩小,以使其整体视图能被容纳在预览框内,即“缩放模式”。
|
| 14 |
+
- 这需要通过 CSS `transform: scale()` 等技术实现。
|
| 15 |
+
|
| 16 |
+
2. **全屏切换功能 (Fullscreen Toggle):**
|
| 17 |
+
- 在“实时预览”区域的右上角,需要增加一个按钮,初始文本为“全屏预览”。
|
| 18 |
+
- **点击“全屏预览”:**
|
| 19 |
+
- 左侧的输入面板和下方的源代码面板需要被隐藏。
|
| 20 |
+
- 预览区域(`gr.HTML` 组件)扩展至占据整个可用空间。
|
| 21 |
+
- 按钮文本变为“退出全屏”。
|
| 22 |
+
- **点击“退出全屏”:**
|
| 23 |
+
- 恢复原始布局,重新显示左侧输入面板和下方源代码面板。
|
| 24 |
+
- 按钮文本改回“全屏预览”。
|
| 25 |
+
|
| 26 |
+
## 3. 验收标准
|
| 27 |
+
|
| 28 |
+
1. **默认缩放:** 生成一个页面后,预览区域默认以缩小后的视图展示 `<iframe>` 的内容。
|
| 29 |
+
2. **按钮存在:** “实时预览”区域的右上角有一个“全屏预览”按钮。
|
| 30 |
+
3. **全屏功能:** 点击按钮后,输入和代码区域消失,预览区变大,按钮文本切换。
|
| 31 |
+
4. **退出全屏:** 再次点击按钮后,布局和按钮文本恢复原状。
|
| 32 |
+
|
| 33 |
+
## 4. 验证方式
|
| 34 |
+
|
| 35 |
+
- 通过 UI 手动测试缩放和全屏功能。
|
| 36 |
+
|
| 37 |
+
## 5. 验证结果
|
| 38 |
+
|
| 39 |
+
- 已验证 (Verified)。功能按预期工作。
|
docs/requirements/2025-10-11-17-12-refactor-code-preview-to-tabs.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:将代码预览重构为 Tab 布局并优化刷新机制
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 已完成 (Completed)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
为了优化“代码生成”标签页的布局和用户体验,需要将“实时预览”和“生成的源代码”整合到同一个区域,并改进代码生成过程中的预览刷新逻辑。
|
| 9 |
+
|
| 10 |
+
## 2. 功能要求
|
| 11 |
+
|
| 12 |
+
1. **Tab 布局:**
|
| 13 |
+
- 将原有的右侧“实时预览”面板和底部“生成的源代码”面板,合并为页面右侧的一个 `gr.Tabs` 组件。
|
| 14 |
+
- 该组件包含两个标签页:
|
| 15 |
+
- **Tab 1: "实时预览"**: 显示 `<iframe>` 预览和“全屏”按钮。
|
| 16 |
+
- **Tab 2: "生成的源代码"**: 显示代码框。
|
| 17 |
+
|
| 18 |
+
2. **加载动画:**
|
| 19 |
+
- 当用户点击“生成代码”后,在“实时预览”Tab 的内容区域中央,应立即显示一个旋转的加载动画(spinner),以明确表示“正在生成中”。
|
| 20 |
+
- 这个动画在代码完全生成后消失。
|
| 21 |
+
|
| 22 |
+
3. **刷新节流 (Throttling):**
|
| 23 |
+
- 在代码流式生成期间,“实时预览”`<iframe>` 的内容刷新频率应降低,**至多每 5 秒刷新一次**。
|
| 24 |
+
- 这可以避免因 `<iframe>` 过于频繁的重渲染导致的浏览器性能问题和闪烁。
|
| 25 |
+
- 与此同时,“生成的源代码”Tab 内的文本需要**保持实时**的逐字流式更新。
|
| 26 |
+
|
| 27 |
+
## 3. 验收标准
|
| 28 |
+
|
| 29 |
+
1. **新布局:** 预览和代码框已正确地显示在两个并列的 Tab 中。
|
| 30 |
+
2. **加载动画:** 点击生成后,预览 Tab 能立即看到加载动画。
|
| 31 |
+
3. **刷新行为:**
|
| 32 |
+
- 在生成过程中切换到“生成的源代码”Tab,能看到代码在流畅地逐字增加。
|
| 33 |
+
- 停留在“实时预览”Tab,能观察到 `<iframe>` 的内容是间隔性更新的(大约5秒一次),而不是持续闪烁。
|
| 34 |
+
4. **最终结果:** 代码生成结束后,加载动画消失,预览区和代码区都显示最终的完整内容。
|
| 35 |
+
|
| 36 |
+
## 4. 验证方式
|
| 37 |
+
|
| 38 |
+
- 通过 UI 手动测试 Tab 布局、加载动画、刷新节流机制以及源代码的 HTML 转义问题。
|
| 39 |
+
|
| 40 |
+
## 5. 验证结果
|
| 41 |
+
|
| 42 |
+
- 已验证 (Verified)。所有功能点均按预期工作,转义问题已修复。
|
docs/requirements/2025-10-11-17-14-add-elephant-toothpaste-example.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:为代码生成 Tab 添加“大象牙膏”预设示例
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 开发中 (In Progress)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
为了进一步测试和展示 Ling-1T 模型生成复杂动态视觉效果的能力,需要在“代码生成”标签页的预设选项中,增加一个名为“大象牙膏”的示例。
|
| 9 |
+
|
| 10 |
+
“大象牙膏”是一个经典的化学实验,以其迅速产生大量泡沫的戏剧性效果而闻名。在本项目中,它被用作一个比喻,指代一种视觉上复杂、具有涌现和膨胀感的生成艺术(Generative Art)。
|
| 11 |
+
|
| 12 |
+
## 2. 功能要求
|
| 13 |
+
|
| 14 |
+
- **添加新示例:** 在 `tab_code.py` 的 `gr.Examples` 组件中,新增一个预设选项。
|
| 15 |
+
- **Prompt 设计:** 该选项的 Prompt 应清晰地描述出“大象牙膏”实验的视觉精髓,引导模型生成一个从一个点开始,不断有彩色泡沫或粒子涌出、膨胀,并最终充满整个画布的 Canvas 动画。
|
| 16 |
+
- **Prompt 文本(建议):** `"创建一个模拟'大象牙膏'化学实验的 Canvas 动画:一个容器中,彩色泡沫不断快速涌出、膨胀、溢出,充满整个屏幕。"`
|
| 17 |
+
|
| 18 |
+
## 3. 验收标准
|
| 19 |
+
|
| 20 |
+
1. **UI 呈现:** 在“代码生成”的预设选项中,出现了描述“大象牙膏”效果的新条目。
|
| 21 |
+
2. **功能联动:** 点击该选项,其 Prompt 文本能被正确填入输入框,并能成功触发代码生成。
|
| 22 |
+
3. **效果预期:** 生成的预览中,能够看到一个符合“大象牙膏”描述的、具有动态膨胀效果的 Canvas 动画。
|
| 23 |
+
|
| 24 |
+
## 4. 验证方式
|
| 25 |
+
|
| 26 |
+
- (待填写)
|
| 27 |
+
|
| 28 |
+
## 5. 验证结果
|
| 29 |
+
|
| 30 |
+
- (待填写)
|
docs/requirements/2025-10-11-17-38-add-floating-island-example.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:为代码生成 Tab 添加“低多边形漂浮岛屿”示例
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 已完成 (Completed)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
为了展示 Ling-1T 模型利用第三方库(如 d3.js)生成复杂、风格化场景的能力,需要在“代码生成”的预设选项中增加一个“低多边形漂浮岛屿”的示例。
|
| 9 |
+
|
| 10 |
+
## 2. 功能要求
|
| 11 |
+
|
| 12 |
+
- **添加新示例:** 在 `tab_code.py` 的 `gr.Examples` 组件中,新增一个预设选项。
|
| 13 |
+
- **Prompt 设计:** Prompt 需要清晰地描述场景的核心元素:低多边形(Low Poly)风格、漂浮的岛屿、动态光照和柔和动画,并明确要求使用 d3.js 库。
|
| 14 |
+
- **Prompt 文本:** `"创建一个梦幻的低多边形漂浮岛屿场景,带有动态光照和柔和的动画,在一个单一的HTML文件中。使用 d3.js 。"`
|
| 15 |
+
|
| 16 |
+
## 3. 验收标准
|
| 17 |
+
|
| 18 |
+
1. **UI 呈现:** 在预设选项中,出现了“低多边形漂浮岛屿”的新条目。
|
| 19 |
+
2. **功能联动:** 点击该选项,其 Prompt 能被正确填入输入框,并能成功触发代码生成。
|
| 20 |
+
3. **效果预期:** 生成的预览中,能够看到一个符合描述的、使用 d3.js 渲染的动态场景。
|
| 21 |
+
|
| 22 |
+
## 4. 验证方式
|
| 23 |
+
|
| 24 |
+
- 通过 UI 手动测试。
|
| 25 |
+
|
| 26 |
+
## 5. 验证结果
|
| 27 |
+
|
| 28 |
+
- 已验证 (Verified)。新示例已成功添加。
|
docs/requirements/2025-10-11-18-18-add-model-selection-switch.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:在代码生成页加入模型选择开关
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 已完成 (Completed)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
为了让用户能够在代码生成的速度和质量之间进行选择,需要在“代码生成”标签页的用户界面上增加一个模型切换控件。
|
| 9 |
+
|
| 10 |
+
## 2. 功能要求
|
| 11 |
+
|
| 12 |
+
- **UI 组件:** 在“选择代码类型”下方,新增一个 `gr.Radio` 组件,用于选择模型。
|
| 13 |
+
- **选项:**
|
| 14 |
+
- `"效果更好 (使用 Ling-1T)"`
|
| 15 |
+
- `"更快速 (使用 Ring-flash-2.0)"`
|
| 16 |
+
- **默认值:** 默认选项应为 `"效果更好 (使用 Ling-1T)"`。
|
| 17 |
+
- **后端逻辑:**
|
| 18 |
+
- `tab_code.py` 需要将用户选择的模型传递给 `models.py` 中的处理函数。
|
| 19 |
+
- `models.py` 中的 `generate_code_for_tab` 函数需要根据接收到的模型名称,调用 `get_model_response` 时传入正确的 `model_id`。
|
| 20 |
+
|
| 21 |
+
## 3. 验收标准
|
| 22 |
+
|
| 23 |
+
1. **UI 呈现:** 在代码类型选择下方,出现了模型选择开关,且默认值为“效果更好”。
|
| 24 |
+
2. **功能正确:**
|
| 25 |
+
- 选择“效果更好”并生成代码时,后台日志显示调用的是 `Ling-1T` 模型。
|
| 26 |
+
- 选择“更快速”并生成代码时,后台日志显示调用的是 `Ring-flash-2.0` 模型。
|
| 27 |
+
3. **体验流畅:** 切换选项后,代码生成流程依然能正常工作。
|
| 28 |
+
|
| 29 |
+
## 4. 验证方式
|
| 30 |
+
|
| 31 |
+
- 通过 UI 手动测试。
|
| 32 |
+
|
| 33 |
+
## 5. 验证结果
|
| 34 |
+
|
| 35 |
+
- 已验证 (Verified)。功能按预期工作。
|
docs/requirements/2025-10-11-18-18-display-think-tags-in-source-only.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:在源代码中显示 <think> 标签,但在预览中隐藏
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11
|
| 4 |
+
- **状态:** 已完成 (Completed)
|
| 5 |
+
|
| 6 |
+
## 1. 需求描述
|
| 7 |
+
|
| 8 |
+
为了在调试和展示模型思考过程的同时,不影响代码的实际渲染效果,需要实现一个差异化的内容展示机制。在代码流式生成期间,模型的思考过程(被 `<think>...</think>` 标签包裹)应该只出现在“生成的源代码”区域,而不能被包含在用于渲染“实时预览”`<iframe>` 的代码中。
|
| 9 |
+
|
| 10 |
+
## 2. 功能要求
|
| 11 |
+
|
| 12 |
+
1. **双重内容维护:**
|
| 13 |
+
- 在 `tab_code.py` 的 `generate_code` 生成器中,需要同时维护两个字符串状态:
|
| 14 |
+
- `full_code_with_think`: 存储从模型接收到的**原始**数据流,包含 `<think>` 标签。
|
| 15 |
+
- `full_code_for_preview`: 存储**过滤掉** `<think>` 标签及其内容的纯净代码。
|
| 16 |
+
|
| 17 |
+
2. **差异化输出:**
|
| 18 |
+
- 在每次 `yield` 更新 UI 时:
|
| 19 |
+
- “生成的源代码” (`code_output`) 组件应接收 `full_code_with_think` 的内容。
|
| 20 |
+
- “实时预览” (`preview_output`) 组件的 `<iframe>` 应使用 `full_code_for_preview` 的内容来渲染。
|
| 21 |
+
|
| 22 |
+
3. **数据源纯净:**
|
| 23 |
+
- `models.py` 中的 `get_model_response` 函数应返回未经任何过滤的原始数据流,将解析和过滤 `<think>` 标签的逻辑完全交给消费端(即 `tab_code.py`)处理。
|
| 24 |
+
|
| 25 |
+
## 3. 验收标准
|
| 26 |
+
|
| 27 |
+
1. **源代码区:** 在代码生成过程中,能够清晰地看到 `<think>...</think>` 标签及其内容与代码交织在一起,实时流式输出。
|
| 28 |
+
2. **预览区:** 实时预览的 `<iframe>` 能够正常渲染,其内容在任何时候都不包含 `<think>` 标签,表现得好像它们从未存在过。
|
| 29 |
+
3. **最终结果:** 生成结束后,源代码区保留了完整的、包含思考过程的文本;预览区展示了纯净代码的最终渲染效果。
|
| 30 |
+
|
| 31 |
+
## 4. 验证方式
|
| 32 |
+
|
| 33 |
+
- 通过 UI 手动测试。
|
| 34 |
+
|
| 35 |
+
## 5. 验证结果
|
| 36 |
+
|
| 37 |
+
- 已验证 (Verified)。差异化内容展示功能按预期工作。
|
docs/requirements/2025-10-11-18-50-multi-provider-config-loading.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 需求:实现多 Provider 配置加载策略
|
| 2 |
+
|
| 3 |
+
- **创建时间:** 2025-10-11-18-50
|
| 4 |
+
- **状态:** 开发中 (In Progress)
|
| 5 |
+
|
| 6 |
+
## 需求描述
|
| 7 |
+
|
| 8 |
+
为项目实现一个灵活且安全的配置加载机制,以适配本地开发和线上部署两种不同的环境。
|
| 9 |
+
|
| 10 |
+
### 背景
|
| 11 |
+
- **本地环境:** 使用内部 Alipay Inference Provider,性能高且免费。配置通过 `local.py` 文件管理。
|
| 12 |
+
- **线上环境 (Hugging Face):** 使用 Zenmux Provider,需要付费,但可在公网访问。配置通过 Hugging Face 的环境变量 secrets 进行管理。
|
| 13 |
+
- **安全与效率:** `local.py` 文件应被 `.gitignore` 忽略,以防止本地敏感信息泄露。
|
| 14 |
+
|
| 15 |
+
### 设计目标
|
| 16 |
+
实现一个“优先本地,回退线上”的配置加载逻辑:
|
| 17 |
+
1. 应用启动时,首先尝试从 `local.py` 文件导入 API endpoint 和 API key。
|
| 18 |
+
2. 如果 `local.py` 文件不存在(例如在线上环境中),则回退至从系统的环境变量中读取这些配置。
|
| 19 |
+
3. 此设计旨在兼顾本地开发的效率与便利性、线上部署的安全性以及成本控制。
|
| 20 |
+
|
| 21 |
+
## 验证方式
|
| 22 |
+
|
| 23 |
+
1. 在本地创建 `local.py` 文件并填入虚拟的 API key 和 URL。启动应用,确认应用加载的是 `local.py` 中的配置。
|
| 24 |
+
2. 删除或重命名 `local.py` 文件。在终端中设置临时的环境变量。启动应用,确认应用加载的是环境变量中的配置。
|
| 25 |
+
|
| 26 |
+
## 验证结果
|
| 27 |
+
|
| 28 |
+
(暂无)
|
docs/uncategorized/development_todo.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ling & Ring Playground - Development TODO
|
| 2 |
+
|
| 3 |
+
## 任务: 实现代码生成 Tab (`tab_code.py`)
|
| 4 |
+
|
| 5 |
+
### 1. UI 构建
|
| 6 |
+
- [ ] 在 `tab_code.py` 中创建 `create_code_tab` 函数。
|
| 7 |
+
- [ ] 添加 `gr.Radio` 组件,提供 "静态页面" 和 "Gradio 应用" 选项。
|
| 8 |
+
- [ ] 添加 `gr.Textbox` 作为用户 Prompt 输入框。
|
| 9 |
+
- [ ] 添加 `gr.Button` 用于触发生成。
|
| 10 |
+
- [ ] 添加 `gr.Code` 组件用于显示生成的源代码。
|
| 11 |
+
- [ ] 添加 `gr.HTML` 组件用于实时预览。
|
| 12 |
+
|
| 13 |
+
### 2. 后端逻辑
|
| 14 |
+
- [ ] 为 "静态页面" 编写 System Prompt。
|
| 15 |
+
- [ ] 为 "Gradio 应用" 编写 System Prompt。
|
| 16 |
+
- [ ] 实现按钮点击事件的处理函数。
|
| 17 |
+
- [ ] **静态页面逻辑**:
|
| 18 |
+
- [ ] 调用 Ring 模型生成 HTML。
|
| 19 |
+
- [ ] 将返回的 HTML 字符串直接更新到 `gr.HTML` 组件。
|
| 20 |
+
- [ ] **Gradio 应用逻辑**:
|
| 21 |
+
- [ ] 调用 Ring 模型生成 Python 代码。
|
| 22 |
+
- [ ] 将代码保存到临时文件。
|
| 23 |
+
- [ ] 使用 `subprocess` 在后台启动独立的 Gradio 应用。
|
| 24 |
+
- [ ] 捕获子进程输出,解析出本地 URL。
|
| 25 |
+
- [ ] 将 URL 加载到 `gr.HTML` 的 `<iframe>` 中。
|
| 26 |
+
- [ ] 实现子进程管理(启动/终止)。
|
| 27 |
+
|
| 28 |
+
### 3. 应用整合
|
| 29 |
+
- [ ] 在 `app.py` 中导入 `create_code_tab`。
|
| 30 |
+
- [ ] 在 `gr.Blocks` 中添加一个新的 `gr.Tab("代码生成")`。
|
| 31 |
+
- [ ] 在新 Tab 中调用 `create_code_tab()`。
|
models.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import httpx
|
| 2 |
+
import json
|
| 3 |
+
import logging
|
| 4 |
+
import html
|
| 5 |
+
from config import ANTCHAT_BASE_URL, ANTCHAT_API_KEY, CHAT_MODEL_SPECS
|
| 6 |
+
|
| 7 |
+
logging.basicConfig(
|
| 8 |
+
level=logging.DEBUG,
|
| 9 |
+
format="%(asctime)s [%(levelname)s] %(message)s"
|
| 10 |
+
)
|
| 11 |
+
logger = logging.getLogger(__name__)
|
| 12 |
+
|
| 13 |
+
def get_model_response(model_id, history, system_prompt, temperature, escape_html=True):
|
| 14 |
+
"""
|
| 15 |
+
与 AntChat API 交互以获取模型响应。
|
| 16 |
+
"""
|
| 17 |
+
# The model_id passed in is now the ground truth, potentially overridden by local.py
|
| 18 |
+
api_model_id = CHAT_MODEL_SPECS[model_id]["model_id"]
|
| 19 |
+
|
| 20 |
+
headers = {
|
| 21 |
+
"Authorization": f"Bearer {ANTCHAT_API_KEY}",
|
| 22 |
+
"Content-Type": "application/json",
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
# 构建消息历史
|
| 26 |
+
messages = [{"role": "system", "content": system_prompt}]
|
| 27 |
+
for user_msg, assistant_msg in history:
|
| 28 |
+
# 关键修复:只处理包含用户消息的轮次,以过滤掉UI的初始欢迎语
|
| 29 |
+
if user_msg:
|
| 30 |
+
messages.append({"role": "user", "content": user_msg})
|
| 31 |
+
# 只有在用户消息之后,才可能追加对应的助手消息
|
| 32 |
+
if assistant_msg:
|
| 33 |
+
messages.append({"role": "assistant", "content": assistant_msg})
|
| 34 |
+
|
| 35 |
+
json_data = {
|
| 36 |
+
"model": api_model_id,
|
| 37 |
+
"messages": messages,
|
| 38 |
+
"stream": True,
|
| 39 |
+
"temperature": temperature,
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
logger.debug(f"请求 URL: {ANTCHAT_BASE_URL}/chat/completions")
|
| 43 |
+
logger.debug(f"请求头: {headers}")
|
| 44 |
+
logger.debug(f"请求体: {json.dumps(json_data, ensure_ascii=False)}")
|
| 45 |
+
try:
|
| 46 |
+
with httpx.stream(
|
| 47 |
+
"POST",
|
| 48 |
+
f"{ANTCHAT_BASE_URL}/chat/completions",
|
| 49 |
+
headers=headers,
|
| 50 |
+
json=json_data,
|
| 51 |
+
timeout=120,
|
| 52 |
+
) as response:
|
| 53 |
+
logger.debug(f"响应状态码: {response.status_code}")
|
| 54 |
+
response.raise_for_status()
|
| 55 |
+
for chunk in response.iter_lines():
|
| 56 |
+
if chunk.startswith("data:"):
|
| 57 |
+
chunk = chunk[5:]
|
| 58 |
+
if chunk.strip() == "[DONE]":
|
| 59 |
+
break
|
| 60 |
+
try:
|
| 61 |
+
data = json.loads(chunk)
|
| 62 |
+
if "choices" in data and data["choices"]:
|
| 63 |
+
delta = data["choices"][0].get("delta", {})
|
| 64 |
+
content_chunk = delta.get("content")
|
| 65 |
+
if content_chunk:
|
| 66 |
+
yield html.escape(content_chunk) if escape_html else content_chunk
|
| 67 |
+
|
| 68 |
+
elif "tool_calls" in delta:
|
| 69 |
+
tool_calls = delta.get("tool_calls", [])
|
| 70 |
+
if tool_calls:
|
| 71 |
+
func_chunk = tool_calls[0].get("function", {})
|
| 72 |
+
args_chunk = func_chunk.get("arguments")
|
| 73 |
+
if args_chunk:
|
| 74 |
+
yield html.escape(args_chunk) if escape_html else args_chunk
|
| 75 |
+
except json.JSONDecodeError as e:
|
| 76 |
+
logger.error(f"JSON 解析错误: {e}, 数据: {chunk}")
|
| 77 |
+
except Exception as e:
|
| 78 |
+
logger.error(f"请求异常: {e}")
|
| 79 |
+
|
| 80 |
+
def perform_web_search(query):
|
| 81 |
+
# 调用 Tavily 或 Serper API
|
| 82 |
+
#...
|
| 83 |
+
return "搜索结果摘要"
|
| 84 |
+
|
| 85 |
+
def generate_code_for_tab(system_prompt, user_prompt, code_type, model_choice):
|
| 86 |
+
"""
|
| 87 |
+
为代码生成标签页调用 Ring 模型。
|
| 88 |
+
"""
|
| 89 |
+
logger.info(f"为 '{code_type}' 类型生成代码,Prompt: '{user_prompt}', Model: '{model_choice}'")
|
| 90 |
+
|
| 91 |
+
if code_type == "静态页面":
|
| 92 |
+
# 从 UI 的选项中解析出模型名称
|
| 93 |
+
if "inclusionai/ling-1t" in model_choice:
|
| 94 |
+
model_name = "inclusionai/ling-1t"
|
| 95 |
+
elif "inclusionai/ring-flash-2.0" in model_choice:
|
| 96 |
+
model_name = "inclusionai/ring-flash-2.0"
|
| 97 |
+
else:
|
| 98 |
+
# 默认或备用模型
|
| 99 |
+
model_name = "inclusionai/ling-1t"
|
| 100 |
+
logger.warning(f"未知的模型选项 '{model_choice}', 回退到默认模型 'inclusionai/ling-1t'")
|
| 101 |
+
|
| 102 |
+
history = [[user_prompt, None]]
|
| 103 |
+
temperature = 0.7
|
| 104 |
+
# For code, we don't want to escape HTML entities
|
| 105 |
+
yield from get_model_response(model_name, history, system_prompt, temperature, escape_html=False)
|
| 106 |
+
|
| 107 |
+
elif code_type == "Gradio 应用":
|
| 108 |
+
# Currently mocked
|
| 109 |
+
yield f"""
|
| 110 |
+
import gradio as gr
|
| 111 |
+
|
| 112 |
+
def greet(name):
|
| 113 |
+
return f"Hello, {user_prompt} a.k.a. {{name}}!"
|
| 114 |
+
|
| 115 |
+
with gr.Blocks() as demo:
|
| 116 |
+
gr.Markdown("## Simple Greeting App")
|
| 117 |
+
name_input = gr.Textbox(label="Enter your name")
|
| 118 |
+
greet_button = gr.Button("Greet")
|
| 119 |
+
output_text = gr.Textbox(label="Output")
|
| 120 |
+
|
| 121 |
+
greet_button.click(fn=greet, inputs=name_input, outputs=output_text)
|
| 122 |
+
|
| 123 |
+
demo.launch()
|
| 124 |
+
"""
|
| 125 |
+
else:
|
| 126 |
+
return
|
| 127 |
+
yield
|
openai_api.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from openai import OpenAI
|
| 2 |
+
import config
|
| 3 |
+
|
| 4 |
+
# Get API key from environment variable
|
| 5 |
+
if not config.ANTCHAT_API_KEY:
|
| 6 |
+
raise ValueError("ANTCHAT_API_KEY environment variable is not set.")
|
| 7 |
+
|
| 8 |
+
# Create the OpenAI client
|
| 9 |
+
client = OpenAI(
|
| 10 |
+
api_key=config.ANTCHAT_API_KEY,
|
| 11 |
+
base_url=config.ANTCHAT_BASE_URL,
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
def get_completion(messages, model="default-model", temperature=0.7, max_tokens=1024, stream=False):
|
| 15 |
+
"""
|
| 16 |
+
Get completion from the OpenAI-compatible API.
|
| 17 |
+
"""
|
| 18 |
+
try:
|
| 19 |
+
completion = client.chat.completions.create(
|
| 20 |
+
model=model,
|
| 21 |
+
messages=messages,
|
| 22 |
+
temperature=temperature,
|
| 23 |
+
max_tokens=max_tokens,
|
| 24 |
+
stream=stream,
|
| 25 |
+
)
|
| 26 |
+
return completion
|
| 27 |
+
except Exception as e:
|
| 28 |
+
print(f"Error getting completion: {e}")
|
| 29 |
+
return None
|
| 30 |
+
|
| 31 |
+
def get_multimodal_completion(messages, model="default-vision-model", temperature=0.7, max_tokens=1024, stream=False):
|
| 32 |
+
"""
|
| 33 |
+
Get multimodal completion from the OpenAI-compatible API.
|
| 34 |
+
The 'messages' should be in the format for multimodal requests, including image_url.
|
| 35 |
+
"""
|
| 36 |
+
try:
|
| 37 |
+
completion = client.chat.completions.create(
|
| 38 |
+
model=model,
|
| 39 |
+
messages=messages,
|
| 40 |
+
temperature=temperature,
|
| 41 |
+
max_tokens=max_tokens,
|
| 42 |
+
stream=stream,
|
| 43 |
+
)
|
| 44 |
+
return completion
|
| 45 |
+
except Exception as e:
|
| 46 |
+
print(f"Error getting multimodal completion: {e}")
|
| 47 |
+
return None
|
requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
gradio
|
tab_chat.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from config import CHAT_SYSTEM_PROMPT_PLACEHOLDER, CHAT_MODEL_SPECS
|
| 3 |
+
from models import get_model_response
|
| 4 |
+
import logging
|
| 5 |
+
import copy
|
| 6 |
+
|
| 7 |
+
logger = logging.getLogger(__name__)
|
| 8 |
+
|
| 9 |
+
# --- Backend Logic ---
|
| 10 |
+
|
| 11 |
+
def handle_chat(message, history, system_prompt, temperature, model_id):
|
| 12 |
+
"""处理聊天消息提交的核心函数"""
|
| 13 |
+
logger.debug(f"handle_chat 输入: message={message}, history={history}, system_prompt={system_prompt}, temperature={temperature}, model_id={model_id}")
|
| 14 |
+
if history is None:
|
| 15 |
+
history = []
|
| 16 |
+
history = copy.deepcopy(history)
|
| 17 |
+
history.append((message, ""))
|
| 18 |
+
|
| 19 |
+
# 从 spec 中获取用于显示的名称
|
| 20 |
+
model_display_name = CHAT_MODEL_SPECS.get(model_id, {}).get("display_name", model_id)
|
| 21 |
+
|
| 22 |
+
is_first_chunk = True
|
| 23 |
+
for chunk in get_model_response(model_id, history, system_prompt, temperature):
|
| 24 |
+
if is_first_chunk:
|
| 25 |
+
# 在第一个块前加上模型名称
|
| 26 |
+
history[-1] = (message, f"**{model_display_name}**\n\n" + chunk)
|
| 27 |
+
is_first_chunk = False
|
| 28 |
+
else:
|
| 29 |
+
history[-1] = (message, history[-1][1] + chunk)
|
| 30 |
+
yield copy.deepcopy(history), ""
|
| 31 |
+
|
| 32 |
+
# --- UI Event Handlers ---
|
| 33 |
+
|
| 34 |
+
def handle_model_change(model_id):
|
| 35 |
+
"""当用户切换模型时,更新UI"""
|
| 36 |
+
spec = CHAT_MODEL_SPECS[model_id]
|
| 37 |
+
scenarios = spec.get("prompt_scenarios", [])
|
| 38 |
+
|
| 39 |
+
# 默认加载第一个场景
|
| 40 |
+
if scenarios:
|
| 41 |
+
first_scenario = scenarios[0]
|
| 42 |
+
scenario_titles = [[s["title"]] for s in scenarios]
|
| 43 |
+
message_examples = [[m] for m in first_scenario["message_examples"]]
|
| 44 |
+
system_prompt_value = first_scenario["system_prompt"]
|
| 45 |
+
else: # 兼容没有场景的情况
|
| 46 |
+
scenario_titles = []
|
| 47 |
+
message_examples = []
|
| 48 |
+
system_prompt_value = ""
|
| 49 |
+
|
| 50 |
+
return (
|
| 51 |
+
gr.update(value=spec["description"]),
|
| 52 |
+
gr.update(samples=scenario_titles),
|
| 53 |
+
gr.update(value=system_prompt_value),
|
| 54 |
+
gr.update(samples=message_examples)
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
def handle_scenario_selection(model_id, evt: gr.SelectData):
|
| 58 |
+
"""当用户从场景数据集中选择一个场景时,更新UI"""
|
| 59 |
+
logger.debug(f"--- Scenario Selection Event ---")
|
| 60 |
+
logger.debug(f"Selected event value: {evt.value}")
|
| 61 |
+
logger.debug(f"Type of event value: {type(evt.value)}")
|
| 62 |
+
|
| 63 |
+
# 修正:从列表中提取字符串
|
| 64 |
+
selected_title = evt.value[0] if isinstance(evt.value, list) and evt.value else None
|
| 65 |
+
if not selected_title:
|
| 66 |
+
logger.error("Selected event value is not a valid list or is empty.")
|
| 67 |
+
return gr.update(), gr.update()
|
| 68 |
+
|
| 69 |
+
spec = CHAT_MODEL_SPECS[model_id]
|
| 70 |
+
scenarios = spec.get("prompt_scenarios", [])
|
| 71 |
+
|
| 72 |
+
available_titles = [s['title'] for s in scenarios]
|
| 73 |
+
logger.debug(f"Available scenario titles for model '{model_id}': {available_titles}")
|
| 74 |
+
|
| 75 |
+
selected_scenario = next((s for s in scenarios if s["title"] == selected_title), None)
|
| 76 |
+
|
| 77 |
+
if selected_scenario:
|
| 78 |
+
logger.debug(f"Found matching scenario: '{selected_title}'")
|
| 79 |
+
system_prompt_value = selected_scenario["system_prompt"]
|
| 80 |
+
message_examples = [[m] for m in selected_scenario["message_examples"]]
|
| 81 |
+
return gr.update(value=system_prompt_value), gr.update(samples=message_examples)
|
| 82 |
+
|
| 83 |
+
logger.warning(f"No matching scenario found for title: '{selected_title}'")
|
| 84 |
+
# 如果找不到场景,则不更新
|
| 85 |
+
return gr.update(), gr.update()
|
| 86 |
+
|
| 87 |
+
# --- UI Creation ---
|
| 88 |
+
|
| 89 |
+
def create_chat_tab():
|
| 90 |
+
"""创建并返回聊天标签页的所有Gradio组件"""
|
| 91 |
+
|
| 92 |
+
# 从配置中提取模型信息用于UI展示
|
| 93 |
+
# choices 是一个 (display_name, model_id) 的元组列表
|
| 94 |
+
model_choices = [(spec["display_name"], model_id) for model_id, spec in CHAT_MODEL_SPECS.items()]
|
| 95 |
+
default_model_id = list(CHAT_MODEL_SPECS.keys())[0]
|
| 96 |
+
default_spec = CHAT_MODEL_SPECS[default_model_id]
|
| 97 |
+
default_scenarios = default_spec.get("prompt_scenarios", [])
|
| 98 |
+
|
| 99 |
+
with gr.TabItem("聊天", id="chat_tab"):
|
| 100 |
+
with gr.Row():
|
| 101 |
+
with gr.Column(scale=3):
|
| 102 |
+
chatbot = gr.Chatbot(
|
| 103 |
+
label="聊天窗口",
|
| 104 |
+
bubble_full_width=False,
|
| 105 |
+
height=500,
|
| 106 |
+
value=[(None, "Hello! I'm Ling. Try selecting a scenario and a message example below to get started.")]
|
| 107 |
+
)
|
| 108 |
+
with gr.Row():
|
| 109 |
+
chat_input = gr.Textbox(placeholder="Ask me anything...", label="输入框", show_label=False, scale=4)
|
| 110 |
+
send_button = gr.Button("发送", variant="primary", scale=1)
|
| 111 |
+
|
| 112 |
+
# 新的场景化示例区域
|
| 113 |
+
with gr.Accordion("✨ 试试这些场景...", open=True):
|
| 114 |
+
# 场景选择器
|
| 115 |
+
scenario_selector = gr.Dataset(
|
| 116 |
+
components=[gr.Textbox(visible=False)],
|
| 117 |
+
samples=[[s["title"]] for s in default_scenarios],
|
| 118 |
+
label="系统提示示例",
|
| 119 |
+
headers=["选择一个角色或任务来开始:"],
|
| 120 |
+
)
|
| 121 |
+
# 消息示例
|
| 122 |
+
message_examples_display = gr.Dataset(
|
| 123 |
+
components=[chat_input],
|
| 124 |
+
samples=[[m] for m in default_scenarios[0]["message_examples"]] if default_scenarios else [],
|
| 125 |
+
label="消息示例",
|
| 126 |
+
headers=["然后,试试这些具体问题:"],
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
with gr.Column(scale=1):
|
| 130 |
+
model_selector = gr.Radio(
|
| 131 |
+
choices=model_choices,
|
| 132 |
+
label="选择模型",
|
| 133 |
+
value=default_model_id
|
| 134 |
+
)
|
| 135 |
+
model_description = gr.Markdown(default_spec["description"])
|
| 136 |
+
system_prompt = gr.Textbox(
|
| 137 |
+
label="System Prompt",
|
| 138 |
+
lines=8,
|
| 139 |
+
placeholder=CHAT_SYSTEM_PROMPT_PLACEHOLDER,
|
| 140 |
+
value=default_scenarios[0]["system_prompt"] if default_scenarios else ""
|
| 141 |
+
)
|
| 142 |
+
temperature_slider = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.1, label="Temperature")
|
| 143 |
+
|
| 144 |
+
# --- Event Listeners ---
|
| 145 |
+
model_selector.change(
|
| 146 |
+
fn=handle_model_change,
|
| 147 |
+
inputs=[model_selector],
|
| 148 |
+
outputs=[model_description, scenario_selector, system_prompt, message_examples_display]
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
scenario_selector.select(
|
| 152 |
+
fn=handle_scenario_selection,
|
| 153 |
+
inputs=[model_selector],
|
| 154 |
+
outputs=[system_prompt, message_examples_display]
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
message_examples_display.click(
|
| 158 |
+
fn=lambda value: value[0],
|
| 159 |
+
inputs=[message_examples_display],
|
| 160 |
+
outputs=[chat_input]
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
+
return {
|
| 164 |
+
"chatbot": chatbot,
|
| 165 |
+
"chat_input": chat_input,
|
| 166 |
+
"send_button": send_button,
|
| 167 |
+
"system_prompt": system_prompt,
|
| 168 |
+
"temperature_slider": temperature_slider,
|
| 169 |
+
"model_selector": model_selector,
|
| 170 |
+
}
|
tab_code.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import subprocess
|
| 3 |
+
import threading
|
| 4 |
+
import queue
|
| 5 |
+
import uuid
|
| 6 |
+
import os
|
| 7 |
+
import tempfile
|
| 8 |
+
import sys
|
| 9 |
+
import logging
|
| 10 |
+
import time
|
| 11 |
+
from models import generate_code_for_tab
|
| 12 |
+
|
| 13 |
+
# 配置日志
|
| 14 |
+
logger = logging.getLogger(__name__)
|
| 15 |
+
|
| 16 |
+
# 用于存储当前运行的 Gradio 子进程
|
| 17 |
+
running_processes = {}
|
| 18 |
+
|
| 19 |
+
def stop_process(session_id):
|
| 20 |
+
"""停止与特定会话关联的子进程"""
|
| 21 |
+
process = running_processes.get(session_id)
|
| 22 |
+
if process and process.poll() is None:
|
| 23 |
+
process.terminate()
|
| 24 |
+
process.wait()
|
| 25 |
+
print(f"Terminated process for session {session_id}")
|
| 26 |
+
if session_id in running_processes:
|
| 27 |
+
del running_processes[session_id]
|
| 28 |
+
|
| 29 |
+
def get_gradio_sys_prompt():
|
| 30 |
+
"""获取用于生成 Gradio 应用的 System Prompt"""
|
| 31 |
+
return """
|
| 32 |
+
You are an expert Gradio developer. Create a complete, runnable, single-file Gradio application based on the user's request.
|
| 33 |
+
The code must be self-contained in a single Python script.
|
| 34 |
+
The script must end with the app launch command, like `demo.launch()`.
|
| 35 |
+
Do not include any explanations, just the raw Python code.
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
def get_html_sys_prompt():
|
| 39 |
+
"""获取用于生成静态页面的 System Prompt"""
|
| 40 |
+
return """
|
| 41 |
+
You are an expert front-end developer. Create a complete, modern, and responsive single HTML file based on the user's request.
|
| 42 |
+
The file must be self-contained, including all necessary HTML, CSS, and JavaScript.
|
| 43 |
+
Do not include any explanations, just the raw HTML code.
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
def run_gradio_in_thread(code, url_queue, session_id):
|
| 47 |
+
"""在单独的线程中运行Gradio应用,以避免阻塞主应用"""
|
| 48 |
+
temp_dir = tempfile.mkdtemp()
|
| 49 |
+
file_path = os.path.join(temp_dir, "app.py")
|
| 50 |
+
with open(file_path, "w") as f:
|
| 51 |
+
f.write(code)
|
| 52 |
+
|
| 53 |
+
python_executable = sys.executable
|
| 54 |
+
process = subprocess.Popen(
|
| 55 |
+
[python_executable, file_path],
|
| 56 |
+
stdout=subprocess.PIPE,
|
| 57 |
+
stderr=subprocess.PIPE,
|
| 58 |
+
text=True,
|
| 59 |
+
bufsize=1,
|
| 60 |
+
universal_newlines=True
|
| 61 |
+
)
|
| 62 |
+
running_processes[session_id] = process
|
| 63 |
+
|
| 64 |
+
for line in process.stdout:
|
| 65 |
+
print(f"Gradio App stdout: {line.strip()}")
|
| 66 |
+
if "Running on local URL:" in line:
|
| 67 |
+
url = line.split("Running on local URL:")[1].strip()
|
| 68 |
+
url_queue.put(url)
|
| 69 |
+
break
|
| 70 |
+
|
| 71 |
+
process.wait()
|
| 72 |
+
try:
|
| 73 |
+
os.remove(file_path)
|
| 74 |
+
os.rmdir(temp_dir)
|
| 75 |
+
except OSError as e:
|
| 76 |
+
print(f"Error cleaning up temp files: {e}")
|
| 77 |
+
|
| 78 |
+
def get_spinner_html():
|
| 79 |
+
"""返回带 CSS 旋转动画的 HTML"""
|
| 80 |
+
return """
|
| 81 |
+
<div style="width: 100%; height: 600px; display: flex; justify-content: center; align-items: center; border: 1px solid #ddd; background-color: #f9f9f9;">
|
| 82 |
+
<div class="spinner"></div>
|
| 83 |
+
</div>
|
| 84 |
+
<style>
|
| 85 |
+
.spinner {
|
| 86 |
+
border: 4px solid rgba(0, 0, 0, 0.1);
|
| 87 |
+
width: 36px;
|
| 88 |
+
height: 36px;
|
| 89 |
+
border-radius: 50%;
|
| 90 |
+
border-left-color: #09f;
|
| 91 |
+
animation: spin 1s ease infinite;
|
| 92 |
+
}
|
| 93 |
+
@keyframes spin {
|
| 94 |
+
0% { transform: rotate(0deg); }
|
| 95 |
+
100% { transform: rotate(360deg); }
|
| 96 |
+
}
|
| 97 |
+
</style>
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
def generate_code(code_type, model_choice, user_prompt, session_id: gr.State):
|
| 101 |
+
"""生成代码并根据类型决定如何展示"""
|
| 102 |
+
logger.info(f"--- [Code Generation] Start ---")
|
| 103 |
+
logger.info(f"Code Type: {code_type}, Model: {model_choice}, Prompt: '{user_prompt}'")
|
| 104 |
+
|
| 105 |
+
stop_process(session_id)
|
| 106 |
+
|
| 107 |
+
if not user_prompt:
|
| 108 |
+
yield "Please enter a prompt.", gr.HTML("Preview will appear here.")
|
| 109 |
+
return
|
| 110 |
+
|
| 111 |
+
if code_type == "静态页面":
|
| 112 |
+
system_prompt = get_html_sys_prompt()
|
| 113 |
+
full_code_with_think = ""
|
| 114 |
+
full_code_for_preview = ""
|
| 115 |
+
buffer = ""
|
| 116 |
+
is_thinking = False
|
| 117 |
+
last_update_time = 0
|
| 118 |
+
|
| 119 |
+
yield "", gr.HTML(get_spinner_html())
|
| 120 |
+
|
| 121 |
+
# The model's raw output is streamed here
|
| 122 |
+
for code_chunk in generate_code_for_tab(system_prompt, user_prompt, code_type, model_choice):
|
| 123 |
+
full_code_with_think += code_chunk
|
| 124 |
+
buffer += code_chunk
|
| 125 |
+
|
| 126 |
+
# Process the buffer to filter out think tags for the preview
|
| 127 |
+
while True:
|
| 128 |
+
if is_thinking:
|
| 129 |
+
end_index = buffer.find("</think>")
|
| 130 |
+
if end_index != -1:
|
| 131 |
+
is_thinking = False
|
| 132 |
+
buffer = buffer[end_index + len("</think>"):]
|
| 133 |
+
else:
|
| 134 |
+
break
|
| 135 |
+
else:
|
| 136 |
+
start_index = buffer.find("<think>")
|
| 137 |
+
if start_index != -1:
|
| 138 |
+
part_to_add = buffer[:start_index]
|
| 139 |
+
full_code_for_preview += part_to_add
|
| 140 |
+
is_thinking = True
|
| 141 |
+
buffer = buffer[start_index:]
|
| 142 |
+
else:
|
| 143 |
+
full_code_for_preview += buffer
|
| 144 |
+
buffer = ""
|
| 145 |
+
break
|
| 146 |
+
|
| 147 |
+
current_time = time.time()
|
| 148 |
+
if current_time - last_update_time >= 5:
|
| 149 |
+
escaped_code = full_code_for_preview.replace("'", "'").replace('"', '"')
|
| 150 |
+
preview_html = f"""
|
| 151 |
+
<div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
|
| 152 |
+
<div style="position: absolute; top: 10px; right: 10px; z-index: 10;">
|
| 153 |
+
<div class="spinner-small"></div>
|
| 154 |
+
</div>
|
| 155 |
+
<iframe srcdoc='{escaped_code}'
|
| 156 |
+
style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
|
| 157 |
+
</iframe>
|
| 158 |
+
</div>
|
| 159 |
+
<style>.spinner-small {{ border: 2px solid rgba(0,0,0,0.1); width: 18px; height: 18px; border-radius: 50%; border-left-color: #09f; animation: spin 1s ease infinite; }} @keyframes spin {{ 0% {{ transform: rotate(0deg); }} 100% {{ transform: rotate(360deg); }} }}</style>
|
| 160 |
+
"""
|
| 161 |
+
yield full_code_with_think, gr.HTML(preview_html)
|
| 162 |
+
last_update_time = current_time
|
| 163 |
+
else:
|
| 164 |
+
yield full_code_with_think, gr.update()
|
| 165 |
+
|
| 166 |
+
# Final update for the preview without the spinner
|
| 167 |
+
escaped_code = full_code_for_preview.replace("'", "'").replace('"', '"')
|
| 168 |
+
final_preview_html = f"""
|
| 169 |
+
<div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
|
| 170 |
+
<iframe srcdoc='{escaped_code}'
|
| 171 |
+
style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
|
| 172 |
+
</iframe>
|
| 173 |
+
</div>
|
| 174 |
+
"""
|
| 175 |
+
yield full_code_with_think, gr.HTML(final_preview_html)
|
| 176 |
+
logger.info("Static page streaming finished.")
|
| 177 |
+
|
| 178 |
+
def toggle_fullscreen(is_fullscreen):
|
| 179 |
+
"""切换全屏模式的可见性"""
|
| 180 |
+
is_fullscreen = not is_fullscreen
|
| 181 |
+
new_button_text = "退出全屏" if is_fullscreen else "全屏预览"
|
| 182 |
+
panel_visibility = not is_fullscreen
|
| 183 |
+
return is_fullscreen, gr.update(value=new_button_text), gr.update(visible=panel_visibility)
|
| 184 |
+
|
| 185 |
+
def create_code_tab():
|
| 186 |
+
"""创建代码生成功能的UI Tab"""
|
| 187 |
+
session_id = str(uuid.uuid4())
|
| 188 |
+
session_state = gr.State(session_id)
|
| 189 |
+
fullscreen_state = gr.State(False)
|
| 190 |
+
|
| 191 |
+
with gr.Blocks() as demo:
|
| 192 |
+
with gr.Row():
|
| 193 |
+
with gr.Column(scale=1) as left_panel:
|
| 194 |
+
gr.Markdown("### 1. 选择代码类型")
|
| 195 |
+
code_type_radio = gr.Radio(["静态页面", "Gradio 应用"], value="静态页面", label="Code Type")
|
| 196 |
+
|
| 197 |
+
gr.Markdown("### 2. 选择模型")
|
| 198 |
+
model_choice_radio = gr.Radio(
|
| 199 |
+
["效果更好 (使用 Ling-1T)", "更快速 (使用 Ring-flash-2.0)"],
|
| 200 |
+
value="效果更好 (使用 Ling-1T)",
|
| 201 |
+
label="Model Selection"
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
gr.Markdown("### 3. 输入你的需求")
|
| 205 |
+
prompt_input = gr.Textbox(lines=5, placeholder="例如:创建一个带有标题和按钮的简单页面", label="Prompt")
|
| 206 |
+
gr.Examples(
|
| 207 |
+
examples=[
|
| 208 |
+
"创建一个在黑色背景上不断绽放五彩烟花的 Canvas 动画。",
|
| 209 |
+
"生成一个具有流光溢彩效果的 Canvas 特效。",
|
| 210 |
+
"设计一个能与鼠标交互的粒子系统 Canvas 动画。",
|
| 211 |
+
"用 HTML Canvas 实现一个经典的贪吃蛇游戏。",
|
| 212 |
+
"创建一个模拟'大象牙膏'化学实验的 Canvas 动画:一个容器中,彩色泡沫不断快速涌出、膨胀、溢出,充满整个屏幕。",
|
| 213 |
+
"创建一个梦幻的低多边形漂浮岛屿场景,带有动态光照和柔和的动画,在一个单一的HTML文件中。使用 d3.js 。"
|
| 214 |
+
],
|
| 215 |
+
inputs=prompt_input,
|
| 216 |
+
label="✨ 不妨试试这些酷炫的例子"
|
| 217 |
+
)
|
| 218 |
+
generate_button = gr.Button("生成代码", variant="primary")
|
| 219 |
+
|
| 220 |
+
with gr.Column(scale=2):
|
| 221 |
+
with gr.Tabs():
|
| 222 |
+
with gr.TabItem("实时预览"):
|
| 223 |
+
with gr.Row():
|
| 224 |
+
gr.Markdown("### 3. 实时预览")
|
| 225 |
+
fullscreen_button = gr.Button("全屏预览", scale=0)
|
| 226 |
+
preview_output = gr.HTML(value="<p>Preview will appear here.</p>")
|
| 227 |
+
with gr.TabItem("生成的源代码"):
|
| 228 |
+
gr.Markdown("### 4. 生成的源代码")
|
| 229 |
+
code_output = gr.Code(language="html", label="Generated Code")
|
| 230 |
+
|
| 231 |
+
generate_button.click(
|
| 232 |
+
fn=generate_code,
|
| 233 |
+
inputs=[code_type_radio, model_choice_radio, prompt_input, session_state],
|
| 234 |
+
outputs=[code_output, preview_output]
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
fullscreen_button.click(
|
| 238 |
+
fn=toggle_fullscreen,
|
| 239 |
+
inputs=[fullscreen_state],
|
| 240 |
+
outputs=[fullscreen_state, fullscreen_button, left_panel]
|
| 241 |
+
)
|
| 242 |
+
|
| 243 |
+
demo.unload(fn=lambda: stop_process(session_id))
|
| 244 |
+
|
| 245 |
+
return demo
|
tab_search.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from config import SEARCH_SYSTEM_PROMPT
|
| 3 |
+
|
| 4 |
+
def handle_web_search(query):
|
| 5 |
+
"""处理“网页检索”标签页的逻辑"""
|
| 6 |
+
# 模拟 Ring 模型进行网页检索和总结
|
| 7 |
+
# 在真实应用中,这里会使用 SEARCH_SYSTEM_PROMPT
|
| 8 |
+
summary = f"根据对网络的检索,关于 ‘{query}’ 的总结如下:\n\n这是一个由 Ring 模型模拟生成的摘要性回答。在实际应用中,模型会访问互联网,抓取相关信息,并生成一段高质量的总结。\n\n### 关键点:\n- **要点一**: 这是第一个关键信息。\n- **要点二**: 这是第二个关键信息。\n- **要点三**: 这是第三个关键信息。"
|
| 9 |
+
|
| 10 |
+
sources = """### 信息来源:
|
| 11 |
+
* [Source 1: Example Domain](https://example.com)
|
| 12 |
+
* [Source 2: Another Example](https://example.com)
|
| 13 |
+
* [Source 3: Wikipedia](https://wikipedia.org)"""
|
| 14 |
+
|
| 15 |
+
full_response = f"{summary}\n\n{sources}"
|
| 16 |
+
|
| 17 |
+
return gr.update(value=full_response, visible=True)
|
| 18 |
+
|
| 19 |
+
def create_search_tab():
|
| 20 |
+
with gr.TabItem("网页检索", id="search_tab"):
|
| 21 |
+
gr.Markdown("<p align='center'>由 <strong>Ring 💍</strong> 模型驱动</p>")
|
| 22 |
+
with gr.Column():
|
| 23 |
+
search_input = gr.Textbox(label="搜索输入区", placeholder="Enter a question to search and summarize...")
|
| 24 |
+
gr.Examples(
|
| 25 |
+
examples=["AI 的最新进展是什么?", "解释一下 Transformer 架构", "总结今天的新闻头条"],
|
| 26 |
+
label="示例提示",
|
| 27 |
+
inputs=[search_input]
|
| 28 |
+
)
|
| 29 |
+
search_button = gr.Button("✨ 检索")
|
| 30 |
+
search_results_output = gr.Markdown(label="结果展示区", visible=False)
|
| 31 |
+
|
| 32 |
+
return {
|
| 33 |
+
"search_input": search_input,
|
| 34 |
+
"search_button": search_button,
|
| 35 |
+
"search_results_output": search_results_output
|
| 36 |
+
}
|
tab_workflow.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from utils import WORKFLOW_SVG_DIAGRAM
|
| 3 |
+
from config import WORKFLOW_GENERATE_SYSTEM_PROMPT, WORKFLOW_EXECUTE_SYSTEM_PROMPT
|
| 4 |
+
|
| 5 |
+
def handle_workflow_generation(description):
|
| 6 |
+
"""处理“工作流执行”标签页的生成逻辑"""
|
| 7 |
+
# 在真实应用中,这里会使用 WORKFLOW_GENERATE_SYSTEM_PROMPT
|
| 8 |
+
# We use a mock SVG diagram from utils
|
| 9 |
+
svg_diagram = WORKFLOW_SVG_DIAGRAM
|
| 10 |
+
|
| 11 |
+
steps = ["Step 1: Plan", "Step 2: Execute", "Step 3: Review"]
|
| 12 |
+
initial_state = {"current_step": 0, "steps": steps}
|
| 13 |
+
initial_status = f"**当前节点**: {steps[0]}"
|
| 14 |
+
initial_chatbot_message = [(None, f"工作流已生成。让我们开始第一步:‘{steps[0]}’。请提供规划所需的信息。 ")]
|
| 15 |
+
|
| 16 |
+
return svg_diagram, initial_status, initial_chatbot_message, initial_state
|
| 17 |
+
|
| 18 |
+
def handle_workflow_chat(user_input, chat_history, state):
|
| 19 |
+
"""处理工作流的交互式聊天"""
|
| 20 |
+
if not state or not state.get("steps"):
|
| 21 |
+
return chat_history, state, "", gr.update(interactive=False)
|
| 22 |
+
|
| 23 |
+
chat_history.append((user_input, None))
|
| 24 |
+
|
| 25 |
+
current_step_index = state["current_step"]
|
| 26 |
+
steps = state["steps"]
|
| 27 |
+
|
| 28 |
+
thinking_message = "..."
|
| 29 |
+
chat_history[-1] = (user_input, thinking_message)
|
| 30 |
+
yield chat_history, state, "", gr.update(interactive=False)
|
| 31 |
+
|
| 32 |
+
current_step_index += 1
|
| 33 |
+
state["current_step"] = current_step_index
|
| 34 |
+
|
| 35 |
+
if current_step_index < len(steps):
|
| 36 |
+
next_step_name = steps[current_step_index]
|
| 37 |
+
response = f"好的,已完成上一步。现在我们进行 ‘{next_step_name}’。请提供相关信息。"
|
| 38 |
+
new_status = f"**当前节点**: {next_step_name}"
|
| 39 |
+
interactive = True
|
| 40 |
+
else:
|
| 41 |
+
response = "所有步骤均已完成!工作流结束。"
|
| 42 |
+
new_status = "**状态**: 已完成"
|
| 43 |
+
interactive = False
|
| 44 |
+
|
| 45 |
+
chat_history.append((None, response))
|
| 46 |
+
|
| 47 |
+
yield chat_history, state, new_status, gr.update(interactive=interactive)
|
| 48 |
+
|
| 49 |
+
def create_workflow_tab():
|
| 50 |
+
with gr.TabItem("工作流执行", id="workflow_tab"):
|
| 51 |
+
gr.Markdown("<p align='center'>由 <strong>Ring 💍</strong> 模型驱动</p>")
|
| 52 |
+
with gr.Row():
|
| 53 |
+
with gr.Column(scale=1):
|
| 54 |
+
workflow_description_input = gr.Textbox(lines=7, label="工作流描述", placeholder="Describe the steps of your workflow...")
|
| 55 |
+
gr.Examples(
|
| 56 |
+
examples=["规划一次东京之旅", "新用户引导流程", "内容审批流程"],
|
| 57 |
+
label="示例提示",
|
| 58 |
+
inputs=[workflow_description_input]
|
| 59 |
+
)
|
| 60 |
+
generate_workflow_button = gr.Button("✨ 生成工作流")
|
| 61 |
+
workflow_visualization_output = gr.HTML(label="工作流图示")
|
| 62 |
+
with gr.Column(scale=1):
|
| 63 |
+
workflow_status_output = gr.Markdown(label="节点状态")
|
| 64 |
+
workflow_chatbot = gr.Chatbot(label="执行对话", height=400)
|
| 65 |
+
workflow_chat_input = gr.Textbox(label="交互输入", placeholder="Your response...", interactive=False)
|
| 66 |
+
|
| 67 |
+
return {
|
| 68 |
+
"workflow_description_input": workflow_description_input,
|
| 69 |
+
"generate_workflow_button": generate_workflow_button,
|
| 70 |
+
"workflow_visualization_output": workflow_visualization_output,
|
| 71 |
+
"workflow_status_output": workflow_status_output,
|
| 72 |
+
"workflow_chatbot": workflow_chatbot,
|
| 73 |
+
"workflow_chat_input": workflow_chat_input
|
| 74 |
+
}
|
utils.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Mock data and helper functions
|
| 2 |
+
|
| 3 |
+
WORKFLOW_SVG_DIAGRAM = """<svg width="100%" height="150" xmlns="http://www.w3.org/2000/svg">
|
| 4 |
+
<defs>
|
| 5 |
+
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
|
| 6 |
+
<path d="M 0 0 L 10 5 L 0 10 z" fill="#9ca3af"></path>
|
| 7 |
+
</marker>
|
| 8 |
+
</defs>
|
| 9 |
+
<g fill="none" stroke="#9ca3af" stroke-width="2">
|
| 10 |
+
<rect x="10" y="50" width="100" height="50" rx="5" fill="#bfdbfe"></rect>
|
| 11 |
+
<text x="60" y="80" text-anchor="middle" fill="#1e3a8a" font-size="12">Step 1: Plan</text>
|
| 12 |
+
<path d="M110 75 L140 75" marker-end="url(#arrow)"></path>
|
| 13 |
+
<rect x="140" y="50" width="100" height="50" rx="5" fill="#f3f4f6"></rect>
|
| 14 |
+
<text x="190" y="80" text-anchor="middle" fill="#4b5563" font-size="12">Step 2: Execute</text>
|
| 15 |
+
<path d="M240 75 L270 75" marker-end="url(#arrow)"></path>
|
| 16 |
+
<rect x="270" y="50" width="100" height="50" rx="5" fill="#f3f4f6"></rect>
|
| 17 |
+
<text x="320" y="80" text-anchor="middle" fill="#4b5563" font-size="12">Step 3: Review</text>
|
| 18 |
+
</g>
|
| 19 |
+
</svg>"""
|