updates
This commit is contained in:
Binary file not shown.
@@ -11,18 +11,20 @@ Usage:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import html
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import anthropic
|
import anthropic
|
||||||
import requests
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv(Path(__file__).parent / ".env")
|
||||||
|
|
||||||
from csv_preprocessor import analyze_file, analyze_lp_file, group_captures, ChannelMetrics, LPMetrics
|
from csv_preprocessor import analyze_file, analyze_lp_file, group_captures, ChannelMetrics, LPMetrics
|
||||||
|
|
||||||
DATA_DIR = Path(__file__).parent / "data"
|
DATA_DIR = Path(__file__).parent / "data"
|
||||||
ANALYSIS_LOG = Path(__file__).parent / "analysis_log.txt"
|
REPORTS_DIR = Path(__file__).parent / "reports"
|
||||||
DISPLAY_URL = "http://192.168.45.8:5000/display"
|
|
||||||
|
|
||||||
CLAUDE_MODEL = "claude-opus-4-6"
|
CLAUDE_MODEL = "claude-opus-4-6"
|
||||||
SYSTEM_PROMPT = (
|
SYSTEM_PROMPT = (
|
||||||
@@ -86,10 +88,83 @@ def build_prompt(all_summaries: list[str]) -> str:
|
|||||||
"1. Identify any consistent spec concerns (HS voltage, LP-11 voltage, LP-low timing).\n"
|
"1. Identify any consistent spec concerns (HS voltage, LP-11 voltage, LP-low timing).\n"
|
||||||
"2. Highlight any trends over captures (amplitude drift, jitter, LP-11 voltage, etc.).\n"
|
"2. Highlight any trends over captures (amplitude drift, jitter, LP-11 voltage, etc.).\n"
|
||||||
"3. Flag anomalies — missing LP transitions, short LP-low, unexpected burst counts.\n"
|
"3. Flag anomalies — missing LP transitions, short LP-low, unexpected burst counts.\n"
|
||||||
"4. Summarise overall signal health in 2–3 sentences."
|
"4. For any ERROR or WARNING lines in the summaries, explain the most likely cause "
|
||||||
|
" (e.g. missing file, bad trigger, signal absent, probe issue) and what to check.\n"
|
||||||
|
"5. Provide specific, actionable recommendations to address all identified issues and anomalies.\n"
|
||||||
|
"6. Summarise overall signal health in 2–3 sentences."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def save_html_report(analysis: str, token_line: str, keys: list) -> Path:
|
||||||
|
"""Write a timestamped HTML report to the reports/ directory."""
|
||||||
|
REPORTS_DIR.mkdir(exist_ok=True)
|
||||||
|
now = datetime.now()
|
||||||
|
filename = now.strftime("%Y%m%d_%H%M%S_analysis.html")
|
||||||
|
path = REPORTS_DIR / filename
|
||||||
|
|
||||||
|
cap_range = (
|
||||||
|
f"Capture {keys[0][1]:04d}"
|
||||||
|
if len(keys) == 1
|
||||||
|
else f"Captures {keys[0][1]:04d}–{keys[-1][1]:04d}"
|
||||||
|
)
|
||||||
|
date_str = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
# Convert plain text analysis to basic HTML (preserve line breaks, bold **)
|
||||||
|
def text_to_html(text: str) -> str:
|
||||||
|
escaped = html.escape(text)
|
||||||
|
# **bold**
|
||||||
|
import re
|
||||||
|
escaped = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', escaped)
|
||||||
|
# Blank lines → paragraph breaks
|
||||||
|
paragraphs = re.split(r'\n{2,}', escaped)
|
||||||
|
parts = []
|
||||||
|
for para in paragraphs:
|
||||||
|
lines = para.strip().splitlines()
|
||||||
|
if not lines:
|
||||||
|
continue
|
||||||
|
# Numbered or bullet list
|
||||||
|
if lines[0].lstrip().startswith(('1.', '2.', '3.', '-', '*')):
|
||||||
|
items = ''.join(f'<li>{l.lstrip("0123456789.-* ")}</li>' for l in lines if l.strip())
|
||||||
|
tag = 'ol' if lines[0].lstrip()[0].isdigit() else 'ul'
|
||||||
|
parts.append(f'<{tag}>{items}</{tag}>')
|
||||||
|
else:
|
||||||
|
parts.append('<p>' + '<br>'.join(lines) + '</p>')
|
||||||
|
return '\n'.join(parts)
|
||||||
|
|
||||||
|
body_html = text_to_html(analysis)
|
||||||
|
|
||||||
|
html_content = f"""<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>MIPI Analysis — {cap_range}</title>
|
||||||
|
<style>
|
||||||
|
body {{ font-family: Arial, sans-serif; max-width: 900px; margin: 40px auto; padding: 0 20px; color: #222; }}
|
||||||
|
h1 {{ color: #1a3a5c; border-bottom: 2px solid #1a3a5c; padding-bottom: 8px; }}
|
||||||
|
.meta {{ color: #555; font-size: 0.95em; margin-top: -8px; margin-bottom: 24px; }}
|
||||||
|
p {{ line-height: 1.6; }}
|
||||||
|
ol, ul {{ line-height: 1.8; padding-left: 24px; }}
|
||||||
|
li {{ margin: 4px 0; }}
|
||||||
|
.tokens {{ color: #888; font-size: 0.8em; margin-top: 32px; border-top: 1px solid #ddd; padding-top: 8px; }}
|
||||||
|
@media print {{ body {{ margin: 20px; }} }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>MIPI D-PHY Analysis Report</h1>
|
||||||
|
<p class="meta">
|
||||||
|
<strong>Generated:</strong> {date_str} |
|
||||||
|
<strong>Scope:</strong> {cap_range} |
|
||||||
|
<strong>Model:</strong> {CLAUDE_MODEL}
|
||||||
|
</p>
|
||||||
|
{body_html}
|
||||||
|
<p class="tokens">{html.escape(token_line)}</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
path.write_text(html_content, encoding="utf-8")
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Main
|
# Main
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -122,7 +197,7 @@ def run_analysis(last: int = 10) -> None:
|
|||||||
system = SYSTEM_PROMPT,
|
system = SYSTEM_PROMPT,
|
||||||
messages = [{"role": "user", "content": prompt}],
|
messages = [{"role": "user", "content": prompt}],
|
||||||
)
|
)
|
||||||
analysis = message.content[0].text
|
analysis = message.content[0].text
|
||||||
token_line = f"Tokens: {message.usage.input_tokens} in / {message.usage.output_tokens} out"
|
token_line = f"Tokens: {message.usage.input_tokens} in / {message.usage.output_tokens} out"
|
||||||
|
|
||||||
# ── Console ───────────────────────────────────────────────────────────
|
# ── Console ───────────────────────────────────────────────────────────
|
||||||
@@ -134,20 +209,9 @@ def run_analysis(last: int = 10) -> None:
|
|||||||
print(f"({token_line})")
|
print(f"({token_line})")
|
||||||
print(separator + "\n")
|
print(separator + "\n")
|
||||||
|
|
||||||
# ── Append to log file ────────────────────────────────────────────────
|
# ── HTML report ───────────────────────────────────────────────────────
|
||||||
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
report_path = save_html_report(analysis, token_line, keys)
|
||||||
with open(ANALYSIS_LOG, "a", encoding="utf-8") as f:
|
print(f"[ANALYSIS] Report saved to {report_path}")
|
||||||
f.write(f"\n{'='*60}\n{ts} — captures {keys[0][1]:04d}–{keys[-1][1]:04d}\n{'='*60}\n")
|
|
||||||
f.write(analysis)
|
|
||||||
f.write(f"\n({token_line})\n")
|
|
||||||
print(f"[ANALYSIS] Report appended to {ANALYSIS_LOG}")
|
|
||||||
|
|
||||||
# ── Send to display ───────────────────────────────────────────────────
|
|
||||||
try:
|
|
||||||
requests.post(DISPLAY_URL, json={"text": analysis}, timeout=5)
|
|
||||||
print("[ANALYSIS] Report sent to display.")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[ANALYSIS] Display send failed: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
@@ -210,7 +274,6 @@ def main() -> None:
|
|||||||
analysis = message.content[0].text
|
analysis = message.content[0].text
|
||||||
token_line = f"Tokens: {message.usage.input_tokens} in / {message.usage.output_tokens} out"
|
token_line = f"Tokens: {message.usage.input_tokens} in / {message.usage.output_tokens} out"
|
||||||
separator = "=" * 60
|
separator = "=" * 60
|
||||||
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
|
|
||||||
# Console
|
# Console
|
||||||
print(f"\n{separator}\nCLAUDE ANALYSIS\n{separator}")
|
print(f"\n{separator}\nCLAUDE ANALYSIS\n{separator}")
|
||||||
@@ -218,19 +281,9 @@ def main() -> None:
|
|||||||
print(f"({token_line})")
|
print(f"({token_line})")
|
||||||
print(separator)
|
print(separator)
|
||||||
|
|
||||||
# Log file
|
# HTML report
|
||||||
with open(ANALYSIS_LOG, "a", encoding="utf-8") as f:
|
report_path = save_html_report(analysis, token_line, keys)
|
||||||
f.write(f"\n{separator}\n{ts}\n{separator}\n")
|
print(f"\nReport saved to {report_path}")
|
||||||
f.write(analysis)
|
|
||||||
f.write(f"\n({token_line})\n")
|
|
||||||
print(f"\nReport appended to {ANALYSIS_LOG}")
|
|
||||||
|
|
||||||
# Display
|
|
||||||
try:
|
|
||||||
requests.post(DISPLAY_URL, json={"text": analysis}, timeout=5)
|
|
||||||
print("Report sent to display.")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Display send failed: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
10
mipi_test.py
10
mipi_test.py
@@ -364,11 +364,17 @@ def test_worker():
|
|||||||
resume_event.wait() # block here while mgmt_worker is running
|
resume_event.wait() # block here while mgmt_worker is running
|
||||||
if not test_running:
|
if not test_running:
|
||||||
break
|
break
|
||||||
requests.put(URL, json={"state": "on"}, timeout=2)
|
try:
|
||||||
|
requests.put(URL, json={"state": "on"}, timeout=2)
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f" WARNING: display ON failed: {e}")
|
||||||
time.sleep(DISPLAY_SETTLE_S)
|
time.sleep(DISPLAY_SETTLE_S)
|
||||||
dual_capture(count)
|
dual_capture(count)
|
||||||
count += 1
|
count += 1
|
||||||
requests.put(URL, json={"state": "off"}, timeout=2)
|
try:
|
||||||
|
requests.put(URL, json={"state": "off"}, timeout=2)
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f" WARNING: display OFF failed: {e}")
|
||||||
time.sleep(1.0)
|
time.sleep(1.0)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user