DEV Community

shashank ms
shashank ms

Posted on

Integrating LLM into Desktop Applications: A Step-by-Step Guide

We are building a lightweight desktop writing assistant that rewrites and summarizes text using an LLM backend. This is the kind of tool you keep in the background while drafting emails or documentation. I will walk through a complete tkinter application that streams responses from Oxlo.ai using the OpenAI-compatible SDK.

What you'll need

  • Python 3.10 or newer
  • An Oxlo.ai API key from https://portal.oxlo.ai
  • The OpenAI Python SDK: pip install openai

Step 1: Create the UI shell

I start with a single-file tkinter app. The layout has an input box, an output box, and a row of action buttons.

import tkinter as tk
from tkinter import ttk

class WriterAssist:
    def __init__(self, root):
        self.root = root
        self.root.title("Writer Assist")
        self.root.geometry("800x600")

        self.input_box = tk.Text(root, wrap=tk.WORD, height=10)
        self.input_box.pack(fill=tk.BOTH, expand=True, padx=8, pady=4)

        btn_frame = ttk.Frame(root)
        btn_frame.pack(fill=tk.X, padx=8, pady=4)

        self.rewrite_btn = ttk.Button(btn_frame, text="Rewrite", command=self.on_rewrite)
        self.rewrite_btn.pack(side=tk.LEFT, padx=2)

        self.output_box = tk.Text(root, wrap=tk.WORD, height=10, state=tk.DISABLED)
        self.output_box.pack(fill=tk.BOTH, expand=True, padx=8, pady=4)

    def on_rewrite(self):
        pass

if __name__ == "__main__":
    app = tk.Tk()
    WriterAssist(app)
    app.mainloop()

Step 2: Configure the Oxlo.ai client

We initialize the OpenAI SDK pointing at Oxlo.ai. I also define the system prompt in its own constant so the model knows it is an editor, not a chatbot.

SYSTEM_PROMPT = """You are a concise writing assistant. Given a user's text, rewrite it to improve clarity and flow. Preserve the original meaning and tone. Do not add greetings or explanations. Output only the rewritten text."""
from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

Step 3: Add the rewrite handler

I fetch the input text, send it to Llama 3.3 70B on Oxlo.ai, and write the result into the output box.

    def on_rewrite(self):
        user_message = self.input_box.get("1.0", tk.END).strip()
        if not user_message:
            return

        self.output_box.configure(state=tk.NORMAL)
        self.output_box.delete("1.0", tk.END)
        self.output_box.configure(state=tk.DISABLED)

        response = client.chat.completions.create(
            model="llama-3.3-70b",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": user_message},
            ],
        )

        result = response.choices[0].message.content

        self.output_box.configure(state=tk.NORMAL)
        self.output_box.insert(tk.END, result)
        self.output_box.configure(state=tk.DISABLED)

Step 4: Stream tokens into the output box

Blocking calls freeze the UI. Switching to streaming lets us write tokens as they arrive so the interface stays responsive.

    def on_rewrite(self):
        user_message = self.input_box.get("1.0", tk.END).strip()
        if not user_message:
            return

        self.output_box.configure(state=tk.NORMAL)
        self.output_box.delete("1.0", tk.END)

        stream = client.chat.completions.create(
            model="llama-3.3-70b",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": user_message},
            ],
            stream=True,
        )

        for chunk in stream:
            token = chunk.choices[0].delta.content or ""
            self.output_box.insert(tk.END, token)
            self.output_box.see(tk.END)
            self.root.update_idletasks()

        self.output_box.configure(state=tk.DISABLED)

Step 5: Add error handling and a second action

Network calls fail, so I wrap the stream in a try block. I also add a Summarize button that reuses the same client but changes the user instruction.

    def call_oxlo(self, instruction, user_text):
        self.output_box.configure(state=tk.NORMAL)
        self.output_box.delete("1.0", tk.END)

        try:
            stream = client.chat.completions.create(
                model="llama-3.3-70b",
                messages=[
                    {"role": "system", "content": SYSTEM_PROMPT},
                    {"role": "user", "content": f"{instruction}: {user_text}"},
                ],
                stream=True,
            )

            for chunk in stream:
                token = chunk.choices[0].delta.content or ""
                self.output_box.insert(tk.END, token)
                self.output_box.see(tk.END)
                self.root.update_idletasks()

        except Exception as e:
            self.output_box.insert(tk.END, f"\nError: {e}")

        self.output_box.configure(state=tk.DISABLED)

    def on_rewrite(self):
        text = self.input_box.get("1.0", tk.END).strip()
        if text:
            self.call_oxlo("Rewrite the following text", text)

    def on_summarize(self):
        text = self.input_box.get("1.0", tk.END).strip()
        if text:
            self.call_oxlo("Summarize the following text in one paragraph", text)

Wire the second button inside __init__:

        self.summarize_btn = ttk.Button(btn_frame, text="Summarize", command=self.on_summarize)
        self.summarize_btn.pack(side=tk.LEFT, padx=2)

Run it

Save everything as writer_assist.py, set your key, and launch.

export OXLO_API_KEY="sk-oxlo.ai-..."
python writer_assist.py

Paste in rough text like "i need to email the team about the deploy but it is broke and i dont know what to say", then click Rewrite. After a few seconds the output box fills with clean text. Example output:

I need to email the team about the deployment, but it is broken and I am unsure what to say.

Click Summarize and it collapses the input to a single concise statement.

Next steps

Add a global keyboard shortcut so the app activates from the system tray, or switch to qwen-3-32b when you need multilingual rewriting. If you roll this out to a team, Oxlo.ai request-based pricing keeps costs flat even when users paste long documents, which is worth testing against your current token-based provider.

Top comments (0)