Skip to content

Commit 325cc76

Browse files
committed
[aimix] first implementation of AI Mix
1 parent a7f8fcd commit 325cc76

File tree

17 files changed

+1804
-9
lines changed

17 files changed

+1804
-9
lines changed

app/src/main/java/io/vproxy/app/app/Main.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import java.io.IOException;
2323

2424
public class Main {
25-
static final String _HELP_STR_ = "" +
25+
static final String _HELP_STR_ =
2626
"vproxy: usage java " + Main.class.getName() + " \\" +
2727
"\n\t\thelp Show this message" +
2828
"\n" +
@@ -131,6 +131,11 @@ private static void runApp(String appClass, String[] args) {
131131
case "proxynexus":
132132
ProxyNexus.main0(args);
133133
break;
134+
case "AiMix":
135+
case "ai-mix":
136+
case "aimix":
137+
AiMix.main0(args);
138+
break;
134139
default:
135140
System.err.println("unknown AppClass: " + appClass);
136141
Utils.exit(1);

base/src/main/java/io/vproxy/base/processor/http1/entity/Chunk.java

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ public ByteArray toByteArray() {
2121
if (extension != null && !extension.isBlank()) {
2222
ext = ";" + extension;
2323
}
24+
if (size == 0 && content != null) {
25+
size = content.length();
26+
}
2427
ByteArray ret = ByteArray.from((Integer.toHexString(size) + ext + "\r\n").getBytes());
2528
if (size == 0) {
2629
return ret;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package io.vproxy.vproxyx;
2+
3+
import io.vproxy.base.component.elgroup.EventLoopGroup;
4+
import io.vproxy.vproxyx.aimix.AiMixServer;
5+
import io.vproxy.vproxyx.aimix.ConfigBuilder;
6+
import vjson.CharStream;
7+
import vjson.JSON;
8+
import vjson.parser.ParserOptions;
9+
10+
import java.io.FileInputStream;
11+
import java.nio.charset.StandardCharsets;
12+
13+
public class AiMix {
14+
private static final String HELP_STR = """
15+
Usage:
16+
conf=${path-to-config-file}
17+
18+
{
19+
listen = ${listening port}
20+
name = aimix # exposed model name
21+
multimodal {
22+
name = ${name of the model}
23+
servers = [
24+
{
25+
type = ${openai or ollama}
26+
address = 127.0.0.1:11434
27+
ollama_options = {
28+
num_thread = 33
29+
}
30+
}
31+
]
32+
}
33+
reasoning {
34+
name = ${name of the model}
35+
servers = [
36+
{
37+
type = ${openai or ollama}
38+
address = 127.0.0.1:10002
39+
}
40+
]
41+
reasoning_tag = "<think>" # optional
42+
end_reasoning_tag = "</think>" # optional
43+
}
44+
language {
45+
name = ${name of the model}
46+
servers = [
47+
{
48+
type = ${openai or ollama}
49+
address = 127.0.0.1:10003
50+
}
51+
]
52+
}
53+
prompt {
54+
# ...... see class Prompt in ConfigBuilder.java
55+
}
56+
sys {
57+
# ...... see class Sys in ConfigBuilder.java
58+
}
59+
}
60+
""";
61+
62+
public static void main0(String[] args) throws Exception {
63+
String confPath = null;
64+
for (var a : args) {
65+
if (a.equals("help") || a.equals("-h") || a.equals("-help") || a.equals("--help")) {
66+
System.out.println(HELP_STR);
67+
return;
68+
}
69+
if (a.startsWith("conf=")) {
70+
var v = a.substring("conf=".length()).trim();
71+
if (v.isEmpty()) {
72+
System.err.println("conf={empty path} is not allowed");
73+
System.exit(1);
74+
return;
75+
}
76+
confPath = v;
77+
}
78+
}
79+
if (confPath == null) {
80+
System.err.println("conf=${...} is not specified");
81+
System.exit(1);
82+
return;
83+
}
84+
String content;
85+
try (var fis = new FileInputStream(confPath)) {
86+
content = new String(fis.readAllBytes(), StandardCharsets.UTF_8);
87+
}
88+
var configBuilder = JSON.deserialize(CharStream.from(content), ConfigBuilder.rule, ParserOptions.allFeatures());
89+
configBuilder.validate();
90+
91+
var el = new EventLoopGroup("ai-mix");
92+
el.add("ai-mix-" + 0);
93+
var config = configBuilder.build(el);
94+
var server = new AiMixServer(el, config);
95+
server.start();
96+
}
97+
}

0 commit comments

Comments
 (0)