-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from vmilovanovicc/backend
Backend functionalities
- Loading branch information
Showing
15 changed files
with
1,019 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
name: Code Quality Checks | ||
|
||
on: | ||
push: | ||
branches: | ||
- '*' | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
check: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v3 | ||
|
||
# Install Tools | ||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: '>=1.20.3' | ||
|
||
- name: Set up Terraform | ||
uses: hashicorp/setup-terraform@v2 | ||
|
||
- name: Configure AWS Credentials | ||
uses: aws-actions/configure-aws-credentials@v2 | ||
with: | ||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | ||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | ||
aws-region: eu-central-1 | ||
|
||
# Validate Go Code | ||
- name: Check Go code formatting | ||
run: gofmt -l . | tee fmt.log && test ! -s fmt.log | ||
|
||
- name: Install Go dependencies | ||
run: go mod download | ||
|
||
- name: Build Go code | ||
run: go build -v ./... | ||
|
||
- name: Run tests (if applicable) | ||
run: go test -v ./... | ||
|
||
- name: Run Code Coverage | ||
run: go test -cover ./... | ||
|
||
# Validate Terraform Code | ||
- name: Check Terraform code formatting | ||
run: terraform fmt -check=true -recursive | ||
continue-on-error: true | ||
|
||
- name: Validate Terraform configuration | ||
run: terraform validate | ||
continue-on-error: true | ||
|
||
# Secrets & Code Vulnerabilities | ||
- name: Check for secrets | ||
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.ref == 'refs/heads/main') | ||
uses: trufflesecurity/TruffleHog-Enterprise-Github-Action@main | ||
with: | ||
args: --fail-verified ${{ github.ref }} HEAD | ||
|
||
- name: Golang - Run Snyk to check for vulnerabilities | ||
uses: snyk/actions/golang@master | ||
continue-on-error: true # To make sure that SARIF upload gets called | ||
env: | ||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | ||
with: | ||
args: --sarif-file-output=snyk_go.sarif | ||
|
||
- name: Terraform - Run Snyk to check for vulnerabilities | ||
uses: snyk/actions/iac@master | ||
continue-on-error: true | ||
env: | ||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | ||
with: | ||
args: --sarif-file-output=snyk_tf.sarif | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,3 +19,9 @@ | |
|
||
# Go workspace file | ||
go.work | ||
|
||
|
||
# Terraform | ||
|
||
# IDE | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,93 @@ | ||
# zobot | ||
Chatbot Translator App with AWS, Golang and Terraform | ||
|
||
<img alt="ProjectStatus" src="https://img.shields.io/badge/IN%20PROGRESS-097969?style=for-the-badge&logo=IN%20PROGRESS&logoColor=FFF"> | ||
|
||
![GitHub language count](https://img.shields.io/github/languages/count/vmilovanovicc/zobot) | ||
![GitHub top language](https://img.shields.io/github/languages/top/vmilovanovicc/zobot) | ||
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/vmilovanovicc/zobot/checks.yaml) | ||
![GitHub pull requests](https://img.shields.io/github/issues-pr/vmilovanovicc/:zobot) | ||
![GitHub](https://img.shields.io/github/license/vmilovanovicc/zobot) | ||
![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/vmilovanovicc/zobot) | ||
![Go Version](https://img.shields.io/github/go-mod/go-version/vmilovanovicc/zobot) | ||
|
||
<br/> | ||
<img alt="Go" src="https://img.shields.io/badge/go-%2300ADD8.svg?style=for-the-badge&logo=go&logoColor=white"> | ||
<img alt="AWS" src="https://img.shields.io/badge/AWS-%23FF9900.svg?style=for-the-badge&logo=amazon-aws&logoColor=white"> | ||
<img alt="Terraform" src="https://img.shields.io/badge/terraform-%235835CC.svg?style=for-the-badge&logo=terraform&logoColor=white"> | ||
|
||
## Prerequisites | ||
|
||
| Tools | Version | | ||
|-----------|-----------| | ||
| Go | `>= 1.20.3` | | ||
| Terraform | `>= 1.5.0` | | ||
|
||
## AWS Services | ||
|
||
| Service | Description | | ||
|--------------------|----------------------------------------------------------| | ||
| Amazon Comprehend | Detect the language source | | ||
| Amazon Translate | Translate user-generated content | | ||
| Amazon Polly | Turn text into life-like speech | | ||
| Amazon Lex | Build bots with Conversational AI | | ||
| Amazon S3 | Object storage | | ||
| AWS Lambda | Run code without provisioning or managing infrastructure | | ||
|
||
--- | ||
|
||
# What is zobot? | ||
|
||
**zobot** is a multilingual chatbot application powered by AWS and written in Go. It uses Amazon Web Services to interact with users, translate text and turn it into lifelike audio. | ||
|
||
## HLA | ||
|
||
![zobot diagram](assets/zobot_hla.png) | ||
|
||
### How zobot works? | ||
- You talk to **zobot** by interacting with Amazon Lex bot. | ||
- With AWS Comprehend, **zobot** detects the language you're using. | ||
- **zobot** uses Amazon Translate to translate your words into a desired language. | ||
- With AWS Polly, **zobot** transforms the translated text with the correct pronunciation into a lifelike speech. | ||
- **zobot** keeps all audio messages in an S3 bucket. | ||
|
||
#### Supported Languages | ||
- English | ||
- Spanish | ||
- French | ||
|
||
--- | ||
|
||
## Testing | ||
Unit tests and [mocks](/backend/mock_client_ops.go) can be found [here](/backend). | ||
|
||
--- | ||
|
||
# References | ||
|
||
### AWS SDK for Go | ||
|
||
- [AWS SDK Go v2 Reference](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2#section-readme) | ||
- [`translate` API client](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/translate) | ||
- [`polly` API client](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/polly) | ||
- [`s3` API client](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3) | ||
|
||
|
||
### AWS Documentation | ||
|
||
- [Amazon Comprehend](https://aws.amazon.com/comprehend/) | ||
- [Amazon Translate](https://aws.amazon.com/translate/) | ||
- [Amazon Polly](https://aws.amazon.com/polly/) | ||
- [Amazon Lex](https://aws.amazon.com/lex/) | ||
- [Amazon S3](https://aws.amazon.com/s3/) | ||
- [AWS Lambda](https://aws.amazon.com/lambda/) | ||
|
||
- [Amazon - Translate Supported Languages](https://docs.aws.amazon.com/translate/latest/dg/what-is-languages.html) | ||
- [Amazon Polly - Voice List](https://docs.aws.amazon.com/polly/latest/dg/voicelist.html) | ||
- [Amazon Polly - Supported Languages](https://docs.aws.amazon.com/polly/latest/dg/SupportedLanguage.html) | ||
|
||
### Other | ||
- [trufflehog](https://github.com/trufflesecurity/trufflehog) - Secrets/Security Scan | ||
- [snyk](https://github.com/snyk/actions) - Code Vulnerabilities Scan | ||
|
||
--- |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package backend | ||
|
||
import ( | ||
"context" | ||
"github.com/aws/aws-sdk-go-v2/aws" | ||
"github.com/aws/aws-sdk-go-v2/config" | ||
"log" | ||
) | ||
|
||
var region = "eu-central-1" | ||
|
||
// LoadAWSConfig loads the Shared AWS Configuration (~/.aws/config) | ||
func LoadAWSConfig() (cfg aws.Config) { | ||
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region)) | ||
if err != nil { | ||
log.Fatalf("failed to load configuration, %v\n", err) | ||
} | ||
return cfg | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package backend | ||
|
||
// For unit testing, mock out the SDK. | ||
// Using Go interfaces, instead of concrete service client. | ||
|
||
import ( | ||
"context" | ||
"github.com/aws/aws-sdk-go-v2/aws" | ||
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" | ||
"github.com/aws/aws-sdk-go-v2/service/polly" | ||
typesPolly "github.com/aws/aws-sdk-go-v2/service/polly/types" | ||
"github.com/aws/aws-sdk-go-v2/service/s3" | ||
typesS3 "github.com/aws/aws-sdk-go-v2/service/s3/types" | ||
"github.com/aws/aws-sdk-go-v2/service/translate" | ||
"strings" | ||
"time" | ||
) | ||
|
||
////////////////////////////////////////// | ||
// TranslateText Mock | ||
////////////////////////////////////////// | ||
|
||
type TranslateTranslateTextAPI interface { | ||
TranslateText(ctx context.Context, params *translate.TranslateTextInput, optFns ...func(*translate.Options)) (*translate.TranslateTextOutput, error) | ||
} | ||
|
||
func TranslateTextFromTranslate(ctx context.Context, api TranslateTranslateTextAPI, text, language string) (string, error) { | ||
sourceLanguageCode := "auto" | ||
response, err := api.TranslateText(ctx, &translate.TranslateTextInput{ | ||
Text: aws.String(text), | ||
TargetLanguageCode: aws.String(language), | ||
SourceLanguageCode: aws.String(sourceLanguageCode), | ||
}) | ||
if err != nil { | ||
return "", err | ||
} | ||
return *response.TranslatedText, nil | ||
} | ||
|
||
////////////////////////////////////////// | ||
// CreateBucket Mock | ||
////////////////////////////////////////// | ||
|
||
type S3CreateBucketAPI interface { | ||
CreateBucket(ctx context.Context, params *s3.CreateBucketInput, optFns ...func(*s3.Options)) (*s3.CreateBucketOutput, error) | ||
} | ||
|
||
func CreateBucketFromS3(ctx context.Context, api S3CreateBucketAPI, bucketName string) (string, error) { | ||
response, err := api.CreateBucket(ctx, &s3.CreateBucketInput{ | ||
Bucket: aws.String(bucketName), | ||
CreateBucketConfiguration: &typesS3.CreateBucketConfiguration{ | ||
LocationConstraint: typesS3.BucketLocationConstraint(region), | ||
}, | ||
}) | ||
if err != nil { | ||
return "", err | ||
} | ||
return *response.Location, nil | ||
} | ||
|
||
////////////////////////////////////////// | ||
// PresignGetObject Mock | ||
////////////////////////////////////////// | ||
|
||
type S3PresignGetObjectAPI interface { | ||
GetPresignedURL(ctx context.Context, params *s3.GetObjectInput, optFns ...func(options *s3.PresignOptions)) (*v4.PresignedHTTPRequest, error) | ||
} | ||
|
||
func GetPresignedURLFromS3(ctx context.Context, api S3PresignGetObjectAPI, bucketName, objectName string, expires time.Time) (string, error) { | ||
response, err := api.GetPresignedURL(ctx, &s3.GetObjectInput{ | ||
Bucket: aws.String(bucketName), | ||
Key: aws.String(objectName), | ||
ResponseExpires: aws.Time(expires), | ||
}) | ||
if err != nil { | ||
return "", err | ||
} | ||
return response.URL, nil | ||
} | ||
|
||
////////////////////////////////////////// | ||
// StartSpeechSynthesisTask Mock | ||
////////////////////////////////////////// | ||
|
||
type PollyStartSpeechSynthesisTaskAPI interface { | ||
StartSpeechSynthesisTask(ctx context.Context, params *polly.StartSpeechSynthesisTaskInput, optFns ...func(*polly.Options)) (*polly.StartSpeechSynthesisTaskOutput, error) | ||
} | ||
|
||
func StartSpeechSynthesisTaskFromPolly(ctx context.Context, api PollyStartSpeechSynthesisTaskAPI, text, bucketName, languageCode, targetVoice string) (string, string, error) { | ||
response, err := api.StartSpeechSynthesisTask(ctx, &polly.StartSpeechSynthesisTaskInput{ | ||
Text: aws.String(text), | ||
OutputS3BucketName: aws.String(bucketName), | ||
VoiceId: typesPolly.VoiceId(targetVoice), | ||
LanguageCode: typesPolly.LanguageCode(languageCode), | ||
OutputFormat: typesPolly.OutputFormatMp3, | ||
Engine: typesPolly.EngineStandard, | ||
}) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
outputURI := strings.Split(*response.SynthesisTask.OutputUri, "/") | ||
objectName := outputURI[len(outputURI)-1] | ||
return *response.SynthesisTask.TaskId, objectName, nil | ||
} | ||
|
||
////////////////////////////////////////// | ||
// GetSpeechSynthesisTask Mock | ||
////////////////////////////////////////// | ||
|
||
type PollyGetSpeechSynthesisTaskAPI interface { | ||
GetSpeechSynthesisTask(ctx context.Context, params *polly.GetSpeechSynthesisTaskInput, optFns ...func(*polly.Options)) (*polly.GetSpeechSynthesisTaskOutput, error) | ||
} | ||
|
||
func GetSpeechSynthesisTaskFromPolly(ctx context.Context, api PollyGetSpeechSynthesisTaskAPI, taskId string) (typesPolly.TaskStatus, error) { | ||
response, err := api.GetSpeechSynthesisTask(ctx, &polly.GetSpeechSynthesisTaskInput{ | ||
TaskId: aws.String(taskId), | ||
}) | ||
if err != nil { | ||
return "", err | ||
} | ||
return response.SynthesisTask.TaskStatus, nil | ||
} |
Oops, something went wrong.