Compare commits

...

8 Commits

Author SHA1 Message Date
Aarthi Manivannan, Premanathan Aarthi Manivannan eec0b2d356 Update 6 files
- /src/main/Resources/application.yml
- /src/main/config/AppProperties.java
- /src/main/service/ExternalApiService.java
- /src/main/controller/GenerateController.java
- /src/test/AppPropertiesTest.java
- /README.md
2025-12-14 19:03:33 +01:00
Aarthi Manivannan, Premanathan Aarthi Manivannan 77dcf6d812 Delete AppPropertiesTest.java 2025-12-14 18:03:41 +01:00
Aarthi Manivannan, Premanathan Aarthi Manivannan b9881d55e7 Delete application.yml 2025-12-14 18:03:26 +01:00
Aarthi Manivannan, Premanathan Aarthi Manivannan a7a8170cd5 Delete ExternalApiService.java 2025-12-14 18:03:05 +01:00
Aarthi Manivannan, Premanathan Aarthi Manivannan 15a4807567 Delete GenerateController.java 2025-12-14 18:02:46 +01:00
Aarthi Manivannan, Premanathan Aarthi Manivannan 3bbd82eddc Delete AppProperties.java 2025-12-14 18:02:13 +01:00
Aarthi Manivannan, Premanathan Aarthi Manivannan 55555bcc37 Update 6 files
- /src1/main/resources/application.yml
- /src1/main/java/com/v2d/document/config/AppProperties.java
- /src1/main/java/com/v2d/document/service/ExternalApiService.java
- /src1/main/java/com/v2d/document/controller/GenerateController.java
- /src1/test/AppPropertiesTest.java
- /README.md
2025-12-09 17:59:09 +01:00
Hughes, Mike 283b4ed6af Merge branch 'develop' into 'main'
Implemented the general modular framework.

See merge request proj-wise2526-video2document/video2document!22
2025-11-15 15:14:24 +01:00
6 changed files with 179 additions and 2 deletions
+23 -2
View File
@@ -88,6 +88,27 @@ Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
---
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
## Sprint 4 Secure API Key Management
In Sprint 4, secure handling of API keys was implemented for the V2D (Video to Document) framework.
### Implementation Overview
- API keys are **not stored in the source code**
- The backend loads the key from an **environment variable**
- A single configuration works for all users without manual setup
- Secrets are protected from being exposed in the repository or frontend
### Configuration
The backend expects the following environment variable:
This variable is injected at runtime by the deployment or CI/CD environment and referenced in `application.yml`.
### Security Benefits
- Prevents accidental exposure of API keys
- Ensures secure collaboration in GitLab
- Follows best practices for secret management
---
+7
View File
@@ -0,0 +1,7 @@
spring:
application:
name: v2d-document
app:
external:
apiKey: ${LLM_API_KEY:}
+13
View File
@@ -0,0 +1,13 @@
package com.v2d.document.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "app.external")
public class AppProperties {
private String apiKey;
public String getApiKey() { return apiKey; }
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
}
@@ -0,0 +1,26 @@
package com.v2d.document.controller;
import com.v2d.document.service.ExternalApiService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/generate")
public class GenerateController {
private final ExternalApiService externalApiService;
public GenerateController(ExternalApiService externalApiService) {
this.externalApiService = externalApiService;
}
@PostMapping
public ResponseEntity<String> generate(@RequestBody Map<String,Object> body) {
// Build provider payload from the user's body (transform safely)
String payload = "{\"text\": \"use this text\"}"; // adapt for real usage
String providerResponse = externalApiService.callProvider(payload);
return ResponseEntity.ok(providerResponse);
}
}
+90
View File
@@ -0,0 +1,90 @@
package com.v2d.document.service;
import com.v2d.document.config.AppProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
@Service
public class ExternalApiService {
private final Logger log = LoggerFactory.getLogger(ExternalApiService.class);
private final AppProperties props;
private final HttpClient http = HttpClient.newHttpClient();
public ExternalApiService(AppProperties props) {
this.props = props;
}
public String callProvider(String jsonPayload) {
String key = props.getApiKey();
if (key == null || key.isBlank()) {
log.warn("External API key is not configured.");
throw new IllegalStateException("External API key missing");
}
try {
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/endpoint")) // replace with real endpoint
.header("Authorization", "Bearer " + key)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString());
return resp.body();
} catch (Exception e) {
log.error("External API call failed: {}", e.getMessage());
throw new RuntimeException("External API call failed", e);
}
}
}
package com.v2d.document.service;
import com.v2d.document.config.AppProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
@Service
public class ExternalApiService {
private final Logger log = LoggerFactory.getLogger(ExternalApiService.class);
private final AppProperties props;
private final HttpClient http = HttpClient.newHttpClient();
public ExternalApiService(AppProperties props) {
this.props = props;
}
public String callProvider(String jsonPayload) {
String key = props.getApiKey();
if (key == null || key.isBlank()) {
log.warn("External API key is not configured.");
throw new IllegalStateException("External API key missing");
}
try {
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/endpoint")) // replace with real endpoint
.header("Authorization", "Bearer " + key)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString());
return resp.body();
} catch (Exception e) {
log.error("External API call failed: {}", e.getMessage());
throw new RuntimeException("External API call failed", e);
}
}
}
+20
View File
@@ -0,0 +1,20 @@
package com.v2d.document.config;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
public class AppPropertiesTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(AppProperties.class)
.withPropertyValues("app.external.apiKey=TEST_KEY");
@Test
void bindsApiKey() {
contextRunner.run(context -> {
AppProperties props = context.getBean(AppProperties.class);
assertThat(props.getApiKey()).isEqualTo("TEST_KEY");
});
}
}