Initial commit

This commit is contained in:
Jonathan Atta
2026-03-03 10:33:56 +01:00
commit da373199e0
139 changed files with 26421 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
import React from 'react';
import {
View,
Text,
ScrollView,
TouchableOpacity,
Image,
StyleSheet,
} from 'react-native';
import { colors, spacing, typography, borderRadius } from '../../../../theme/tokens';
import type { ModelConfigFormState, Agent } from '../types';
interface AgentChipProps {
agent: Agent;
isSelected: boolean;
onSelect: (id: string) => void;
}
function AgentChip({ agent, isSelected, onSelect }: AgentChipProps) {
return (
<TouchableOpacity
style={[styles.agentChip, isSelected && styles.agentChipActive]}
onPress={() => onSelect(agent.id)}
>
{agent.avatarUri ? (
<Image
source={{ uri: agent.avatarUri }}
style={styles.agentAvatar}
/>
) : (
<Text style={styles.agentInitial}>
{agent.name[0]?.toUpperCase()}
</Text>
)}
<Text style={[styles.agentChipText, isSelected && styles.agentChipTextActive]}>
{agent.name}
</Text>
</TouchableOpacity>
);
}
interface AgentSectionProps {
state: ModelConfigFormState;
}
export default function AgentSection({ state }: AgentSectionProps) {
const { agents, agentId, setAgentId, usingAgent, activeAgent } = state;
const hintText = usingAgent
? `Le prompt de l'agent « ${activeAgent?.name} » sera utilisé`
: 'Aucun agent — le prompt système ci-dessous sera utilisé';
return (
<>
<Text style={styles.groupTitle}>🤖 Agent</Text>
<View style={styles.card}>
<Text style={styles.agentHint}>{hintText}</Text>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.chipScroll}
contentContainerStyle={styles.chipScrollContent}
>
<TouchableOpacity
style={[styles.agentChip, !usingAgent && styles.agentChipActive]}
onPress={() => setAgentId(null)}
>
<Text style={[styles.agentChipText, !usingAgent && styles.agentChipTextActive]}>
Aucun
</Text>
</TouchableOpacity>
{agents.map(agent => (
<AgentChip
key={agent.id}
agent={agent}
isSelected={agentId === agent.id}
onSelect={setAgentId}
/>
))}
</ScrollView>
</View>
</>
);
}
const styles = StyleSheet.create({
groupTitle: {
fontSize: typography.sizes.md,
fontWeight: typography.weights.semibold,
color: colors.textPrimary,
marginBottom: spacing.sm,
},
card: {
backgroundColor: colors.surface,
borderRadius: borderRadius.lg,
borderWidth: 1,
borderColor: colors.border,
padding: spacing.md,
marginBottom: spacing.sm,
},
agentHint: {
fontSize: typography.sizes.sm,
color: colors.textSecondary,
},
chipScroll: { marginTop: spacing.sm },
chipScrollContent: { gap: spacing.xs },
agentChip: {
flexDirection: 'row',
alignItems: 'center',
borderWidth: 1,
borderColor: colors.border,
borderRadius: borderRadius.xl,
paddingHorizontal: spacing.md,
paddingVertical: 6,
backgroundColor: colors.background,
},
agentChipActive: {
borderColor: colors.primary,
backgroundColor: colors.primary,
},
agentChipText: {
fontSize: typography.sizes.sm,
color: colors.textSecondary,
},
agentChipTextActive: {
color: colors.surface,
fontWeight: typography.weights.semibold,
},
agentAvatar: {
width: 18,
height: 18,
borderRadius: 9,
marginRight: 5,
},
agentInitial: {
marginRight: 4,
color: colors.textSecondary,
},
});

View File

@@ -0,0 +1,145 @@
import React from 'react';
import { View, TextInput, StyleSheet } from 'react-native';
import { colors, spacing, borderRadius, typography } from '../../../../theme/tokens';
import { SectionHeader } from '../components/SectionHeader';
import { ParamRow } from '../components/ParamRow';
import { NumInput } from '../components/NumInput';
import { BoolRow } from '../components/BoolRow';
import { SelectRow } from '../components/SelectRow';
import { CACHE_TYPES, type ModelConfigFormState, type CacheType } from '../types';
interface LoadingSectionProps {
state: ModelConfigFormState;
}
export default function LoadingSection({ state }: LoadingSectionProps) {
const {
expanded, toggle, showTooltip,
nCtx, setNCtx, nBatch, setNBatch,
nUbatch, setNUbatch, nThreads, setNThreads,
nGpuLayers, setNGpuLayers,
flashAttn, setFlashAttn,
cacheTypeK, setCacheTypeK,
cacheTypeV, setCacheTypeV,
useMlock, setUseMlock, useMmap, setUseMmap,
ropeFreqBase, setRopeFreqBase,
ropeFreqScale, setRopeFreqScale,
ctxShift, setCtxShift, kvUnified, setKvUnified,
nCpuMoe, setNCpuMoe, cpuMask, setCpuMask,
nParallel, setNParallel,
} = state;
return (
<>
<SectionHeader
title="🔧 Chargement du Modèle"
badge="17 params"
expanded={expanded.loading}
onToggle={() => toggle('loading')}
/>
{expanded.loading && (
<View style={styles.card}>
<ParamRow paramKey="n_ctx" onInfo={showTooltip}>
<NumInput value={nCtx} onChange={setNCtx} placeholder="2048" />
</ParamRow>
<ParamRow paramKey="n_batch" onInfo={showTooltip}>
<NumInput value={nBatch} onChange={setNBatch} placeholder="512 (défaut)" />
</ParamRow>
<ParamRow paramKey="n_ubatch" onInfo={showTooltip}>
<NumInput value={nUbatch} onChange={setNUbatch} placeholder="= n_batch (défaut)" />
</ParamRow>
<ParamRow paramKey="n_threads" onInfo={showTooltip}>
<NumInput value={nThreads} onChange={setNThreads} placeholder="auto (0)" />
</ParamRow>
<ParamRow paramKey="n_gpu_layers" onInfo={showTooltip}>
<NumInput value={nGpuLayers} onChange={setNGpuLayers} placeholder="0 (iOS seul.)" />
</ParamRow>
<BoolRow
paramKey="flash_attn"
value={flashAttn}
onChange={setFlashAttn}
onInfo={showTooltip}
/>
<SelectRow
paramKey="cache_type_k"
value={cacheTypeK}
options={CACHE_TYPES}
onChange={v => setCacheTypeK(v as CacheType)}
onInfo={showTooltip}
/>
<SelectRow
paramKey="cache_type_v"
value={cacheTypeV}
options={CACHE_TYPES}
onChange={v => setCacheTypeV(v as CacheType)}
onInfo={showTooltip}
/>
<BoolRow
paramKey="use_mlock"
value={useMlock}
onChange={setUseMlock}
onInfo={showTooltip}
/>
<BoolRow
paramKey="use_mmap"
value={useMmap}
onChange={setUseMmap}
onInfo={showTooltip}
/>
<ParamRow paramKey="rope_freq_base" onInfo={showTooltip}>
<NumInput value={ropeFreqBase} onChange={setRopeFreqBase} placeholder="0 (auto)" />
</ParamRow>
<ParamRow paramKey="rope_freq_scale" onInfo={showTooltip}>
<NumInput value={ropeFreqScale} onChange={setRopeFreqScale} placeholder="0 (auto)" />
</ParamRow>
<BoolRow
paramKey="ctx_shift"
value={ctxShift}
onChange={setCtxShift}
onInfo={showTooltip}
/>
<BoolRow
paramKey="kv_unified"
value={kvUnified}
onChange={setKvUnified}
onInfo={showTooltip}
/>
<ParamRow paramKey="n_cpu_moe" onInfo={showTooltip}>
<NumInput value={nCpuMoe} onChange={setNCpuMoe} placeholder="0 (défaut)" />
</ParamRow>
<ParamRow paramKey="cpu_mask" onInfo={showTooltip}>
<TextInput
style={styles.textInput}
value={cpuMask}
onChangeText={setCpuMask}
placeholder='ex: "0-3" ou "0,2,4,6"'
placeholderTextColor={colors.textTertiary}
/>
</ParamRow>
<ParamRow paramKey="n_parallel" onInfo={showTooltip}>
<NumInput value={nParallel} onChange={setNParallel} placeholder="1 (défaut)" />
</ParamRow>
</View>
)}
</>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: colors.surface,
borderRadius: borderRadius.lg,
borderWidth: 1,
borderColor: colors.border,
padding: spacing.md,
marginBottom: spacing.sm,
},
textInput: {
backgroundColor: colors.background,
borderRadius: borderRadius.md,
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
fontSize: typography.sizes.sm,
color: colors.textPrimary,
},
});

View File

@@ -0,0 +1,73 @@
import React from 'react';
import { View, TextInput, StyleSheet } from 'react-native';
import { colors, spacing, borderRadius, typography } from '../../../../theme/tokens';
import { SectionHeader } from '../components/SectionHeader';
import { ParamRow } from '../components/ParamRow';
import { NumInput } from '../components/NumInput';
import { BoolRow } from '../components/BoolRow';
import type { ModelConfigFormState } from '../types';
interface OutputSectionProps {
state: ModelConfigFormState;
}
export default function OutputSection({ state }: OutputSectionProps) {
const {
expanded, toggle, showTooltip,
ignoreEos, setIgnoreEos,
nProbs, setNProbs,
stopStr, setStopStr,
} = state;
return (
<>
<SectionHeader
title="📤 Sortie"
badge="3 params"
expanded={expanded.output}
onToggle={() => toggle('output')}
/>
{expanded.output && (
<View style={styles.card}>
<BoolRow
paramKey="ignore_eos"
value={ignoreEos}
onChange={setIgnoreEos}
onInfo={showTooltip}
/>
<ParamRow paramKey="n_probs" onInfo={showTooltip}>
<NumInput value={nProbs} onChange={setNProbs} placeholder="0 (désactivé)" />
</ParamRow>
<ParamRow paramKey="stop" onInfo={showTooltip}>
<TextInput
style={styles.textInput}
value={stopStr}
onChangeText={setStopStr}
placeholder='ex: "User:,<|im_end|>,###"'
placeholderTextColor={colors.textTertiary}
/>
</ParamRow>
</View>
)}
</>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: colors.surface,
borderRadius: borderRadius.lg,
borderWidth: 1,
borderColor: colors.border,
padding: spacing.md,
marginBottom: spacing.sm,
},
textInput: {
backgroundColor: colors.background,
borderRadius: borderRadius.md,
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
fontSize: typography.sizes.sm,
color: colors.textPrimary,
},
});

View File

@@ -0,0 +1,95 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { colors, spacing, borderRadius } from '../../../../theme/tokens';
import { SectionHeader } from '../components/SectionHeader';
import { ParamRow } from '../components/ParamRow';
import { NumInput } from '../components/NumInput';
import type { ModelConfigFormState } from '../types';
interface PenaltiesSectionProps {
state: ModelConfigFormState;
}
export default function PenaltiesSection({ state }: PenaltiesSectionProps) {
const {
expanded, toggle, showTooltip,
penaltyRepeat, setPenaltyRepeat,
penaltyLastN, setPenaltyLastN,
penaltyFreq, setPenaltyFreq,
penaltyPresent, setPenaltyPresent,
dryMultiplier, setDryMultiplier,
dryBase, setDryBase,
dryAllowed, setDryAllowed,
dryLastN, setDryLastN,
} = state;
return (
<>
<SectionHeader
title="🚫 Pénalités de Répétition"
badge="8 params"
expanded={expanded.penalties}
onToggle={() => toggle('penalties')}
/>
{expanded.penalties && (
<View style={styles.card}>
<ParamRow paramKey="penalty_repeat" onInfo={showTooltip}>
<NumInput
value={penaltyRepeat}
onChange={setPenaltyRepeat}
placeholder="1.0 (désactivé)"
/>
</ParamRow>
<ParamRow paramKey="penalty_last_n" onInfo={showTooltip}>
<NumInput value={penaltyLastN} onChange={setPenaltyLastN} placeholder="64" />
</ParamRow>
<ParamRow paramKey="penalty_freq" onInfo={showTooltip}>
<NumInput
value={penaltyFreq}
onChange={setPenaltyFreq}
placeholder="0.0 (désactivé)"
/>
</ParamRow>
<ParamRow paramKey="penalty_present" onInfo={showTooltip}>
<NumInput
value={penaltyPresent}
onChange={setPenaltyPresent}
placeholder="0.0 (désactivé)"
/>
</ParamRow>
<ParamRow paramKey="dry_multiplier" onInfo={showTooltip}>
<NumInput
value={dryMultiplier}
onChange={setDryMultiplier}
placeholder="0.0 (désactivé)"
/>
</ParamRow>
<ParamRow paramKey="dry_base" onInfo={showTooltip}>
<NumInput value={dryBase} onChange={setDryBase} placeholder="1.75" />
</ParamRow>
<ParamRow paramKey="dry_allowed_length" onInfo={showTooltip}>
<NumInput value={dryAllowed} onChange={setDryAllowed} placeholder="2" />
</ParamRow>
<ParamRow paramKey="dry_penalty_last_n" onInfo={showTooltip}>
<NumInput
value={dryLastN}
onChange={setDryLastN}
placeholder="-1 (tout le contexte)"
/>
</ParamRow>
</View>
)}
</>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: colors.surface,
borderRadius: borderRadius.lg,
borderWidth: 1,
borderColor: colors.border,
padding: spacing.md,
marginBottom: spacing.sm,
},
});

View File

@@ -0,0 +1,94 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { colors, spacing, borderRadius } from '../../../../theme/tokens';
import { SectionHeader } from '../components/SectionHeader';
import { ParamRow } from '../components/ParamRow';
import { NumInput } from '../components/NumInput';
import { SelectRow } from '../components/SelectRow';
import type { ModelConfigFormState } from '../types';
interface SamplingSectionProps {
state: ModelConfigFormState;
}
export default function SamplingSection({ state }: SamplingSectionProps) {
const {
expanded, toggle, showTooltip,
temperature, setTemperature,
topK, setTopK, topP, setTopP, minP, setMinP,
nPredict, setNPredict, seed, setSeed,
typicalP, setTypicalP, topNSigma, setTopNSigma,
mirostat, setMirostat,
mirostatTau, setMirostatTau, mirostatEta, setMirostatEta,
xtcProb, setXtcProb, xtcThresh, setXtcThresh,
} = state;
return (
<>
<SectionHeader
title="🎲 Sampling"
badge="13 params"
expanded={expanded.sampling}
onToggle={() => toggle('sampling')}
/>
{expanded.sampling && (
<View style={styles.card}>
<ParamRow paramKey="temperature" onInfo={showTooltip}>
<NumInput value={temperature} onChange={setTemperature} placeholder="0.8" />
</ParamRow>
<ParamRow paramKey="top_k" onInfo={showTooltip}>
<NumInput value={topK} onChange={setTopK} placeholder="40" />
</ParamRow>
<ParamRow paramKey="top_p" onInfo={showTooltip}>
<NumInput value={topP} onChange={setTopP} placeholder="0.95" />
</ParamRow>
<ParamRow paramKey="min_p" onInfo={showTooltip}>
<NumInput value={minP} onChange={setMinP} placeholder="0.05" />
</ParamRow>
<ParamRow paramKey="n_predict" onInfo={showTooltip}>
<NumInput value={nPredict} onChange={setNPredict} placeholder="-1 (infini)" />
</ParamRow>
<ParamRow paramKey="seed" onInfo={showTooltip}>
<NumInput value={seed} onChange={setSeed} placeholder="-1 (aléatoire)" />
</ParamRow>
<ParamRow paramKey="typical_p" onInfo={showTooltip}>
<NumInput value={typicalP} onChange={setTypicalP} placeholder="1.0 (désactivé)" />
</ParamRow>
<ParamRow paramKey="top_n_sigma" onInfo={showTooltip}>
<NumInput value={topNSigma} onChange={setTopNSigma} placeholder="-1.0 (désactivé)" />
</ParamRow>
<SelectRow
paramKey="mirostat"
value={mirostat}
options={['0', '1', '2']}
onChange={setMirostat}
onInfo={showTooltip}
/>
<ParamRow paramKey="mirostat_tau" onInfo={showTooltip}>
<NumInput value={mirostatTau} onChange={setMirostatTau} placeholder="5.0" />
</ParamRow>
<ParamRow paramKey="mirostat_eta" onInfo={showTooltip}>
<NumInput value={mirostatEta} onChange={setMirostatEta} placeholder="0.1" />
</ParamRow>
<ParamRow paramKey="xtc_probability" onInfo={showTooltip}>
<NumInput value={xtcProb} onChange={setXtcProb} placeholder="0.0 (désactivé)" />
</ParamRow>
<ParamRow paramKey="xtc_threshold" onInfo={showTooltip}>
<NumInput value={xtcThresh} onChange={setXtcThresh} placeholder="0.1" />
</ParamRow>
</View>
)}
</>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: colors.surface,
borderRadius: borderRadius.lg,
borderWidth: 1,
borderColor: colors.border,
padding: spacing.md,
marginBottom: spacing.sm,
},
});

View File

@@ -0,0 +1,93 @@
import React from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';
import { colors, spacing, typography, borderRadius } from '../../../../theme/tokens';
import { ParamRow } from '../components/ParamRow';
import type { ModelConfigFormState } from '../types';
interface SystemPromptSectionProps {
state: ModelConfigFormState;
}
export default function SystemPromptSection({ state }: SystemPromptSectionProps) {
const {
usingAgent,
activeAgent,
systemPrompt,
setSystemPrompt,
showTooltip,
} = state;
const value = usingAgent
? (activeAgent?.systemPrompt ?? '')
: systemPrompt;
return (
<>
<Text style={styles.groupTitle}>🗒 Prompt Système</Text>
<View style={[styles.card, usingAgent && styles.cardDisabled]}>
{usingAgent && (
<Text style={styles.disabledHint}>
Désactivé le prompt de l'agent est utilisé à la place
</Text>
)}
<ParamRow paramKey="systemPrompt" onInfo={showTooltip}>
<TextInput
style={[
styles.textInput,
styles.multiline,
usingAgent && styles.inputDisabled,
]}
value={value}
onChangeText={usingAgent ? undefined : setSystemPrompt}
editable={!usingAgent}
multiline
numberOfLines={5}
textAlignVertical="top"
placeholderTextColor={colors.textTertiary}
/>
</ParamRow>
</View>
</>
);
}
const styles = StyleSheet.create({
groupTitle: {
fontSize: typography.sizes.md,
fontWeight: typography.weights.semibold,
color: colors.textPrimary,
marginBottom: spacing.sm,
},
card: {
backgroundColor: colors.surface,
borderRadius: borderRadius.lg,
borderWidth: 1,
borderColor: colors.border,
padding: spacing.md,
marginBottom: spacing.sm,
},
cardDisabled: { opacity: 0.55 },
disabledHint: {
fontSize: typography.sizes.xs,
color: colors.warning,
marginBottom: spacing.sm,
fontWeight: typography.weights.medium,
},
textInput: {
backgroundColor: colors.background,
borderRadius: borderRadius.md,
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
fontSize: typography.sizes.sm,
color: colors.textPrimary,
},
multiline: {
minHeight: 110,
textAlignVertical: 'top',
paddingTop: spacing.sm,
},
inputDisabled: {
color: colors.textTertiary,
backgroundColor: colors.surfaceSecondary,
},
});