airabbitX commited on
Commit
2436ec9
β€’
1 Parent(s): f7fcdcd

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +69 -12
  2. app.py +7 -0
  3. ui.py +138 -0
  4. utils.py +54 -0
README.md CHANGED
@@ -1,12 +1,69 @@
1
- ---
2
- title: Lsp
3
- emoji: 😻
4
- colorFrom: blue
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 5.6.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # LLM LSP
2
+
3
+ A proof of concept for intelligent document editing that works like humans do - scan, jump, edit.
4
+
5
+ ## The Idea
6
+ Instead of making AI read entire documents, we let it:
7
+ 1. Scan headers to find location (like grep)
8
+ 2. Jump to right section (like sed)
9
+ 3. Make targeted changes
10
+ 4. Put it back (like cat)
11
+
12
+ ## Quick Start
13
+ ```python
14
+ pip install -r requirements.txt # openai, gradio
15
+
16
+ from lsp import LSP
17
+ editor = LSP(api_key="your-key")
18
+ editor.edit("doc.md", "add version warning")
19
+ ```
20
+
21
+ ## How It Works
22
+
23
+ 1. **Map Sections Fast**
24
+ ```python
25
+ sections = find_sections("doc.md") # Uses grep-like scan
26
+ ```
27
+
28
+ 2. **AI Picks Target**
29
+ ```json
30
+ {
31
+ "sections": {"## Setup": 10, "## Config": 50},
32
+ "task": "add version warning",
33
+ "target": "## Setup at line 10"
34
+ }
35
+ ```
36
+
37
+ 3. **Extract & Edit**
38
+ ```python
39
+ content = extract_section(file, 10, 49) # Just that piece
40
+ new_content = ai.modify(content) # AI edits small part
41
+ ```
42
+
43
+ 4. **Put It Back**
44
+ ```python
45
+ replace_section(file, 10, 49, new_content)
46
+ ```
47
+
48
+ ## Try It
49
+ ```bash
50
+ python main.py # Launches Gradio UI
51
+ ```
52
+
53
+ ## Status
54
+ - POC stage
55
+ - Works with markdown files
56
+ - Uses gpt-4o-mini
57
+ - Basic UI
58
+
59
+ ## Limits
60
+ - One section at a time
61
+ - Just markdown for now
62
+ - No fancy error handling
63
+ - Will fuck up if sections aren't clear
64
+
65
+ ## Next Steps?
66
+ - Handle multiple sections
67
+ - Better section detection
68
+ - More formats
69
+ - Whatever you need it to do
app.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from ui import LSPUI
2
+ from utils import logger, log_step
3
+
4
+ if __name__ == "__main__":
5
+ log_step("MAIN", "Starting SmartEdit application")
6
+ app = LSPUI()
7
+ app.launch()
ui.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from models import LSP
3
+ from utils import logger, log_step
4
+ import asyncio
5
+ from typing import Optional
6
+
7
+ class LSPUI:
8
+ def __init__(self):
9
+ self.lsp: Optional[LSP] = None
10
+ self.setup_interface()
11
+
12
+ def validate_inputs(self, api_key: str, file: gr.File, instruction: str):
13
+ """Validate input parameters"""
14
+ if not api_key:
15
+ return False, "Error: API key required"
16
+ if not file:
17
+ return False, "Error: No file uploaded"
18
+ if not instruction:
19
+ return False, "Error: No edit instruction"
20
+ return True, None
21
+
22
+ def read_file_content(self, file: gr.File) -> str:
23
+ """Read content from file upload"""
24
+ if isinstance(file, str):
25
+ with open(file, 'r') as f:
26
+ return f.read()
27
+ return file.read().decode('utf-8')
28
+
29
+ async def process_smart(self, api_key: str, file: gr.File, instruction: str):
30
+ """Handle smart approach independently"""
31
+ try:
32
+ # Validate and initialize
33
+ valid, error = self.validate_inputs(api_key, file, instruction)
34
+ if not valid:
35
+ return error, error, error
36
+
37
+ if not self.lsp:
38
+ self.lsp = LSP(api_key)
39
+
40
+ content = self.read_file_content(file)
41
+ log_step("UI", "Starting smart approach")
42
+
43
+ # Process
44
+ result, traces, elapsed_time = await self.lsp.edit_smart(content, instruction)
45
+ log_step("UI", f"Smart approach completed in {elapsed_time:.2f}s")
46
+
47
+ return (
48
+ result,
49
+ "\n".join(traces),
50
+ f"βœ“ Completed in {elapsed_time:.2f}s"
51
+ )
52
+ except Exception as e:
53
+ error_msg = f"Error: {str(e)}"
54
+ log_step("UI", f"Error in smart approach: {error_msg}")
55
+ return error_msg, error_msg, "βœ— Failed"
56
+
57
+ async def process_naive(self, api_key: str, file: gr.File, instruction: str):
58
+ """Handle naive approach independently"""
59
+ try:
60
+ # Validate and initialize
61
+ valid, error = self.validate_inputs(api_key, file, instruction)
62
+ if not valid:
63
+ return error, error, error
64
+
65
+ if not self.lsp:
66
+ self.lsp = LSP(api_key)
67
+
68
+ content = self.read_file_content(file)
69
+ log_step("UI", "Starting naive approach")
70
+
71
+ # Process
72
+ result, traces, elapsed_time = await self.lsp.edit_naive(content, instruction)
73
+ log_step("UI", f"Naive approach completed in {elapsed_time:.2f}s")
74
+
75
+ return (
76
+ result,
77
+ "\n".join(traces),
78
+ f"βœ“ Completed in {elapsed_time:.2f}s"
79
+ )
80
+ except Exception as e:
81
+ error_msg = f"Error: {str(e)}"
82
+ log_step("UI", f"Error in naive approach: {error_msg}")
83
+ return error_msg, error_msg, "βœ— Failed"
84
+
85
+ def setup_interface(self):
86
+ """Setup the Gradio interface"""
87
+ with gr.Blocks(title="LSP Comparison") as self.blocks:
88
+ gr.Markdown("# LLM Selective Processing Demo")
89
+
90
+ with gr.Row():
91
+ api_key = gr.Textbox(label="OpenAI API Key", type="password")
92
+
93
+ with gr.Row():
94
+ file_upload = gr.File(
95
+ label="Upload Markdown File",
96
+ file_types=[".md", ".txt"]
97
+ )
98
+ instruction = gr.Textbox(label="What to edit")
99
+
100
+ with gr.Row():
101
+ smart_btn = gr.Button("Update with LSP")
102
+ naive_btn = gr.Button("Update w/o LSP")
103
+
104
+ with gr.Row():
105
+ with gr.Column():
106
+ gr.Markdown("### Smart Approach (Section-Aware)")
107
+ smart_result = gr.Textbox(label="Result", lines=10, value="")
108
+ smart_trace = gr.Textbox(label="Traces", lines=10, value="")
109
+ smart_status = gr.Textbox(label="Status", value="")
110
+
111
+ with gr.Column():
112
+ gr.Markdown("### Naive Approach (Full Document)")
113
+ naive_result = gr.Textbox(label="Result", lines=10, value="")
114
+ naive_trace = gr.Textbox(label="Traces", lines=10, value="")
115
+ naive_status = gr.Textbox(label="Status", value="")
116
+
117
+ # Set up independent event handlers
118
+ smart_btn.click(
119
+ fn=lambda: ("Working on it...", "Processing...", "⏳ Running..."),
120
+ outputs=[smart_result, smart_trace, smart_status]
121
+ ).then(
122
+ fn=self.process_smart,
123
+ inputs=[api_key, file_upload, instruction],
124
+ outputs=[smart_result, smart_trace, smart_status]
125
+ )
126
+
127
+ naive_btn.click(
128
+ fn=lambda: ("Working on it...", "Processing...", "⏳ Running..."),
129
+ outputs=[naive_result, naive_trace, naive_status]
130
+ ).then(
131
+ fn=self.process_naive,
132
+ inputs=[api_key, file_upload, instruction],
133
+ outputs=[naive_result, naive_trace, naive_status]
134
+ )
135
+
136
+ def launch(self):
137
+ """Launch the Gradio interface"""
138
+ self.blocks.launch()
utils.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from datetime import datetime
3
+
4
+ # Set up logging
5
+ logging.basicConfig(
6
+ level=logging.INFO,
7
+ format='%(asctime)s - %(levelname)s - %(message)s',
8
+ handlers=[
9
+ logging.StreamHandler(),
10
+ logging.FileHandler('lsp.log')
11
+ ]
12
+ )
13
+ logger = logging.getLogger(__name__)
14
+
15
+ SYSTEM_PROMPT = """You are part of a document editing system.
16
+ Follow these EXACT steps with ZERO deviation:
17
+
18
+ PHASE 1: FIND TARGET SECTION
19
+ Input you get:
20
+ - Section map like:
21
+ "# Introduction": 1
22
+ "## Setup Steps": 10
23
+ "## Hostname Management": 50
24
+
25
+ - Edit instruction like: "add intro about hostname importance"
26
+
27
+ You must: ONLY identify target section and line numbers
28
+
29
+ PHASE 2: SECTION MODIFICATION
30
+ Input you get:
31
+ - Only the content of target section
32
+ - The edit instruction
33
+
34
+ Example Trace:
35
+ 1. Got map: {"### App Stop Sequence": 100, "## Hostname Management": 150}
36
+ Got instruction: "add intro about importance"
37
+ β†’ I choose: "## Hostname Management" at line 150
38
+
39
+ 2. Got section content:
40
+ ## Hostname Management
41
+ - Default: `{app_name}.localhost`
42
+ β†’ I add intro explaining hostname importance
43
+
44
+ Remember: You never see full document. You work only with:
45
+ 1. Section headers + line numbers
46
+ 2. Then JUST the section to modify
47
+ """
48
+
49
+ def log_step(phase: str, msg: str, data: dict = None):
50
+ """Utility function for consistent logging"""
51
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
52
+ logger.info(f"[{timestamp}] [{phase}] {msg}")
53
+ if data:
54
+ logger.info(f"[{timestamp}] Data: {data}")