Agent Skills开发教程 本教程基于Skill Creator核心指南编写，将详细讲解Agent Skills（以下简称“Skill”）的定义、核心原则、结构组成、设计理念及完整开发流程，帮助你快速掌握Skill开发方法，打造可扩展Claude能力的专业化模块。 一、Skill基础认知（About Skills） Skill是模块化、独立的功能包，通过提供专业知识、工作流程和工具集成，扩展Claude的核心能力。你可以将其理解为“特定领域的入职指南”——它能让通用型Claude转变为具备专属流程知识的专业代理，这些流程知识是通用模型无法完全掌握的。 1.1 Skill的核心价值 专业工作流程：针对特定领域的多步骤操作流程（如PDF处理、API调用流程等）。 工具集成能力：提供特定文件格式（如DOCX、PDF）或API的操作说明。 领域专业知识：包含公司专属知识、数据 schema、业务逻辑等定制化内容。 捆绑资源包：整合脚本、参考文档、资产文件等，支撑复杂重复任务的高效执行。 二、Skill开发核心原则（Core Principles） 遵循以下原则可确保Skill的高效性、易用性和上下文友好性，是开发优质Skill的基础。 2.1 简洁为王（Concise is Key） 上下文窗口是宝贵的公共资源，Skill需与系统提示、对话历史、其他Skill元数据及用户请求共享该窗口。开发时需牢记： 默认假设“Claude已足够智能”，仅添加Claude不具备的上下文信息。 对每段信息进行核验：“Claude真的需要这段解释吗？”“这段内容的Token成本是否合理？” 优先使用简洁示例，而非冗长说明。 2.2 设置适当自由度（Set Appropriate Degrees of Freedom） 根据任务的脆弱性和可变性，匹配对应的指令 specificity 级别，如同为Claude规划行动路径——悬崖边的窄桥需严格护栏（低自由度），开阔田野可自由探索（高自由度）。 高自由度（文本型指令）：适用于多种方案均有效、决策依赖上下文或需启发式引导的场景（如创意文案优化、通用咨询）。 中自由度（伪代码/带参数脚本）：适用于有优选模式、允许适度变体或配置影响行为的场景（如带参数的数据分析脚本）。 低自由度（特定脚本/少参数）：适用于操作脆弱易出错、一致性至关重要或需严格遵循固定序列的场景（如系统部署步骤、敏感数据处理）。 三、Skill的结构组成（Anatomy of a Skill） 每个Skill必须包含SKILL.md文件（必需），可选择性包含捆绑资源。标准目录结构如下： skill-name/ ├── SKILL.md (必需) │ ├── YAML前置元数据 (必需) │ │ ├── name: (必需) │ │ └── description: (必需) │ └── Markdown指令 (必需) └── 捆绑资源 (可选) ├── scripts/ - 可执行代码（Python/Bash等） ├── references/ - 按需加载的参考文档 └── assets/ - 输出用资源（模板、图标等） 3.1 必需组件：SKILL.md 该文件是Skill的核心，包含Claude识别和使用Skill所需的全部关键信息，分为前置元数据和正文两部分。 3.1.1 前置元数据（YAML格式） 仅包含两个必需字段，是Claude判断Skill用途和触发时机的核心依据，需清晰、全面描述。 name：Skill名称（简洁唯一，如“pdf-editor”“bigquery-skill”）。 description：Skill描述（核心触发机制），需同时说明“Skill功能”和“触发场景”，避免冗余。示例：“Comprehensive document creation, editing, and analysis with support for tracked changes. Use when Claude needs to work with .docx files for creating/editing documents or handling tracked changes.” 注意：禁止添加其他YAML字段，仅保留name和description。 3.1.2 正文（Markdown格式） 包含Skill使用的指令和指南，仅在Skill触发后才会加载。写作需遵循“命令式/不定式语气”（如“Extract text with pdfplumber”），聚焦核心流程，避免无关信息。 3.2 可选组件：捆绑资源 根据Skill需求选择性添加，用于存储可复用内容，减少正文冗余并提升执行效率。 3.2.1 scripts/（可执行脚本目录） 存储Python、Bash等可执行代码，适用于“重复执行”或“需确定性可靠性”的任务（如PDF旋转、数据清洗）。 使用场景：相同代码需重复编写、任务要求结果可确定。 示例：scripts/rotate_pdf.py（PDF旋转脚本）。 注意：脚本需实际运行测试，确保无bug；若存在多个相似脚本，可抽样测试以平衡效率。 3.2.2 references/（参考文档目录） 存储需按需加载的参考资料，用于支撑Claude的决策和操作（如数据 schema、API文档、公司政策）。 使用场景：文档内容较详细、仅特定场景需用到。 示例：references/schema.md（数据库表结构）、references/api_docs.md（API说明）。 最佳实践：① 大型文件（>10k字）需在SKILL.md中添加grep搜索模式；② 信息仅存于一处（SKILL.md或参考文件，不重复）；③ 仅将核心流程保留在SKILL.md，详细内容迁移至参考文件。 3.2.3 assets/（输出资产目录） 存储用于“最终输出”的文件，不加载到上下文（如模板、图标、字体、前端脚手架）。 使用场景：Skill输出需依赖固定资源（如生成PPT需模板、输出文档需logo）。 示例：assets/logo.png（品牌图标）、assets/frontend-template/（React项目模板）。 3.3 禁止包含的文件 Skill仅需包含支撑功能的核心文件，禁止添加无关文档，包括但不限于：README.md、INSTALLATION_GUIDE.md、QUICK_REFERENCE.md、CHANGELOG.md等。此类文件会增加冗余并造成混淆。 四、渐进式披露设计原则（Progressive Disclosure Design Principle） 该原则通过“三级加载机制”高效管理上下文，避免Skill占用过多Token，核心是“按需加载、最小化上下文”。 4.1 三级加载系统 元数据（name + description）：始终在上下文（约100词，占用极少Token）。 SKILL.md正文：Skill触发时加载（建议<5k字，控制在500行内）。 捆绑资源：Claude根据需求按需加载（无字数限制，脚本可执行无需加载上下文）。 4.2 三种核心模式 当SKILL.md正文接近500行限制时，需拆分内容至参考文件，并在正文中明确引用，确保Claude知晓资源位置和使用时机。 模式1：高级指南+参考文件 正文保留核心流程，高级功能链接至对应参考文件，示例： # PDF Processing ## Quick start Extract text with pdfplumber: [简单代码示例] ## Advanced features - **Form filling**: See [FORMS.md](FORMS.md) for complete guide - **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods - **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns 模式2：按领域组织资源 多领域Skill按领域拆分参考文件，避免加载无关内容，示例目录结构： bigquery-skill/ ├── SKILL.md (概述+导航) └── reference/ ├── finance.md (财务指标) ├── sales.md (销售数据) ├── product.md (产品API) └── marketing.md (营销活动) 模式3：条件化细节展示 正文展示基础内容，高级细节链接至参考文件，示例： # DOCX Processing ## Creating documents Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md). ## Editing documents For simple edits, modify the XML directly. **For tracked changes**: See [REDLINING.md](REDLINING.md) **For OOXML details**: See [OOXML.md](OOXML.md) 关键注意事项 参考文件需直接链接自SKILL.md，避免深层嵌套。 长参考文件（>100行）需在顶部添加目录，方便Claude快速预览范围。 五、Skill开发完整流程（Skill Creation Process） Skill开发需遵循以下6个步骤，按顺序执行（无明确理由不得跳过），确保Skill质量和可用性。 步骤1：通过具体示例理解Skill需求 仅当Skill用途和使用模式已完全明确时可跳过，即使优化现有Skill，此步骤也有参考价值。核心是通过“具体示例”明确Skill功能和触发场景。 获取示例：直接收集用户真实使用案例，或生成示例后经用户验证。 核心问题（以高中语文作文评分SKILL为例）： Skill需支持哪些功能？（作文评分，点评，改进建议等）f 用户会如何触发Skill？（给出一篇作文，要求打分等） 注意：避免一次性提问过多，优先聚焦核心问题，逐步跟进补充。 完成标志：清晰掌握Skill需支持的所有功能和触发场景。 步骤2：规划可复用Skill内容 分析步骤1中的具体示例，提炼可复用资源（脚本、参考文件、资产），将“重复任务”转化为“可复用组件”，降低后续维护成本。 示例分析： PDF编辑Skill：旋转PDF需重复编写代码 → 规划scripts/rotate_pdf.py。 前端项目构建Skill：创建项目需重复编写HTML/React模板 → 规划assets/frontend-template/。 BigQuery查询Skill：需反复查阅表结构 → 规划references/schema.md。 高中语文作文评分SKILL：需要有一个作文评分标准 规划一个评分标准.md 需要一个字数统计的py脚本 输出：可复用资源清单（明确每个资源的类型、用途和存储路径）。 步骤3：初始化Skill（Initialize the Skill） 仅当Skill已存在（需迭代或打包）时可跳过，新Skill必须通过初始化脚本创建，确保目录结构标准化，提升开发效率。 核心操作：运行init_skill.py脚本，生成标准化Skill模板。 scripts/init_skill.py <skill-name> --path <output-directory> 脚本功能： 在指定路径创建Skill目录（skill-name）。 生成带前置元数据和TODO占位符的SKILL.md模板。 创建scripts/、references/、assets/目录及示例文件。 后续操作：根据需求自定义或删除生成的模板文件（示例文件仅用于展示结构，非必需）。 步骤4：编辑Skill（Edit the Skill） 基于初始化模板，实现可复用资源并完善SKILL.md，核心是“为Claude编写指南”——需提供非显而易见但有价值的信息（流程、注意事项、资源位置）。 4.1 优先实现可复用资源 根据步骤2的规划，编写scripts/、references/、assets/中的内容： 脚本：编写后需运行测试，确保无bug。 参考文件：按领域/功能分类，添加目录（长文件）。 资产：放入输出所需的模板、图标等文件。 注意：删除无需使用的示例文件（如Skill不涉及脚本，可删除scripts/目录下的示例）。 4.2 完善SKILL.md 前置元数据：完善name和description，确保触发场景清晰。 正文：按“核心流程+资源引用”编写，使用命令式语气，链接参考文件和脚本（如“See FORMS.md for form filling guide”）。 步骤5：打包Skill（Package the Skill） Skill开发完成后，需打包为可分发的.skill文件（本质是zip压缩包），打包前会自动验证Skill合法性。 核心操作：运行package_skill.py脚本。 # 基础打包（输出至当前目录） scripts/package_skill.py <path/to/skill-folder> # 指定输出目录（输出至dist目录） scripts/package_skill.py <path/to/skill-folder> ./dist 脚本流程： 验证（Validation）：自动检查以下内容，验证失败则报错并退出： YAML前置元数据格式及必需字段（name、description）。 Skill命名规范和目录结构。 description的完整性和质量。 文件组织和资源引用的有效性。 打包（Packaging）：验证通过后，生成以Skill名称命名的.skill文件（如pdf-editor.skill），包含所有核心文件和目录结构。 注意：需修复所有验证错误后，重新运行打包命令。 步骤6：迭代优化（Iterate） Skill发布后，需基于真实使用场景持续优化，解决使用中的问题和低效点，形成“使用-反馈-优化”的闭环。 迭代流程： 在真实任务中使用Skill。 记录Skill的不足（如流程繁琐、触发不精准、资源缺失）。 明确SKILL.md或捆绑资源的修改方向。 实施修改并测试，重复步骤5打包发布。 六、总结 Agent Skills开发的核心是“简洁、高效、可复用”——通过遵循核心原则、标准化结构、渐进式披露设计和完整开发流程，可打造出能精准扩展Claude能力的专业Skill。关键在于聚焦“Claude真正需要的信息”，避免冗余，让Skill在上下文友好的前提下发挥最大价值。 （注：参考来源：Anthropics）
南京工业大学统一身份认证（智慧南工）登录逆向分析
南京工业大学统一身份认证平台（SSO）逆向分析 📋 目录 1. 概述 2. 系统架构分析 3. 双密钥体系原理 4. 加密算法逆向 5. 前端混淆破解 6. 动态参数分析 7. 登录流程解析 1. 概述 1.1 目标系统 系统名称: 南京工业大学统一身份认证平台 登录地址: https://sfgl.njtech.edu.cn/cas/login 认证协议: CAS (Central Authentication Service) 前端框架: Angular 加密库: CryptoJS 1.2 核心文件 文件名 作用 关键内容 https://sfgl.njtech.edu.cn/cas/login 登录页面主体 密钥2、execution参数 https://sfgl.njtech.edu.cn/gate/public/deploy/deploy.js 脚本加载器 密钥1混淆、配置请求 https://sfgl.njtech.edu.cn/gate/public/utils/loginNew.js 设备检测 PC/Mobile判断 crypto-js.min.js 加密库 DES/MD5/SHA256算法 1.3 加密技术栈 加密算法: DES 加密模式: ECB 填充方式: PKCS7 编码格式: Base64 2. 系统架构分析 2.1 页面加载流程 从 login 可以看到页面加载顺序： 2.2 脚本依赖关系 从 deploy.js 第52-58行可以看到完整的依赖加载： var cptfile = [ baseUrl + '/public/convertBaseUrl.js', baseUrl + '/public/crypto/md5.min.js', baseUrl + '/public/crypto/core.min.js', baseUrl + '/public/crypto/crypto-js.min.js', baseUrl + '/public/crypto/enc-base64.min.js', baseUrl + '/public/crypto/mode-ecb.min.js', baseUrl + '/public/crypto/pad-pkcs7.min. js' ]; 这些文件通过 loadScript() 函数（第38-50行）依次加载。 2.3 页面初始化流程 从 deploy.js 第175行的 _casPageInit() 函数可以看到： function _casPageInit() { var loadedJs = []; var hasRun; function nextLoad(jsPath) { loadedJs.push(jsPath); var hasRuntime; var hasPolyfills; // 等待runtime和polyfills都加载完成 for (var i = 0; i < loadedJs.length; i++) { var path = loadedJs[i]; if (path.indexOf('runtime') !== -1) { hasRuntime = true; } else if (path.indexOf('polyfills') !== -1) { hasPolyfills = true; } } // 加载main脚本 if (hasRuntime && hasPolyfills && !hasRun) { hasRun = true; for (var i = 0; i < jsCssConfig.js.length; i++) { var jsPath = jsCssConfig.js[i]; if (jsPath.indexOf('main') !== -1) { loadOneJS(jsPath); } } } } } 3. 双密钥体系原理 3.1 密钥1：API通信密钥 3.1.1 存储位置与混淆 在 deploy.js 第124行： var url_mseAge = '_%C3%D8%AF%7C%A1%BD%BE%C2%C4%C4%92'; 3.1.2 解混淆函数 在 deploy.js 第16-26行： var uncompile = function (code) { code = unescape(code); let c = String.fromCharCode(code.charCodeAt(0) - code.length); for (let i = 1; i < code.length; i++) { c += String.fromCharCode(code. charCodeAt(i) - c.charCodeAt(i - 1)); } return c; }; 算法分析： 输入: '_%C3%D8%AF%7C%A1%BD%BE%C2%C4%C4%92' 步骤1: unescape() URL解码 '_%C3%D8%AF%7C%A1%BD%BE%C2%C4%C4%92' → '_ÃØ¯|¡½¾ÂÄÄ'' 步骤2: 差分解码 第一个字符: charCode(0) - length '_'. charCodeAt(0) = 95 length = 12 第一个输出: 95 - 12 = 83 → 'S' 第二个字符: charCode(1) - charCode(result[0]) 'Ã'. charCodeAt(0) = 195 result[0]. charCodeAt(0) = 83 第二个输出: 195 - 83 = 112 → 'p' 依此类推... 最终输出: 'SphG5lQmUoU=' 这是一种差分编码（Delta Encoding），每个字符的ASCII值是前一个字符加上一个差值。 3.1.3 使用场景 从 deploy.js 第130-165行的 getSelfConfig 函数可以看到： function getSelfConfig(key, cb) { let rfurl = baseUrl + '/linkid/protected/api/dictconfig/get'; // 判断是否需要加密 let hasCrypto = false; if (configUrl) { const allconfigkey = Object.keys(configUrl); for (let i = 0; i < allconfigkey.length; i++) { for (let o = 0; o < configUrl[allconfigkey[i]].length; o++) { const CurrentconfigUrl = configUrl[allconfigkey[i]][o]; if (isIncludeUrl(rfurl, CurrentconfigUrl)) { hasCrypto = true; break; } } } } // 发送加密请求 if (hasCrypto) { xhr.setRequestHeader('hasCrypto', 'true'); xhr.send(desEncrypt(uncompile(url_mseAge), JSON.stringify([key]))); } else { xhr.send(JSON.stringify([key])); } // 处理加密响应 if (! isJSONTmp) { var tmpgetunpackbody = getUnPackBody(uncompile(url_mseAge), jsonObj); } } 从测试结果可以看到，密钥1保护以下API： { "5G": [ "/data-sync/public/network/openUser/xxx", "/data-sync/public/network/cancelUser/xxx", "/data-sync/api/account/protected/tel/add", "/data-sync/api/account/tel/add", "/data-sync/api/thirdparty/tel/verify" ], "SID": [ "/linkid/api/aggregate/app/protected/obtain/", "/linkid/api/aggregate/app/protected/face/user/active/", "/linkid/protected/api/user/userId/check/", "/api/protected/realname/preQuery", "/api/protected/realname/auth", // ... 共23个接口 ] } 3.2 密钥2：密码加密密钥 3.2.1 存储位置 在 login 第77行： B0MCcDgT4Eo= 实际访问时获得的值为 zgEBWBZtq5s=（动态生成）。 3.2.2 参数提取 从页面隐藏元素中可以看到完整的登录参数： UsernamePassword zgEBWBZtq5s= edd59515-9448-42e3-8f17-cb1e8abb8d9e_H4sIAA... api/captcha/generate/DEFAULT service=http%3A%2F%2Fjwgl.njtech.edu.cn%2Fsso%2Fktiotlogin%3Fstatus%3Dsuccess 3dc54c41-da03-4f06-8052-823888cc4e9d_H4sIAA... 3.3 密钥独立性验证 从实际测试的登录请求可以看到： POST /cas/login username=202412345 password=TeDO/u3gzkxtgmHPJV47qA== # 使用密钥2加密 croypto=zgEBWBZtq5s= # 密钥2原样传回 type=UsernamePassword _eventId=submit execution=3dc54c41-da03-4f06-8052-823888cc4e9d_H4sIAA... 登录流程中没有使用密钥1，证明两个密钥完全独立。 4. 加密算法分析 4.1 加密函数定位 在 deploy.js 第7-15行： var desEncrypt = function (key, content) { const keyHex = CryptoJS.enc.Base64.parse(key); const encString = CryptoJS.DES.encrypt(content, keyHex, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return encString.toString(); }; 4.2 解密函数 在 deploy.js 第1-6行： var desDecrypt = function (key, content) { const keyHex = CryptoJS.enc. Base64.parse(key); const decString = CryptoJS.DES.decrypt(content, keyHex, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad. Pkcs7 }); return decString.toString(CryptoJS.enc.Utf8); }; 4.3 DES算法特征 从 crypto-js.min.js 中可以看到DES实现的关键部分： var d = u.DES = s.extend({ _doReset: function() { // 密钥调度 for (var t = this._key.words, r = t.words, e = t.sigBytes / 4, i = this._nRounds = e + 6, n = 4 * (i + 1), s = this._keySchedule = [], a = 0; a < n; a++) // ... }, encryptBlock: function(t, r) { this._doCryptBlock(t, r, this._keySchedule, a, c, h, l, o) }, decryptBlock: function(t, r) { var e = t[r + 1]; t[r + 1] = t[r + 3], t[r + 3] = e, this._doCryptBlock(t, r, this._invKeySchedule, f, u, d, v, s); // ... } }); 4.4 ECB模式特征 从加密配置可以看到使用了ECB模式： { mode: CryptoJS.mode. ECB, padding: CryptoJS.pad.Pkcs7 } ECB模式的工作原理： 明文: [Block1] [Block2] [Block3] ↓ ↓ ↓ DES-E DES-E DES-E ↓ ↓ ↓ 密文: [Cipher1][Cipher2][Cipher3] 每个块独立加密，不依赖前后块。 4.5 PKCS7填充 从 crypto-js.min.js 可以看到填充实现： var _ = p. Pkcs7 = { pad: function(t, r) { for (var e = 4 * r, i = e - t.sigBytes % e, n = i << 24 | i << 16 | i << 8 | i, s = [], a = 0; a < i; a += 4) s.push(n); var c = o.create(s, i); t.concat(c) }, unpad: function(t) { var r = 255 & t.words[t.sigBytes - 1 >>> 2]; t.sigBytes -= r } }; 填充规则： 原始数据长度 % 8 == 剩余字节数: 0字节 → 填充 08 08 08 08 08 08 08 08 1字节 → 填充 07 07 07 07 07 07 07 2字节 → 填充 06 06 06 06 06 06 ... 7字节 → 填充 01 4.6 加密过程验证 测试输出： // 输入 密钥: zgEBWBZtq5s= 明文: test123 // 加密过程 1. Base64解码密钥: ce0101581656db9b (8字节) 2. UTF-8编码明文: 74657374313233 (7字节) 3. PKCS7填充: 7465737431323301 (8字节, 填充了0x01) 4. DES-ECB加密: 0acbdcc58742a8d4 (8字节) 5. Base64编码: CsvcxYdCqNQ= // 输出 加密结果: CsvcxYdCqNQ= 5. 前端混淆破解 5.1 差分编码原理 5.1.1 编码过程推导 从 uncompile 函数的逆向分析可以推导出编码过程： // 解码: result[i] = encoded[i] - result[i-1] // 反推编码: encoded[i] = original[i] + original[i-1] 原始字符串: S p h G 5 l Q m U o U = ASCII码: 83 112 104 71 53 108 81 109 85 111 85 61 长度: 12 编码过程: 位置0: 83 + 12 = 95 → '_' 位置1: 112 + 83 = 195 → 'Ã' (escape后 %C3) 位置2: 104 + 112 = 216 → 'Ø' (escape后 %D8) 位置3: 71 + 104 = 175 → '¯' (escape后 %AF) 位置4: 53 + 71 = 124 → '|' (escape后 %7C) 位置5: 108 + 53 = 161 → '¡' (escape后 %A1) 位置6: 81 + 108 = 189 → '½' (escape后 %BD) 位置7: 109 + 81 = 190 → '¾' (escape后 %BE) 位置8: 85 + 109 = 194 → 'Â' (escape后 %C2) 位置9: 111 + 85 = 196 → 'Ä' (escape后 %C4) 位置10: 85 + 111 = 196 → 'Ä' (escape后 %C4) 位置11: 61 + 85 = 146 → ''' (escape后 %92) 最终: '_%C3%D8%AF%7C%A1%BD%BE%C2%C4%C4%92' 5.1.2 算法特征 差分编码的特点： 可逆性：解码函数可以完全恢复原始数据 依赖性：每个字符依赖前一个字符 错误传播：一个字符错误会影响后续所有字符 长度保持：编码后长度不变 5.2 URL编码层 escape() 函数的作用： // ASCII可见字符（不编码） '_' → '_' '|' → '|' // 非ASCII字符（编码） 'Ã' (195) → '%C3' 'Ø' (216) → '%D8' '¯' (175) → '%AF' 5.3 多层解密 从 deploy.js 第126-145行可以看到多层解密逻辑： function getUnPackBody(key, body) { let dec = ''; let isJSON = false; const convertData = function (body) { // 开始解密 dec = desDecrypt(key, body); isJSON = false; if (dec != '') { try { JSON.parse(dec); isJSON = true; return; } catch (str_error) { isJSON = false; } // 如果解密结果不是JSON，继续解密 if (!isJSON) { convertData(dec); } } }; convertData(body); return JSON.parse(dec || null); } 这说明服务器可能返回嵌套加密的数据，需要递归解密直到得到有效的JSON。 6. 动态参数分析 6.1 execution参数 从 login 可以看到execution的格式： 格式分析： 3dc54c41-da03-4f06-8052-823888cc4e9d_H4sIAAAAAAAAAO1ce2xcxRkfn9+... 组成部分: ├─ UUID部分: 3dc54c41-da03-4f06-8052-823888cc4e9d │ • 长度: 36字符 │ • 格式: 8-4-4-4-12 │ • 作用: 唯一标识本次登录流程 │ └─ 数据部分: H4sIAAAAAAAAAO1ce2wcxRkfn9+... • 格式: Base64编码 • 识别: H4sI 是Gzip压缩的Magic Number • 内容: Gzip(JSON数据) 6.2 login-page-flowkey参数 从 login 第80行： edd59515-9448-42e3-8f17-cb1e8abb8d9e_H4sIAAAAAAAAALU6a2xb53lH1FuWLdmWnbhZXE... 与execution格式相同：UUID_Base64GzipData 6.3 验证码URL 从 login 第79行： 该元素为空，但从 deploy.js 第285行可以看到检测逻辑： var captchaUrlElem = doc.getElementById('captcha-url'); if (captchaUrlElem && captchaUrlElem.innerText. trim()) { this.captchaUrl = `${this.gateUrl}/${captchaUrlElem.innerText.trim()}`; } 从 loginNew.js 可以看到验证码相关代码： var ruleList_content = document.body; var d_style = null; if (window.getComputedStyle) { d_style = window.getComputedStyle(ruleList_content, null); } else { d_style = ruleList_content.currentStyle; } if (d_style. content. indexOf('x') !== -1) { if(document.getElementById('recaptcha-invisible')){ document.getElementById('recaptcha-invisible').innerText = true; document.getElementById('captcha-url').innerText = "api/captcha/generate/DEFAULT"; } } 通过CSS的 content 属性判断是否需要验证码。 6.4 认证类型列表 从 login 第31-42行可以看到支持的认证方式： UsernamePassword 用户名密码认证 ./images/login-page/UsernamePassword.png false smsLogin 手机验证码认证 ./images/login-page/smsLogin.png false corpwechatQr 企业微信扫码认证 false 6.5 第三方认证 从 login 第85-132行可以看到完整的第三方认证列表： Or login with: adapter corpWechat Wechat tyEduCloud dingDing dingDingWlan singleWechatOauth feishuOauth zhilinOauth isni ssoOauth corpWechatOauth2 welinkOauth ccwork 7. 登录流程解析 7.1 请求参数完整映射 从实际抓包数据： POST /cas/login HTTP/1.1 username=202412345 type=UsernamePassword _eventId=submit geolocation= execution=3dc54c41-da03-4f06-8052-823888cc4e9d_H4sIAA... captcha_code=a3d2 croypto=zgEBWBZtq5s= password=TeDO/u3gzkxtgmHPJV47qA== 对应关系： 表单字段 来源 说明 username 用户输入 学号/用户名 password 加密计算 DES(密钥2, 明文密码) croypto #login-croypto 密钥2原值 type #current-login-type 固定值 UsernamePassword _eventId 固定值 submit execution UUID_GzipBase64 captcha_code 用户输入 验证码（可选） geolocation 固定值 空字符串 7.2 加密时序 1. 页面加载 ↓ 2. 提取 login-croypto → 密钥2 (zgEBWBZtq5s=) ↓ 3. 用户输入密码 → password (test123) ↓ 4. Base64解码密钥2 zgEBWBZtq5s= → [0xce, 0x01, 0x01, 0x58, 0x16, 0x56, 0xdb, 0x9b] ↓ 5. DES-ECB加密 plaintext: test123 (7字节) padding: test123\x01 (8字节, PKCS7) encrypted: [0x0a, 0xcb, 0xdc, 0xc5, 0x87, 0x42, 0xa8, 0xd4] ↓ 6. Base64编码 CsvcxYdCqNQ= ↓ 7. 提交表单 7.3 设备检测流程 从 loginNew.js 可以看到完整的设备检测逻辑： // 1. 创建检测元素 var newElement = document.createElement('div'); newElement.classList.add('pl_box'); newElement.id ='pl_dom'; document.body.appendChild(newElement); // 2. CSS媒体查询 // @media screen and (orientation: portrait) { // .pl_box { width: 20px; height: 30px; } // } // @media screen and (orientation: landscape) { // .pl_box { width: 30px; height: 20px; } // } // 3. 判断方向 const width = document.getElementById('pl_dom').clientWidth; const height = document. getElementById('pl_dom').clientHeight; if (parseInt(width) < parseInt(height)) { neworientation. current = 'portrait'; // 竖屏 } else { neworientation. current = 'landscape'; // 横屏 } // 4. 根据方向加载不同页面 if (landscape && res == 'new') { device = 'PC'; script. onload = function () { window.casPageInit("loginnew"); }; } else if (landscape) { device = 'PC'; script.onload = function () { window.casPageInit("login"); }; } else if (portrait) { device = 'PHONE'; script.onload = function () { window.casPageInit("login"); }; } 7.4 自动重定向逻辑 从 login 第203-229行： var list = document.getElementsByClassName('ruleList'); var isAdapterRedirect = false; var isAutoRedirect = false; var isAutoRedirectClientName = null; // 检查是否有自动重定向的认证方式 for (var i = 0; i < list.length; i++) { var ele = list[i]. getElementsByClassName('code')[0]; var code = ele.innerText; var autoRedirect = list[i].getElementsByClassName('isRedirect')[0]; var autoRedirectCode = autoRedirect.innerText; if (autoRedirectCode == 'true') { isAutoRedirect = true; isAutoRedirectClientName = code; break; } if (code == 'adapter') { isAdapterRedirect = true; } } // 执行重定向 if (isAutoRedirect) { url = url.replace('#client_name', isAutoRedirectClientName); window.location. href = url; } if (isAdapterRedirect) { url = url.replace('#client_name', 'adapter'); window.location.href = url; } 7.5 配置请求流程 从 deploy.js 第267-283行： getSelfConfig('URL_CRYPTO_DATA', function () { console.log(configUrl, config); getSelfConfig('pc. self.page.config', function () { console.log(configUrl, config); if (pageName === 'serviceerror') { // 处理服务错误页面 } else if (pageName === 'logout' || pageName === 'propagatelogout' || pageName === 'error') { // 处理登出页面 if (document.getElementById('logout-header-logo')) { document.getElementById('logout-header-logo').src = window.convertHref(config.logo); } if (document.getElementById('logout-body-bg')) { document.getElementById('logout-body-bg').style.backgroundImage = "url('" + window.convertHref(config.background) + "')"; } } else { // 处理登录页面 _casPageInit(); } }); }); 配置加载顺序： URL_CRYPTO_DATA - 获取需要加密的API列表 pc.self.page.config - 获取页面自定义配置 根据页面类型执行相应初始化 7.6 错误处理 从 login 第234-252行： var clientType = document.getElementById("current-login-type").innerText; var errorCode = document.getElementById("login-error-code").innerText; if (errorCode === "1410041" && (clientType == "dingDingWlan" || clientType == "adapter" || ... )) { if (clientType == "") { clientType = "appToken" } url = "./public/client/bind/fail?clientname=#clientname"; url = url.replace('#clientname', clientType); window.location.href = url; } if (errorCode === "1030028" && (clientType == "dingDingWlan" || clientType == "adapter" || ...)) { if (clientType == "") { clientType = "appToken" } url = "./public/client/bind/error?clientname=#clientname"; url = url.replace('#clientname', clientType); window.location.href = url; } 错误码含义： 1410041 - 绑定失败，跳转到 bind/fail 页面 1030028 - 绑定错误，跳转到 bind/error 页面 本报告的所有内容仅供学习和研究使用。作者通过分析公开可访问的前端代码和网络请求，学习和理解现代Web应用的认证机制,加密实现和前端架构设计。 作者从未、也绝不会利用本内容进行任何非法活动。 作者不对他人使用本报告内容产生的任何后果承担责任。 任何人使用本报告内容从事违法活动，均与作者无关，由使用者自行承担全部法律责任。
九江学院统一身份认证系统登录加密逆向分析
九江学院统一身份认证系统登录加密逆向分析 📋 目录 一、背景介绍 二、初步侦察 三、关键文件分析 四、加密流程深度解析 五、总结 一、背景介绍 1.1 目标系统 系统名称：九江学院统一身份认证平台 登录地址：https://authserver.jju.edu.cn/authserver/login 目标：分析并理解前端密码加密逻辑 1.2 技术栈 前端加密：CryptoJS (AES-CBC加密) 后端框架：基于CAS (Central Authentication Service) 传输协议：HTTPS 1.3 分析工具 Chrome DevTools (网络抓包、调试) HTML源码查看 JavaScript代码分析 二、初步侦察 2.1 网络请求抓包 打开登录页面，按 F12 进入开发者工具，切换到 Network 标签，执行一次登录操作： POST /authserver/login? service=https://ehall.jju.edu.cn/login HTTP/1.1 Host: authserver.jju.edu.cn Content-Type: application/x-www-form-urlencoded username=202012345& password=U2FsdGVkX1%2BabcdefghijklmnopqrstuvwxyzABCDEF... & execution=e7637a06-8937-4197-b207-5986a5a159e6_... & _eventId=submit& cllt=userNameLogin 关键发现： ✅ 用户名明文传输 ✅ 密码已加密（Base64格式） ✅ 存在 execution 参数（类似CSRF Token） 2.2 页面源码分析 右键查看页面源代码，搜索关键字 password、encrypt、salt： 发现： AES加密密钥直接嵌入在HTML页面的隐藏字段中 三、关键文件分析 3.1 加密核心文件：encrypt.js 定位到 /authserver/jjuThemea/static/common/encrypt.js 3.1.1 随机字符串生成器 // 定义随机字符集（排除易混淆字符 I, L, O, 0, 1, 9） var $aes_chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; var aes_chars_len = $aes_chars.length; // 生成指定长度的随机字符串 function randomString(len) { var retStr = ''; for (i = 0; i < len; i++) { retStr += $aes_chars.charAt(Math.floor(Math.random() * aes_chars_len)); } return retStr; } 原理解析： 字符集包含 48 个字符（26个大写字母 + 22个小写字母和数字） 排除了 I, L, O, 0, 1, 9 等易混淆字符 使用 Math.random() 生成伪随机数 每次调用返回指定长度的随机字符串 3.1.2 AES加密核心函数 // AES加密核心函数 function getAesString(data, key0, iv0) { // 去除密钥首尾空字符 key0 = key0.replace(/(^\s+)|(\s+$)/g, ""); // 将密钥和IV转换为CryptoJS可识别的格式 var key = CryptoJS.enc. Utf8.parse(key0); var iv = CryptoJS.enc.Utf8.parse(iv0); // 执行AES加密 var encrypted = CryptoJS.AES.encrypt(data, key, { iv: iv, // 初始化向量 mode: CryptoJS.mode.CBC, // CBC模式 padding: CryptoJS.pad.Pkcs7 // PKCS7填充 }); // 返回Base64编码的密文 return encrypted.toString(); } 原理解析： 参数 作用 说明 data 明文数据 要加密的内容 key0 加密密钥 16字节AES密钥 iv0 初始化向量 16字节随机IV mode: CBC 加密模式 密码块链接模式 padding: Pkcs7 填充方式 PKCS#7填充标准 3.1.3 完整加密流程 // 密码加密入口函数 function encryptPassword(pwd0, key) { try { return encryptAES(pwd0, key); } catch (e) { return pwd0; } } // 完整加密实现 function encryptAES(data, aesKey) { if (!aesKey) { return data; } // 关键步骤： // 1. 生成64位随机前缀 // 2. 拼接：随机前缀 + 原始密码 // 3. 生成16位随机IV // 4. 调用AES加密 var encrypted = getAesString( randomString(64) + data, // 64位随机前缀 + 密码 aesKey, // 加密密钥 randomString(16) // 16位随机IV ); return encrypted; } 加密流程可视化： 原始密码: "MyPassword123" ↓ 生成64位随机前缀: "TxmRpDkNwYs... 64个字符..." ↓ 拼接明文: "TxmRpDkNwYs...64个字符... MyPassword123" ↓ 生成16位随机IV: "AbCdEfGhJkMnPqRs" ↓ AES-CBC加密 (使用密钥和IV) ↓ Base64编码 ↓ 最终密文: "U2FsdGVkX1+abc..." 3.2 登录逻辑文件：login.js 定位到 /authserver/jjuThemea/static/web/js/login.js 3.2.1 密钥获取与加密调用 // 表单验证与加密函数 function checkForm() { var cllt = $(". login-main #cllt").val(); if (cllt == 'userNameLogin') { // 验证用户名和密码... if (utils.requireInput($(LOGIN_USERNAME_ID), 0, 100, ... )) { return; } if (utils.requireInput($(LOGIN_PASSWORD_ID), 0, 32, ...)) { return; } // 从HTML页面获取AES密钥 var aesKey = $("#pwdEncryptSalt").val(); // 获取用户输入的密码 var password = $(LOGIN_PASSWORD_ID).val(); // 使用密钥加密密码 var encryptedPassword = encryptPassword(password, aesKey); // 将加密后的密码存入隐藏字段 $("#saltPassword").val(encryptedPassword); // 禁用原始密码输入框（防止明文提交） $(LOGIN_PASSWORD_ID).attr("disabled", "disabled"); } return true; } 流程说明： 用户点击登录按钮 ↓ 触发 checkForm() 函数 ↓ 验证用户名和密码格式 ↓ 从页面获取密钥: $("#pwdEncryptSalt").val() ↓ 获取用户输入: $(LOGIN_PASSWORD_ID).val() ↓ 调用加密函数: encryptPassword(password, aesKey) ↓ 将密文存入隐藏字段: $("#saltPassword").val(encrypted) ↓ 禁用原始密码输入框 ↓ 提交表单（只提交密文） 3.3 HTML页面分析：login_page.html 3.3.1 关键表单字段 登录 字段说明表： 字段名 ID/Name 类型 作用 是否提交 用户名 username text 用户输入 ✅ 明文提交 原始密码 passwordText password 用户输入 ❌ 被禁用 加密密码 password (saltPassword) hidden 存储密文 ✅ 密文提交 加密密钥 pwdEncryptSalt hidden 存储密钥 ❌ 不提交 验证码 captcha text 用户输入 ✅ 明文提交 执行标识 execution hidden CSRF保护 ✅ 提交 3.3.2 密钥生成机制 服务器端（伪代码）： @GetMapping("/login") public String loginPage(HttpSession session, Model model) { // 1. 生成16位随机密钥 String aesKey = generateRandomKey(16); // 例如: "V4Kh77JL6yk52pNG" // 2. 存入服务器Session（用于后续解密） session.setAttribute("aesKey", aesKey); // 3. 将密钥传递给前端页面 model.addAttribute("pwdEncryptSalt", aesKey); return "login"; } 密钥生命周期： 用户访问登录页面 ↓ 服务器生成随机密钥（16位） ↓ 存入Session: session.put("aesKey", key) ↓ 嵌入HTML: ↓ 返回页面给浏览器 ↓ JavaScript读取密钥进行加密 ↓ 用户提交登录 ↓ 服务器从Session取出密钥 ↓ 使用相同密钥解密密码 ↓ 验证密码是否正确 四、加密流程深度解析 4.1 完整加密流程图 ┌─────────────────────────────────────────────────────┐ │ 步骤1: 用户输入密码 │ │ 输入: "MyPassword123" │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤2: JavaScript从HTML获取密钥 │ │ $("#pwdEncryptSalt").val() → "V4Kh77JL6yk52pNG" │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤3: 生成64位随机前缀 │ │ randomString(64) │ │ → "TxmRpDkNwYsFqJzH... 64个字符..." │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────���───────────────────────────────────┐ │ 步骤4: 拼接明文 │ │ "TxmRpDkNwYsF...64位... MyPassword123" │ │ 总长度: 64 + 13 = 77 字符 │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤5: 生成16位随机IV │ │ randomString(16) │ │ → "AbCdEfGhJkMnPqRs" │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤6: UTF-8编码 │ │ 明文 → 77字节 │ │ 密钥 → 16字节 │ │ IV → 16字节 │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤7: PKCS7填充 │ │ 77字节 → 填充到16的倍数 → 80字节 │ │ 填充内容: 添加3个字节 0x03 │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤8: AES-CBC加密 │ │ 明文块1(16B) ⊕ IV → AES → 密文块1 │ │ 明文块2(16B) ⊕ 密文块1 → AES → 密文块2 │ │ 明文块3(16B) ⊕ 密文块2 → AES → 密文块3 │ │ 明文块4(16B) ⊕ 密文块3 → AES → 密文块4 │ │ 明文块5(16B) ⊕ 密文块4 → AES → 密文块5 │ │ 结果: 80字节密文 │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤9: 打包IV和密文 │ │ [IV(16字节)][密文(80字节)] = 96字节 │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤10: Base64编码 │ │ 96字节 → Base64 → 128字符 │ │ "U2FsdGVkX1+abcdefghijk..." │ └────────────────┬────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 步骤11: 提交到服务器 │ │ POST /authserver/login │ │ password=U2FsdGVkX1+abc... │ └─────────────────────────────────────────────────────┘ 4.2 三大核心机制 4.2.1 机制一：64位随机前缀 作用：防止密码字典攻击 // 实现代码 randomString(64) + password 原理：每次加密都在密码前添加64位随机字符，使得相同密码产生完全不同的密文 4.2.2 机制二：16位随机IV 作用：确保相同明文产生不同密文 // 实现代码 var iv = randomString(16); CryptoJS.AES.encrypt(data, key, { iv: iv, mode: CryptoJS.mode.CBC }); 原理：CBC模式下，IV参与第一个数据块的加密，每次使用不同的IV会产生不同的密文 4.2.3 机制三：动态密钥 作用：防止密钥重用和会话劫持 原理：服务器为每个会话生成独立的加密密钥，存储在Session中，客户端从HTML页面获取并使用 4.3 数据结构 4.3.1 加密前的明文结构 ┌──────────────────────────────────────┬─────────────────┐ │ 64位随机前缀 │ 原始密码 │ ├──────────────────────────────────────┼─────────────────┤ │ TxmRpDkNwYsFqJzHcBnMaXvKgWeRtPsJf │ MyPassword123 │ │ DhLmQwZxCvBnMkYuHgTrEwQpLkJh │ │ └──────────────────────────────────────┴─────────────────┘ 64 字符 13 字符 ↓ 总长度: 77 字符 ↓ UTF-8编码: 77 字节 ↓ PKCS7填充: 80 字节 4.3.2 加密后的密文结构 ┌─────────────────┬──────────────────────────────────┐ │ IV (16字节) │ 实际密文 (80字节) │ ├─────────────────┼──────────────────────────────────┤ │ AbCdEfGhJkMn... │ [加密后的二进制数据] │ └─────────────────┴──────────────────────────────────┘ 16字节 80字节 ↓ 总计: 96字节 ↓ Base64编码: 128字符 4.4 服务器端解密流程 接收密文: "U2FsdGVkX1+abc..." ↓ Base64解码 → 96字节 ↓ 分离: IV(16字节) + 密文(80字节) ↓ 从Session获取密钥: "V4Kh77JL6yk52pNG" ↓ AES-CBC解密 ↓ 去除PKCS7填充 → 77字节 ↓ 去掉前64位随机前缀 ↓ 得到原始密码: "MyPassword123" ↓ 验证密码是否正确 五、总结 5.1 核心技术要点 加密算法： 算法: AES-128 模式: CBC (Cipher Block Chaining) 填充: PKCS7 编码: Base64 三大核心机制： 序号 机制 参数 作用 1 随机前缀 64位字符 防止字典攻击 2 随机IV 16字节 增加密文随机性 3 动态密钥 16字节 防止密钥重用 完整流程： 前端流程: 1. 访问登录页面 → 获取动态密钥 2. 生成64位随机前缀 → 拼接密码 3. 生成16位随机IV → 执行AES加密 4. 打包IV和密文 → Base64编码 5. 提交密文到服务器 后端流程: 1. 接收Base64密文 → 解码 2. 分离IV和密文 → 从Session获取密钥 3. AES解密 → 去除填充 4. 去掉64位前缀 → 得到原始密码 5. 验证密码 → 返回结果 5.2 关键知识点 密钥管理： 来源: HTML页面隐藏字段 长度: 16字节 (AES-128) 生命周期: Session级别（约30分钟） 获取方式: $("#pwdEncryptSalt").val() 核心函数： randomString(length) // 生成随机字符串 getAesString(data, key, iv) // AES加密核心 encryptPassword(password, key) // 密码加密入口 5.3 常见问题 Q: 密钥从哪里来？ A: 从HTML页面的隐藏字段 中获取 Q: 每次登录密钥都不同吗？ A: 是的，每次访问登录页面服务器会生成新的密钥 Q: 为什么要加64位随机前缀？ A: 防止密码字典攻击，增加破解难度到 10^108 Q: IV的作用是什么？ A: 确保相同密码产生不同密文，可以公开传输（编码在密文前16字节） 5.4 免责声明 本文档仅供学习和研究使用，请勿用于非法用途。 使用本文档内容造成的任何后果由使用者自行承担。 建议在合法合规的前提下学习相关技术。 文档信息 版本: v1.0 类型: 逆向分析文档 目的: 学习研究 许可: 仅供学习使用
OpenList WebUI for OpenWrt - 一个独立的 OpenList (Alist分支) OpenWrt LuCI 管理界面
!!! OpenList WebUI for OpenWrt - 一个独立的 OpenList (Alist分支) OpenWrt LuCI 管理界面 项目地址：drfccv/luci-app-openlistui !!! 功能特性 🎯 现代化界面设计 - 采用响应式布局，支持多种设备访问 📊 系统概览 - 实时显示系统状态、服务运行情况和资源使用 🔄 更新管理 - 便捷的组件更新和版本管理 📝 日志查看 - 实时日志监控，支持过滤和自动刷新 ⚙️ 配置管理 - 简化的配置界面，支持各种参数调整 🌐 多语言支持 - 支持中文界面 界面预览 系统概览 系统概览页面提供了完整的系统状态监控，包括： 服务运行状态 系统资源使用情况 快速操作按钮 系统信息展示 更新管理 更新管理页面支持： 组件版本查看 一键更新功能 更新进度显示 更新日志查看 配置设置 配置设置页面包含： 服务配置选项 网络设置 安全配置 高级选项 快速开始 编译安装 # 编译默认架构 (x86_64) ./build.sh # 编译指定架构 ./build.sh aarch64 ./build.sh mips ./build.sh mipsel ./build.sh arm ./build.sh armv7 # 编译所有支持的架构 ./build.sh all # 快速编译（跳过feeds更新） ./build.sh --fast ./build.sh -f x86_64 # 开发模式（包含时间戳） ./build.sh --dev x86_64 # 显示版本信息 ./build.sh version # 清理构建文件 ./build.sh clean # 显示帮助信息 ./build.sh help 构建输出 每次构建会生成： IPK包: output/luci-app-openlistui_架构_时间戳.ipk 构建信息: output/luci-app-openlistui_架构_时间戳.info 构建日志: build-logs/build-架构-时间戳.log 版本信息: 包内 /usr/lib/lua/luci/version-openlistui 配置文件 可以通过 build.conf 自定义构建参数： 默认架构 SDK URLs 构建选项 依赖包列表 支持的架构 x86_64 - x86 64位 (默认) aarch64 - ARM 64位 mips - MIPS 大端序 (ath79) mipsel - MIPS 小端序 (ramips) arm - ARM 32位 (bcm2708) armv7 - ARMv7 (bcm2709) 构建选项 -f, --fast - 跳过feeds更新 (适用于重复构建) --dev - 开发模式，为包文件名添加时间戳 安装说明 编译IPK包: 使用构建脚本编译对应架构的IPK包 安装界面包: 安装编译生成的 luci-app-openlistui IPK包 重启服务: 重启 uhttpd 服务以加载新界面 访问界面: 通过 OpenWrt 管理界面访问 OpenList 管理页面 开发说明 目录结构 luci-app-openlist/ ├── luasrc/ # Lua 源码 │ ├── controller/ # 控制器 │ ├── model/ # 数据模型 │ └── view/ # 视图模板 ├── htdocs/ # 静态资源 ├── po/ # 多语言文件 ├── root/ # 系统文件 ├── screenshots/ # 界面截图 └── CONTROL/ # 包控制文件 开发命令 # 检查版本信息 make version # 生成版本文件（调试用） make gen-version # 查看构建变量 grep "PKG_" Makefile 注意事项 此包为独立的 LuCI 网页界面，无需依赖额外的核心包 使用 openlistui 命名空间避免与原始 luci-app-openlist 冲突 确保 OpenWrt 系统版本兼容性 支持多种主流路由器架构 许可证 MIT License 贡献 欢迎提交 Issue 和 Pull Request 来改进这个项目。 OpenList WebUI
🚄 MCP Server 12306 ✨ 项目简介 MCP Server 12306是一款基于 Model Context Protocol (MCP) 的高性能火车票查询后端，支持官方 12306 余票、票价、车站、经停、换乘查询以及智能时间工具，适配 AI/自动化/智能助手等场景。界面友好，易于集成，开箱即用。 🚀 功能亮点 实时余票/车次/座席/时刻/换乘一站式查询 全国车站信息管理与模糊搜索 官方经停站、一次中转方案全支持 实时查询各车次票价信息 智能时间工具，支持时区和时间戳 Streamable HTTP/STDIO传输协议，支持MCP 2025-03-26标准 FastAPI异步高性能，秒级响应 MCP标准，AI/自动化场景即插即用 🛠️ 快速上手 本项目支持两种运行模式： Stdio 模式：适用于 Claude Desktop 等本地 MCP 客户端（推荐）。 Streamable HTTP 模式：适用于远程部署或通过 SSE/Post 访问。 模式 1：Stdio 模式（Claude Desktop 推荐） 在此模式下，MCP Server 通过标准输入/输出与客户端通信，无需占用网络端口。 方式 A：使用 uvx（推荐） uvx 是 uv 包管理器提供的工具，环境隔离且启动极快。 { "mcpServers": { "12306": { "command": "uvx", "args": ["mcp-server-12306"] } } } 方式 B：使用 pipx 如果您更习惯使用 pipx： { "mcpServers": { "12306": { "command": "pipx", "args": ["run", "--no-cache", "mcp-server-12306"] } } } 方式 C：本地源码运行 适用于开发者调试： { "mcpServers": { "12306": { "command": "uv", "args": ["run", "python", "-m", "mcp_12306.cli"], "cwd": "/path/to/mcp-server-12306" } } } 模式 2：Streamable HTTP 模式 在此模式下，Server 启动一个 Web 服务（默认 8000 端口），支持 MCP 的 SSE（Server-Sent Events）和 POST 交互。 方式 A：本地源码运行 # 1. 克隆并安装依赖 git clone https://github.com/drfccv/mcp-server-12306.git cd mcp-server-12306 uv sync # 2. 启动服务器 uv run python scripts/start_server.py MCP 客户端配置： { "mcpServers": { "12306": { "url": "http://localhost:8000/mcp" } } } 方式 B：Docker 部署 # 拉取镜像并运行 docker run -d -p 8000:8000 --name mcp-server-12306 drfccv/mcp-server-12306:latest 🤖 工具一览 支持的主流程工具 工具名 典型场景/功能描述 query_tickets 余票/车次/座席/时刻一站式查询 query_ticket_price 实时查询各车次票价信息 search_stations 车站模糊搜索，支持中文/拼音/简拼 get_station_info 获取车站详情（名称、代码、地理等） query_transfer 一次中转换乘方案，自动拼接最优中转 get_train_route_stations 查询指定列车经停站及时刻表 get_current_time 获取当前时间与相对日期，帮助用户准确选择出行日期 📚 工具文档 本项目所有主流程工具的详细功能、实现与使用方法，均已收录于 /docs 目录下： query_tickets.md — 余票/车次/座席/时刻一站式查询 query_ticket_price.md — 实时查询各车次票价信息 search_stations.md — 车站智能搜索 query_transfer.md — 一次中转换乘方案 get_train_route_stations.md — 查询列车经停站 get_current_time.md — 获取当前时间与相对日期 每个文档包含： 工具功能说明 实现方法 请求参数与返回示例 典型调用方式 如需二次开发或集成，建议先阅读对应工具的文档。 🧩 目录结构 src/mcp_12306/ # 主源代码 ├─ server.py # FastAPI主入口 ├─ services/ # 业务逻辑（车票/车站/HTTP） ├─ utils/ # 工具与配置 scripts/ # 启动与数据脚本 📄 License MIT License ⚠️ 免责声明 本项目仅供学习、研究与技术交流，严禁用于任何商业用途。 本项目不存储、不篡改、不传播任何 12306 官方数据，仅作为官方公开接口的智能聚合与转发。 使用本项目造成的任何后果（包括但不限于账号封禁、数据异常、法律风险等）均由使用者本人承担，项目作者不承担任何责任。 请遵守中国法律法规及 12306 官方相关规定，合理合规使用。
正方教务系统爬虫-微信小程序前后端
正方教务系统完整解决方案 - 微信小程序 + 后端 API 项目简介 这是一个完整的正方教务系统第三方解决方案，包含微信小程序前端和 Python 后端 API 服务。该项目为学生提供便捷的教务管理服务，支持课表查询、成绩管理、选课系统等核心功能。 ⚠️ 重要说明：本项目为第三方开发的非官方 API，仅供学习交流使用。 🔗 前端项目: ZFJW-miniprogram 🔗 后端项目: ZFJW-backend 项目架构 整体架构图 ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ │ │ │ │ 微信小程序端 │◄──►│ Python 后端 API │◄──►│ 正方教务系统 │ │ │ │ │ │ │ │ - TypeScript 100% │ │ - Python 99.6% │ │ - 各高校教务系统 │ │ - 本地数据缓存 │ │ - Flask 框架 │ │ - 第三方接口调用 │ │ - 隐私保护设计 │ │ - RESTful API │ │ - 数据获取与解析 │ │ │ │ │ │ │ └─────────────────────┘ └─────────────────────┘ └─────────────────────┘ 技术栈对比 组件 前端小程序 后端 API 语言 TypeScript (100%) Python (99.6%) 框架 微信小程序原生 Flask 2.0+ 特性 本地缓存、隐私保护 RESTful API、多校支持 部署 微信小程序平台 独立服务器/Docker 核心功能 🎯 完整功能矩阵 功能模块 前端实现 后端支持 状态 用户认证 ✅ 登录界面、密码管理 ✅ 验证码登录、Session 管理 已完成 个人信息 ✅ 信息展示、资料管理 ✅ 学生信息查询 已完成 智能课表 ✅ 周视图、手势滑动 ✅ 课表查询 已完成 成绩管理 ✅ 多学期查询、GPA 计算 ✅ 成绩统计分析 已完成 考试安排 ✅ 考试时间展示 ✅ 考试信息查询 已完成 选课系统 ✅ 已选课程显示 🚧 选课操作开发中 部分完成 教学评价 ✅ 一键评教功能 ✅ 评价数据处理 已完成 通知公告 ✅ 通知展示 ✅ 消息推送 已完成 空教室查询 🚧 界面开发中 🚧 查询接口开发中 计划中 🔥 核心特性 前端特性 🎨 现代化界面: 简洁美观的用户界面设计 📱 响应式布局: 适配不同屏幕尺寸 💾 智能缓存: 离线数据查看，减少网络请求 🔒 隐私保护: 数据本地存储，不上传云端 ⚡ 流畅体验: 手势操作，快速响应 后端特性 🚀 高性能: 基于 Flask 的轻量级架构 🏫 多校支持: 灵活的学校配置系统 🔐 安全可靠: 完善的认证和会话管理 🐳 容器化: 支持 Docker 部署 📊 数据处理: 智能的数据解析和统计 详细功能介绍 📅 智能课表系统 前端实现： // 课表周视图组件 interface ScheduleWeekView { currentWeek: number; scheduleData: CourseInfo[]; weekDays: string[]; timeSlots: TimeSlot[]; } // 手势滑动切换周次 const handleSwipeChange = (e: any) => { const { current } = e.detail; setCurrentWeek(current + 1); loadScheduleData(current + 1); }; 后端 API： @app.route('/api/schedule', methods=['GET']) def get_schedule(): """获取课表数据""" week = request.args.get('week', 1) try: schedule_data = zfn_api.get_schedule(week) return jsonify({ 'code': 200, 'data': schedule_data, 'message': 'success' }) except Exception as e: return jsonify({ 'code': 500, 'message': str(e) }) 📊 成绩管理系统 前端功能： 多学期成绩查询 GPA 自动计算 成绩统计图表 学分统计展示 后端处理： def calculate_gpa(grades_data): """计算 GPA""" total_credits = 0 total_grade_points = 0 for grade in grades_data: credit = float(grade.get('credit', 0)) score = float(grade.get('score', 0)) grade_point = score_to_gpa(score) total_credits += credit total_grade_points += credit * grade_point return total_grade_points / total_credits if total_credits > 0 else 0 🔐 安全认证机制 前端实现： // 登录管理器 class LoginManager { private static instance: LoginManager; // 登录验证 async login(username: string, password: string, captcha: string) { const loginData = { username, password: this.encryptPassword(password), captcha }; const response = await api.post('/login', loginData); if (response.code === 200) { this.saveLoginInfo(response.data); return true; } return false; } // 密码加密 private encryptPassword(password: string): string { // 实现密码加密逻辑 return btoa(password); } } 后端验证： @app.route('/api/login', methods=['POST']) def login(): """用户登录验证""" data = request.get_json() username = data.get('username') password = data.get('password') captcha = data.get('captcha') try: # 验证登录信息 login_result = zfn_api.login(username, password, captcha) if login_result['success']: # 创建会话 session['user_id'] = username session['login_time'] = datetime.now() return jsonify({ 'code': 200, 'data': login_result['data'], 'message': '登录成功' }) else: return jsonify({ 'code': 401, 'message': login_result['message'] }) except Exception as e: return jsonify({ 'code': 500, 'message': f'登录失败: {str(e)}' }) 部署指南 🖥️ 后端部署 本地开发环境 # 1. 克隆后端项目 git clone https://github.com/drfccv/ZFJW-backend.git cd ZFJW-backend # 2. 创建虚拟环境 python -m venv venv source venv/bin/activate # Linux/Mac venv\Scripts\activate # Windows # 3. 安装依赖 pip install -r requirements.txt # 4. 配置学校信息 cp school_config.example.json school_config.json # 编辑 school_config.json 添加你的学校配置 # 5. 启动服务 python app.py Docker 部署 # 1. 构建镜像 docker build -t zfjw-backend . # 2. 运行容器 docker run -d -p 5000:5000 --name zfjw-backend zfjw-backend # 3. 查看日志 docker logs -f zfjw-backend 生产环境部署 # 使用 Gunicorn 部署 pip install gunicorn gunicorn -w 4 -b 0.0.0.0:5000 app:app # 或使用 uWSGI pip install uwsgi uwsgi --http :5000 --module app:app --processes 4 📱 前端部署 开发环境 # 1. 克隆前端项目 git clone https://github.com/drfccv/ZFJW-miniprogram.git cd ZFJW-miniprogram # 2. 安装依赖 npm install # 3. 配置后端 API 地址 # 修改 utils/config.ts 中的 API_BASE_URL # 4. 微信开发者工具 # 使用微信开发者工具打开项目目录 # 开启"不校验合法域名"选项 生产环境 # 1. 配置服务器域名 # 在微信小程序后台添加 request 合法域名 # https://your-api-domain.com # 2. 上传代码 # 使用微信开发者工具上传代码 # 提交审核并发布 学校配置 添加新学校支持 获取学校教务系统信息 # 访问学校教务系统，获取以下信息： # - 教务系统 URL # - 登录接口路径 # - 验证码接口 # - 页面编码格式 创建学校配置文件 { "school_code": "your_school", "school_name": "你的学校名称", "base_url": "http://jwxt.your-school.edu.cn", "login_url": "/jsxsd/xk/LoginToXk", "captcha_url": "/jsxsd/verifycode.servlet", "encoding": "gbk", "timeout": 30, "headers": { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1" } } 测试配置 # 创建测试脚本 import requests from school_config import load_school_config config = load_school_config('your_school') session = requests.Session() # 测试登录 response = session.post( config['base_url'] + config['login_url'], data={ 'userAccount': 'test_username', 'userPassword': 'test_password', 'RANDOMCODE': 'test_captcha' }, headers=config['headers'] ) print(f"登录测试结果: {response.status_code}") 常见问题与解决方案 ❓ 登录相关问题 Q: 登录失败怎么办？ A: 检查以下几点： 1. 学号密码是否正确 2. 验证码是否正确输入 3. 学校教务系统是否正常运行 4. 网络连接是否稳定 5. 后端服务是否正常启动 Q: 验证码识别不准确？ A: 验证码识别问题： 1. 刷新验证码重新输入 2. 检查验证码图片是否清晰 3. 确认输入的验证码字符正确 4. 如果持续失败，可能需要手动输入 🔧 技术问题 Q: 后端 API 启动失败？ # 检查 Python 版本 python --version # 需要 3.7+ # 检查依赖安装 pip list | grep Flask # 检查端口占用 netstat -an | grep 5000 lsof -i :5000 # Linux/Mac # 查看详细错误日志 python app.py --debug Q: 小程序无法连接后端？ // 检查 API 地址配置 const API_BASE_URL = 'https://your-api-domain.com'; // 检查网络请求 wx.request({ url: API_BASE_URL + '/api/health', success: (res) => { console.log('API 连接正常:', res.data); }, fail: (err) => { console.error('API 连接失败:', err); } }); Q: 数据不显示或显示错误？ A: 数据问题排查： 1. 检查登录状态是否有效 2. 确认学期时间设置正确 3. 查看控制台错误日志 4. 验证后端 API 返回数据 5. 清除缓存重新获取数据 安全与隐私 🔒 数据安全措施 前端安全 敏感数据本地加密存储 不上传个人信息到第三方服务器 支持随时清除本地数据 使用 HTTPS 加密通信 后端安全 不存储用户密码 Session 超时自动清理 请求频率限制 输入数据验证和过滤 通信安全 API 接口使用 HTTPS 数据传输加密 防止中间人攻击 会话令牌管理 🛡️ 隐私保护承诺 ✅ 不收集用户个人隐私信息 ✅ 不进行用户行为跟踪分析 ✅ 数据仅用于教务查询功能 ✅ 支持用户随时删除数据 ✅ 遵循最小数据收集原则 ✅ 本地存储优先原则 贡献指南 🤝 参与贡献 我们欢迎所有形式的贡献！ 贡献类型： 🐛 Bug 修复 ✨ 新功能开发 📝 文档完善 🏫 学校配置添加 🧪 测试用例编写 🎨 UI/UX 改进 贡献流程： Fork 项目到个人账号 创建功能分支 git checkout -b feature/amazing-feature 提交更改 git commit -m 'Add amazing feature' 推送分支 git push origin feature/amazing-feature 创建 Pull Request 📋 开发规范 代码规范： # 前端 TypeScript npm run lint # 代码检查 npm run format # 代码格式化 # 后端 Python pip install black flake8 black . # 代码格式化 flake8 . # 代码检查 提交规范： feat: 新功能 fix: 修复bug docs: 文档更新 style: 代码格式调整 refactor: 重构代码 test: 测试相关 chore: 其他修改 社区与支持 💬 交流渠道 GitHub Issues: 问题反馈 GitHub Discussions: 讨论交流 QQ 群: 2713587802（学习交流） 📧 联系方式 开发者: @drfccv 邮箱: 27123587802@qq.com 用途: 学习交流、问题反馈、功能建议 免责声明 ⚠️ 重要提醒： 1. 本项目为第三方开发的非官方工具 2. 仅供学习交流和个人使用 3. 请勿用于商业用途或违法活动 4. 使用本项目造成的任何后果由使用者承担 5. 开发者不对数据准确性承担责任 6. 请遵守学校相关规定和法律法规 开源协议 本项目采用 MIT License 开源协议。 致谢 感谢所有贡献者和用户的支持！ 感谢微信小程序平台提供的开发环境 感谢 Flask 框架的优秀设计 感谢开源社区的无私奉献 感谢所有提供学校配置的同学 ⭐ 如果这个项目对你有帮助，请给我们一个 Star！ Made with ❤️ by drfccv | 最后更新: 2024-12-08
DeerFlow-CN 本项目基于 bytedance/deer-flow 二次开发，专为中文用户优化，支持一键部署、SearXNG 集成、SSL 证书等。 🌐 在线 Demo 体验 项目简介 DeerFlow-CN 是一款面向深度研究与高效信息检索的 AI 工具，结合大语言模型与多种外部工具，适用于学术、科研、知识管理等场景。相比原版，DeerFlow-CN 提供了更好的中文体验、屏幕适配与本地化增强。 环境要求 🟢 Node.js 22 及以上 🐍 Python 3.12 及以上 推荐工具 ⚡ uv：简化 Python 环境与依赖管理，自动创建虚拟环境并安装依赖，无需手动配置 Python 环境。 🔄 nvm：高效管理多版本 Node.js 运行时。 🚀 pnpm：高效安装和管理 Node.js 项目依赖。 主要特点 🇨🇳 全面汉化：界面、交互、设置、提示等全部中文化。 📱 屏幕自适应：支持移动端、4K、竖屏等多种分辨率，体验更佳。 💬 Chat 简单聊天模式：可选择不调用 researcher，仅用 LLM 聊天。 🛠️ Settings 界面优化：修复 Tab 显示异常，交互更流畅。 🔍 SearXNG 集成：支持 SearXNG 作为搜索来源，隐私友好。 🧩 一键安装/启动 SearXNG：内置脚本自动安装并集成 SearXNG。 ⚡ 一键启动脚本：start.js/start-with-searxng.js 支持 SSL，证书自动加载。 🔒 SSL 支持：可直接部署 HTTPS，证书与密钥位于 web/fullchain.pem、web/privkey.pem。 项目架构 ├── main.py / server.py # 后端主入口 ├── src/ # 核心后端逻辑（agents/、llms/、tools/等） ├── web/ # 前端 Next.js + Tailwind + React │ ├── src/app/ # 页面与组件 │ ├── public/ # 静态资源 │ ├── start.js # 一键启动脚本（支持SSL） │ ├── start-with-searxng.js # 启动并集成SearXNG │ ├── fullchain.pem # SSL证书 │ ├── privkey.pem # SSL密钥 │ └── ... ├── conf.yaml # LLM与API配置 ├── .env # API密钥配置 ├── docs/ # 配置与使用文档 └── ... 快速开始 1. 克隆项目 git clone https://github.com/drfccv/deer-flow-cn.git cd deer-flow-cn 2. 安装依赖 uv sync 3. 配置环境变量 复制并编辑 .env： cp .env.example .env # 配置 Tavily、Brave Search、volcengine TTS 等 API Key 复制并编辑 conf.yaml： cp conf.yaml.example conf.yaml # 配置 LLM 接口与模型 详细配置说明见 docs/configuration_guide.md 4. 安装 Marp（PPT 生成）（可选） marp-cli 安装文档 macOS: brew install marp-cli 5. 安装 SearXNG（可选，推荐） bash ./src/tools/install-searxng.sh 6. 安装前端依赖 cd web pnpm install 7. 一键启动（推荐，自动启用SSL） 启动后端+前端+SearXNG（推荐）： node start-with-searxng.js 仅启动后端+前端（不含SearXNG）： node start.js 默认自动加载 web/fullchain.pem、web/privkey.pem 证书。 8. 开发模式 启动前端： pnpm dev 启动后端： uv run server.py --ssl --ssl-certfile=web/fullchain.pem --ssl-keyfile=web/privkey.pem 可省略 --ssl 参数则为 HTTP，添加 --ssl 参数即启用 HTTPS。 主要配置说明 .env：API 密钥（Tavily、Brave、TTS等） conf.yaml：LLM模型与API配置，详见 docs/configuration_guide.md web/fullchain.pem、web/privkey.pem：SSL证书与密钥 主要改进与亮点 全面汉化，适合中文用户 响应式设计，适配多终端 Chat支持“简单聊天”模式 Settings界面Tab显示修复 SearXNG一键集成与自动安装 一键SSL部署，安全易用 参考与致谢 原项目：bytedance/deer-flow SearXNG: https://github.com/searxng/searxng Marp: https://github.com/marp-team/marp-cli 如有问题请查阅 docs/FAQ.md 或提交 issue。
🦌 DeerFlow 项目分享 一个由社区驱动的深度研究框架，结合语言模型与工具，如网页搜索、爬虫和 Python 执行，致力于回馈开源社区。(GitHub) 📌 项目简介 DeerFlow（Deep Exploration and Efficient Research Flow）是由字节跳动开源的多智能体研究自动化框架，旨在通过协调多个专用智能体（如搜索、编码、内容生成等）来增强复杂研究工作流程。该框架集成了 Python 执行、网页爬虫和 ByteDance 的 MCP 平台等工具，强调人机协作，使其在实际研究和企业应用中高度适应。 (Reddit) ✨ 核心特性 多智能体架构：每个智能体负责特定任务，如任务规划、知识检索、代码执行或报告合成，通过 LangGraph 构建的有向图进行交互，实现任务的稳健编排和数据流控制。 (Learnopoly) LangChain 与 LangGraph 集成：利用 LangChain 进行语言模型推理和记忆处理，LangGraph 实现多智能体的编排，支持复杂的研究流程。(Learnopoly) 工具集成： 网页搜索与爬虫：实时获取知识，聚合外部数据源。 Python 执行与可视化：支持数据处理、统计分析和代码生成，提供执行验证。 MCP 集成：兼容 ByteDance 的内部模型控制平台，支持更深入的自动化流程。 多模态输出生成：不仅限于文本摘要，还可协同生成幻灯片、播客脚本或视觉内容。 (Learnopoly) 人机协作：强调人类在研究流程中的参与，确保结果的透明性和可控性。(Learnopoly) 🚀 快速开始 环境要求 Python：版本 3.12+ Node.js：版本 22+(GitHub) 推荐工具 uv：简化 Python 环境和依赖管理。 nvm：轻松管理多个 Node.js 运行时版本。 pnpm：安装和管理 Node.js 项目的依赖项。(GitHub) 安装步骤 # 克隆仓库 git clone https://github.com/bytedance/deer-flow.git cd deer-flow # 安装依赖，uv 将自动创建虚拟环境并安装所需的包 uv sync # 配置 .env 文件，添加您的 API 密钥 cp .env.example .env 请根据需要配置 .env 文件中的 API 密钥，例如 Tavily、Brave_SEARCH 和 volcengine TTS。(GitHub) 🧠 示例演示 DeerFlow 提供了多个演示示例，展示了其在不同场景下的应用： 埃菲尔铁塔与世界最高建筑的高度对比 GitHub 上的热门趋势仓库 撰写关于南京传统菜肴的文章 如何装饰租赁公寓 更多示例请访问官方项目页面：deerflow.tech(Reddit) 🤝 鸣谢 DeerFlow 构建在开源社区的卓越工作之上，特别感谢以下项目：(GitHub) LangChain：提供了强大的语言模型交互和链式调用框架。 LangGraph：实现了多智能体的编排，支持复杂的工作流程。(GitHub, Learnopoly) 特别感谢核心作者：(GitHub) Daniel Walnut Henry Li 他们的愿景、热情和奉献使 DeerFlow 项目得以实现。 📈 Star 趋势 🖼️ 运行截图 以下是我在本地运行 DeerFlow 的截图： 如需了解更多信息，请访问项目的 GitHub 页面：https://github.com/bytedance/deer-flow
AI 旅行规划助手 🌍✈️ 一个基于人工智能的旅行规划助手，利用大语言模型和高德地图API为用户定制个性化的旅行计划。 🔗 项目地址 📝 在线体验 Demo ✨ 功能特点 🤖 AI驱动的旅行规划：基于硅基流动Qwen/Qwen3-235B-A22B模型智能生成详细的多日旅程 🗺️ 高德地图集成：准确显示景点位置和路线规划 🌦️ 实时天气信息：获取目的地的准确天气预报 🏨 完整旅行建议：包含住宿、交通、餐饮和景点游览时间推荐 💾 智能缓存机制：减少API调用，提高响应速度 📱 响应式设计：适配各种设备尺寸，提供良好的移动端体验 🚀 快速开始 前提条件 Node.js 16.x 或更高版本 高德地图API密钥 大语言模型API密钥 (如DeepSeek API) 安装步骤 克隆仓库 git clone https://github.com/Drfccv/AI-Trip-Planner.git cd AI-Trip-Planner 安装依赖 npm install 创建环境配置 在项目根目录创建.env文件，添加以下内容： export const ENV = { AMAP_API_KEY: 'YOUR_AMAP_KEY', AMAP_SECURITY_KEY: 'YOUR_AMAP_SECURITY_KEY', DEEPSEEK_API_KEY: 'YOUR_SILICONFLOW_KEY' }; 启动开发服务器 npm run dev 打开浏览器访问 http://localhost:5173 🏗️ 技术栈 前端框架: React + TypeScript 构建工具: Vite UI组件库: Ant Design 地图服务: 高德地图 JavaScript API 状态管理: React Hooks HTTP客户端: Axios AI服务: 硅基流动API (Qwen/Qwen3-235B-A22B模型) 📝 使用指南 在首页填写旅行信息表单: 目的地城市 旅行日期和天数 交通方式偏好 住宿偏好 旅行风格标签 点击"生成旅行计划"按钮 系统将调用AI生成详细的旅行计划并展示: 每日行程安排 景点信息与推荐游览时间 交通与住宿建议 餐饮推荐 天气预报 互动地图 可以随时返回调整参数重新规划 🧩 项目结构 src/ ├── assets/ # 静态资源 ├── components/ # 可复用组件 │ ├── AmapComponent.tsx # 高德地图组件 │ ├── LoadingPage.tsx # 加载页面组件 │ ├── TripInputForm.tsx # 旅行输入表单 │ └── TripPlanResult.tsx # 旅行计划结果展示 ├── pages/ # 页面组件 │ ├── HomePage.tsx # 首页 │ └── ResultPage.tsx # 结果页 ├── services/ # API服务 │ └── api.ts # API调用函数 ├── types/ # TypeScript类型定义 │ └── index.ts # 类型定义文件 └── utils/ # 工具函数 └── mockData.ts # 模拟数据 🌟 核心功能实现细节 AI旅行计划生成 使用硅基流动提供的Qwen/Qwen3-235B-A22B大语言模型生成定制化的旅行计划。该模型是基于通义千问系列的超大规模语言模型，拥有2350亿参数量，具有强大的自然语言理解和生成能力。 系统会将用户的旅行偏好（目的地、日期、天数、交通方式、住宿偏好和旅行风格标签）格式化后发送给模型，模型会返回结构化的旅行计划JSON数据，包括： 每日详细行程安排 景点推荐与描述 游览时间建议 餐饮推荐 交通与住宿安排 根据用户偏好定制的总体建议 模型会基于城市特点、季节因素、用户偏好等多维度信息优化生成结果，并且会考虑景点之间的地理位置关系，合理安排游览顺序。 高德地图集成 景点定位: 通过高德POI搜索API获取景点准确位置 路线规划: 根据交通方式提供合理的游览路线 地图可视化: 直观展示每日或全程的景点分布(BUG) 天气信息 调用高德天气API获取目的地的实时天气预报，帮助用户做好行前准备。 高德JSAPI仅可查询未来3天天气，后续考虑更换API服务 📄 许可证 MIT 🤝 贡献指南 欢迎提交Pull Request或Issue！对于重大变更，请先开Issue讨论您想要改变的内容。 📞 联系方式 如有任何问题或建议，请通过以下方式联系我： Email: 2713587802@qq.com GitHub: Drfccv AI旅行规划助手 - 让旅行计划变得简单而智能，由Qwen/Qwen3-235B-A22B模型提供强大的AI能力支持 🌈
[hide-toggle name="本文中使用的配置参考"]CPU : AMD R9-7940HX GPU : NV RTX4060Laptop MEM : 32G[/hide-toggle] 下载及使用RVC 项目地址：https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI 下载对应的版本，此处不多赘述 解压文件至无中文路径中，打开go-web.bat，等待一会会弹出一个网页 准备声音训练数据集 准备5分钟以上的wav格式纯人声音频，如无则可通过RVC自带的人声分离 准备好待处理的音频，并打开刚刚的网页，选择伴奏人声分离&去混响&去人声，分离模型可自行根据说明进行选择，输出格式依然选择wav如图点击转换即可处理。进入rvc/opt即可看到输出的音频文件，复制文件路径 进行训练 在webui中选择“训练”目标采样率建议选择48k，输入训练文件夹路径粘贴刚复制的数据集所在文件夹路径，总训练轮数视情况而定，这里选择了30轮保存，总150轮，其他设置视机器配置而定，4060laptop训练6分钟的数据，耗时约6小时，点击“一键训练”即可开始 模型推理 训练完成后的模型会保存在rvc/assets/weights下，底模文件“在rvc/logs/"实验名"/*.index” 在webui中选择推理，刷新音色列表及索引路径，选择训练出来的模型，接着输入想要变声的音频文件路径 例： 点击开始转换，很快就可以得到输出的结果 实时变声 训练出来的模型可用于RVC实时变声，这里不多进行赘述，网上有很多相关教程，需下载虚拟声卡如VoiceMeeter，使用rvc目录下的go-realtime-gui.bat 训练集及输出模型(提取码：uVIQ)