feat: project setup
This commit is contained in:
0
CONSTITUTION.md
Normal file
0
CONSTITUTION.md
Normal file
0
CONTRIBUTING.md
Normal file
0
CONTRIBUTING.md
Normal file
0
Dockerfile
Normal file
0
Dockerfile
Normal file
39
README.md
Normal file
39
README.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# SpeakEasy: Know who's talking
|
||||||
|
|
||||||
|
## Client flow
|
||||||
|
1. Client uploads `EPUB`
|
||||||
|
2. Backend:
|
||||||
|
- Stores file
|
||||||
|
- Creates `book_id`
|
||||||
|
- Publishes job to RabbitMQ
|
||||||
|
3. Client subscribes:
|
||||||
|
- `GET /books/{book_id}/stream` via WebSocket
|
||||||
|
4. Backend:
|
||||||
|
- Authenticates user
|
||||||
|
- Remembers: `connection -> book_id`
|
||||||
|
5. Worker processes text:
|
||||||
|
- Calls Ollama
|
||||||
|
- Stores result in Postgres
|
||||||
|
- Emits "result ready" event
|
||||||
|
6. Backend:
|
||||||
|
- Receives event
|
||||||
|
- Pushes mathing results to the subscribed client
|
||||||
|
|
||||||
|
### Example WebSocket message to client
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"book_id": "book-abc",
|
||||||
|
"paragraph_id": "p-432",
|
||||||
|
"speaker": "Mary",
|
||||||
|
"confidence": 0.87
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Worker flow
|
||||||
|
1. Receives job from RabbitMQ
|
||||||
|
2. Loads paragraph text
|
||||||
|
3. Embeds paragraph
|
||||||
|
4. Queries vector DB (pgvector)
|
||||||
|
5. Builds prompt with retrieved content
|
||||||
|
6. Sends prompt to Ollama
|
||||||
|
7. Stores result
|
||||||
18
ai/AI.md
Normal file
18
ai/AI.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# AI
|
||||||
|
|
||||||
|
## FILES
|
||||||
|
- **client** `AI Service Clients`
|
||||||
|
- client.go `Client Interface`
|
||||||
|
- ollama.go `Ollama HTTP Client`
|
||||||
|
- **detector** `Speaker Detection Logic`
|
||||||
|
- context.go `Context tracking for conversations`
|
||||||
|
- patterns.go `Rule-based Fallback Detection`
|
||||||
|
- speaker.go `Main Speaker Detection`
|
||||||
|
- **models** `Model Management`
|
||||||
|
- config.go `Model Configurations`
|
||||||
|
- manager.go `Model Downloading/Switching`
|
||||||
|
- registry.go `Available Models Registry`
|
||||||
|
- **prompts** `Prompt Templates`
|
||||||
|
- speaker_detection.go `Prompts for Speaker Identification`
|
||||||
|
- templates.go `Prompt Template Utilities`
|
||||||
|
|
||||||
2
ai/client/client.go
Normal file
2
ai/client/client.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
2
ai/client/ollama.go
Normal file
2
ai/client/ollama.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
2
ai/detector/context.go
Normal file
2
ai/detector/context.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package detector
|
||||||
|
|
||||||
2
ai/detector/patterns.go
Normal file
2
ai/detector/patterns.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package detector
|
||||||
|
|
||||||
2
ai/detector/speaker.go
Normal file
2
ai/detector/speaker.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package detector
|
||||||
|
|
||||||
2
ai/models/config.go
Normal file
2
ai/models/config.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
2
ai/models/manager.go
Normal file
2
ai/models/manager.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
2
ai/models/registry.go
Normal file
2
ai/models/registry.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
2
ai/prompts/speaker_detection.go
Normal file
2
ai/prompts/speaker_detection.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package prompts
|
||||||
|
|
||||||
2
ai/prompts/templates.go
Normal file
2
ai/prompts/templates.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
package prompts
|
||||||
|
|
||||||
10
app.go
Normal file
10
app.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import server_config "speakeasy/config/server"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sc := server_config.CreateNewConfig()
|
||||||
|
sc.LoadConfig()
|
||||||
|
println(sc.SERVER_HOST)
|
||||||
|
println(sc.SERVER_PORT)
|
||||||
|
}
|
||||||
0
client/CLIENT.md
Normal file
0
client/CLIENT.md
Normal file
8
config/CONFIG.md
Normal file
8
config/CONFIG.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# CONFIG
|
||||||
|
|
||||||
|
- **server** `Server Configuration`
|
||||||
|
- config.go
|
||||||
|
- env.go
|
||||||
|
- **frontend** `Client Configuration`
|
||||||
|
- config.go
|
||||||
|
- env.go
|
||||||
1
config/frontend/config.go
Normal file
1
config/frontend/config.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package frontend
|
||||||
1
config/frontend/env.go
Normal file
1
config/frontend/env.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package frontend
|
||||||
62
config/server/config.go
Normal file
62
config/server/config.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "log"
|
||||||
|
"speakeasy/utils/env"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
VERSION = "dev"
|
||||||
|
BUILD_TIME = time.Now()
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServerConfig is a configuration model for the backend
|
||||||
|
type ServerConfig struct {
|
||||||
|
PG_HOST string
|
||||||
|
PG_USER string
|
||||||
|
PG_PASSWORD string
|
||||||
|
RABBITMQ_HOST string
|
||||||
|
RABBITMQ_USER string
|
||||||
|
RABBITMQ_PASSWORD string
|
||||||
|
OLLAMA_HOST string
|
||||||
|
OLLAMA_MODEL_ACCURACY string
|
||||||
|
SERVER_HOST string
|
||||||
|
SERVER_PORT int
|
||||||
|
CLIENT_HOST string
|
||||||
|
CLIENT_PORT int
|
||||||
|
VERSION string
|
||||||
|
BUILD_TIME time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelAccuracy is a configuration option for the Ollama Model Manager
|
||||||
|
type ModelAccuracy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FAST ModelAccuracy = "FAST" // gemma:2b
|
||||||
|
BALANCED ModelAccuracy = "BALANCED" // phi3:mini
|
||||||
|
ACCURATE ModelAccuracy = "ACCURATE" // llama3.1:8b
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateNewConfig returns an empty server config
|
||||||
|
func CreateNewConfig() ServerConfig {
|
||||||
|
return ServerConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadConfig loads config from environment variables
|
||||||
|
func (c *ServerConfig) LoadConfig() {
|
||||||
|
c.PG_HOST = env.GetString("PG_HOST", "localhost:8888")
|
||||||
|
c.PG_USER = env.GetString("PG_USER", "speakeasy")
|
||||||
|
c.PG_PASSWORD = env.GetString("PG_PASSWORD", "speakeasy")
|
||||||
|
c.RABBITMQ_HOST = env.GetString("RABBITMQ_HOST", "localhost:5672")
|
||||||
|
c.RABBITMQ_PASSWORD = env.GetString("RABBITMQ_PASSWORD", "speakeasy")
|
||||||
|
c.RABBITMQ_USER = env.GetString("RABBITMQ_USER", "speakeasy")
|
||||||
|
c.OLLAMA_HOST = env.GetString("OLLAMA_HOST", "localhost:11434")
|
||||||
|
c.OLLAMA_MODEL_ACCURACY = env.GetString("OLLAMA_MODEL_ACCURACY", "BALANCED")
|
||||||
|
c.SERVER_HOST = env.GetString("SERVER_HOST", "localhost")
|
||||||
|
c.SERVER_PORT = env.GetInt("SERVER_PORT", 3456)
|
||||||
|
c.CLIENT_HOST = env.GetString("CLIENT_HOST", "localhost")
|
||||||
|
c.CLIENT_PORT = env.GetInt("CLIENT_PORT", 3457)
|
||||||
|
c.VERSION = VERSION
|
||||||
|
c.BUILD_TIME = BUILD_TIME
|
||||||
|
}
|
||||||
1
config/server/env.go
Normal file
1
config/server/env.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package server
|
||||||
54
docker-compose.yml
Normal file
54
docker-compose.yml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
services:
|
||||||
|
# Postgres with pgvector extension
|
||||||
|
db:
|
||||||
|
container_name: speakeasy_db
|
||||||
|
image: pgvector/pgvector:pg18
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: speakeasy
|
||||||
|
POSTGRES_PASSWORD: speakeasy
|
||||||
|
POSTGRES_DB: speakeasy
|
||||||
|
ports:
|
||||||
|
- "8888:5432"
|
||||||
|
volumes:
|
||||||
|
- pg_data:/var/lib/postgres
|
||||||
|
- ./init:/docker-entrypoint-initdb.d
|
||||||
|
networks:
|
||||||
|
- speakeasy_network
|
||||||
|
|
||||||
|
# RabbitMQ server
|
||||||
|
rabbitmq:
|
||||||
|
container_name: speakeasy_rabbitmq
|
||||||
|
image: rabbitmq:4.2.2-management-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5672:5672" # Default port
|
||||||
|
- "15672:15672" # Management port
|
||||||
|
environment:
|
||||||
|
RABBITMQ_DEFAULT_USER: speakeasy
|
||||||
|
RABBITMQ_DEFAULT_PASS: speakeasy
|
||||||
|
volumes:
|
||||||
|
- rabbitmq_data:/var/lib/rabbitmq
|
||||||
|
networks:
|
||||||
|
- speakeasy_network
|
||||||
|
|
||||||
|
# Ollama server
|
||||||
|
ollama:
|
||||||
|
container_name: speakeasy_ollama
|
||||||
|
image: ollama/ollama:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "11434:11434"
|
||||||
|
networks:
|
||||||
|
- speakeasy_network
|
||||||
|
volumes:
|
||||||
|
- ollama_data:/root/.ollama
|
||||||
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pg_data:
|
||||||
|
rabbitmq_data:
|
||||||
|
ollama_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
speakeasy_network:
|
||||||
1
init/init_pgvector.sql
Normal file
1
init/init_pgvector.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
9
models/MODELS.md
Normal file
9
models/MODELS.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# MODELS
|
||||||
|
|
||||||
|
## FILES
|
||||||
|
- **book** `Interfaces for Elements of the Book`
|
||||||
|
- model.go `Structs`
|
||||||
|
- functions.go `Helper Functions`
|
||||||
|
- **citations** `Interfaces for Interacting With Citations`
|
||||||
|
- model.go `Structs`
|
||||||
|
- functions.go `Helper Functions`
|
||||||
8
models/book/functions.go
Normal file
8
models/book/functions.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package book
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// String helper method to convert dialogue struct into a string
|
||||||
|
func (d *Dialogue) String() string {
|
||||||
|
return fmt.Sprintf("%s", d.Content)
|
||||||
|
}
|
||||||
43
models/book/model.go
Normal file
43
models/book/model.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package book
|
||||||
|
|
||||||
|
// Book is a model for storing chapters, author, title, and total pages
|
||||||
|
type Book struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Chapters []Chapter `json:"chapters"`
|
||||||
|
TotalPages int `json:"total_pages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chapter is a model that holds chaper number and pages within that chapter
|
||||||
|
type Chapter struct {
|
||||||
|
Index int `json:"index"` // Chapter number
|
||||||
|
Pages []Page `json:"pages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page is model that stores page number and paragraphs
|
||||||
|
type Page struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
Paragraphs []Paragraph `json:"paragraphs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paragraph is a model that stores paragraph number and lines
|
||||||
|
type Paragraph struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
Lines []Line `json:"lines"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line is an interface for storing the content of a line
|
||||||
|
type Line struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
Content any `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dialogue is a model that stores the speaker, and text
|
||||||
|
type Dialogue struct {
|
||||||
|
Speaker *string `json:"speaker,omitempty"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Narration is a model that stores text that isnt dialogue
|
||||||
|
type Narration struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
|
||||||
13
models/citations/functions.go
Normal file
13
models/citations/functions.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package citations
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Method to return a MLA citation as a string
|
||||||
|
func (c *MLACitation) String() string {
|
||||||
|
return fmt.Sprintf(`"%s" (%s, %d)`, c.Content, c.LastName, c.PageNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to return a APA citation as a string
|
||||||
|
func (c *APACitation) String() string {
|
||||||
|
return fmt.Sprintf(`"%s" (%s, %d, p. %d)`, c.Content, c.LastName, c.Year, c.PageNumber)
|
||||||
|
}
|
||||||
17
models/citations/model.go
Normal file
17
models/citations/model.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package citations
|
||||||
|
|
||||||
|
// MLACitation is a model for creating an inline citation in the MLA format: (Doe 23)
|
||||||
|
type MLACitation struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
PageNumber int `json:"page_number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APACitation is a model for creating an inline citation in the APA format: (Doe, 2020, p. 23)
|
||||||
|
type APACitation struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
Year int `json:"year"`
|
||||||
|
PageNumber int `json:"page_number"`
|
||||||
|
}
|
||||||
|
|
||||||
0
parser/PARSER.md
Normal file
0
parser/PARSER.md
Normal file
0
rabbitmq/RABBITMQ.md
Normal file
0
rabbitmq/RABBITMQ.md
Normal file
0
rag/RAG.md
Normal file
0
rag/RAG.md
Normal file
1
utils/UTILS.md
Normal file
1
utils/UTILS.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
41
utils/env/loader.go
vendored
Normal file
41
utils/env/loader.go
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package env
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetStringOrNull retrieves a string environment variable or returns the default value if not set
|
||||||
|
func GetString(name string, defaultValue string) string {
|
||||||
|
value := os.Getenv(name)
|
||||||
|
if value == "" {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIntOrNull retrieves an int environment variable or returns the default value if not set
|
||||||
|
func GetInt(name string, defaultValue int) int {
|
||||||
|
value := os.Getenv(name)
|
||||||
|
if value == "" {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
intValue, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return intValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBoolOrNull retrieves a bool environment variable or returns the default value if not set
|
||||||
|
func GetBool(name string, defaultValue bool) bool {
|
||||||
|
value := os.Getenv(name)
|
||||||
|
if value == "" {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
boolValue, err := strconv.ParseBool(value)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return boolValue
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user