0.4 - Прогон по одной записи, стрим в файл.
This commit is contained in:
@@ -1,27 +1,44 @@
|
|||||||
# Папки
|
# cart-to-json
|
||||||
|
|
||||||
|
Парсинг .txt списков автомобилей в JSON через Ollama.
|
||||||
|
|
||||||
|
## Папки
|
||||||
- `lists/` — необработанные .txt файлы
|
- `lists/` — необработанные .txt файлы
|
||||||
- `done/` — обработанные файлы (переносятся из lists/)
|
- `done/` — обработанные (переносятся из lists/)
|
||||||
- `res/` — результат в JSON
|
- `res/` — результат в JSON
|
||||||
|
|
||||||
# Запуск
|
## Формат входных данных
|
||||||
|
Табуляция: `brand`, `model`, `engine_code`, `date_range`.
|
||||||
|
Разделители записей задаются в `RECORD_DELIMITERS` (по умолчанию `\n`, `\r\n`, `\r`).
|
||||||
|
**Важно:** `\n` разделяет только по строкам. Несколько записей в одной строке не разобьются.
|
||||||
|
|
||||||
## Docker
|
## Запуск
|
||||||
```bash
|
|
||||||
chmod +x run.sh && ./run.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
### Локально
|
||||||
# Статус загрузки и работы модели в отдельном терминале
|
|
||||||
docker compose logs -f ollama
|
|
||||||
```
|
|
||||||
|
|
||||||
При первом запуске Ollama скачает модель `gemma3n:e4b` (7.5 GB) (может занять несколько минут).
|
|
||||||
|
|
||||||
## Локально
|
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
python3 parse.py
|
python3 parse.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
```bash
|
||||||
|
chmod +x run.sh && ./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Логи Ollama:
|
||||||
|
```bash
|
||||||
|
docker compose logs -f ollama
|
||||||
|
```
|
||||||
|
|
||||||
|
При первом запуске скачивается модель `mithunrajm06/gemma-3n-e4b:latest`.
|
||||||
|
|
||||||
|
## Переменные окружения
|
||||||
|
| Переменная | Описание |
|
||||||
|
|------------|----------|
|
||||||
|
| `OLLAMA_HOST` | URL Ollama (по умолчанию `http://localhost:11434`) |
|
||||||
|
| `MODEL` | Модель для парсинга |
|
||||||
|
| `NUM_CTX` | Размер контекста (32768) |
|
||||||
|
| `NUM_PREDICT` | Лимит выходных токенов (512) |
|
||||||
|
| `LOG_STREAM` | `1` — вывод стрима в консоль |
|
||||||
|
| `SHOW_IO` | `1` — показывать вход и выход по каждой записи |
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -7,14 +7,14 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "11435:11434" # 11435 — если локальный Ollama уже на 11434
|
- "11435:11434" # 11435 — если локальный Ollama уже на 11434
|
||||||
environment:
|
environment:
|
||||||
OLLAMA_MODEL: gemma3n:e4b
|
OLLAMA_MODEL: mithunrajm06/gemma-3n-e4b:latest
|
||||||
entrypoint: ["/bin/sh", "-c"]
|
entrypoint: ["/bin/sh", "-c"]
|
||||||
command:
|
command:
|
||||||
- |
|
- |
|
||||||
ollama serve &
|
ollama serve &
|
||||||
sleep 10
|
sleep 10
|
||||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
ollama pull $${OLLAMA_MODEL:-gemma3n:e4b} 2>/dev/null && break
|
ollama pull $${OLLAMA_MODEL:-mithunrajm06/gemma-3n-e4b:latest} 2>/dev/null && break
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
wait
|
wait
|
||||||
@@ -28,7 +28,7 @@ services:
|
|||||||
- ./done:/app/done
|
- ./done:/app/done
|
||||||
environment:
|
environment:
|
||||||
OLLAMA_HOST: http://ollama:11434
|
OLLAMA_HOST: http://ollama:11434
|
||||||
MODEL: gemma3n:e4b
|
MODEL: mithunrajm06/gemma-3n-e4b:latest
|
||||||
depends_on:
|
depends_on:
|
||||||
ollama:
|
ollama:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
OLLAMA_HOST="${OLLAMA_HOST:-http://localhost:11434}"
|
OLLAMA_HOST="${OLLAMA_HOST:-http://localhost:11434}"
|
||||||
MODEL="${MODEL:-gemma3n:e4b}"
|
MODEL="${MODEL:-mithunrajm06/gemma-3n-e4b:latest}"
|
||||||
MODEL_NAME="${MODEL%%:*}"
|
MODEL_NAME="${MODEL%%:*}"
|
||||||
|
|
||||||
echo "Waiting for Ollama..."
|
echo "Waiting for Ollama..."
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
HYUNDAI Accent 1.3 [G4E-A] 08.1999- HYUNDAI Accent 1.3 [G4EH] 08.2002- \n HYUNDAI Accent 1.4 GL 11.2005-
|
HYUNDAI Accent 1.3 [G4E-A] 08.1999-
|
||||||
HYUNDAI Accent 1.5 [G4EB] 08.2002- HYUNDAI Accent 1.6 [G4ED-G] 12.2002-
|
HYUNDAI Accent 1.3 [G4EH] 08.2002-
|
||||||
|
HYUNDAI Accent 1.4 GL 11.2005-
|
||||||
|
HYUNDAI Accent 1.5 [G4EB] 08.2002-
|
||||||
|
HYUNDAI Accent 1.6 [G4ED-G] 12.2002-
|
||||||
HYUNDAI Accent 1.6 GLS 11.2005-
|
HYUNDAI Accent 1.6 GLS 11.2005-
|
||||||
HYUNDAI Coupe 1.6 16V [G4ED-G] 03.2002-
|
HYUNDAI Coupe 1.6 16V [G4ED-G] 03.2002-
|
||||||
HYUNDAI Coupe 2.0 16V [G4GF] 08.2002-
|
HYUNDAI Coupe 2.0 16V [G4GF] 08.2002-
|
||||||
HYUNDAI Coupe 2.0 GLS 08.2002-
|
HYUNDAI Coupe 2.0 GLS 08.2002-
|
||||||
KIA Rio 1.6 16V [G4ED] 03.2005-
|
KIA Rio 1.6 16V [G4ED] 03.2005-
|
||||||
|
MERCEDES-BENZ CABRIOLET (W111) 280 SE 3.5 (111.025) [M 116.980] 01/1969 - 12/1971
|
||||||
|
MERCEDES-BENZ COUPE (W111) 280 SE 3.5 (111.026) [M 116.980] 01/1969 - 12/1971
|
||||||
|
MERCEDES-BENZ S-CLASS (W108, W109) 280 SE,SEL 3.5 (108.057, 108.058) [M 116.980] 03/1971 - 08/1972
|
||||||
|
MERCEDES-BENZ S-CLASS (W108, W109) 300 SEL 3.5 (109.056) [M 116.981] 01/1970 - 07/1972
|
||||||
|
MERCEDES-BENZ S-CLASS (W116) 350 SE,SEL (116.028, 116.029) [M 116.983] 08/1972 - 02/1976
|
||||||
|
MERCEDES-BENZ SL купе (C107) 350 SLC (107.023) [M 116.982, M 116.984] 01/1972 - 02/1976
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Скрипт загружает .txt файлы из lists/, отправляет каждый в локальную Ollama
|
Скрипт загружает .txt файлы из lists/, разбивает по разделителю,
|
||||||
с системным промптом и сохраняет ответ в res/. Успешные файлы переносятся в done/.
|
отправляет каждую запись в Ollama, собирает JSON в res/.
|
||||||
При падении можно перезапустить — необработанные остаются в lists/.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@@ -19,71 +18,97 @@ LISTS_DIR = pathlib.Path(__file__).parent / "lists"
|
|||||||
RES_DIR = pathlib.Path(__file__).parent / "res"
|
RES_DIR = pathlib.Path(__file__).parent / "res"
|
||||||
DONE_DIR = pathlib.Path(__file__).parent / "done"
|
DONE_DIR = pathlib.Path(__file__).parent / "done"
|
||||||
OLLAMA_HOST = os.environ.get("OLLAMA_HOST", "http://localhost:11434")
|
OLLAMA_HOST = os.environ.get("OLLAMA_HOST", "http://localhost:11434")
|
||||||
MODEL = os.environ.get("MODEL", "gemma3n:e4b")
|
MODEL = os.environ.get("MODEL", "mithunrajm06/gemma-3n-e4b:latest")
|
||||||
# размер контекста (токенов для этой модели это максимум, больше контекст больше расход ОЗУ)
|
NUM_CTX = int(os.environ.get("NUM_CTX", "32768"))
|
||||||
NUM_CTX = int(os.environ.get("NUM_CTX", "32768"))
|
NUM_PREDICT = int(os.environ.get("NUM_PREDICT", "512"))
|
||||||
RETRY_COUNT = 3
|
RETRY_COUNT = 3
|
||||||
RETRY_DELAY = 5
|
RETRY_DELAY = 5
|
||||||
LOG_STREAM = os.environ.get("LOG_STREAM", "").lower() in ("1", "true", "yes")
|
LOG_STREAM = os.environ.get("LOG_STREAM", "").lower() in ("1", "true", "yes")
|
||||||
|
# показывать вход и выход по каждой записи (0/false — отключить)
|
||||||
|
SHOW_IO = os.environ.get("SHOW_IO", "1").lower() in ("1", "true", "yes")
|
||||||
|
|
||||||
SYSTEM_PROMPT = """You are a data processing assistant.
|
# Разделители записей при разбиении файла (\n — перенос строки, \r\n — Windows)
|
||||||
The input text is a list of tab-separated lines: brand, model, engine_code, date_range.
|
RECORD_DELIMITERS = ("\n", "\r\n", "\r")
|
||||||
Convert to a JSON array of objects with fields: brand, model, engine_code, date_range.
|
|
||||||
The number of elements in JSON MUST match the number of lines in the list.
|
EXTRACT_PROMPT = """Extract brand, model, engine_code, date_range from the text.
|
||||||
Keep empty fields as empty string "".
|
Return JSON object only: {"brand":"","model":"","engine_code":"","date_range":""}
|
||||||
Output ONLY the JSON array. No explanations, no markdown, no other text before or after."""
|
Empty fields as "". No other text."""
|
||||||
|
|
||||||
|
|
||||||
def process_file(client: Client, filepath: pathlib.Path) -> bool:
|
def prepare_records(content: str) -> list[str]:
|
||||||
"""Обрабатывает один файл. Возвращает True при успехе."""
|
"""1) Подготовка списка записей из файла по разделителям."""
|
||||||
content = filepath.read_text(encoding="utf-8")
|
for sep in RECORD_DELIMITERS:
|
||||||
out_path = RES_DIR / filepath.with_suffix(".json").name
|
content = content.replace(sep, RECORD_DELIMITERS[0])
|
||||||
|
return [r.strip() for r in content.split(RECORD_DELIMITERS[0]) if r.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def extract_record(client: Client, record: str) -> dict:
|
||||||
|
"""2) Отправка промпт + 1 запись в нейронку. 3) Получение ответа."""
|
||||||
for attempt in range(1, RETRY_COUNT + 1):
|
for attempt in range(1, RETRY_COUNT + 1):
|
||||||
try:
|
try:
|
||||||
t0 = time.perf_counter()
|
response = client.chat(
|
||||||
print(f" {filepath.name} — ", end="", flush=True)
|
|
||||||
|
|
||||||
result = ""
|
|
||||||
stream = client.chat(
|
|
||||||
model=MODEL,
|
model=MODEL,
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "system", "content": SYSTEM_PROMPT},
|
{"role": "system", "content": EXTRACT_PROMPT},
|
||||||
{"role": "user", "content": f"Convert to JSON. Output only the JSON array:\n\n{content}"},
|
{"role": "user", "content": record},
|
||||||
],
|
],
|
||||||
options={"num_ctx": NUM_CTX},
|
options={"num_ctx": NUM_CTX, "num_predict": NUM_PREDICT},
|
||||||
stream=True,
|
|
||||||
)
|
)
|
||||||
for chunk in stream:
|
result = response.get("message", {}).get("content", "")
|
||||||
part = chunk.get("message", {}).get("content", "") or ""
|
if "```" in result:
|
||||||
result += part
|
result = result.split("```")[1]
|
||||||
if part:
|
if result.strip().lower().startswith("json"):
|
||||||
if LOG_STREAM:
|
result = result.strip()[4:].strip()
|
||||||
sys.stdout.write(part)
|
obj = json.loads(result)
|
||||||
else:
|
return {
|
||||||
sys.stdout.write(".")
|
"brand": obj.get("brand", ""),
|
||||||
sys.stdout.flush()
|
"model": obj.get("model", ""),
|
||||||
|
"engine_code": obj.get("engine_code", ""),
|
||||||
elapsed = time.perf_counter() - t0
|
"date_range": obj.get("date_range", ""),
|
||||||
try:
|
}
|
||||||
data = json.loads(result)
|
except (json.JSONDecodeError, KeyError) as e:
|
||||||
out_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
out_path.write_text(result, encoding="utf-8")
|
|
||||||
|
|
||||||
print(f"\n" if LOG_STREAM else " ", end="")
|
|
||||||
print(f" {len(result)} chars, {elapsed:.1f}s — OK")
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f" {filepath.name} — попытка {attempt}/{RETRY_COUNT} — ошибка: {e}")
|
|
||||||
if attempt < RETRY_COUNT:
|
if attempt < RETRY_COUNT:
|
||||||
time.sleep(RETRY_DELAY)
|
time.sleep(RETRY_DELAY)
|
||||||
else:
|
else:
|
||||||
print(f" {filepath.name} — пропущен после {RETRY_COUNT} попыток")
|
return {"brand": "", "model": "", "engine_code": "", "date_range": record}
|
||||||
return False
|
except Exception:
|
||||||
|
if attempt < RETRY_COUNT:
|
||||||
|
time.sleep(RETRY_DELAY)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
return {"brand": "", "model": "", "engine_code": "", "date_range": record}
|
||||||
|
|
||||||
return False
|
|
||||||
|
def process_file(client: Client, filepath: pathlib.Path) -> bool:
|
||||||
|
"""Обработка файла: подготовка → запрос по записи → добавление в JSON."""
|
||||||
|
content = filepath.read_text(encoding="utf-8")
|
||||||
|
records = prepare_records(content)
|
||||||
|
out_path = RES_DIR / filepath.with_suffix(".json").name
|
||||||
|
|
||||||
|
if not records:
|
||||||
|
print(f" {filepath.name} — 0 записей")
|
||||||
|
return False
|
||||||
|
|
||||||
|
out_path.write_text("[]", encoding="utf-8")
|
||||||
|
total = len(records)
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
data = []
|
||||||
|
|
||||||
|
for i, record in enumerate(records, 1):
|
||||||
|
print(f" [{i}/{total}] ", end="", flush=True)
|
||||||
|
obj = extract_record(client, record)
|
||||||
|
data.append(obj)
|
||||||
|
out_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||||
|
if SHOW_IO:
|
||||||
|
inp = record[:60] + "…" if len(record) > 60 else record
|
||||||
|
out = json.dumps(obj, ensure_ascii=False)
|
||||||
|
print(f"вход: {inp}", flush=True)
|
||||||
|
print(f" выход: {out}", flush=True)
|
||||||
|
else:
|
||||||
|
print("✓", flush=True)
|
||||||
|
elapsed = time.perf_counter() - t0
|
||||||
|
print(f" {filepath.name} — {total} записей, {elapsed:.1f}s — OK")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
@@ -99,13 +124,7 @@ def main() -> None:
|
|||||||
|
|
||||||
print(f"Файлов к обработке: {len(txt_files)}")
|
print(f"Файлов к обработке: {len(txt_files)}")
|
||||||
|
|
||||||
# Последовательная обработка: следующий файл только после завершения текущего
|
|
||||||
for filepath in txt_files:
|
for filepath in txt_files:
|
||||||
out_path = RES_DIR / filepath.with_suffix(".json").name
|
|
||||||
if out_path.exists():
|
|
||||||
print(f" {filepath.name} — уже в res/, перенос в done/")
|
|
||||||
shutil.move(str(filepath), DONE_DIR / filepath.name)
|
|
||||||
continue
|
|
||||||
if process_file(client, filepath):
|
if process_file(client, filepath):
|
||||||
shutil.move(str(filepath), DONE_DIR / filepath.name)
|
shutil.move(str(filepath), DONE_DIR / filepath.name)
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Локальный парсер без Ollama: читает .txt из lists/, парсит табуляцию,
|
|
||||||
сохраняет JSON в res/, переносит успешные в done/.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import pathlib
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
LISTS_DIR = pathlib.Path(__file__).parent / "lists"
|
|
||||||
RES_DIR = pathlib.Path(__file__).parent / "res"
|
|
||||||
DONE_DIR = pathlib.Path(__file__).parent / "done"
|
|
||||||
|
|
||||||
|
|
||||||
def parse_line(line: str) -> dict:
|
|
||||||
parts = line.strip().split("\t")
|
|
||||||
return {
|
|
||||||
"brand": parts[0] if len(parts) > 0 else "",
|
|
||||||
"model": parts[1] if len(parts) > 1 else "",
|
|
||||||
"engine_code": parts[2] if len(parts) > 2 else "",
|
|
||||||
"date_range": parts[3] if len(parts) > 3 else "",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
RES_DIR.mkdir(exist_ok=True)
|
|
||||||
DONE_DIR.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
for filepath in sorted(LISTS_DIR.glob("*.txt")):
|
|
||||||
content = filepath.read_text(encoding="utf-8")
|
|
||||||
lines = [ln for ln in content.splitlines() if ln.strip()]
|
|
||||||
data = [parse_line(ln) for ln in lines]
|
|
||||||
|
|
||||||
out_path = RES_DIR / filepath.with_suffix(".json").name
|
|
||||||
out_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
||||||
shutil.move(str(filepath), DONE_DIR / filepath.name)
|
|
||||||
print(f" {filepath.name} — {len(data)} записей — OK")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Accent 1.3",
|
||||||
|
"engine_code": "G4E-A",
|
||||||
|
"date_range": "08.1999-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Accent 1.3",
|
||||||
|
"engine_code": "G4EH",
|
||||||
|
"date_range": "08.2002-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Accent 1.4 GL",
|
||||||
|
"engine_code": "",
|
||||||
|
"date_range": "11.2005-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Accent 1.5",
|
||||||
|
"engine_code": "G4EB",
|
||||||
|
"date_range": "08.2002-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Accent 1.6",
|
||||||
|
"engine_code": "G4ED-G",
|
||||||
|
"date_range": "12.2002-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Accent 1.6 GLS",
|
||||||
|
"engine_code": "",
|
||||||
|
"date_range": "11.2005-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Coupe 1.6 16V",
|
||||||
|
"engine_code": "G4ED-G",
|
||||||
|
"date_range": "03.2002-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Coupe 2.0 16V",
|
||||||
|
"engine_code": "G4GF",
|
||||||
|
"date_range": "08.2002-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "HYUNDAI",
|
||||||
|
"model": "Coupe 2.0 GLS",
|
||||||
|
"engine_code": "",
|
||||||
|
"date_range": "08.2002-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "KIA",
|
||||||
|
"model": "Rio 1.6 16V",
|
||||||
|
"engine_code": "G4ED",
|
||||||
|
"date_range": "03.2005-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "MERCEDES-BENZ",
|
||||||
|
"model": "CABRIOLET (W111) 280 SE 3.5",
|
||||||
|
"engine_code": "111.025",
|
||||||
|
"date_range": "01/1969 - 12/1971"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "MERCEDES-BENZ",
|
||||||
|
"model": "COUPE (W111) 280 SE 3.5",
|
||||||
|
"engine_code": "111.026",
|
||||||
|
"date_range": "01/1969 - 12/1971"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "MERCEDES-BENZ",
|
||||||
|
"model": "S-CLASS (W108, W109) 280 SE,SEL 3.5",
|
||||||
|
"engine_code": "M 116.980",
|
||||||
|
"date_range": "03/1971 - 08/1972"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "MERCEDES-BENZ",
|
||||||
|
"model": "S-CLASS (W108, W109) 300 SEL 3.5",
|
||||||
|
"engine_code": "109.056 M 116.981",
|
||||||
|
"date_range": "01/1970 - 07/1972"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "MERCEDES-BENZ",
|
||||||
|
"model": "S-CLASS (W116) 350 SE,SEL",
|
||||||
|
"engine_code": "M 116.983",
|
||||||
|
"date_range": "08/1972 - 02/1976"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brand": "MERCEDES-BENZ",
|
||||||
|
"model": "SL купе (C107) 350 SLC (107.023)",
|
||||||
|
"engine_code": "M 116.982, M 116.984",
|
||||||
|
"date_range": "01/1972 - 02/1976"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -4,7 +4,7 @@ set -e
|
|||||||
docker compose up -d --build ollama
|
docker compose up -d --build ollama
|
||||||
echo "Ожидание загрузки модели..."
|
echo "Ожидание загрузки модели..."
|
||||||
elapsed=0
|
elapsed=0
|
||||||
until docker exec ollama ollama list 2>/dev/null | grep -q gemma3n; do
|
until docker exec ollama ollama list 2>/dev/null | grep -q "gemma-3n"; do
|
||||||
echo " ${elapsed}s — загрузка..."
|
echo " ${elapsed}s — загрузка..."
|
||||||
sleep 10
|
sleep 10
|
||||||
elapsed=$((elapsed + 10))
|
elapsed=$((elapsed + 10))
|
||||||
|
|||||||
Reference in New Issue
Block a user