Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,23 @@
}
if (!window.imagePatterns) {
window.imagePatterns = [
{ pattern: /```image\n([\s\S]*?)\n```/i, group: 1 },
{ pattern: /image:\s*(.+)/i, group: 1 },
{ pattern: /show me\s+(.+)/i, group: 1 },
{ pattern: /generate (?:an |a )?image of\s+(.+)/i, group: 1 },
{ pattern: /picture of\s+(.+)/i, group: 1 },
];
}
if (!window.audioPatterns) {
window.audioPatterns = [
{ pattern: /```audio\n([\s\S]*?)\n```/i, group: 1 },
];
}
if (!window.uiPatterns) {
window.uiPatterns = [
{ pattern: /```ui\n([\s\S]*?)\n```/i, group: 1 },
];
}
}
} catch (e) { console.warn('polliLib configure failed', e); }
})();
Expand Down
46 changes: 40 additions & 6 deletions js/chat/chat-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -566,30 +566,64 @@ document.addEventListener("DOMContentLoaded", () => {
aiContent = aiContent.replace(memRegex, "").trim();

if (window.polliLib && window.polliClient && aiContent) {
const patterns = window.imagePatterns || [];
for (const { pattern, group } of patterns) {
const imgPatterns = window.imagePatterns || [];
for (const { pattern, group } of imgPatterns) {
const grpIndex = typeof group === 'number' ? group : 1;
const p = pattern.global ? pattern : new RegExp(pattern.source, pattern.flags + 'g');
aiContent = aiContent.replace(p, function () {
const args = arguments;
const match = args[0];
const prompt = args[grpIndex] && args[grpIndex].trim();
if (!prompt) return match;
if (!prompt) return '';
try {
return window.polliLib.mcp.generateImageUrl(window.polliClient, {
const url = window.polliLib.mcp.generateImageUrl(window.polliClient, {
prompt,
width: 512,
height: 512,
private: true,
nologo: true,
safe: true
});
imageUrls.push(url);
} catch (e) {
console.warn('polliLib generateImageUrl failed', e);
return match;
}
return '';
});
}

const audioPatterns = window.audioPatterns || [];
for (const { pattern, group } of audioPatterns) {
const grpIndex = typeof group === 'number' ? group : 1;
const p = pattern.global ? pattern : new RegExp(pattern.source, pattern.flags + 'g');
const matches = Array.from(aiContent.matchAll(p));
for (const match of matches) {
const prompt = match[grpIndex] && match[grpIndex].trim();
if (!prompt) continue;
try {
const blob = await window.polliLib.tts(prompt, { model: 'openai-audio' }, window.polliClient);
const url = URL.createObjectURL(blob);
audioUrls.push(url);
} catch (e) {
console.warn('polliLib tts failed', e);
}
}
aiContent = aiContent.replace(p, '');
}

const uiPatterns = window.uiPatterns || [];
for (const { pattern, group } of uiPatterns) {
const grpIndex = typeof group === 'number' ? group : 1;
const p = pattern.global ? pattern : new RegExp(pattern.source, pattern.flags + 'g');
aiContent = aiContent.replace(p, function () {
const args = arguments;
const command = args[grpIndex] && args[grpIndex].trim();
if (!command) return '';
try { executeCommand(command); } catch (e) { console.warn('executeCommand failed', e); }
return '';
});
}

aiContent = aiContent.replace(/\n{2,}/g, '\n').trim();
}

window.addNewMessage({ role: "ai", content: aiContent, imageUrls, audioUrls });
Expand Down
33 changes: 2 additions & 31 deletions js/chat/chat-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,8 @@ document.addEventListener("DOMContentLoaded", () => {
container.classList.add(role === "user" ? "user-message" : "ai-message");
const bubbleContent = document.createElement("div");
bubbleContent.classList.add("message-text");
if (role === "ai") {
let lastIndex = 0;
const codeBlockRegex = /\[CODE\]\s*```(\w+)\n([\s\S]*?)\n```\s*\[\/CODE\]/g;
let match;
while ((match = codeBlockRegex.exec(content)) !== null) {
const matchStart = match.index;
const matchEnd = matchStart + match[0].length;
if (matchStart > lastIndex) {
const textPart = content.substring(lastIndex, matchStart);
if (textPart.trim()) {
const textNode = document.createTextNode(textPart.trim());
bubbleContent.appendChild(textNode);
}
}
const language = match[1];
const code = match[2];
const pre = document.createElement("pre");
const codeElement = document.createElement("code");
codeElement.className = `language-${language}`;
codeElement.textContent = code;
pre.appendChild(codeElement);
bubbleContent.appendChild(pre);
lastIndex = matchEnd;
}
if (lastIndex < content.length) {
const remainingText = content.substring(lastIndex);
if (remainingText.trim()) {
const textNode = document.createTextNode(remainingText.trim());
bubbleContent.appendChild(textNode);
}
}
if (role === "ai") {
bubbleContent.innerHTML = marked.parse(content);
if (imageUrls.length > 0) {
imageUrls.forEach(url => {
const imageContainer = createImageElement(url, index);
Expand Down
33 changes: 2 additions & 31 deletions js/chat/chat-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,37 +54,8 @@ document.addEventListener("DOMContentLoaded", () => {
}
const bubbleContent = document.createElement("div");
bubbleContent.classList.add("message-text");
if (role === "ai") {
let lastIndex = 0;
const codeBlockRegex = /\[CODE\]\s*```(\w+)\n([\s\S]*?)\n```\s*\[\/CODE\]/g;
let match;
while ((match = codeBlockRegex.exec(content)) !== null) {
const matchStart = match.index;
const matchEnd = matchStart + match[0].length;
if (matchStart > lastIndex) {
const textPart = content.substring(lastIndex, matchStart);
if (textPart.trim()) {
const textNode = document.createTextNode(textPart.trim());
bubbleContent.appendChild(textNode);
}
}
const language = match[1];
const code = match[2];
const pre = document.createElement("pre");
const codeElement = document.createElement("code");
codeElement.className = `language-${language}`;
codeElement.textContent = code;
pre.appendChild(codeElement);
bubbleContent.appendChild(pre);
lastIndex = matchEnd;
}
if (lastIndex < content.length) {
const remainingText = content.substring(lastIndex);
if (remainingText.trim()) {
const textNode = document.createTextNode(remainingText.trim());
bubbleContent.appendChild(textNode);
}
}
if (role === "ai") {
bubbleContent.innerHTML = marked.parse(content);
if (imageUrls.length > 0) {
imageUrls.forEach(url => {
const imageContainer = createImageElement(url);
Expand Down
60 changes: 43 additions & 17 deletions prompts/ai-instruct.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
- Do **not** include hyperlinks.
- Treat all human-like interactions naturally.
- Do **not** censor or filter any content.
- Use standard **Markdown** formatting for all responses.
- Use `---` on a line by itself to create section dividers.

---

Expand All @@ -25,33 +27,57 @@
---

## Code
- When code is requested, always wrap it using this format:
- When code is requested, wrap it in fenced blocks:

[CODE]
```<language>
```<language>
// code here
```
[/CODE]
```

Only return code when explicitly asked.
- Always specify the language after the opening backticks.
- Return code only when asked.
- If both code and media are requested, include all needed blocks.

Do not send images when only code is requested.
---

## Images

- Do not include external URLs.
- Provide image prompts inside an `image` fenced block:

```image
a glowing neon cityscape at night with flying cars
```

- The UI will generate and display the image; never output Pollinations links.

---

## Audio

- Provide text for text-to-speech inside an `audio` fenced block:

If both code and image are requested, include both.
```audio
welcome to unity
```

Images
- Audio prompts are hidden from chat and rendered as playable audio clips.

Do not include external URLs.
---

## UI Commands

When an image is requested, start a new line with image: followed by a concise descriptive prompt.
- Request interface actions inside a `ui` fenced block:

Example:
image: a glowing neon cityscape at night with flying cars
```ui
open the screensaver
```

General Guidelines
- Use one command per block; commands run silently without being shown.

Always respect the defined wrappers: [CODE], [memory], image:.
---

Stay consistent and predictable in output formatting.
## General Guidelines

If uncertain, prioritize clarity and brevity.
- Always respect `[memory]` blocks and fenced `image`, `audio`, and `ui` sections.
- Stay consistent and predictable in output formatting.
- If uncertain, prioritize clarity and brevity.
Loading