Compare commits
1 Commits
37612bbac2
...
remove-qwe
60
app/page.tsx
60
app/page.tsx
@@ -1,6 +1,6 @@
|
|||||||
"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";
|
||||||
@@ -8,59 +8,9 @@ import PRDGenerator from "@/components/PRDGenerator";
|
|||||||
import ActionPlanGenerator from "@/components/ActionPlanGenerator";
|
import ActionPlanGenerator from "@/components/ActionPlanGenerator";
|
||||||
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) {
|
||||||
@@ -80,12 +30,10 @@ export default function Home() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
|
<div className="flex h-screen bg-background">
|
||||||
<Sidebar currentView={currentView} onViewChange={setCurrentView} />
|
<Sidebar currentView={currentView} onViewChange={setCurrentView} />
|
||||||
<main className="flex-1 overflow-auto p-8">
|
<main className="flex-1 overflow-auto">
|
||||||
<div className="mx-auto max-w-7xl">
|
<div className="container mx-auto p-6">{renderContent()}</div>
|
||||||
{renderContent()}
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export default function ActionPlanGenerator() {
|
|||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
const keys = JSON.parse(saved);
|
const keys = JSON.parse(saved);
|
||||||
if (keys.qwen) modelAdapter.updateQwenApiKey(keys.qwen);
|
|
||||||
if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama);
|
if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama);
|
||||||
if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai);
|
if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -133,7 +132,7 @@ export default function ActionPlanGenerator() {
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium">AI Provider</label>
|
<label className="text-sm font-medium">AI Provider</label>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{(["qwen", "ollama", "zai"] as const).map((provider) => (
|
{(["ollama", "zai"] as const).map((provider) => (
|
||||||
<Button
|
<Button
|
||||||
key={provider}
|
key={provider}
|
||||||
variant={selectedProvider === provider ? "default" : "outline"}
|
variant={selectedProvider === provider ? "default" : "outline"}
|
||||||
@@ -141,7 +140,7 @@ export default function ActionPlanGenerator() {
|
|||||||
onClick={() => setSelectedProvider(provider)}
|
onClick={() => setSelectedProvider(provider)}
|
||||||
className="capitalize"
|
className="capitalize"
|
||||||
>
|
>
|
||||||
{provider === "qwen" ? "Qwen" : provider === "ollama" ? "Ollama" : "Z.AI"}
|
{provider === "ollama" ? "Ollama" : "Z.AI"}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ export default function PRDGenerator() {
|
|||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
const keys = JSON.parse(saved);
|
const keys = JSON.parse(saved);
|
||||||
if (keys.qwen) modelAdapter.updateQwenApiKey(keys.qwen);
|
|
||||||
if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama);
|
if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama);
|
||||||
if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai);
|
if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -147,7 +146,7 @@ export default function PRDGenerator() {
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium">AI Provider</label>
|
<label className="text-sm font-medium">AI Provider</label>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{(["qwen", "ollama", "zai"] as const).map((provider) => (
|
{(["ollama", "zai"] as const).map((provider) => (
|
||||||
<Button
|
<Button
|
||||||
key={provider}
|
key={provider}
|
||||||
variant={selectedProvider === provider ? "default" : "outline"}
|
variant={selectedProvider === provider ? "default" : "outline"}
|
||||||
@@ -155,7 +154,7 @@ export default function PRDGenerator() {
|
|||||||
onClick={() => setSelectedProvider(provider)}
|
onClick={() => setSelectedProvider(provider)}
|
||||||
className="capitalize"
|
className="capitalize"
|
||||||
>
|
>
|
||||||
{provider === "qwen" ? "Qwen" : provider === "ollama" ? "Ollama" : "Z.AI"}
|
{provider === "ollama" ? "Ollama" : "Z.AI"}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export default function PromptEnhancer() {
|
|||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
const keys = JSON.parse(saved);
|
const keys = JSON.parse(saved);
|
||||||
if (keys.qwen) modelAdapter.updateQwenApiKey(keys.qwen);
|
|
||||||
if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama);
|
if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama);
|
||||||
if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai);
|
if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -124,7 +123,7 @@ export default function PromptEnhancer() {
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium">AI Provider</label>
|
<label className="text-sm font-medium">AI Provider</label>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{(["qwen", "ollama", "zai"] as const).map((provider) => (
|
{(["ollama", "zai"] as const).map((provider) => (
|
||||||
<Button
|
<Button
|
||||||
key={provider}
|
key={provider}
|
||||||
variant={selectedProvider === provider ? "default" : "outline"}
|
variant={selectedProvider === provider ? "default" : "outline"}
|
||||||
@@ -135,7 +134,7 @@ export default function PromptEnhancer() {
|
|||||||
selectedProvider === provider && "bg-primary text-primary-foreground"
|
selectedProvider === provider && "bg-primary text-primary-foreground"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{provider === "qwen" ? "Qwen" : provider === "ollama" ? "Ollama" : "Z.AI"}
|
{provider === "ollama" ? "Ollama" : "Z.AI"}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,15 +3,19 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import useStore from "@/lib/store";
|
import useStore from "@/lib/store";
|
||||||
import modelAdapter from "@/lib/services/adapter-instance";
|
import modelAdapter from "@/lib/services/adapter-instance";
|
||||||
import { Save, Key, Server, Eye, EyeOff } from "lucide-react";
|
import { Save, Key, Server, Eye, EyeOff } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
|
|
||||||
export default function SettingsPanel() {
|
export default function SettingsPanel() {
|
||||||
const { apiKeys, setApiKey, selectedProvider, setSelectedProvider, qwenTokens, setQwenTokens } = useStore();
|
const {
|
||||||
|
apiKeys,
|
||||||
|
setApiKey,
|
||||||
|
selectedProvider,
|
||||||
|
setSelectedProvider
|
||||||
|
} = useStore();
|
||||||
|
|
||||||
const [showApiKey, setShowApiKey] = useState<Record<string, boolean>>({});
|
const [showApiKey, setShowApiKey] = useState<Record<string, boolean>>({});
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
@@ -27,10 +31,6 @@ export default function SettingsPanel() {
|
|||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
const keys = JSON.parse(saved);
|
const keys = JSON.parse(saved);
|
||||||
if (keys.qwen) {
|
|
||||||
setApiKey("qwen", keys.qwen);
|
|
||||||
modelAdapter.updateQwenApiKey(keys.qwen);
|
|
||||||
}
|
|
||||||
if (keys.ollama) {
|
if (keys.ollama) {
|
||||||
setApiKey("ollama", keys.ollama);
|
setApiKey("ollama", keys.ollama);
|
||||||
modelAdapter.updateOllamaApiKey(keys.ollama);
|
modelAdapter.updateOllamaApiKey(keys.ollama);
|
||||||
@@ -47,12 +47,9 @@ export default function SettingsPanel() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleApiKeyChange = (provider: string, value: string) => {
|
const handleApiKeyChange = (provider: string, value: string) => {
|
||||||
setApiKey(provider as "qwen" | "ollama" | "zai", value);
|
setApiKey(provider as "ollama" | "zai", value);
|
||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case "qwen":
|
|
||||||
modelAdapter.updateQwenApiKey(value);
|
|
||||||
break;
|
|
||||||
case "ollama":
|
case "ollama":
|
||||||
modelAdapter.updateOllamaApiKey(value);
|
modelAdapter.updateOllamaApiKey(value);
|
||||||
break;
|
break;
|
||||||
@@ -79,69 +76,6 @@ export default function SettingsPanel() {
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-6">
|
<CardContent className="space-y-6">
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="flex items-center gap-2 text-sm font-medium">
|
|
||||||
<Server className="h-4 w-4" />
|
|
||||||
Qwen Code API Key
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<Input
|
|
||||||
type={showApiKey.qwen ? "text" : "password"}
|
|
||||||
placeholder="Enter your Qwen API key"
|
|
||||||
value={apiKeys.qwen || ""}
|
|
||||||
onChange={(e) => handleApiKeyChange("qwen", e.target.value)}
|
|
||||||
className="font-mono text-sm"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className="absolute right-0 top-0 h-full"
|
|
||||||
onClick={() => setShowApiKey((prev) => ({ ...prev, qwen: !prev.qwen }))}
|
|
||||||
>
|
|
||||||
{showApiKey.qwen ? (
|
|
||||||
<EyeOff className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<Eye className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<p className="text-xs text-muted-foreground flex-1">
|
|
||||||
Get API key from{" "}
|
|
||||||
<a
|
|
||||||
href="https://help.aliyun.com/zh/dashscope/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
|
||||||
>
|
|
||||||
Alibaba DashScope
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
variant={qwenTokens ? "secondary" : "outline"}
|
|
||||||
size="sm"
|
|
||||||
className="h-8"
|
|
||||||
onClick={() => {
|
|
||||||
if (qwenTokens) {
|
|
||||||
setQwenTokens(undefined as any);
|
|
||||||
localStorage.removeItem("promptarch-qwen-tokens");
|
|
||||||
modelAdapter.updateQwenApiKey(apiKeys.qwen || "");
|
|
||||||
} else {
|
|
||||||
window.location.href = modelAdapter.getQwenAuthUrl();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{qwenTokens ? "Logout from Qwen" : "Login with Qwen (OAuth)"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
{qwenTokens && (
|
|
||||||
<p className="text-[10px] text-green-600 dark:text-green-400 font-medium">
|
|
||||||
✓ Authenticated via OAuth (Expires: {new Date(qwenTokens.expiresAt || 0).toLocaleString()})
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="flex items-center gap-2 text-sm font-medium">
|
<label className="flex items-center gap-2 text-sm font-medium">
|
||||||
<Server className="h-4 w-4" />
|
<Server className="h-4 w-4" />
|
||||||
@@ -238,7 +172,7 @@ export default function SettingsPanel() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<div className="grid gap-3">
|
<div className="grid gap-3">
|
||||||
{(["qwen", "ollama", "zai"] as const).map((provider) => (
|
{(["ollama", "zai"] as const).map((provider) => (
|
||||||
<button
|
<button
|
||||||
key={provider}
|
key={provider}
|
||||||
onClick={() => setSelectedProvider(provider)}
|
onClick={() => setSelectedProvider(provider)}
|
||||||
@@ -254,7 +188,6 @@ export default function SettingsPanel() {
|
|||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h3 className="font-medium capitalize">{provider}</h3>
|
<h3 className="font-medium capitalize">{provider}</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{provider === "qwen" && "Alibaba DashScope API"}
|
|
||||||
{provider === "ollama" && "Ollama Cloud API"}
|
{provider === "ollama" && "Ollama Cloud API"}
|
||||||
{provider === "zai" && "Z.AI Plan API"}
|
{provider === "zai" && "Z.AI Plan API"}
|
||||||
</p>
|
</p>
|
||||||
@@ -278,7 +211,7 @@ export default function SettingsPanel() {
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="rounded-md border bg-muted/30 p-4">
|
<div className="rounded-md border bg-muted/30 p-4">
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
All API keys are stored locally in your browser. Your prompts are sent directly to the selected AI provider and are not stored by PromptArch.
|
All API keys are stored locally in your browser. Your prompts are sent directly to selected AI provider and are not stored by PromptArch.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
14
lib/store.ts
14
lib/store.ts
@@ -10,11 +10,6 @@ interface AppState {
|
|||||||
selectedModels: Record<ModelProvider, string>;
|
selectedModels: Record<ModelProvider, string>;
|
||||||
availableModels: Record<ModelProvider, string[]>;
|
availableModels: Record<ModelProvider, string[]>;
|
||||||
apiKeys: Record<ModelProvider, string>;
|
apiKeys: Record<ModelProvider, string>;
|
||||||
qwenTokens?: {
|
|
||||||
accessToken: string;
|
|
||||||
refreshToken?: string;
|
|
||||||
expiresAt?: number;
|
|
||||||
};
|
|
||||||
isProcessing: boolean;
|
isProcessing: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
history: {
|
history: {
|
||||||
@@ -31,7 +26,6 @@ interface AppState {
|
|||||||
setSelectedModel: (provider: ModelProvider, model: string) => void;
|
setSelectedModel: (provider: ModelProvider, model: string) => void;
|
||||||
setAvailableModels: (provider: ModelProvider, models: string[]) => void;
|
setAvailableModels: (provider: ModelProvider, models: string[]) => void;
|
||||||
setApiKey: (provider: ModelProvider, key: string) => void;
|
setApiKey: (provider: ModelProvider, key: string) => void;
|
||||||
setQwenTokens: (tokens: { accessToken: string; refreshToken?: string; expiresAt?: number }) => void;
|
|
||||||
setProcessing: (processing: boolean) => void;
|
setProcessing: (processing: boolean) => void;
|
||||||
setError: (error: string | null) => void;
|
setError: (error: string | null) => void;
|
||||||
addToHistory: (prompt: string) => void;
|
addToHistory: (prompt: string) => void;
|
||||||
@@ -44,26 +38,22 @@ const useStore = create<AppState>((set) => ({
|
|||||||
enhancedPrompt: null,
|
enhancedPrompt: null,
|
||||||
prd: null,
|
prd: null,
|
||||||
actionPlan: null,
|
actionPlan: null,
|
||||||
selectedProvider: "qwen",
|
selectedProvider: "ollama",
|
||||||
selectedModels: {
|
selectedModels: {
|
||||||
qwen: "qwen-coder-plus",
|
|
||||||
ollama: "gpt-oss:120b",
|
ollama: "gpt-oss:120b",
|
||||||
zai: "glm-4.7",
|
zai: "glm-4.7",
|
||||||
},
|
},
|
||||||
availableModels: {
|
availableModels: {
|
||||||
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.6", "glm-4.5", "glm-4.5-air", "glm-4-flash", "glm-4-flashx"],
|
zai: ["glm-4.7", "glm-4.6", "glm-4.5", "glm-4.5-air", "glm-4-flash", "glm-4-flashx"],
|
||||||
},
|
},
|
||||||
apiKeys: {
|
apiKeys: {
|
||||||
qwen: "",
|
|
||||||
ollama: "",
|
ollama: "",
|
||||||
zai: "",
|
zai: "",
|
||||||
},
|
},
|
||||||
isProcessing: false,
|
isProcessing: false,
|
||||||
error: null,
|
error: null,
|
||||||
history: [],
|
history: [],
|
||||||
|
|
||||||
setCurrentPrompt: (prompt) => set({ currentPrompt: prompt }),
|
setCurrentPrompt: (prompt) => set({ currentPrompt: prompt }),
|
||||||
setEnhancedPrompt: (enhanced) => set({ enhancedPrompt: enhanced }),
|
setEnhancedPrompt: (enhanced) => set({ enhancedPrompt: enhanced }),
|
||||||
setPRD: (prd) => set({ prd }),
|
setPRD: (prd) => set({ prd }),
|
||||||
@@ -81,7 +71,6 @@ const useStore = create<AppState>((set) => ({
|
|||||||
set((state) => ({
|
set((state) => ({
|
||||||
apiKeys: { ...state.apiKeys, [provider]: key },
|
apiKeys: { ...state.apiKeys, [provider]: key },
|
||||||
})),
|
})),
|
||||||
setQwenTokens: (tokens) => set({ qwenTokens: tokens }),
|
|
||||||
setProcessing: (processing) => set({ isProcessing: processing }),
|
setProcessing: (processing) => set({ isProcessing: processing }),
|
||||||
setError: (error) => set({ error }),
|
setError: (error) => set({ error }),
|
||||||
addToHistory: (prompt) =>
|
addToHistory: (prompt) =>
|
||||||
@@ -102,6 +91,7 @@ const useStore = create<AppState>((set) => ({
|
|||||||
enhancedPrompt: null,
|
enhancedPrompt: null,
|
||||||
prd: null,
|
prd: null,
|
||||||
actionPlan: null,
|
actionPlan: null,
|
||||||
|
isProcessing: false,
|
||||||
error: null,
|
error: null,
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|||||||
134
types/index.ts
134
types/index.ts
@@ -1,84 +1,8 @@
|
|||||||
export type ModelProvider = "qwen" | "ollama" | "zai";
|
export type ModelProvider = "ollama" | "zai";
|
||||||
|
|
||||||
export interface ModelConfig {
|
export interface ChatMessage {
|
||||||
provider: ModelProvider;
|
role: "system" | "user" | "assistant";
|
||||||
model: string;
|
content: string;
|
||||||
apiKey?: string;
|
|
||||||
endpoint?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PromptEnhancement {
|
|
||||||
original: string;
|
|
||||||
enhanced: string;
|
|
||||||
quality: number;
|
|
||||||
intent: string;
|
|
||||||
patterns: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PRD {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
overview: string;
|
|
||||||
objectives: string[];
|
|
||||||
userPersonas: UserPersona[];
|
|
||||||
functionalRequirements: Requirement[];
|
|
||||||
nonFunctionalRequirements: Requirement[];
|
|
||||||
technicalArchitecture: string;
|
|
||||||
successMetrics: string[];
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserPersona {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
goals: string[];
|
|
||||||
painPoints: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Requirement {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
priority: "high" | "medium" | "low";
|
|
||||||
status: "pending" | "in-progress" | "completed";
|
|
||||||
dependencies?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActionPlan {
|
|
||||||
id: string;
|
|
||||||
prdId: string;
|
|
||||||
tasks: Task[];
|
|
||||||
frameworks: FrameworkRecommendation[];
|
|
||||||
architecture: ArchitectureGuideline;
|
|
||||||
estimatedDuration: string;
|
|
||||||
createdAt: Date;
|
|
||||||
rawContent?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Task {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
priority: "high" | "medium" | "low";
|
|
||||||
estimatedHours: number;
|
|
||||||
dependencies: string[];
|
|
||||||
status: "pending" | "in-progress" | "completed";
|
|
||||||
assignee?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FrameworkRecommendation {
|
|
||||||
category: string;
|
|
||||||
recommendation: string;
|
|
||||||
rationale: string;
|
|
||||||
alternatives: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ArchitectureGuideline {
|
|
||||||
pattern: string;
|
|
||||||
structure: string;
|
|
||||||
technologies: string[];
|
|
||||||
bestPractices: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APIResponse<T> {
|
export interface APIResponse<T> {
|
||||||
@@ -87,7 +11,51 @@ export interface APIResponse<T> {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChatMessage {
|
export interface PromptEnhancement {
|
||||||
role: "system" | "user" | "assistant";
|
id: string;
|
||||||
content: string;
|
originalPrompt: string;
|
||||||
|
enhancedPrompt: string;
|
||||||
|
provider: ModelProvider;
|
||||||
|
model: string;
|
||||||
|
timestamp: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PRD {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
overview: string;
|
||||||
|
objectives: string[];
|
||||||
|
userPersonas: string[];
|
||||||
|
functionalRequirements: string[];
|
||||||
|
nonFunctionalRequirements: string[];
|
||||||
|
technicalArchitecture: string;
|
||||||
|
successMetrics: string[];
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActionPlan {
|
||||||
|
id: string;
|
||||||
|
prdId: string;
|
||||||
|
tasks: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
priority: "high" | "medium" | "low";
|
||||||
|
dependencies: string[];
|
||||||
|
estimatedEffort: string;
|
||||||
|
}[];
|
||||||
|
frameworks: {
|
||||||
|
name: string;
|
||||||
|
reason: string;
|
||||||
|
}[];
|
||||||
|
architecture: {
|
||||||
|
pattern: string;
|
||||||
|
structure: string;
|
||||||
|
technologies: string[];
|
||||||
|
bestPractices: string[];
|
||||||
|
};
|
||||||
|
estimatedDuration: string;
|
||||||
|
createdAt: Date;
|
||||||
|
rawContent?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user