Adding terminal messenger
This is a golang based application that connects to the basic messenger
This commit is contained in:
parent
97ac50cb0a
commit
fc9b17bcec
166
terminal-messenger/application/README.md
Normal file
166
terminal-messenger/application/README.md
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
# Terminal Messenger
|
||||||
|
|
||||||
|
A simple, colorful terminal-based messenger application written in Go that connects to a remote messaging endpoint.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- 🎨 **Colorized output** - Blue for your input, green for assistant responses
|
||||||
|
- ⌨️ **Input history** - Navigate previous messages with arrow keys
|
||||||
|
- 💬 **Conversation context** - Maintains conversation continuity across messages
|
||||||
|
- 🚀 **Simple and fast** - Minimal setup, quick startup
|
||||||
|
- 📝 **Line editing** - Full cursor movement and text editing support
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Go 1.16 or higher
|
||||||
|
- Internet connection
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. **Clone or download the project**
|
||||||
|
|
||||||
|
2. **Initialize Go module**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go mod init messenger
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Install dependencies**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/chzyer/readline
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Build the application (optional)**
|
||||||
|
```bash
|
||||||
|
go build -o messenger main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Running the application
|
||||||
|
|
||||||
|
**Using go run:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go run main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
**Or if you built the binary:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./messenger
|
||||||
|
```
|
||||||
|
|
||||||
|
### Getting started
|
||||||
|
|
||||||
|
1. When prompted, enter a model name (or press Enter for "default")
|
||||||
|
2. Start typing your messages
|
||||||
|
3. The assistant will respond to each message
|
||||||
|
4. Use arrow keys to navigate through your input history
|
||||||
|
5. Type `quit` or `exit` to end the session
|
||||||
|
|
||||||
|
### Keyboard shortcuts
|
||||||
|
|
||||||
|
- **↑ (Up arrow)** - Navigate to previous input
|
||||||
|
- **↓ (Down arrow)** - Navigate to next input
|
||||||
|
- **←/→ (Left/Right arrows)** - Move cursor within current input
|
||||||
|
- **Ctrl+A** - Jump to beginning of line
|
||||||
|
- **Ctrl+E** - Jump to end of line
|
||||||
|
- **Ctrl+C** - Interrupt/exit application
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The application connects to:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://router.ivastudio.verint.live/ProxyScript/run/67bca862210071627d32ef12/current/basic_messenger
|
||||||
|
```
|
||||||
|
|
||||||
|
To change the endpoint, modify the `apiURL` constant in `main.go`.
|
||||||
|
|
||||||
|
### Request format
|
||||||
|
|
||||||
|
The application sends POST requests with the following JSON structure:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"input": "your message here",
|
||||||
|
"model": "model name",
|
||||||
|
"previous_response_id": "previous response ID for context",
|
||||||
|
"metadata": {
|
||||||
|
"channel": "text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response format
|
||||||
|
|
||||||
|
Expected response structure:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "response-id",
|
||||||
|
"object": "response",
|
||||||
|
"created_at": 1234567890,
|
||||||
|
"status": "completed",
|
||||||
|
"model": "Model Name",
|
||||||
|
"output": [
|
||||||
|
{
|
||||||
|
"type": "message",
|
||||||
|
"id": "message-id",
|
||||||
|
"role": "assistant",
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "output_text",
|
||||||
|
"text": "Assistant response here",
|
||||||
|
"annotations": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── main.go # Main application file
|
||||||
|
├── go.mod # Go module file
|
||||||
|
└── README.md # This file
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Connection errors
|
||||||
|
|
||||||
|
If you encounter connection errors, check:
|
||||||
|
|
||||||
|
- Your internet connection
|
||||||
|
- The endpoint URL is accessible
|
||||||
|
- Firewall settings aren't blocking the connection
|
||||||
|
|
||||||
|
### Module errors
|
||||||
|
|
||||||
|
If you get "module not found" errors:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go mod tidy
|
||||||
|
```
|
||||||
|
|
||||||
|
### History file permissions
|
||||||
|
|
||||||
|
The app creates a history file at `/tmp/messenger_history.tmp`. If you encounter permission errors, ensure you have write access to `/tmp/`.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- [github.com/chzyer/readline](https://github.com/chzyer/readline) - For input history and line editing
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is provided as-is for educational and development purposes.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Feel free to submit issues, fork the repository, and create pull requests for any improvements.
|
||||||
8
terminal-messenger/application/go.mod
Normal file
8
terminal-messenger/application/go.mod
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module messenger
|
||||||
|
|
||||||
|
go 1.24.6
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/chzyer/readline v1.5.1 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
|
||||||
|
)
|
||||||
6
terminal-messenger/application/go.sum
Normal file
6
terminal-messenger/application/go.sum
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||||
|
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||||
|
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||||
|
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||||
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
|
||||||
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
196
terminal-messenger/application/main.go
Normal file
196
terminal-messenger/application/main.go
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/chzyer/readline"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
apiURL = "https://router.ivastudio.verint.live/ProxyScript/run/67bca862210071627d32ef12/current/basic_messenger"
|
||||||
|
colorReset = "\033[0m"
|
||||||
|
colorBlue = "\033[34m"
|
||||||
|
colorGreen = "\033[32m"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Channel string `json:"channel"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
Input string `json:"input"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
PreviousResponseID string `json:"previous_response_id,omitempty"`
|
||||||
|
Metadata Metadata `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContentItem struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
Annotations []string `json:"annotations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutputMessage struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content []ContentItem `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Output []OutputMessage `json:"output"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Messenger struct {
|
||||||
|
client *http.Client
|
||||||
|
model string
|
||||||
|
previousResponseID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMessenger(model string) *Messenger {
|
||||||
|
return &Messenger{
|
||||||
|
client: &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
},
|
||||||
|
model: model,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) sendRequest(input string) (*Response, error) {
|
||||||
|
msg := Message{
|
||||||
|
Input: input,
|
||||||
|
Model: m.model,
|
||||||
|
PreviousResponseID: m.previousResponseID,
|
||||||
|
Metadata: Metadata{
|
||||||
|
Channel: "text",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal JSON: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := m.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var response Response
|
||||||
|
if err := json.Unmarshal(body, &response); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update previous response ID for conversation continuity
|
||||||
|
if response.ID != "" {
|
||||||
|
m.previousResponseID = response.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) SendMessage(text string) (string, error) {
|
||||||
|
resp, err := m.sendRequest(text)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Status != "completed" {
|
||||||
|
return "", fmt.Errorf("response status: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract text from the response output
|
||||||
|
if len(resp.Output) > 0 && len(resp.Output[0].Content) > 0 {
|
||||||
|
return resp.Output[0].Content[0].Text, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("no output received")
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHeader() {
|
||||||
|
fmt.Println("=== Terminal Messenger ===")
|
||||||
|
fmt.Println("Type your message (or 'quit' to exit)")
|
||||||
|
fmt.Println("Use ↑/↓ arrows to navigate history")
|
||||||
|
fmt.Println("==========================")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Get model
|
||||||
|
fmt.Print("Enter model name (default: 'default'): ")
|
||||||
|
var model string
|
||||||
|
fmt.Scanln(&model)
|
||||||
|
|
||||||
|
if model == "" {
|
||||||
|
model = "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
messenger := NewMessenger(model)
|
||||||
|
|
||||||
|
printHeader()
|
||||||
|
|
||||||
|
// Setup readline for input history and line editing
|
||||||
|
rl, err := readline.NewEx(&readline.Config{
|
||||||
|
Prompt: colorBlue + "You: " + colorReset,
|
||||||
|
HistoryFile: "/tmp/messenger_history.tmp",
|
||||||
|
InterruptPrompt: "^C",
|
||||||
|
EOFPrompt: "exit",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error setting up readline: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rl.Close()
|
||||||
|
|
||||||
|
// Main message loop
|
||||||
|
for {
|
||||||
|
input, err := rl.Readline()
|
||||||
|
if err != nil { // io.EOF or readline.ErrInterrupt
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
|
||||||
|
if input == "quit" || input == "exit" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if input == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := messenger.SendMessage(input)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(colorGreen+"Assistant: %s"+colorReset+"\n\n", response)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\nGoodbye!")
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user