diff --git a/GPTutor-Backend/pom.xml b/GPTutor-Backend/pom.xml
index 9bcaa2f5..a6832357 100644
--- a/GPTutor-Backend/pom.xml
+++ b/GPTutor-Backend/pom.xml
@@ -22,11 +22,6 @@
aws-java-sdk-s3
1.12.546
-
- org.springframework
- spring-websocket
- 6.0.10
-
org.springframework.boot
spring-boot-starter-websocket
@@ -36,21 +31,6 @@
spring-boot-starter-test
test
-
- org.springframework.boot
- spring-boot-autoconfigure
- 3.0.5
-
-
- org.springframework
- spring-web
- 6.0.6
-
-
- org.springframework.boot
- spring-boot
- 3.0.5
-
org.springframework.boot
spring-boot-starter-web
diff --git a/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ConversationController.java b/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ConversationController.java
index b7ceb7a7..56e38a27 100644
--- a/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ConversationController.java
+++ b/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ConversationController.java
@@ -14,8 +14,11 @@
@RestController
public class ConversationController {
- @Autowired
- ConversationsService conversationsService;
+ private final ConversationsService conversationsService;
+
+ public ConversationController(ConversationsService conversationsService) {
+ this.conversationsService = conversationsService;
+ }
@PostMapping(path = "/vk-doc/conversation")
public String getConversationVkDoc(@RequestBody QuestionRequest questionRequest) {
@@ -23,8 +26,8 @@ public String getConversationVkDoc(@RequestBody QuestionRequest questionRequest)
}
@PostMapping(path = "/conversation", consumes = MediaType.APPLICATION_JSON_VALUE)
- public T getConversation(@RequestBody ConversationRequest conversationRequest, HttpServletRequest request) throws IOException {
- return (T) conversationsService.getConversation(conversationRequest, (String) request.getAttribute("vkUserId"));
+ public Object getConversation(@RequestBody ConversationRequest conversationRequest, HttpServletRequest request) throws IOException {
+ return conversationsService.getConversation(conversationRequest, (String) request.getAttribute("vkUserId"));
}
}
diff --git a/GPTutor-Backend/src/main/java/com/chatgpt/controllers/HistoryController.java b/GPTutor-Backend/src/main/java/com/chatgpt/controllers/HistoryController.java
index 6562d4a3..a9a45622 100644
--- a/GPTutor-Backend/src/main/java/com/chatgpt/controllers/HistoryController.java
+++ b/GPTutor-Backend/src/main/java/com/chatgpt/controllers/HistoryController.java
@@ -18,12 +18,13 @@
@RestController
public class HistoryController {
+ private final HistoryService historyService;
+ private final MessageRepository messageRepository;
- @Autowired
- HistoryService historyService;
-
- @Autowired
- MessageRepository messageRepository;
+ public HistoryController(HistoryService historyService, MessageRepository messageRepository) {
+ this.historyService = historyService;
+ this.messageRepository = messageRepository;
+ }
@PostMapping(path = "/history")
@RateLimiter(name = "historyLimit", fallbackMethod = "fallbackMethod")
diff --git a/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ImagesController.java b/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ImagesController.java
index 619faabd..4ab22210 100644
--- a/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ImagesController.java
+++ b/GPTutor-Backend/src/main/java/com/chatgpt/controllers/ImagesController.java
@@ -19,14 +19,15 @@
@RestController
public class ImagesController {
- @Autowired
- ImagesService imagesService;
-
- @Autowired
- ComplaintsService complaintsService;
-
- @Autowired
- ImageLikeService imageLikeService;
+ private final ImagesService imagesService;
+ private final ComplaintsService complaintsService;
+ private final ImageLikeService imageLikeService;
+
+ public ImagesController(ImagesService imagesService, ComplaintsService complaintsService, ImageLikeService imageLikeService) {
+ this.imagesService = imagesService;
+ this.complaintsService = complaintsService;
+ this.imageLikeService = imageLikeService;
+ }
@PostMapping(path = "/image")
List generateImage(@RequestBody GenerateImageRequest prompt, HttpServletRequest request) {
diff --git a/GPTutor-Frontend/src/App.tsx b/GPTutor-Frontend/src/App.tsx
index f7bc2896..1b8ca59b 100644
--- a/GPTutor-Frontend/src/App.tsx
+++ b/GPTutor-Frontend/src/App.tsx
@@ -1,4 +1,11 @@
import React, { useEffect } from "react";
+import { retrieveLaunchParams } from "@telegram-apps/sdk";
+import { useLocation } from "@happysanta/router";
+import {
+ useAdaptivity,
+ useAppearance,
+ useInsets,
+} from "@vkontakte/vk-bridge-react";
import {
AdaptivityProvider,
AppRoot,
@@ -11,70 +18,83 @@ import bridge, {
AppearanceType,
parseURLSearchParamsForGetLaunchParams,
} from "@vkontakte/vk-bridge";
-import { useLocation } from "@happysanta/router";
-import {
- useAdaptivity,
- useAppearance,
- useInsets,
-} from "@vkontakte/vk-bridge-react";
-import "markdown-it-latex/dist/index.css";
+// Styles
+import "markdown-it-latex/dist/index.css";
import "@vkontakte/vkui/dist/vkui.css";
import "./index.css";
+// Core entities and services
import { vkUserModel } from "./entity/user";
import { online } from "./api/online";
+import { appService } from "$/services/AppService";
+import { transformVKBridgeAdaptivity } from "$/utility/strings";
+// Theme components
import { OneDark } from "./OneDark";
import { OneLight } from "./OneLight";
+
+// Routing
import { Modals, Panels, Views } from "./entity/routing";
+// Navigation and utilities
+import { useNavigationContext } from "./NavigationContext";
+import { SnackbarNotifier } from "./components/SnackbarNotifier";
+import UtilBlock from "./UtilBlock";
+
+// Main panels
import { Home } from "./panels/Home";
import { Chapters } from "./panels/Chapters";
import { History } from "./panels/History";
import { Modes } from "./panels/Modes";
-
-import { useNavigationContext } from "./NavigationContext";
-import { SnackbarNotifier } from "./components/SnackbarNotifier";
import { ChatSettings } from "./panels/ChatSettings";
-import { ApplicationInfo } from "./modals/ApplicationInfo";
+import { LoadingPanel } from "$/panels/LoadingPanel";
+
+// Chat panels
import { ChatFree } from "./panels/ChatFree";
import { ChatLesson } from "./panels/ChatLesson";
import { ChatInterview } from "./panels/ChatInterview";
-import { InterviewQuestions } from "./modals/InterviewQuestions";
-import { LeetcodeProblems } from "./panels/LeetCodeProblems";
import { ChatLeetCode } from "./panels/ChatLeetCode";
+import { ChatTrainer } from "./panels/ChatTrainer";
+
+// LeetCode panels
+import { LeetcodeProblems } from "./panels/LeetCodeProblems";
import { ProblemDetail } from "./panels/ProblemDetail";
-import { AppAlert } from "./modals/AppAlert";
+
+// Code editor
import { CodeEditor } from "./panels/CodeEditor";
-import { ChatTrainer } from "./panels/ChatTrainer";
-import { ImageGenerationResult } from "./panels/ImageGenerationResult";
-import UtilBlock from "./UtilBlock";
-import { appService } from "$/services/AppService";
-import { LoadingPanel } from "$/panels/LoadingPanel";
+// Image generation panels
import { ImageGeneration } from "$/panels/ImageGeneration";
+import { ImageGenerationResult } from "./panels/ImageGenerationResult";
import { ImageGenerationExamples } from "$/panels/ImageGenerationExamples";
import Gallery from "$/panels/Gallery";
import ImageCreatePrompts from "$/panels/ImageCreatePrompts";
-import Profile from "$/panels/Profile";
-import ApplicationInfoStableArt from "./modals/ApplicationInfoStableArt/ApplicationInfoStableArt";
import { PublishingImages } from "$/panels/PublishingImages";
-import { Agreement } from "$/modals/Agreement";
-import { DetailImage } from "$/modals/DetailImage";
-import { WeakRequestModal } from "$/modals/WeakRequestModal";
+
+// Profile panels
+import Profile from "$/panels/Profile";
import { GPTutorProfile } from "$/panels/GPTutorProfile";
-import { transformVKBridgeAdaptivity } from "$/utility/strings";
+
+// Other feature panels
import { MermaidPage } from "$/panels/MermaidPage";
import { AdditionalRequests } from "$/panels/AdditionalRequests";
import { AnecdoteMain } from "$/panels/AnecdoteMain";
import AnecdoteGeneration from "./panels/AnecdoteGeneration/AnecdoteGeneration";
import { AnecdoteNews } from "$/panels/AnecdoteNews";
-import ApplicationInfoHumor from "./modals/ApplicationInfoHumor/ApplicationInfoHumor";
import { BingPanel } from "$/panels/BingPanel";
import VKDocQuestionPanel from "./panels/VKDocQuestionPanel/VKDocQestionPanel";
import { VkDocQuestionRequest } from "$/panels/VkDocQuestionRequest";
-import { retrieveLaunchParams } from "@telegram-apps/sdk";
+
+// Modals
+import { ApplicationInfo } from "./modals/ApplicationInfo";
+import ApplicationInfoStableArt from "./modals/ApplicationInfoStableArt/ApplicationInfoStableArt";
+import ApplicationInfoHumor from "./modals/ApplicationInfoHumor/ApplicationInfoHumor";
+import { InterviewQuestions } from "./modals/InterviewQuestions";
+import { Agreement } from "$/modals/Agreement";
+import { DetailImage } from "$/modals/DetailImage";
+import { WeakRequestModal } from "$/modals/WeakRequestModal";
+import { AppAlert } from "./modals/AppAlert";
const App = () => {
const location = useLocation();
diff --git a/GPTutor-Models/app.py b/GPTutor-Models/app.py
index 2be60706..92274960 100644
--- a/GPTutor-Models/app.py
+++ b/GPTutor-Models/app.py
@@ -1,49 +1,38 @@
-from flask import Flask, request
+from flask import Flask, request, jsonify
+import logging
+import traceback
from images.dalle3 import generate_dalle
from images.prodia import txt2img
from vk_docs.index import create_question_vk_doc
app = Flask(__name__)
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
@app.post('/llm')
def llm_post():
- return None
+ return jsonify({"message": "LLM POST endpoint not implemented"}), 501
@app.get('/llm')
def llm_get():
- return []
+ return jsonify([])
@app.post("/image")
def image():
- return txt2img(
- prompt=request.json["prompt"],
- model=request.json["modelId"],
- negative_prompt=request.json["negativePrompt"],
- scheduler=request.json["scheduler"],
- guidance_scale=request.json["guidanceScale"],
- seed=request.json["seed"],
- steps=request.json["numInferenceSteps"],
- )
-
-
-@app.post("/vk-doc-question")
-def vk_doc_question():
- return create_question_vk_doc(
- question=request.json["question"],
- source=request.json["source"]
- )
-
-
-@app.post("/dalle")
-def dalle():
- print(request.json)
-
try:
- return txt2img(
+ if not request.json:
+ return jsonify({"error": "JSON payload required"}), 400
+
+ required_fields = ["prompt", "modelId", "negativePrompt", "scheduler", "guidanceScale", "seed", "numInferenceSteps"]
+ for field in required_fields:
+ if field not in request.json:
+ return jsonify({"error": f"Missing required field: {field}"}), 400
+
+ result = txt2img(
prompt=request.json["prompt"],
model=request.json["modelId"],
negative_prompt=request.json["negativePrompt"],
@@ -52,10 +41,47 @@ def dalle():
seed=request.json["seed"],
steps=request.json["numInferenceSteps"],
)
+ return jsonify(result)
+ except Exception as e:
+ logger.error(f"Error in image generation: {str(e)}")
+ logger.error(traceback.format_exc())
+ return jsonify({"error": "Image generation failed"}), 500
+
+@app.post("/vk-doc-question")
+def vk_doc_question():
+ try:
+ if not request.json:
+ return jsonify({"error": "JSON payload required"}), 400
+
+ if "question" not in request.json or "source" not in request.json:
+ return jsonify({"error": "Missing required fields: question, source"}), 400
+
+ result = create_question_vk_doc(
+ question=request.json["question"],
+ source=request.json["source"]
+ )
+ return jsonify(result)
except Exception as e:
- print(e)
- return txt2img(
+ logger.error(f"Error in VK doc question: {str(e)}")
+ logger.error(traceback.format_exc())
+ return jsonify({"error": "VK doc question processing failed"}), 500
+
+
+@app.post("/dalle")
+def dalle():
+ try:
+ if not request.json:
+ return jsonify({"error": "JSON payload required"}), 400
+
+ logger.info(f"DALLE request: {request.json}")
+
+ required_fields = ["prompt", "modelId", "negativePrompt", "scheduler", "guidanceScale", "seed", "numInferenceSteps"]
+ for field in required_fields:
+ if field not in request.json:
+ return jsonify({"error": f"Missing required field: {field}"}), 400
+
+ result = txt2img(
prompt=request.json["prompt"],
model=request.json["modelId"],
negative_prompt=request.json["negativePrompt"],
@@ -64,6 +90,11 @@ def dalle():
seed=request.json["seed"],
steps=request.json["numInferenceSteps"],
)
+ return jsonify(result)
+ except Exception as e:
+ logger.error(f"Error in DALLE generation: {str(e)}")
+ logger.error(traceback.format_exc())
+ return jsonify({"error": "DALLE generation failed"}), 500
def run_flask():
diff --git a/GPTutor-Rag/index.ts b/GPTutor-Rag/index.ts
index 50bc22bc..5b442da3 100644
--- a/GPTutor-Rag/index.ts
+++ b/GPTutor-Rag/index.ts
@@ -1,5 +1,4 @@
-import express from "express";
-
+import express, { Request, Response } from "express";
import { GigaChatEmbeddings } from "./GigaChatSupport/GigaChatEmbeddings";
import { FaissStore } from "@langchain/community/vectorstores/faiss";
import * as bodyParser from "body-parser";
@@ -10,60 +9,107 @@ import dotenv from "dotenv";
dotenv.config();
const app = express();
+const PORT = process.env.PORT || 5000;
app.use(bodyParser.json());
+interface DocQuestionRequest {
+ question: string;
+ source: string;
+}
+
+type SupportedSources = "all" | "vk_api_docs" | "vk_ui" | "videos";
+
+function isValidSource(source: string): source is SupportedSources {
+ return ["all", "vk_api_docs", "vk_ui", "videos"].includes(source);
+}
+
(async () => {
- const vectorStoreVKUIDoc = await FaissStore.loadFromPython(
- "./faiss_vk_ui_docs_index",
- new GigaChatEmbeddings({ clientSecretKey: process.env.CLIENT_SECRET_KEY })
- );
-
- const vectorStoreVKDoc = await FaissStore.load(
- "./faiss_vk_docs_index_js",
- new GigaChatEmbeddings({ clientSecretKey: process.env.CLIENT_SECRET_KEY })
- );
-
- const vectorStoreVideos = await FaissStore.loadFromPython(
- "./faiss_vk_videos_index",
- new GigaChatEmbeddings({ clientSecretKey: process.env.CLIENT_SECRET_KEY })
- );
-
- function createRetriever(source: string) {
- if (source === "all") {
- return new EnsembleRetriever({
- retrievers: [
- vectorStoreVKUIDoc.asRetriever({ k: 2 }),
- vectorStoreVKDoc.asRetriever({ k: 2 }),
- vectorStoreVideos.asRetriever({ k: 2 }),
- ],
- weights: [0.33, 0.33, 0.33],
- });
+ try {
+ console.log("Loading vector stores...");
+
+ if (!process.env.CLIENT_SECRET_KEY) {
+ throw new Error("CLIENT_SECRET_KEY environment variable is required");
}
- if (source == "vk_api_docs") {
- return new EnsembleRetriever({
- retrievers: [vectorStoreVKDoc.asRetriever({ k: 3 })],
- });
- }
+ const embeddings = new GigaChatEmbeddings({ clientSecretKey: process.env.CLIENT_SECRET_KEY });
- if (source == "vk_ui") {
- return vectorStoreVKUIDoc.asRetriever({ k: 3 });
- }
+ const vectorStoreVKUIDoc = await FaissStore.loadFromPython(
+ "./faiss_vk_ui_docs_index",
+ embeddings
+ );
- return vectorStoreVideos.asRetriever({ k: 3 });
- }
+ const vectorStoreVKDoc = await FaissStore.load(
+ "./faiss_vk_docs_index_js",
+ embeddings
+ );
+
+ const vectorStoreVideos = await FaissStore.loadFromPython(
+ "./faiss_vk_videos_index",
+ embeddings
+ );
- app.post("/doc-question", async (req, res) => {
- try {
- const { question, source } = req.body;
- res.send(await createWorkflow(question, createRetriever(source)));
- } catch (e) {
- res.send("Что-то пошло не так");
+ console.log("Vector stores loaded successfully");
+
+ function createRetriever(source: SupportedSources) {
+ switch (source) {
+ case "all":
+ return new EnsembleRetriever({
+ retrievers: [
+ vectorStoreVKUIDoc.asRetriever({ k: 2 }),
+ vectorStoreVKDoc.asRetriever({ k: 2 }),
+ vectorStoreVideos.asRetriever({ k: 2 }),
+ ],
+ weights: [0.33, 0.33, 0.33],
+ });
+ case "vk_api_docs":
+ return new EnsembleRetriever({
+ retrievers: [vectorStoreVKDoc.asRetriever({ k: 3 })],
+ });
+ case "vk_ui":
+ return vectorStoreVKUIDoc.asRetriever({ k: 3 });
+ case "videos":
+ return vectorStoreVideos.asRetriever({ k: 3 });
+ default:
+ throw new Error(`Unsupported source: ${source}`);
+ }
}
- });
- app.listen(5000, () => {
- console.log(`Server running on port ${5000}`);
- });
+ app.post("/doc-question", async (req: Request<{}, any, DocQuestionRequest>, res: Response) => {
+ try {
+ const { question, source } = req.body;
+
+ if (!question || !source) {
+ return res.status(400).json({
+ error: "Missing required fields: question and source are required"
+ });
+ }
+
+ if (!isValidSource(source)) {
+ return res.status(400).json({
+ error: `Invalid source. Supported sources: ${["all", "vk_api_docs", "vk_ui", "videos"].join(", ")}`
+ });
+ }
+
+ const result = await createWorkflow(question, createRetriever(source));
+ res.json({ result });
+ } catch (error) {
+ console.error("Error processing doc question:", error);
+ res.status(500).json({
+ error: "Internal server error occurred while processing your question"
+ });
+ }
+ });
+
+ app.get("/health", (req: Request, res: Response) => {
+ res.json({ status: "healthy", timestamp: new Date().toISOString() });
+ });
+
+ app.listen(PORT, () => {
+ console.log(`Server running on port ${PORT}`);
+ });
+ } catch (error) {
+ console.error("Failed to initialize server:", error);
+ process.exit(1);
+ }
})();