docs: replace README with Next.js boilerplate template
Updated README.md from a detailed OllaHub project description to the standard Next.js getting started template, likely to initialize or reset the project as a Next.js application.
This commit is contained in:
1 parent
58e5522700
commit
a3f8226fda
42 files changed
+4465
-314
No files matched your search
+50
@@ -0,0 +1,50 @@
|
||||
export type ChatRole = "user" | "assistant" | "system";
|
||||
|
||||
export type Message = {
|
||||
id: string;
|
||||
role: ChatRole;
|
||||
content: string;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
export type ChatState = {
|
||||
messages: Message[];
|
||||
selectedModel: string | null;
|
||||
isStreaming: boolean;
|
||||
streamingContent: string;
|
||||
};
|
||||
|
||||
export function createMessage(role: ChatRole, content: string): Message {
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
role,
|
||||
content,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
export function formatTimestamp(timestamp: number): string {
|
||||
const now = Date.now();
|
||||
const diff = now - timestamp;
|
||||
const minutes = Math.floor(diff / 60000);
|
||||
|
||||
if (minutes < 1) return "agora";
|
||||
if (minutes < 60) return `${minutes} min atrás`;
|
||||
|
||||
const hours = Math.floor(minutes / 60);
|
||||
if (hours < 24) return `${hours}h atrás`;
|
||||
|
||||
const days = Math.floor(hours / 24);
|
||||
return `${days}d atrás`;
|
||||
}
|
||||
|
||||
export function convertToOllamaMessages(messages: Message[]) {
|
||||
return messages.map((msg) => ({
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
}));
|
||||
}
|
||||
|
||||
export function createSystemMessage(content: string): Message {
|
||||
return createMessage("system", content);
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
export type Device = "CPU" | "GPU";
|
||||
|
||||
export type ModelInfo = {
|
||||
id: string;
|
||||
name: string;
|
||||
sizeGB: number;
|
||||
quantization: string;
|
||||
device: Device;
|
||||
estCpuUsagePct?: number;
|
||||
estVramGB?: number;
|
||||
};
|
||||
|
||||
export const mockModels: ModelInfo[] = [
|
||||
{
|
||||
id: "llama3.1-8b-q4",
|
||||
name: "llama3.1:8b-q4",
|
||||
sizeGB: 4.8,
|
||||
quantization: "Q4",
|
||||
device: "CPU",
|
||||
estCpuUsagePct: 85,
|
||||
estVramGB: 0.0,
|
||||
},
|
||||
{
|
||||
id: "llama3.1-8b-q8",
|
||||
name: "llama3.1:8b-q8",
|
||||
sizeGB: 8.9,
|
||||
quantization: "Q8",
|
||||
device: "GPU",
|
||||
estCpuUsagePct: 20,
|
||||
estVramGB: 8,
|
||||
},
|
||||
{
|
||||
id: "mistral-7b-q4",
|
||||
name: "mistral:7b-q4",
|
||||
sizeGB: 4.1,
|
||||
quantization: "Q4",
|
||||
device: "CPU",
|
||||
estCpuUsagePct: 75,
|
||||
estVramGB: 0,
|
||||
},
|
||||
{
|
||||
id: "mistral-7b-q8",
|
||||
name: "mistral:7b-q8",
|
||||
sizeGB: 7.9,
|
||||
quantization: "Q8",
|
||||
device: "GPU",
|
||||
estCpuUsagePct: 18,
|
||||
estVramGB: 8,
|
||||
},
|
||||
{
|
||||
id: "qwen2.5-7b-q4",
|
||||
name: "qwen2.5:7b-q4",
|
||||
sizeGB: 4.2,
|
||||
quantization: "Q4",
|
||||
device: "CPU",
|
||||
estCpuUsagePct: 80,
|
||||
estVramGB: 0,
|
||||
},
|
||||
{
|
||||
id: "qwen2.5-7b-q8",
|
||||
name: "qwen2.5:7b-q8",
|
||||
sizeGB: 8.1,
|
||||
quantization: "Q8",
|
||||
device: "GPU",
|
||||
estCpuUsagePct: 22,
|
||||
estVramGB: 8,
|
||||
},
|
||||
];
|
||||
|
||||
export function inferQuantization(nameOrDetails: string | unknown): string {
|
||||
const s =
|
||||
typeof nameOrDetails === "string" ? nameOrDetails.toLowerCase() : "";
|
||||
if (s.includes("q8")) return "Q8";
|
||||
if (s.includes("q5")) return "Q5";
|
||||
if (s.includes("q4")) return "Q4";
|
||||
return "Q?";
|
||||
}
|
||||
|
||||
export function inferDevice(details?: unknown): Device {
|
||||
const s = typeof details === "string" ? details.toLowerCase() : "";
|
||||
if (s.includes("cuda") || s.includes("metal") || s.includes("gpu"))
|
||||
return "GPU";
|
||||
return "CPU";
|
||||
}
|
||||
|
||||
export function estimateCpuVram(
|
||||
info: Pick<ModelInfo, "sizeGB" | "quantization" | "device">,
|
||||
) {
|
||||
const q = info.quantization.toUpperCase();
|
||||
let cpuPct = 50;
|
||||
let vramGB = 0;
|
||||
if (info.device === "GPU") {
|
||||
vramGB = Math.max(4, Math.round(info.sizeGB));
|
||||
cpuPct = 20;
|
||||
} else {
|
||||
// heurística simples: quantizações mais baixas usam mais CPU
|
||||
cpuPct = q === "Q8" ? 60 : q === "Q5" ? 70 : 85;
|
||||
}
|
||||
return { cpuPct, vramGB };
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Ollama } from "ollama";
|
||||
|
||||
export const OLLAMA_HOST = process.env.OLLAMA_HOST || "http://localhost:11434";
|
||||
|
||||
export async function listModelsViaSdk() {
|
||||
try {
|
||||
const client = new Ollama({ host: OLLAMA_HOST });
|
||||
const res = await client.list();
|
||||
return res?.models ?? [];
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function listModelsViaHttp() {
|
||||
const url = `${OLLAMA_HOST}/api/tags`;
|
||||
const res = await fetch(url, { cache: "no-store" });
|
||||
if (!res.ok) throw new Error(`Ollama HTTP error ${res.status}`);
|
||||
const data = await res.json();
|
||||
return data?.models ?? [];
|
||||
}
|
||||
|
||||
export async function chatWithStream(
|
||||
model: string,
|
||||
messages: Array<{ role: string; content: string }>,
|
||||
options?: Record<string, unknown>,
|
||||
system?: string
|
||||
) {
|
||||
const client = new Ollama({ host: OLLAMA_HOST });
|
||||
return client.chat({
|
||||
model,
|
||||
messages,
|
||||
stream: true,
|
||||
options,
|
||||
system,
|
||||
});
|
||||
}
|
||||
|
||||
export async function pullModel(model: string) {
|
||||
const client = new Ollama({ host: OLLAMA_HOST });
|
||||
return client.pull({ model, stream: true });
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
export const DEFAULT_SYSTEM_PROMPT = `Você é um assistente de IA especializado em desenvolvimento de software e análise técnica.
|
||||
|
||||
FORMATAÇÃO OBRIGATÓRIA:
|
||||
- Sempre use blocos de código markdown com especificação de linguagem
|
||||
- Para JavaScript/TypeScript: \`\`\`javascript ou \`\`\`typescript
|
||||
- Para Python: \`\`\`python
|
||||
- Para Bash/Shell: \`\`\`bash
|
||||
- Para SQL: \`\`\`sql
|
||||
- Para JSON: \`\`\`json
|
||||
- Para YAML: \`\`\`yaml
|
||||
- Para Docker: \`\`\`dockerfile
|
||||
- Para configurações: \`\`\`toml, \`\`\`ini, \`\`\`conf
|
||||
|
||||
ESTRUTURA DE RESPOSTAS:
|
||||
1. Explicação conceitual clara
|
||||
2. Exemplo prático em bloco de código
|
||||
3. Explicação do código quando necessário
|
||||
4. Boas práticas
|
||||
5. Possíveis problemas e soluções
|
||||
|
||||
CONTEXTO OLLAHUB:
|
||||
- Execução local via Ollama
|
||||
- Stack frequente: Next.js, React, Node.js
|
||||
- Priorize exemplos executáveis e explique comandos e configurações.`;
|
||||
|
||||
export function mergeSystemPrompt(userPrompt?: string) {
|
||||
if (!userPrompt || userPrompt.trim().length === 0)
|
||||
return DEFAULT_SYSTEM_PROMPT;
|
||||
return `${DEFAULT_SYSTEM_PROMPT}\n\nDiretivas do usuário:\n${userPrompt}`;
|
||||
}
|
||||
Reference in new issue
Block a user