What's new
Runion

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Как создать идеального советчика по технологиям: Веб-приложение с ИИ, которое не требует кофеина!

hackeryaroslav

Midle Weight
Депозит
$0

Авторство: hackeryaroslav​

Источник: xss.is​

Введение

Думал какое-то время над идеей следующей статьи, но вспомнил что можно совмещать ИИ и веб разработку и тогда я пришел с идеей. Проект AI Tech Stack Optimizer предназначен для анализа текущего стека технологий и предоставления рекомендаций по улучшению с помощью ИИ. Используя модель Gemini 1.5 Flash от Google, этот инструмент генерирует советы по альтернативным технологиям и оценивает их на основе заданных параметров. Если вы хотите объединить ИИ и веб-разработку, этот проект поможет вам эффективно оптимизировать выбор технологий и улучшить ваши проекты. В этой статье мы разберем, как работает этот инструмент, как настроить модель и многое другое, надеюсь зайдет, особенно для новичков.

Screenshot 2024-08-19 232918.png



Screenshot 2024-08-19 233021.png



Screenshot 2024-08-19 233131.png



Screenshot 2024-08-19 233223.png

Начнем с самого простого: заберем ключ ИИ для его успешной работы в нашем приложении. Сделать это довольно легко. Переходим по ссылке: https://aistudio.google.com/app/prompts/new_chat предварительно войти в свой аккаунт.

Screenshot 2024-08-19 233506.png

Кликаем по кнопке Get API key и создаем свой ключ, дальше копируем из окошка:

Screenshot 2024-08-19 233559.png

Вставьте свой ключ в файле .env в корне проекта:

Screenshot 2024-08-19 233704.png

Общая структура проекта​

Прежде чем углубляться в код, рассмотрим структуру нашего проекта:

Код с оформлением (BB-коды): Скопировать в буфер обмена
Code:
ai_tech_stack_optimizer/
├── app/
│   ├── __init__.py
│   ├── routes.py
│   ├── models.py
│   ├── forms.py
│   ├── ai_logic/
│   │   ├── __init__.py
│   │   ├── stack_analyzer.py
│   │   └── recommendation_engine.py
│   ├── static/
│   │   ├── css/
│   │   │   └── main.css
│   │   └── js/
│   │       └── main.js
│   └── templates/
│       ├── base.html
│       ├── index.html
│       └── results.html
├── config.py
├── requirements.txt
└── run.py

Краткое описание структуры:

  • app/: содержит логику приложения.
    • ai_logic/: модуль, включающий основной анализ и генерацию рекомендаций с помощью AI.
    • static/: статические файлы CSS и JS.
    • templates/: HTML-шаблоны для отображения данных.
  • config.py: файл конфигурации с параметрами, такими как API-ключи.
  • run.py: основной файл для запуска приложения.

Обзор файла recommendation_engine.py

Файл recommendation_engine.py отвечает за предоставление рекомендаций по альтернативным технологиям на основе анализа текущего стека технологий пользователя. Этот процесс включает использование модели генеративного ИИ для предложения улучшений и альтернатив. Давайте подробнее разберем каждую часть этого файла.

Импорт библиотек

Python: Скопировать в буфер обмена
Code:
from flask import current_app
import json
import google.generativeai as genai
from app import db
from app.models import Recommendation, TechStack

Здесь мы импортируем необходимые библиотеки и модули:
  • current_app из Flask позволяет получить доступ к текущему экземпляру приложения Flask.
  • json используется для работы с JSON данными.
  • google.generativeai импортирует библиотеку для работы с моделью генеративного ИИ.
  • db из app - объект базы данных для взаимодействия с базой данных SQLAlchemy.
  • Recommendation и TechStack из app.models представляют модели для работы с рекомендациями и технологическими стеками в базе данных.

Функция get_recommendations

Основная функция в этом файле — get_recommendations, которая принимает анализ текущего стека технологий и возвращает рекомендации и общее мнение о стеке.

Конфигурация и инициализация модели

Python: Скопировать в буфер обмена
Code:
def get_recommendations(analysis):
    genai.configure(api_key=current_app.config["GEMINI_API_KEY"])
    model = genai.GenerativeModel("gemini-1.5-flash")

В начале функции мы настраиваем модель генеративного ИИ с помощью API-ключа из конфигурации приложения и создаем экземпляр модели gemini-1.5-flash.

Генерация рекомендаций

Python: Скопировать в буфер обмена
Code:
recommendations = {}
    overall_opinion = {}

Инициализируем словари для хранения рекомендаций и общего мнения.
Python: Скопировать в буфер обмена
Code:
    for tech, details in analysis.items():
        prompt = f"""
        Analyze the following technology: {tech}
        Category: {details.get('category', 'N/A')}
        Popularity: {details.get('popularity', 'N/A')}
        Description: {details.get('description', 'N/A')}

        Provide 3 alternative technologies that might be better suited for a project using {tech}.
        For each alternative, give a reason why it might be better and a score from 0 to 1.
        Format the response as a JSON object with the following structure:
        {{
            "alternatives": [
                {{
                    "name": "Alternative1",
                    "reason": "Reason for recommending Alternative1",
                    "score": 0.9
                }},
                // ... more alternatives
            ]
        }}
        """

Для каждой технологии в стеке мы создаем запрос (prompt) для модели ИИ, чтобы получить три альтернативные технологии, которые могут быть более подходящими. Запрос также включает категорию, популярность и описание технологии. Промпт был заранее создан с помощью ИИ.

Python: Скопировать в буфер обмена
Code:
        try:
            response = model.generate_content(prompt)
            result = response.text

            json_start = result.find("{")
            json_end = result.rfind("}") + 1
            if json_start != -1 and json_end != -1:
                json_str = result[json_start:json_end]
                result_json = json.loads(json_str)
            else:
                raise ValueError("No valid JSON object found in the response")

            recommendations[tech] = result_json["alternatives"]
            tech_stack = TechStack.query.filter_by(name=tech).first()
            if not tech_stack:
                tech_stack = TechStack(
                    name=tech,
                    category=details.get("category"),
                    popularity=details.get("popularity"),
                    description=details.get("description"),
                )
                db.session.add(tech_stack)
                db.session.flush()

            for alt in result_json["alternatives"]:
                recommendation = Recommendation(
                    tech_stack_id=tech_stack.id,
                    recommendation=f"Consider using {alt['name']} instead of {tech}",
                    reason=alt["reason"],
                    score=alt["score"],
                )
                db.session.add(recommendation)

        except (json.JSONDecodeError, KeyError, ValueError) as e:
            print(f"Error processing recommendations for {tech}: {e}")
            print(f"Received response: {result}")
            recommendations[tech] = []
        except Exception as e:
            print(f"Unexpected error processing recommendations: {e}")
            recommendations[tech] = []

Здесь мы обрабатываем ответ от модели. Мы извлекаем JSON из текста ответа и проверяем его на корректность. Затем сохраняем рекомендации в базу данных, создавая новые записи в TechStack и Recommendation по необходимости.

Генерация общего мнения

Python: Скопировать в буфер обмена
Code:
tech_stack_str = ", ".join(analysis.keys())
    overall_prompt = f"""
    Analyze the following technology stack: {tech_stack_str}


    Provide an overall opinion about this stack, including its strengths and weaknesses.
    Format the response as a JSON object with the following structure:
    {{
        "opinion": "Overall opinion about the stack",
        "strengths": ["Strength 1", "Strength 2", "Strength 3"],
        "weaknesses": ["Weakness 1", "Weakness 2", "Weakness 3"]
    }}
    """

Создаем запрос для получения общего мнения о стеке технологий, включая его сильные и слабые стороны.


Python: Скопировать в буфер обмена
Code:
try:
        response = model.generate_content(overall_prompt)
        result = response.text


        json_start = result.find("{")
        json_end = result.rfind("}") + 1
        if json_start != -1 and json_end != -1:
            json_str = result[json_start:json_end]
            overall_opinion = json.loads(json_str)
        else:
            raise ValueError("No valid JSON object found in the response")


    except Exception as e:
        print(f"Error processing overall opinion: {e}")
        overall_opinion = {
            "opinion": "Unable to generate overall opinion",
            "strengths": [],
            "weaknesses": [],
        }
    db.session.commit()


    return recommendations, overall_opinion

В конце обрабатываем ответ для общего мнения, записываем результаты в базу данных и возвращаем рекомендации и общее мнение.

Разбор файла stack_analyzer.py

Файл stack_analyzer.py отвечает за анализ стека технологий, предоставленного пользователем. Этот анализ основывается на данных, хранящихся в базе данных, и возвращает информацию о каждой технологии.

Импорт библиотек и модулей

Python: Скопировать в буфер обмена
Code:
from sqlalchemy import func
from app.models import TechStack
from app import db

Здесь импортируются необходимые модули:
  • func из sqlalchemy используется для выполнения операций с базой данных.
  • TechStack из app.models представляет модель для хранения данных о технологиях.
  • db из app — объект базы данных SQLAlchemy.

Функция analyze_stack

Python: Скопировать в буфер обмена
Code:
def analyze_stack(tech_stack_list):
    analysis = {}

Функция analyze_stack принимает список технологий (tech_stack_list) и возвращает словарь с результатами анализа.

Обработка каждой технологии

Python: Скопировать в буфер обмена
Code:
    for tech in tech_stack_list:
        tech = tech.strip().lower()
        db_tech = TechStack.query.filter(func.lower(TechStack.name) == tech).first()

Для каждой технологии из списка:
  1. Убираются пробелы и приводится название технологии к нижнему регистру.
  2. Выполняется запрос к базе данных для поиска технологии с таким же именем (в нижнем регистре).

Формирование анализа

Python: Скопировать в буфер обмена
Code:
        if db_tech:
            analysis[tech] = {
                "category": db_tech.category,
                "popularity": db_tech.popularity,
                "description": db_tech.description,
            }
        else:
            analysis[tech] = {
                "category": "Unknown",
                "popularity": 0,
                "description": "Technology not found in our database",
            }

Если технология найдена в базе данных, её категория, популярность и описание добавляются в результат анализа. Если технология отсутствует, возвращаются значения по умолчанию: категория "Unknown", популярность 0 и сообщение о том, что технология не найдена.

Возвращаемый результат

Python: Скопировать в буфер обмена
return analysis

Функция возвращает словарь analysis, который содержит информацию о каждой технологии из предоставленного списка.

Разбор файла main.js

Файл main.js отвечает за взаимодействие пользователя с веб-страницей, обработку формы, отправку данных на сервер и отображение результатов анализа. Рассмотрим каждую часть кода подробно.

Обработчик события DOMContentLoaded

JavaScript: Скопировать в буфер обмена
Code:
document.addEventListener("DOMContentLoaded", function () {
  const form = document.querySelector("form");
  const resultSection = document.createElement("div");
  resultSection.id = "results";
  document.querySelector("main").appendChild(resultSection);

Когда весь HTML документ загружен и готов, этот код выполняет следующее:
  1. Ищет элемент формы на странице.
  2. Создаёт новый <div> элемент с идентификатором results, куда будут помещаться результаты анализа.
  3. Добавляет этот <div> в элемент <main> на странице.

Обработка события отправки формы

JavaScript: Скопировать в буфер обмена
Code:
  form.addEventListener("submit", function (e) {
    e.preventDefault();

    const checkedCheckboxes = document.querySelectorAll(
      'input[name="tech_stack"]:checked'
    );
    const techStack = Array.from(checkedCheckboxes).map((cb) => cb.value);

    if (techStack.length === 0) {
      console.error("No technologies selected");
      resultSection.innerHTML =
        '<p class="error">Please select at least one technology.</p>';
      return;
    }

    resultSection.innerHTML = '<p class="loading">Loading...</p>';

    fetch("/api/analyze", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ tech_stack: techStack }),
    })
      .then((response) => {
        if (!response.ok) {
          throw new Error("Network response was not ok");
        }
        return response.json();
      })
      .then((data) => {
        if (data.error) {
          throw new Error(data.error);
        }
        displayResults(data);
      })
      .catch((error) => {
        console.error("Error:", error);
        resultSection.innerHTML = `<p class="error">An error occurred: ${error.message}</p>`;
      });
  });

При отправке формы происходит следующее:
  1. Событие отправки формы отменяется с помощью e.preventDefault(), чтобы предотвратить перезагрузку страницы.
  2. Получаются все отмеченные чекбоксы, и их значения собираются в массив techStack.
  3. Если не выбрано ни одной технологии, отображается сообщение об ошибке.
  4. Если технологии выбраны, отображается сообщение о загрузке.
  5. Выполняется POST запрос на сервер по адресу /api/analyze с массивом выбранных технологий в теле запроса.
  6. Если запрос успешен, данные обрабатываются функцией displayResults.
  7. Если возникает ошибка, отображается сообщение об ошибке.

Функция displayResults

JavaScript: Скопировать в буфер обмена
Code:
  function displayResults(data) {
    let html = "<h2>Analysis Results</h2>";

    html += "<h3>Tech Stack Analysis</h3>";
    for (const [tech, details] of Object.entries(data.analysis)) {
      html += `
                <div class="tech-item">
                    <h4>${escapeHTML(tech)}</h4>
                    <p>Category: ${escapeHTML(details.category)}</p>
                    <p>Popularity: ${escapeHTML(details.popularity)}</p>
                    <p>Description: ${escapeHTML(details.description)}</p>
                </div>
            `;
    }

    html += "<h3>Recommendations</h3>";
    for (const [tech, alternatives] of Object.entries(data.recommendations)) {
      html += `
                <div class="recommendation-item">
                    <h4>Alternatives for ${escapeHTML(tech)}</h4>
                    <ul>
                        ${alternatives
                          .map(
                            (alt) => `
                            <li>
                                <strong>${escapeHTML(alt.name)}</strong>
                                <p>Reason: ${escapeHTML(alt.reason)}</p>
                                <p>Score: ${escapeHTML(alt.score)}</p>
                            </li>
                        `
                          )
                          .join("")}
                    </ul>
                </div>
            `;
    }
    html += "<h2>Overall Opinion</h2>";
    html += `
            <p><strong>Opinion:</strong> ${escapeHTML(
              data.overall_opinion.opinion
            )}</p>
            <h3>Strengths</h3>
            <ul>
                ${data.overall_opinion.strengths
                  .map((strength) => `<li>${escapeHTML(strength)}</li>`)
                  .join("")}
            </ul>
            <h3>Weaknesses</h3>
            <ul>
                ${data.overall_opinion.weaknesses
                  .map((weakness) => `<li>${escapeHTML(weakness)}</li>`)
                  .join("")}
            </ul>
        `;

    resultSection.innerHTML = html;
  }

Функция displayResults используется для формирования HTML-кода с результатами анализа:
  1. Создаётся заголовок и разделы для анализа стека технологий, рекомендаций и общего мнения.
  2. Для каждого элемента анализа и рекомендаций формируется HTML-код.
  3. Данные экранируются с помощью функции escapeHTML для предотвращения XSS-атак.
  4. Полученный HTML вставляется в resultSection.

Функция escapeHTML

JavaScript: Скопировать в буфер обмена
Code:
function escapeHTML(text) {
    const div = document.createElement("div");
    div.textContent = text;
    return div.innerHTML;
  }

Функция escapeHTML предотвращает возможные XSS-атаки, экранируя специальные символы в тексте, чтобы они не интерпретировались как HTML-код.

Шаблон base.html
Файл base.html является основой для всех других шаблонов. Он задает общий вид и структуру веб-страницы, включая заголовок, основное содержимое и подвал.
HTML: Скопировать в буфер обмена
Code:
{% extends "base.html" %}
{% block content %}
<section class="tech-stack-form">
  <h2>Analyze Your Tech Stack</h2>
  <form method="POST" action="{{ url_for('main.index') }}">
    {{ form.hidden_tag() }}
    <div class="form-group">
      <label for="tech_stack">Select your technologies:</label>
      <div class="checkbox-container">
        {% for tech in technologies %}
        <div class="checkbox-item">
          <input class="form-check-input" type="checkbox" id="tech_{{ tech.id }}" name="tech_stack" value="{{ tech.name }}" />
          <label class="form-check-label" for="tech_{{ tech.id }}">{{ tech.name }}</label>
          <p class="checkbox-description">{{ tech.description }}</p>
        </div>
        {% endfor %}
      </div>
    </div>
    {{ form.submit(class="btn") }}
  </form>
</section>
{% endblock %}

Его работа заключается в следущем:
  1. {% extends "base.html" %}: Указывает на наследование от base.html.
  2. <section class="tech-stack-form">:Определяет секцию формы для выбора технологий.
    • <form method="POST" action="{{ url_for('main.index') }}">: Форма отправляется методом POST на маршрут, определенный в url_for('main.index').
    • {{ form.hidden_tag() }}: Отображает скрытые поля формы, необходимые для CSRF защиты.
    • <div class="form-group">:Обертка для группы элементов формы.
      • {% for tech in technologies %}: Перебирает список технологий и создает чекбоксы для каждой из них.
      • <input class="form-check-input" ... />: Определяет чекбоксы для выбора технологий.
      • <label class="form-check-label" for="tech_{{ tech.id }}">: Метка для чекбокса с описанием технологии.

Шаблон error.html​

Файл error.html предназначен для отображения сообщений об ошибках. Он расширяет base.html и предоставляет базовый макет для сообщений об ошибках.

HTML: Скопировать в буфер обмена
Code:
{% extends "base.html" %}
{% block content %}
<section class="error">
  <h2>Error</h2>
  <p>{{ message }}</p>
  <a href="{{ url_for('main.index') }}" class="btn">Go back</a>
</section>
{% endblock %}

  • {% extends "base.html" %}: Указывает, что данный шаблон расширяет base.html.
  • {% block content %}{% endblock %}: Задает область, где будет отображаться специфическое содержимое для этой страницы.
  • <section class="error">:Определяет секцию для сообщения об ошибке.
    • {{ message }}: Показ сообщения об ошибке, которое будет передано из обработчика ошибок на сервере.
    • <a href="{{ url_for('main.index') }}" class="btn">Go back</a>: Ссылка для возврата на главную страницу.

Шаблон index.html​

Файл index.html представляет собой основную страницу приложения, где пользователи могут выбрать технологии для анализа.

HTML: Скопировать в буфер обмена
Code:
{% extends "base.html" %}
{% block content %}
<section class="tech-stack-form">
  <h2>Analyze Your Tech Stack</h2>
  <form method="POST" action="{{ url_for('main.index') }}">
    {{ form.hidden_tag() }}
    <div class="form-group">
      <label for="tech_stack">Select your technologies:</label>
      <div class="checkbox-container">
        {% for tech in technologies %}
        <div class="checkbox-item">
          <input class="form-check-input" type="checkbox" id="tech_{{ tech.id }}" name="tech_stack" value="{{ tech.name }}" />
          <label class="form-check-label" for="tech_{{ tech.id }}">{{ tech.name }}</label>
          <p class="checkbox-description">{{ tech.description }}</p>
        </div>
        {% endfor %}
      </div>
    </div>
    {{ form.submit(class="btn") }}
  </form>
</section>
{% endblock %}

  • {% extends "base.html" %}: Указывает на наследование от base.html.
  • <section class="tech-stack-form">:Определяет секцию формы для выбора технологий.
    • <form method="POST" action="{{ url_for('main.index') }}">: Форма отправляется методом POST на маршрут, определенный в url_for('main.index').
    • {{ form.hidden_tag() }}: Отображает скрытые поля формы, необходимые для CSRF защиты.
    • <div class="form-group">:Обертка для группы элементов формы.
      • {% for tech in technologies %}: Перебирает список технологий и создает чекбоксы для каждой из них.
      • <input class="form-check-input" ... />: Определяет чекбоксы для выбора технологий.
      • <label class="form-check-label" for="tech_{{ tech.id }}">: Метка для чекбокса с описанием технологии.

Шаблон results.html​

Файл results.html отображает результаты анализа выбранных технологий и рекомендации.

HTML: Скопировать в буфер обмена
Code:
{% extends "base.html" %}
{% block content %}

<section class="overall-opinion">
  <h2>Overall Opinion</h2>
  <p><strong>Opinion:</strong> {{ overall_opinion.opinion }}</p>
  <h3>Strengths</h3>
  <ul>
    {% for strength in overall_opinion.strengths %}
    <li>{{ strength }}</li>
    {% endfor %}
  </ul>
  <h3>Weaknesses</h3>
  <ul>
    {% for weakness in overall_opinion.weaknesses %}
    <li>{{ weakness }}</li>
    {% endfor %}
  </ul>
</section>

<section class="analysis-results">
  <h2>Analysis Results</h2>
  <div class="tech-stack-analysis">
    {% for tech, details in analysis.items() %}
    <div class="tech-item">
      <h3>{{ tech }}</h3>
      <p><strong>Category:</strong> {{ details.category }}</p>
      <p><strong>Popularity:</strong> {{ details.popularity }}</p>
      <p><strong>Description:</strong> {{ details.description }}</p>
    </div>
    {% endfor %}
  </div>
</section>

<section class="recommendations">
  <h2>Recommendations</h2>
  {% for tech, alternatives in recommendations.items() %}
  <div class="recommendation-item">
    <h3>Alternatives for {{ tech }}</h3>
    <ul>
      {% for alt in alternatives %}
      <li>
        <strong>{{ alt.name }}</strong>
        <p><strong>Reason:</strong> {{ alt.reason }}</p>
        <p><strong>Score:</strong> {{ alt.score }}</p>
      </li>
      {% endfor %}
    </ul>
  </div>
  {% endfor %}
</section>

{% endblock %}

  • {% extends "base.html" %}: Наследование от базового шаблона.
  • <section class="overall-opinion">:Секция для отображения общего мнения о выбранных технологиях.
    • <p><strong>Opinion:</strong> {{ overall_opinion.opinion }}</p>: Отображает мнение о техстеке.
    • **<h3>Strengths</h3> и <h3>Weaknesses</h3>: Отображают сильные и слабые стороны.
  • <section class="analysis-results">:Показывает результаты анализа технологий.
    • {% for tech, details in analysis.items() %}: Перебирает результаты анализа и отображает информацию о каждой технологии.
  • <section class="recommendations">:Предлагает альтернативные решения для выбранных технологий.
    • {% for tech, alternatives in recommendations.items() %}: Перебирает рекомендации по альтернативам для каждой технологии.

Обзор файла main.css
Спойлер: супер крутое объяснение
Я не планирую его объяснять, с этим можно легко разобраться самим. Код файла можете посмотреть в зип файле ниже!

Обзор файла __init__.py​

Файл __init__.py отвечает за создание и настройку основного приложения Flask и подключение базы данных.

Импорт библиотек и модулей

Python: Скопировать в буфер обмена
Code:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config

Здесь мы импортируем необходимые библиотеки:
  • Flask из flask для создания приложения.
  • SQLAlchemy из flask_sqlalchemy для работы с базой данных.
  • Config из config для загрузки настроек приложения.
Создание и настройка приложения
Python: Скопировать в буфер обмена
Code:
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)

    db.init_app(app)

    from app import routes
    app.register_blueprint(routes.main)

    return app
  • Инициализация SQLAlchemy: db = SQLAlchemy() создает объект для работы с базой данных.
  • Функция create_app():
    • Создает экземпляр приложения Flask.
    • Загружает конфигурацию из объекта Config.
    • Инициализирует SQLAlchemy с помощью db.init_app(app).
    • Регистрирует маршруты через Blueprint из модуля routes.
    • Возвращает экземпляр настроенного приложения.

Обзор файла forms.py​

Файл forms.py определяет форму для ввода текущего стека технологий с использованием библиотеки WTForms.

Импорт библиотек

Python: Скопировать в буфер обмена
Code:
from flask_wtf import FlaskForm
from wtforms import TextAreaField, SubmitField
from wtforms.validators import DataRequired

Здесь импортируются:
  • FlaskForm из flask_wtf для создания форм.
  • TextAreaField и SubmitField из wtforms для полей ввода и кнопок.
  • DataRequired для проверки, что поле не пустое.

Определение формы TechStackForm

Python: Скопировать в буфер обмена
Code:
class TechStackForm(FlaskForm):
    tech_stack = TextAreaField("Your Current Tech Stack", validators=[DataRequired()])
    submit = SubmitField("Analyze")
  • tech_stack: Текстовое поле для ввода текущего стека технологий, с проверкой на обязательность заполнения.
  • submit: Кнопка отправки формы с текстом "Analyze".

Обзор файла models.py​

Файл models.py содержит определения моделей данных для работы с базой данных.

Импорт библиотеки

Python: Скопировать в буфер обмена
from app import db

Импорт объекта db для взаимодействия с базой данных SQLAlchemy.

Определение моделей

Python: Скопировать в буфер обмена
Code:
class TechStack(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    category = db.Column(db.String(50))
    popularity = db.Column(db.Float)

TechStack:
  • id: Уникальный идентификатор стека технологий (первичный ключ).
  • name: Название технологии.
  • description: Описание технологии.
  • category: Категория технологии.
  • popularity: Популярность технологии (число с плавающей точкой).
Python: Скопировать в буфер обмена
Code:
class Recommendation(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tech_stack_id = db.Column(
        db.Integer, db.ForeignKey("tech_stack.id"), nullable=False
    )
    recommendation = db.Column(db.Text, nullable=False)
    reason = db.Column(db.Text)
    score = db.Column(db.Float)

Recommendation:
  • id: Уникальный идентификатор рекомендации (первичный ключ).
  • tech_stack_id: Внешний ключ, связывающий рекомендацию с конкретным стеком технологий из модели TechStack.
  • recommendation: Текст рекомендации (например, предложение альтернативной технологии).
  • reason: Причина рекомендации.
  • score: Оценка рекомендации (число с плавающей точкой).

Обзор файла routes.py​

Файл routes.py определяет маршруты для обработки запросов в приложении Flask. Он управляет основными страницами приложения и API для анализа технологий и получения рекомендаций.

Импорт библиотек и модулей

Python: Скопировать в буфер обмена
Code:
from flask import Blueprint, render_template, request, jsonify, current_app
from app.forms import TechStackForm
from app.ai_logic.stack_analyzer import analyze_stack
from app.ai_logic.recommendation_engine import get_recommendations
from app.models import TechStack
  • Blueprint: Из flask используется для организации маршрутов.
  • render_template: Для рендеринга HTML-шаблонов.
  • request: Для обработки входящих запросов.
  • jsonify: Для формирования JSON-ответов.
  • current_app: Для доступа к текущему экземпляру приложения.
  • TechStackForm: Форма для ввода стека технологий.
  • analyze_stack и get_recommendations: Функции для анализа технологий и генерации рекомендаций.
  • TechStack: Модель для работы с данными о технологиях.
Создание Blueprint
Python: Скопировать в буфер обмена
main = Blueprint("main", __name__)

Создаем Blueprint с именем main для управления маршрутами.

Основной маршрут (index)

Python: Скопировать в буфер обмена
Code:
@main.route("/", methods=["GET", "POST"])
def index():
    form = TechStackForm()
    technologies = TechStack.query.all()
    if form.validate_on_submit():
        selected_technologies = request.form.getlist("tech_stack")
        tech_stack = ", ".join(selected_technologies)
        analysis = analyze_stack(tech_stack)
        try:
            recommendations = get_recommendations(analysis)
            return render_template(
                "results.html", analysis=analysis, recommendations=recommendations
            )
        except Exception as e:
            current_app.logger.error(f"Error generating recommendations: {e}")
            return render_template(
                "error.html",
                message="An error occurred while generating recommendations. Please try again later.",
            )
    return render_template("index.html", form=form, technologies=technologies)
  • Методы: Поддерживает GET и POST запросы.
  • Форма: Создается экземпляр формы TechStackForm.
  • Запрос технологий: Получаем все технологии из базы данных TechStack.
  • Обработка формы: Если форма успешно отправлена и проверена:
    • Получаем выбранные технологии.
    • Анализируем стек технологий с помощью функции analyze_stack.
    • Получаем рекомендации с помощью get_recommendations.
    • Отображаем результаты или ошибку в зависимости от результата.
  • Рендеринг шаблонов: index.html для начальной страницы и results.html для отображения результатов анализа.

API маршрут (api_analyze)

Python: Скопировать в буфер обмена
Code:
@main.route("/api/analyze", methods=["POST"])
def api_analyze():
    data = request.json
    tech_stack = data.get("tech_stack")
    analysis = analyze_stack(tech_stack)
    try:
        recommendations, overall_opinion = get_recommendations(analysis)
        return jsonify(
            {
                "analysis": analysis,
                "recommendations": recommendations,
                "overall_opinion": overall_opinion,
            }
        )
    except Exception as e:
        current_app.logger.error(f"Error generating recommendations: {e}")
        return (
            jsonify({"error": "An error occurred while generating recommendations"}),
            500,
        )
  • Метод: Поддерживает только POST запросы.
  • Получение данных: Извлекаем данные из запроса JSON.
  • Анализ и рекомендации: Анализируем стек технологий и получаем рекомендации.
  • Формирование ответа: Возвращаем результаты в формате JSON или сообщение об ошибке в случае исключения.

Обзор файла config.py​

Файл config.py содержит конфигурацию для приложения Flask. Он управляет настройками для базы данных, секретными ключами и другими параметрами.

Импорт библиотек

Python: Скопировать в буфер обмена
Code:
import os
from dotenv import load_dotenv
  • os: Для доступа к переменным окружения и другим системным функциям.
  • load_dotenv: Из библиотеки dotenv используется для загрузки переменных окружения из файла .env.
Загрузка переменных окружения
Python: Скопировать в буфер обмена
load_dotenv()

Загружает переменные окружения из файла .env, чтобы их можно было использовать в конфигурации.

Класс Config

Python: Скопировать в буфер обмена
Code:
class Config:
    SECRET_KEY = os.environ.get("SECRET_KEY") or "imsupersecret"
    SQLALCHEMY_DATABASE_URI = (
        os.environ.get("DATABASE_URL")
        or "postgresql://юзер:пароль@localhost:5432/бд"
    )
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    GEMINI_API_KEY = os.environ.get("API_KEY")

  • SECRET_KEY: Секретный ключ для защиты данных сеансов и других данных. Если переменная окружения SECRET_KEY не установлена, используется "imsupersecret" по умолчанию.
  • SQLALCHEMY_DATABASE_URI: URI для подключения к базе данных. Если переменная окружения DATABASE_URL не установлена, используется локальная база данных PostgreSQL по умолчанию.
  • SQLALCHEMY_TRACK_MODIFICATIONS: Устанавливает, нужно ли отслеживать изменения объектов и отправлять сигналы. Установлено в False, чтобы отключить эту функциональность, что улучшает производительность.
  • GEMINI_API_KEY: Ключ API для модели генеративного ИИ, загружается из переменной окружения API_KEY.

Создав базу через PgAdmin4 мы выполним вот такой запрос на создании изначальной даты:

SQL: Скопировать в буфер обмена
Code:
INSERT INTO tech_stack (id, name, description, category, popularity)
VALUES
(1, 'html', 'A markup language used for structuring and presenting content on the web.', 'Web Development', 1),
(2, 'css', 'A style sheet language used for describing the presentation of a document written in HTML or XML.', 'Web Development', 1),
(3, 'javascript', 'A programming language that enables interactive web pages and is an essential part of web applications.', 'Web Development', 1),
(4, 'flask', 'A micro web framework written in Python.', 'Web Development', 0.8),
(5, 'github', 'A platform for version control and collaboration, allowing multiple people to work on projects at once.', 'Development Tools', 0.7),
(6, 'python', 'A versatile language with a strong focus on readability and simplicity, popular in web development, data science, and more.', 'Programming Language', 1),
(7, 'java', 'A robust, object-oriented programming language used for building large-scale applications and systems.', 'Programming Language', 0.9),
(8, 'typescript', 'A superset of JavaScript that adds static typing and improves code maintainability and readability.', 'Programming Language', 0.8),
(9, 'c++', 'An extension of C that includes object-oriented features and is used for system/software development, game development, and more.', 'Programming Language', 0.7),
(10, 'react', 'A JavaScript library for building user interfaces, developed by Facebook.', 'Web Development', 1),
(11, 'angular', 'A platform and framework for building single-page client applications using HTML and TypeScript, maintained by Google.', 'Web Development', 0.9),
(12, 'vue.js', 'A progressive framework for building user interfaces, known for its simplicity and flexibility.', 'Web Development', 0.9),
(13, 'django', 'A high-level Python web framework that encourages rapid development and clean, pragmatic design.', 'Web Development', 0.8),
(14, 'pytorch', 'An open-source machine learning library for Python, known for its flexibility and ease of use.', 'Machine Learning', 0.8),
(15, 'tensorflow', 'An open-source library for numerical computation and machine learning, widely used for deep learning.', 'Machine Learning', 0.9),
(16, 'mysql', 'An open-source relational database management system known for its reliability and performance.', 'Database', 1),
(17, 'postgresql', 'A powerful, open-source object-relational database system known for its robustness and advanced features.', 'Database', 0.9),
(18, 'redis', 'An open-source, in-memory data structure store, used as a database, cache, and message broker.', 'Database', 0.8),
(19, 'sass', 'A preprocessor scripting language that is interpreted or compiled into CSS, providing features like variables and nesting.', 'Web Development', 0.7),
(20, 'less', 'A backward-compatible language extension for CSS, with features like variables, mixins, and nested rules.', 'Web Development', 0.7),
(21, 'aws', 'Amazon Web Services, a comprehensive and widely adopted cloud platform offering various services like computing power, storage, and databases.', 'Cloud Computing', 1),
(22, 'azure', 'Microsoft Azure, a cloud computing service offering various cloud services including those for computing, analytics, storage, and networking.', 'Cloud Computing', 0.9),
(23, 'google cloud platform', 'A suite of cloud computing services offered by Google, providing computing, storage, and other cloud services.', 'Cloud Computing', 0.8),
(24, 'git', 'A distributed version control system for tracking changes in source code during software development.', 'Development Tools', 1),
(25, 'gitlab', 'A web-based DevOps lifecycle tool that provides a Git repository manager providing wiki, issue-tracking, and CI/CD pipeline features.', 'Development Tools', 0.8),
(26, 'swift', 'A powerful and intuitive programming language for macOS, iOS, watchOS, and tvOS app development.', 'Programming Language', 0.7),
(27, 'ruby', 'A dynamic, open-source programming language with a focus on simplicity and productivity.', 'Programming Language', 0.6),
(28, 'go', 'A statically typed, compiled language designed for simplicity and efficiency, known for its performance and concurrency features.', 'Programming Language', 0.7);

Обзор файла run.py​

Файл run.py запускает приложение Flask и настраивает базу данных.

Python: Скопировать в буфер обмена
Code:
from app import create_app, db

app = create_app()

if __name__ == "__main__":
    with app.app_context():
        db.create_all()
    app.run(debug=True)
  • Импорт: Импортируем функцию create_app и объект db из модуля app.
  • Создание приложения: Создаем экземпляр приложения с помощью create_app().
  • Создание таблиц: Если файл запускается как основной (__name__ == "__main__"), создаем все таблицы в базе данных с помощью db.create_all().
  • Запуск приложения: Запускаем приложение Flask в режиме отладки (debug=True), что упрощает разработку, предоставляя подробные сообщения об ошибках.

Заключение​

В этой статье мы подробно рассмотрели структуру и функциональность приложения Flask, ориентированного на анализ и рекомендации технологий. Мы начали с конфигурационных файлов, которые задают основы приложения, включая ключи безопасности и параметры подключения к базе данных. Переходя к файлам кода, мы рассмотрели реализацию логики приложения, обработку запросов и взаимодействие с ИИ для предоставления рекомендаций.

Мы также рассмотрели архитектуру приложения, включающую создание и управление моделями данных с помощью SQLAlchemy, а также реализацию логики генерации рекомендаций и анализа стека технологий и тд.

Наконец, мы обсудили настройки, необходимые для работы приложения, включая использование переменных окружения и запуск приложения с помощью run.py. Код также доступен ниже в виде zip файла, желаю вам удачи!

Вложения​


  • article.zip
    20.5 КБ · Просмотры: 3
 
Top