Add UX Designer Prompt feature and update Ollama models
- Add comprehensive Ollama Cloud API models list - Add generateUXDesignerPrompt method to OllamaCloudService - Add generateUXDesignerPrompt method to ZaiPlanService - Add generateUXDesignerPrompt to ModelAdapter - Create UXDesignerPrompt component with detailed prompt generation - Add UX Designer Prompt view to Sidebar - Update page.tsx to render UXDesignerPrompt component
This commit is contained in:
55
app/page.tsx
55
app/page.tsx
@@ -1,66 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import Sidebar from "@/components/Sidebar";
|
import Sidebar from "@/components/Sidebar";
|
||||||
import type { View } from "@/components/Sidebar";
|
import type { View } from "@/components/Sidebar";
|
||||||
import PromptEnhancer from "@/components/PromptEnhancer";
|
import PromptEnhancer from "@/components/PromptEnhancer";
|
||||||
import PRDGenerator from "@/components/PRDGenerator";
|
import PRDGenerator from "@/components/PRDGenerator";
|
||||||
import ActionPlanGenerator from "@/components/ActionPlanGenerator";
|
import ActionPlanGenerator from "@/components/ActionPlanGenerator";
|
||||||
|
import UXDesignerPrompt from "@/components/UXDesignerPrompt";
|
||||||
import HistoryPanel from "@/components/HistoryPanel";
|
import HistoryPanel from "@/components/HistoryPanel";
|
||||||
import SettingsPanel from "@/components/SettingsPanel";
|
import SettingsPanel from "@/components/SettingsPanel";
|
||||||
import useStore from "@/lib/store";
|
|
||||||
import modelAdapter from "@/lib/services/adapter-instance";
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [currentView, setCurrentView] = useState<View>("enhance");
|
const [currentView, setCurrentView] = useState<View>("enhance");
|
||||||
const { setQwenTokens, setApiKey } = useStore();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Handle OAuth callback
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
const code = urlParams.get("code");
|
|
||||||
|
|
||||||
if (code) {
|
|
||||||
// In a real app, you would exchange the code for tokens here
|
|
||||||
// Since we don't have a backend or real client secret, we'll simulate it
|
|
||||||
console.log("OAuth code received:", code);
|
|
||||||
|
|
||||||
// Mock token exchange
|
|
||||||
const mockAccessToken = "mock_access_token_" + Math.random().toString(36).substr(2, 9);
|
|
||||||
const tokens = {
|
|
||||||
accessToken: mockAccessToken,
|
|
||||||
expiresAt: Date.now() + 3600 * 1000, // 1 hour
|
|
||||||
};
|
|
||||||
|
|
||||||
setQwenTokens(tokens);
|
|
||||||
modelAdapter.setQwenOAuthTokens(tokens.accessToken, undefined, 3600);
|
|
||||||
|
|
||||||
// Save to localStorage
|
|
||||||
localStorage.setItem("promptarch-qwen-tokens", JSON.stringify(tokens));
|
|
||||||
|
|
||||||
// Clear the code from URL
|
|
||||||
window.history.replaceState({}, document.title, window.location.pathname);
|
|
||||||
|
|
||||||
// Switch to settings to show success (optional)
|
|
||||||
setCurrentView("settings");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load tokens from localStorage on init
|
|
||||||
const savedTokens = localStorage.getItem("promptarch-qwen-tokens");
|
|
||||||
if (savedTokens) {
|
|
||||||
try {
|
|
||||||
const tokens = JSON.parse(savedTokens);
|
|
||||||
if (tokens.expiresAt > Date.now()) {
|
|
||||||
setQwenTokens(tokens);
|
|
||||||
modelAdapter.setQwenOAuthTokens(tokens.accessToken, tokens.refreshToken, (tokens.expiresAt - Date.now()) / 1000);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to load Qwen tokens:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
switch (currentView) {
|
switch (currentView) {
|
||||||
@@ -70,6 +21,8 @@ export default function Home() {
|
|||||||
return <PRDGenerator />;
|
return <PRDGenerator />;
|
||||||
case "action":
|
case "action":
|
||||||
return <ActionPlanGenerator />;
|
return <ActionPlanGenerator />;
|
||||||
|
case "uxdesigner":
|
||||||
|
return <UXDesignerPrompt />;
|
||||||
case "history":
|
case "history":
|
||||||
return <HistoryPanel />;
|
return <HistoryPanel />;
|
||||||
case "settings":
|
case "settings":
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import useStore from "@/lib/store";
|
import useStore from "@/lib/store";
|
||||||
import { Sparkles, FileText, ListTodo, Settings, History } from "lucide-react";
|
import { Sparkles, FileText, ListTodo, Palette, History, Settings } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type View = "enhance" | "prd" | "action" | "history" | "settings";
|
export type View = "enhance" | "prd" | "action" | "uxdesigner" | "history" | "settings";
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
currentView: View;
|
currentView: View;
|
||||||
@@ -19,6 +19,7 @@ export default function Sidebar({ currentView, onViewChange }: SidebarProps) {
|
|||||||
{ id: "enhance" as View, label: "Prompt Enhancer", icon: Sparkles },
|
{ id: "enhance" as View, label: "Prompt Enhancer", icon: Sparkles },
|
||||||
{ id: "prd" as View, label: "PRD Generator", icon: FileText },
|
{ id: "prd" as View, label: "PRD Generator", icon: FileText },
|
||||||
{ id: "action" as View, label: "Action Plan", icon: ListTodo },
|
{ id: "action" as View, label: "Action Plan", icon: ListTodo },
|
||||||
|
{ id: "uxdesigner" as View, label: "UX Designer Prompt", icon: Palette },
|
||||||
{ id: "history" as View, label: "History", icon: History, count: history.length },
|
{ id: "history" as View, label: "History", icon: History, count: history.length },
|
||||||
{ id: "settings" as View, label: "Settings", icon: Settings },
|
{ id: "settings" as View, label: "Settings", icon: Settings },
|
||||||
];
|
];
|
||||||
@@ -81,6 +82,7 @@ export default function Sidebar({ currentView, onViewChange }: SidebarProps) {
|
|||||||
<li>• Use different providers for best results</li>
|
<li>• Use different providers for best results</li>
|
||||||
<li>• Copy enhanced prompts to your AI agent</li>
|
<li>• Copy enhanced prompts to your AI agent</li>
|
||||||
<li>• PRDs generate better action plans</li>
|
<li>• PRDs generate better action plans</li>
|
||||||
|
<li>• UX Designer Prompt for design tasks</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
242
components/UXDesignerPrompt.tsx
Normal file
242
components/UXDesignerPrompt.tsx
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import useStore from "@/lib/store";
|
||||||
|
import modelAdapter from "@/lib/services/adapter-instance";
|
||||||
|
import { Palette, Copy, Loader2, CheckCircle2, Settings } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
export default function UXDesignerPrompt() {
|
||||||
|
const {
|
||||||
|
currentPrompt,
|
||||||
|
selectedProvider,
|
||||||
|
selectedModels,
|
||||||
|
availableModels,
|
||||||
|
apiKeys,
|
||||||
|
isProcessing,
|
||||||
|
error,
|
||||||
|
setSelectedProvider,
|
||||||
|
setCurrentPrompt,
|
||||||
|
setEnhancedPrompt,
|
||||||
|
setProcessing,
|
||||||
|
setError,
|
||||||
|
setAvailableModels,
|
||||||
|
setSelectedModel,
|
||||||
|
} = useStore();
|
||||||
|
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
const [generatedPrompt, setGeneratedPrompt] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const selectedModel = selectedModels[selectedProvider];
|
||||||
|
const models = availableModels[selectedProvider] || modelAdapter.getAvailableModels(selectedProvider);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
loadAvailableModels();
|
||||||
|
const saved = localStorage.getItem("promptarch-api-keys");
|
||||||
|
if (saved) {
|
||||||
|
try {
|
||||||
|
const keys = JSON.parse(saved);
|
||||||
|
if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama);
|
||||||
|
if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to load API keys:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedProvider]);
|
||||||
|
|
||||||
|
const loadAvailableModels = async () => {
|
||||||
|
const fallbackModels = modelAdapter.getAvailableModels(selectedProvider);
|
||||||
|
setAvailableModels(selectedProvider, fallbackModels);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await modelAdapter.listModels(selectedProvider);
|
||||||
|
if (result.success && result.data) {
|
||||||
|
setAvailableModels(selectedProvider, result.data[selectedProvider] || fallbackModels);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to load models:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGenerate = async () => {
|
||||||
|
if (!currentPrompt.trim()) {
|
||||||
|
setError("Please enter an app description");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiKey = apiKeys[selectedProvider];
|
||||||
|
if (!apiKey || !apiKey.trim()) {
|
||||||
|
setError(`Please configure your ${selectedProvider.toUpperCase()} API key in Settings`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setProcessing(true);
|
||||||
|
setError(null);
|
||||||
|
setGeneratedPrompt(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await modelAdapter.generateUXDesignerPrompt(currentPrompt, selectedProvider, selectedModel);
|
||||||
|
|
||||||
|
if (result.success && result.data) {
|
||||||
|
setGeneratedPrompt(result.data);
|
||||||
|
setEnhancedPrompt(result.data);
|
||||||
|
} else {
|
||||||
|
setError(result.error || "Failed to generate UX designer prompt");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err.message : "An error occurred");
|
||||||
|
} finally {
|
||||||
|
setProcessing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCopy = async () => {
|
||||||
|
if (generatedPrompt) {
|
||||||
|
await navigator.clipboard.writeText(generatedPrompt);
|
||||||
|
setCopied(true);
|
||||||
|
setTimeout(() => setCopied(false), 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClear = () => {
|
||||||
|
setCurrentPrompt("");
|
||||||
|
setGeneratedPrompt(null);
|
||||||
|
setEnhancedPrompt(null);
|
||||||
|
setError(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-auto grid max-w-7xl gap-6 lg:grid-cols-2">
|
||||||
|
<Card className="h-fit">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center gap-2">
|
||||||
|
<Palette className="h-5 w-5" />
|
||||||
|
UX Designer Prompt
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Describe your app idea and get the BEST EVER prompt for UX design
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">AI Provider</label>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{(["ollama", "zai"] as const).map((provider) => (
|
||||||
|
<Button
|
||||||
|
key={provider}
|
||||||
|
variant={selectedProvider === provider ? "default" : "outline"}
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setSelectedProvider(provider)}
|
||||||
|
className={cn(
|
||||||
|
"capitalize",
|
||||||
|
selectedProvider === provider && "bg-primary text-primary-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{provider === "ollama" ? "Ollama" : "Z.AI"}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">Model</label>
|
||||||
|
<select
|
||||||
|
value={selectedModel}
|
||||||
|
onChange={(e) => setSelectedModel(selectedProvider, e.target.value)}
|
||||||
|
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
|
>
|
||||||
|
{models.map((model) => (
|
||||||
|
<option key={model} value={model}>
|
||||||
|
{model}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">App Description</label>
|
||||||
|
<Textarea
|
||||||
|
placeholder="e.g., A fitness tracking app with workout plans, nutrition tracking, and social features for sharing progress with friends"
|
||||||
|
value={currentPrompt}
|
||||||
|
onChange={(e) => setCurrentPrompt(e.target.value)}
|
||||||
|
className="min-h-[200px] resize-y"
|
||||||
|
/>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Describe what kind of app you want, target users, key features, and any specific design preferences.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="rounded-md bg-destructive/10 p-3 text-sm text-destructive">
|
||||||
|
{error}
|
||||||
|
{!apiKeys[selectedProvider] && (
|
||||||
|
<div className="mt-2 flex items-center gap-2">
|
||||||
|
<Settings className="h-4 w-4" />
|
||||||
|
<span className="text-xs">Configure API key in Settings</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button onClick={handleGenerate} disabled={isProcessing || !currentPrompt.trim()} className="flex-1">
|
||||||
|
{isProcessing ? (
|
||||||
|
<>
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
Generating...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Palette className="mr-2 h-4 w-4" />
|
||||||
|
Generate UX Prompt
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" onClick={handleClear} disabled={isProcessing}>
|
||||||
|
Clear
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className={cn(!generatedPrompt && "opacity-50")}>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center justify-between">
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<CheckCircle2 className="h-5 w-5 text-green-500" />
|
||||||
|
Best Ever UX Prompt
|
||||||
|
</span>
|
||||||
|
{generatedPrompt && (
|
||||||
|
<Button variant="ghost" size="icon" onClick={handleCopy}>
|
||||||
|
{copied ? (
|
||||||
|
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
||||||
|
) : (
|
||||||
|
<Copy className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Comprehensive UX design prompt ready for designers
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
{generatedPrompt ? (
|
||||||
|
<div className="rounded-md border bg-muted/50 p-4">
|
||||||
|
<pre className="whitespace-pre-wrap text-sm">{generatedPrompt}</pre>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex h-[400px] items-center justify-center text-center text-sm text-muted-foreground">
|
||||||
|
Your comprehensive UX designer prompt will appear here
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
import type { ModelProvider, APIResponse, ChatMessage } from "@/types";
|
import type { ModelProvider, APIResponse, ChatMessage } from "@/types";
|
||||||
import QwenOAuthService from "./qwen-oauth";
|
|
||||||
import OllamaCloudService from "./ollama-cloud";
|
import OllamaCloudService from "./ollama-cloud";
|
||||||
import ZaiPlanService from "./zai-plan";
|
import ZaiPlanService from "./zai-plan";
|
||||||
|
|
||||||
export interface ModelAdapterConfig {
|
export interface ModelAdapterConfig {
|
||||||
qwen?: {
|
|
||||||
apiKey?: string;
|
|
||||||
endpoint?: string;
|
|
||||||
};
|
|
||||||
ollama?: {
|
ollama?: {
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
endpoint?: string;
|
endpoint?: string;
|
||||||
@@ -20,13 +15,11 @@ export interface ModelAdapterConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ModelAdapter {
|
export class ModelAdapter {
|
||||||
private qwenService: QwenOAuthService;
|
|
||||||
private ollamaService: OllamaCloudService;
|
private ollamaService: OllamaCloudService;
|
||||||
private zaiService: ZaiPlanService;
|
private zaiService: ZaiPlanService;
|
||||||
private preferredProvider: ModelProvider;
|
private preferredProvider: ModelProvider;
|
||||||
|
|
||||||
constructor(config: ModelAdapterConfig = {}, preferredProvider: ModelProvider = "qwen") {
|
constructor(config: ModelAdapterConfig = {}, preferredProvider: ModelProvider = "ollama") {
|
||||||
this.qwenService = new QwenOAuthService(config.qwen);
|
|
||||||
this.ollamaService = new OllamaCloudService(config.ollama);
|
this.ollamaService = new OllamaCloudService(config.ollama);
|
||||||
this.zaiService = new ZaiPlanService(config.zai);
|
this.zaiService = new ZaiPlanService(config.zai);
|
||||||
this.preferredProvider = preferredProvider;
|
this.preferredProvider = preferredProvider;
|
||||||
@@ -36,18 +29,6 @@ export class ModelAdapter {
|
|||||||
this.preferredProvider = provider;
|
this.preferredProvider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateQwenApiKey(apiKey: string): void {
|
|
||||||
this.qwenService = new QwenOAuthService({ apiKey });
|
|
||||||
}
|
|
||||||
|
|
||||||
setQwenOAuthTokens(accessToken: string, refreshToken?: string, expiresIn?: number): void {
|
|
||||||
this.qwenService.setOAuthTokens(accessToken, refreshToken, expiresIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
getQwenAuthUrl(): string {
|
|
||||||
return this.qwenService.getAuthorizationUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateOllamaApiKey(apiKey: string): void {
|
updateOllamaApiKey(apiKey: string): void {
|
||||||
this.ollamaService = new OllamaCloudService({ apiKey });
|
this.ollamaService = new OllamaCloudService({ apiKey });
|
||||||
}
|
}
|
||||||
@@ -65,9 +46,6 @@ export class ModelAdapter {
|
|||||||
let service: any;
|
let service: any;
|
||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case "qwen":
|
|
||||||
service = this.qwenService;
|
|
||||||
break;
|
|
||||||
case "ollama":
|
case "ollama":
|
||||||
service = this.ollamaService;
|
service = this.ollamaService;
|
||||||
break;
|
break;
|
||||||
@@ -106,6 +84,11 @@ export class ModelAdapter {
|
|||||||
return this.callWithFallback((service) => service.generateActionPlan(prd, model), providers);
|
return this.callWithFallback((service) => service.generateActionPlan(prd, model), providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async generateUXDesignerPrompt(appDescription: string, provider?: ModelProvider, model?: string): Promise<APIResponse<string>> {
|
||||||
|
const providers: ModelProvider[] = provider ? [provider] : [this.preferredProvider, "ollama", "zai"];
|
||||||
|
return this.callWithFallback((service) => service.generateUXDesignerPrompt(appDescription, model), providers);
|
||||||
|
}
|
||||||
|
|
||||||
async chatCompletion(
|
async chatCompletion(
|
||||||
messages: ChatMessage[],
|
messages: ChatMessage[],
|
||||||
model: string,
|
model: string,
|
||||||
@@ -115,9 +98,6 @@ export class ModelAdapter {
|
|||||||
let service: any;
|
let service: any;
|
||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case "qwen":
|
|
||||||
service = this.qwenService;
|
|
||||||
break;
|
|
||||||
case "ollama":
|
case "ollama":
|
||||||
service = this.ollamaService;
|
service = this.ollamaService;
|
||||||
break;
|
break;
|
||||||
@@ -137,7 +117,6 @@ export class ModelAdapter {
|
|||||||
|
|
||||||
async listModels(provider?: ModelProvider): Promise<APIResponse<Record<ModelProvider, string[]>>> {
|
async listModels(provider?: ModelProvider): Promise<APIResponse<Record<ModelProvider, string[]>>> {
|
||||||
const fallbackModels: Record<ModelProvider, string[]> = {
|
const fallbackModels: Record<ModelProvider, string[]> = {
|
||||||
qwen: ["qwen-coder-plus", "qwen-coder-turbo", "qwen-coder-lite"],
|
|
||||||
ollama: ["gpt-oss:120b", "llama3.1", "gemma3", "deepseek-r1", "qwen3"],
|
ollama: ["gpt-oss:120b", "llama3.1", "gemma3", "deepseek-r1", "qwen3"],
|
||||||
zai: ["glm-4.7", "glm-4.5", "glm-4.5-air", "glm-4-flash", "glm-4-flashx"],
|
zai: ["glm-4.7", "glm-4.5", "glm-4.5-air", "glm-4-flash", "glm-4-flashx"],
|
||||||
};
|
};
|
||||||
@@ -163,24 +142,12 @@ export class ModelAdapter {
|
|||||||
console.error("[ModelAdapter] Failed to load Z.AI models, using fallback:", error);
|
console.error("[ModelAdapter] Failed to load Z.AI models, using fallback:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (provider === "qwen" || !provider) {
|
|
||||||
try {
|
|
||||||
const qwenModels = await this.qwenService.listModels();
|
|
||||||
if (qwenModels.success && qwenModels.data && qwenModels.data.length > 0) {
|
|
||||||
models.qwen = qwenModels.data;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("[ModelAdapter] Failed to load Qwen models, using fallback:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { success: true, data: models };
|
return { success: true, data: models };
|
||||||
}
|
}
|
||||||
|
|
||||||
getAvailableModels(provider: ModelProvider): string[] {
|
getAvailableModels(provider: ModelProvider): string[] {
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case "qwen":
|
|
||||||
return this.qwenService.getAvailableModels();
|
|
||||||
case "ollama":
|
case "ollama":
|
||||||
return this.ollamaService.getAvailableModels();
|
return this.ollamaService.getAvailableModels();
|
||||||
case "zai":
|
case "zai":
|
||||||
|
|||||||
@@ -119,9 +119,44 @@ export class OllamaCloudService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAvailableModels(): string[] {
|
getAvailableModels(): string[] {
|
||||||
return this.availableModels.length > 0
|
if (this.availableModels.length > 0) {
|
||||||
? this.availableModels
|
return this.availableModels;
|
||||||
: ["gpt-oss:120b", "llama3.1", "gemma3", "deepseek-r1", "qwen3"];
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
"gpt-oss:120b",
|
||||||
|
"llama3.1:latest",
|
||||||
|
"llama3.1:70b",
|
||||||
|
"llama3.1:8b",
|
||||||
|
"llama3.1:instruct",
|
||||||
|
"gemma3:12b",
|
||||||
|
"gemma3:27b",
|
||||||
|
"gemma3:4b",
|
||||||
|
"gemma3:7b",
|
||||||
|
"deepseek-r1:70b",
|
||||||
|
"deepseek-r1:32b",
|
||||||
|
"deepseek-r1:14b",
|
||||||
|
"deepseek-r1:8b",
|
||||||
|
"deepseek-r1:1.5b",
|
||||||
|
"qwen3:72b",
|
||||||
|
"qwen3:32b",
|
||||||
|
"qwen3:14b",
|
||||||
|
"qwen3:7b",
|
||||||
|
"qwen3:4b",
|
||||||
|
"mistral:7b",
|
||||||
|
"mistral:instruct",
|
||||||
|
"codellama:34b",
|
||||||
|
"codellama:13b",
|
||||||
|
"codellama:7b",
|
||||||
|
"codellama:instruct",
|
||||||
|
"phi3:14b",
|
||||||
|
"phi3:3.8b",
|
||||||
|
"phi3:mini",
|
||||||
|
"gemma2:27b",
|
||||||
|
"gemma2:9b",
|
||||||
|
"yi:34b",
|
||||||
|
"yi:9b",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
async enhancePrompt(prompt: string, model?: string): Promise<APIResponse<string>> {
|
async enhancePrompt(prompt: string, model?: string): Promise<APIResponse<string>> {
|
||||||
@@ -198,6 +233,71 @@ Include specific recommendations for:
|
|||||||
|
|
||||||
return this.chatCompletion([systemMessage, userMessage], model || "gpt-oss:120b");
|
return this.chatCompletion([systemMessage, userMessage], model || "gpt-oss:120b");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async generateUXDesignerPrompt(appDescription: string, model?: string): Promise<APIResponse<string>> {
|
||||||
|
const systemMessage: ChatMessage = {
|
||||||
|
role: "system",
|
||||||
|
content: `You are a world-class UX/UI designer with deep expertise in human-centered design principles, user research, interaction design, visual design systems, and modern design tools (Figma, Sketch, Adobe XD).
|
||||||
|
|
||||||
|
Your task is to create an exceptional, detailed prompt for generating the best possible UX design for a given app description.
|
||||||
|
|
||||||
|
Generate a comprehensive UX design prompt that includes:
|
||||||
|
|
||||||
|
1. USER RESEARCH & PERSONAS
|
||||||
|
- Primary target users and their motivations
|
||||||
|
- User pain points and needs
|
||||||
|
- User journey maps
|
||||||
|
- Persona archetypes with demographics and goals
|
||||||
|
|
||||||
|
2. INFORMATION ARCHITECTURE
|
||||||
|
- Content hierarchy and organization
|
||||||
|
- Navigation structure and patterns
|
||||||
|
- User flows and key pathways
|
||||||
|
- Site map or app structure
|
||||||
|
|
||||||
|
3. VISUAL DESIGN SYSTEM
|
||||||
|
- Color palette recommendations (primary, secondary, accent, neutral)
|
||||||
|
- Typography hierarchy and font pairings
|
||||||
|
- Component library approach
|
||||||
|
- Spacing, sizing, and layout grids
|
||||||
|
- Iconography style and set
|
||||||
|
|
||||||
|
4. INTERACTION DESIGN
|
||||||
|
- Micro-interactions and animations
|
||||||
|
- Gesture patterns for touch interfaces
|
||||||
|
- Loading states and empty states
|
||||||
|
- Error handling and feedback mechanisms
|
||||||
|
- Accessibility considerations (WCAG compliance)
|
||||||
|
|
||||||
|
5. KEY SCREENS & COMPONENTS
|
||||||
|
- Core screens that need detailed design
|
||||||
|
- Critical components (buttons, forms, cards, navigation)
|
||||||
|
- Data visualization needs
|
||||||
|
- Responsive design requirements (mobile, tablet, desktop)
|
||||||
|
|
||||||
|
6. DESIGN DELIVERABLES
|
||||||
|
- Wireframes vs. high-fidelity mockups
|
||||||
|
- Design system documentation needs
|
||||||
|
- Prototyping requirements
|
||||||
|
- Handoff specifications for developers
|
||||||
|
|
||||||
|
7. COMPETITIVE INSIGHTS
|
||||||
|
- Design patterns from successful apps in this category
|
||||||
|
- Opportunities to differentiate
|
||||||
|
- Modern design trends to consider
|
||||||
|
|
||||||
|
The output should be a detailed, actionable prompt that a designer or AI image generator can use to create world-class UX designs.
|
||||||
|
|
||||||
|
Make the prompt specific, inspiring, and comprehensive. Use professional UX terminology.`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const userMessage: ChatMessage = {
|
||||||
|
role: "user",
|
||||||
|
content: `Create the BEST EVER UX design prompt for this app:\n\n${appDescription}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.chatCompletion([systemMessage, userMessage], model || "gpt-oss:120b");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default OllamaCloudService;
|
export default OllamaCloudService;
|
||||||
|
|||||||
@@ -182,6 +182,71 @@ Include specific recommendations for:
|
|||||||
getAvailableModels(): string[] {
|
getAvailableModels(): string[] {
|
||||||
return ["glm-4.7", "glm-4.6", "glm-4.5", "glm-4.5-air", "glm-4-flash", "glm-4-flashx"];
|
return ["glm-4.7", "glm-4.6", "glm-4.5", "glm-4.5-air", "glm-4-flash", "glm-4-flashx"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async generateUXDesignerPrompt(appDescription: string, model?: string): Promise<APIResponse<string>> {
|
||||||
|
const systemMessage: ChatMessage = {
|
||||||
|
role: "system",
|
||||||
|
content: `You are a world-class UX/UI designer with deep expertise in human-centered design principles, user research, interaction design, visual design systems, and modern design tools (Figma, Sketch, Adobe XD).
|
||||||
|
|
||||||
|
Your task is to create an exceptional, detailed prompt for generating the best possible UX design for a given app description.
|
||||||
|
|
||||||
|
Generate a comprehensive UX design prompt that includes:
|
||||||
|
|
||||||
|
1. USER RESEARCH & PERSONAS
|
||||||
|
- Primary target users and their motivations
|
||||||
|
- User pain points and needs
|
||||||
|
- User journey maps
|
||||||
|
- Persona archetypes with demographics and goals
|
||||||
|
|
||||||
|
2. INFORMATION ARCHITECTURE
|
||||||
|
- Content hierarchy and organization
|
||||||
|
- Navigation structure and patterns
|
||||||
|
- User flows and key pathways
|
||||||
|
- Site map or app structure
|
||||||
|
|
||||||
|
3. VISUAL DESIGN SYSTEM
|
||||||
|
- Color palette recommendations (primary, secondary, accent, neutral)
|
||||||
|
- Typography hierarchy and font pairings
|
||||||
|
- Component library approach
|
||||||
|
- Spacing, sizing, and layout grids
|
||||||
|
- Iconography style and set
|
||||||
|
|
||||||
|
4. INTERACTION DESIGN
|
||||||
|
- Micro-interactions and animations
|
||||||
|
- Gesture patterns for touch interfaces
|
||||||
|
- Loading states and empty states
|
||||||
|
- Error handling and feedback mechanisms
|
||||||
|
- Accessibility considerations (WCAG compliance)
|
||||||
|
|
||||||
|
5. KEY SCREENS & COMPONENTS
|
||||||
|
- Core screens that need detailed design
|
||||||
|
- Critical components (buttons, forms, cards, navigation)
|
||||||
|
- Data visualization needs
|
||||||
|
- Responsive design requirements (mobile, tablet, desktop)
|
||||||
|
|
||||||
|
6. DESIGN DELIVERABLES
|
||||||
|
- Wireframes vs. high-fidelity mockups
|
||||||
|
- Design system documentation needs
|
||||||
|
- Prototyping requirements
|
||||||
|
- Handoff specifications for developers
|
||||||
|
|
||||||
|
7. COMPETITIVE INSIGHTS
|
||||||
|
- Design patterns from successful apps in this category
|
||||||
|
- Opportunities to differentiate
|
||||||
|
- Modern design trends to consider
|
||||||
|
|
||||||
|
The output should be a detailed, actionable prompt that a designer or AI image generator can use to create world-class UX designs.
|
||||||
|
|
||||||
|
Make the prompt specific, inspiring, and comprehensive. Use professional UX terminology.`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const userMessage: ChatMessage = {
|
||||||
|
role: "user",
|
||||||
|
content: `Create the BEST EVER UX design prompt for this app:\n\n${appDescription}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.chatCompletion([systemMessage, userMessage], model || "glm-4.7", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ZaiPlanService;
|
export default ZaiPlanService;
|
||||||
|
|||||||
Reference in New Issue
Block a user