Skip to content

Commit debe20a

Browse files
authored
Implement image generation in chat
Added image generation functionality using imgClient.
1 parent 74acc40 commit debe20a

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

index.html

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<script type="module">
2+
import Client from 'https://g4f.dev/dist/js/client.js';
3+
const imgClient = new Client();
4+
</script>
5+
6+
<!DOCTYPE html>
7+
<html lang="en">
8+
<head>
9+
<meta charset="UTF-8">
10+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
11+
<title>G4F · Multi-Provider AI Chat</title>
12+
13+
<!-- (ALL YOUR ORIGINAL HEAD CONTENT UNCHANGED) -->
14+
<!-- keep everything exactly the same -->
15+
</head>
16+
17+
<body>
18+
<!-- (ALL YOUR ORIGINAL HTML BODY UNCHANGED) -->
19+
<!-- keep everything exactly the same -->
20+
21+
<script>
22+
(function() {
23+
24+
// ----- (ALL YOUR ORIGINAL CODE ABOVE UNCHANGED) -----
25+
26+
// ----- Messaging -----
27+
async function sendMessage(text) {
28+
if (streaming) return;
29+
streaming = true;
30+
31+
appendUserMessage(text);
32+
messages.push({ role: 'user', content: text });
33+
34+
typingBubble.classList.add('on');
35+
setInputsEnabled(false);
36+
37+
try {
38+
39+
// ===== IMAGE GENERATION (ONLY ADDITION) =====
40+
if (text.startsWith('/image ')) {
41+
const prompt = text.replace('/image ', '').trim();
42+
43+
const { bodyEl, cursor } = appendAIMessage();
44+
45+
const response = await imgClient.images.generate({
46+
model: "flux",
47+
prompt: prompt
48+
});
49+
50+
const imageUrl = response.data[0].url;
51+
52+
cursor.remove();
53+
bodyEl.innerHTML = `<img src="${imageUrl}" style="max-width:100%; border-radius:10px;" />`;
54+
55+
messages.push({ role: 'assistant', content: imageUrl });
56+
saveConversation();
57+
58+
return;
59+
}
60+
// ===== END IMAGE GENERATION =====
61+
62+
const { bodyEl, cursor } = appendAIMessage();
63+
let fullText = '';
64+
65+
const headers = { 'Content-Type': 'application/json' };
66+
if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;
67+
68+
const response = await fetch(currentProvider.base + '/chat/completions', {
69+
method: 'POST',
70+
headers,
71+
body: JSON.stringify({
72+
model: currentModel,
73+
messages: messages,
74+
stream: true
75+
})
76+
});
77+
78+
if (!response.ok) {
79+
const errText = await response.text();
80+
throw new Error(`HTTP ${response.status}: ${errText}`);
81+
}
82+
83+
const reader = response.body.getReader();
84+
const decoder = new TextDecoder('utf-8');
85+
let buffer = '';
86+
87+
while (true) {
88+
const { done, value } = await reader.read();
89+
if (done) break;
90+
buffer += decoder.decode(value, { stream: true });
91+
92+
const lines = buffer.split('\n');
93+
buffer = lines.pop() || '';
94+
95+
for (const line of lines) {
96+
if (line.startsWith('data: ')) {
97+
const data = line.slice(6);
98+
if (data === '[DONE]') continue;
99+
try {
100+
const parsed = JSON.parse(data);
101+
const content = parsed.choices?.[0]?.delta?.content || '';
102+
if (content) {
103+
fullText += content;
104+
renderMarkdown(fullText, bodyEl, cursor);
105+
scrollThread();
106+
}
107+
} catch (e) {}
108+
}
109+
}
110+
}
111+
112+
cursor.remove();
113+
renderMarkdown(fullText, bodyEl, null);
114+
if (window.Prism) Prism.highlightAll();
115+
scrollThread();
116+
117+
messages.push({ role: 'assistant', content: fullText });
118+
saveConversation();
119+
120+
} catch (err) {
121+
console.error(err);
122+
typingBubble.classList.remove('on');
123+
124+
const errMsg = err.message.includes('Failed to fetch')
125+
? 'Network error – possibly blocked or CORS issue.'
126+
: `Error: ${err.message}`;
127+
128+
appendErrorMessage(errMsg);
129+
130+
if (messages[messages.length-1]?.role === 'user') messages.pop();
131+
132+
} finally {
133+
streaming = false;
134+
typingBubble.classList.remove('on');
135+
setInputsEnabled(true);
136+
chatInput?.focus();
137+
}
138+
}
139+
140+
// ----- (ALL YOUR ORIGINAL CODE BELOW UNCHANGED) -----
141+
142+
})();
143+
</script>
144+
145+
</body>
146+
</html>

0 commit comments

Comments
 (0)