From 24ca1521b44c69a80c7801a8e8a2e7e975329b53 Mon Sep 17 00:00:00 2001 From: Krrish Ghimire Date: Fri, 10 Jul 2026 11:39:19 +0545 Subject: [PATCH] fix timeout, cors and token issues --- .../com/krrishg/config/SecurityConfig.java | 7 +--- .../com/krrishg/controller/LLMController.java | 4 +- .../main/java/com/krrishg/dto/LLMOptions.java | 2 +- .../java/com/krrishg/service/LLMService.java | 4 ++ .../krrishg/service/llm/ProviderFactory.java | 5 ++- backend/src/main/resources/application.yml | 4 +- docker-compose.v3.yml | 40 +++++++++++++++++++ frontend/nginx.conf | 2 + 8 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 docker-compose.v3.yml diff --git a/backend/src/main/java/com/krrishg/config/SecurityConfig.java b/backend/src/main/java/com/krrishg/config/SecurityConfig.java index 3221316..bb3f8eb 100644 --- a/backend/src/main/java/com/krrishg/config/SecurityConfig.java +++ b/backend/src/main/java/com/krrishg/config/SecurityConfig.java @@ -5,7 +5,6 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -13,7 +12,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @@ -33,9 +31,6 @@ public class SecurityConfig { private final JwtConfig jwtConfig; - @Value("${indie.cors.allowed-origins:http://localhost:4200}") - private String[] allowedOrigins; - public SecurityConfig(JwtConfig jwtConfig) { this.jwtConfig = jwtConfig; } @@ -72,7 +67,7 @@ public class SecurityConfig { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); - config.setAllowedOrigins(List.of(allowedOrigins)); + config.setAllowedOriginPatterns(List.of("*")); config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")); config.setAllowedHeaders(List.of("*")); config.setAllowCredentials(true); diff --git a/backend/src/main/java/com/krrishg/controller/LLMController.java b/backend/src/main/java/com/krrishg/controller/LLMController.java index 2ce566f..3217775 100644 --- a/backend/src/main/java/com/krrishg/controller/LLMController.java +++ b/backend/src/main/java/com/krrishg/controller/LLMController.java @@ -72,7 +72,7 @@ public class LLMController { SiteStructure structure = llmService.generateSite( principal.id(), siteId, prompt, references, provider, apiKey, baseUrl, model); return ResponseEntity.ok(structure); - } catch (IllegalStateException e) { + } catch (IllegalStateException | IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of("error", e.getMessage())); } } @@ -130,7 +130,7 @@ public class LLMController { SiteStructure structure = llmService.refineSite(principal.id(), siteId, currentStructure, prompt, references, provider, apiKey, baseUrl, model); return ResponseEntity.ok(structure); - } catch (IllegalStateException e) { + } catch (IllegalStateException | IllegalArgumentException e) { return ResponseEntity.badRequest().body(Map.of("error", e.getMessage())); } } diff --git a/backend/src/main/java/com/krrishg/dto/LLMOptions.java b/backend/src/main/java/com/krrishg/dto/LLMOptions.java index 181d659..38bd3e7 100644 --- a/backend/src/main/java/com/krrishg/dto/LLMOptions.java +++ b/backend/src/main/java/com/krrishg/dto/LLMOptions.java @@ -13,7 +13,7 @@ public class LLMOptions { private double temperature = 0.9; @Builder.Default - private int maxTokens = 4096; + private int maxTokens = 16384; @Builder.Default private int timeoutSeconds = 60; diff --git a/backend/src/main/java/com/krrishg/service/LLMService.java b/backend/src/main/java/com/krrishg/service/LLMService.java index 5b9a65c..903e23d 100644 --- a/backend/src/main/java/com/krrishg/service/LLMService.java +++ b/backend/src/main/java/com/krrishg/service/LLMService.java @@ -6,6 +6,7 @@ import com.krrishg.dto.LLMResult; import com.krrishg.dto.Reference; import com.krrishg.dto.SiteStructure; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.ResourceAccessException; import com.krrishg.model.GenerationVersion; import com.krrishg.model.User; import com.krrishg.repository.UserRepository; @@ -204,6 +205,9 @@ public class LLMService { LLMProvider p = providerFactory.createProvider(provider, apiKey, baseUrl, model); try { return p.generate(systemPrompt, userPrompt, references, options); + } catch (ResourceAccessException e) { + throw new IllegalStateException( + provider + " timed out. Please try again or use a simpler prompt."); } catch (HttpClientErrorException e) { String detail = e.getResponseBodyAsString(); String msg = switch (e.getStatusCode().value()) { diff --git a/backend/src/main/java/com/krrishg/service/llm/ProviderFactory.java b/backend/src/main/java/com/krrishg/service/llm/ProviderFactory.java index ec3afe9..56eaab2 100644 --- a/backend/src/main/java/com/krrishg/service/llm/ProviderFactory.java +++ b/backend/src/main/java/com/krrishg/service/llm/ProviderFactory.java @@ -14,14 +14,17 @@ public class ProviderFactory { private final RestTemplateBuilder restTemplateBuilder; private final Map providerConfigs; + private final Duration readTimeout; public ProviderFactory( @Value("${indie.llm.providers.gemini.model:gemini-3.1-flash-lite}") String geminiModel, @Value("${indie.llm.providers.gemini.url:https://generativelanguage.googleapis.com/v1beta/models}") String geminiUrl, @Value("${indie.llm.providers.openai.model:gpt-4o-mini}") String openaiModel, @Value("${indie.llm.providers.openai.url:https://api.openai.com/v1/chat/completions}") String openaiUrl, + @Value("${indie.llm.read-timeout:180s}") Duration readTimeout, RestTemplateBuilder restTemplateBuilder) { this.restTemplateBuilder = restTemplateBuilder; + this.readTimeout = readTimeout; this.providerConfigs = Map.of( "gemini", new ProviderConfig(geminiModel, geminiUrl), "openai", new ProviderConfig(openaiModel, openaiUrl) @@ -52,7 +55,7 @@ public class ProviderFactory { } RestTemplate rt = restTemplateBuilder .setConnectTimeout(Duration.ofSeconds(30)) - .setReadTimeout(Duration.ofSeconds(60)) + .setReadTimeout(readTimeout) .build(); return switch (name) { case "gemini" -> new GeminiProvider(apiKey, resolvedModel, url, rt); diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 5cbf099..f845ef3 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -55,9 +55,6 @@ indie: repos-path: ${INDIE_GIT_REPOS_PATH:/home/krrish/git/sites/} author-name: ${INDIE_GIT_AUTHOR_NAME:Indie Platform} author-email: ${INDIE_GIT_AUTHOR_EMAIL:git@indie.local} - cors: - allowed-origins: ${INDIE_CORS_ORIGINS:http://localhost:4200,http://localhost:3000} - storage: endpoint: ${INDIE_STORAGE_ENDPOINT:http://localhost:9000} region: ${INDIE_STORAGE_REGION:auto} @@ -74,6 +71,7 @@ indie: verification-token-expiration-minutes: ${INDIE_VERIFICATION_TOKEN_EXPIRATION:1440} llm: + read-timeout: ${INDIE_LLM_READ_TIMEOUT:180s} rate-limit: max-requests-per-hour: ${INDIE_LLM_RATE_LIMIT:10} providers: diff --git a/docker-compose.v3.yml b/docker-compose.v3.yml new file mode 100644 index 0000000..27bbe1c --- /dev/null +++ b/docker-compose.v3.yml @@ -0,0 +1,40 @@ +version: '3' + +services: + postgres: + image: postgres:16-alpine + network_mode: host + environment: + POSTGRES_DB: indie + POSTGRES_USER: indie + POSTGRES_PASSWORD: indie_dev + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U indie"] + interval: 5s + timeout: 5s + retries: 5 + + mongodb: + image: mongo:7 + network_mode: host + environment: + MONGO_INITDB_DATABASE: indie + volumes: + - mongodata:/data/db + + minio: + image: minio/minio:latest + network_mode: host + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: indieadmin + MINIO_ROOT_PASSWORD: indiesecret + volumes: + - miniodata:/data + +volumes: + pgdata: + mongodata: + miniodata: \ No newline at end of file diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 51a4c17..c045a23 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -10,5 +10,7 @@ server { location /api/ { proxy_pass http://backend:8080; + proxy_read_timeout 180s; + proxy_connect_timeout 30s; } }