fix timeout, cors and token issues
This commit is contained in:
@@ -5,7 +5,6 @@ import jakarta.servlet.FilterChain;
|
|||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
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.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
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.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
@@ -33,9 +31,6 @@ public class SecurityConfig {
|
|||||||
|
|
||||||
private final JwtConfig jwtConfig;
|
private final JwtConfig jwtConfig;
|
||||||
|
|
||||||
@Value("${indie.cors.allowed-origins:http://localhost:4200}")
|
|
||||||
private String[] allowedOrigins;
|
|
||||||
|
|
||||||
public SecurityConfig(JwtConfig jwtConfig) {
|
public SecurityConfig(JwtConfig jwtConfig) {
|
||||||
this.jwtConfig = jwtConfig;
|
this.jwtConfig = jwtConfig;
|
||||||
}
|
}
|
||||||
@@ -72,7 +67,7 @@ public class SecurityConfig {
|
|||||||
@Bean
|
@Bean
|
||||||
public CorsConfigurationSource corsConfigurationSource() {
|
public CorsConfigurationSource corsConfigurationSource() {
|
||||||
CorsConfiguration config = new CorsConfiguration();
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
config.setAllowedOrigins(List.of(allowedOrigins));
|
config.setAllowedOriginPatterns(List.of("*"));
|
||||||
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
|
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
|
||||||
config.setAllowedHeaders(List.of("*"));
|
config.setAllowedHeaders(List.of("*"));
|
||||||
config.setAllowCredentials(true);
|
config.setAllowCredentials(true);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class LLMController {
|
|||||||
SiteStructure structure = llmService.generateSite(
|
SiteStructure structure = llmService.generateSite(
|
||||||
principal.id(), siteId, prompt, references, provider, apiKey, baseUrl, model);
|
principal.id(), siteId, prompt, references, provider, apiKey, baseUrl, model);
|
||||||
return ResponseEntity.ok(structure);
|
return ResponseEntity.ok(structure);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||||
return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
|
return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ public class LLMController {
|
|||||||
SiteStructure structure = llmService.refineSite(principal.id(), siteId,
|
SiteStructure structure = llmService.refineSite(principal.id(), siteId,
|
||||||
currentStructure, prompt, references, provider, apiKey, baseUrl, model);
|
currentStructure, prompt, references, provider, apiKey, baseUrl, model);
|
||||||
return ResponseEntity.ok(structure);
|
return ResponseEntity.ok(structure);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||||
return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
|
return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class LLMOptions {
|
|||||||
private double temperature = 0.9;
|
private double temperature = 0.9;
|
||||||
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int maxTokens = 4096;
|
private int maxTokens = 16384;
|
||||||
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int timeoutSeconds = 60;
|
private int timeoutSeconds = 60;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.krrishg.dto.LLMResult;
|
|||||||
import com.krrishg.dto.Reference;
|
import com.krrishg.dto.Reference;
|
||||||
import com.krrishg.dto.SiteStructure;
|
import com.krrishg.dto.SiteStructure;
|
||||||
import org.springframework.web.client.HttpClientErrorException;
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
|
import org.springframework.web.client.ResourceAccessException;
|
||||||
import com.krrishg.model.GenerationVersion;
|
import com.krrishg.model.GenerationVersion;
|
||||||
import com.krrishg.model.User;
|
import com.krrishg.model.User;
|
||||||
import com.krrishg.repository.UserRepository;
|
import com.krrishg.repository.UserRepository;
|
||||||
@@ -204,6 +205,9 @@ public class LLMService {
|
|||||||
LLMProvider p = providerFactory.createProvider(provider, apiKey, baseUrl, model);
|
LLMProvider p = providerFactory.createProvider(provider, apiKey, baseUrl, model);
|
||||||
try {
|
try {
|
||||||
return p.generate(systemPrompt, userPrompt, references, options);
|
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) {
|
} catch (HttpClientErrorException e) {
|
||||||
String detail = e.getResponseBodyAsString();
|
String detail = e.getResponseBodyAsString();
|
||||||
String msg = switch (e.getStatusCode().value()) {
|
String msg = switch (e.getStatusCode().value()) {
|
||||||
|
|||||||
@@ -14,14 +14,17 @@ public class ProviderFactory {
|
|||||||
|
|
||||||
private final RestTemplateBuilder restTemplateBuilder;
|
private final RestTemplateBuilder restTemplateBuilder;
|
||||||
private final Map<String, ProviderConfig> providerConfigs;
|
private final Map<String, ProviderConfig> providerConfigs;
|
||||||
|
private final Duration readTimeout;
|
||||||
|
|
||||||
public ProviderFactory(
|
public ProviderFactory(
|
||||||
@Value("${indie.llm.providers.gemini.model:gemini-3.1-flash-lite}") String geminiModel,
|
@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.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.model:gpt-4o-mini}") String openaiModel,
|
||||||
@Value("${indie.llm.providers.openai.url:https://api.openai.com/v1/chat/completions}") String openaiUrl,
|
@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) {
|
RestTemplateBuilder restTemplateBuilder) {
|
||||||
this.restTemplateBuilder = restTemplateBuilder;
|
this.restTemplateBuilder = restTemplateBuilder;
|
||||||
|
this.readTimeout = readTimeout;
|
||||||
this.providerConfigs = Map.of(
|
this.providerConfigs = Map.of(
|
||||||
"gemini", new ProviderConfig(geminiModel, geminiUrl),
|
"gemini", new ProviderConfig(geminiModel, geminiUrl),
|
||||||
"openai", new ProviderConfig(openaiModel, openaiUrl)
|
"openai", new ProviderConfig(openaiModel, openaiUrl)
|
||||||
@@ -52,7 +55,7 @@ public class ProviderFactory {
|
|||||||
}
|
}
|
||||||
RestTemplate rt = restTemplateBuilder
|
RestTemplate rt = restTemplateBuilder
|
||||||
.setConnectTimeout(Duration.ofSeconds(30))
|
.setConnectTimeout(Duration.ofSeconds(30))
|
||||||
.setReadTimeout(Duration.ofSeconds(60))
|
.setReadTimeout(readTimeout)
|
||||||
.build();
|
.build();
|
||||||
return switch (name) {
|
return switch (name) {
|
||||||
case "gemini" -> new GeminiProvider(apiKey, resolvedModel, url, rt);
|
case "gemini" -> new GeminiProvider(apiKey, resolvedModel, url, rt);
|
||||||
|
|||||||
@@ -55,9 +55,6 @@ indie:
|
|||||||
repos-path: ${INDIE_GIT_REPOS_PATH:/home/krrish/git/sites/}
|
repos-path: ${INDIE_GIT_REPOS_PATH:/home/krrish/git/sites/}
|
||||||
author-name: ${INDIE_GIT_AUTHOR_NAME:Indie Platform}
|
author-name: ${INDIE_GIT_AUTHOR_NAME:Indie Platform}
|
||||||
author-email: ${INDIE_GIT_AUTHOR_EMAIL:git@indie.local}
|
author-email: ${INDIE_GIT_AUTHOR_EMAIL:git@indie.local}
|
||||||
cors:
|
|
||||||
allowed-origins: ${INDIE_CORS_ORIGINS:http://localhost:4200,http://localhost:3000}
|
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
endpoint: ${INDIE_STORAGE_ENDPOINT:http://localhost:9000}
|
endpoint: ${INDIE_STORAGE_ENDPOINT:http://localhost:9000}
|
||||||
region: ${INDIE_STORAGE_REGION:auto}
|
region: ${INDIE_STORAGE_REGION:auto}
|
||||||
@@ -74,6 +71,7 @@ indie:
|
|||||||
verification-token-expiration-minutes: ${INDIE_VERIFICATION_TOKEN_EXPIRATION:1440}
|
verification-token-expiration-minutes: ${INDIE_VERIFICATION_TOKEN_EXPIRATION:1440}
|
||||||
|
|
||||||
llm:
|
llm:
|
||||||
|
read-timeout: ${INDIE_LLM_READ_TIMEOUT:180s}
|
||||||
rate-limit:
|
rate-limit:
|
||||||
max-requests-per-hour: ${INDIE_LLM_RATE_LIMIT:10}
|
max-requests-per-hour: ${INDIE_LLM_RATE_LIMIT:10}
|
||||||
providers:
|
providers:
|
||||||
|
|||||||
40
docker-compose.v3.yml
Normal file
40
docker-compose.v3.yml
Normal file
@@ -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:
|
||||||
@@ -10,5 +10,7 @@ server {
|
|||||||
|
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://backend:8080;
|
proxy_pass http://backend:8080;
|
||||||
|
proxy_read_timeout 180s;
|
||||||
|
proxy_connect_timeout 30s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user