{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import langchain\n",
    "from langchain import PromptTemplate, LLMChain"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# huggingface"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import HuggingFacePipeline\n",
    "\n",
    "llm = HuggingFacePipeline.from_model_id(\n",
    "    model_id=\"bigscience/bloom-560m\",\n",
    "    task=\"text-generation\",\n",
    "    model_kwargs={\"temperature\": 0, \"max_length\": 64},\n",
    ")\n",
    "\n",
    "\n",
    "# Integrate the model in an LLMChain\n",
    "from langchain import PromptTemplate, LLMChain\n",
    "\n",
    "template = \"\"\"Question: {question}\n",
    "\n",
    "Answer: Let's think step by step.\"\"\"\n",
    "prompt = PromptTemplate(template=template, input_variables=[\"question\"])\n",
    "\n",
    "llm_chain = LLMChain(prompt=prompt, llm=llm)\n",
    "\n",
    "question = \"What is electroencephalography?\"\n",
    "\n",
    "print(llm_chain.run(question))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# galactica"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import galai as gal\n",
    "\n",
    "model = gal.load_model(\"standard\")\n",
    "# model.generate(\"Scaled dot product attention:\\n\\n\\\\[\")\n",
    "# Scaled dot product attention:\\n\\n\\\\[ \\\\displaystyle\\\\text{Attention}(Q,K,V)=\\\\text{softmax}(\\\\frac{QK^{T}}{\\\\sqrt{d_{k}}}%\\n)V \\\\]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.generate(\"from this list, [vodka, strawberries, corn, peas],create a new python list that ONLY includes produce <work>\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "TEXT = \"vodka, strawberries, corn, peas, cherries, sodapop\"\n",
    "model.generate( '\\n\\nQuestion: Of the items in this list, \\n\\n vodka, strawberries, corn, peas, cherries, diet coke, \\n\\n which can grow in a garden?\\n\\nAnswer:')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.generate(\"a plant compatability matrix is a a python matrix and will have a score of -1 for negative relationship between plants, 0 for neutral relationship between plants, and 1 for a positive relationship between plants. create a python array of plant compatibility between the plants listed: \" + str(plant_list))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# openai + langchain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# plant compatiblity context source: https://waldenlabs.com/the-ultimate-companion-planting-guide-chart/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "file_path = 'C:/Users/dheym/OneDrive/Documents/api_keys/openai_api_keys.txt'\n",
    "with open(file_path, 'r') as file:\n",
    "    OPENAI_API_KEY = file.read()\n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
    "#If you'd prefer not to set an environment variable you can pass the key in directly via the openai_api_key named parameter when initiating the OpenAI LLM class:\n",
    "\n",
    "\n",
    "chat = ChatOpenAI()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def parse_and_evaluate_text(text):\n",
    "    # Find the indices of the opening and closing brackets\n",
    "    opening_bracket_index = text.find(\"[\")\n",
    "    closing_bracket_index = text.find(\"]\")\n",
    "\n",
    "    if opening_bracket_index != -1 and closing_bracket_index != -1:\n",
    "        # Extract the text within the brackets\n",
    "        extracted_list = \"[\" + text[opening_bracket_index + 1: closing_bracket_index] + \"]\"\n",
    "        # Return the evaluated text list\n",
    "        return eval(extracted_list)\n",
    "        \n",
    "\n",
    "    else:\n",
    "        print(\"Error with parsing plant list\")\n",
    "        return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts.chat import (\n",
    "    ChatPromptTemplate,\n",
    "    SystemMessagePromptTemplate,\n",
    "    AIMessagePromptTemplate,\n",
    "    HumanMessagePromptTemplate,\n",
    ")\n",
    "\n",
    "\n",
    "def parse_and_evaluate_text(text):\n",
    "    # Find the indices of the opening and closing brackets\n",
    "    opening_bracket_index = text.find(\"[\")\n",
    "    closing_bracket_index = text.find(\"]\")\n",
    "\n",
    "    if opening_bracket_index != -1 and closing_bracket_index != -1:\n",
    "        # Extract the text within the brackets\n",
    "        extracted_list = \"[\" + text[opening_bracket_index + 1: closing_bracket_index] + \"]\"\n",
    "        # Return the evaluated text list\n",
    "        return eval(extracted_list)\n",
    "        \n",
    "\n",
    "    else:\n",
    "        print(\"Error with parsing plant list\")\n",
    "        return None\n",
    "    \n",
    "def chat_response(template, prompt_text):\n",
    "    system_message_prompt = SystemMessagePromptTemplate.from_template(template)\n",
    "    human_template=\"{text}\"\n",
    "    human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)\n",
    "    chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])\n",
    "    response = chat(chat_prompt.format_prompt(text= prompt_text).to_messages())\n",
    "    return response\n",
    "\n",
    "# get the plant list from user input\n",
    "def get_plant_list(input_plant_text):\n",
    "    template=\"You are a helpful assistant that knows all about gardening and plants and python data structures.\"\n",
    "    text = 'which of the elements of this list can be grown in a garden, [' + input_plant_text + ']? Return JUST a python list object containing the elements that can be grown in a garden. Do not include any other text or explanation.'\n",
    "    plant_list_text = chat_response(template, text)\n",
    "    plant_list = parse_and_evaluate_text(plant_list_text.content)\n",
    "    print(plant_list)\n",
    "    return plant_list\n",
    "\n",
    "# get compatability matrix for companion planting\n",
    "def get_compatibility_matrix(plant_list):\n",
    "    # Convert the compatibility matrix to a string\n",
    "    with open('compatibilities_text.txt', 'r') as file:\n",
    "        # Read the contents of the file\n",
    "        compatibility_text = file.read()\n",
    "    plant_comp_context = compatibility_text\n",
    "    template=\"You are a helpful assistant that knows all about gardening, companion planting, and python data structures- specifically compatibility matrices.\"\n",
    "    text = 'from this list of plants, [' + str(plant_list) + '], Return JUST a python array (with values separated by commas like this: [[0,1],[1,0]]\\n\\n ) for companion plant compatibility. Each row and column should represent plants, and the element of the array will contain a -1, 0, or 1 depending on if the relationship between plants is antagonists, neutral, or companions, respectively. You must refer to this knowledge base of information on plant compatibility: \\n\\n, ' + plant_comp_context + '\\n\\n A plant\\'s compatibility with itself is always 0. Do not include any other text or explanation.'\n",
    "    compatibility_mat = chat_response(template, text)\n",
    "    \n",
    "    # Find the indices of the opening and closing brackets\n",
    "    opening_bracket_index = compatibility_mat.content.find(\"[[\")\n",
    "    closing_bracket_index = compatibility_mat.content.find(\"]]\")\n",
    "    if opening_bracket_index != -1 and closing_bracket_index != -1:\n",
    "        # Extract the text within the brackets\n",
    "        extracted_mat = \"[\" + compatibility_mat.content[opening_bracket_index + 1: closing_bracket_index] + \"]]\"\n",
    "        # Return the evaluated mat\n",
    "        return eval(extracted_mat)\n",
    "    else:\n",
    "        print(\"Error with parsing plant compatibility matrix\")\n",
    "        return None\n",
    "    return \n",
    "\n",
    "\n",
    "input_plant_text = \"strawberries, mint, pepper, diet coke, carrots, lettuce, vodka, basil, tomatoes, marigolds, lemons, spinach, brocoli\"\n",
    "input_plant_text = \"apples, basil, bean, rue, oregano, onion\"\n",
    "plant_list = get_plant_list(input_plant_text)\n",
    "extracted_mat = get_compatibility_matrix(plant_list)\n",
    "print(extracted_mat)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## langchain additional context and fine tuning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# process the plant compatibility matrix to a json\n",
    "import csv\n",
    "import json\n",
    "\n",
    "# Open the CSV file\n",
    "with open('plant_compatability.csv', 'r') as file:\n",
    "    reader = csv.reader(file)\n",
    "    \n",
    "    # Read the header row to get the plant names\n",
    "    header = next(reader)\n",
    "    \n",
    "    # Create an empty dictionary to store the compatibility matrix\n",
    "    compatibility_matrix = {}\n",
    "    \n",
    "    # Iterate over the rows in the CSV file\n",
    "    for row in reader:\n",
    "        # Extract the plant name from the first column\n",
    "        plant = row[0]\n",
    "        \n",
    "        # Create a dictionary to store the compatibility values for the current plant\n",
    "        compatibility_values = {}\n",
    "        \n",
    "        # Iterate over the compatibility values in the row\n",
    "        for i, value in enumerate(row[1:], start=1):\n",
    "            # Extract the plant name from the header row\n",
    "            companion_plant = header[i]\n",
    "            \n",
    "            # Convert the compatibility value to an integer\n",
    "            compatibility = int(value) if value else 0\n",
    "            \n",
    "            # Add the compatibility value to the dictionary\n",
    "            compatibility_values[companion_plant] = compatibility\n",
    "        \n",
    "        # Add the compatibility values dictionary to the main compatibility matrix\n",
    "        compatibility_matrix[plant] = compatibility_values\n",
    "\n",
    "# Save the compatibility matrix as a JSON file\n",
    "with open('compatibility_matrix.json', 'w') as file:\n",
    "    json.dump(compatibility_matrix, file, indent=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openai\n",
    "\n",
    "# Load the compatibility matrix from the JSON file\n",
    "with open('compatibility_matrix.json', 'r') as file:\n",
    "    compatibility_matrix = json.load(file)\n",
    "\n",
    "# Convert the compatibility matrix to a string\n",
    "compatibility_matrix_text = json.dumps(compatibility_matrix)\n",
    "with open('compatibilities_text.txt', 'r') as file:\n",
    "    # Read the contents of the file\n",
    "    compatibility_matrix_text = file.read()\n",
    "\n",
    "# Set up the LangChain API credentials\n",
    "openai.api_key = OPENAI_API_KEY\n",
    "\n",
    "# Define the prompt for the GPT model\n",
    "prompt = \"Can you provide companion plant suggestions for my garden given what you know about companion planting?\"\n",
    "\n",
    "# Concatenate the prompt and compatibility matrix text as the input to the GPT model\n",
    "input_text = f\"{prompt}\\n\\n{compatibility_matrix_text}\"\n",
    "\n",
    "# Generate a response from the GPT model\n",
    "response = openai.Completion.create(\n",
    "    engine='text-davinci-003',\n",
    "    prompt=input_text,\n",
    "    max_tokens=575\n",
    ")\n",
    "\n",
    "print(response.choices[0])\n",
    "# Extract the generated companion plant suggestions from the response\n",
    "suggestions = response.choices[0].text.strip()\n",
    "\n",
    "# Print the companion plant suggestions\n",
    "print(suggestions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.client import Client\n",
    "\n",
    "# Load the fine-tuned GPT model\n",
    "model = OpenAI(openai_api_key=OPENAI_API_KEY)\n",
    "\n",
    "# Load the knowledge base or context from websites or documents\n",
    "knowledge_base = YourProcessedData()\n",
    "\n",
    "# Initialize the Langchain client\n",
    "client = Client()\n",
    "\n",
    "# Set the context for the GPT model\n",
    "context = \"Context from websites or documents\"\n",
    "model.set_context(context)\n",
    "\n",
    "# Get companion plant compatibility predictions\n",
    "plants = ['strawberries', 'mint', 'carrots', 'lettuce', 'basil']\n",
    "predictions = []\n",
    "\n",
    "for plant in plants:\n",
    "    # Generate a question for each plant\n",
    "    question = f\"Which plants are compatible with {plant}?\"\n",
    "    \n",
    "    # Provide the question and context to the Langchain client\n",
    "    response = client.query(question, context=context)\n",
    "    \n",
    "    # Process and extract the answer from the response\n",
    "    answer = response['answer']\n",
    "    predictions.append((plant, answer))\n",
    "\n",
    "# Process and display the compatibility predictions\n",
    "for plant, compatibility in predictions:\n",
    "    print(f\"{plant}: {compatibility}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import networkx as nx\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Define the plant list\n",
    "plants = ['strawberries', 'mint', 'carrots', 'lettuce', 'basil', 'tomatoes', 'marigolds', 'lemons', 'strawberries', 'spinach', 'broccoli']\n",
    "\n",
    "# Define the compatibility matrix\n",
    "compatibility_matrix = np.array([\n",
    "[0, 1, 0, 0, 1, -1, 1, 0, 0, 0, -1],\n",
    "[1, 0, 0, 0, 1, -1, 1, 0, 1, 0, -1],\n",
    "[0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0],\n",
    "[0, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0],\n",
    "[1, 1, 0, 0, 0, -1, 1, 0, 0, 0, -1],\n",
    "[-1, -1, 1, 1, -1, 0, -1, 0, 0, 0, 1],\n",
    "[1, 1, 0, 0, 1, -1, 0, 0, 0, 0, -1],\n",
    "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
    "[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
    "[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, -1],\n",
    "[-1, -1, 0, 0, -1, 1, -1, 0, 0, -1, 0]\n",
    "])\n",
    "\n",
    "# Create an empty graph\n",
    "G = nx.Graph()\n",
    "\n",
    "# Add nodes (plants) to the graph\n",
    "G.add_nodes_from(plants)\n",
    "\n",
    "# Add edges (compatibility) to the graph\n",
    "for i in range(len(plants)):\n",
    "    for j in range(i + 1, len(plants)):\n",
    "        if compatibility_matrix[i][j] == 0:\n",
    "            color = 'grey'\n",
    "        elif compatibility_matrix[i][j] == -1:\n",
    "            color = 'pink'\n",
    "        else:\n",
    "            color = 'green'\n",
    "        G.add_edge(plants[i], plants[j], color=color)\n",
    "\n",
    "# Plot the graph\n",
    "pos = nx.spring_layout(G)\n",
    "colors = [G[u][v]['color'] for u, v in G.edges()]\n",
    "nx.draw_networkx(G, pos, with_labels=True, node_color='lightgreen', edge_color=colors, width=2.0, alpha=0.8)\n",
    "\n",
    "# Set edge colors in the legend\n",
    "color_legend = {'Neutral': 'grey', 'Negative': 'pink', 'Positive': 'green'}\n",
    "legend_lines = [plt.Line2D([0], [0], color=color, linewidth=3) for color in color_legend.values()]\n",
    "legend_labels = list(color_legend.keys())\n",
    "plt.legend(legend_lines, legend_labels, loc='best')\n",
    "\n",
    "# Show the plot\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import streamlit as st\n",
    "import networkx as nx\n",
    "import plotly.graph_objects as go\n",
    "\n",
    "# Define the plants and compatibility matrix\n",
    "plants = ['strawberries', 'mint', 'carrots', 'lettuce', 'basil', 'tomatoes', 'marigolds', 'lemons', 'strawberries', 'spinach', 'broccoli']\n",
    "compatibility_matrix = [\n",
    "    [0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1],\n",
    "    [1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1],\n",
    "    [0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
    "    [0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]\n",
    "]\n",
    "\n",
    "# Create a directed graph\n",
    "G = nx.DiGraph()\n",
    "\n",
    "# Add nodes to the graph\n",
    "G.add_nodes_from(plants)\n",
    "\n",
    "# Define positions for the nodes\n",
    "pos = nx.spring_layout(G)\n",
    "\n",
    "# Assign positions to the nodes\n",
    "for node, position in pos.items():\n",
    "    G.nodes[node]['pos'] = position\n",
    "\n",
    "# Iterate over the compatibility matrix and add edges with corresponding colors\n",
    "for i in range(len(plants)):\n",
    "    for j in range(len(plants)):\n",
    "        if compatibility_matrix[i][j] == -1:\n",
    "            G.add_edge(plants[i], plants[j], color='red')\n",
    "        elif compatibility_matrix[i][j] == 1:\n",
    "            G.add_edge(plants[i], plants[j], color='green')\n",
    "        else:\n",
    "            G.add_edge(plants[i], plants[j], color='lightgray')\n",
    "\n",
    "# Create edge traces\n",
    "# Create edge traces\n",
    "edge_traces = []\n",
    "for edge in G.edges():\n",
    "    x0, y0 = G.nodes[edge[0]]['pos']\n",
    "    x1, y1 = G.nodes[edge[1]]['pos']\n",
    "    color = G.edges[edge]['color']\n",
    "    trace = go.Scatter(x=[x0, x1, None], y=[y0, y1, None], mode='lines', line=dict(color=color, width=2))\n",
    "    edge_traces.append(trace)\n",
    "\n",
    "# Create node traces\n",
    "node_traces = []\n",
    "for node in G.nodes():\n",
    "    x, y = G.nodes[node]['pos']\n",
    "    trace = go.Scatter(x=[x], y=[y], mode='markers', marker=dict(color='black', size=10), name=node)\n",
    "    node_traces.append(trace)\n",
    "\n",
    "# Create figure\n",
    "fig = go.Figure(data=edge_traces + node_traces)\n",
    "\n",
    "# Set layout options\n",
    "fig.update_layout(\n",
    "    title='Plant Network',\n",
    "    showlegend=False,\n",
    "    hovermode='closest',\n",
    "    margin=dict(b=20, l=5, r=5, t=40),\n",
    "    xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),\n",
    "    yaxis=dict(showgrid=False, zeroline=False, showticklabels=False)\n",
    ")\n",
    "\n",
    "# Render the graph\n",
    "#st.plotly_chart(fig)\n",
    "fig"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import streamlit as st\n",
    "import networkx as nx\n",
    "import plotly.graph_objects as go\n",
    "\n",
    "# Define the plants and compatibility matrix\n",
    "plants = ['strawberries', 'mint', 'carrots', 'lettuce', 'basil', 'tomatoes', 'marigolds', 'lemons', 'strawberries', 'spinach', 'broccoli']\n",
    "compatibility_matrix = [\n",
    "    [0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1],\n",
    "    [1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1],\n",
    "    [0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
    "    [0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1],\n",
    "    [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],\n",
    "    [1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]\n",
    "]\n",
    "\n",
    "# Create the graph\n",
    "G = nx.Graph()\n",
    "G.add_nodes_from(plants)\n",
    "for i in range(len(plants)):\n",
    "    for j in range(i + 1, len(plants)):\n",
    "        if compatibility_matrix[i][j] == 0:\n",
    "            G.add_edge(plants[i], plants[j], color='lightgrey')\n",
    "        else:\n",
    "            G.add_edge(plants[i], plants[j], color='green' if compatibility_matrix[i][j] == 1 else 'pink')\n",
    "\n",
    "# Generate positions for the nodes\n",
    "pos = nx.spring_layout(G)\n",
    "\n",
    "# Create node trace\n",
    "node_trace = go.Scatter(\n",
    "    x=[pos[node][0] for node in G.nodes()],\n",
    "    y=[pos[node][1] for node in G.nodes()],\n",
    "    text=list(G.nodes()),\n",
    "    mode='markers+text',\n",
    "    textposition='top center',\n",
    "    hoverinfo='text',\n",
    "    marker=dict(\n",
    "        size=20,\n",
    "        color='lightblue',\n",
    "        line_width=2,\n",
    "    )\n",
    ")\n",
    "\n",
    "# Create edge trace\n",
    "edge_trace = go.Scatter(\n",
    "    x=[],\n",
    "    y=[],\n",
    "    line=dict(width=1, color='lightgrey'),\n",
    "    hoverinfo='none',\n",
    "    mode='lines'\n",
    ")\n",
    "\n",
    "# Add coordinates to edge trace\n",
    "for edge in G.edges():\n",
    "    x0, y0 = pos[edge[0]]\n",
    "    x1, y1 = pos[edge[1]]\n",
    "    edge_trace['x'] += tuple([x0, x1, None])\n",
    "    edge_trace['y'] += tuple([y0, y1, None])\n",
    "\n",
    "# Create edge traces for colored edges\n",
    "edge_traces = []\n",
    "for edge in G.edges(data=True):\n",
    "    x0, y0 = pos[edge[0]]\n",
    "    x1, y1 = pos[edge[1]]\n",
    "    color = edge[2]['color']\n",
    "    trace = go.Scatter(\n",
    "        x=[x0, x1],\n",
    "        y=[y0, y1],\n",
    "        mode='lines',\n",
    "        line=dict(width=2, color=color),\n",
    "        hoverinfo='none'\n",
    "    )\n",
    "    edge_traces.append(trace)\n",
    "\n",
    "# Create layout\n",
    "layout = go.Layout(\n",
    "    title='Plant Compatibility Network Graph',\n",
    "    showlegend=False,\n",
    "    hovermode='closest',\n",
    "    margin=dict(b=20, l=5, r=5, t=40),\n",
    "    xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),\n",
    "    yaxis=dict(showgrid=False, zeroline=False, showticklabels=False)\n",
    ")\n",
    "\n",
    "# Create figure\n",
    "fig = go.Figure(data=[edge_trace, *edge_traces, node_trace], layout=layout)\n",
    "\n",
    "# Render the graph using Plotly in Streamlit\n",
    "st.plotly_chart(fig)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "import numpy as np\n",
    "\n",
    "# Define the compatibility matrix\n",
    "compatibility_matrix = np.array([\n",
    "    [-1, 1, 0, -1],\n",
    "    [1, -1, 1, -1],\n",
    "    [1, 0, -1, 1],\n",
    "    [-1, -1, 1, -1]\n",
    "])\n",
    "\n",
    "# Define the user-selected plants, number of plant beds, and constraints\n",
    "user_plants = [\"A\", \"B\", \"C\", \"D\"]\n",
    "num_plant_beds = 4\n",
    "min_species_per_bed = 1\n",
    "max_species_per_bed = 2\n",
    "\n",
    "# Genetic Algorithm parameters\n",
    "population_size = 50\n",
    "num_generations = 100\n",
    "tournament_size = 3\n",
    "crossover_rate = 0.8\n",
    "mutation_rate = 0.1\n",
    "\n",
    "# Generate an initial population randomly\n",
    "def generate_initial_population():\n",
    "    population = []\n",
    "    for _ in range(population_size):\n",
    "        grouping = []\n",
    "        for _ in range(num_plant_beds):\n",
    "            num_species = random.randint(min_species_per_bed, max_species_per_bed)\n",
    "            species = random.sample(user_plants, num_species)\n",
    "            grouping.append(species)\n",
    "        population.append(grouping)\n",
    "    return population\n",
    "\n",
    "# Calculate the fitness score of a grouping\n",
    "def calculate_fitness(grouping):\n",
    "    score = 0\n",
    "    for bed1 in range(num_plant_beds):\n",
    "        for bed2 in range(bed1 + 1, num_plant_beds):\n",
    "            for species1 in grouping[bed1]:\n",
    "                for species2 in grouping[bed2]:\n",
    "                    species1_index = user_plants.index(species1)\n",
    "                    species2_index = user_plants.index(species2)\n",
    "                    score += compatibility_matrix[species1_index][species2_index]\n",
    "    return score\n",
    "\n",
    "# Perform tournament selection\n",
    "def tournament_selection(population):\n",
    "    selected = []\n",
    "    for _ in range(population_size):\n",
    "        participants = random.sample(population, tournament_size)\n",
    "        winner = max(participants, key=calculate_fitness)\n",
    "        selected.append(winner)\n",
    "    return selected\n",
    "\n",
    "# Perform crossover between two parents\n",
    "def crossover(parent1, parent2):\n",
    "    if random.random() < crossover_rate:\n",
    "        crossover_point = random.randint(1, num_plant_beds - 1)\n",
    "        child1 = parent1[:crossover_point] + parent2[crossover_point:]\n",
    "        child2 = parent2[:crossover_point] + parent1[crossover_point:]\n",
    "        return child1, child2\n",
    "    else:\n",
    "        return parent1, parent2\n",
    "\n",
    "# Perform mutation on an individual\n",
    "def mutate(individual):\n",
    "    if random.random() < mutation_rate:\n",
    "        mutated_bed = random.randint(0, num_plant_beds - 1)\n",
    "        new_species = random.sample(user_plants, random.randint(min_species_per_bed, max_species_per_bed))\n",
    "        individual[mutated_bed] = new_species\n",
    "    return individual\n",
    "\n",
    "# Perform replacement of the population with the offspring\n",
    "def replacement(population, offspring):\n",
    "    sorted_population = sorted(population, key=calculate_fitness, reverse=True)\n",
    "    sorted_offspring = sorted(offspring, key=calculate_fitness, reverse=True)\n",
    "    return sorted_population[:population_size - len(offspring)] + sorted_offspring\n",
    "\n",
    "# Genetic Algorithm main function\n",
    "def genetic_algorithm():\n",
    "    population = generate_initial_population()\n",
    "\n",
    "    for generation in range(num_generations):\n",
    "        print(f\"Generation {generation + 1}\")\n",
    "\n",
    "        selected_population = tournament_selection(population)\n",
    "        offspring = []\n",
    "\n",
    "        for _ in range(population_size // 2):\n",
    "            parent1 = random.choice(selected_population)\n",
    "            parent2 = random.choice(selected_population)\n",
    "            child1, child2 = crossover(parent1, parent2)\n",
    "            child1 = mutate(child1)\n",
    "            child2 = mutate(child2)\n",
    "            offspring.extend([child1, child2])\n",
    "\n",
    "        population = replacement(population, offspring)\n",
    "\n",
    "    best_grouping = max(population, key=calculate_fitness)\n",
    "    best_fitness = calculate_fitness(best_grouping)\n",
    "    print(f\"Best Grouping: {best_grouping}\")\n",
    "    print(f\"Fitness Score: {best_fitness}\")\n",
    "\n",
    "# Run the Genetic Algorithm\n",
    "genetic_algorithm()\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def query_farmersalmanac(title, first_paragraph_only=True):\n",
    "    base_url = \"https://www.almanac.com/companion-planting-guide-vegetables\"\n",
    "    url = f\"{base_url}/w/api.php?format=json&action=query&prop=extracts&explaintext=1&titles={title}\"\n",
    "    if first_paragraph_only:\n",
    "        url += \"&exintro=1\"\n",
    "    data = requests.get(url).json()\n",
    "    return Document(\n",
    "      metadata={\"source\": f\"{base_url}\"},\n",
    "      page_content=list(data[\"query\"][\"pages\"].values())[0][\"extract\"],\n",
    "  )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## future with sources\n",
    "- https://dzlab.github.io/2023/01/02/prompt-langchain/\n",
    "- https://techcommunity.microsoft.com/t5/startups-at-microsoft/build-a-chatbot-to-query-your-documentation-using-langchain-and/ba-p/3833134"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "GRDN_env",
   "language": "python",
   "name": "grdn_env"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}