Browse Source

增加了 AI,

后端版本: 8.2.10
前端版本: 8.2.48
main
wangshaoping 4 months ago
parent
commit
3d6bb0a258
  1. 3
      app.platform/build.gradle
  2. 9
      build-version.gradle
  3. 42
      build.gradle
  4. 5
      erm.frontend/package.json
  5. 2
      erm.frontend/src/boostrap.ts
  6. 8
      erm.frontend/webpack.config.common.cjs
  7. 43
      erm.frontend/webpack.config.mf.cjs
  8. 42
      erm.frontend/webpack.env.build.cjs
  9. 13
      gradle.properties
  10. 5
      io.sc.engine.mv.frontend/package.json
  11. 2
      io.sc.engine.mv.frontend/src/boostrap.ts
  12. 1
      io.sc.engine.mv.frontend/src/views/result/Result.vue
  13. 28
      io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue
  14. 10
      io.sc.engine.mv.frontend/src/views/sample/Sample.vue
  15. 8
      io.sc.engine.mv.frontend/webpack.config.common.cjs
  16. 43
      io.sc.engine.mv.frontend/webpack.config.mf.cjs
  17. 42
      io.sc.engine.mv.frontend/webpack.env.build.cjs
  18. 34
      io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeBinomialHistoryWebController.java
  19. 34
      io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeChiSquareHistoryWebController.java
  20. 5
      io.sc.engine.rule.frontend/package.json
  21. 2
      io.sc.engine.rule.frontend/src/boostrap.ts
  22. 8
      io.sc.engine.rule.frontend/webpack.config.common.cjs
  23. 43
      io.sc.engine.rule.frontend/webpack.config.mf.cjs
  24. 42
      io.sc.engine.rule.frontend/webpack.env.build.cjs
  25. 5
      io.sc.engine.st.frontend/package.json
  26. 2
      io.sc.engine.st.frontend/src/boostrap.ts
  27. 2
      io.sc.engine.st.frontend/src/views/DepFactor/DepFactor.vue
  28. 6
      io.sc.engine.st.frontend/src/views/DepFactor/DepFactorDefine.vue
  29. 2
      io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactor.vue
  30. 6
      io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactorDefine.vue
  31. 6
      io.sc.engine.st.frontend/src/views/Model/ModelAnalysisFactor.vue
  32. 6
      io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactor.vue
  33. 6
      io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactorDefine.vue
  34. 6
      io.sc.engine.st.frontend/src/views/TestCase/TestResult.vue
  35. 8
      io.sc.engine.st.frontend/webpack.config.common.cjs
  36. 43
      io.sc.engine.st.frontend/webpack.config.mf.cjs
  37. 42
      io.sc.engine.st.frontend/webpack.env.build.cjs
  38. 8
      io.sc.platform.ai/build.gradle
  39. 0
      io.sc.platform.ai/gradle.properties
  40. 4
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/AnythingllmService.java
  41. 6
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/impl/AnythingllmServiceImpl.java
  42. 86
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatApi.java
  43. 45
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatCallback.java
  44. 25
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/MessageWrapper.java
  45. 66
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/OllamaApi.java
  46. 31
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/controller/OllamaWebController.java
  47. 13
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/OllamaService.java
  48. 69
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/impl/OllamaServiceImpl.java
  49. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/blobs/BlobsApi.java
  50. 84
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatApi.java
  51. 44
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatCallback.java
  52. 80
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatRequest.java
  53. 117
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatResponse.java
  54. 54
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Message.java
  55. 4
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Tool.java
  56. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/copy/OllamaCopyApi.java
  57. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/create/OllamaCreateApi.java
  58. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/delete/OllamaDeleteApi.java
  59. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embed/OllamaEmbedApi.java
  60. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embeddings/OllamaEmbeddingsApi.java
  61. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/generate/OllamaGenerateApi.java
  62. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/ps/OllamaPsApi.java
  63. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/pull/OllamaPullApi.java
  64. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/push/OllamaPushApi.java
  65. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/show/OllamaShowApi.java
  66. 71
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Details.java
  67. 65
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Model.java
  68. 42
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsApi.java
  69. 19
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsResponse.java
  70. 11
      io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/version/OllamaVersionApi.java
  71. 16
      io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/components.json
  72. 5
      io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/messages.json
  73. 67
      io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/parameters.json
  74. 4
      io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/security.json
  75. 12
      io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters.properties
  76. 12
      io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_tw_CN.properties
  77. 13
      io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_zh_CN.properties
  78. 1
      io.sc.platform.app-nacos/build.gradle
  79. 5
      io.sc.platform.core.frontend/package.json
  80. 2
      io.sc.platform.core.frontend/src/boostrap.ts
  81. 2
      io.sc.platform.core.frontend/src/components/index.ts
  82. 1
      io.sc.platform.core.frontend/src/i18n/messages.json
  83. 1
      io.sc.platform.core.frontend/src/i18n/messages_tw_CN.json
  84. 1
      io.sc.platform.core.frontend/src/i18n/messages_zh_CN.json
  85. 9
      io.sc.platform.core.frontend/src/menus/menus.json
  86. 6
      io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue
  87. 2
      io.sc.platform.core.frontend/src/platform/index.ts
  88. 8
      io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue
  89. 35
      io.sc.platform.core.frontend/src/platform/plugin/axios.ts
  90. 2
      io.sc.platform.core.frontend/src/platform/plugin/index.ts
  91. 2
      io.sc.platform.core.frontend/src/platform/plugin/quasar-components.ts
  92. 1
      io.sc.platform.core.frontend/src/platform/plugin/quasar.ts
  93. 15
      io.sc.platform.core.frontend/src/routes/routes.json
  94. 25
      io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue
  95. 7
      io.sc.platform.core.frontend/template-project/package.json
  96. 2
      io.sc.platform.core.frontend/template-project/src/boostrap.ts
  97. 2
      io.sc.platform.core.frontend/template-project/src/components/index.ts
  98. 1
      io.sc.platform.core.frontend/template-project/src/i18n/messages.json
  99. 1
      io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json
  100. 1
      io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json

3
app.platform/build.gradle

@ -16,6 +16,9 @@ dependencies {
project(":io.sc.platform.developer"),
project(":io.sc.standard"),
// ai
project(":io.sc.platform.ai"),
//
project(":io.sc.platform.scheduler.manager"),
project(":io.sc.platform.scheduler.executor"),

9
build-version.gradle

@ -16,6 +16,15 @@ ext['PlatformDependencyVersions'] =[
"org.codehaus.groovy:groovy-sql" : "${groovy_version}",
"org.codehaus.groovy:groovy-xml" : "${groovy_version}",
"mysql:mysql-connector-java" : "${jdbc_mysql_version}",
"com.oracle.database.jdbc:ojdbc8" : "${jdbc_oracle_version}",
"org.mybatis:mybatis" : "${mybatis_version}",
"org.apache.commons:commons-compress" : "${commons_compress_version}",
"com.github.virtuald:curvesapi" : "${curvesapi_version}",
"org.jetbrains.kotlin:kotlin-stdlib" : "${kotlin_stdlib_version}",
"org.apache.poi:poi" : "${poi_version}",
"org.apache.poi:poi-ooxml" : "${poi_version}",
"org.reflections:reflections" : "${reflections_version}",
"com.squareup.okhttp3:okhttp" : "${okhttp_version}"
];
/***********************************************************************

42
build.gradle

@ -59,6 +59,7 @@ subprojects {
// exclude group: "org.apache.logging.log4j", module: "log4j-to-slf4j"
// exclude group: "org.slf4j", module: "slf4j-jdk14"
exclude group: "org.slf4j", module: "slf4j-nop"
exclude group: "org.slf4j", module: "slf4j-reload4j"
//exclude group: "com.mysql", module: "mysql-connector-j"
if(PlatformDependencyVersions!=null && PlatformDependencyVersions.size()>0) {
@ -751,6 +752,37 @@ subprojects {
excludeDirs += file('dist')
}
}
task classpath() {}
tasks.classpath.doFirst {
if(isFrontendProject(file('.'))){
println '开始执行 classpath ......'
}
}
tasks.classpath.doLast {
List<String> jars =new ArrayList<>();
def doc =new XmlParser().parse(file(project.name + '.iml').absolutePath);
doc.component.each { component ->
if(component.@name=='NewModuleRootManager'){
component.orderEntry.each { entry ->
if(entry.@type=='module-library'){
entry.library.CLASSES.root.each { jar ->
String url =jar.@url;
url =url.substring(0,url.length()-2);
url =url.substring(url.lastIndexOf('/')+1);
jars.add(url);
}
}
}
}
}
Collections.sort(jars);
println project.name + ' dependencies jars : {'
jars.each {
println ' ' + it;
}
println '}';
}
}
/***********************************************************************
@ -902,6 +934,16 @@ cleanIdea {
dependsOn cleanIdeaWorkspace
}
/*-----------------------------------------------------------------
* IDEA
*----------------------------------------------------------------*/
task cleanIdeaSettings(){}
tasks.cleanIdeaSettings.doFirst {
delete System.getProperty("user.home") + "/Library/Application Support/JetBrains"
delete System.getProperty("user.home") + "/Library/Logs/JetBrains"
delete System.getProperty("user.home") + "/Library/Caches/JetBrains"
}
task github {
println ''
}

5
erm.frontend/package.json

@ -87,6 +87,7 @@
"@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4",
@ -100,7 +101,7 @@
"@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0",
"axios": "1.7.9",
"axios": "1.8.2",
"codemirror": "6.0.1",
"dayjs": "1.11.13",
"echarts": "5.6.0",
@ -111,7 +112,7 @@
"node-sql-parser": "5.3.6",
"pinia": "2.3.0",
"pinia-undo": "0.2.4",
"platform-core": "8.2.40",
"platform-core": "8.2.48",
"quasar": "2.17.6",
"sort-array": "5.0.0",
"svg-path-commander": "2.1.7",

2
erm.frontend/src/boostrap.ts

@ -15,6 +15,8 @@ import App from './App.vue';
import 'platform-core/dist/css/platform-core.css';
// 导入 tailwind utilities css
import 'tailwindcss/utilities.css';
// 导入 quasar-ui-qmarkdown css
import '@quasar/quasar-ui-qmarkdown/dist/index.css';
// 设置远程组件加载器
// 覆盖 platform-core 包中的 remoteComponentLoader 函数

8
erm.frontend/webpack.config.common.cjs

@ -22,7 +22,7 @@ module.exports = {
// 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录
path: path.resolve(__dirname, `dist/public/${projectName}`),
// 输出文件名
filename: `javascript/[name].[contenthash:5].js`,
filename: `javascript/[name].[contenthash:6].js`,
// 指定发布路径,使用 auto 可具有更多灵活性
publicPath: 'auto',
// 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果
@ -69,7 +69,7 @@ module.exports = {
test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: `fonts/[name].[contenthash:5].[ext]`,
filename: `fonts/[name].[contenthash:6].[ext]`,
},
},
@ -122,8 +122,8 @@ module.exports = {
// css 抽取插件
new MiniCssExtractPlugin({
filename: `css/[name].[contenthash:5].css`,
chunkFilename: `css/[name].[contenthash:5].css`,
filename: `css/[name].[contenthash:6].css`,
chunkFilename: `css/[name].[contenthash:6].css`,
}),
// 自动生成静态 index.html 文件

43
erm.frontend/webpack.config.mf.cjs

@ -2,18 +2,18 @@
* webpack module federation 配置
*/
const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5
const Json5 = require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称
const projectName = packageJson.name; // 项目名称
const deps = packageJson.dependencies; // 项目依赖
// 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值
const data = fs.readFileSync('./src/routes/routes.json', 'utf8');
const routes =Json5.parse(data);
const mfExposes ={};
for(const route of routes){
mfExposes[route.component]= route.componentPath;
const routes = Json5.parse(data);
const mfExposes = {};
for (const route of routes) {
mfExposes[route.component] = route.componentPath;
}
// 导出 webapck 配置的模块联邦部分
@ -57,24 +57,25 @@ module.exports = {
'@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true },
'@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true },
'@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true },
'axios': { requiredVersion: deps['axios'], singleton: true },
'codemirror': { requiredVersion: deps['codemirror'], singleton: true },
'dayjs': { requiredVersion: deps['dayjs'], singleton: true },
'echarts':{ requiredVersion: deps['echarts'], singleton: true },
'exceljs':{ requiredVersion: deps['exceljs'], singleton: true },
'file-saver':{ requiredVersion: deps['file-saver'], singleton: true },
'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true },
'mockjs': { requiredVersion: deps['mockjs'], singleton: true },
'pinia': { requiredVersion: deps['pinia'], singleton: true },
axios: { requiredVersion: deps['axios'], singleton: true },
codemirror: { requiredVersion: deps['codemirror'], singleton: true },
dayjs: { requiredVersion: deps['dayjs'], singleton: true },
echarts: { requiredVersion: deps['echarts'], singleton: true },
exceljs: { requiredVersion: deps['exceljs'], singleton: true },
'file-saver': { requiredVersion: deps['file-saver'], singleton: true },
luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true },
mockjs: { requiredVersion: deps['mockjs'], singleton: true },
pinia: { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true },
quasar: { requiredVersion: deps['quasar'], singleton: true },
'@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true },
'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
vue: { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }
}
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true },
},
}),
]
],
};

42
erm.frontend/webpack.env.build.cjs

@ -22,76 +22,76 @@ module.exports = merge(common, mf, {
splitChunks: {
cacheGroups: {
'shared': {
shared: {
name: 'vue',
test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vue': {
vue: {
name: 'vue',
test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'codemirror':{
codemirror: {
name: 'codemirror',
test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'quasar': {
quasar: {
name: 'quasar',
test: /[\\/]node_modules[\\/](quasar)[\\/]/,
test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'platform-core': {
name: 'platform-core',
test: /[\\/]node_modules[\\/]platform-core[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'echarts': {
echarts: {
name: 'echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'maxgraph': {
maxgraph: {
name: 'maxgraph',
test: /[\\/]node_modules[\\/]@maxgraph[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'@univerjs': {
name: '@univerjs',
test: /[\\/]node_modules[\\/]@univerjs[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'view': {
view: {
name: 'view',
test: /[\\/]view[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vendors': {
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true
enforce: true,
},
},
},
}
}
},
});

13
gradle.properties

@ -39,17 +39,20 @@ application_version=1.0.0
platform_group=io.sc
platform_version=8.2.10
platform_plugin_version=8.2.10
platform_core_frontend_version=8.2.40
platform_core_frontend_version=8.2.48
###########################################################
# dependencies version
###########################################################
ai4j_version=1.2.0
asciidoctor_version=3.3.2
asm_version=9.7.1
checker_version=3.43.0
commons_compress_version=1.25.0
commons_fileupload_version=1.4
commons_io_version=2.16.1
commons_text_version=1.12.0
curvesapi_version=1.08
cxf_version=3.2.7
dm_hibernate_version=8.1.2.192
enjoy_version=5.2.2
@ -64,18 +67,24 @@ jboss_logging_version=3.3.2.Final
jcommander_version=1.82
jdbc_dm_version=8.1.2.192
jdbc_mysql_version=5.1.49
jdbc_oracle_version=19.23.0.0
jib_version=3.3.2
jjwt_version=0.9.1
jxls_jexcel_version=1.0.7
jxls_poi_version=1.0.15
jxls_version=2.4.6
mybatis_version=2.3.2
kotlin_stdlib_version=1.9.25
mybatis_version=3.5.14
mybatis_spring_boot_starter_version=2.3.2
nimbusds_version=9.22
ollama4j_version=1.0.78
okhttp_version=4.12.0
opencsv_version=5.7.1
oshi_version=6.6.1
p6spy_version=3.9.1
pinyin4j_version=2.5.1
poi_version=5.2.5
reflections_version=0.10.2
schemacrawler_version=16.19.11
shadow_gradle_plugin_version=8.3.1
spring_boot_version=2.7.18

5
io.sc.engine.mv.frontend/package.json

@ -87,6 +87,7 @@
"@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4",
@ -100,7 +101,7 @@
"@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0",
"axios": "1.7.9",
"axios": "1.8.2",
"codemirror": "6.0.1",
"dayjs": "1.11.13",
"echarts": "5.6.0",
@ -111,7 +112,7 @@
"node-sql-parser": "5.3.6",
"pinia": "2.3.0",
"pinia-undo": "0.2.4",
"platform-core": "8.2.40",
"platform-core": "8.2.48",
"quasar": "2.17.6",
"sort-array": "5.0.0",
"svg-path-commander": "2.1.7",

2
io.sc.engine.mv.frontend/src/boostrap.ts

@ -15,6 +15,8 @@ import App from './App.vue';
import 'platform-core/dist/css/platform-core.css';
// 导入 tailwind utilities css
import 'tailwindcss/utilities.css';
// 导入 quasar-ui-qmarkdown css
import '@quasar/quasar-ui-qmarkdown/dist/index.css';
// 设置远程组件加载器
// 覆盖 platform-core 包中的 remoteComponentLoader 函数

1
io.sc.engine.mv.frontend/src/views/result/Result.vue

@ -13,6 +13,7 @@
:title="$t('menu.engine.mv.result')"
:config-button="true"
dense-header
db-click-operation="detail"
selection="multiple"
:checkbox-selection="false"
:data-url="Environment.apiContextPath('/api/mv/viewer/result')"

28
io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue

@ -121,20 +121,20 @@
:pageable="false"
:toolbar-actions="['refresh', 'separator', 'export']"
:columns="[
{ width: 30, name: 'level', label: $t('io.sc.engine.mv.result.binomial.level'), align: 'right' },
{ width: 30, name: 'pd', label: $t('io.sc.engine.mv.result.binomial.pd'), align: 'right' },
{ width: 30, name: 'count', label: $t('io.sc.engine.mv.result.binomial.count'), align: 'right' },
{ width: 50, name: 'defaultCount', label: $t('io.sc.engine.mv.result.binomial.defaultCount'), align: 'right' },
{ width: 50, name: 'ndAvg', label: $t('io.sc.engine.mv.result.binomial.ndAvg'), align: 'right', hidden: true },
{ width: 50, name: 'ndSd', label: $t('io.sc.engine.mv.result.binomial.ndSd'), align: 'right', hidden: true },
{ width: 50, name: 'sl', label: $t('io.sc.engine.mv.result.binomial.sl'), align: 'right', hidden: true },
{ width: 50, name: 'cl', label: $t('io.sc.engine.mv.result.binomial.cl'), align: 'right', hidden: true },
{ width: 50, name: 'zUpper', label: $t('io.sc.engine.mv.result.binomial.zUpper'), align: 'right', hidden: true },
{ width: 50, name: 'zLower', label: $t('io.sc.engine.mv.result.binomial.zLower'), align: 'right', hidden: true },
{ width: 50, name: 'dUpper', label: $t('io.sc.engine.mv.result.binomial.dUpper'), align: 'right', hidden: true },
{ width: 50, name: 'dLower', label: $t('io.sc.engine.mv.result.binomial.dLower'), align: 'right', hidden: true },
{ width: 50, name: 'leUpper', label: $t('io.sc.engine.mv.result.binomial.leUpper'), align: 'center', format: passOrNotFormater },
{ width: 50, name: 'geLower', label: $t('io.sc.engine.mv.result.binomial.geLower'), align: 'center', format: passOrNotFormater },
{ width: 90, name: 'level', label: $t('io.sc.engine.mv.result.binomial.level'), align: 'right' },
{ width: 90, name: 'pd', label: $t('io.sc.engine.mv.result.binomial.pd'), align: 'right' },
{ width: 140, name: 'count', label: $t('io.sc.engine.mv.result.binomial.count'), align: 'right', format: Formater.thousands() },
{ width: 140, name: 'defaultCount', label: $t('io.sc.engine.mv.result.binomial.defaultCount'), align: 'right' },
{ width: 120, name: 'ndAvg', label: $t('io.sc.engine.mv.result.binomial.ndAvg'), align: 'right', hidden: true },
{ width: 120, name: 'ndSd', label: $t('io.sc.engine.mv.result.binomial.ndSd'), align: 'right', hidden: true },
{ width: 90, name: 'sl', label: $t('io.sc.engine.mv.result.binomial.sl'), align: 'right', hidden: true },
{ width: 90, name: 'cl', label: $t('io.sc.engine.mv.result.binomial.cl'), align: 'right', hidden: true },
{ width: 130, name: 'zUpper', label: $t('io.sc.engine.mv.result.binomial.zUpper'), align: 'right', hidden: true },
{ width: 130, name: 'zLower', label: $t('io.sc.engine.mv.result.binomial.zLower'), align: 'right', hidden: true },
{ width: 100, name: 'dUpper', label: $t('io.sc.engine.mv.result.binomial.dUpper'), align: 'right', hidden: true },
{ width: 100, name: 'dLower', label: $t('io.sc.engine.mv.result.binomial.dLower'), align: 'right', hidden: true },
{ width: 220, name: 'leUpper', label: $t('io.sc.engine.mv.result.binomial.leUpper'), align: 'center', format: passOrNotFormater },
{ width: 220, name: 'geLower', label: $t('io.sc.engine.mv.result.binomial.geLower'), align: 'center', format: passOrNotFormater },
]"
></w-grid>
</div>

10
io.sc.engine.mv.frontend/src/views/sample/Sample.vue

@ -51,10 +51,10 @@
'export',
]"
:columns="[
{ width: 100, name: 'customId', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customId') },
{ width: 100, name: 'customName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customName') },
{ width: 140, name: 'customId', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customId') },
{ width: 150, name: 'customName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customName') },
{ width: 120, name: 'modelId', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.modelId') },
{ width: 150, name: 'modelName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.modelName') },
{ width: 140, name: 'modelName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.modelName') },
{ width: 90, name: 'pd', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.pd'), align: 'right' },
{ width: 90, name: 'score', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.score'), align: 'right' },
{ width: 90, name: 'scoreQuantitative', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.scoreQuantitative'), align: 'right' },
@ -95,8 +95,8 @@
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['refresh', 'separator', 'view', 'separator', 'export']"
:columns="[
{ width: 100, name: 'customId', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.customId') },
{ width: 100, name: 'defaultConfirmDate', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.defaultConfirmDate') },
{ width: 200, name: 'customId', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.customId') },
{ width: '100%', name: 'defaultConfirmDate', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.defaultConfirmDate') },
]"
:viewer="{
panel: {

8
io.sc.engine.mv.frontend/webpack.config.common.cjs

@ -22,7 +22,7 @@ module.exports = {
// 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录
path: path.resolve(__dirname, `dist/public/${projectName}`),
// 输出文件名
filename: `javascript/[name].[contenthash:5].js`,
filename: `javascript/[name].[contenthash:6].js`,
// 指定发布路径,使用 auto 可具有更多灵活性
publicPath: 'auto',
// 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果
@ -69,7 +69,7 @@ module.exports = {
test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: `fonts/[name].[contenthash:5].[ext]`,
filename: `fonts/[name].[contenthash:6].[ext]`,
},
},
@ -122,8 +122,8 @@ module.exports = {
// css 抽取插件
new MiniCssExtractPlugin({
filename: `css/[name].[contenthash:5].css`,
chunkFilename: `css/[name].[contenthash:5].css`,
filename: `css/[name].[contenthash:6].css`,
chunkFilename: `css/[name].[contenthash:6].css`,
}),
// 自动生成静态 index.html 文件

43
io.sc.engine.mv.frontend/webpack.config.mf.cjs

@ -2,18 +2,18 @@
* webpack module federation 配置
*/
const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5
const Json5 = require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称
const projectName = packageJson.name; // 项目名称
const deps = packageJson.dependencies; // 项目依赖
// 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值
const data = fs.readFileSync('./src/routes/routes.json', 'utf8');
const routes =Json5.parse(data);
const mfExposes ={};
for(const route of routes){
mfExposes[route.component]= route.componentPath;
const routes = Json5.parse(data);
const mfExposes = {};
for (const route of routes) {
mfExposes[route.component] = route.componentPath;
}
// 导出 webapck 配置的模块联邦部分
@ -57,24 +57,25 @@ module.exports = {
'@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true },
'@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true },
'@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true },
'axios': { requiredVersion: deps['axios'], singleton: true },
'codemirror': { requiredVersion: deps['codemirror'], singleton: true },
'dayjs': { requiredVersion: deps['dayjs'], singleton: true },
'echarts':{ requiredVersion: deps['echarts'], singleton: true },
'exceljs':{ requiredVersion: deps['exceljs'], singleton: true },
'file-saver':{ requiredVersion: deps['file-saver'], singleton: true },
'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true },
'mockjs': { requiredVersion: deps['mockjs'], singleton: true },
'pinia': { requiredVersion: deps['pinia'], singleton: true },
axios: { requiredVersion: deps['axios'], singleton: true },
codemirror: { requiredVersion: deps['codemirror'], singleton: true },
dayjs: { requiredVersion: deps['dayjs'], singleton: true },
echarts: { requiredVersion: deps['echarts'], singleton: true },
exceljs: { requiredVersion: deps['exceljs'], singleton: true },
'file-saver': { requiredVersion: deps['file-saver'], singleton: true },
luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true },
mockjs: { requiredVersion: deps['mockjs'], singleton: true },
pinia: { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true },
quasar: { requiredVersion: deps['quasar'], singleton: true },
'@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true },
'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
vue: { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }
}
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true },
},
}),
]
],
};

42
io.sc.engine.mv.frontend/webpack.env.build.cjs

@ -22,76 +22,76 @@ module.exports = merge(common, mf, {
splitChunks: {
cacheGroups: {
'shared': {
shared: {
name: 'vue',
test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vue': {
vue: {
name: 'vue',
test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'codemirror':{
codemirror: {
name: 'codemirror',
test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'quasar': {
quasar: {
name: 'quasar',
test: /[\\/]node_modules[\\/](quasar)[\\/]/,
test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'platform-core': {
name: 'platform-core',
test: /[\\/]node_modules[\\/]platform-core[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'echarts': {
echarts: {
name: 'echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'maxgraph': {
maxgraph: {
name: 'maxgraph',
test: /[\\/]node_modules[\\/]@maxgraph[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'@univerjs': {
name: '@univerjs',
test: /[\\/]node_modules[\\/]@univerjs[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'view': {
view: {
name: 'view',
test: /[\\/]view[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vendors': {
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true
enforce: true,
},
},
},
}
}
},
});

34
io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeBinomialHistoryWebController.java

@ -6,9 +6,12 @@ import io.sc.engine.mv.viewer.jpa.entity.id.CoeBinomialHistoryId;
import io.sc.engine.mv.viewer.jpa.repository.CoeBinomialHistoryRepository;
import io.sc.engine.mv.viewer.service.CoeBinomialHistoryService;
import io.sc.engine.mv.viewer.vo.CoeBinomialHistoryVo;
import io.sc.engine.mv.viewer.vo.CoeChiSquareHistoryVo;
import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.orm.service.support.CriteriaBuilder;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.QueryResult;
import io.sc.platform.util.support.NumberStringComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
@ -18,6 +21,10 @@ import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@RestController("io.sc.engine.mv.viewer.controller.CoeBinomialHistoryWebController")
@RequestMapping("/api/mv/viewer/binomial")
@ -42,6 +49,31 @@ public class CoeBinomialHistoryWebController extends RestCrudController<CoeBinom
if(!queryParameter.existsSortBy()){
queryParameter.addSortBy("level");
}
return super.query(request,response,queryParameter);
Page<CoeBinomialHistoryVo> page =super.query(request,response,queryParameter);
String sortPropertyName =queryParameter.getFirstSort().getProperty();
if("level".equals(sortPropertyName)){
boolean isAscending =queryParameter.getFirstSort().isAscending();
return QueryResult.sort(page,new CoeBinomialHistoryVoComparator(isAscending));
}else{
return page;
}
}
private class CoeBinomialHistoryVoComparator implements Comparator<CoeBinomialHistoryVo> {
private NumberStringComparator numberStringComparator =new NumberStringComparator();
private boolean isAscending =true;
public CoeBinomialHistoryVoComparator(boolean isAscending){
this.isAscending =isAscending;
}
@Override
public int compare(CoeBinomialHistoryVo o1, CoeBinomialHistoryVo o2) {
if(isAscending) {
return numberStringComparator.compare(o1.getLevel(), o2.getLevel());
}else{
return numberStringComparator.compare(o2.getLevel(), o1.getLevel());
}
}
}
}

34
io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeChiSquareHistoryWebController.java

@ -9,6 +9,8 @@ import io.sc.engine.mv.viewer.vo.CoeChiSquareHistoryVo;
import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.orm.service.support.CriteriaBuilder;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.QueryResult;
import io.sc.platform.util.support.NumberStringComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
@ -18,6 +20,10 @@ import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@RestController("io.sc.engine.mv.viewer.controller.CoeChiSquareHistoryWebController")
@RequestMapping("/api/mv/viewer/chiSquare")
@ -42,6 +48,32 @@ public class CoeChiSquareHistoryWebController extends RestCrudController<CoeChiS
if(!queryParameter.existsSortBy()){
queryParameter.addSortBy("level");
}
return super.query(request,response,queryParameter);
Page<CoeChiSquareHistoryVo> page =super.query(request,response,queryParameter);
String sortPropertyName =queryParameter.getFirstSort().getProperty();
if("level".equals(sortPropertyName)){
boolean isAscending =queryParameter.getFirstSort().isAscending();
return QueryResult.sort(page,new CoeChiSquareHistoryVoComparator(isAscending));
}else{
return page;
}
}
private class CoeChiSquareHistoryVoComparator implements Comparator<CoeChiSquareHistoryVo> {
private NumberStringComparator numberStringComparator =new NumberStringComparator();
private boolean isAscending =true;
public CoeChiSquareHistoryVoComparator(boolean isAscending){
this.isAscending =isAscending;
}
@Override
public int compare(CoeChiSquareHistoryVo o1, CoeChiSquareHistoryVo o2) {
if(isAscending) {
return numberStringComparator.compare(o1.getLevel(), o2.getLevel());
}else{
return numberStringComparator.compare(o2.getLevel(), o1.getLevel());
}
}
}
}

5
io.sc.engine.rule.frontend/package.json

@ -87,6 +87,7 @@
"@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4",
@ -100,7 +101,7 @@
"@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0",
"axios": "1.7.9",
"axios": "1.8.2",
"codemirror": "6.0.1",
"dayjs": "1.11.13",
"echarts": "5.6.0",
@ -111,7 +112,7 @@
"node-sql-parser": "5.3.6",
"pinia": "2.3.0",
"pinia-undo": "0.2.4",
"platform-core": "8.2.40",
"platform-core": "8.2.48",
"quasar": "2.17.6",
"sort-array": "5.0.0",
"svg-path-commander": "2.1.7",

2
io.sc.engine.rule.frontend/src/boostrap.ts

@ -15,6 +15,8 @@ import App from './App.vue';
import 'platform-core/dist/css/platform-core.css';
// 导入 tailwind utilities css
import 'tailwindcss/utilities.css';
// 导入 quasar-ui-qmarkdown css
import '@quasar/quasar-ui-qmarkdown/dist/index.css';
// 设置远程组件加载器
// 覆盖 platform-core 包中的 remoteComponentLoader 函数

8
io.sc.engine.rule.frontend/webpack.config.common.cjs

@ -22,7 +22,7 @@ module.exports = {
// 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录
path: path.resolve(__dirname, `dist/public/${projectName}`),
// 输出文件名
filename: `javascript/[name].[contenthash:5].js`,
filename: `javascript/[name].[contenthash:6].js`,
// 指定发布路径,使用 auto 可具有更多灵活性
publicPath: 'auto',
// 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果
@ -69,7 +69,7 @@ module.exports = {
test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: `fonts/[name].[contenthash:5].[ext]`,
filename: `fonts/[name].[contenthash:6].[ext]`,
},
},
@ -122,8 +122,8 @@ module.exports = {
// css 抽取插件
new MiniCssExtractPlugin({
filename: `css/[name].[contenthash:5].css`,
chunkFilename: `css/[name].[contenthash:5].css`,
filename: `css/[name].[contenthash:6].css`,
chunkFilename: `css/[name].[contenthash:6].css`,
}),
// 自动生成静态 index.html 文件

43
io.sc.engine.rule.frontend/webpack.config.mf.cjs

@ -2,18 +2,18 @@
* webpack module federation 配置
*/
const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5
const Json5 = require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称
const projectName = packageJson.name; // 项目名称
const deps = packageJson.dependencies; // 项目依赖
// 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值
const data = fs.readFileSync('./src/routes/routes.json', 'utf8');
const routes =Json5.parse(data);
const mfExposes ={};
for(const route of routes){
mfExposes[route.component]= route.componentPath;
const routes = Json5.parse(data);
const mfExposes = {};
for (const route of routes) {
mfExposes[route.component] = route.componentPath;
}
// 导出 webapck 配置的模块联邦部分
@ -57,24 +57,25 @@ module.exports = {
'@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true },
'@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true },
'@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true },
'axios': { requiredVersion: deps['axios'], singleton: true },
'codemirror': { requiredVersion: deps['codemirror'], singleton: true },
'dayjs': { requiredVersion: deps['dayjs'], singleton: true },
'echarts':{ requiredVersion: deps['echarts'], singleton: true },
'exceljs':{ requiredVersion: deps['exceljs'], singleton: true },
'file-saver':{ requiredVersion: deps['file-saver'], singleton: true },
'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true },
'mockjs': { requiredVersion: deps['mockjs'], singleton: true },
'pinia': { requiredVersion: deps['pinia'], singleton: true },
axios: { requiredVersion: deps['axios'], singleton: true },
codemirror: { requiredVersion: deps['codemirror'], singleton: true },
dayjs: { requiredVersion: deps['dayjs'], singleton: true },
echarts: { requiredVersion: deps['echarts'], singleton: true },
exceljs: { requiredVersion: deps['exceljs'], singleton: true },
'file-saver': { requiredVersion: deps['file-saver'], singleton: true },
luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true },
mockjs: { requiredVersion: deps['mockjs'], singleton: true },
pinia: { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true },
quasar: { requiredVersion: deps['quasar'], singleton: true },
'@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true },
'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
vue: { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }
}
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true },
},
}),
]
],
};

42
io.sc.engine.rule.frontend/webpack.env.build.cjs

@ -22,76 +22,76 @@ module.exports = merge(common, mf, {
splitChunks: {
cacheGroups: {
'shared': {
shared: {
name: 'vue',
test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vue': {
vue: {
name: 'vue',
test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'codemirror':{
codemirror: {
name: 'codemirror',
test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'quasar': {
quasar: {
name: 'quasar',
test: /[\\/]node_modules[\\/](quasar)[\\/]/,
test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'platform-core': {
name: 'platform-core',
test: /[\\/]node_modules[\\/]platform-core[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'echarts': {
echarts: {
name: 'echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'maxgraph': {
maxgraph: {
name: 'maxgraph',
test: /[\\/]node_modules[\\/]@maxgraph[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'@univerjs': {
name: '@univerjs',
test: /[\\/]node_modules[\\/]@univerjs[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'view': {
view: {
name: 'view',
test: /[\\/]view[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vendors': {
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true
enforce: true,
},
},
},
}
}
},
});

5
io.sc.engine.st.frontend/package.json

@ -87,6 +87,7 @@
"@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4",
@ -100,7 +101,7 @@
"@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0",
"axios": "1.7.9",
"axios": "1.8.2",
"codemirror": "6.0.1",
"dayjs": "1.11.13",
"echarts": "5.6.0",
@ -111,7 +112,7 @@
"node-sql-parser": "5.3.6",
"pinia": "2.3.0",
"pinia-undo": "0.2.4",
"platform-core": "8.2.40",
"platform-core": "8.2.48",
"quasar": "2.17.6",
"sort-array": "5.0.0",
"svg-path-commander": "2.1.7",

2
io.sc.engine.st.frontend/src/boostrap.ts

@ -15,6 +15,8 @@ import App from './App.vue';
import 'platform-core/dist/css/platform-core.css';
// 导入 tailwind utilities css
import 'tailwindcss/utilities.css';
// 导入 quasar-ui-qmarkdown css
import '@quasar/quasar-ui-qmarkdown/dist/index.css';
// 设置远程组件加载器
// 覆盖 platform-core 包中的 remoteComponentLoader 函数

2
io.sc.engine.st.frontend/src/views/DepFactor/DepFactor.vue

@ -49,7 +49,7 @@
{ width: 60, name: 'year', label: t('year'), align: 'right' },
{ width: 60, name: 'quarter', label: t('quarter'), align: 'right' },
{ width: 60, name: 'month', label: t('month'), align: 'right' },
{ width: 100, name: 'value', label: t('value') },
{ width: 100, name: 'value', label: t('value'), align: factorDefine.valueType === 'NUMERIC' ? 'right' : 'left' },
]"
:editor="{
dialog: {

6
io.sc.engine.st.frontend/src/views/DepFactor/DepFactorDefine.vue

@ -79,10 +79,10 @@
'export',
]"
:columns="[
{ width: 160, name: 'name', label: $t('name') },
{ width: '100%', name: 'name', label: $t('name') },
{ width: 150, name: 'code', label: $t('code') },
{
width: 100,
width: 120,
name: 'type',
label: $t('type'),
format: (value, row) => {
@ -93,7 +93,7 @@
},
},
{ width: 60, name: 'period', label: $t('period'), format: Formater.enum(Enums.Period) },
{ width: 70, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) },
{ width: 80, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) },
]"
:editor="{
dialog: {

2
io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactor.vue

@ -49,7 +49,7 @@
{ width: 60, name: 'year', label: t('year'), align: 'right' },
{ width: 60, name: 'quarter', label: t('quarter'), align: 'right' },
{ width: 60, name: 'month', label: t('month'), align: 'right' },
{ width: 100, name: 'value', label: t('value') },
{ width: 100, name: 'value', label: t('value'), align: factorDefine.valueType === 'NUMERIC' ? 'right' : 'left' },
]"
:editor="{
dialog: {

6
io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactorDefine.vue

@ -79,10 +79,10 @@
'export',
]"
:columns="[
{ width: 160, name: 'name', label: $t('name') },
{ width: '100%', name: 'name', label: $t('name') },
{ width: 150, name: 'code', label: $t('code') },
{
width: 100,
width: 120,
name: 'type',
label: $t('type'),
format: (value, row) => {
@ -93,7 +93,7 @@
},
},
{ width: 60, name: 'period', label: $t('period'), format: Formater.enum(Enums.Period) },
{ width: 70, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) },
{ width: 80, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) },
]"
:editor="{
dialog: {

6
io.sc.engine.st.frontend/src/views/Model/ModelAnalysisFactor.vue

@ -28,9 +28,9 @@
:toolbar-actions="['refresh']"
:columns="[
{ width: 120, name: 'variable', label: $t('engine.st.model.analysisFactor.grid.entity.variable') },
{ width: 100, name: 'coefficient', label: $t('engine.st.model.analysisFactor.grid.entity.coefficient') },
{ width: 120, name: 'coefficientSe', label: $t('engine.st.model.analysisFactor.grid.entity.coefficientSe') },
{ width: 120, name: 't', label: $t('engine.st.model.analysisFactor.grid.entity.t') },
{ width: 100, name: 'coefficient', label: $t('engine.st.model.analysisFactor.grid.entity.coefficient'), align: 'right' },
{ width: 120, name: 'coefficientSe', label: $t('engine.st.model.analysisFactor.grid.entity.coefficientSe'), align: 'right' },
{ width: 120, name: 't', label: $t('engine.st.model.analysisFactor.grid.entity.t'), align: 'right' },
]"
></w-grid>
</template>

6
io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactor.vue

@ -86,9 +86,9 @@
{ width: 60, name: 'year', label: t('year'), align: 'right' },
{ width: 60, name: 'quarter', label: t('quarter'), align: 'right' },
{ width: 60, name: 'month', label: t('month'), align: 'right' },
{ width: 80, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow') },
{ width: 80, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid') },
{ width: 80, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh') },
{ width: 80, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow'), align: 'right' },
{ width: 80, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid'), align: 'right' },
{ width: 80, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh'), align: 'right' },
]"
:editor="{
dialog: {

6
io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactorDefine.vue

@ -42,10 +42,10 @@
'export',
]"
:columns="[
{ width: 160, name: 'name', label: $t('name') },
{ width: '100%', name: 'name', label: $t('name') },
{ width: 150, name: 'code', label: $t('code') },
{
width: 100,
width: 120,
name: 'type',
label: $t('type'),
format: (value, row) => {
@ -56,7 +56,7 @@
},
},
{ width: 60, name: 'period', label: $t('period'), format: Formater.enum(Enums.Period) },
{ width: 70, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) },
{ width: 80, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) },
]"
:editor="{
dialog: {

6
io.sc.engine.st.frontend/src/views/TestCase/TestResult.vue

@ -15,9 +15,9 @@
{ width: 60, name: 'year', label: t('year'), align: 'right' },
{ width: 60, name: 'quarter', label: t('quarter'), align: 'right' },
{ width: 60, name: 'month', label: t('month'), align: 'right' },
{ width: 100, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow') },
{ width: 100, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid') },
{ width: 100, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh') },
{ width: 100, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow'), align: 'right' },
{ width: 100, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid'), align: 'right' },
{ width: 100, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh'), align: 'right' },
]"
:viewer="{
panel: {

8
io.sc.engine.st.frontend/webpack.config.common.cjs

@ -22,7 +22,7 @@ module.exports = {
// 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录
path: path.resolve(__dirname, `dist/public/${projectName}`),
// 输出文件名
filename: `javascript/[name].[contenthash:5].js`,
filename: `javascript/[name].[contenthash:6].js`,
// 指定发布路径,使用 auto 可具有更多灵活性
publicPath: 'auto',
// 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果
@ -69,7 +69,7 @@ module.exports = {
test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: `fonts/[name].[contenthash:5].[ext]`,
filename: `fonts/[name].[contenthash:6].[ext]`,
},
},
@ -122,8 +122,8 @@ module.exports = {
// css 抽取插件
new MiniCssExtractPlugin({
filename: `css/[name].[contenthash:5].css`,
chunkFilename: `css/[name].[contenthash:5].css`,
filename: `css/[name].[contenthash:6].css`,
chunkFilename: `css/[name].[contenthash:6].css`,
}),
// 自动生成静态 index.html 文件

43
io.sc.engine.st.frontend/webpack.config.mf.cjs

@ -2,18 +2,18 @@
* webpack module federation 配置
*/
const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5
const Json5 = require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称
const projectName = packageJson.name; // 项目名称
const deps = packageJson.dependencies; // 项目依赖
// 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值
const data = fs.readFileSync('./src/routes/routes.json', 'utf8');
const routes =Json5.parse(data);
const mfExposes ={};
for(const route of routes){
mfExposes[route.component]= route.componentPath;
const routes = Json5.parse(data);
const mfExposes = {};
for (const route of routes) {
mfExposes[route.component] = route.componentPath;
}
// 导出 webapck 配置的模块联邦部分
@ -57,24 +57,25 @@ module.exports = {
'@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true },
'@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true },
'@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true },
'axios': { requiredVersion: deps['axios'], singleton: true },
'codemirror': { requiredVersion: deps['codemirror'], singleton: true },
'dayjs': { requiredVersion: deps['dayjs'], singleton: true },
'echarts':{ requiredVersion: deps['echarts'], singleton: true },
'exceljs':{ requiredVersion: deps['exceljs'], singleton: true },
'file-saver':{ requiredVersion: deps['file-saver'], singleton: true },
'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true },
'mockjs': { requiredVersion: deps['mockjs'], singleton: true },
'pinia': { requiredVersion: deps['pinia'], singleton: true },
axios: { requiredVersion: deps['axios'], singleton: true },
codemirror: { requiredVersion: deps['codemirror'], singleton: true },
dayjs: { requiredVersion: deps['dayjs'], singleton: true },
echarts: { requiredVersion: deps['echarts'], singleton: true },
exceljs: { requiredVersion: deps['exceljs'], singleton: true },
'file-saver': { requiredVersion: deps['file-saver'], singleton: true },
luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true },
mockjs: { requiredVersion: deps['mockjs'], singleton: true },
pinia: { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true },
quasar: { requiredVersion: deps['quasar'], singleton: true },
'@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true },
'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
vue: { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }
}
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true },
},
}),
]
],
};

42
io.sc.engine.st.frontend/webpack.env.build.cjs

@ -22,76 +22,76 @@ module.exports = merge(common, mf, {
splitChunks: {
cacheGroups: {
'shared': {
shared: {
name: 'vue',
test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vue': {
vue: {
name: 'vue',
test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'codemirror':{
codemirror: {
name: 'codemirror',
test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'quasar': {
quasar: {
name: 'quasar',
test: /[\\/]node_modules[\\/](quasar)[\\/]/,
test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'platform-core': {
name: 'platform-core',
test: /[\\/]node_modules[\\/]platform-core[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'echarts': {
echarts: {
name: 'echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'maxgraph': {
maxgraph: {
name: 'maxgraph',
test: /[\\/]node_modules[\\/]@maxgraph[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'@univerjs': {
name: '@univerjs',
test: /[\\/]node_modules[\\/]@univerjs[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'view': {
view: {
name: 'view',
test: /[\\/]view[\\/]/,
priority: 20,
chunks: 'all',
enforce: true
enforce: true,
},
'vendors': {
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true
enforce: true,
},
},
},
}
}
},
});

8
io.sc.platform.ai/build.gradle

@ -0,0 +1,8 @@
dependencies {
api(
project(":io.sc.platform.system"),
project(":io.sc.platform.ai.frontend"),
//"io.github.lnyo-cly:ai4j-spring-boot-starter:${ai4j_version}",
"com.squareup.okhttp3:okhttp:${okhttp_version}"
)
}

0
io.sc.platform.ai/gradle.properties

4
io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/AnythingllmService.java

@ -0,0 +1,4 @@
package io.sc.platform.ai.anythingllm.service;
public interface AnythingllmService {
}

6
io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/impl/AnythingllmServiceImpl.java

@ -0,0 +1,6 @@
package io.sc.platform.ai.anythingllm.service.impl;
import io.sc.platform.ai.anythingllm.service.AnythingllmService;
public class AnythingllmServiceImpl implements AnythingllmService {
}

86
io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatApi.java

@ -0,0 +1,86 @@
package io.sc.platform.ai.anythingllm.service.support.workspaces;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.sc.platform.ai.ollama.MessageWrapper;
import io.sc.platform.ai.ollama.OllamaApi;
import io.sc.platform.ai.ollama.service.support.chat.ChatRequest;
import io.sc.platform.ai.ollama.service.support.chat.Message;
import io.sc.platform.util.CollectionUtil;
import io.sc.platform.util.ObjectMapperUtil;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.util.List;
public class StreamChatApi extends OllamaApi {
private static final Logger log = LoggerFactory.getLogger(StreamChatApi.class);
public StreamChatApi(String baseUrl){
super("/api/chat","POST");
this.baseUrl =baseUrl;
}
public ResponseBodyEmitter execute(MessageWrapper chatRequest) {
ChatRequest chatCompletion =createChatCompletion(chatRequest);
if(chatCompletion==null) { return null; }
Call call =createRequestCall(chatCompletion);
if(call==null) { return null; }
ResponseBodyEmitter emitter =new ResponseBodyEmitter();
call.enqueue(new StreamChatCallback(emitter));
return emitter;
}
private ChatRequest createChatCompletion(MessageWrapper chatRequest) {
if(chatRequest==null) { return null; }
String model =chatRequest.getModel();
if(!StringUtils.hasText(model)) { return null; }
List<String> questions =chatRequest.getQuestions();
if(!CollectionUtil.hasElements(questions)){ return null; }
ChatRequest chatCompletion =new ChatRequest();
chatCompletion.setModel(model);
chatCompletion.addMessage(new Message("user", "使用中文回答"));
for(String question : questions){
chatCompletion.addMessage(new Message("user",question));
}
return chatCompletion;
}
private Call createRequestCall(ChatRequest chatCompletion) {
if(chatCompletion==null) { return null; }
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(this.connectTimeout)
.readTimeout(this.readTimeout)
.writeTimeout(this.writeTimeout)
.build();
Headers headers = new Headers.Builder()
.set("Content-Type", "application/json")
.set("Accept", "text/event-stream")
.build();
String json ="";
try {
json = ObjectMapperUtil.json().writeValueAsString(chatCompletion);
} catch (JsonProcessingException e){
log.error("",e);
return null;
}
RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
okhttp3.Request request = new okhttp3.Request.Builder()
.url(this.baseUrl + this.url)
.headers(headers)
.post(body)
.build();
Call call = client.newCall(request);
return call;
}
}

45
io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatCallback.java

@ -0,0 +1,45 @@
package io.sc.platform.ai.anythingllm.service.support.workspaces;
import io.sc.platform.ai.ollama.service.support.chat.ChatResponse;
import io.sc.platform.util.ObjectMapperUtil;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSource;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.io.IOException;
public class StreamChatCallback implements Callback {
private ResponseBodyEmitter emitter;
public StreamChatCallback(ResponseBodyEmitter emitter){
this.emitter =emitter;
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
emitter.completeWithError(e);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if(response.isSuccessful()) {
try (ResponseBody body = response.body()) {
BufferedSource bufferedSource = body.source();
while (!bufferedSource.exhausted()) {
String line = bufferedSource.readUtf8Line();
ChatResponse responseObject =ObjectMapperUtil.json().readValue(line, ChatResponse.class);
emitter.send(responseObject.getMessage().getContent());
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
} else {
emitter.completeWithError(new RuntimeException(response.message()));
}
}
}

25
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/MessageWrapper.java

@ -0,0 +1,25 @@
package io.sc.platform.ai.ollama;
import java.util.ArrayList;
import java.util.List;
public class MessageWrapper {
private String model;
private List<String> questions =new ArrayList<>();
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public List<String> getQuestions() {
return questions;
}
public void setQuestions(List<String> questions) {
this.questions = questions;
}
}

66
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/OllamaApi.java

@ -0,0 +1,66 @@
package io.sc.platform.ai.ollama;
import java.time.Duration;
public class OllamaApi {
protected String baseUrl ="http://localhost:11434";
protected String url;
protected String method;
protected Duration connectTimeout =Duration.ofMinutes(2);
protected Duration readTimeout =Duration.ofMinutes(2);
protected Duration writeTimeout =Duration.ofMinutes(2);
public OllamaApi(){}
public OllamaApi(String url,String method){
this.url =url;
this.method =method;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Duration getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Duration getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
public Duration getWriteTimeout() {
return writeTimeout;
}
public void setWriteTimeout(Duration writeTimeout) {
this.writeTimeout = writeTimeout;
}
}

31
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/controller/OllamaWebController.java

@ -0,0 +1,31 @@
package io.sc.platform.ai.ollama.controller;
import io.sc.platform.ai.ollama.MessageWrapper;
import io.sc.platform.ai.ollama.service.OllamaService;
import io.sc.platform.ai.ollama.service.support.tags.TagsResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.util.List;
@RestController("io.sc.platform.ai.ollama.controller.OllamaWebController")
@RequestMapping("/api/ai/ollama")
public class OllamaWebController {
@Autowired private OllamaService ollamaService;
@PostMapping("/chat")
public ResponseBodyEmitter chat(@RequestBody MessageWrapper wrapper){
return ollamaService.chat(wrapper);
}
@GetMapping("/tags")
public TagsResponse tags(){
return ollamaService.tags();
}
@GetMapping("/modelNames")
public List<String> modelNames(){
return ollamaService.modelNames();
}
}

13
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/OllamaService.java

@ -0,0 +1,13 @@
package io.sc.platform.ai.ollama.service;
import io.sc.platform.ai.ollama.MessageWrapper;
import io.sc.platform.ai.ollama.service.support.tags.TagsResponse;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.util.List;
public interface OllamaService {
public ResponseBodyEmitter chat(MessageWrapper wrapper);
public TagsResponse tags();
public List<String> modelNames();
}

69
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/impl/OllamaServiceImpl.java

@ -0,0 +1,69 @@
package io.sc.platform.ai.ollama.service.impl;
import io.sc.platform.ai.ollama.MessageWrapper;
import io.sc.platform.ai.ollama.service.OllamaService;
import io.sc.platform.ai.ollama.service.support.chat.ChatApi;
import io.sc.platform.ai.ollama.service.support.tags.Model;
import io.sc.platform.ai.ollama.service.support.tags.TagsApi;
import io.sc.platform.ai.ollama.service.support.tags.TagsResponse;
import io.sc.platform.mvc.service.SystemParameterService;
import io.sc.platform.util.CollectionUtil;
import io.sc.platform.util.StringUtil;
import io.sc.platform.util.support.NumberStringComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Service("io.sc.platform.ai.service.impl.OllamaServiceImpl")
public class OllamaServiceImpl implements OllamaService {
private static final String KEY_API_URL ="parameter.ai.provider.ollama.apiUrl";
private static final String KEY_DEFAULT_MODEL_NAME ="parameter.ai.provider.ollama.defaultModelName";
@Autowired private SystemParameterService systemParameterService;
@Override
public ResponseBodyEmitter chat(MessageWrapper wrapper) {
Map<String,String> parameters =getParameters();
if(!StringUtil.hasText(wrapper.getModel())){
wrapper.setModel(parameters.get(KEY_DEFAULT_MODEL_NAME));
}
ChatApi api =new ChatApi(parameters.get(KEY_API_URL));
return api.execute(wrapper);
}
@Override
public TagsResponse tags() {
Map<String,String> parameters =getParameters();
TagsApi api =new TagsApi(parameters.get(KEY_API_URL));
return api.execute();
}
@Override
public List<String> modelNames() {
Map<String,String> parameters =getParameters();
TagsApi api =new TagsApi(parameters.get(KEY_API_URL));
TagsResponse response =api.execute();
if(response==null){
return Collections.emptyList();
}
List<Model> models =response.getModels();
if(!CollectionUtil.hasElements(models)){
return Collections.emptyList();
}
List<String> result =new ArrayList<>();
for(Model model : models){
result.add(model.getModel());
}
Collections.sort(result, new NumberStringComparator());
return result;
}
private Map<String,String> getParameters(){
return systemParameterService.getParameters(new String[]{KEY_API_URL,KEY_DEFAULT_MODEL_NAME});
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/blobs/BlobsApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.blobs;
import io.sc.platform.ai.ollama.OllamaApi;
public class BlobsApi extends OllamaApi {
public BlobsApi(){
super("/api/blobs/","HEAD");
}
}

84
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatApi.java

@ -0,0 +1,84 @@
package io.sc.platform.ai.ollama.service.support.chat;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.sc.platform.ai.ollama.MessageWrapper;
import io.sc.platform.ai.ollama.OllamaApi;
import io.sc.platform.util.CollectionUtil;
import io.sc.platform.util.ObjectMapperUtil;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.util.List;
public class ChatApi extends OllamaApi {
private static final Logger log = LoggerFactory.getLogger(ChatApi.class);
public ChatApi(String baseUrl){
super("/api/chat","POST");
this.baseUrl =baseUrl;
}
public ResponseBodyEmitter execute(MessageWrapper wrapper) {
ChatRequest chatRequest =createChatRequest(wrapper);
if(chatRequest==null) { return null; }
Call call =createRequestCall(chatRequest);
if(call==null) { return null; }
ResponseBodyEmitter emitter =new ResponseBodyEmitter();
call.enqueue(new ChatCallback(emitter));
return emitter;
}
private ChatRequest createChatRequest(MessageWrapper wrapper) {
if(wrapper==null) { return null; }
String model =wrapper.getModel();
if(!StringUtils.hasText(model)) { return null; }
List<String> questions =wrapper.getQuestions();
if(!CollectionUtil.hasElements(questions)){ return null; }
ChatRequest request =new ChatRequest();
request.setModel(model);
request.addMessage(new Message("user", "使用中文回答"));
for(String question : questions){
request.addMessage(new Message("user",question));
}
return request;
}
private Call createRequestCall(ChatRequest chatRequest) {
if(chatRequest==null) { return null; }
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(this.connectTimeout)
.readTimeout(this.readTimeout)
.writeTimeout(this.writeTimeout)
.build();
Headers headers = new Headers.Builder()
.set("Content-Type", "application/json")
.set("Accept", "text/event-stream")
.build();
String json ="";
try {
json = ObjectMapperUtil.json().writeValueAsString(chatRequest);
} catch (JsonProcessingException e){
log.error("",e);
return null;
}
RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
okhttp3.Request request = new okhttp3.Request.Builder()
.url(this.baseUrl + this.url)
.headers(headers)
.post(body)
.build();
Call call = client.newCall(request);
return call;
}
}

44
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatCallback.java

@ -0,0 +1,44 @@
package io.sc.platform.ai.ollama.service.support.chat;
import io.sc.platform.util.ObjectMapperUtil;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSource;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.io.IOException;
public class ChatCallback implements Callback {
private ResponseBodyEmitter emitter;
public ChatCallback(ResponseBodyEmitter emitter){
this.emitter =emitter;
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
emitter.completeWithError(e);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if(response.isSuccessful()) {
try (ResponseBody body = response.body()) {
BufferedSource bufferedSource = body.source();
while (!bufferedSource.exhausted()) {
String line = bufferedSource.readUtf8Line();
ChatResponse chatResponse =ObjectMapperUtil.json().readValue(line, ChatResponse.class);
emitter.send(chatResponse.getMessage().getContent());
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
} else {
emitter.completeWithError(new RuntimeException(response.message()));
}
}
}

80
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatRequest.java

@ -0,0 +1,80 @@
package io.sc.platform.ai.ollama.service.support.chat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown=true)
public class ChatRequest {
private String model;
private List<Message> messages =new ArrayList<>();
private List<Tool> tools =new ArrayList<>();
private String format;
private Map<String,Object> options =new HashMap<>();
private boolean stream =true;
private long keepAlive =1000*60*5;
public void addMessage(Message message){
messages.add(message);
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public List<Message> getMessages() {
return messages;
}
public void setMessages(List<Message> messages) {
this.messages = messages;
}
public List<Tool> getTools() {
return tools;
}
public void setTools(List<Tool> tools) {
this.tools = tools;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public Map<String, Object> getOptions() {
return options;
}
public void setOptions(Map<String, Object> options) {
this.options = options;
}
public boolean getStream() {
return stream;
}
public void setStream(boolean stream) {
this.stream = stream;
}
public long getKeepAlive() {
return keepAlive;
}
public void setKeepAlive(long keepAlive) {
this.keepAlive = keepAlive;
}
}

117
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatResponse.java

@ -0,0 +1,117 @@
package io.sc.platform.ai.ollama.service.support.chat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown=true)
public class ChatResponse {
@JsonProperty("model")
private String model;
@JsonProperty("created_at")
private String createdAt;
@JsonProperty("message")
private Message message;
@JsonProperty("done")
private boolean done;
@JsonProperty("total_duration")
private long totalDuration;
@JsonProperty("load_duration")
private long loadDuration;
@JsonProperty("prompt_eval_count")
private long promptEvalCount;
@JsonProperty("prompt_eval_duration")
private long promptEvalDuration;
@JsonProperty("eval_count")
private long evalCount;
@JsonProperty("eval_duration")
private long evalDuration;
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
public long getTotalDuration() {
return totalDuration;
}
public void setTotalDuration(long totalDuration) {
this.totalDuration = totalDuration;
}
public long getLoadDuration() {
return loadDuration;
}
public void setLoadDuration(long loadDuration) {
this.loadDuration = loadDuration;
}
public long getPromptEvalCount() {
return promptEvalCount;
}
public void setPromptEvalCount(long promptEvalCount) {
this.promptEvalCount = promptEvalCount;
}
public long getPromptEvalDuration() {
return promptEvalDuration;
}
public void setPromptEvalDuration(long promptEvalDuration) {
this.promptEvalDuration = promptEvalDuration;
}
public long getEvalCount() {
return evalCount;
}
public void setEvalCount(long evalCount) {
this.evalCount = evalCount;
}
public long getEvalDuration() {
return evalDuration;
}
public void setEvalDuration(long evalDuration) {
this.evalDuration = evalDuration;
}
}

54
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Message.java

@ -0,0 +1,54 @@
package io.sc.platform.ai.ollama.service.support.chat;
import java.util.ArrayList;
import java.util.List;
public class Message {
public static final String SYSTEM ="system";
public static final String USER ="user";
public static final String ASSISTANT ="assistant";
public static final String TOOL ="tool";
private String role;
private String content;
private List<String> images =new ArrayList<>();
private List<Tool> toolCalls =new ArrayList<>();
public Message(){}
public Message(String role,String content){
this.role =role;
this.content =content;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
public List<Tool> getToolCalls() {
return toolCalls;
}
public void setToolCalls(List<Tool> toolCalls) {
this.toolCalls = toolCalls;
}
}

4
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Tool.java

@ -0,0 +1,4 @@
package io.sc.platform.ai.ollama.service.support.chat;
public class Tool {
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/copy/OllamaCopyApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.copy;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaCopyApi extends OllamaApi {
public OllamaCopyApi(){
super("/api/copy","POST");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/create/OllamaCreateApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.create;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaCreateApi extends OllamaApi {
public OllamaCreateApi(){
super("/api/create","POST");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/delete/OllamaDeleteApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.delete;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaDeleteApi extends OllamaApi {
public OllamaDeleteApi(){
super("/api/delete","DELETE");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embed/OllamaEmbedApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.embed;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaEmbedApi extends OllamaApi {
public OllamaEmbedApi(){
super("/api/embed","POST");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embeddings/OllamaEmbeddingsApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.embeddings;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaEmbeddingsApi extends OllamaApi {
public OllamaEmbeddingsApi(){
super("/api/embeddings","POST");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/generate/OllamaGenerateApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.generate;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaGenerateApi extends OllamaApi {
public OllamaGenerateApi(){
super("/api/generate","POST");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/ps/OllamaPsApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.ps;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaPsApi extends OllamaApi {
public OllamaPsApi(){
super("/api/ps","GET");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/pull/OllamaPullApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.pull;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaPullApi extends OllamaApi {
public OllamaPullApi(){
super("/api/pull","POST");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/push/OllamaPushApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.push;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaPushApi extends OllamaApi {
public OllamaPushApi(){
super("/api/push","POST");
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/show/OllamaShowApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.show;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaShowApi extends OllamaApi {
public OllamaShowApi(){
super("/api/show","POST");
}
}

71
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Details.java

@ -0,0 +1,71 @@
package io.sc.platform.ai.ollama.service.support.tags;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown=true)
public class Details {
@JsonProperty("parent_model")
private String parentModel;
private String format;
private String family;
private List<String> families;
@JsonProperty("parameter_size")
private String parameterSize;
@JsonProperty("quantization_level")
private String quantizationLevel;
public String getParentModel() {
return parentModel;
}
public void setParentModel(String parentModel) {
this.parentModel = parentModel;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public String getFamily() {
return family;
}
public void setFamily(String family) {
this.family = family;
}
public List<String> getFamilies() {
return families;
}
public void setFamilies(List<String> families) {
this.families = families;
}
public String getParameterSize() {
return parameterSize;
}
public void setParameterSize(String parameterSize) {
this.parameterSize = parameterSize;
}
public String getQuantizationLevel() {
return quantizationLevel;
}
public void setQuantizationLevel(String quantizationLevel) {
this.quantizationLevel = quantizationLevel;
}
}

65
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Model.java

@ -0,0 +1,65 @@
package io.sc.platform.ai.ollama.service.support.tags;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown=true)
public class Model {
private String name;
private String model;
@JsonProperty("modified_at")
private String modifiedAt;
private long size;
private String digest;
private Details details;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getModifiedAt() {
return modifiedAt;
}
public void setModifiedAt(String modifiedAt) {
this.modifiedAt = modifiedAt;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public String getDigest() {
return digest;
}
public void setDigest(String digest) {
this.digest = digest;
}
public Details getDetails() {
return details;
}
public void setDetails(Details details) {
this.details = details;
}
}

42
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsApi.java

@ -0,0 +1,42 @@
package io.sc.platform.ai.ollama.service.support.tags;
import io.sc.platform.ai.ollama.OllamaApi;
import io.sc.platform.util.ObjectMapperUtil;
import okhttp3.*;
import java.io.IOException;
public class TagsApi extends OllamaApi {
public TagsApi(String baseUrl){
super("/api/tags","GET");
this.baseUrl =baseUrl;
}
public TagsResponse execute() {
Call call =createRequestCall();
if(call==null) { return null; }
try {
Response response = call.execute();
ResponseBody body =response.body();
TagsResponse tagsResponse = ObjectMapperUtil.json().readValue(body.source().readUtf8(), TagsResponse.class);
return tagsResponse;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Call createRequestCall() {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(this.connectTimeout)
.readTimeout(this.readTimeout)
.writeTimeout(this.writeTimeout)
.build();
Request request = new Request.Builder()
.url(this.baseUrl + this.url)
.get()
.build();
Call call = client.newCall(request);
return call;
}
}

19
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsResponse.java

@ -0,0 +1,19 @@
package io.sc.platform.ai.ollama.service.support.tags;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.ArrayList;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown=true)
public class TagsResponse {
private List<Model> models =new ArrayList<>();
public List<Model> getModels() {
return models;
}
public void setModels(List<Model> models) {
this.models = models;
}
}

11
io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/version/OllamaVersionApi.java

@ -0,0 +1,11 @@
package io.sc.platform.ai.ollama.service.support.version;
import io.sc.platform.ai.ollama.OllamaApi;
public class OllamaVersionApi extends OllamaApi {
public OllamaVersionApi(){
super("/api/version","GET");
}
}

16
io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/components.json

@ -0,0 +1,16 @@
/*
*
* : , spring
* 使:
* includes:
* excludes:
* : includes excludes , excludes ,
*/
{
"includes":[
"io.sc.platform.ai.ollama.controller",
"io.sc.platform.ai.ollama.service.impl"
],
"excludes":[]
}

5
io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/messages.json

@ -0,0 +1,5 @@
{
"includes":[
"io/sc/platform/ai/i18n/parameters"
]
}

67
io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/parameters.json

@ -0,0 +1,67 @@
/*
*
* :
* 使:
* id:
* parentId: ,
* code: ,
* defaultValue:
* order:
*/
[
//AI
{"id":"parameter.ai","order":2000},
//AI /
{
"id" :"parameter.ai.chat.enable",
"parentId" :"parameter.ai",
"code" :"parameter.ai.chat.enable",
"defaultValue" :"true",
"order" : 100,
"options" : {
"true" : "parameter.ai.chat.enable.options.enable",
"false" : "parameter.ai.chat.enable.options.disable"
}
},
//AI /
{
"id" :"parameter.ai.provider.default",
"parentId" :"parameter.ai",
"code" :"parameter.ai.provider.default",
"defaultValue" :"ollama",
"order" : 200,
"options" : {
"ollama" : "parameter.ai.provider.default.options.ollama"
}
},
//AI /
{"id":"parameter.ai.provider", "parentId":"parameter.ai", "order":300},
//AI //Ollama
{"id":"parameter.ai.provider.ollama", "parentId":"parameter.ai.provider", "order":100},
//AI //Ollama/api url
{
"id" :"parameter.ai.provider.ollama.apiUrl",
"parentId" :"parameter.ai.provider.ollama",
"code" :"parameter.ai.provider.ollama.apiUrl",
"defaultValue" :"http://localhost:11434",
"order" : 100
},
//AI //Ollama/
{
"id" :"parameter.ai.provider.ollama.defaultModelName",
"parentId" :"parameter.ai.provider.ollama",
"code" :"parameter.ai.provider.ollama.defaultModelName",
"defaultValue" :"deepseek-r1:14b",
"order" : 200,
"options" : {
"deepseek-r1:1.5b" : "deepseek-r1:1.5b",
"deepseek-r1:7b" : "deepseek-r1:7b",
"deepseek-r1:8b" : "deepseek-r1:8b",
"deepseek-r1:14b" : "deepseek-r1:14b",
"deepseek-r1:32b" : "deepseek-r1:32b",
"deepseek-r1:70b" : "deepseek-r1:70b",
"deepseek-r1:671b" : "deepseek-r1:671b"
}
}
]

4
io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/security.json

@ -0,0 +1,4 @@
{
"permitPatterns":[
]
}

12
io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters.properties

@ -0,0 +1,12 @@
parameter.ai=AI
parameter.ai.chat.enable=AI Chat Enable
parameter.ai.chat.enable.options.enable=Enable
parameter.ai.chat.enable.options.disable=Disable
parameter.ai.provider.default=Model Provider (default)
parameter.ai.provider.default.options.ollama=Ollama
parameter.ai.provider=Model Providers
parameter.ai.provider.ollama=Ollama
parameter.ai.provider.ollama.apiUrl=Api URL
parameter.ai.provider.ollama.defaultModelName=Default Model Name

12
io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_tw_CN.properties

@ -0,0 +1,12 @@
parameter.ai=\u4EBA\u5DE5\u667A\u80FD
parameter.ai.chat.enable=\u662F\u5426\u958B\u555F\u667A\u80FD\u5C0D\u8A71
parameter.ai.chat.enable.options.enable=\u958B\u555F
parameter.ai.chat.enable.options.disable=\u95DC\u9589
parameter.ai.provider.default=\u9ED8\u8A8D\u6A21\u578B\u63D0\u4F9B\u5546
parameter.ai.provider.default.options.ollama=Ollama
parameter.ai.provider=\u6A21\u578B\u63D0\u4F9B\u5546
parameter.ai.provider.ollama=Ollama
parameter.ai.provider.ollama.apiUrl=Api URL
parameter.ai.provider.ollama.defaultModelName=\u9ED8\u8A8D\u6A21\u578B\u540D\u7A31

13
io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_zh_CN.properties

@ -0,0 +1,13 @@
parameter.ai=\u4EBA\u5DE5\u667A\u80FD
parameter.ai.chat.enable=\u662F\u5426\u5F00\u542F\u667A\u80FD\u5BF9\u8BDD
parameter.ai.chat.enable.options.enable=\u5F00\u542F
parameter.ai.chat.enable.options.disable=\u5173\u95ED
parameter.ai.provider.default=\u9ED8\u8BA4\u6A21\u578B\u63D0\u4F9B\u5546
parameter.ai.provider.default.options.ollama=Ollama
parameter.ai.provider=\u6A21\u578B\u63D0\u4F9B\u5546
parameter.ai.provider.ollama=Ollama
parameter.ai.provider.ollama.apiUrl=Api URL
parameter.ai.provider.ollama.defaultModelName=\u9ED8\u8BA4\u6A21\u578B\u540D\u79F0

1
io.sc.platform.app-nacos/build.gradle

@ -1,6 +1,5 @@
dependencies {
api(
project(":io.sc.platform.app"),
project(":io.sc.platform.springcloud.nacos"),
project(":io.sc.platform.springcloud.sentinel"),
)

5
io.sc.platform.core.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "platform-core",
"version": "8.2.40",
"version": "8.2.48",
"description": "前端核心包,用于快速构建前端的脚手架",
"//main": "库的主文件",
"main": "dist/platform-core.js",
@ -115,6 +115,7 @@
"@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4",
@ -128,7 +129,7 @@
"@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0",
"axios": "1.7.9",
"axios": "1.8.2",
"codemirror": "6.0.1",
"dayjs": "1.11.13",
"echarts": "5.6.0",

2
io.sc.platform.core.frontend/src/boostrap.ts

@ -15,6 +15,8 @@ import App from './App.vue';
//<C> import 'platform-core/dist/css/platform-core.css';
//<C> // 导入 tailwind utilities css
//<C> import 'tailwindcss/utilities.css';
//<C> // 导入 quasar-ui-qmarkdown css
//<C> import '@quasar/quasar-ui-qmarkdown/dist/index.css';
// 设置远程组件加载器
// 覆盖 platform-core 包中的 remoteComponentLoader 函数

2
io.sc.platform.core.frontend/src/components/index.ts

@ -11,6 +11,7 @@ import component_testcase_loading from '@/views/testcase/loading/loading.vue';
import component_testcase_excel from '@/views/testcase/excel/Excel.vue';
import component_testcase_word from '@/views/testcase/word/Word.vue';
import component_testcase_maxgraph from '@/views/testcase/maxgraph/Maxgraph.vue';
import component_testcase_ai from '@/views/testcase/ai/Ai.vue';
import component_testcase_likmDialog from '@/views/likm/Dialog.vue';
import component_testcase_likmDrawer from '@/views/likm/Drawer.vue';
import component_testcase_likmForm from '@/views/likm/Form.vue';
@ -31,6 +32,7 @@ const localComponents = {
'component.testcase.excel': component_testcase_excel,
'component.testcase.word': component_testcase_word,
'component.testcase.maxgraph': component_testcase_maxgraph,
'component.testcase.ai': component_testcase_ai,
'component.testcase.likmDialog': component_testcase_likmDialog,
'component.testcase.likmDrawer': component_testcase_likmDrawer,
'component.testcase.likmForm': component_testcase_likmForm,

1
io.sc.platform.core.frontend/src/i18n/messages.json

@ -10,6 +10,7 @@
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
"menu.testcase.maxgraph": "Graph Editor",
"menu.testcase.ai": "AI",
"route.testcase.noMenuRoute": "No Menu Route"
}

1
io.sc.platform.core.frontend/src/i18n/messages_tw_CN.json

@ -10,6 +10,7 @@
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
"menu.testcase.maxgraph": "图形编辑器",
"menu.testcase.ai": "AI",
"route.testcase.noMenuRoute": "無關聯菜單路由"
}

1
io.sc.platform.core.frontend/src/i18n/messages_zh_CN.json

@ -10,6 +10,7 @@
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
"menu.testcase.maxgraph": "图形编辑器",
"menu.testcase.ai": "AI",
"route.testcase.noMenuRoute": "无关联菜单路由"
}

9
io.sc.platform.core.frontend/src/menus/menus.json

@ -109,6 +109,15 @@
"icon": "bi-palette",
"routeName": "route.testcase.maxgraph"
},
{
"type": "ROUTE",
"order": 700,
"parentId": "menu.testcase",
"id": "menu.testcase.ai",
"titleI18nKey": "menu.testcase.ai",
"icon": "bi-palette",
"routeName": "route.testcase.ai"
},
{ "type": "GROUP", "order": 30000, "id": "menu.testcase.likm", "titleI18nKey": "测试用例-likm", "icon": "home" },
{

6
io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue

@ -14,6 +14,10 @@ const props = defineProps({
fixed: { type: Boolean, default: false },
});
const emit = defineEmits<{
(e: 'sizeChanged', height: object): void;
}>();
const gc = Environment.getConfigure();
const q = useQuasar();
const containerRef = ref<HTMLElement>();
@ -64,6 +68,7 @@ const changeDivHeight = () => {
}
containerHeightRef.value = height > 0 ? height : 0;
}
emit('sizeChanged', { width: containerRef.value.getBoundingClientRect().width, height: containerHeightRef.value });
} else if (props.expand === 'parent') {
const parentElement = containerRef.value.parentElement;
const availableHeight = Math.floor(parentElement.getBoundingClientRect().y) + Math.floor(parentElement.clientHeight);
@ -74,6 +79,7 @@ const changeDivHeight = () => {
let height = availableHeight - y;
containerHeightRef.value = height > 0 ? height : 0;
}
emit('sizeChanged', { width: containerRef.value.getBoundingClientRect().width, height: containerHeightRef.value });
}
}
};

2
io.sc.platform.core.frontend/src/platform/index.ts

@ -78,7 +78,7 @@ export { PConst } from './PConst';
/**
*
*/
export { axios, blobAxios, noErrorAxios } from './plugin';
export { axios, blobAxios, noErrorAxios, Fetch } from './plugin';
export { eventBus } from './plugin';
export { i18n, t, $t } from './plugin';
export { usePlatformStore } from './plugin';

8
io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue

@ -27,9 +27,9 @@
<!-- space -->
<q-space />
<!-- search action-->
<!-- <q-input v-if="quasar.screen.gt.sm" v-model="searchContent" dark dense standout style="width: 200px"> </q-input> -->
<q-btn v-if="gc.theme.topper.actions['searcher'].enable" stretch flat icon="bi-search" :title="t('search')" @click="search"> </q-btn>
<!-- ai chat action -->
<q-btn v-if="gc.theme.topper.actions['ai-chat'].enable" stretch flat icon="bi-chat-dots" :title="t('aiChat')" :to="{ name: 'route.ai.chatNoMenuRoute' }">
</q-btn>
<!-- fullscreen action -->
<q-btn
@ -44,7 +44,7 @@
</q-btn>
<!-- messages dropdown action-->
<q-btn v-if="gc.theme.topper.actions['notifier'].enable" stretch flat icon="bi-chat-dots" size="md" :title="t('alter')">
<q-btn v-if="gc.theme.topper.actions['notifier'].enable" stretch flat icon="bi-bell" size="md" :title="t('alter')">
<q-badge color="red" rounded floating class="mt-2 mr-1">120</q-badge>
<q-menu>
<q-list style="min-width: 100px">

35
io.sc.platform.core.frontend/src/platform/plugin/axios.ts

@ -4,7 +4,8 @@ import Axios from 'axios';
import { i18n } from './i18n';
import { Environment } from '@/platform/plugin/environment';
import { AuthenticationManager, SessionManager, ServerExceptionHandler } from './manager';
import { QuasarTools } from '@/platform/utils';
import { QuasarTools, Tools } from '@/platform/utils';
import { getHashes } from 'node:crypto';
const ignoredUrls: string[] = [PConst.API_I18N_MESSAGES_URL, PConst.API_APP_CONFIGURE_URL];
const gc = Environment.getConfigure();
@ -102,6 +103,36 @@ blobAxios.interceptors.response.use((response: any) => {
return response;
}, getResponseErrorInterceptor(true));
class Fetch {
public static buildHeaders() {
const gc = Environment.getConfigure();
// 监测会话是否过期
if (SessionManager.isTimeout()) {
AuthenticationManager.removeLocalAccessToken();
}
// 请求头
const headers = {
locale: gc.setting.i18n.locale,
'Content-Type': 'application/json; charset=UTF-8',
};
if (AuthenticationManager.getLocalAccessToken()) {
headers['Authorization'] = 'Bearer ' + AuthenticationManager.getLocalAccessToken() + '';
}
return headers;
}
public static isAuthorization(url: string) {
// 忽略无需认证的请求 URL
for (const ignoredUrl of ignoredUrls) {
if (ignoredUrl.includes(url)) {
return false;
}
}
return true;
}
}
export default {
install: (app: App) => {
app.config.globalProperties.$axios = axios;
@ -109,4 +140,4 @@ export default {
},
};
export { axios, blobAxios, noErrorAxios };
export { axios, blobAxios, noErrorAxios, Fetch };

2
io.sc.platform.core.frontend/src/platform/plugin/index.ts

@ -15,7 +15,7 @@ export default {
},
};
export { axios, blobAxios, noErrorAxios } from './axios';
export { axios, blobAxios, noErrorAxios, Fetch } from './axios';
export { eventBus } from './quasar';
export { i18n, t, $t } from './i18n';
export { usePlatformStore } from './pinia';

2
io.sc.platform.core.frontend/src/platform/plugin/quasar-components.ts

@ -123,3 +123,5 @@ export {
QVideo,
QVirtualScroll,
} from 'quasar';
export { QMarkdown } from '@quasar/quasar-ui-qmarkdown';

1
io.sc.platform.core.frontend/src/platform/plugin/quasar.ts

@ -9,6 +9,7 @@ const gc = Environment.getConfigure();
const eventBus: any = new EventBus();
import { Quasar } from 'quasar';
import qmarkdown from '@quasar/quasar-ui-qmarkdown';
import * as quasarComponents from './quasar-components';
import * as quasarDirectives from './quasar-directives';

15
io.sc.platform.core.frontend/src/routes/routes.json

@ -14,7 +14,7 @@
{
"force": true,
"name": "route.testcase.noMenuRoute",
"icon":'bi-1-circle',
"icon": "bi-1-circle",
"path": "testcase/noMenuRoute/:id",
"parent": "/",
"priority": 0,
@ -116,6 +116,19 @@
}
},
{
"name": "route.testcase.ai",
"path": "testcase/ai",
"parent": "/",
"priority": 0,
"component": "component.testcase.ai",
"componentPath": "@/views/testcase/ai/Ai.vue",
"redirect": null,
"meta": {
"permissions": ["/testcase/ai/**/*"]
}
},
{
"name": "route.testcase.likm.dialog",
"path": "testcase/likm/dialog",

25
io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue

@ -1,6 +1,14 @@
<template>
<div>
<q-btn label="ok" @click="click"></q-btn>
<w-v-expand-div @size-changed="sizeChanged">
<q-markdown> ### Title 100 </q-markdown>
<q-splitter
:model-value="80"
horizontal
:style="{
height: splitterHeightRef + 'px',
}"
>
<template #before>
<w-code-mirror
v-model="modelValue"
lang="java"
@ -12,7 +20,13 @@
:auto-completion="autoCompletionManager.autoCompletion()"
:user-defined-functions="userDefinedFunctionsManager.userDefinedFunctions().value"
></w-code-mirror>
</div>
</template>
<template #after>
<q-btn label="ok" @click="click"></q-btn>
</template>
</q-splitter>
</w-v-expand-div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
@ -21,6 +35,11 @@ import { UserDefinedFunctionsManager } from './UserDefinedFunctionsManager';
import { AutoCompletionManager } from './AutoCompletionManager';
const modelValue = ref('${个人征信报告.报告头.报告头信息单元.报告标识信息段.报告编号} #{枚举}');
const splitterHeightRef = ref(70);
const sizeChanged = (args: any) => {
splitterHeightRef.value = args.height;
};
const click = () => {
//console.log(modelValue.value);

7
io.sc.platform.core.frontend/template-project/package.json

@ -1,6 +1,6 @@
{
"name": "platform-core",
"version": "8.2.40",
"version": "8.2.48",
"description": "前端核心包,用于快速构建前端的脚手架",
"private": false,
"keywords": [],
@ -87,6 +87,7 @@
"@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4",
@ -100,7 +101,7 @@
"@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0",
"axios": "1.7.9",
"axios": "1.8.2",
"codemirror": "6.0.1",
"dayjs": "1.11.13",
"echarts": "5.6.0",
@ -110,7 +111,7 @@
"mockjs": "1.1.0",
"node-sql-parser": "5.3.6",
"pinia": "2.3.0",
"platform-core": "8.2.40",
"platform-core": "8.2.48",
"quasar": "2.17.6",
"sort-array": "5.0.0",
"svg-path-commander": "2.1.7",

2
io.sc.platform.core.frontend/template-project/src/boostrap.ts

@ -15,6 +15,8 @@ import App from './App.vue';
import 'platform-core/dist/css/platform-core.css';
// 导入 tailwind utilities css
import 'tailwindcss/utilities.css';
// 导入 quasar-ui-qmarkdown css
import '@quasar/quasar-ui-qmarkdown/dist/index.css';
// 设置远程组件加载器
// 覆盖 platform-core 包中的 remoteComponentLoader 函数

2
io.sc.platform.core.frontend/template-project/src/components/index.ts

@ -11,6 +11,7 @@ import component_testcase_loading from '@/views/testcase/loading/loading.vue';
import component_testcase_excel from '@/views/testcase/excel/Excel.vue';
import component_testcase_word from '@/views/testcase/word/Word.vue';
import component_testcase_maxgraph from '@/views/testcase/maxgraph/Maxgraph.vue';
import component_testcase_ai from '@/views/testcase/ai/Ai.vue';
import component_testcase_likmDialog from '@/views/likm/Dialog.vue';
import component_testcase_likmDrawer from '@/views/likm/Drawer.vue';
import component_testcase_likmForm from '@/views/likm/Form.vue';
@ -31,6 +32,7 @@ const localComponents = {
'component.testcase.excel': component_testcase_excel,
'component.testcase.word': component_testcase_word,
'component.testcase.maxgraph': component_testcase_maxgraph,
'component.testcase.ai': component_testcase_ai,
'component.testcase.likmDialog': component_testcase_likmDialog,
'component.testcase.likmDrawer': component_testcase_likmDrawer,
'component.testcase.likmForm': component_testcase_likmForm,

1
io.sc.platform.core.frontend/template-project/src/i18n/messages.json

@ -10,6 +10,7 @@
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
"menu.testcase.maxgraph": "Graph Editor",
"menu.testcase.ai": "AI",
"route.testcase.noMenuRoute": "No Menu Route"
}

1
io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json

@ -10,6 +10,7 @@
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
"menu.testcase.maxgraph": "图形编辑器",
"menu.testcase.ai": "AI",
"route.testcase.noMenuRoute": "無關聯菜單路由"
}

1
io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json

@ -10,6 +10,7 @@
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
"menu.testcase.maxgraph": "图形编辑器",
"menu.testcase.ai": "AI",
"route.testcase.noMenuRoute": "无关联菜单路由"
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save