docs/QUICKSTART.md

# ExLLM Quick Start Guide

Get up and running with ExLLM in 5 minutes! This guide covers installation, basic configuration, and common usage patterns.

## Installation

Add ExLLM to your `mix.exs` dependencies:

```elixir
def deps do
  [
    {:ex_llm, "~> 0.7.0"}
  ]
end
```

Then run:

```bash
mix deps.get
```

## Configuration

### Environment Variables

Set API keys for the providers you want to use:

```bash
# Core providers
export ANTHROPIC_API_KEY="sk-ant-your-key"
export OPENAI_API_KEY="sk-your-key"
export GROQ_API_KEY="gsk_your-key"

# Additional providers (optional)
export GEMINI_API_KEY="your-gemini-key"
export MISTRAL_API_KEY="your-mistral-key"
export OPENROUTER_API_KEY="sk-or-your-key"
export PERPLEXITY_API_KEY="pplx-your-key"
```

### Application Configuration (Optional)

```elixir
# config/config.exs
config :ex_llm,
  # Default provider
  default_provider: :anthropic,
  
  # Cost tracking
  cost_tracking_enabled: true,
  
  # Test caching (speeds up tests 25x)
  test_cache: [
    enabled: true,
    cache_dir: "test/cache",
    ttl: 604_800_000  # 7 days in milliseconds
  ]
```

## Basic Usage

### Simple Chat Completion

```elixir
# Start with a basic chat
{:ok, response} = ExLLM.chat(:anthropic, [
  %{role: "user", content: "What is the capital of France?"}
])

IO.puts(response.content)
# => "The capital of France is Paris."

# Access additional metadata
IO.puts("Model: #{response.model}")
IO.puts("Cost: $#{response.cost}")
IO.puts("Tokens used: #{response.usage.total_tokens}")
```

### Different Providers

```elixir
# Try different providers
{:ok, response1} = ExLLM.chat(:openai, [
  %{role: "user", content: "Explain quantum computing briefly"}
])

{:ok, response2} = ExLLM.chat(:groq, [
  %{role: "user", content: "Write a haiku about coding"}
])

{:ok, response3} = ExLLM.chat(:gemini, [
  %{role: "user", content: "What's 2+2?"}
])
```

### Streaming Responses

```elixir
# Stream responses in real-time
ExLLM.chat_stream(:openai, [
  %{role: "user", content: "Write a short story about a robot"}
], fn chunk ->
  IO.write(chunk.delta)
end)
```

### Session Management

```elixir
# Maintain conversation context
{:ok, session} = ExLLM.Session.new(:anthropic)

# First message
{:ok, session, response1} = ExLLM.Session.chat(session, "Hi, I'm learning Elixir")
IO.puts(response1.content)

# Continue the conversation
{:ok, session, response2} = ExLLM.Session.chat(session, "What are GenServers?")
IO.puts(response2.content)

# Session automatically tracks conversation history
IO.puts("Messages in session: #{length(session.messages)}")
IO.puts("Total cost: $#{session.total_cost}")
```

## Advanced Features

### Multimodal (Vision)

```elixir
# Analyze images (with Gemini or OpenAI)
image_data = File.read!("image.jpg") |> Base.encode64()

{:ok, response} = ExLLM.chat(:gemini, [
  %{role: "user", content: [
    %{type: "text", text: "What's in this image?"},
    %{type: "image", image: %{
      data: image_data,
      media_type: "image/jpeg"
    }}
  ]}
])

IO.puts(response.content)
```

### Function Calling

```elixir
# Define tools
tools = [
  %{
    type: "function",
    function: %{
      name: "get_weather",
      description: "Get current weather for a location",
      parameters: %{
        type: "object",
        properties: %{
          location: %{type: "string", description: "City name"},
          unit: %{type: "string", enum: ["celsius", "fahrenheit"]}
        },
        required: ["location"]
      }
    }
  }
]

{:ok, response} = ExLLM.chat(:openai, [
  %{role: "user", content: "What's the weather in Paris?"}
], tools: tools)

# Handle function calls
case response.function_calls do
  [%{name: "get_weather", arguments: args}] ->
    # Call your weather API here
    weather_data = get_weather(args["location"])
    
    # Continue conversation with function result
    {:ok, final_response} = ExLLM.chat(:openai, [
      %{role: "user", content: "What's the weather in Paris?"},
      response.message,
      %{role: "function", name: "get_weather", content: Jason.encode!(weather_data)}
    ])
    
  _ ->
    IO.puts(response.content)
end
```

### Model Discovery

```elixir
# List available models
{:ok, models} = ExLLM.list_models(:anthropic)

Enum.each(models, fn model ->
  IO.puts("#{model.id} - Context: #{model.context_window} tokens")
end)

# Get specific model info
{:ok, model} = ExLLM.get_model(:openai, "gpt-4o")
IO.puts("Supports streaming: #{model.capabilities.supports_streaming}")
IO.puts("Supports vision: #{model.capabilities.supports_vision}")
```

## Testing

### Fast Testing with Caching

ExLLM includes intelligent test caching for 25x faster integration tests:

```bash
# Run tests with automatic caching
mix test

# Test specific providers
mix test.anthropic
mix test.openai --include live_api

# Manage cache
mix ex_llm.cache stats
mix ex_llm.cache clean --older-than 7d
```

### Writing Tests

```elixir
defmodule MyAppTest do
  use ExUnit.Case
  
  # Tag for automatic caching
  @moduletag :live_api
  @moduletag :requires_api_key
  @moduletag provider: :anthropic
  
  test "chat completion works" do
    {:ok, response} = ExLLM.chat(:anthropic, [
      %{role: "user", content: "Say hello"}
    ])
    
    assert response.content =~ "hello"
    assert response.cost > 0
  end
end
```

## Local Models

### Ollama

```bash
# Start Ollama
ollama serve

# Pull a model
ollama pull llama3.2
```

```elixir
# Use local Ollama models
{:ok, response} = ExLLM.chat(:ollama, [
  %{role: "user", content: "Hello!"}
], model: "llama3.2")
```

### LM Studio

```bash
# Start LM Studio server on localhost:1234
```

```elixir
# Use LM Studio models
{:ok, response} = ExLLM.chat(:lmstudio, [
  %{role: "user", content: "Hello!"}
])
```

### Bumblebee (Elixir Native)

```elixir
# Add to deps for local inference
{:exla, "~> 0.7"}  # For CPU/GPU acceleration

# Use Bumblebee models
{:ok, response} = ExLLM.chat(:bumblebee, [
  %{role: "user", content: "Hello!"}
], model: "microsoft/DialoGPT-medium")
```

## Error Handling

```elixir
case ExLLM.chat(:anthropic, messages) do
  {:ok, response} ->
    IO.puts(response.content)
    
  {:error, {:api_error, %{status: 401}}} ->
    IO.puts("Invalid API key")
    
  {:error, {:api_error, %{status: 429}}} ->
    IO.puts("Rate limited - try again later")
    
  {:error, {:api_error, %{status: 400, body: body}}} ->
    IO.puts("Bad request: #{inspect(body)}")
    
  {:error, {:network_error, reason}} ->
    IO.puts("Network error: #{reason}")
    
  {:error, reason} ->
    IO.puts("Other error: #{inspect(reason)}")
end
```

## Environment-Specific Configuration

### Development

```elixir
# config/dev.exs
config :ex_llm,
  log_level: :debug,
  log_components: [:http_client, :streaming],
  test_cache: [enabled: true]
```

### Test

```elixir
# config/test.exs
config :ex_llm,
  log_level: :warn,
  test_cache: [
    enabled: true,
    cache_dir: "test/cache",
    ttl: 604_800_000  # 7 days
  ]
```

### Production

```elixir
# config/prod.exs
config :ex_llm,
  log_level: :info,
  log_redaction: true,
  cost_tracking_enabled: true
```

## Next Steps

1. **Read the [User Guide](USER_GUIDE.md)** for comprehensive documentation
2. **Check [Provider Capabilities](PROVIDER_CAPABILITIES.md)** to compare features
3. **Review [Testing Guide](TESTING.md)** for advanced testing patterns and caching

## Common Issues

### "API key not found"
```bash
# Make sure you've set the environment variable
export ANTHROPIC_API_KEY="your-key"
```

### "Model not found"
```elixir
# Check available models
{:ok, models} = ExLLM.list_models(:anthropic)
```

### "Rate limited"
```elixir
# Use different providers or implement backoff
Process.sleep(1000)
{:ok, response} = ExLLM.chat(:groq, messages)  # Try Groq for speed
```

### Tests running slowly
```bash
# Enable test caching
export EX_LLM_TEST_CACHE_ENABLED=true
mix test --include live_api
```

That's it! You're now ready to build amazing applications with ExLLM. 🚀