Skip to content

Commit c769f9b

Browse files
author
Tom Softreck
committed
update
1 parent 094e399 commit c769f9b

File tree

7 files changed

+705
-380
lines changed

7 files changed

+705
-380
lines changed

example.py

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,75 @@
1-
#!/usr/bin/env python3
1+
#!/usr/bin/env python
2+
"""
3+
Example usage of ApiFuncFramework
4+
"""
5+
26
import logging
3-
import json
4-
import sys
57
import os
8+
import sys
9+
import json
610

7-
# Add the src directory to the Python path if needed
8-
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'src')))
9-
from apifunc.json_to_html import json_to_html
10-
from apifunc.html_to_pdf import html_to_pdf
11+
# Add the src directory to the Python path
12+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
1113

12-
from apifunc.apifunc import (
13-
DynamicgRPCComponent,
14-
PipelineOrchestrator
15-
)
14+
# Import the necessary components from apifunc
15+
from apifunc.components import DynamicgRPCComponent
16+
from apifunc.apifunc import ApiFuncConfig, ApiFuncFramework
1617

1718
# Configure logging
1819
logging.basicConfig(
1920
level=logging.INFO,
20-
format='%(asctime)s - %(levelname)s - %(message)s'
21+
format='%(asctime)s - %(levelname)s - %(message)s',
22+
datefmt='%Y-%m-%d %H:%M:%S'
2123
)
2224
logger = logging.getLogger(__name__)
2325

24-
def main():
26+
def json_to_html(json_data):
27+
"""Convert JSON data to HTML"""
2528
try:
26-
logger.info("Starting the apifunc example pipeline...")
29+
# Parse JSON if it's a string
30+
if isinstance(json_data, str):
31+
data = json.loads(json_data)
32+
else:
33+
data = json_data
34+
35+
# Create a simple HTML representation
36+
html = "<html><body><h1>JSON Data</h1><ul>"
37+
for key, value in data.items():
38+
html += f"<li><strong>{key}:</strong> {value}</li>"
39+
html += "</ul></body></html>"
2740

28-
# Sample data
29-
sample_data = {
30-
"title": "Sample Report",
31-
"author": "APIFunc",
32-
"date": "2025-03-28",
33-
"content": "This is a sample report generated by APIFunc."
34-
}
41+
return html
42+
except Exception as e:
43+
logger.error(f"Error converting JSON to HTML: {e}")
44+
return f"<html><body><h1>Error</h1><p>{str(e)}</p></body></html>"
3545

36-
# Create pipeline components
37-
# Przykład użycia z określonym portem
38-
json_html_component = DynamicgRPCComponent(json_to_html, port=50051)
39-
html_pdf_component = DynamicgRPCComponent(html_to_pdf, port=50052)
46+
def main():
47+
"""Main function"""
48+
try:
49+
logger.info("Starting the apifunc example pipeline...")
4050

41-
# Create and execute pipeline
42-
pipeline = PipelineOrchestrator()
43-
pipeline.add_component(json_html_component)
44-
pipeline.add_component(html_pdf_component)
51+
# Create framework with configuration
52+
config = ApiFuncConfig(
53+
proto_dir="./proto",
54+
generated_dir="./generated",
55+
port=50051 # Set the port here in the config
56+
)
57+
framework = ApiFuncFramework(config)
4558

46-
# Execute pipeline
47-
result = pipeline.execute_pipeline(sample_data)
59+
# Register the function with the framework
60+
# The framework will create a DynamicgRPCComponent internally
61+
framework.register_function(json_to_html)
4862

49-
# Save the result
50-
with open("output.pdf", "wb") as f:
51-
f.write(result)
63+
# Start the gRPC server
64+
server = framework.start_server()
5265

53-
logger.info("Pipeline executed successfully. Output saved to output.pdf")
66+
logger.info(f"Server running on port {config.port}. Press Ctrl+C to stop.")
67+
server.wait_for_termination()
5468

69+
except KeyboardInterrupt:
70+
logger.info("Server stopped by user.")
5571
except Exception as e:
56-
logger.error(f"Error processing: {e}")
57-
import traceback
58-
traceback.print_exc()
72+
logger.error(f"Error processing: {str(e)}", exc_info=True)
5973

6074
if __name__ == "__main__":
6175
main()

example2.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Example of a pipeline with two gRPC services
4+
"""
5+
6+
import logging
7+
import json
8+
import sys
9+
import os
10+
import base64
11+
12+
# Add the src directory to the Python path if needed
13+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'src')))
14+
15+
# Import the necessary components from apifunc
16+
from apifunc.apifunc import ApiFuncConfig, ApiFuncFramework
17+
from apifunc.components import DynamicgRPCComponent
18+
19+
# Configure logging
20+
logging.basicConfig(
21+
level=logging.INFO,
22+
format='%(asctime)s - %(levelname)s - %(message)s'
23+
)
24+
logger = logging.getLogger(__name__)
25+
26+
# Define the pipeline components as functions
27+
def json_to_html(json_data):
28+
"""Convert JSON data to HTML"""
29+
try:
30+
# Parse JSON if it's a string
31+
if isinstance(json_data, str):
32+
data = json.loads(json_data)
33+
else:
34+
data = json_data
35+
36+
# Create a simple HTML representation
37+
html = f"""
38+
<html>
39+
<head>
40+
<title>{data.get('title', 'Report')}</title>
41+
<style>
42+
body {{ font-family: Arial, sans-serif; margin: 40px; }}
43+
h1 {{ color: #2c3e50; }}
44+
.info {{ color: #7f8c8d; margin-bottom: 20px; }}
45+
.content {{ line-height: 1.6; }}
46+
</style>
47+
</head>
48+
<body>
49+
<h1>{data.get('title', 'Report')}</h1>
50+
<div class="info">
51+
<p>Author: {data.get('author', 'Unknown')}</p>
52+
<p>Date: {data.get('date', 'N/A')}</p>
53+
</div>
54+
<div class="content">
55+
<p>{data.get('content', '')}</p>
56+
</div>
57+
</body>
58+
</html>
59+
"""
60+
61+
return html
62+
except Exception as e:
63+
logger.error(f"Error converting JSON to HTML: {e}")
64+
return f"<html><body><h1>Error</h1><p>{str(e)}</p></body></html>"
65+
66+
def html_to_pdf(html_content):
67+
"""Convert HTML to PDF using WeasyPrint"""
68+
try:
69+
# Import WeasyPrint here to avoid dependency issues
70+
from weasyprint import HTML
71+
import io
72+
73+
# Convert HTML to PDF
74+
pdf_buffer = io.BytesIO()
75+
HTML(string=html_content).write_pdf(pdf_buffer)
76+
77+
# Return PDF as base64 encoded string for gRPC transport
78+
pdf_data = pdf_buffer.getvalue()
79+
return base64.b64encode(pdf_data).decode('utf-8')
80+
except Exception as e:
81+
logger.error(f"Error converting HTML to PDF: {e}")
82+
raise
83+
84+
# Pipeline orchestrator class
85+
class PipelineOrchestrator:
86+
"""Class to orchestrate the execution of pipeline components"""
87+
88+
def __init__(self):
89+
self.components = []
90+
91+
def add_component(self, component):
92+
"""Add a component to the pipeline"""
93+
self.components.append(component)
94+
95+
def execute_pipeline(self, input_data):
96+
"""Execute the pipeline with the given input data"""
97+
current_data = input_data
98+
99+
for i, component in enumerate(self.components):
100+
logger.info(f"Executing component {i+1}/{len(self.components)}: {component.name}")
101+
current_data = component.process(current_data)
102+
103+
return current_data
104+
105+
def main():
106+
try:
107+
logger.info("Starting the apifunc example pipeline with two services...")
108+
109+
# Sample data
110+
sample_data = {
111+
"title": "Sample Report",
112+
"author": "APIFunc",
113+
"date": "2025-03-28",
114+
"content": "This is a sample report generated by APIFunc."
115+
}
116+
117+
# Create configurations for both services
118+
json_html_config = ApiFuncConfig(
119+
proto_dir="./proto/json_html",
120+
generated_dir="./generated/json_html",
121+
port=50051
122+
)
123+
124+
html_pdf_config = ApiFuncConfig(
125+
proto_dir="./proto/html_pdf",
126+
generated_dir="./generated/html_pdf",
127+
port=50052
128+
)
129+
130+
# Create framework instances
131+
json_html_framework = ApiFuncFramework(json_html_config)
132+
html_pdf_framework = ApiFuncFramework(html_pdf_config)
133+
134+
# Register functions with frameworks
135+
json_html_framework.register_function(json_to_html)
136+
html_pdf_framework.register_function(html_to_pdf)
137+
138+
# Start servers in separate threads
139+
import threading
140+
141+
def run_server(framework, name):
142+
logger.info(f"Starting {name} server on port {framework.config.port}")
143+
server = framework.start_server()
144+
try:
145+
server.wait_for_termination()
146+
except KeyboardInterrupt:
147+
server.stop(0)
148+
logger.info(f"{name} server stopped")
149+
150+
# Start servers in background threads
151+
json_html_thread = threading.Thread(
152+
target=run_server,
153+
args=(json_html_framework, "JSON-to-HTML"),
154+
daemon=True
155+
)
156+
157+
html_pdf_thread = threading.Thread(
158+
target=run_server,
159+
args=(html_pdf_framework, "HTML-to-PDF"),
160+
daemon=True
161+
)
162+
163+
json_html_thread.start()
164+
html_pdf_thread.start()
165+
166+
# Give servers time to start
167+
import time
168+
time.sleep(2)
169+
170+
# Create gRPC clients for the services
171+
import grpc
172+
173+
# Create components that use the gRPC services
174+
json_html_component = DynamicgRPCComponent(
175+
json_to_html,
176+
proto_dir=json_html_config.proto_dir,
177+
generated_dir=json_html_config.generated_dir
178+
)
179+
180+
html_pdf_component = DynamicgRPCComponent(
181+
html_to_pdf,
182+
proto_dir=html_pdf_config.proto_dir,
183+
generated_dir=html_pdf_config.generated_dir
184+
)
185+
186+
# Create and execute pipeline
187+
pipeline = PipelineOrchestrator()
188+
pipeline.add_component(json_html_component)
189+
pipeline.add_component(html_pdf_component)
190+
191+
# Execute pipeline
192+
logger.info("Executing pipeline...")
193+
result = pipeline.execute_pipeline(sample_data)
194+
195+
# Decode the base64 PDF data
196+
pdf_data = base64.b64decode(result)
197+
198+
# Save the result
199+
output_file = "output.pdf"
200+
with open(output_file, "wb") as f:
201+
f.write(pdf_data)
202+
203+
logger.info(f"Pipeline executed successfully. Output saved to {output_file}")
204+
205+
except Exception as e:
206+
logger.error(f"Error processing: {e}")
207+
import traceback
208+
traceback.print_exc()
209+
210+
# Keep the main thread running to allow the server threads to continue
211+
try:
212+
while True:
213+
time.sleep(1)
214+
except KeyboardInterrupt:
215+
logger.info("Shutting down...")
216+
217+
if __name__ == "__main__":
218+
main()

0 commit comments

Comments
 (0)