Add local LLM console runner
This commit is contained in:
1 parent
afa8f3780f
commit
f186af3387
2 files changed
+99
No files matched your search
@@ -0,0 +1,89 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import ollama
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_MODEL = "qwen2.5:3b"
|
||||||
|
DEFAULT_FILES = [
|
||||||
|
"README.md",
|
||||||
|
"Auto_Seat.ino",
|
||||||
|
"upload.ps1",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def read_context(paths: list[str]) -> str:
|
||||||
|
chunks: list[str] = []
|
||||||
|
for item in paths:
|
||||||
|
path = Path(item)
|
||||||
|
if not path.exists() or not path.is_file():
|
||||||
|
continue
|
||||||
|
|
||||||
|
text = path.read_text(encoding="utf-8", errors="replace")
|
||||||
|
chunks.append(f"## {path.as_posix()}\n{text}")
|
||||||
|
|
||||||
|
return "\n\n".join(chunks)
|
||||||
|
|
||||||
|
|
||||||
|
def ask(model: str, context: str, question: str) -> str:
|
||||||
|
system_prompt = (
|
||||||
|
"You are a local assistant for this Arduino Auto_Seat project. "
|
||||||
|
"Answer in Korean by default. Use the provided project context when it is relevant. "
|
||||||
|
"If the context does not contain the answer, say that clearly and reason from general knowledge."
|
||||||
|
)
|
||||||
|
|
||||||
|
if context:
|
||||||
|
user_prompt = f"Project context:\n{context}\n\nQuestion:\n{question}"
|
||||||
|
else:
|
||||||
|
user_prompt = question
|
||||||
|
|
||||||
|
response = ollama.chat(
|
||||||
|
model=model,
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_prompt},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return response["message"]["content"]
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description="Local LLM chat for the Auto_Seat project.")
|
||||||
|
parser.add_argument("--model", default=DEFAULT_MODEL, help=f"Ollama model name. Default: {DEFAULT_MODEL}")
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-context",
|
||||||
|
action="store_true",
|
||||||
|
help="Chat without loading project files into the prompt.",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
context = "" if args.no_context else read_context(DEFAULT_FILES)
|
||||||
|
|
||||||
|
print(f"Local LLM ready: {args.model}")
|
||||||
|
print("Ask anything. Type /exit to quit.")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
question = input("\nYou> ").strip()
|
||||||
|
except (EOFError, KeyboardInterrupt):
|
||||||
|
print()
|
||||||
|
break
|
||||||
|
|
||||||
|
if question.lower() in {"/exit", "/quit", "exit", "quit"}:
|
||||||
|
break
|
||||||
|
if not question:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
answer = ask(args.model, context, question)
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"\nError: {exc}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"\nLLM> {answer}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||||
|
|
||||||
|
if (-not (Test-Path ".\.venv\Scripts\python.exe")) {
|
||||||
|
python -m venv .venv
|
||||||
|
}
|
||||||
|
|
||||||
|
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
|
||||||
|
.\.venv\Scripts\python.exe .\local_llm_chat.py
|
||||||
Reference in new issue
Block a user