Skip to content

Commit e3d96fe

Browse files
committed
APIAuto:AI Agent:支持自定义模型
1 parent d6ce220 commit e3d96fe

3 files changed

Lines changed: 175 additions & 15 deletions

File tree

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ Bilibili:https://search.bilibili.com/all?keyword=APIAuto
123123
[别再生成测试代码了!](https://mp.weixin.qq.com/s/G1GVNhhFbSX5GoyRU6GURg) <br />
124124
[APIAuto: 最先进的 HTTP 接口工具](https://blog.csdn.net/Nifc666/article/details/141966487) <br />
125125
[APIAuto 开源项目教程](https://blog.csdn.net/gitblog_00138/article/details/142802330) <br />
126-
[Github 2.2k Star!一款开源的机器学习 HTTP 接口工具!](https://mp.weixin.qq.com/s/4ZS80QP-WN-holFQkrxK-w)
126+
[Github 2.2k Star!一款开源的机器学习 HTTP 接口工具!](https://mp.weixin.qq.com/s/4ZS80QP-WN-holFQkrxK-w) <br />
127+
[APIAuto:机器学习驱动的零代码HTTP接口智能测试平台深度解析](https://blog.csdn.net/weixin_33940469/article/details/162085502)
127128

128129
### 百度、搜狗、抖音公网接口调用演示 <br />
129130
因为这些接口不支持 CORS 跨域,所以需要开启托管服务代理。<br />

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/index.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
<a style="border-bottom: #DDD 1px solid;width: 100%;display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden;" href="javascript:void(0)" @click="showConfig(! isRandomShow, 5)">{{ isRandomShow ? '隐藏(固定)参数注入 Random Test' : '显示(编辑)参数注入 Random Test' }}</a>
135135
<a style="border-bottom: #DDD 1px solid;width: 100%;display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden;" href="javascript:void(0)" @click="showConfig(! isHeaderShow, 4)">{{ (isHeaderShow ? '隐藏(固定)' : '显示(编辑)') + (isEditResponse ? '响应头 Response Header' : '请求头 Request Header' ) }}</a>
136136
<a style="border-bottom: #DDD 1px solid;width: 100%;display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden;" href="javascript:void(0)" @click="showConfig(! isScriptShow, 13)">{{ (isScriptShow ? '隐藏(固定)' : '显示(编辑)') + '执行脚本 JavaScript' }}</a>
137-
<a v-show="User.id != null && User.id > 0" class="setting-item" href="javascript:void(0)" @click="showConfig(! isAgentEnabled, 18)">{{ (isAgentEnabled ? '隐藏' : '显示') + '网页自动操作 AI Agent' }} </a>
137+
<a class="setting-item" href="javascript:void(0)" @click="showConfig(! isAgentEnabled, 18)">{{ (isAgentEnabled ? '隐藏' : '显示') + '网页自动操作 AI Agent' }} </a>
138138
<a v-show="User.id != null && User.id > 0" class="setting-item" href="javascript:void(0)" @click="showConfig(! isStatisticsEnabled, 17)">{{ (isStatisticsEnabled ? '隐藏' : '显示') + '测试统计报告 Test Report' }} </a>
139139
<a class="setting-item" href="javascript:void(0)" @click="showConfig(true, 2)">生成代码(封装,解析) : {{ language || '例如 Java' }}</a>
140140
<a v-show="User.id != null && User.id > 0" class="setting-item" href="javascript:void(0)" @click="showConfig(true, 0)">数据库类型 Database: {{ database || '例如 MYSQL' }}</a>
@@ -1075,7 +1075,6 @@
10751075
<script src="js/FileSaver.js"></script>
10761076
<script src="js/uuid.js"></script>
10771077
<script src="js/clipboard.min.js"></script>
1078-
<script src="js/helper.js"></script>
10791078

10801079
<!-- 必须在main.js前 TODO 可能有冲突,代码写入vue文件? <<<<<<<<<<<<<<<< -->
10811080
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
@@ -1163,7 +1162,7 @@
11631162
<script src="md/lib/jquery.flowchart.min.js"></script>
11641163

11651164
<script src="md/editormd.js"></script>
1166-
<script src="https://registry.npmmirror.com/page-agent/1.10.0/files/dist/iife/page-agent.demo.js" crossorigin="true"></script>
1165+
<script src="https://registry.npmmirror.com/page-agent/1.10.0/files/dist/iife/page-agent.demo.js?autoInit=false" crossorigin="true"></script>
11671166

11681167
</body>
11691168
</html>

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/js/main.js

Lines changed: 171 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)