Initial commit: VoIdeaAI - voice-first AI idea assistant
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"""Export service for VoIdea — JSON, Markdown, HTML (printable as PDF)."""
|
||||
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
def export_json(
|
||||
title: str,
|
||||
content: str,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
) -> str:
|
||||
data = {
|
||||
"title": title,
|
||||
"exported_at": datetime.utcnow().isoformat(),
|
||||
"content": content,
|
||||
"metadata": metadata or {},
|
||||
}
|
||||
return json.dumps(data, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
def export_markdown(
|
||||
title: str,
|
||||
content: str,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
) -> str:
|
||||
lines = [f"# {title}", ""]
|
||||
if metadata:
|
||||
for k, v in metadata.items():
|
||||
lines.append(f"- **{k}**: {v}")
|
||||
lines.append("")
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
lines.append(content)
|
||||
lines.append("")
|
||||
lines.append(f"*Экспортировано {datetime.utcnow().isoformat()}*")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def export_html(
|
||||
title: str,
|
||||
content: str,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
) -> str:
|
||||
meta_rows = ""
|
||||
if metadata:
|
||||
for k, v in metadata.items():
|
||||
meta_rows += f"<tr><td><strong>{k}</strong></td><td>{v}</td></tr>\n"
|
||||
|
||||
content_html = content.replace("\n", "<br>\n")
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{title}</title>
|
||||
<style>
|
||||
body {{ font-family: 'Segoe UI', sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #333; }}
|
||||
h1 {{ color: #1a1a2e; border-bottom: 2px solid #e0e0e0; padding-bottom: 10px; }}
|
||||
table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
|
||||
td {{ padding: 6px 12px; border: 1px solid #e0e0e0; }}
|
||||
.meta {{ background: #f5f5f5; border-radius: 8px; padding: 16px; margin: 20px 0; }}
|
||||
.footer {{ margin-top: 40px; font-size: 12px; color: #999; text-align: center; }}
|
||||
@media print {{ body {{ margin: 0; }} }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{title}</h1>
|
||||
<div class="meta"><table>{meta_rows}</table></div>
|
||||
<hr>
|
||||
<div>{content_html}</div>
|
||||
<div class="footer">Экспортировано из VoIdeaAI • {datetime.utcnow().isoformat()}</div>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
CONTENT_TYPE_MAP = {
|
||||
"json": "application/json",
|
||||
"md": "text/markdown; charset=utf-8",
|
||||
"html": "text/html; charset=utf-8",
|
||||
}
|
||||
|
||||
FILE_EXT_MAP = {
|
||||
"json": "json",
|
||||
"md": "md",
|
||||
"html": "html",
|
||||
}
|
||||
|
||||
|
||||
def export_content(
|
||||
fmt: str,
|
||||
title: str,
|
||||
content: str,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
) -> tuple[str, str, str]:
|
||||
"""Export content in requested format.
|
||||
|
||||
Returns (content_str, content_type, file_extension).
|
||||
"""
|
||||
fmt = fmt.lower()
|
||||
if fmt == "json":
|
||||
return export_json(title, content, metadata), CONTENT_TYPE_MAP["json"], FILE_EXT_MAP["json"]
|
||||
elif fmt == "md":
|
||||
return export_markdown(title, content, metadata), CONTENT_TYPE_MAP["md"], FILE_EXT_MAP["md"]
|
||||
else:
|
||||
return export_html(title, content, metadata), CONTENT_TYPE_MAP["html"], FILE_EXT_MAP["html"]
|
||||
Reference in New Issue
Block a user