# Pylogue - Full DI Chat Framework


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## 🚀 Quick Start

### Minimal Example (5 lines)

``` python
from pylogue.chatapp import create_default_chat_app

async def my_responder(msg: str, context=None) -> str:
    return f"You said: {msg}"

app = create_default_chat_app(responder=my_responder)
app.run(port=5001)
```

### Custom Styling

``` python
from pylogue.card import ChatCard
from pylogue.chatapp import create_default_chat_app, ChatAppConfig

card = ChatCard(
    user_color="#1a3a1a",
    assistant_color="#1a1a3a",
    user_emoji="👤",
    assistant_emoji="🤖"
)

config = ChatAppConfig(
    app_title="My Assistant",
    bg_color="#0a0a0a"
)

app = create_default_chat_app(
    responder=my_responder,
    card=card,
    config=config
)
```

## 🎨 Full DI Example

Complete control with dependency injection:

``` python
from pylogue.chatapp import ChatApp, ChatAppConfig
from pylogue.session import InMemorySessionManager
from pylogue.service import ChatService
from pylogue.renderer import ChatRenderer
from pylogue.card import ChatCard

# 1. Configure components
session_manager = InMemorySessionManager()

chat_service = ChatService(
    responder=my_responder,
    context_provider=lambda s: s.get_messages()
)

renderer = ChatRenderer(
    card=ChatCard(user_color="#2a2a2a")
)

config = ChatAppConfig(
    app_title="Custom App"
)

# 2. Compose application
app = ChatApp(
    session_manager=session_manager,
    chat_service=chat_service,
    renderer=renderer,
    config=config
)

# 3. Run
app.run(port=5001)
```

## 🔌 Extensibility

### Custom Session Storage

``` python
from pylogue.session import SessionManager

class RedisSessionManager(SessionManager):
    def __init__(self, redis_client):
        self.redis = redis_client
    
    def create_session(self, session_id, initial_messages):
        # Store in Redis
        pass
    
    def get_session(self, session_id):
        # Retrieve from Redis
        pass
```

### Custom Responder (AI/LLM)

``` python
class OpenAIResponder:
    def __init__(self, api_key, model="gpt-4"):
        self.client = OpenAI(api_key=api_key)
        self.model = model
    
    async def __call__(self, message: str, context=None) -> str:
        # Call OpenAI API
        response = await self.client.chat.completions.create(
            model=self.model,
            messages=[{"role": "user", "content": message}]
        )
        return response.choices[0].message.content
```

### Custom Error Handler

``` python
class SlackErrorHandler:
    def __init__(self, slack_webhook):
        self.webhook = slack_webhook
    
    def __call__(self, error: Exception, message: str) -> str:
        # Send to Slack
        requests.post(self.webhook, json={"text": f"Error: {error}"})
        return "An error occurred. Team has been notified."
```

## 🧪 Testing

Each component is independently testable:

``` python
# Test session management
from pylogue.session import ChatSession

session = ChatSession("test-id")
session.add_message("User", "Hello")
assert len(session) == 1

# Test service
from pylogue.service import ChatService

service = ChatService(responder=my_responder)
response = await service.process_message("Test")
assert "Test" in response

# Test renderer
from pylogue.renderer import ChatRenderer
from pylogue.session import Message

renderer = ChatRenderer()
messages = [Message(role="User", content="Hi")]
html = renderer.render_messages(messages)
# Assert HTML structure
```

## 📚 Examples

See `6-Examples.ipynb` for complete working examples:

1.  **Echo Bot** - Simplest possible implementation
2.  **Custom Styled Chat** - UI/UX customization
3.  **Context-Aware Assistant** - Uses conversation history
4.  **Code Assistant** - Syntax highlighting support
5.  **Supply Chain RCA** - Domain-specific implementation

## 🔧 Configuration Options

### ChatAppConfig

``` python
@dataclass
class ChatAppConfig:
    app_title: str = "Chat Application"
    page_title: str = "Chat"
    bg_color: str = "#1a1a1a"
    header_style: str = "..."
    ws_endpoint: str = "/ws"
    markdown_enabled: bool = True
    syntax_highlighting: bool = True
    highlight_langs: List[str] = [...]
    spinner_css: Optional[str] = None
    initial_messages_factory: Optional[Callable] = None
```

### ChatCard

``` python
ChatCard(
    user_color: str = "#DCF8C6",
    assistant_color: str = "#E6E6E6",
    user_emoji: str = "🗣️",
    assistant_emoji: str = "🕵️‍♂️",
    width: str = "60%",
    font_size: str = "1.5em",
    padding: str = "1.25em",
    border_radius: str = "1em",
    # ... many more options
)
```

## 🎯 Design Principles

1.  **Separation of Concerns**: Each layer has a single responsibility
2.  **Dependency Injection**: All dependencies are explicit and
    injectable
3.  **Protocol-Oriented**: Components communicate via
    protocols/interfaces
4.  **Testability**: Every component can be tested in isolation
5.  **Extensibility**: Easy to swap implementations without changing
    code
6.  **Composition over Inheritance**: Build complex apps from simple
    parts

## 🔄 Migration from Old Code

If you have existing code using global functions:

**Before:**

``` python
user_messages = {}  # Global state

def render_chat_list(messages):
    # ...
    
def create_chat_app(responder):
    # Tightly coupled
```

**After:**

``` python
app = create_default_chat_app(responder=your_responder)
# All state management, rendering, and logic handled cleanly
```

## 📖 Next Steps

1.  Read through the notebooks in order:

    - `2-Session.ipynb` - Understand state management
    - `3-Service.ipynb` - Learn business logic layer
    - `4-Renderer.ipynb` - Explore presentation layer
    - `5-ChatApp.ipynb` - See full integration
    - `6-Examples.ipynb` - Working examples

2.  Try the examples in `6-Examples.ipynb`

3.  Build your own custom responder

4.  Deploy to production with your preferred hosting

## 🤝 Contributing

This is a fully modular framework. To extend:

1.  Implement the relevant Protocol
2.  Inject your implementation
3.  Test independently
4.  Compose with other components

No need to modify core code!
