caiosilva1221 commited on
Commit
00e32a4
·
verified ·
1 Parent(s): f3c5e82

Update src/components/ask-ai/ask-ai.tsx

Browse files
Files changed (1) hide show
  1. src/components/ask-ai/ask-ai.tsx +45 -35
src/components/ask-ai/ask-ai.tsx CHANGED
@@ -2,10 +2,9 @@
2
  import { useState } from "react";
3
  import { RiSparkling2Fill } from "react-icons/ri";
4
  import { GrSend } from "react-icons/gr";
 
5
  import classNames from "classnames";
6
  import { toast } from "react-toastify";
7
- import { MdPreview } from "react-icons/md";
8
-
9
  import { defaultHTML } from "./../../../utils/consts";
10
  import SuccessSound from "./../../assets/success.mp3";
11
 
@@ -39,26 +38,39 @@ function AskAI({
39
 
40
  let contentResponse = "";
41
  let lastRenderTime = 0;
 
42
  try {
43
  onNewPrompt(prompt);
44
 
45
  const request = await fetch("https://openrouter.ai/api/v1/chat/completions", {
46
  method: "POST",
47
  headers: {
 
48
  "Content-Type": "application/json",
49
- "Authorization": "Bearer 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"
 
50
  },
51
  body: JSON.stringify({
52
- model: "openrouter/auto", // ou outro como deepseek-coder
 
53
  messages: [
54
- { role: "system", content: "Você é um especialista em HTML. Gere apenas código HTML puro, sem explicações." },
55
- { role: "user", content: prompt }
56
- ],
57
- stream: true
 
 
 
 
 
58
  })
59
  });
60
 
61
- if (!request.body) throw new Error("Sem resposta da IA.");
 
 
 
 
62
 
63
  const reader = request.body.getReader();
64
  const decoder = new TextDecoder("utf-8");
@@ -66,7 +78,7 @@ function AskAI({
66
  const read = async () => {
67
  const { done, value } = await reader.read();
68
  if (done) {
69
- toast.success("IA respondeu com sucesso!");
70
  setPrompt("");
71
  setPreviousPrompt(prompt);
72
  setisAiWorking(false);
@@ -80,21 +92,25 @@ function AskAI({
80
  }
81
 
82
  const chunk = decoder.decode(value, { stream: true });
83
- contentResponse += chunk;
84
-
85
- const newHtml = contentResponse.match(/<!DOCTYPE html>[\s\S]*/)?.[0];
86
- if (newHtml) {
87
- let partialDoc = newHtml;
88
- if (!partialDoc.includes("</html>")) partialDoc += "\n</html>";
89
-
90
- const now = Date.now();
91
- if (now - lastRenderTime > 300) {
92
- setHtml(partialDoc);
93
- lastRenderTime = now;
94
- }
95
-
96
- if (partialDoc.length > 200) {
97
- onScrollToBottom();
 
 
 
 
98
  }
99
  }
100
 
@@ -104,7 +120,7 @@ function AskAI({
104
  read();
105
  } catch (error: any) {
106
  setisAiWorking(false);
107
- toast.error(error.message || "Erro ao chamar IA");
108
  }
109
  };
110
 
@@ -125,21 +141,15 @@ function AskAI({
125
  type="text"
126
  disabled={isAiWorking}
127
  className="w-full bg-transparent max-lg:text-sm outline-none px-3 text-white placeholder:text-gray-500 font-code"
128
- placeholder={
129
- hasAsked ? "What do you want to ask AI next?" : "Ask AI anything..."
130
- }
131
  value={prompt}
132
  onChange={(e) => setPrompt(e.target.value)}
133
- onKeyDown={(e) => {
134
- if (e.key === "Enter") {
135
- callAi();
136
- }
137
- }}
138
  />
139
  <div className="flex items-center justify-end gap-2">
140
  <button
141
  disabled={isAiWorking}
142
- className="relative overflow-hidden cursor-pointer flex-none flex items-center justify-center rounded-full text-sm font-semibold size-8 text-center bg-pink-500 hover:bg-pink-400 text-white shadow-sm dark:shadow-highlight/20 disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed disabled:hover:bg-gray-300"
143
  onClick={callAi}
144
  >
145
  <GrSend className="-translate-x-[1px]" />
 
2
  import { useState } from "react";
3
  import { RiSparkling2Fill } from "react-icons/ri";
4
  import { GrSend } from "react-icons/gr";
5
+ import { MdPreview } from "react-icons/md";
6
  import classNames from "classnames";
7
  import { toast } from "react-toastify";
 
 
8
  import { defaultHTML } from "./../../../utils/consts";
9
  import SuccessSound from "./../../assets/success.mp3";
10
 
 
38
 
39
  let contentResponse = "";
40
  let lastRenderTime = 0;
41
+
42
  try {
43
  onNewPrompt(prompt);
44
 
45
  const request = await fetch("https://openrouter.ai/api/v1/chat/completions", {
46
  method: "POST",
47
  headers: {
48
+ "Authorization": "Bearer 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",
49
  "Content-Type": "application/json",
50
+ "HTTP-Referer": "https://raypages.com", // ou o seu domínio
51
+ "X-Title": "RayPages AI"
52
  },
53
  body: JSON.stringify({
54
+ model: "deepseek-chat-v3.0",
55
+ stream: true,
56
  messages: [
57
+ {
58
+ role: "system",
59
+ content: "Você é um especialista em landing pages. Gere um HTML bonito e persuasivo para a copy enviada. Responda apenas com código HTML válido e completo."
60
+ },
61
+ {
62
+ role: "user",
63
+ content: prompt
64
+ }
65
+ ]
66
  })
67
  });
68
 
69
+ if (!request.ok || !request.body) {
70
+ toast.error("Erro ao chamar a IA.");
71
+ setisAiWorking(false);
72
+ return;
73
+ }
74
 
75
  const reader = request.body.getReader();
76
  const decoder = new TextDecoder("utf-8");
 
78
  const read = async () => {
79
  const { done, value } = await reader.read();
80
  if (done) {
81
+ toast.success("Página gerada com sucesso!");
82
  setPrompt("");
83
  setPreviousPrompt(prompt);
84
  setisAiWorking(false);
 
92
  }
93
 
94
  const chunk = decoder.decode(value, { stream: true });
95
+ const matches = chunk.match(/"content":"([^"]*)"/g);
96
+ if (matches) {
97
+ for (const match of matches) {
98
+ const text = match.replace(/"content":"|"/g, "").replace(/\\n/g, "\n").replace(/\\t/g, "\t");
99
+ contentResponse += text;
100
+
101
+ const newHtml = contentResponse.match(/<!DOCTYPE html>[\s\S]*/)?.[0];
102
+ if (newHtml) {
103
+ let partialDoc = newHtml;
104
+ if (!partialDoc.includes("</html>")) partialDoc += "\n</html>";
105
+
106
+ const now = Date.now();
107
+ if (now - lastRenderTime > 300) {
108
+ setHtml(partialDoc);
109
+ lastRenderTime = now;
110
+ }
111
+
112
+ if (partialDoc.length > 200) onScrollToBottom();
113
+ }
114
  }
115
  }
116
 
 
120
  read();
121
  } catch (error: any) {
122
  setisAiWorking(false);
123
+ toast.error("Erro: " + error.message);
124
  }
125
  };
126
 
 
141
  type="text"
142
  disabled={isAiWorking}
143
  className="w-full bg-transparent max-lg:text-sm outline-none px-3 text-white placeholder:text-gray-500 font-code"
144
+ placeholder={hasAsked ? "What do you want to ask AI next?" : "Ask AI anything..."}
 
 
145
  value={prompt}
146
  onChange={(e) => setPrompt(e.target.value)}
147
+ onKeyDown={(e) => { if (e.key === "Enter") callAi(); }}
 
 
 
 
148
  />
149
  <div className="flex items-center justify-end gap-2">
150
  <button
151
  disabled={isAiWorking}
152
+ className="relative overflow-hidden cursor-pointer flex-none flex items-center justify-center rounded-full text-sm font-semibold size-8 text-center bg-pink-500 hover:bg-pink-400 text-white shadow-sm disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed"
153
  onClick={callAi}
154
  >
155
  <GrSend className="-translate-x-[1px]" />