:💩: | GPT -> gpt-unslother
This commit is contained in:
139
.gitignore
vendored
139
.gitignore
vendored
@@ -1,138 +1,3 @@
|
|||||||
# ---> Node
|
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
node_modules/
|
||||||
jspm_packages/
|
.DS_Store
|
||||||
|
dist/
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional stylelint cache
|
|
||||||
.stylelintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variable files
|
|
||||||
.env
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
|
||||||
|
|
||||||
# Gatsby files
|
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
|
||||||
.temp
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# vitepress build output
|
|
||||||
**/.vitepress/dist
|
|
||||||
|
|
||||||
# vitepress cache directory
|
|
||||||
**/.vitepress/cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
|
||||||
.docusaurus
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -1,3 +1,13 @@
|
|||||||
# shelter-plugins
|
# shelter-plugins
|
||||||
|
|
||||||
ORIGINAL: https://github.com/edde746/shelter-plugins
|
> **Note:** This repository is a fork of [edde746/shelter-plugins](https://github.com/edde746/shelter-plugins).
|
||||||
|
|
||||||
|
## Self-Hosting
|
||||||
|
|
||||||
|
These plugins can be hosted on your own server using NGINX. See the [NGINX Static Hosting Guide](docs/NGINX-STATIC-HOSTING.md) for setup instructions.
|
||||||
|
|
||||||
|
## gpt-unslothed
|
||||||
|
|
||||||
|
Use local language models via Unsloth Studio API to generate responses based on recent messages in the channel and a prompt.
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
211
docs/NGINX-STATIC-HOSTING.md
Normal file
211
docs/NGINX-STATIC-HOSTING.md
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
# Hosting Shelter Plugins with NGINX
|
||||||
|
|
||||||
|
This guide walks you through hosting the built plugin files using NGINX on your own server.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- A server running NGINX
|
||||||
|
- Access to the server via SSH
|
||||||
|
- Basic familiarity with Linux command line
|
||||||
|
|
||||||
|
## Step 1: Prepare the Plugin Files
|
||||||
|
|
||||||
|
First, build the plugins locally using Lune:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install pnpm if you haven't already
|
||||||
|
npm install -g pnpm
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# Build the plugins
|
||||||
|
pnpm lune ci
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates the built plugin files in the `dist/` directory (e.g., `dist/gpt/plugin.js`, `dist/gpt/plugin.json`).
|
||||||
|
|
||||||
|
## Step 2: Set Up the Web Directory
|
||||||
|
|
||||||
|
Create a directory for the static files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create the directory (you can change the path as needed)
|
||||||
|
sudo mkdir -p /var/www/shelter-plugins
|
||||||
|
|
||||||
|
# Copy the built files
|
||||||
|
sudo cp -r dist/* /var/www/shelter-plugins/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3: Configure NGINX
|
||||||
|
|
||||||
|
Create a new NGINX configuration file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/nginx/sites-available/shelter-plugins
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the following configuration:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name plugins.your-domain.com; # Change to your domain
|
||||||
|
|
||||||
|
root /var/www/shelter-plugins;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Serve plugin files
|
||||||
|
location /gpt-unslothed {
|
||||||
|
default_type application/json;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Serve preview images
|
||||||
|
location /previews {
|
||||||
|
default_type image/png;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Serve README
|
||||||
|
location /README.md {
|
||||||
|
default_type text/markdown;
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Catch-all for 404
|
||||||
|
location = /404.html {
|
||||||
|
internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirect all other requests to 404
|
||||||
|
location / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Notes
|
||||||
|
|
||||||
|
- Change `plugins.your-domain.com` to your actual domain or IP address
|
||||||
|
- The `default_type application/json` ensures browsers don't try to execute the plugin files
|
||||||
|
- The configuration serves plugins from paths like `http://plugins.your-domain.com/gpt-unslothed/`
|
||||||
|
|
||||||
|
## Step 4: Enable the Site
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable the site
|
||||||
|
sudo ln -s /etc/nginx/sites-available/shelter-plugins /etc/nginx/sites-enabled/
|
||||||
|
|
||||||
|
# Test the configuration
|
||||||
|
sudo nginx -t
|
||||||
|
|
||||||
|
# Reload NGINX
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 5: Use in Shelter
|
||||||
|
|
||||||
|
In Shelter, add the plugin using the URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://plugins.your-domain.com/gpt-unslothed/plugin.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Or if using HTTPS (recommended):
|
||||||
|
|
||||||
|
```
|
||||||
|
https://plugins.your-domain.com/gpt-unslothed/plugin.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optional: Set Up HTTPS with Let's Encrypt
|
||||||
|
|
||||||
|
Install Certbot and get an SSL certificate:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Certbot (Ubuntu/Debian)
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install certbot python3-certbot-nginx
|
||||||
|
|
||||||
|
# Get the certificate
|
||||||
|
sudo certbot --nginx -d plugins.your-domain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Certbot will automatically update your NGINX configuration to use HTTPS.
|
||||||
|
|
||||||
|
## Automation: Deploying Updates
|
||||||
|
|
||||||
|
To make updates easier, you can create a simple deployment script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# deploy.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Build plugins
|
||||||
|
echo "Building plugins..."
|
||||||
|
pnpm lune ci
|
||||||
|
|
||||||
|
# Copy files
|
||||||
|
echo "Copying files to web directory..."
|
||||||
|
sudo rsync -av --delete dist/ /var/www/shelter-plugins/
|
||||||
|
|
||||||
|
# Reload NGINX (optional)
|
||||||
|
# sudo systemctl reload nginx
|
||||||
|
|
||||||
|
echo "Deployment complete!"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make it executable and run it when you want to deploy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x deploy.sh
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
After deployment, your server should look like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
/var/www/shelter-plugins/
|
||||||
|
├── gpt-unslothed/
|
||||||
|
│ ├── plugin.json
|
||||||
|
│ ├── index.jsx
|
||||||
|
│ └── settings.jsx
|
||||||
|
└── previews/
|
||||||
|
└── gpt.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### 404 Not Found
|
||||||
|
|
||||||
|
- Ensure the `dist/` directory contents were copied correctly
|
||||||
|
- Check that your NGINX site is enabled: `ls /etc/nginx/sites-enabled/`
|
||||||
|
- Check NGINX error logs: `sudo tail -f /var/log/nginx/error.log`
|
||||||
|
|
||||||
|
### Plugin not loading in Shelter
|
||||||
|
|
||||||
|
- Make sure the URL points to `plugin.json`, not the directory
|
||||||
|
- Check browser console for CORS errors (may need to add CORS headers)
|
||||||
|
|
||||||
|
### Adding CORS headers
|
||||||
|
|
||||||
|
If Shelter is experiencing CORS issues, add these headers to your NGINX config:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'Content-Type';
|
||||||
|
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_type application/json;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
```
|
||||||
17
lune.config.js
Normal file
17
lune.config.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Welcome to your Lune config file!
|
||||||
|
// You can view documentation on Lune here:
|
||||||
|
// https://github.com/uwu/shelter/tree/main/packages/lune
|
||||||
|
// uncomment lines below to enable options, and feel free to delete this header.
|
||||||
|
import { defineConfig } from "@uwu/lune";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
// this is the directory that your plugins live in.
|
||||||
|
// repoSubDir: "plugins-live-in-here",
|
||||||
|
|
||||||
|
// this enables CSS Module support - see docs for info
|
||||||
|
// cssModules: true,
|
||||||
|
|
||||||
|
// these add extra esbuild plugins into the pipeline.
|
||||||
|
// prePlugins: [],
|
||||||
|
// postPlugins: [],
|
||||||
|
});
|
||||||
8
package.json
Normal file
8
package.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"@uwu/lune": "^1.2.1",
|
||||||
|
"@uwu/shelter-defs": "^1.1.0"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"workspaces": ["plugins/*"]
|
||||||
|
}
|
||||||
253
plugins/gpt-unslothed/index.jsx
Normal file
253
plugins/gpt-unslothed/index.jsx
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
const {
|
||||||
|
observeDom,
|
||||||
|
ui: {
|
||||||
|
injectCss,
|
||||||
|
Button,
|
||||||
|
openModal,
|
||||||
|
ModalRoot,
|
||||||
|
ModalHeader,
|
||||||
|
ModalBody,
|
||||||
|
ModalFooter,
|
||||||
|
ModalSizes,
|
||||||
|
Text,
|
||||||
|
TextBox,
|
||||||
|
ReactiveRoot,
|
||||||
|
TextArea,
|
||||||
|
ButtonLooks,
|
||||||
|
},
|
||||||
|
plugin: { store },
|
||||||
|
util: { getFiber },
|
||||||
|
} = shelter;
|
||||||
|
|
||||||
|
let popupButton = null;
|
||||||
|
let unobserve = null;
|
||||||
|
|
||||||
|
const getMessageHistory = () => {
|
||||||
|
const messageElements = document.querySelectorAll('div[class^="message-"]');
|
||||||
|
|
||||||
|
const messages = [...messageElements].map((message) => ({
|
||||||
|
username: message.querySelector("h3 > span > span")?.textContent,
|
||||||
|
message: message.querySelector("div > div > div").textContent,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return messages.reduce((acc, message) => {
|
||||||
|
if (message.username) {
|
||||||
|
acc.push(message);
|
||||||
|
} else {
|
||||||
|
acc[acc.length - 1].message += `\n${message.message}`;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadingIndicator = () => (
|
||||||
|
<svg
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
id="loading-indicator"
|
||||||
|
fill="white"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
|
||||||
|
opacity=".25"
|
||||||
|
/>
|
||||||
|
<path d="M10.72,19.9a8,8,0,0,1-6.5-9.79A7.77,7.77,0,0,1,10.4,4.16a8,8,0,0,1,9.49,6.52A1.54,1.54,0,0,0,21.38,12h.13a1.37,1.37,0,0,0,1.38-1.54,11,11,0,1,0-12.7,12.39A1.54,1.54,0,0,0,12,21.34h0A1.47,1.47,0,0,0,10.72,19.9Z">
|
||||||
|
<animateTransform
|
||||||
|
attributeName="transform"
|
||||||
|
type="rotate"
|
||||||
|
dur="0.75s"
|
||||||
|
values="0 12 12;360 12 12"
|
||||||
|
repeatCount="indefinite"
|
||||||
|
/>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Credits to yellowsink for this messagebar stuff
|
||||||
|
// https://github.com/yellowsink
|
||||||
|
const appendTextToMessagebar = (text) => {
|
||||||
|
const elem = document.querySelector('[class*="slateContainer"]');
|
||||||
|
const fiber = getFiber(elem);
|
||||||
|
const editor = fiber.child.pendingProps.editor;
|
||||||
|
|
||||||
|
editor.insertText(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function onLoad() {
|
||||||
|
injectCss(`
|
||||||
|
.label-spacing {
|
||||||
|
margin-bottom: .125rem;
|
||||||
|
}
|
||||||
|
.mb-2 {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr-2 {
|
||||||
|
padding-right: .5rem;
|
||||||
|
}`);
|
||||||
|
|
||||||
|
let closeModal = null;
|
||||||
|
const openGenerationModal = async () => {
|
||||||
|
let savedModel = store.model || "";
|
||||||
|
|
||||||
|
let model = savedModel;
|
||||||
|
let prompt = "";
|
||||||
|
closeModal = openModal((p) => (
|
||||||
|
<ModalRoot size={ModalSizes.SMALL}>
|
||||||
|
<ModalHeader close={() => closeModal()}>Generate Response</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<div className="pr-2">
|
||||||
|
<div className="mb-2 flex">
|
||||||
|
<div className="label-spacing">
|
||||||
|
<Text>Model</Text>
|
||||||
|
</div>
|
||||||
|
<TextBox
|
||||||
|
placeholder="local-model"
|
||||||
|
value={savedModel}
|
||||||
|
onInput={(e) => {
|
||||||
|
model = e;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="label-spacing">
|
||||||
|
<Text>Prompt</Text>
|
||||||
|
</div>
|
||||||
|
<TextArea
|
||||||
|
width="100%"
|
||||||
|
value=""
|
||||||
|
placeholder="Prompt"
|
||||||
|
onInput={(e) => {
|
||||||
|
prompt = e;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
grow={true}
|
||||||
|
onClick={async () => {
|
||||||
|
closeModal();
|
||||||
|
|
||||||
|
const myUsername = document.querySelector(
|
||||||
|
"[class^=nameTag] > div"
|
||||||
|
).textContent;
|
||||||
|
|
||||||
|
store.model = model;
|
||||||
|
|
||||||
|
const messages = [
|
||||||
|
...getMessageHistory()
|
||||||
|
.slice(-7)
|
||||||
|
.map((message) => ({
|
||||||
|
role: "user",
|
||||||
|
content: `${message.username}: ${message.message}`,
|
||||||
|
})),
|
||||||
|
{
|
||||||
|
role: "system",
|
||||||
|
content: `generate a response as "${myUsername}" according to the prompt: "${prompt}"`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// add loading indicator
|
||||||
|
const messageBar = document.querySelector(
|
||||||
|
'[class*="slateContainer"]'
|
||||||
|
);
|
||||||
|
// get absolute position of messagebar
|
||||||
|
const { x, y } = messageBar.getBoundingClientRect();
|
||||||
|
const loadingIndicatorElem = document.body.appendChild(
|
||||||
|
loadingIndicator()
|
||||||
|
);
|
||||||
|
|
||||||
|
loadingIndicatorElem.style.position = "absolute";
|
||||||
|
loadingIndicatorElem.style.left = `${x}px`;
|
||||||
|
loadingIndicatorElem.style.top = `${y + 12}px`;
|
||||||
|
|
||||||
|
// Unsloth Studio API
|
||||||
|
const apiUrl = `${store.unslothUrl}/v1/chat/completions`;
|
||||||
|
const apiHeaders = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
if (store.unslothKey) {
|
||||||
|
apiHeaders["Authorization"] = `Bearer ${store.unslothKey}`;
|
||||||
|
}
|
||||||
|
const apiBody = {
|
||||||
|
model,
|
||||||
|
messages,
|
||||||
|
stream: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(apiUrl, {
|
||||||
|
method: "POST",
|
||||||
|
headers: apiHeaders,
|
||||||
|
body: JSON.stringify(apiBody),
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((res) => {
|
||||||
|
const response = res.choices[0].message.content;
|
||||||
|
appendTextToMessagebar(
|
||||||
|
response
|
||||||
|
.replace(/^(?=.{0,49}:)([\w\s\-]+?[^ ]):/, "")
|
||||||
|
.trim()
|
||||||
|
);
|
||||||
|
|
||||||
|
loadingIndicatorElem.remove();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("API Error:", err);
|
||||||
|
loadingIndicatorElem.remove();
|
||||||
|
alert(`Error: ${err.message || "Failed to generate response"}`);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Generate
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalRoot>
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
unobserve = observeDom(
|
||||||
|
'[class^="channelTextArea"] [class^="buttons"]',
|
||||||
|
(node) => {
|
||||||
|
if (document.querySelector("#generate-button")) return;
|
||||||
|
const secondLastChild = node.lastChild.previousSibling;
|
||||||
|
popupButton = node.insertBefore(
|
||||||
|
<ReactiveRoot>
|
||||||
|
<div className={secondLastChild.className} id="generate-button">
|
||||||
|
<button
|
||||||
|
onClick={openGenerationModal}
|
||||||
|
className={secondLastChild.firstChild.className}
|
||||||
|
>
|
||||||
|
<div className={secondLastChild.firstChild.firstChild.className}>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 315.8 320"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path d="m294.9 131c7.3-21.8 4.8-45.7-6.9-65.5-17.5-30.4-52.6-46-86.8-38.7-15.2-17.2-37.1-26.9-60.1-26.8-35 0-66.1 22.5-76.9 55.8-22.5 4.6-41.9 18.7-53.3 38.7-17.6 30.3-13.6 68.5 9.9 94.5-7.3 21.8-4.8 45.7 6.9 65.5 17.5 30.4 52.6 46 86.8 38.7 15.2 17.2 37.2 27 60.1 26.8 35.1 0 66.2-22.5 76.9-55.9 22.5-4.6 41.9-18.7 53.3-38.7 17.6-30.3 13.5-68.5-9.9-94.5zm-120.3 168.1c-14 0-27.6-4.9-38.4-13.9.5-.3 1.3-.7 1.9-1.1l63.7-36.8c3.3-1.9 5.3-5.3 5.2-9.1v-89.8l26.9 15.6c.3.1.5.4.5.7v74.4c0 33.1-26.8 59.9-59.9 60zm-128.8-55c-7-12.1-9.6-26.4-7.2-40.2.5.3 1.3.8 1.9 1.1l63.7 36.8c3.2 1.9 7.2 1.9 10.5 0l77.8-44.9v31.1c0 .3-.1.6-.4.8l-64.4 37.2c-28.7 16.5-65.3 6.7-81.9-21.9zm-16.8-139.1c7-12.2 18-21.5 31.2-26.3v2.2 73.6c0 3.7 2 7.2 5.2 9.1l77.8 44.9-26.9 15.6c-.3.2-.6.2-.9 0l-64.4-37.2c-28.6-16.6-38.5-53.2-22-81.9zm221.3 51.5-77.8-44.9 26.9-15.5c.3-.2.6-.2.9 0l64.4 37.2c28.7 16.6 38.5 53.3 21.9 81.9-7 12.1-18 21.4-31.2 26.3v-75.8c0-3.7-2-7.2-5.2-9.1zm26.8-40.3c-.5-.3-1.3-.8-1.9-1.1l-63.7-36.8c-3.2-1.9-7.2-1.9-10.5 0l-77.8 44.9v-31.1c0-.3.1-.6.4-.8l64.4-37.2c28.7-16.5 65.4-6.7 81.9 22 7 12.1 9.5 26.3 7.1 40.1zm-168.5 55.4-26.9-15.6c-.3-.1-.5-.4-.5-.7v-74.4c0-33.1 26.9-60 60-59.9 14 0 27.6 4.9 38.3 13.9-.5.3-1.3.7-1.9 1.1l-63.7 36.8c-3.3 1.8-5.3 5.3-5.2 9.1v89.8s0 0 0 0zm14.6-31.5 34.7-20 34.7 20v40l-34.6 20-34.7-20v-40z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ReactiveRoot>,
|
||||||
|
node.firstChild
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onUnload() {
|
||||||
|
unobserve();
|
||||||
|
popupButton?.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
export { default as settings } from "./settings";
|
||||||
5
plugins/gpt-unslothed/plugin.json
Normal file
5
plugins/gpt-unslothed/plugin.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "gpt-unslothed",
|
||||||
|
"author": "edde746",
|
||||||
|
"description": "Use local language models via Unsloth Studio API to generate messages based on history and a prompt."
|
||||||
|
}
|
||||||
27
plugins/gpt-unslothed/settings.jsx
Normal file
27
plugins/gpt-unslothed/settings.jsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const {
|
||||||
|
plugin: { store },
|
||||||
|
ui: { TextBox, Text },
|
||||||
|
} = shelter;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<>
|
||||||
|
<Text>Unsloth Studio URL</Text>
|
||||||
|
<TextBox
|
||||||
|
placeholder="http://127.0.0.1:8888"
|
||||||
|
value={store.unslothUrl}
|
||||||
|
onInput={(value) => {
|
||||||
|
store.unslothUrl = value;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="mb-2 mt-2">
|
||||||
|
<Text>Unsloth API Key (optional)</Text>
|
||||||
|
<TextBox
|
||||||
|
placeholder="sk-unsloth-..."
|
||||||
|
value={store.unslothKey}
|
||||||
|
onInput={(value) => {
|
||||||
|
store.unslothKey = value;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
1518
pnpm-lock.yaml
generated
Normal file
1518
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
pnpm-workspace.yaml
Normal file
2
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
- plugins/*
|
||||||
BIN
previews/gpt.png
Normal file
BIN
previews/gpt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user