# PocketGroq

PocketGroq provides a simpler interface to interact with the Groq API, aiding in rapid development by abstracting complex API calls into simple functions. It now includes a powerful WebTool for web searches and content retrieval, enhancing its capabilities for information gathering and processing. The latest version also introduces Chain of Thought (CoT) reasoning capabilities, making it even more versatile for complex problem-solving tasks.

![PocketGroq Logo](https://github.com/user-attachments/assets/d06b6aaf-400e-40db-bdaf-626aaa1040ef)

## New Features

### Chain of Thought (CoT) Reasoning

PocketGroq now supports Chain of Thought reasoning, allowing for more complex problem-solving and step-by-step analysis. The new CoT features include:

- `solve_problem_with_cot(problem: str)`: Solves a complex problem using Chain of Thought reasoning.
- `generate_cot(problem: str)`: Generates intermediate reasoning steps for a given problem.
- `synthesize_cot(cot_steps: List[str])`: Synthesizes a final answer from Chain of Thought steps.

### Enhanced Test Suite

The test suite has been expanded and now includes a menu-driven interface for selective test execution. New tests have been added for the Chain of Thought functionality.

## Installation and Upgrading

### Installing PocketGroq

#### Option 1: Install from PyPI (Recommended)

The easiest way to install PocketGroq is directly from PyPI using pip:

```bash
pip install pocketgroq
```

This will install the latest stable version of PocketGroq and its dependencies.

#### Option 2: Install from Source

If you want to use the latest development version or contribute to PocketGroq, you can install it from the source:

1. Clone the repository:

```bash
git clone https://github.com/jgravelle/pocketgroq.git
cd pocketgroq
```

2. Install the package and its dependencies:

```bash
pip install -e .
```

This will install PocketGroq in editable mode, allowing you to make changes to the source code and immediately see the effects.

### Upgrading PocketGroq

To upgrade an existing installation of PocketGroq to the latest version, use the following command:

```bash
pip install --upgrade pocketgroq
```

This will fetch and install the most recent version of PocketGroq from PyPI, along with any updated dependencies.

To upgrade to a specific version, you can specify the version number:

```bash
pip install --upgrade pocketgroq==0.3.0
```

After upgrading, it's a good idea to verify the installed version:

```bash
pip show pocketgroq
```

This will display information about the installed PocketGroq package, including its version number.

## Basic Usage

### Initializing GroqProvider and WebTool

```python
from pocketgroq import GroqProvider
from pocketgroq.web_tool import WebTool

# Initialize the GroqProvider
groq = GroqProvider()

# Initialize the WebTool
web_tool = WebTool(num_results=5, max_tokens=4096)
```

### Performing Web Searches

```python
query = "Latest developments in AI"
search_results = web_tool.search(query)

for result in search_results:
    print(f"Title: {result['title']}")
    print(f"URL: {result['url']}")
    print(f"Description: {result['description']}")
    print("---")
```

### Retrieving Web Content

```python
url = "https://example.com/article"
content = web_tool.get_web_content(url)
print(content[:500])  # Print first 500 characters
```

### Combining Web Search with Language Model

```python
query = "Explain the latest breakthroughs in quantum computing"
search_results = web_tool.search(query)

# Prepare context from search results
context = "\n".join([f"{r['title']}: {r['description']}" for r in search_results])

# Generate response using the context
prompt = f"Based on the following information:\n\n{context}\n\nProvide a concise summary of the latest breakthroughs in quantum computing."
response = groq.generate(prompt, max_tokens=4096, model="llama3-70b-8192", temperature=0.0)
print(response)
```

### Performing Basic Chat Completion

```python
response = groq.generate(
    prompt="Explain the importance of fast language models",
    model="llama3-8b-8192",
    temperature=0.5,
    max_tokens=1024,
    top_p=1,
    stop=None,
    stream=False
)
print(response)
```

### Streaming a Chat Completion

```python
stream = groq.generate(
    prompt="Explain the importance of fast language models",
    model="llama3-8b-8192",
    temperature=0.5,
    max_tokens=1024,
    top_p=1,
    stop=None,
    stream=True
)

for chunk in stream:
    print(chunk, end="")
```

### Overriding the Default Model

```python
selected_model = 'llama3-groq-8b-8192-tool-use-preview'
response = groq.generate("Explain quantum computing", model=selected_model)
print("Response with Selected Model:", response)
```

### Performing a Chat Completion with a Stop Sequence

```python
response = groq.generate(
    prompt="Count to 10. Your response must begin with \"1, \". Example: 1, 2, 3, ...",
    model="llama3-8b-8192",
    temperature=0.5,
    max_tokens=1024,
    top_p=1,
    stop=", 6",
    stream=False
)
print(response)
```

### Asynchronous Generation

```python
import asyncio

async def main():
    response = await groq.generate(
        prompt="Explain the theory of relativity",
        model="llama3-8b-8192",
        temperature=0.5,
        max_tokens=1024,
        top_p=1,
        stop=None,
        async_mode=True
    )
    print(response)

asyncio.run(main())
```

### Streaming an Async Chat Completion

```python
import asyncio

async def main():
    stream = await groq.generate(
        prompt="Explain the importance of fast language models",
        model="llama3-8b-8192",
        temperature=0.5,
        max_tokens=1024,
        top_p=1,
        stop=None,
        stream=True,
        async_mode=True
    )

    async for chunk in stream:
        print(chunk, end="")

asyncio.run(main())
```

### JSON Mode

```python
from typing import List, Optional
from pydantic import BaseModel
from pocketgroq import GroqProvider

class Ingredient(BaseModel):
    name: str
    quantity: str
    quantity_unit: Optional[str]

class Recipe(BaseModel):
    recipe_name: str
    ingredients: List[Ingredient]
    directions: List[str]

def get_recipe(recipe_name: str) -> Recipe:
    response = groq.generate(
        prompt=f"Fetch a recipe for {recipe_name}",
        model="llama3-8b-8192",
        temperature=0,
        stream=False,
        json_mode=True
    )
    return Recipe.parse_raw(response)

def print_recipe(recipe: Recipe):
    print("Recipe:", recipe.recipe_name)
    print("\nIngredients:")
    for ingredient in recipe.ingredients:
        print(f"- {ingredient.name}: {ingredient.quantity} {ingredient.quantity_unit or ''}")
    print("\nDirections:")
    for step, direction in enumerate(recipe.directions, start=1):
        print(f"{step}. {direction}")

recipe = get_recipe("apple pie")
print_recipe(recipe)
```

### Tool Usage

PocketGroq allows you to define tools (functions) that the model can use during the conversation:

```python
def reverse_string(input_string: str) -> dict:
    return {"reversed_string": input_string[::-1]}

tools = [
    {
        "type": "function",
        "function": {
            "name": "reverse_string",
            "description": "Reverse the given string",
            "parameters": {
                "type": "object",
                "properties": {
                    "input_string": {
                        "type": "string",
                        "description": "The string to be reversed",
                    }
                },
                "required": ["input_string"],
            },
            "implementation": reverse_string
        }
    }
]

response = groq.generate("Please reverse the string 'hello world'", tools=tools)
print("Response:", response)
```

### Vision (llava-v1.5-7b-4096-preview model only)

```python
from pocketgroq import GroqProvider
import base64

def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode('utf-8')

groq = GroqProvider()

# Via URL
response_url = groq.generate(
    prompt="What's in this image?",
    model="llava-v1.5-7b-4096-preview",
    image_url="https://example.com/image.png"
)
print(response_url)

# Via passed-in image
image_path = "path_to_your_image.jpg"
base64_image = encode_image(image_path)

response_base64 = groq.generate(
    prompt="What's in this image?",
    model="llava-v1.5-7b-4096-preview",
    image_url=f"data:image/jpeg;base64,{base64_image}"
)
print(response_base64)
```

## Chain of Thought Usage

```python
from pocketgroq import GroqProvider

groq = GroqProvider()

# Solve a complex problem using Chain of Thought
problem = """
A farmer has a rectangular field that is 100 meters long and 50 meters wide. 
He wants to increase the area of the field by 20% by increasing both the length and the width by the same percentage. 
What should be the new length and width of the field? 
Round your answer to the nearest centimeter.
"""
answer = groq.solve_problem_with_cot(problem)
print("Answer:", answer)

# Generate Chain of Thought steps
problem = "What is the sum of the first 10 prime numbers?"
cot_steps = groq.generate_cot(problem)
print("Chain of Thought Steps:")
for i, step in enumerate(cot_steps, 1):
    print(f"{i}. {step}")

# Synthesize an answer from Chain of Thought steps
cot_steps = [
    "The first 10 prime numbers are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29",
    "To find the sum, we add these numbers: 2 + 3 + 5 + 7 + 11 + 13 + 17 + 19 + 23 + 29",
    "Calculating the sum: 129"
]
final_answer = groq.synthesize_cot(cot_steps)
print("Synthesized Answer:", final_answer)
```

## WebTool Functionality

The WebTool provides two main functions:

1. `search(query: str, num_results: int = 10) -> List[Dict[str, Any]]`: Performs a web search and returns a list of search results.
2. `get_web_content(url: str) -> str`: Retrieves the content of a web page.

### Example: Advanced Web Search and Content Analysis

```python
from pocketgroq import GroqProvider
from pocketgroq.web_tool import WebTool

groq = GroqProvider()
web_tool = WebTool()

# Perform a web search
query = "Recent advancements in renewable energy"
search_results = web_tool.search(query, num_results=3)

# Analyze each search result
for result in search_results:
    print(f"Analyzing: {result['title']}")
    content = web_tool.get_web_content(result['url'])
    
    analysis_prompt = f"Analyze the following content about renewable energy and provide key insights:\n\n{content[:4000]}"
    analysis = groq.generate(analysis_prompt, max_tokens=1000)
    
    print(f"Analysis: {analysis}")
    print("---")
```

This example demonstrates how to use the WebTool to perform a search, retrieve content from each search result, and then use the GroqProvider to analyze the content.

## Use Case Scenarios

1. **Content Generation**: Use PocketGroq for automated blog post writing, social media content creation, or product descriptions.

```python
blog_topic = "The Future of Artificial Intelligence"
blog_post = groq.generate(f"Write a 500-word blog post about {blog_topic}")
print(blog_post)
```

2. **Code Assistant**: Leverage PocketGroq for code explanation, debugging, or generation.

```python
code_snippet = """
def quicksort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksort(left) + middle + quicksort(right)
"""
explanation = groq.generate(f"Explain this Python code and suggest any improvements:\n\n{code_snippet}")
print(explanation)
```

3. **Data Analysis**: Use PocketGroq to interpret data or generate data analysis reports.

```python
data = {
    "sales": [100, 150, 200, 180, 220],
    "expenses": [80, 90, 110, 100, 130]
}
analysis = groq.generate(f"Analyze this sales and expenses data and provide insights:\n\n{data}", json_mode=True)
print(analysis)
```

4. **Image Analysis**: Utilize PocketGroq's image handling capabilities for various visual tasks.

```python
image_url = "https://example.com/chart.jpg"
chart_analysis = groq.generate("Analyze this chart image and provide key insights", image_path=image_url)
print(chart_analysis)
```

5. **Automated Customer Support**: Implement PocketGroq in a chatbot for handling customer inquiries.

```python
user_query = "How do I reset my password?"
response = groq.generate(f"Provide a step-by-step guide to answer this customer query: {user_query}")
print(response)
```

6. **Web Research Assistant**: Utilize PocketGroq's WebTool for automated web research and summarization.

```python
from pocketgroq import GroqProvider
from pocketgroq.web_tool import WebTool

groq = GroqProvider()
web_tool = WebTool()

research_topic = "Impact of artificial intelligence on job markets"
search_results = web_tool.search(research_topic, num_results=5)

research_summary = groq.generate(
    f"Based on the following search results about '{research_topic}', provide a comprehensive summary:\n\n" +
    "\n".join([f"- {r['title']}: {r['description']}" for r in search_results])
)

print(research_summary)
```

7. **Complex Problem Solving**: Utilize PocketGroq's Chain of Thought capabilities for solving intricate problems.

```python
from pocketgroq import GroqProvider

groq = GroqProvider()

complex_problem = """In a small town, 60% of the adults work in manufacturing, 25% work in services, and the rest are unemployed. 
If the town has 10,000 adults and the local government wants to reduce unemployment by half by creating new 
manufacturing jobs, how many new jobs need to be created?
"""

solution = groq.solve_problem_with_cot(complex_problem)
print(solution)
```

## Testing

PocketGroq now includes a comprehensive test suite with a menu-driven interface for selective test execution. To run the tests:

1. Navigate to the PocketGroq directory.
2. Run the test script:

```bash
python test.py
```

3. You will see a menu with options to run individual tests or all tests at once:

```
PocketGroq Test Menu:
1. Basic Chat Completion
2. Streaming Chat Completion
3. Override Default Model
4. Chat Completion with Stop Sequence
5. Asynchronous Generation
6. Streaming Async Chat Completion
7. JSON Mode
8. Tool Usage
9. Vision
10. Chain of Thought Problem Solving
11. Chain of Thought Step Generation
12. Chain of Thought Synthesis
13. Run All Tests
0. Exit
```

4. Select the desired option by entering the corresponding number.

The test suite covers:

- Basic chat completion
- Streaming chat completion
- Model override
- Chat completion with stop sequence
- Asynchronous generation
- Streaming asynchronous chat completion
- JSON mode
- Tool usage
- Vision capabilities
- Chain of Thought problem solving
- Chain of Thought step generation
- Chain of Thought synthesis

Each test demonstrates a specific feature of PocketGroq and checks if the output meets the expected criteria. Running these tests helps ensure that all functionalities are working correctly after updates or modifications to the codebase.

## Configuration

PocketGroq uses environment variables for configuration. Set `GROQ_API_KEY` in your environment or in a `.env` file in your project root. This API key is essential for authenticating with the Groq API.

Example of setting the API key in a `.env` file:

```
GROQ_API_KEY=your_api_key_here
```

Make sure to keep your API key confidential and never commit it to version control.

## Error Handling

PocketGroq raises custom exceptions to help you handle errors more effectively:

- `GroqAPIKeyMissingError`: Raised when the Groq API key is missing.
- `GroqAPIError`: Raised when there's an error with the Groq API.

Handle these exceptions in your code for robust error management. For example:

```python
from pocketgroq import GroqProvider, GroqAPIKeyMissingError, GroqAPIError

try:
    groq = GroqProvider()
    response = groq.generate("Hello, world!")
except GroqAPIKeyMissingError:
    print("Please set your GROQ_API_KEY environment variable.")
except GroqAPIError as e:
    print(f"An error occurred while calling the Groq API: {e}")
```

## Contributing

Contributions to PocketGroq are welcome! If you encounter any problems, have feature suggestions, or want to improve the codebase, feel free to:

1. Open issues on the [GitHub repository](https://github.com/jgravelle/pocketgroq).
2. Submit pull requests with bug fixes or new features.
3. Improve documentation or add examples.

When contributing, please:

- Follow the existing code style and conventions.
- Write clear commit messages.
- Add or update tests for new features or bug fixes.
- Update the README if you're adding new functionality.

## License

This project is licensed under the MIT License. When using PocketGroq in your projects, please include a mention of J. Gravelle in your code and/or documentation. He's kinda full of himself, but he'd appreciate the acknowledgment.

![J. Gravelle](https://github.com/user-attachments/assets/73c812cd-685e-4969-9497-639ae9312d6c)

---

Thank you for using PocketGroq! We hope this tool enhances your development process and enables you to create amazing AI-powered applications with ease. If you have any questions or need further assistance, don't hesitate to reach out to the community or check the documentation. Happy coding!