kalhdrawi commited on
Commit
e3c1646
·
1 Parent(s): a96208d

Reupload OmniDev clean version

Browse files
app/api/augment/route.ts CHANGED
@@ -1,6 +1,7 @@
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
  import { NextRequest, NextResponse } from "next/server";
3
  import { GoogleGenAI } from "@google/genai";
 
4
  import { InferenceClient } from "@huggingface/inference";
5
  import type { AugmentRequest, AugmentResponse } from "@/types";
6
 
@@ -27,18 +28,41 @@ Constraints:
27
  - Produce compilable code for the chosen language/framework
28
  `;
29
 
30
- function extractJson(text: string): any {
 
 
 
 
 
 
 
 
31
  try {
32
- return JSON.parse(text);
33
  } catch {
34
- // Try to strip code fences or extraneous text
35
- const start = text.indexOf("{");
36
- const end = text.lastIndexOf("}");
37
- if (start >= 0 && end > start) {
38
- const candidate = text.slice(start, end + 1);
39
- return JSON.parse(candidate);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  }
41
- throw new Error("Model did not return valid JSON");
42
  }
43
  }
44
 
@@ -93,13 +117,14 @@ export async function POST(req: NextRequest) {
93
  text = res.choices?.[0]?.message?.content || "";
94
  }
95
 
96
- if (!text.trim()) {
 
97
  return NextResponse.json({ ok: false, message: "Empty model response" } as AugmentResponse, { status: 500 });
98
  }
99
 
100
  let json: any;
101
  try {
102
- json = extractJson(text);
103
  } catch (e: any) {
104
  return NextResponse.json({ ok: false, message: e?.message || "Invalid JSON from model", raw: text } as any, { status: 500 });
105
  }
@@ -108,6 +133,10 @@ export async function POST(req: NextRequest) {
108
  if (json && json.ok && Array.isArray(json.files)) {
109
  return NextResponse.json(json as AugmentResponse, { status: 200 });
110
  }
 
 
 
 
111
 
112
  return NextResponse.json({ ok: false, message: "Model returned unexpected shape", raw: json } as any, { status: 500 });
113
  } catch (e: any) {
 
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
  import { NextRequest, NextResponse } from "next/server";
3
  import { GoogleGenAI } from "@google/genai";
4
+ import JSON5 from "json5";
5
  import { InferenceClient } from "@huggingface/inference";
6
  import type { AugmentRequest, AugmentResponse } from "@/types";
7
 
 
28
  - Produce compilable code for the chosen language/framework
29
  `;
30
 
31
+ function cleanText(raw: string): string {
32
+ let t = raw || "";
33
+ t = t.replace(/```[a-zA-Z]*\n?/g, "");
34
+ t = t.replace(/```/g, "");
35
+ return t.trim();
36
+ }
37
+
38
+ function tryParseAny(jsonish: string): any {
39
+ // Try strict JSON first
40
  try {
41
+ return JSON.parse(jsonish);
42
  } catch {
43
+ // Relaxed JSON5 parse (handles trailing commas, etc.)
44
+ try {
45
+ // Prefer full string
46
+ return JSON5.parse(jsonish);
47
+ } catch {
48
+ // Try to extract object
49
+ const sObj = jsonish.indexOf("{");
50
+ const eObj = jsonish.lastIndexOf("}");
51
+ if (sObj >= 0 && eObj > sObj) {
52
+ const candidate = jsonish.slice(sObj, eObj + 1);
53
+ try { return JSON.parse(candidate); } catch {}
54
+ try { return JSON5.parse(candidate); } catch {}
55
+ }
56
+ // Try to extract array
57
+ const sArr = jsonish.indexOf("[");
58
+ const eArr = jsonish.lastIndexOf("]");
59
+ if (sArr >= 0 && eArr > sArr) {
60
+ const candidate = jsonish.slice(sArr, eArr + 1);
61
+ try { return JSON.parse(candidate); } catch {}
62
+ try { return JSON5.parse(candidate); } catch {}
63
+ }
64
+ throw new Error("Model did not return valid JSON");
65
  }
 
66
  }
67
  }
68
 
 
117
  text = res.choices?.[0]?.message?.content || "";
118
  }
119
 
120
+ const cleaned = cleanText(text);
121
+ if (!cleaned) {
122
  return NextResponse.json({ ok: false, message: "Empty model response" } as AugmentResponse, { status: 500 });
123
  }
124
 
125
  let json: any;
126
  try {
127
+ json = tryParseAny(cleaned);
128
  } catch (e: any) {
129
  return NextResponse.json({ ok: false, message: e?.message || "Invalid JSON from model", raw: text } as any, { status: 500 });
130
  }
 
133
  if (json && json.ok && Array.isArray(json.files)) {
134
  return NextResponse.json(json as AugmentResponse, { status: 200 });
135
  }
136
+ // If model returned array at root, assume it's files
137
+ if (Array.isArray(json)) {
138
+ return NextResponse.json({ ok: true, files: json } as AugmentResponse, { status: 200 });
139
+ }
140
 
141
  return NextResponse.json({ ok: false, message: "Model returned unexpected shape", raw: json } as any, { status: 500 });
142
  } catch (e: any) {
components/new/scaffold.tsx CHANGED
@@ -6,9 +6,8 @@ import { useRouter } from "next/navigation";
6
  import { Button } from "@/components/ui/button";
7
  import { toast } from "sonner";
8
  import { NEW_STACKS, NewStackId } from "@/lib/new-stacks";
9
- import { HERO_STYLES } from "@/lib/hero-presets";
10
 
11
- function buildInstruction(stack: NewStackId, lang: "js" | "ts", hero: string, title?: string) {
12
  const jsOrTs = lang === 'ts' ? 'TypeScript' : 'JavaScript';
13
  const reactEntry = lang === 'ts' ? "/frontend/src/main.tsx and /frontend/src/App.tsx" : "/frontend/src/main.jsx and /frontend/src/App.jsx";
14
 
@@ -21,7 +20,7 @@ Title: ${title || 'OmniDev Full-Stack App'}
21
  Requirements:
22
  - Frontend under /frontend using React + Vite (${jsOrTs}), TailwindCSS preconfigured.
23
  - Backend under /backend using Express (${jsOrTs}, ESM), with basic routes (GET /, GET /health) and CORS enabled.
24
- - Use a Hero section with style: ${hero}. Keep it performant and accessible.
25
  - Add a minimal README.md at root with start instructions.
26
  - Provide package.json in both /frontend and /backend with scripts to start dev/prod.
27
  - Provide /frontend/index.html and ${reactEntry}.
@@ -36,7 +35,7 @@ Title: ${title || 'OmniDev Next App'}
36
 
37
  Requirements:
38
  - Next.js (${jsOrTs}), App Router, TailwindCSS.
39
- - Implement a landing page with a Hero section style: ${hero}.
40
  - Add /api/health route that returns { ok: true }.
41
  - Provide package.json with dev/build scripts.
42
  - Keep it simple and runnable with \'next dev\'.
@@ -48,7 +47,7 @@ Title: ${title || 'OmniDev Nest + React'}
48
 
49
  Requirements:
50
  - Backend under /backend using NestJS (${jsOrTs}). Generate AppModule, AppController with GET / and GET /health. Enable CORS.
51
- - Frontend under /frontend using React + Vite (${jsOrTs}), TailwindCSS with a modern Hero section style: ${hero}.
52
  - Provide package.json in both apps with start/build scripts.
53
  - Return STRICT JSON ONLY as file updates (no markdown), paths rooted from repo.`;
54
  }
@@ -63,7 +62,6 @@ export default function ScaffoldNew() {
63
  const [logs, setLogs] = useState<string[]>([]);
64
  const [stack, setStack] = useState<NewStackId>("express-react");
65
  const [lang, setLang] = useState<"js" | "ts">("js");
66
- const [hero, setHero] = useState<string>(HERO_STYLES[0].id);
67
  const [title, setTitle] = useState<string>("");
68
 
69
  async function runScaffold() {
@@ -76,7 +74,7 @@ export default function ScaffoldNew() {
76
  setLogs(["Starting scaffold via Augment..."]);
77
  try {
78
  // 1) Call augment to generate full-stack files
79
- const instruction = buildInstruction(stack, lang, hero, title);
80
  const aug = await fetch('/api/augment', {
81
  method: 'POST',
82
  headers: { 'Content-Type': 'application/json' },
@@ -86,8 +84,9 @@ export default function ScaffoldNew() {
86
  language: lang === 'ts' ? 'typescript' : 'javascript',
87
  framework: stack,
88
  response_type: 'file_updates',
89
- model,
90
- provider,
 
91
  }),
92
  }).then(r => r.json());
93
  if (!aug?.ok || !Array.isArray(aug.files) || aug.files.length === 0) {
@@ -141,14 +140,7 @@ export default function ScaffoldNew() {
141
  </select>
142
  <p className="text-xs text-neutral-500 mt-1">{NEW_STACKS.find(s => s.id === stack)?.description}</p>
143
  </div>
144
- <div>
145
- <label className="text-sm block mb-1">Hero Style</label>
146
- <select className="w-full bg-neutral-800 rounded p-2 text-sm" value={hero} onChange={(e) => setHero(e.target.value)}>
147
- {HERO_STYLES.map(h => (
148
- <option key={h.id} value={h.id}>{h.label}</option>
149
- ))}
150
- </select>
151
- </div>
152
  </div>
153
  {error && <p className="text-red-400 text-sm mt-3">{error}</p>}
154
  <ul className="text-sm text-neutral-400 space-y-1 mt-3">
 
6
  import { Button } from "@/components/ui/button";
7
  import { toast } from "sonner";
8
  import { NEW_STACKS, NewStackId } from "@/lib/new-stacks";
 
9
 
10
+ function buildInstruction(stack: NewStackId, lang: "js" | "ts", title?: string) {
11
  const jsOrTs = lang === 'ts' ? 'TypeScript' : 'JavaScript';
12
  const reactEntry = lang === 'ts' ? "/frontend/src/main.tsx and /frontend/src/App.tsx" : "/frontend/src/main.jsx and /frontend/src/App.jsx";
13
 
 
20
  Requirements:
21
  - Frontend under /frontend using React + Vite (${jsOrTs}), TailwindCSS preconfigured.
22
  - Backend under /backend using Express (${jsOrTs}, ESM), with basic routes (GET /, GET /health) and CORS enabled.
23
+ - Create a visually striking Hero section (animated) appropriate to the app, optimized and accessible.
24
  - Add a minimal README.md at root with start instructions.
25
  - Provide package.json in both /frontend and /backend with scripts to start dev/prod.
26
  - Provide /frontend/index.html and ${reactEntry}.
 
35
 
36
  Requirements:
37
  - Next.js (${jsOrTs}), App Router, TailwindCSS.
38
+ - Implement a landing page with an animated Hero section suitable for the domain.
39
  - Add /api/health route that returns { ok: true }.
40
  - Provide package.json with dev/build scripts.
41
  - Keep it simple and runnable with \'next dev\'.
 
47
 
48
  Requirements:
49
  - Backend under /backend using NestJS (${jsOrTs}). Generate AppModule, AppController with GET / and GET /health. Enable CORS.
50
+ - Frontend under /frontend using React + Vite (${jsOrTs}), TailwindCSS with a modern animated Hero section appropriate to the app.
51
  - Provide package.json in both apps with start/build scripts.
52
  - Return STRICT JSON ONLY as file updates (no markdown), paths rooted from repo.`;
53
  }
 
62
  const [logs, setLogs] = useState<string[]>([]);
63
  const [stack, setStack] = useState<NewStackId>("express-react");
64
  const [lang, setLang] = useState<"js" | "ts">("js");
 
65
  const [title, setTitle] = useState<string>("");
66
 
67
  async function runScaffold() {
 
74
  setLogs(["Starting scaffold via Augment..."]);
75
  try {
76
  // 1) Call augment to generate full-stack files
77
+ const instruction = buildInstruction(stack, lang, title);
78
  const aug = await fetch('/api/augment', {
79
  method: 'POST',
80
  headers: { 'Content-Type': 'application/json' },
 
84
  language: lang === 'ts' ? 'typescript' : 'javascript',
85
  framework: stack,
86
  response_type: 'file_updates',
87
+ // Force Gemini for scaffold stage
88
+ model: 'gemini-2.5-flash',
89
+ provider: 'google',
90
  }),
91
  }).then(r => r.json());
92
  if (!aug?.ok || !Array.isArray(aug.files) || aug.files.length === 0) {
 
140
  </select>
141
  <p className="text-xs text-neutral-500 mt-1">{NEW_STACKS.find(s => s.id === stack)?.description}</p>
142
  </div>
143
+ {/* Hero selection removed: AI decides the best hero automatically */}
 
 
 
 
 
 
 
144
  </div>
145
  {error && <p className="text-red-400 text-sm mt-3">{error}</p>}
146
  <ul className="text-sm text-neutral-400 space-y-1 mt-3">
package-lock.json CHANGED
@@ -34,6 +34,7 @@
34
  "clsx": "^2.1.1",
35
  "date-fns": "^4.1.0",
36
  "framer-motion": "^12.23.22",
 
37
  "log4js": "^6.9.1",
38
  "log4js-json-layout": "^2.2.3",
39
  "lucide-react": "^0.542.0",
 
34
  "clsx": "^2.1.1",
35
  "date-fns": "^4.1.0",
36
  "framer-motion": "^12.23.22",
37
+ "json5": "^2.2.3",
38
  "log4js": "^6.9.1",
39
  "log4js-json-layout": "^2.2.3",
40
  "lucide-react": "^0.542.0",
package.json CHANGED
@@ -8,6 +8,7 @@
8
  "start": "next start"
9
  },
10
  "dependencies": {
 
11
  "@google/genai": "^0.11.0",
12
  "mime": "^4.0.4",
13
  "@huggingface/hub": "^2.6.2",
 
8
  "start": "next start"
9
  },
10
  "dependencies": {
11
+ "json5": "^2.2.3",
12
  "@google/genai": "^0.11.0",
13
  "mime": "^4.0.4",
14
  "@huggingface/hub": "^2.6.2",