Spaces:
Runtime error
Runtime error
Add document authoring
Browse files- Dockerfile +48 -9
- Modelfile +0 -2
- Modelfile.embeddings +0 -1
- app.py +0 -10
- index.html +100 -3
- nginx.conf +11 -1
- public/javascript-app.js +90 -0
- service-config.yml +3 -3
- start-container.sh +0 -28
- start-services.sh +23 -2
- vite.config.ts +14 -3
Dockerfile
CHANGED
|
@@ -1,5 +1,12 @@
|
|
| 1 |
FROM pspdfkit/ai-assistant:nightly
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
# Set environment variables
|
| 4 |
ENV HOME=/home/node \
|
| 5 |
PNPM_HOME=/root/.local/share/pnpm \
|
|
@@ -66,19 +73,15 @@ RUN mkdir -p /var/cache/nginx \
|
|
| 66 |
/run/nginx
|
| 67 |
|
| 68 |
# Copy application files to /base BEFORE switching user
|
| 69 |
-
COPY --chown=node:node app.py service-config.yml /base/app/
|
| 70 |
COPY --chown=node:node nginx.conf /etc/nginx/nginx.conf
|
| 71 |
-
COPY --chown=node:node
|
| 72 |
COPY --chown=node:node service-config.yml /service-config.yml
|
| 73 |
|
| 74 |
-
# Create app directories and set up Python
|
| 75 |
USER node
|
| 76 |
RUN mkdir -p $HOME/models && \
|
| 77 |
-
mkdir -p $HOME/pgdata
|
| 78 |
-
python3 -m venv $HOME/venv && \
|
| 79 |
-
$HOME/venv/bin/pip install flask
|
| 80 |
|
| 81 |
-
# pgvector
|
| 82 |
USER root
|
| 83 |
RUN git clone https://github.com/pgvector/pgvector.git && \
|
| 84 |
cd pgvector && \
|
|
@@ -91,9 +94,45 @@ RUN git clone https://github.com/pgvector/pgvector.git && \
|
|
| 91 |
USER node
|
| 92 |
RUN wget -q https://huggingface.co/bartowski/gemma-2-2b-it-GGUF/resolve/main/gemma-2-2b-it-Q4_K_M.gguf -O $HOME/models/gemma-2b.gguf && \
|
| 93 |
wget -q https://huggingface.co/leliuga/all-MiniLM-L6-v2-GGUF/resolve/main/all-MiniLM-L6-v2.F16.gguf -O $HOME/models/embeddings.gguf && \
|
| 94 |
-
chmod +x /base/app/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
|
| 96 |
-
|
|
|
|
| 97 |
|
| 98 |
USER root
|
| 99 |
|
|
|
|
| 1 |
FROM pspdfkit/ai-assistant:nightly
|
| 2 |
|
| 3 |
+
# The main ai assistant JS app is in /base/app.
|
| 4 |
+
# Then I have a document authoring web app that is a Vite server that serves index.html and
|
| 5 |
+
# communicates with the ai assistant.
|
| 6 |
+
#
|
| 7 |
+
# Where should we put this web app? In /base/app it's gonna be problematic.
|
| 8 |
+
# New folder? /docauth?
|
| 9 |
+
|
| 10 |
# Set environment variables
|
| 11 |
ENV HOME=/home/node \
|
| 12 |
PNPM_HOME=/root/.local/share/pnpm \
|
|
|
|
| 73 |
/run/nginx
|
| 74 |
|
| 75 |
# Copy application files to /base BEFORE switching user
|
|
|
|
| 76 |
COPY --chown=node:node nginx.conf /etc/nginx/nginx.conf
|
| 77 |
+
COPY --chown=node:node start-services.sh /base/app/
|
| 78 |
COPY --chown=node:node service-config.yml /service-config.yml
|
| 79 |
|
|
|
|
| 80 |
USER node
|
| 81 |
RUN mkdir -p $HOME/models && \
|
| 82 |
+
mkdir -p $HOME/pgdata
|
|
|
|
|
|
|
| 83 |
|
| 84 |
+
# Install pgvector (needs root)
|
| 85 |
USER root
|
| 86 |
RUN git clone https://github.com/pgvector/pgvector.git && \
|
| 87 |
cd pgvector && \
|
|
|
|
| 94 |
USER node
|
| 95 |
RUN wget -q https://huggingface.co/bartowski/gemma-2-2b-it-GGUF/resolve/main/gemma-2-2b-it-Q4_K_M.gguf -O $HOME/models/gemma-2b.gguf && \
|
| 96 |
wget -q https://huggingface.co/leliuga/all-MiniLM-L6-v2-GGUF/resolve/main/all-MiniLM-L6-v2.F16.gguf -O $HOME/models/embeddings.gguf && \
|
| 97 |
+
chmod +x /base/app/start-services.sh
|
| 98 |
+
|
| 99 |
+
USER root
|
| 100 |
+
# Fix permissions for scripts and pnpm directory
|
| 101 |
+
RUN chmod +x /base/app/start-services.sh && \
|
| 102 |
+
mkdir -p /root/.local/share/pnpm && \
|
| 103 |
+
chmod 755 /root && \
|
| 104 |
+
chmod 755 /root/.local && \
|
| 105 |
+
chmod 755 /root/.local/share && \
|
| 106 |
+
chmod -R 755 /root/.local/share/pnpm && \
|
| 107 |
+
chown -R node:node /root/.local/share/pnpm
|
| 108 |
+
|
| 109 |
+
# Set up document authoring in a separate directory
|
| 110 |
+
WORKDIR /docauth
|
| 111 |
+
|
| 112 |
+
# Create directory and set permissions
|
| 113 |
+
USER root
|
| 114 |
+
RUN mkdir -p /docauth && \
|
| 115 |
+
chown -R node:node /docauth && \
|
| 116 |
+
chmod -R 755 /docauth
|
| 117 |
+
|
| 118 |
+
USER node
|
| 119 |
+
|
| 120 |
+
# Copy package files
|
| 121 |
+
COPY --chown=node:node package*.json ./
|
| 122 |
+
COPY --chown=node:node tsconfig*.json ./
|
| 123 |
+
COPY --chown=node:node vite.config.ts ./
|
| 124 |
+
COPY --chown=node:node .eslintrc.cjs ./
|
| 125 |
+
|
| 126 |
+
# Install dependencies
|
| 127 |
+
RUN npm install
|
| 128 |
+
|
| 129 |
+
# Copy source files
|
| 130 |
+
COPY --chown=node:node src ./src
|
| 131 |
+
COPY --chown=node:node public ./public
|
| 132 |
+
COPY --chown=node:node index.html ./
|
| 133 |
|
| 134 |
+
# Expose Vite's port (using 7860 as configured in vite.config.ts)
|
| 135 |
+
EXPOSE 7860
|
| 136 |
|
| 137 |
USER root
|
| 138 |
|
Modelfile
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
FROM /models/gemma-2-2b-it-Q4_K_M.gguf
|
| 2 |
-
|
|
|
|
|
|
|
|
|
Modelfile.embeddings
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
FROM /models/mxbai-embed-large-v1-f16.gguf
|
|
|
|
|
|
app.py
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
from flask import Flask
|
| 2 |
-
|
| 3 |
-
app = Flask(__name__)
|
| 4 |
-
|
| 5 |
-
@app.route('/')
|
| 6 |
-
def home():
|
| 7 |
-
return "PostgreSQL is running with Flask!"
|
| 8 |
-
|
| 9 |
-
if __name__ == '__main__':
|
| 10 |
-
app.run(host='0.0.0.0', port=7860)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
index.html
CHANGED
|
@@ -5,10 +5,107 @@
|
|
| 5 |
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
| 6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
<title>Document Authoring SDK</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
</head>
|
| 9 |
<body>
|
| 10 |
-
<
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
</body>
|
| 14 |
</html>
|
|
|
|
| 5 |
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
| 6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
<title>Document Authoring SDK</title>
|
| 8 |
+
<style>
|
| 9 |
+
.spinner {
|
| 10 |
+
display: inline-block;
|
| 11 |
+
width: 16px;
|
| 12 |
+
height: 16px;
|
| 13 |
+
border: 2px solid #f3f3f3;
|
| 14 |
+
border-top: 2px solid #3498db;
|
| 15 |
+
border-radius: 50%;
|
| 16 |
+
animation: spin 1s linear infinite;
|
| 17 |
+
margin-right: 8px;
|
| 18 |
+
vertical-align: middle;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
@keyframes spin {
|
| 22 |
+
0% { transform: rotate(0deg); }
|
| 23 |
+
100% { transform: rotate(360deg); }
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
#translateButton:disabled {
|
| 27 |
+
cursor: not-allowed;
|
| 28 |
+
opacity: 0.7;
|
| 29 |
+
}
|
| 30 |
+
</style>
|
| 31 |
</head>
|
| 32 |
<body>
|
| 33 |
+
<button id="translateButton">Translate to English</button>
|
| 34 |
+
<div id="editor" style="border: 1px solid black; width: 1024px; height: 600px; position: relative"></div>
|
| 35 |
+
|
| 36 |
+
<script src="https://document-authoring-cdn.pspdfkit.com/releases/document-authoring-1.0.26-umd.js" crossorigin></script>
|
| 37 |
+
<script>
|
| 38 |
+
(async () => {
|
| 39 |
+
const docAuthSystem = await DocAuth.createDocAuthSystem({
|
| 40 |
+
// assets: { base: '<CUSTOM_DOCUMENT_AUTHORING_ASSETS_LOCATION>' },
|
| 41 |
+
// licenseKey: '<YOUR_LICENSE_KEY>',
|
| 42 |
+
});
|
| 43 |
+
|
| 44 |
+
const editor = await docAuthSystem.createEditor(
|
| 45 |
+
document.getElementById("editor"),
|
| 46 |
+
{
|
| 47 |
+
document: await docAuthSystem.createDocumentFromPlaintext('Hi there!\n\nHow are you?'),
|
| 48 |
+
}
|
| 49 |
+
);
|
| 50 |
+
|
| 51 |
+
// Translation function.
|
| 52 |
+
async function translate(content, lang = "English") {
|
| 53 |
+
try {
|
| 54 |
+
const response = await fetch('/api/aia/v1/chat/completions', {
|
| 55 |
+
method: 'POST',
|
| 56 |
+
headers: {
|
| 57 |
+
'Content-Type': 'application/json',
|
| 58 |
+
'Authorization': 'Token token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MzMyNjQ2MDcsImV4cCI6MTczMzUyMzgwN30.WWyks6NOU43_2OcZX82z3P4QUwQiUA61SeTZsNobIGoVg3uDTkedXWqISIB7QqTnRyf_D92t_pGr5g_GzqBaOTqaXYJJPco9mtZjtAyUpdWr1UHu4jx-zoKUpCeguZQZbHG6vqYzu1BNV1iPdij2OIoUrr_DY--G-6m5-31E0LcDZb7ysUyZL1Ai_q7PPRwTS8mEtvuF4QO6Cw_a77X7Qh9x_V8a_WwNMFwQMRkIUAsRx3IOI10q0hdwP-k8xYtTbHQO-z66pRl6I71ATclR7FS5FraoLLmWlq8lqNKfzeOgER8Kcf8uB87zHQbfk0QR8AfJGmZDE8pG5F3QG29MeA'
|
| 59 |
+
},
|
| 60 |
+
body: JSON.stringify({
|
| 61 |
+
messages: [
|
| 62 |
+
{
|
| 63 |
+
role: "system",
|
| 64 |
+
content: "You are a translator. Only provide the translation, no explanations or additional text."
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
role: "user",
|
| 68 |
+
content: `Translate the following text to ${lang}: ${content}`
|
| 69 |
+
}
|
| 70 |
+
],
|
| 71 |
+
model: "gemma-2b",
|
| 72 |
+
stream: false
|
| 73 |
+
})
|
| 74 |
+
});
|
| 75 |
+
|
| 76 |
+
if (!response.ok) {
|
| 77 |
+
throw new Error('Translation request failed');
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
const data = await response.json();
|
| 81 |
+
console.log('Translation API response:', data);
|
| 82 |
+
return data.choices[0].message.content;
|
| 83 |
+
} catch (error) {
|
| 84 |
+
console.error("Translation error:", error);
|
| 85 |
+
throw new Error("Failed to generate translation");
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
async function testDummy() {
|
| 90 |
+
try {
|
| 91 |
+
const response = await fetch('/dummy');
|
| 92 |
+
const text = await response.text();
|
| 93 |
+
console.log('Dummy response:', text);
|
| 94 |
+
} catch (error) {
|
| 95 |
+
console.error('Dummy error:', error);
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
// Dev exports
|
| 100 |
+
window.DocAuth = DocAuth;
|
| 101 |
+
window.docAuthSystem = docAuthSystem;
|
| 102 |
+
window.editor = editor;
|
| 103 |
+
|
| 104 |
+
const testButton = document.createElement('button');
|
| 105 |
+
testButton.textContent = 'Test Dummy';
|
| 106 |
+
document.body.insertBefore(testButton, document.getElementById('editor'));
|
| 107 |
+
testButton.addEventListener('click', testDummy);
|
| 108 |
+
})();
|
| 109 |
+
</script>
|
| 110 |
</body>
|
| 111 |
</html>
|
nginx.conf
CHANGED
|
@@ -4,8 +4,18 @@ events {
|
|
| 4 |
|
| 5 |
http {
|
| 6 |
server {
|
| 7 |
-
listen
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
location /v1/embeddings {
|
| 10 |
proxy_pass http://127.0.0.1:8081;
|
| 11 |
}
|
|
|
|
| 4 |
|
| 5 |
http {
|
| 6 |
server {
|
| 7 |
+
listen 7860;
|
| 8 |
|
| 9 |
+
location / {
|
| 10 |
+
return 200 'Hello World!<br><a href="https://dmartincy-document-translation.hf.space/dummy">Go to dummy page</a>';
|
| 11 |
+
add_header Content-Type text/html;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
location /dummy {
|
| 15 |
+
return 200 'Hello dummy';
|
| 16 |
+
add_header Content-Type text/html;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
location /v1/embeddings {
|
| 20 |
proxy_pass http://127.0.0.1:8081;
|
| 21 |
}
|
public/javascript-app.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import DocAuth from "https://document-authoring-cdn.pspdfkit.com/releases/document-authoring-1.0.26-esm.js";
|
| 2 |
+
|
| 3 |
+
const docAuthSystem = await DocAuth.createDocAuthSystem({
|
| 4 |
+
// assets: { base: '<CUSTOM_DOCUMENT_AUTHORING_ASSETS_LOCATION>' },
|
| 5 |
+
// licenseKey: '<YOUR_LICENSE_KEY>',
|
| 6 |
+
});
|
| 7 |
+
|
| 8 |
+
const editor = await docAuthSystem.createEditor(
|
| 9 |
+
document.getElementById("editor"),
|
| 10 |
+
{
|
| 11 |
+
document: await docAuthSystem.importDOCX(fetch("./Spanish.docx")),
|
| 12 |
+
}
|
| 13 |
+
);
|
| 14 |
+
|
| 15 |
+
// Translation function.
|
| 16 |
+
async function translate(content, lang = "English") {
|
| 17 |
+
try {
|
| 18 |
+
const response = await fetch('/api/aia/v1/chat/completions', {
|
| 19 |
+
method: 'POST',
|
| 20 |
+
headers: {
|
| 21 |
+
'Content-Type': 'application/json',
|
| 22 |
+
'Authorization': 'Token token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MzMyNjQ2MDcsImV4cCI6MTczMzUyMzgwN30.WWyks6NOU43_2OcZX82z3P4QUwQiUA61SeTZsNobIGoVg3uDTkedXWqISIB7QqTnRyf_D92t_pGr5g_GzqBaOTqaXYJJPco9mtZjtAyUpdWr1UHu4jx-zoKUpCeguZQZbHG6vqYzu1BNV1iPdij2OIoUrr_DY--G-6m5-31E0LcDZb7ysUyZL1Ai_q7PPRwTS8mEtvuF4QO6Cw_a77X7Qh9x_V8a_WwNMFwQMRkIUAsRx3IOI10q0hdwP-k8xYtTbHQO-z66pRl6I71ATclR7FS5FraoLLmWlq8lqNKfzeOgER8Kcf8uB87zHQbfk0QR8AfJGmZDE8pG5F3QG29MeA'
|
| 23 |
+
},
|
| 24 |
+
body: JSON.stringify({
|
| 25 |
+
messages: [
|
| 26 |
+
{
|
| 27 |
+
role: "system",
|
| 28 |
+
content: "You are a translator. Only provide the translation, no explanations or additional text."
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
role: "user",
|
| 32 |
+
content: `Translate the following text to ${lang}: ${content}`
|
| 33 |
+
}
|
| 34 |
+
],
|
| 35 |
+
model: "gemma-2b",
|
| 36 |
+
stream: false
|
| 37 |
+
})
|
| 38 |
+
});
|
| 39 |
+
|
| 40 |
+
if (!response.ok) {
|
| 41 |
+
throw new Error('Translation request failed');
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
const data = await response.json();
|
| 45 |
+
console.log('Translation API response:', data);
|
| 46 |
+
return data.choices[0].message.content;
|
| 47 |
+
} catch (error) {
|
| 48 |
+
console.error("Translation error:", error);
|
| 49 |
+
throw new Error("Failed to generate translation");
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
// Function to recursively translate text in the JSON structure.
|
| 54 |
+
async function translateRecursive(obj) {
|
| 55 |
+
for (let key in obj) {
|
| 56 |
+
if (typeof obj[key] === "string" && key === "text" && obj[key].length > 0) {
|
| 57 |
+
obj[key] = await translate(obj[key]);
|
| 58 |
+
} else if (typeof obj[key] === "object") {
|
| 59 |
+
await translateRecursive(obj[key]);
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
// Function to translate the document.
|
| 65 |
+
async function translateDocument() {
|
| 66 |
+
try {
|
| 67 |
+
translateButton.disabled = true;
|
| 68 |
+
translateButton.innerHTML = '<span class="spinner"></span> Translating...';
|
| 69 |
+
|
| 70 |
+
const jsonDoc = await editor.currentDocument().saveDocument();
|
| 71 |
+
await translateRecursive(jsonDoc.container.document);
|
| 72 |
+
|
| 73 |
+
const translatedDoc = await docAuthSystem.loadDocument(jsonDoc);
|
| 74 |
+
editor.setCurrentDocument(translatedDoc);
|
| 75 |
+
} catch (error) {
|
| 76 |
+
console.error("Translation error:", error);
|
| 77 |
+
} finally {
|
| 78 |
+
translateButton.disabled = false;
|
| 79 |
+
translateButton.innerHTML = 'Translate to English';
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
// Add click event listener to the translate button.
|
| 84 |
+
const translateButton = document.getElementById("translateButton");
|
| 85 |
+
translateButton.addEventListener("click", translateDocument);
|
| 86 |
+
|
| 87 |
+
// Dev exports.
|
| 88 |
+
window.DocAuth = DocAuth;
|
| 89 |
+
window.docAuthSystem = docAuthSystem;
|
| 90 |
+
window.editor = editor;
|
service-config.yml
CHANGED
|
@@ -4,17 +4,17 @@ aiServices:
|
|
| 4 |
chat:
|
| 5 |
provider:
|
| 6 |
name: 'openai-compat'
|
| 7 |
-
baseUrl: http://127.0.0.1:
|
| 8 |
model: 'gemma-2b'
|
| 9 |
textEmbeddings:
|
| 10 |
provider:
|
| 11 |
name: 'openai-compat'
|
| 12 |
-
baseUrl: http://127.0.0.1:
|
| 13 |
model: 'all-MiniLM-L6-v2'
|
| 14 |
headless:
|
| 15 |
- provider:
|
| 16 |
name: 'openai-compat'
|
| 17 |
-
baseUrl: http://127.0.0.1:
|
| 18 |
model:
|
| 19 |
name: 'gemma-2b'
|
| 20 |
id: 'gemma-2b'
|
|
|
|
| 4 |
chat:
|
| 5 |
provider:
|
| 6 |
name: 'openai-compat'
|
| 7 |
+
baseUrl: http://127.0.0.1:7861/v1
|
| 8 |
model: 'gemma-2b'
|
| 9 |
textEmbeddings:
|
| 10 |
provider:
|
| 11 |
name: 'openai-compat'
|
| 12 |
+
baseUrl: http://127.0.0.1:7861/v1
|
| 13 |
model: 'all-MiniLM-L6-v2'
|
| 14 |
headless:
|
| 15 |
- provider:
|
| 16 |
name: 'openai-compat'
|
| 17 |
+
baseUrl: http://127.0.0.1:7861/v1
|
| 18 |
model:
|
| 19 |
name: 'gemma-2b'
|
| 20 |
id: 'gemma-2b'
|
start-container.sh
DELETED
|
@@ -1,28 +0,0 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
|
| 3 |
-
# Start nginx
|
| 4 |
-
nginx
|
| 5 |
-
|
| 6 |
-
# Start llamafiler instances
|
| 7 |
-
/usr/local/bin/llamafiler --model /base/gemma-2b.gguf --listen 0.0.0.0:8082 &
|
| 8 |
-
GEMMA_PID=$!
|
| 9 |
-
|
| 10 |
-
/usr/local/bin/llamafiler --model /base/embeddings.gguf --listen 0.0.0.0:8081 &
|
| 11 |
-
EMBEDDINGS_PID=$!
|
| 12 |
-
|
| 13 |
-
# Wait for services
|
| 14 |
-
until curl -s --fail -X POST http://localhost:8080/v1/chat/completions \
|
| 15 |
-
-H "Content-Type: application/json" \
|
| 16 |
-
-d '{"model": "gemma-2b", "messages":[{"role":"user","content":"hi"}]}' >/dev/null 2>&1 && \
|
| 17 |
-
curl -s --fail -X POST http://localhost:8080/v1/embeddings \
|
| 18 |
-
-H "Content-Type: application/json" \
|
| 19 |
-
-d '{"input":"test"}' >/dev/null 2>&1
|
| 20 |
-
do
|
| 21 |
-
sleep 1
|
| 22 |
-
echo "Waiting for services..."
|
| 23 |
-
done
|
| 24 |
-
|
| 25 |
-
echo 'Services are ready!'
|
| 26 |
-
|
| 27 |
-
# Start the main application
|
| 28 |
-
exec ./bin/entrypoint.sh node app/main.bundle.js
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
start-services.sh
CHANGED
|
@@ -46,6 +46,27 @@ done
|
|
| 46 |
|
| 47 |
echo "PostgreSQL is ready!"
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
# 4. Start Llamafiler (reusing existing code)
|
| 50 |
echo "Starting llamafiler services..."
|
| 51 |
mkdir -p /tmp/llamafiler
|
|
@@ -63,10 +84,10 @@ echo "Waiting for initial model loading..."
|
|
| 63 |
sleep 15 # Give more time for the models to load into memory
|
| 64 |
|
| 65 |
echo 'Waiting for servers to start...'
|
| 66 |
-
until curl -s --fail -X POST http://
|
| 67 |
-H "Content-Type: application/json" \
|
| 68 |
-d '{"model": "gemma-2b", "messages":[{"role":"user","content":"hi"}]}' >/dev/null 2>&1 && \
|
| 69 |
-
curl -s --fail -X POST http://
|
| 70 |
-H "Content-Type: application/json" \
|
| 71 |
-d '{"input":"test"}' >/dev/null 2>&1
|
| 72 |
do
|
|
|
|
| 46 |
|
| 47 |
echo "PostgreSQL is ready!"
|
| 48 |
|
| 49 |
+
# Start the web app
|
| 50 |
+
echo "Starting web app..."
|
| 51 |
+
cd /docauth
|
| 52 |
+
export NODE_OPTIONS="--experimental-vm-modules --experimental-json-modules"
|
| 53 |
+
|
| 54 |
+
# Start vite with the existing config.
|
| 55 |
+
npx vite serve --host 0.0.0.0 --port 7860 &
|
| 56 |
+
|
| 57 |
+
# Wait for the web app to start
|
| 58 |
+
echo "Waiting for web app..."
|
| 59 |
+
until curl -s http://127.0.0.1:7860 > /dev/null; do
|
| 60 |
+
echo "Waiting for web app..."
|
| 61 |
+
sleep 2
|
| 62 |
+
if [ $SECONDS -gt 30 ]; then
|
| 63 |
+
echo "Timeout waiting for web app"
|
| 64 |
+
exit 1
|
| 65 |
+
fi
|
| 66 |
+
done
|
| 67 |
+
|
| 68 |
+
echo "Web app is ready!"
|
| 69 |
+
|
| 70 |
# 4. Start Llamafiler (reusing existing code)
|
| 71 |
echo "Starting llamafiler services..."
|
| 72 |
mkdir -p /tmp/llamafiler
|
|
|
|
| 84 |
sleep 15 # Give more time for the models to load into memory
|
| 85 |
|
| 86 |
echo 'Waiting for servers to start...'
|
| 87 |
+
until curl -s --fail -X POST http://127.0.0.1:7861/v1/chat/completions \
|
| 88 |
-H "Content-Type: application/json" \
|
| 89 |
-d '{"model": "gemma-2b", "messages":[{"role":"user","content":"hi"}]}' >/dev/null 2>&1 && \
|
| 90 |
+
curl -s --fail -X POST http://127.0.0.1:7861/v1/embeddings \
|
| 91 |
-H "Content-Type: application/json" \
|
| 92 |
-d '{"input":"test"}' >/dev/null 2>&1
|
| 93 |
do
|
vite.config.ts
CHANGED
|
@@ -8,14 +8,25 @@ export default defineConfig({
|
|
| 8 |
appType: 'mpa',
|
| 9 |
server: {
|
| 10 |
host: '0.0.0.0', // Listen on all available network interfaces
|
| 11 |
-
port:
|
| 12 |
headers: {
|
| 13 |
'Cross-Origin-Embedder-Policy': 'require-corp',
|
| 14 |
-
'Cross-Origin-Opener-Policy': 'same-origin'
|
| 15 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
proxy: {
|
| 17 |
'/api/aia': {
|
| 18 |
-
target: 'http://
|
| 19 |
changeOrigin: true,
|
| 20 |
rewrite: (path) => {
|
| 21 |
console.log('Rewriting path:', path);
|
|
|
|
| 8 |
appType: 'mpa',
|
| 9 |
server: {
|
| 10 |
host: '0.0.0.0', // Listen on all available network interfaces
|
| 11 |
+
port: 7860,
|
| 12 |
headers: {
|
| 13 |
'Cross-Origin-Embedder-Policy': 'require-corp',
|
| 14 |
+
'Cross-Origin-Opener-Policy': 'same-origin',
|
| 15 |
},
|
| 16 |
+
middleware: [
|
| 17 |
+
// Add custom middleware for /dummy route
|
| 18 |
+
(req, res, next) => {
|
| 19 |
+
if (req.url === '/dummy') {
|
| 20 |
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
| 21 |
+
res.end('Hello World!');
|
| 22 |
+
return;
|
| 23 |
+
}
|
| 24 |
+
next();
|
| 25 |
+
}
|
| 26 |
+
],
|
| 27 |
proxy: {
|
| 28 |
'/api/aia': {
|
| 29 |
+
target: 'http://127.0.0.1:4000',
|
| 30 |
changeOrigin: true,
|
| 31 |
rewrite: (path) => {
|
| 32 |
console.log('Rewriting path:', path);
|