Spaces:
Configuration error
Configuration error
Upload 19 files
Browse files- .gitignore +63 -0
- App.tsx +283 -0
- Dockerfile +77 -0
- GEMINI.md +50 -0
- README0.md +20 -0
- constants.ts +18 -0
- examples.ts +60 -0
- index.html +45 -19
- index.tsx +20 -0
- metadata.json +7 -0
- package-lock.json +0 -0
- package.json +42 -0
- requirements.txt +11 -0
- tsconfig.json +32 -0
- types.ts +72 -0
- vite.config.ts +72 -0
.gitignore
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# Logs
|
| 3 |
+
|
| 4 |
+
logs
|
| 5 |
+
|
| 6 |
+
*.log
|
| 7 |
+
|
| 8 |
+
npm-debug.log*
|
| 9 |
+
|
| 10 |
+
yarn-debug.log*
|
| 11 |
+
|
| 12 |
+
yarn-error.log*
|
| 13 |
+
|
| 14 |
+
pnpm-debug.log*
|
| 15 |
+
|
| 16 |
+
lerna-debug.log*
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
node_modules
|
| 21 |
+
|
| 22 |
+
dist
|
| 23 |
+
|
| 24 |
+
dist-ssr
|
| 25 |
+
|
| 26 |
+
*.local
|
| 27 |
+
|
| 28 |
+
.env
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
# Editor directories and files
|
| 33 |
+
|
| 34 |
+
.vscode/*
|
| 35 |
+
|
| 36 |
+
!.vscode/extensions.json
|
| 37 |
+
|
| 38 |
+
.idea
|
| 39 |
+
|
| 40 |
+
.DS_Store
|
| 41 |
+
|
| 42 |
+
*.suo
|
| 43 |
+
|
| 44 |
+
*.ntvs*
|
| 45 |
+
|
| 46 |
+
*.njsproj
|
| 47 |
+
|
| 48 |
+
*.sln
|
| 49 |
+
|
| 50 |
+
*.sw?
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
# Python
|
| 55 |
+
|
| 56 |
+
__pycache__/
|
| 57 |
+
|
| 58 |
+
*.pyc
|
| 59 |
+
|
| 60 |
+
.venv
|
| 61 |
+
|
| 62 |
+
venv/
|
| 63 |
+
|
App.tsx
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import React, { useState, useMemo } from 'react';
|
| 3 |
+
|
| 4 |
+
import { ToolDefinition, GeneratedCode, ToolType, FunctionDefinition, ParameterType } from './types';
|
| 5 |
+
|
| 6 |
+
import ToolForm from './components/ToolForm';
|
| 7 |
+
|
| 8 |
+
import CodeOutput from './components/CodeOutput';
|
| 9 |
+
|
| 10 |
+
import { generateAllCode } from './services/codeGenerator';
|
| 11 |
+
|
| 12 |
+
import { nmapScannerExample } from './examples';
|
| 13 |
+
|
| 14 |
+
import Button from './components/ui/Button';
|
| 15 |
+
|
| 16 |
+
import AiPrompt from './components/AiPrompt';
|
| 17 |
+
|
| 18 |
+
import { generateToolDefinitionFromPrompt } from './services/aiService';
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
const initialFunction: FunctionDefinition = {
|
| 23 |
+
|
| 24 |
+
id: crypto.randomUUID(),
|
| 25 |
+
|
| 26 |
+
name: 'example_function',
|
| 27 |
+
|
| 28 |
+
description: 'Краткое описание того, что делает эта функция.',
|
| 29 |
+
|
| 30 |
+
parameters: [
|
| 31 |
+
|
| 32 |
+
{
|
| 33 |
+
|
| 34 |
+
id: crypto.randomUUID(),
|
| 35 |
+
|
| 36 |
+
name: 'example_param',
|
| 37 |
+
|
| 38 |
+
type: ParameterType.STRING, // Исправлено с 'str' as any
|
| 39 |
+
|
| 40 |
+
description: 'Описание параметра.',
|
| 41 |
+
|
| 42 |
+
required: true,
|
| 43 |
+
|
| 44 |
+
},
|
| 45 |
+
|
| 46 |
+
],
|
| 47 |
+
|
| 48 |
+
returnType: ParameterType.STRING, // Исправлено с 'str' as any
|
| 49 |
+
|
| 50 |
+
returnDescription: 'Описание возвращаемого значения.',
|
| 51 |
+
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
const initialToolDefinition: ToolDefinition = {
|
| 57 |
+
|
| 58 |
+
name: 'my_tool',
|
| 59 |
+
|
| 60 |
+
type: ToolType.UTILITY,
|
| 61 |
+
|
| 62 |
+
dependencies: '',
|
| 63 |
+
|
| 64 |
+
functions: [initialFunction],
|
| 65 |
+
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
const App: React.FC = () => {
|
| 71 |
+
|
| 72 |
+
const [toolDefinition, setToolDefinition] = useState<ToolDefinition>(initialToolDefinition);
|
| 73 |
+
|
| 74 |
+
const [aiPrompt, setAiPrompt] = useState<string>('');
|
| 75 |
+
|
| 76 |
+
const [isGenerating, setIsGenerating] = useState<boolean>(false);
|
| 77 |
+
|
| 78 |
+
const [aiError, setAiError] = useState<string | null>(null);
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
const generatedCode = useMemo<GeneratedCode | null>(() => {
|
| 83 |
+
|
| 84 |
+
try {
|
| 85 |
+
|
| 86 |
+
if (toolDefinition.name && toolDefinition.functions.length > 0 && toolDefinition.functions.every(f => f.name)) {
|
| 87 |
+
|
| 88 |
+
return generateAllCode(toolDefinition);
|
| 89 |
+
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
return null;
|
| 93 |
+
|
| 94 |
+
} catch (error) {
|
| 95 |
+
|
| 96 |
+
console.error("Error generating code:", error);
|
| 97 |
+
|
| 98 |
+
return null;
|
| 99 |
+
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
}, [toolDefinition]);
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
const loadNmapExample = () => {
|
| 107 |
+
|
| 108 |
+
setToolDefinition(nmapScannerExample);
|
| 109 |
+
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
const handleAiGenerate = async () => {
|
| 115 |
+
|
| 116 |
+
if (!aiPrompt.trim()) {
|
| 117 |
+
|
| 118 |
+
setAiError("Пожалуйста, введите описание инструмента.");
|
| 119 |
+
|
| 120 |
+
return;
|
| 121 |
+
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
setIsGenerating(true);
|
| 125 |
+
|
| 126 |
+
setAiError(null);
|
| 127 |
+
|
| 128 |
+
try {
|
| 129 |
+
|
| 130 |
+
const jsonString = await generateToolDefinitionFromPrompt(aiPrompt);
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
// Бэкенд уже должен был очистить markdown, но на всякий случай
|
| 135 |
+
|
| 136 |
+
const cleanedJsonString = jsonString.replace(/^```json\s*|\s*```$/g, '').trim();
|
| 137 |
+
|
| 138 |
+
const newToolDefinition = JSON.parse(cleanedJsonString);
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
// Добавим уникальные ID, так как AI их не генерирует
|
| 143 |
+
|
| 144 |
+
if (newToolDefinition.functions) {
|
| 145 |
+
|
| 146 |
+
newToolDefinition.functions.forEach((func: FunctionDefinition) => {
|
| 147 |
+
|
| 148 |
+
func.id = crypto.randomUUID();
|
| 149 |
+
|
| 150 |
+
if (func.parameters) {
|
| 151 |
+
|
| 152 |
+
func.parameters.forEach((param: any) => {
|
| 153 |
+
|
| 154 |
+
param.id = crypto.randomUUID();
|
| 155 |
+
|
| 156 |
+
});
|
| 157 |
+
|
| 158 |
+
} else {
|
| 159 |
+
|
| 160 |
+
func.parameters = []; // Убедимся, что параметры существуют
|
| 161 |
+
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
});
|
| 165 |
+
|
| 166 |
+
} else {
|
| 167 |
+
|
| 168 |
+
newToolDefinition.functions = []; // Убедимся, что функции существуют
|
| 169 |
+
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
setToolDefinition(newToolDefinition);
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
} catch (error) {
|
| 179 |
+
|
| 180 |
+
console.error("AI generation failed:", error);
|
| 181 |
+
|
| 182 |
+
setAiError(`Не удалось сгенерировать инструмент: ${error.message}. Проверьте консоль.`);
|
| 183 |
+
|
| 184 |
+
} finally {
|
| 185 |
+
|
| 186 |
+
setIsGenerating(false);
|
| 187 |
+
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
};
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
return (
|
| 195 |
+
|
| 196 |
+
<div className="min-h-screen bg-gray-900 text-gray-100 p-4 sm:p-6 lg:p-8">
|
| 197 |
+
|
| 198 |
+
<div className="max-w-screen-2xl mx-auto">
|
| 199 |
+
|
| 200 |
+
<header className="mb-8">
|
| 201 |
+
|
| 202 |
+
<div className="text-center">
|
| 203 |
+
|
| 204 |
+
<h1 className="text-4xl sm:text-5xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-sky-400 to-blue-600">
|
| 205 |
+
|
| 206 |
+
Gemini CLI Tool Generator
|
| 207 |
+
|
| 208 |
+
</h1>
|
| 209 |
+
|
| 210 |
+
<p className="mt-2 text-lg text-gray-400">
|
| 211 |
+
|
| 212 |
+
Создайте кастомные расширения, которые Gemini сможет вызывать для решения ваших задач.
|
| 213 |
+
|
| 214 |
+
</p>
|
| 215 |
+
|
| 216 |
+
</div>
|
| 217 |
+
|
| 218 |
+
<div className="text-center mt-4">
|
| 219 |
+
|
| 220 |
+
<Button onClick={loadNmapExample} variant="secondary">
|
| 221 |
+
|
| 222 |
+
Загрузить пример: Nmap Scanner
|
| 223 |
+
|
| 224 |
+
</Button>
|
| 225 |
+
|
| 226 |
+
</div>
|
| 227 |
+
|
| 228 |
+
</header>
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
<AiPrompt
|
| 233 |
+
|
| 234 |
+
prompt={aiPrompt}
|
| 235 |
+
|
| 236 |
+
setPrompt={setAiPrompt}
|
| 237 |
+
|
| 238 |
+
onGenerate={handleAiGenerate}
|
| 239 |
+
|
| 240 |
+
isLoading={isGenerating}
|
| 241 |
+
|
| 242 |
+
error={aiError}
|
| 243 |
+
|
| 244 |
+
/>
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
<main className="grid grid-cols-1 xl:grid-cols-2 gap-8 mt-8">
|
| 249 |
+
|
| 250 |
+
<ToolForm toolDefinition={toolDefinition} setToolDefinition={setToolDefinition} />
|
| 251 |
+
|
| 252 |
+
<CodeOutput generatedCode={generatedCode} toolName={toolDefinition.name} />
|
| 253 |
+
|
| 254 |
+
</main>
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
<footer className="text-center mt-12 py-4 border-t border-gray-700">
|
| 259 |
+
|
| 260 |
+
<p className="text-gray-500">
|
| 261 |
+
|
| 262 |
+
Разработано с использованием React, Tailwind CSS и Gemini.
|
| 263 |
+
|
| 264 |
+
</p>
|
| 265 |
+
|
| 266 |
+
</footer>
|
| 267 |
+
|
| 268 |
+
</div>
|
| 269 |
+
|
| 270 |
+
</div>
|
| 271 |
+
|
| 272 |
+
);
|
| 273 |
+
|
| 274 |
+
};
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
export default App;
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
|
| 282 |
+
|
| 283 |
+
|
Dockerfile
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# Этап 1: Сборка React-фронтенда
|
| 3 |
+
|
| 4 |
+
FROM node:18-slim AS build
|
| 5 |
+
|
| 6 |
+
WORKDIR /app
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
# Копируем package.json и устанавливаем npm зависимости
|
| 11 |
+
|
| 12 |
+
COPY package.json package-lock.json ./
|
| 13 |
+
|
| 14 |
+
RUN npm install
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
# Копируем остальной код фронтенда
|
| 19 |
+
|
| 20 |
+
COPY . .
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
# Собираем production build (создает папку 'dist')
|
| 25 |
+
|
| 26 |
+
RUN npm run build
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
# Этап 2: Настройка Python-сервера (FastAPI)
|
| 31 |
+
|
| 32 |
+
FROM python:3.10-slim
|
| 33 |
+
|
| 34 |
+
WORKDIR /app
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
# Установка переменных окружения
|
| 39 |
+
|
| 40 |
+
ENV PYTHONUNBUFFERED 1
|
| 41 |
+
|
| 42 |
+
ENV PYTHONDONTWRITEBYTECODE 1
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
# Копируем Python-зависимости и устанавливаем их
|
| 47 |
+
|
| 48 |
+
COPY requirements.txt .
|
| 49 |
+
|
| 50 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
# Копируем код бэкенда (FastAPI)
|
| 55 |
+
|
| 56 |
+
COPY ./backend ./backend
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
# Копируем собранный фронтенд из Этапа 1
|
| 61 |
+
|
| 62 |
+
COPY --from=build /app/dist ./dist
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
# Порт 7860 - стандартный для HF Spaces
|
| 67 |
+
|
| 68 |
+
EXPOSE 7860
|
| 69 |
+
|
| 70 |
+
ENV PORT=7860
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
# Команда для запуска Uvicorn (FastAPI)
|
| 75 |
+
|
| 76 |
+
CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "7860"]
|
| 77 |
+
|
GEMINI.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Инструкция для Агента: Инструмент "nmap_scanner"
|
| 2 |
+
|
| 3 |
+
## Описание
|
| 4 |
+
|
| 5 |
+
Этот инструмент предоставляет прямой доступ к сетевому сканеру Nmap для проведения разведки и обнаружения хостов в сети. Он относится к типу **UTILITY**. Используй его для анализа сетевой безопасности, инвентаризации устройств и проверки открытых портов.
|
| 6 |
+
|
| 7 |
+
## Функции
|
| 8 |
+
|
| 9 |
+
### `nmap_scanner:run_scan`
|
| 10 |
+
|
| 11 |
+
Запускает детальное сканирование Nmap на указанные цели. Позволяет гибко настраивать тип сканирования, определять службы и версии ПО.
|
| 12 |
+
|
| 13 |
+
**Параметры:**
|
| 14 |
+
- `targets` (*str*): Цели для сканирования (IP-адрес, домен, CIDR-диапазон). Например: '192.168.1.1', 'scanme.nmap.org', '10.0.0.0/24'. (обязательный)
|
| 15 |
+
- `ports` (*str*): Порты для сканирования. Например: '21-25,80,443', '1-1024'. (обязательный)
|
| 16 |
+
- `arguments` (*str*): Дополнительные аргументы командной строки Nmap. Например: '-sV -sC' для определения версий и запуска скриптов, или '-A' для агрессивного сканирования. (обязательный)
|
| 17 |
+
|
| 18 |
+
**Возвращает:**
|
| 19 |
+
*dict* - Результат сканирования в формате JSON, содержащий информацию о хостах, их состоянии, открытых портах, службах и версиях.
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
### `nmap_scanner:host_discovery`
|
| 24 |
+
|
| 25 |
+
Быстро обнаруживает активные (включенные) хосты в указанной сети с помощью 'ping scan' (`-sn`), не проводя полного сканирования портов.
|
| 26 |
+
|
| 27 |
+
**Параметры:**
|
| 28 |
+
- `network_cidr` (*str*): Сетевой диапазон в формате CIDR для обнаружения хостов. Например: '192.168.1.0/24'. (обязательный)
|
| 29 |
+
|
| 30 |
+
**Возвращает:**
|
| 31 |
+
*list* - Список IP-адресов активных хостов, обнаруженных в сети.
|
| 32 |
+
|
| 33 |
+
## Примеры использования
|
| 34 |
+
|
| 35 |
+
**ВАЖНО:** Всегда используй формат `nmap_scanner:имя_функции()`.
|
| 36 |
+
|
| 37 |
+
**Пример 1: Обнаружение всех активных устройств в локальной сети**
|
| 38 |
+
```
|
| 39 |
+
nmap_scanner:host_discovery(network_cidr="192.168.0.0/24")
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
**Пример 2: Быстрое сканирование популярных портов на конкретном хосте**
|
| 43 |
+
```
|
| 44 |
+
nmap_scanner:run_scan(targets="192.168.1.1", ports="1-1024", arguments="-T4")
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
**Пример 3: Агрессивное сканирование веб-сервера для определения ОС, служб и уязвимостей**
|
| 48 |
+
```
|
| 49 |
+
nmap_scanner:run_scan(targets="scanme.nmap.org", ports="80,443", arguments="-A -v")
|
| 50 |
+
```
|
README0.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div align="center">
|
| 2 |
+
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
|
| 3 |
+
</div>
|
| 4 |
+
|
| 5 |
+
# Run and deploy your AI Studio app
|
| 6 |
+
|
| 7 |
+
This contains everything you need to run your app locally.
|
| 8 |
+
|
| 9 |
+
View your app in AI Studio: https://ai.studio/apps/drive/1DWLDNsbZ8bO_lQPzuDVQB3cpW92HgYCC
|
| 10 |
+
|
| 11 |
+
## Run Locally
|
| 12 |
+
|
| 13 |
+
**Prerequisites:** Node.js
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
1. Install dependencies:
|
| 17 |
+
`npm install`
|
| 18 |
+
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
|
| 19 |
+
3. Run the app:
|
| 20 |
+
`npm run dev`
|
constants.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import { ToolType, ParameterType } from './types';
|
| 3 |
+
|
| 4 |
+
export const TOOL_TYPES: ToolType[] = Object.values(ToolType);
|
| 5 |
+
export const PARAMETER_TYPES: ParameterType[] = Object.values(ParameterType);
|
| 6 |
+
|
| 7 |
+
export const PARAMETER_TYPE_DESCRIPTIONS: Record<ParameterType, string> = {
|
| 8 |
+
[ParameterType.STRING]: 'Текстовая строка (e.g., "hello world").',
|
| 9 |
+
[ParameterType.INTEGER]: 'Целое число (e.g., 10, -5).',
|
| 10 |
+
[ParameterType.FLOAT]: 'Число с плавающей точкой (e.g., 3.14).',
|
| 11 |
+
[ParameterType.BOOLEAN]: 'Логическое значение (True или False).',
|
| 12 |
+
[ParameterType.LIST]: 'Упорядоченный список элементов (e.g., ["a", "b"]).',
|
| 13 |
+
[ParameterType.DICTIONARY]: 'Словарь пар ключ-значение (e.g., {"key": "value"}).'
|
| 14 |
+
};
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
|
examples.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import { ToolDefinition, ToolType, ParameterType } from './types';
|
| 3 |
+
|
| 4 |
+
export const nmapScannerExample: ToolDefinition = {
|
| 5 |
+
name: 'nmap_scanner',
|
| 6 |
+
type: ToolType.UTILITY,
|
| 7 |
+
dependencies: 'python-nmap',
|
| 8 |
+
functions: [
|
| 9 |
+
{
|
| 10 |
+
id: 'nmap-func-1',
|
| 11 |
+
name: 'run_scan',
|
| 12 |
+
description: 'Запускает сканирование Nmap на указанные цели с заданными аргументами. Позволяет выполнять гибкую разведку сети.',
|
| 13 |
+
parameters: [
|
| 14 |
+
{
|
| 15 |
+
id: 'nmap-param-1',
|
| 16 |
+
name: 'targets',
|
| 17 |
+
type: ParameterType.STRING,
|
| 18 |
+
description: "Цели для сканирования (IP, домен, CIDR). Например: '192.168.1.1', 'scanme.nmap.org', '10.0.0.0/24'.",
|
| 19 |
+
required: true,
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
id: 'nmap-param-2',
|
| 23 |
+
name: 'ports',
|
| 24 |
+
type: ParameterType.STRING,
|
| 25 |
+
description: "Порты для сканирования. Например: '21-25,80,443,8080'.",
|
| 26 |
+
required: true,
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
id: 'nmap-param-3',
|
| 30 |
+
name: 'arguments',
|
| 31 |
+
type: ParameterType.STRING,
|
| 32 |
+
description: "Дополнительные аргументы Nmap для тонкой настройки сканирования. Например: '-sV -sC -O'.",
|
| 33 |
+
required: true,
|
| 34 |
+
},
|
| 35 |
+
],
|
| 36 |
+
returnType: ParameterType.DICTIONARY,
|
| 37 |
+
returnDescription: 'Результат сканирования в формате JSON, содержащий информацию о хостах, портах, службах и их версиях.',
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
id: 'nmap-func-2',
|
| 41 |
+
name: 'host_discovery',
|
| 42 |
+
description: 'Обнаруживает активные хосты в указанной сети (ping scan), не проводя сканирование портов.',
|
| 43 |
+
parameters: [
|
| 44 |
+
{
|
| 45 |
+
id: 'nmap-param-4',
|
| 46 |
+
name: 'network_cidr',
|
| 47 |
+
type: ParameterType.STRING,
|
| 48 |
+
description: "Сетевой диапазон в формате CIDR для обнаружения хостов. Например: '192.168.1.0/24'.",
|
| 49 |
+
required: true,
|
| 50 |
+
},
|
| 51 |
+
],
|
| 52 |
+
returnType: ParameterType.LIST,
|
| 53 |
+
returnDescription: 'Список IP-адресов активных хостов, обнаруженных в сети.',
|
| 54 |
+
},
|
| 55 |
+
],
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
|
index.html
CHANGED
|
@@ -1,19 +1,45 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
<!DOCTYPE html>
|
| 3 |
+
<html lang="en">
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8" />
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
+
<title>FastMCP Tool Generator</title>
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
| 10 |
+
<style>
|
| 11 |
+
/* Custom scrollbar for webkit browsers */
|
| 12 |
+
::-webkit-scrollbar {
|
| 13 |
+
width: 8px;
|
| 14 |
+
height: 8px;
|
| 15 |
+
}
|
| 16 |
+
::-webkit-scrollbar-track {
|
| 17 |
+
background: #1f2937; /* bg-gray-800 */
|
| 18 |
+
}
|
| 19 |
+
::-webkit-scrollbar-thumb {
|
| 20 |
+
background: #4b5563; /* bg-gray-600 */
|
| 21 |
+
border-radius: 4px;
|
| 22 |
+
}
|
| 23 |
+
::-webkit-scrollbar-thumb:hover {
|
| 24 |
+
background: #6b7280; /* bg-gray-500 */
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
<script type="importmap">
|
| 28 |
+
{
|
| 29 |
+
"imports": {
|
| 30 |
+
"react": "https://aistudiocdn.com/react@^19.2.0",
|
| 31 |
+
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
|
| 32 |
+
"react/": "https://aistudiocdn.com/react@^19.2.0/",
|
| 33 |
+
"@google/genai": "https://aistudiocdn.com/@google/genai@^1.29.0"
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
</script>
|
| 37 |
+
<link rel="stylesheet" href="/index.css">
|
| 38 |
+
</head>
|
| 39 |
+
<body class="bg-gray-900 text-gray-100">
|
| 40 |
+
<div id="root"></div>
|
| 41 |
+
<script type="module" src="/index.tsx"></script>
|
| 42 |
+
</body>
|
| 43 |
+
</html>
|
| 44 |
+
|
| 45 |
+
|
index.tsx
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import React from 'react';
|
| 3 |
+
import ReactDOM from 'react-dom/client';
|
| 4 |
+
import App from './App';
|
| 5 |
+
|
| 6 |
+
const rootElement = document.getElementById('root');
|
| 7 |
+
if (!rootElement) {
|
| 8 |
+
throw new Error("Could not find root element to mount to");
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
const root = ReactDOM.createRoot(rootElement);
|
| 12 |
+
root.render(
|
| 13 |
+
<React.StrictMode>
|
| 14 |
+
<App />
|
| 15 |
+
</React.StrictMode>
|
| 16 |
+
);
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
|
metadata.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "Copy of Copy of Copy of FastMCP Tool Generator",
|
| 3 |
+
"description": "A web application to generate complete, self-contained, and deployable FastMCP tool boilerplates for Gemini CLI based on user's technical requirements. It creates all necessary files including server logic, setup configuration, and agent instructions.",
|
| 4 |
+
"requestFramePermissions": []
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
|
package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
{
|
| 3 |
+
"name": "fastmcp-tool-generator-hf",
|
| 4 |
+
"version": "0.0.0",
|
| 5 |
+
"private": true,
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "vite",
|
| 8 |
+
"build": "tsc && vite build",
|
| 9 |
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
| 10 |
+
"preview": "vite preview"
|
| 11 |
+
},
|
| 12 |
+
"dependencies": {
|
| 13 |
+
"autoprefixer": "^10.4.19",
|
| 14 |
+
"axios": "^1.7.2",
|
| 15 |
+
"highlight.js": "^11.9.0",
|
| 16 |
+
"jszip": "^3.10.1",
|
| 17 |
+
"postcss": "^8.4.38",
|
| 18 |
+
"react": "^18.2.0",
|
| 19 |
+
"react-dom": "^18.2.0",
|
| 20 |
+
"react-hot-toast": "^2.4.1",
|
| 21 |
+
"tailwindcss": "^3.4.4"
|
| 22 |
+
},
|
| 23 |
+
"devDependencies": {
|
| 24 |
+
"@types/highlight.js": "^10.1.0",
|
| 25 |
+
"@types/jszip": "^3.10.1",
|
| 26 |
+
"@types/react": "^18.2.66",
|
| 27 |
+
"@types/react-dom": "^18.2.22",
|
| 28 |
+
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
| 29 |
+
"@typescript-eslint/parser": "^7.2.0",
|
| 30 |
+
"@vitejs/plugin-react": "^4.2.1",
|
| 31 |
+
"eslint": "^8.57.0",
|
| 32 |
+
"eslint-plugin-react-hooks": "^4.6.0",
|
| 33 |
+
"eslint-plugin-react-refresh": "^0.4.6",
|
| 34 |
+
"typescript": "^5.2.2",
|
| 35 |
+
"vite": "^5.2.0"
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
fastapi
|
| 3 |
+
|
| 4 |
+
uvicorn[standard]
|
| 5 |
+
|
| 6 |
+
google-generativeai
|
| 7 |
+
|
| 8 |
+
pydantic
|
| 9 |
+
|
| 10 |
+
python-dotenv
|
| 11 |
+
|
tsconfig.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"target": "ES2022",
|
| 4 |
+
"experimentalDecorators": true,
|
| 5 |
+
"useDefineForClassFields": false,
|
| 6 |
+
"module": "ESNext",
|
| 7 |
+
"lib": [
|
| 8 |
+
"ES2022",
|
| 9 |
+
"DOM",
|
| 10 |
+
"DOM.Iterable"
|
| 11 |
+
],
|
| 12 |
+
"skipLibCheck": true,
|
| 13 |
+
"types": [
|
| 14 |
+
"node"
|
| 15 |
+
],
|
| 16 |
+
"moduleResolution": "bundler",
|
| 17 |
+
"isolatedModules": true,
|
| 18 |
+
"moduleDetection": "force",
|
| 19 |
+
"allowJs": true,
|
| 20 |
+
"jsx": "react-jsx",
|
| 21 |
+
"paths": {
|
| 22 |
+
"@/*": [
|
| 23 |
+
"./*"
|
| 24 |
+
]
|
| 25 |
+
},
|
| 26 |
+
"allowImportingTsExtensions": true,
|
| 27 |
+
"noEmit": true
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
|
types.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
export enum ToolType {
|
| 3 |
+
REST_API = 'REST_API',
|
| 4 |
+
CLI = 'CLI',
|
| 5 |
+
DATABASE = 'DATABASE',
|
| 6 |
+
CUSTOM = 'CUSTOM',
|
| 7 |
+
UTILITY = 'UTILITY',
|
| 8 |
+
CALCULATOR = 'CALCULATOR',
|
| 9 |
+
CONVERTER = 'CONVERTER'
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
export enum ParameterType {
|
| 13 |
+
STRING = 'str',
|
| 14 |
+
INTEGER = 'int',
|
| 15 |
+
FLOAT = 'float',
|
| 16 |
+
BOOLEAN = 'bool',
|
| 17 |
+
LIST = 'list',
|
| 18 |
+
DICTIONARY = 'dict'
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
export interface ParameterDefinition {
|
| 22 |
+
id: string;
|
| 23 |
+
name: string;
|
| 24 |
+
type: ParameterType;
|
| 25 |
+
description: string;
|
| 26 |
+
required: boolean;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
export interface FunctionDefinition {
|
| 30 |
+
id: string;
|
| 31 |
+
name: string;
|
| 32 |
+
description: string;
|
| 33 |
+
parameters: ParameterDefinition[];
|
| 34 |
+
returnType: ParameterType;
|
| 35 |
+
returnDescription: string;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
export interface ToolDefinition {
|
| 39 |
+
name: string;
|
| 40 |
+
type: ToolType;
|
| 41 |
+
dependencies: string;
|
| 42 |
+
functions: FunctionDefinition[];
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
export interface GeneratedCode {
|
| 46 |
+
setupPy: string;
|
| 47 |
+
serverPy: string;
|
| 48 |
+
settingsJson: string;
|
| 49 |
+
geminiMd: string;
|
| 50 |
+
examplesMd: string;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
// Ркспортируем для использования РІ AI промпте
|
| 54 |
+
export const initialFunctionForPrompt: Omit<FunctionDefinition, 'id'> = {
|
| 55 |
+
name: 'example_function',
|
| 56 |
+
description: 'Краткое описание того, что делает эта функция.',
|
| 57 |
+
parameters: [
|
| 58 |
+
{
|
| 59 |
+
id: 'param-id-1', // id здесь для примера, в реальности он генерируется
|
| 60 |
+
name: 'example_param',
|
| 61 |
+
type: ParameterType.STRING,
|
| 62 |
+
description: 'Описание параметра.',
|
| 63 |
+
required: true,
|
| 64 |
+
},
|
| 65 |
+
],
|
| 66 |
+
returnType: ParameterType.STRING,
|
| 67 |
+
returnDescription: 'Описание возвращаемого значения.',
|
| 68 |
+
};
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
|
vite.config.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import path from 'path';
|
| 2 |
+
|
| 3 |
+
import { defineConfig, loadEnv } from 'vite';
|
| 4 |
+
|
| 5 |
+
import react from '@vitejs/plugin-react';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
export default defineConfig(({ mode }) => {
|
| 10 |
+
|
| 11 |
+
const env = loadEnv(mode, '.', '');
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
// Порт для FastAPI (бэкенда) при локальной разработке
|
| 16 |
+
|
| 17 |
+
const PYTHON_BACKEND_PORT = 8000;
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
return {
|
| 22 |
+
|
| 23 |
+
server: {
|
| 24 |
+
|
| 25 |
+
// Используем порт 3000 для Vite (фронтенда)
|
| 26 |
+
|
| 27 |
+
port: 3000,
|
| 28 |
+
|
| 29 |
+
host: '0.0.0.0',
|
| 30 |
+
|
| 31 |
+
proxy: {
|
| 32 |
+
|
| 33 |
+
// Перенаправляем все /api запросы на наш Python бэкенд
|
| 34 |
+
|
| 35 |
+
'/api': {
|
| 36 |
+
|
| 37 |
+
target: `http://127.0.0.1:${PYTHON_BACKEND_PORT}`, // ИСПРАВЛЕНО
|
| 38 |
+
|
| 39 |
+
changeOrigin: true,
|
| 40 |
+
|
| 41 |
+
secure: false,
|
| 42 |
+
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
},
|
| 48 |
+
|
| 49 |
+
plugins: [react()],
|
| 50 |
+
|
| 51 |
+
define: {
|
| 52 |
+
|
| 53 |
+
// Ключ API БОЛЬШЕ НЕ НУЖЕН в define!
|
| 54 |
+
|
| 55 |
+
},
|
| 56 |
+
|
| 57 |
+
resolve: {
|
| 58 |
+
|
| 59 |
+
alias: {
|
| 60 |
+
|
| 61 |
+
'@': path.resolve(__dirname, '.'),
|
| 62 |
+
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
});
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
|