-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathserver.js
More file actions
142 lines (124 loc) · 4.08 KB
/
server.js
File metadata and controls
142 lines (124 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
require("dotenv").config();
const express = require("express");
const multer = require("multer");
const axios = require("axios");
const cors = require("cors");
const rateLimit = require("express-rate-limit");
const app = express();
app.set("trust proxy", 1);
const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 5 * 1024 * 1024 },
fileFilter: (req, file, cb) => {
if (!file.mimetype.startsWith("image/")) {
return cb(new Error("Only image files are allowed"));
}
cb(null, true);
},
});
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 10,
message: {
error: "Too many requests. Please try again later.",
},
handler: (req, res, next, options) => {
console.warn(`Rate limit exceeded from IP: ${req.ip}`);
res.status(429).json(options.message);
},
});
app.use(
cors({
origin: "https://codeforces-project.vercel.app",
})
);
app.use(express.json());
app.use("/analyze-food", limiter);
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY;
const ANALYSIS_PROMPT = `
**IMPORTANT:**
1. **Start your response with:** "Rating: X/10" where X is the rating.
**Review the food label and consider the following:**
- Macronutrient balance (protein, carbs, fats)
- Whole foods vs processed ingredients
- Additives, preservatives, and artificial ingredients
- Added sugars (hidden sugars like glucose syrup, fructose)
- Common allergens (e.g., nuts, soy, gluten)
- Fiber content and digestive health
- Claims vs reality (e.g., "high protein" but low protein per serving)
- Misleading marketing tactics (e.g., "natural" but contains artificial preservatives)
**Recommendation:** Should the user eat this regularly, occasionally, or avoid it?
`;
app.post("/analyze-food", upload.single("image"), async (req, res) => {
try {
if (!req.file) return res.status(400).json({ error: "No file uploaded" });
const imageBase64 = req.file.buffer.toString("base64");
const extractionResponse = await axios.post(
"https://openrouter.ai/api/v1/chat/completions",
{
model: "qwen/qwen2.5-vl-72b-instruct:free",
messages: [
{
role: "user",
content: [
{ type: "text", text: "Extract the food label details in a plain text format." },
{
type: "image_url",
image_url: { url: `data:image/jpeg;base64,${imageBase64}` },
},
],
},
],
temperature: 0.1,
max_tokens: 2000,
},
{
headers: {
Authorization: `Bearer ${OPENROUTER_API_KEY}`,
},
}
);
const choices = extractionResponse.data.choices;
if (!choices || choices.length === 0) {
return res.status(500).json({ error: "Failed to extract text from image" });
}
const extractedText = choices[0].message.content;
const analysisResponse = await axios.post(
"https://openrouter.ai/api/v1/chat/completions",
{
model: "meta-llama/llama-3.3-70b-instruct:free",
messages: [
{
role: "user",
content: `${ANALYSIS_PROMPT}\n\nFood Label Details:\n${extractedText}`,
},
],
temperature: 0.3,
max_tokens: 500,
},
{
headers: {
Authorization: `Bearer ${OPENROUTER_API_KEY}`,
},
}
);
const analysisText = analysisResponse.data.choices[0].message.content;
res.json({
analysis: analysisText,
});
} catch (error) {
console.error("Error in pipeline:", error.response?.data || error.message);
if (error.message.includes("File too large")) {
return res.status(413).json({ error: "Uploaded file is too large. Max: 5MB" });
}
if (error.message.includes("Only image files are allowed")) {
return res.status(415).json({ error: "Unsupported file type. Only images allowed." });
}
res.status(500).json({
error: "Analysis failed",
details: error.response?.data || error.message,
});
}
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));