@@ -1561,6 +1561,168 @@ https://github.com/Tencent/APIJSON/issues
15611561 },
15621562
15631563 methods: {
1564+ getPageAgentConfig: function () {
1565+ var model = StringUtil.trim(this.aiModel)
1566+ var baseURL = StringUtil.trim(this.aiBaseUrl)
1567+ var apiKey = StringUtil.trim(this.aiApiKey)
1568+ var language = StringUtil.trim(this.aiLanguage) || 'zh-CN'
1569+ var customFetchURL = null
1570+ if (StringUtil.isNotEmpty(baseURL, true)) {
1571+ if (baseURL.indexOf('://') < 0) {
1572+ baseURL = 'https://' + baseURL
1573+ }
1574+ baseURL = baseURL.replace(/\+$/, '')
1575+ var lowerBaseURL = baseURL.toLowerCase()
1576+
1577+ // page-agent 内部固定请求 `${baseURL}/chat/completions`,通过 customFetch 控制最终请求地址,避免被内部追加路径影响
1578+ var protocolIndex = baseURL.indexOf('://')
1579+ var pathIndex = protocolIndex < 0 ? -1 : baseURL.indexOf('/', protocolIndex + 3)
1580+ if (pathIndex >= 0) {
1581+ var pathBaseURL = baseURL
1582+ var queryIndex = pathBaseURL.indexOf('?')
1583+ var query = queryIndex < 0 ? 1 : pathBaseURL.substring(queryIndex)
1584+ var pathBaseURLWithoutQuery = queryIndex < 0 ? pathBaseURL : pathBaseURL.substring(0, queryIndex)
1585+ var lowerPathBaseURL = pathBaseURLWithoutQuery.toLowerCase()
1586+
1587+ if (lowerPathBaseURL.indexOf('/chat/completions') >= 0
1588+ || lowerPathBaseURL.indexOf('/responses') >= 0
1589+ || lowerPathBaseURL.indexOf('/messages') >= 0
1590+ || lowerPathBaseURL.indexOf('/generatecontent') >= 0) {
1591+ customFetchURL = baseURL
1592+ } else if (lowerPathBaseURL.indexOf('genaiapi.cloudsway.net') >= 0
1593+ || lowerPathBaseURL.indexOf('.openai.azure.com/openai/v1') >= 0) {
1594+ customFetchURL = pathBaseURLWithoutQuery + '/chat/completions' + query
1595+ } else {
1596+ customFetchURL = baseURL
1597+ }
1598+ } else if (lowerBaseURL.indexOf('.openai.azure.com') >= 0) {
1599+ customFetchURL = baseURL + '/openai/v1/chat/completions'
1600+ }
1601+ }
1602+
1603+ return {
1604+ model: model,
1605+ baseURL: baseURL,
1606+ apikey: apiKey,
1607+ language: language,
1608+ customFetchURL: customFetchURL
1609+ }
1610+ },
1611+
1612+ initPageAgent: function (showPanel) {
1613+ if (IS_BROWSER == false) {
1614+ return null
1615+ }
1616+
1617+ var AgentClass = window.PageAgent
1618+ if (AgentClass == null) {
1619+ alert('PageAgent 加载失败,请检查 page-agent 脚本是否可访问!')
1620+ return null
1621+ }
1622+
1623+ var config = this.getPageAgentConfig()
1624+ if (StringUtil.isEmpty(config.model, true) || StringUtil.isEmpty(config.baseURL, true)) {
1625+ alert('请先配置 PageAgent 的模型和 Base URL!')
1626+ return null
1627+ }
1628+
1629+ this.disposePageAgent()
1630+ try {
1631+ var agentConfig = {
1632+ model: config.model,
1633+ baseURL: config.baseURL,
1634+ apikey: config.apiKey,
1635+ language: config.language,
1636+ transformRequestBody: function (body) {
1637+ var modelName = StringUtil.get(body.model)
1638+ if (modelName.indexOf('/') >= 0) {
1639+ modelName = modelName.substring(modelName.lastIndexOf('/') + 1)
1640+ }
1641+
1642+ modelName = modelName.replace(/_/g, '').replace(/\./g, '')
1643+
1644+ // GPT-5 系列在 Azure/0penAI-compatible Chat Completions 上只支持默认温度;
1645+ // page-agent 默认会带 temperature: 0.7, 服务端会返回 unsupported_value
1646+ if (modelName.indexOf('gpt-5') >= 0 || modelName.indexOf('gpt5') >= 0) {
1647+ delete body.temperature
1648+ delete body.verbosity
1649+ }
1650+
1651+ return body
1652+ }
1653+ }
1654+
1655+ if (StringUtil.isNotEmpty(config.customFetchURL, true)) {
1656+ agentConfig.customFetch = function (url, init) {
1657+ console.log('[PageAgent] rewrite LLM request URL: ', url, '=>', config.customFetchURL)
1658+ return fetch(config.customFetchURL, init)
1659+ }
1660+ }
1661+
1662+ var agent = window.pageAgent = new AgentClass(agentConfig)
1663+ if (showPanel != false) {
1664+ agent?.panel?.show()
1665+ }
1666+
1667+ console.log('[PageAgent] initialized with config:', {
1668+ model: agentConfig.model,
1669+ baseURL: agentConfig.baseURL,
1670+ apikey: StringUtil.isEmpty(agentConfig.apiKey, true) ? '(empty)'
1671+ : (agentConfig.apiKey.length <= 6 ? '***'
1672+ : (agentConfig.apiKey.slice(0, 3) + '***' + agentConfig.apiKey.slice(-3))
1673+ ),
1674+ language: agentConfig.language,
1675+ customFetchURL: config.customFetchURL
1676+ })
1677+
1678+ return agent
1679+ } catch (e) {
1680+ console.log(e)
1681+ alert('PageAgent 初始化失败:' + e.message)
1682+ return null
1683+ }
1684+ },
1685+
1686+ disposePageAgent: function () {
1687+ if (IS_BROWSER == false || window.pageAgent == null) {
1688+ return
1689+ }
1690+
1691+ try {
1692+ var oldAgent = window.pageAgent
1693+ var oldPanel = oldAgent?.panel
1694+ if (oldPanel != null) {
1695+ try {
1696+ oldPanel.hide?.()
1697+ } catch (e1) {
1698+ console.log(e1)
1699+ }
1700+
1701+ // agent.dispose() 不会连带清 Panel 的 DOM, 只有 panel.dispose() 里才
1702+ // 会走 wrapper.remove(),否则每次改配置都会在页面上残留一个隐藏的旧面板
1703+ try {
1704+ oldPanel.dispose?.()
1705+ } catch (e2) {
1706+ console.log(e2)
1707+ }
1708+ }
1709+
1710+ if (typeof oldAgent.dispose == 'function') {
1711+ oldAgent.dispose()
1712+ }
1713+ } catch (e) {
1714+ console.log(e)
1715+ } finally {
1716+ window.pageAgent = null
1717+ }
1718+ },
1719+
1720+ refreshPageAgent: function () {
1721+ if (this.isAgentEnabled) {
1722+ this.initPageAgent(true)
1723+ }
1724+ },
1725+
15641726 // 全部展开
15651727 expandAll: function () {
15661728 if (this.view != 'code') {
@@ -2450,13 +2612,7 @@ https://github.com/Tencent/APIJSON/issues
24502612 case 18:
24512613 this.isAgentEnabled = show
24522614 this.saveCache('', 'isAgentEnabled', show)
2453- pageAgent = pageAgent || new PageAgent()
2454- const config = pageAgent?.config || new PageAgentCoreConfig()
2455- config.model = this.aiModel || config?.model
2456- config.baseURL = this.aiBaseUrl || config?.baseURL
2457- config.apiKey = this.aiApiKey || config?.apiKey
2458- config.language = this.aiLanguage || config?.language
2459- pageAgent?.panel?.show()
2615+ this.initPageAgent(true)
24602616 break
24612617 case 12:
24622618 this.isEncodeEnabled = show
@@ -2518,7 +2674,7 @@ https://github.com/Tencent/APIJSON/issues
25182674 else if (index == 18) {
25192675 this.isAgentEnabled = show
25202676 this.saveCache('', 'isAgentEnabled', show)
2521- pageAgent?.panel?.hide ()
2677+ this.disposePageAgent ()
25222678 }
25232679 else if (index == 14) {
25242680 this.isEnvCompareEnabled = show
@@ -2636,7 +2792,7 @@ https://github.com/Tencent/APIJSON/issues
26362792 save: function () {
26372793 var name = (this.history || {}).name
26382794 if (StringUtil.isEmpty(name)) {
2639- Helper. alert('名称不能为空!', 'danger')
2795+ alert('名称不能为空!', 'danger')
26402796 return
26412797 }
26422798
@@ -2653,7 +2809,7 @@ https://github.com/Tencent/APIJSON/issues
26532809 }
26542810 var key = String(Date.now())
26552811 localforage.setItem(key, val, function (err, value) {
2656- Helper. alert('保存成功!', 'success')
2812+ alert('保存成功!', 'success')
26572813 App.showSave(false)
26582814 val.key = key
26592815 App.historys.push(val)
@@ -3074,7 +3230,7 @@ https://github.com/Tencent/APIJSON/issues
30743230 saveTextAs('# ' + this.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON'
30753231 + '\n\nBASE_URL: ' + this.getBaseUrl()
30763232 + '\n\n\n## 测试用例(Markdown格式,可用工具预览) \n\n' + this.getDoc4TestCase()
3077- + ' \n\n\n\n\n\n\n\n## 文档(Markdown格式,可用工具预览) \n\n' + doc
3233+ + (this.view != 'markdown' ? '' : ' \n\n\n\n\n\n\n\n## 文档(Markdown格式,可用工具预览) \n\n' + doc)
30783234 , this.exTxt.name + '.txt')
30793235 }
30803236 else if (this.view == 'markdown' || this.view == 'output') { //model
@@ -4139,18 +4295,22 @@ https://github.com/Tencent/APIJSON/issues
41394295 case 19:
41404296 this.aiModel = StringUtil.get(this.exTxt.name)
41414297 this.saveCache('', 'aiModel', this.aiModel)
4298+ this.refreshPageAgent()
41424299 break
41434300 case 20:
41444301 this.aiBaseUrl = StringUtil.get(this.exTxt.name)
41454302 this.saveCache('', 'aiBaseUrl', this.aiBaseUrl)
4303+ this.refreshPageAgent()
41464304 break
41474305 case 21:
41484306 this.aiApiKey = StringUtil.get(this.exTxt.name)
41494307 this.saveCache('', 'aiApiKey', this.aiApiKey)
4308+ this.refreshPageAgent()
41504309 break
41514310 case 22:
41524311 this.aiLanguage = StringUtil.get(this.exTxt.name)
41534312 this.saveCache('', 'aiLanguage', this.aiLanguage)
4313+ this.refreshPageAgent()
41544314 break
41554315 case 8:
41564316 var thirdParty = this.exTxt.name
0 commit comments