Розробка AI-міграції коду між мовами

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
Розробка AI-міграції коду між мовами
Складний
~2-4 тижні
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    901
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1119
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    853

AI-міграція коду між мовами програмування

Міграція кодової бази з однієї мови на іншу — завдання, яке раніше вирішували одним із двох способів: переписували вручну (дорого та довго) або шукали транспайлери (вузька застосовність, низька якість результату). AI-міграція займає проміжне положення: вона не просто переводить синтаксис, але адаптує ідіоми, заміняє бібліотеки на ідіоматичні аналоги та враховує особливості цільової мови.

Архітектура системи міграції

Наївний підхід — скормити LLM весь файл і попросити перевести. Він працює для файлів до 200–300 рядків. Для реальних кодових баз потрібна інша архітектура:

Dependency Analyzer — будує граф залежностей між файлами/модулями. Визначає порядок міграції.

Chunk Splitter — розбиває файли на незалежні чанки (клас, функція, модуль), які можна мігрувати та тестувати окремо.

Context Manager — передає в LLM уже мігровані залежності, щоб нові файли використовували правильні імпорти.

Validator — компілює та тестує мігрований код.

Glossary — словник відповідностей: бібліотека оригіналу → бібліотека в цільовій мові.

Міграція Python → TypeScript

from anthropic import Anthropic
from pathlib import Path
import ast
import json
from typing import Optional

client = Anthropic()

# Словник відповідності бібліотек Python → TypeScript/Node.js
PYTHON_TO_TS_GLOSSARY = {
    "fastapi": "express + zod (or hono)",
    "pydantic": "zod",
    "sqlalchemy": "prisma (or drizzle-orm)",
    "pytest": "jest (or vitest)",
    "requests": "fetch (native) or axios",
    "asyncio": "native async/await + Promise",
    "datetime": "Date + date-fns",
    "pathlib": "path (node built-in)",
    "dataclass": "interface or class with constructor",
    "TypedDict": "interface",
    "Optional[X]": "X | undefined",
    "List[X]": "X[]",
    "Dict[K, V]": "Record<K, V>",
}

MIGRATION_SYSTEM = """Ти — senior engineer, який мігрує Python код на TypeScript.

Принципи:
- Використовуй ідіоми TypeScript, не Python з іншим синтаксисом
- Pydantic моделі → Zod схеми + TypeScript інтерфейси
- SQLAlchemy → Prisma (якщо ORM) або raw SQL з типами
- FastAPI декоратори → Express/Hono роути
- Python async/await → TypeScript async/await (вони ідентичні за семантикою)
- Exception handling: Python exceptions → TypeScript Error класи + Result types
- Type hints → строгі TypeScript типи (no any)

Структура TypeScript файлу:
1. imports (використовуй ESM)
2. типи/інтерфейси
3. константи
4. основний код

Угоди:
- snake_case → camelCase для змінних/функцій
- snake_case → PascalCase для класів
- Додавай JSDoc для публічних функцій"""

class PythonToTypeScriptMigrator:

    def __init__(self):
        self.migrated_modules: dict[str, str] = {}  # original_path -> ts_content
        self.type_glossary: dict[str, str] = {}  # python_type -> ts_type

    def migrate_file(
        self,
        py_file: str,
        related_migrations: Optional[dict[str, str]] = None,
    ) -> str:
        """Мігрує один Python файл у TypeScript"""

        source = Path(py_file).read_text()

        # Аналізуємо імпорти через AST
        imports = self._extract_imports(source)
        library_mapping = self._map_libraries(imports)

        # Збираємо контекст з уже мігрованих залежностей
        context_parts = []
        if related_migrations:
            for dep_file, ts_content in related_migrations.items():
                context_parts.append(
                    f"// Already migrated: {dep_file}\n{ts_content[:1000]}"
                )

        context = "\n\n".join(context_parts) if context_parts else ""

        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=8096,
            system=MIGRATION_SYSTEM,
            messages=[{
                "role": "user",
                "content": f"""Мігруй Python файл у TypeScript.

Файл: {py_file}
```python
{source}

Бібліотеки (Python → TypeScript): {json.dumps(library_mapping, ensure_ascii=False, indent=2)}

{f"Контекст уже мігрованих залежностей:{chr(10)}{context}" if context else ""}

Поверни тільки TypeScript код файлу.""" }] )

    ts_code = response.content[0].text
    # Видаляємо markdown обертку якщо є
    if "```typescript" in ts_code:
        ts_code = ts_code.split("```typescript")[1].split("```")[0].strip()
    elif "```" in ts_code:
        ts_code = ts_code.split("```")[1].split("```")[0].strip()

    return ts_code

def _extract_imports(self, source: str) -> list[str]:
    """Витягує імпорти через AST"""
    try:
        tree = ast.parse(source)
        imports = []
        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                imports.extend(alias.name for alias in node.names)
            elif isinstance(node, ast.ImportFrom):
                if node.module:
                    imports.append(node.module.split(".")[0])
        return list(set(imports))
    except SyntaxError:
        return []

def _map_libraries(self, python_imports: list[str]) -> dict:
    """Зіставляє Python бібліотеки з TypeScript аналогами"""
    mapping = {}
    for lib in python_imports:
        if lib in PYTHON_TO_TS_GLOSSARY:
            mapping[lib] = PYTHON_TO_TS_GLOSSARY[lib]
    return mapping

def migrate_project(self, src_dir: str, output_dir: str) -> dict:
    """Мігрує весь Python проект у TypeScript"""
    src_path = Path(src_dir)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    # Будуємо граф залежностей
    files = list(src_path.rglob("*.py"))
    migration_order = self._topological_sort(files)

    results = {}
    for py_file in migration_order:
        if py_file.name.startswith("test_"):
            continue  # Тести мігруємо окремо

        # Отримуємо уже мігровані залежності
        related = {
            str(dep): self.migrated_modules[str(dep)]
            for dep in migration_order
            if str(dep) in self.migrated_modules
        }

        ts_content = self.migrate_file(str(py_file), related[-3:] if len(related) > 3 else related)

        # Зберігаємо
        relative = py_file.relative_to(src_path)
        ts_file = output_path / relative.with_suffix(".ts")
        ts_file.parent.mkdir(parents=True, exist_ok=True)
        ts_file.write_text(ts_content)

        self.migrated_modules[str(py_file)] = ts_content
        results[str(py_file)] = str(ts_file)

    return results

def _topological_sort(self, files: list[Path]) -> list[Path]:
    """Сортує файли в порядку залежностей (спрощена версія)"""
    # Проста евристика: спочатку моделі, потім утиліти, потім сервіси, потім роути
    priority = {"model": 0, "schema": 0, "type": 0, "util": 1, "helper": 1,
               "service": 2, "repo": 2, "route": 3, "handler": 3, "view": 3, "app": 4}

    def get_priority(path: Path) -> int:
        name = path.stem.lower()
        for key, p in priority.items():
            if key in name:
                return p
        return 2  # Default

    return sorted(files, key=get_priority)

### Міграція з валідацією

```python
def migrate_and_validate(py_file: str, ts_output: str) -> dict:
    """Мігрує файл та запускає TypeScript компілятор"""
    import subprocess

    migrator = PythonToTypeScriptMigrator()
    ts_code = migrator.migrate_file(py_file)

    Path(ts_output).write_text(ts_code)

    # Компілюємо для перевірки типів
    result = subprocess.run(
        ["npx", "tsc", "--noEmit", "--strict", ts_output],
        capture_output=True, text=True
    )

    if result.returncode != 0:
        # Пробуємо виправити помилки компіляції
        fixed_code = fix_typescript_errors(ts_code, result.stdout + result.stderr)
        Path(ts_output).write_text(fixed_code)

        result = subprocess.run(
            ["npx", "tsc", "--noEmit", "--strict", ts_output],
            capture_output=True, text=True
        )

    return {
        "success": result.returncode == 0,
        "errors": result.stdout + result.stderr if result.returncode != 0 else "",
        "output_file": ts_output,
    }

def fix_typescript_errors(ts_code: str, errors: str) -> str:
    """Виправляє помилки TypeScript компілятора через LLM"""
    response = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=8096,
        messages=[{
            "role": "user",
            "content": f"""Виправ помилки TypeScript компілятора.

Код:
```typescript
{ts_code}

Помилки компілятора:

{errors}

Поверни виправлений код.""" }] ) text = response.content[0].text if "typescript" in text: return text.split("typescript")[1].split("```")[0].strip() return text


### Інші напрямки міграції

Система аналогічно працює для інших пар мов. Ключові відмінності — у словнику бібліотек:

**Java → Kotlin**: jackson → kotlinx.serialization, Spring annotations → Ktor/Spring аналоги, checked exceptions → sealed classes з Result.

**PHP → Python**: Laravel Eloquent → SQLAlchemy, Blade templates → Jinja2, Composer → pip/uv.

**JavaScript → TypeScript**: основна робота — додавання типів, заміна `any` на конкретні типи, додавання Zod валідації на boundaries.

### Практичний кейс: Python microservice → TypeScript

**Контекст**: стартап мігрував notification-сервіс (Python FastAPI, 3200 рядків) у TypeScript для уніфікації стеку (фронтенд-команда знала тільки JS/TS).

**Обсяг**: 28 файлів, 12 Pydantic моделей, 34 API endpoints, 180 юніт-тестів.

**Процес (2 тижні)**:
- Тиждень 1: налаштування glossary, міграція моделей та утиліт (автоматично), ручна доробка 3 складних файлів з бізнес-логікою
- Тиждень 2: міграція роутів, адаптація тестів (Jest), інтеграційне тестування

**Результати**:
- 85% коду мігровано автоматично без ручних правок
- 15% потребувало доробки (складна логіка з Python-специфічними ідіомами)
- TypeScript compilation errors: 47 → 0 (після 2 ітерацій LLM fix)
- Test coverage мігрованого сервісу: 71% (було 74% у Python — мінімальна втрата)

**Неочікуваний плюс**: під час міграції AI виявив 3 місця з потенційними race conditions у Python коді, які були виправлені в TypeScript версії.

### Строки

- Прототип міграції одного файлу: 1–2 дні
- Система з dependency graph та batch-міграцією: 1 тиждень
- Валідація + auto-fix loop: 1 тиждень
- Повна міграція проекту 5000–15000 рядків: 3–6 тижнів (включаючи QA)