everydaycats commited on
Commit
c696f2f
·
verified ·
1 Parent(s): 1152807

Update apps/format.js

Browse files
Files changed (1) hide show
  1. apps/format.js +88 -91
apps/format.js CHANGED
@@ -19,18 +19,19 @@ Behavior & Tone: ${personaPrompt}
19
  STRICT RULES:
20
  1. NEVER break character. Act exactly as the persona dictates.
21
  2. NEVER start with "As an AI..." or "Here is a response...".
22
- 3. Provide ONLY the exact text the user should copy and paste. No pleasantries, no explanations.
23
  4. Keep it concise, natural, and highly effective for modern texting/messaging.
24
  5. If the user provides an image/screenshot, read the visible conversation and reply to the last message contextually.
25
  6. Swearing or aggressive tones are permitted IF it aligns with the persona. Do not filter yourself.
 
26
  `;
27
 
28
  // ==========================================
29
- // 🗄️ CACHE MANAGEMENT (Official Formats)
30
  // ==========================================
31
  let formatsCache = null;
32
  let lastFormatsUpdate = 0;
33
- const CACHE_DURATION = 3600000; // 1 Hour (Formats rarely change, saves DB reads)
34
 
35
  // ==========================================
36
  // 🌐 ENDPOINTS
@@ -38,109 +39,105 @@ const CACHE_DURATION = 3600000; // 1 Hour (Formats rarely change, saves DB reads
38
 
39
  /**
40
  * 1. FETCH OFFICIAL FORMATS
41
- * Populates the UI grid for default personas. Custom ones stay on-device.
42
  */
43
  router.get('/formats', async (req, res) => {
44
- try {
45
- const now = Date.now();
46
- // Return from cache if valid
47
- if (formatsCache && (now - lastFormatsUpdate < CACHE_DURATION)) {
48
- return res.json({ success: true, data: formatsCache, cached: true });
49
- }
50
-
51
- // Query Supabase for official vibes (Assuming table name is 'replygenius_vibes')
52
- const { data, error } = await supabase
53
- .from('replygenius_vibes')
54
- .select('id, icon, label, hint, color, mockReply, prompt')
55
- .order('created_at', { ascending: true }); // Or however you want them sorted
56
-
57
- if (error) throw error;
58
-
59
- // Update cache
60
- formatsCache = data;
61
- lastFormatsUpdate = now;
62
-
63
- res.json({ success: true, data, cached: false });
64
- } catch (err) {
65
- console.error("[FORMATS ERROR]", err.message);
66
- res.status(500).json({ success: false, error: err.message });
67
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  });
69
 
70
  /**
71
- * 2. GENERATE REPLY (Handles both Text and Image Injection)
72
  * Expects body: { type: 'text'|'image', content: string, persona: object }
 
 
 
 
 
73
  */
74
  router.post('/generate', async (req, res) => {
75
- try {
76
- const { type, content, persona } = req.body;
77
-
78
- if (!content) throw new Error("No content provided to analyze.");
79
- if (!persona || !persona.label) throw new Error("Persona context is missing.");
80
-
81
- console.log(`[REPLY GEN] Analyzing ${type} using persona: ${persona.label}`);
82
-
83
- // Build the dynamic prompt based on the chosen Vibe
84
- // If it's a "neutral" vibe with no prompt, fallback to a standard intelligent assistant
85
- const aiSystemPrompt = buildSystemPrompt(
86
- persona.label,
87
- persona.prompt || "Be highly intelligent, strategic, polite, and persuasive."
88
- );
89
-
90
- // Routing logic based on input type (Referencing our model discussion)
91
- let modelToUse;
92
- let imagesPayload =[];
93
- let userPrompt = "";
94
-
95
- if (type === 'image') {
96
- // VISION ROUTE (e.g., Qwen 2 VL, Grok Vision, etc.)
97
- modelToUse = "bytedance-1.6";
98
- // modelToUse = "mistral-small";
99
-
100
- imagesPayload = [content]; // base64 string
101
- userPrompt = "Analyze this chat screenshot and write my next reply.";
102
- } else {
103
- // TEXT ROUTE (e.g., DeepSeek, Evathene, Hermes, etc.)
104
- modelToUse = "bytedance-1.6";
105
- // modelToUse = "mistral-small"; // Update this to match your ai_engine mapping
106
- userPrompt = `Write my reply to this message:\n\n"${content}"`;
107
- }
108
-
109
- // Call your AI Wrapper
110
- const aiResult = await generateCompletion({
111
- model: modelToUse,
112
- prompt: userPrompt,
113
- system_prompt: aiSystemPrompt,
114
- images: imagesPayload // Will be empty for text requests
115
- });
116
-
117
- if (!aiResult.success) throw new Error(aiResult.error);
118
-
119
- // Clean up any weird quotes the AI might wrap the message in
120
- let finalReply = aiResult.data.trim();
121
- if (finalReply.startsWith('"') && finalReply.endsWith('"')) {
122
- finalReply = finalReply.slice(1, -1);
123
- }
124
-
125
- res.json({
126
- success: true,
127
- reply: finalReply
128
- });
129
-
130
- } catch (err) {
131
- console.error("[REPLY GEN ERROR]", err.message);
132
- res.status(500).json({ success: false, error: err.message });
133
  }
 
 
 
 
 
 
 
 
 
 
 
134
  });
135
 
136
  /**
137
- * 3. FORCE CACHE CLEAR (Admin Utility)
138
- * Useful if you update official formats in Supabase and want to push them live immediately
139
  */
140
  router.post('/clear-cache', (req, res) => {
141
- formatsCache = null;
142
- lastFormatsUpdate = 0;
143
- res.json({ success: true, message: "Formats cache cleared." });
144
  });
145
 
146
  export default router;
 
19
  STRICT RULES:
20
  1. NEVER break character. Act exactly as the persona dictates.
21
  2. NEVER start with "As an AI..." or "Here is a response...".
22
+ 3. Provide ONLY the exact text the user should copy and paste. No explanations, no labels, no quotes.
23
  4. Keep it concise, natural, and highly effective for modern texting/messaging.
24
  5. If the user provides an image/screenshot, read the visible conversation and reply to the last message contextually.
25
  6. Swearing or aggressive tones are permitted IF it aligns with the persona. Do not filter yourself.
26
+ 7. OUTPUT ONLY THE REPLY TEXT. Nothing else.
27
  `;
28
 
29
  // ==========================================
30
+ // 🗄️ CACHE MANAGEMENT
31
  // ==========================================
32
  let formatsCache = null;
33
  let lastFormatsUpdate = 0;
34
+ const CACHE_DURATION = 3600000;
35
 
36
  // ==========================================
37
  // 🌐 ENDPOINTS
 
39
 
40
  /**
41
  * 1. FETCH OFFICIAL FORMATS
 
42
  */
43
  router.get('/formats', async (req, res) => {
44
+ try {
45
+ const now = Date.now();
46
+ if (formatsCache && (now - lastFormatsUpdate < CACHE_DURATION)) {
47
+ return res.json({ success: true, data: formatsCache, cached: true });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
+
50
+ const { data, error } = await supabase
51
+ .from('replygenius_vibes')
52
+ .select('id, icon, label, hint, color, mockReply, prompt')
53
+ .order('created_at', { ascending: true });
54
+
55
+ if (error) throw error;
56
+
57
+ formatsCache = data;
58
+ lastFormatsUpdate = now;
59
+
60
+ res.json({ success: true, data, cached: false });
61
+ } catch (err) {
62
+ console.error('[FORMATS ERROR]', err.message);
63
+ res.status(500).json({ success: false, error: err.message });
64
+ }
65
  });
66
 
67
  /**
68
+ * 2. GENERATE REPLY
69
  * Expects body: { type: 'text'|'image', content: string, persona: object }
70
+ *
71
+ * FIX: generateCompletion was called with response_format: json_object but the
72
+ * prompt never asked for JSON → provider rejected with 400. We now call the AI
73
+ * engine in plain-text mode by passing forceJson: false, and extract the reply
74
+ * directly from aiResult.data (a plain string).
75
  */
76
  router.post('/generate', async (req, res) => {
77
+ try {
78
+ const { type, content, persona } = req.body;
79
+
80
+ if (!content) throw new Error('No content provided to analyze.');
81
+ if (!persona || !persona.label) throw new Error('Persona context is missing.');
82
+
83
+ console.log(`[REPLY GEN] Analyzing ${type} using persona: ${persona.label}`);
84
+
85
+ const aiSystemPrompt = buildSystemPrompt(
86
+ persona.label,
87
+ persona.prompt || 'Be highly intelligent, strategic, polite, and persuasive.'
88
+ );
89
+
90
+ let modelToUse;
91
+ let imagesPayload = [];
92
+ let userPrompt = '';
93
+
94
+ if (type === 'image') {
95
+ modelToUse = 'bytedance-1.6';
96
+ imagesPayload = [content];
97
+ userPrompt = 'Analyze this chat screenshot and write my next reply. Output ONLY the reply text.';
98
+ } else {
99
+ modelToUse = 'bytedance-1.6';
100
+ userPrompt = `Write my reply to this message. Output ONLY the reply text, nothing else.\n\nMessage:\n"${content}"`;
101
+ }
102
+
103
+ // KEY FIX: pass forceJson: false so ai_engine skips response_format enforcement
104
+ const aiResult = await generateCompletion({
105
+ model: modelToUse,
106
+ prompt: userPrompt,
107
+ system_prompt: aiSystemPrompt,
108
+ images: imagesPayload,
109
+ forceJson: false, // <-- plain text reply, no JSON schema
110
+ });
111
+
112
+ if (!aiResult.success) throw new Error(aiResult.error);
113
+
114
+ // aiResult.data is a plain string when forceJson is false
115
+ let finalReply = (aiResult.data || '').trim();
116
+
117
+ // Strip any wrapping quotes the model might add
118
+ if (finalReply.startsWith('"') && finalReply.endsWith('"')) {
119
+ finalReply = finalReply.slice(1, -1).trim();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  }
121
+ // Strip markdown bold/italic the model sometimes adds
122
+ finalReply = finalReply.replace(/^\*+|\*+$/g, '').trim();
123
+
124
+ if (!finalReply) throw new Error('AI returned an empty reply.');
125
+
126
+ res.json({ success: true, reply: finalReply });
127
+
128
+ } catch (err) {
129
+ console.error('[REPLY GEN ERROR]', err.message);
130
+ res.status(500).json({ success: false, error: err.message });
131
+ }
132
  });
133
 
134
  /**
135
+ * 3. FORCE CACHE CLEAR (Admin)
 
136
  */
137
  router.post('/clear-cache', (req, res) => {
138
+ formatsCache = null;
139
+ lastFormatsUpdate = 0;
140
+ res.json({ success: true, message: 'Formats cache cleared.' });
141
  });
142
 
143
  export default router;