-
-
Notifications
You must be signed in to change notification settings - Fork 235
Expand file tree
/
Copy path_shared.ts
More file actions
163 lines (139 loc) · 4.74 KB
/
_shared.ts
File metadata and controls
163 lines (139 loc) · 4.74 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import { z } from "zod";
import { streamText } from "ai";
import { stripe } from "../_lib/_stripe";
import { kv } from "@vercel/kv";
import { Ratelimit } from "@upstash/ratelimit";
export const reqSchema = z.object({
prompt: z.string().min(1),
document: z.string(),
});
async function checkUserStatus(req: Request) {
let isPro = false;
let customerId: null | string = null;
const token = req.headers.get("Authorization");
if (token) {
const sid = token.split(" ")[1];
const sub = await stripe.subscriptions.retrieve(sid);
if (sub.status === "active" || sub.status === "trialing") {
isPro = true;
customerId = sub.customer as string;
}
}
return { isPro, customerId };
}
export async function handleRateLimit(
req: Request,
isPro: boolean,
customerId: string | null
) {
const ip = getIp(req);
const ratelimit = new Ratelimit({
redis: kv,
limiter: isPro
? Ratelimit.slidingWindow(3, "1m")
: Ratelimit.fixedWindow(2, "30d"),
});
const rateLimitKey = isPro ? `pro_${customerId}` : `unauth_${ip}`;
const { success, limit, reset, remaining } = await ratelimit.limit(
rateLimitKey
);
if (!success) {
return new Response("You have reached your request limit.", {
status: 429,
headers: {
"X-RateLimit-Limit": limit.toString(),
"X-RateLimit-Remaining": remaining.toString(),
"X-RateLimit-Reset": reset.toString(),
},
});
}
return null;
}
/**
* Rate limit for template requests
*/
export async function templateRateLimit(req: Request) {
const ip = getIp(req);
const ratelimit = new Ratelimit({
redis: kv,
limiter: Ratelimit.slidingWindow(3, "1m"),
});
const rateLimitKey = `template_${ip}`;
const { success, limit, reset, remaining } = await ratelimit.limit(
rateLimitKey
);
if (!success) {
return new Response("You have reached your request limit for templates.", {
status: 429,
headers: {
"X-RateLimit-Limit": limit.toString(),
"X-RateLimit-Remaining": remaining.toString(),
"X-RateLimit-Reset": reset.toString(),
},
});
}
return null;
}
export const DEFAULT_MODEL = "openai/gpt-oss-120b";
export const GATEWAY_OPTIONS = {
gateway: {
order: ["cerebras"],
},
};
export async function processRequest(
req: Request,
systemMessage: string,
content: string,
model: string = DEFAULT_MODEL
) {
const { isPro, customerId } = await checkUserStatus(req);
const rateLimitResponse = await handleRateLimit(req, isPro, customerId);
if (rateLimitResponse) return rateLimitResponse;
const result = streamText({
model,
system: systemMessage,
temperature: 0.1,
providerOptions: GATEWAY_OPTIONS,
messages: [
{
role: "user",
content,
},
],
});
return result.toTextStreamResponse();
}
function getIp(req: Request) {
return (
req.headers.get("x-real-ip") ||
req.headers.get("cf-connecting-ip") ||
req.headers.get("x-forwarded-for") ||
req.headers.get("x-client-ip") ||
req.headers.get("x-cluster-client-ip") ||
req.headers.get("forwarded-for") ||
req.headers.get("forwarded") ||
req.headers.get("via") ||
req.headers.get("x-forwarded") ||
req.headers.get
);
}
export const systemMessageStyle = `You can style nodes using classes at the end of a node. Available styles include:
- Colors: .color_blue, .color_red, .color_green, .color_yellow, .color_orange
- Shapes: .shape_circle, .shape_diamond, .shape_ellipse, .shape_right-rhomboid`;
export const systemMessageExample = `Node A
Node B .shape_circle
\\(Secret Node)
Node C
label from c to d: Node D .color_green.shape_diamond
label from d to a: (Node A)`;
export const systemMessageSyntax = `Flowchart Fun Syntax:
- Indentation creates parent→child edges (tree-shaped graph).
- Text before a colon labels the edge: "yes: Next Step" creates an edge labeled "yes".
- Reference a previously declared node by wrapping its label in parentheses: (Node Name).
- Escape these characters in node/edge labels: ( ) : # . \\
- Style nodes with classes at the end: Node A .color_blue.shape_diamond`;
export const systemMessagePitfalls = `Common mistakes to avoid:
- NEVER start a line with an edge label at the root level (no indentation). "start: Node A" on the first line is invalid because there is no parent node to draw an edge from. Create the source node first, then indent the labeled edge beneath it.
- Only reference nodes that have already been declared above. (Node X) is invalid if Node X has not appeared yet.
- Indentation must be consistent. Use spaces (not tabs). Each indent level adds children to the nearest less-indented node above.
- Do NOT wrap your output in markdown code fences (\`\`\`). Return raw Flowchart Fun syntax only.`;